Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ee24fa8

Browse files
authored
Merge pull request atom#160 from atom/ku-nav-hunks
Various File Patch View things
2 parents 4d415e2 + fc826f5 commit ee24fa8

File tree

6 files changed

+220
-22
lines changed

6 files changed

+220
-22
lines changed

keymaps/git.cson

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@
77
'.git-CommitView-editor atom-text-editor:not([mini])':
88
'cmd-enter': 'git:commit'
99
'ctrl-enter': 'git:commit'
10+
11+
'.git-FilePatchView':
12+
'/': 'git:toggle-patch-selection-mode'
13+
'tab': 'git:focus-next-hunk'

lib/models/hunk-line.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ export default class HunkLine {
3838
return this.status
3939
}
4040

41+
isChanged () {
42+
return this.getStatus() === 'added' || this.getStatus() === 'removed'
43+
}
44+
4145
getOrigin () {
4246
switch (this.getStatus()) {
4347
case 'added':

lib/views/file-patch-view.js

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,53 @@ import HunkView from './hunk-view'
99
const EMPTY_SET = new Set()
1010

1111
export default class FilePatchView {
12-
constructor ({filePatch, repository, stagingStatus, registerHunkView}) {
12+
constructor ({filePatch, repository, stagingStatus, selectionMode, registerHunkView}) {
1313
this.filePatch = filePatch
1414
this.repository = repository
1515
this.filePatchSubscriptions = new CompositeDisposable(
1616
this.filePatch.onDidUpdate(this.didUpdateFilePatch.bind(this)),
1717
this.filePatch.onDidDestroy(this.didDestroyFilePatch.bind(this))
1818
)
1919
this.stagingStatus = stagingStatus
20-
this.selectedLines = null
21-
this.selectedHunk = null
20+
this.selectedHunk = filePatch.getHunks()[0]
21+
this.selectedHunkIndex = 0
22+
this.setInitialSelection(this.selectedHunk)
2223
this.registerHunkView = registerHunkView
2324
this.emitter = new Emitter()
25+
this.selectionMode = selectionMode || 'hunk'
2426
etch.initialize(this)
27+
this.subscriptions = atom.commands.add(this.element, {
28+
'git:toggle-patch-selection-mode': this.togglePatchSelectionMode.bind(this),
29+
'git:focus-next-hunk': this.focusNextHunk.bind(this)
30+
})
2531
}
2632

27-
update ({filePatch, repository, stagingStatus}) {
33+
setInitialSelection (hunk) {
34+
if (hunk) {
35+
if (this.selectionMode === 'hunk') {
36+
this.selectNonContextLines(hunk.getLines())
37+
} else {
38+
this.selectNonContextLines([this.getFirstNonContextLine(hunk)])
39+
}
40+
} else {
41+
this.selectNonContextLines([])
42+
}
43+
}
44+
45+
selectNonContextLines (lines) {
46+
this.selectedLines = new Set(lines.filter(l => l.isChanged()))
47+
}
48+
49+
focusNextHunk () {
50+
const hunks = this.filePatch.getHunks()
51+
let index = hunks.indexOf(this.selectedHunk)
52+
this.selectedHunk = ++index < hunks.length ? hunks[index] : hunks[0]
53+
this.selectedHunkIndex = index < hunks.length ? index : 0
54+
this.setInitialSelection(this.selectedHunk)
55+
return etch.update(this)
56+
}
57+
58+
update ({filePatch, repository, stagingStatus, selectionMode}) {
2859
if (this.filePatchSubscriptions) this.filePatchSubscriptions.dispose()
2960

3061
this.filePatch = filePatch
@@ -34,21 +65,26 @@ export default class FilePatchView {
3465
)
3566
this.repository = repository
3667
this.stagingStatus = stagingStatus
68+
this.selectionMode = selectionMode || this.selectionMode
69+
this.selectedHunk = filePatch.getHunks()[0]
70+
this.selectedHunkIndex = 0
71+
this.setInitialSelection(this.selectedHunk)
3772
this.emitter.emit('did-change-title', this.getTitle())
3873
return etch.update(this)
3974
}
4075

4176
destroy () {
4277
this.emitter.emit('did-destroy')
78+
this.subscriptions.dispose()
4379
return etch.destroy(this)
4480
}
4581

4682
render () {
4783
let stageButtonLabelPrefix = this.stagingStatus === 'unstaged' ? 'Stage' : 'Unstage'
4884
return (
49-
<div className='git-FilePatchView'>{this.filePatch.getHunks().map((hunk) => {
85+
<div className='git-FilePatchView' tabIndex='-1'>{this.filePatch.getHunks().map((hunk) => {
5086
const isSelected = hunk === this.selectedHunk
51-
const selectedLines = (isSelected && this.selectedLines != null) ? this.selectedLines : EMPTY_SET
87+
const selectedLines = isSelected ? this.selectedLines : EMPTY_SET
5288
return (
5389
<HunkView
5490
hunk={hunk}
@@ -64,6 +100,20 @@ export default class FilePatchView {
64100
)
65101
}
66102

103+
getFirstNonContextLine (hunk) {
104+
const lines = hunk.getLines()
105+
for (let i = 0; i < lines.length; i++) {
106+
const line = lines[i]
107+
if (line.isChanged()) return line
108+
}
109+
}
110+
111+
togglePatchSelectionMode () {
112+
this.selectionMode = this.selectionMode === 'hunk' ? 'hunkLine' : 'hunk'
113+
this.setInitialSelection(this.selectedHunk)
114+
return etch.update(this)
115+
}
116+
67117
getTitle () {
68118
let title = this.stagingStatus === 'staged' ? 'Staged' : 'Unstaged'
69119
title += ' Changes: '
@@ -80,12 +130,17 @@ export default class FilePatchView {
80130
}
81131

82132
didSelectLinesForHunk (hunk, selectedLines) {
83-
this.selectedLines = selectedLines
84133
this.selectedHunk = hunk
134+
this.selectedHunkIndex = this.filePatch.getHunks().indexOf(hunk)
135+
if (this.selectionMode === 'hunk') {
136+
this.selectNonContextLines(hunk.getLines())
137+
} else {
138+
this.selectNonContextLines([...selectedLines])
139+
}
85140
etch.update(this)
86141
}
87142

88-
didClickStageButtonForHunk (hunk) {
143+
async didClickStageButtonForHunk (hunk) {
89144
// TODO: Test the behavior of this line, which ensure we only attempt to
90145
// stage the selected lines if we clicked the stage button on the hunk
91146
// containing them.
@@ -95,26 +150,37 @@ export default class FilePatchView {
95150
if (this.stagingStatus === 'unstaged') {
96151
if (this.selectedLines && clickedSelectedHunk) {
97152
patchToApply = this.filePatch.getStagePatchForLines(this.selectedLines)
98-
this.selectedLines = null
153+
this.selectedLines = EMPTY_SET
99154
} else {
100155
patchToApply = this.filePatch.getStagePatchForHunk(hunk)
101156
}
102157
} else if (this.stagingStatus === 'staged') {
103158
if (this.selectedLines && clickedSelectedHunk) {
104159
patchToApply = this.filePatch.getUnstagePatchForLines(this.selectedLines)
105-
this.selectedLines = null
160+
this.selectedLines = EMPTY_SET
106161
} else {
107162
patchToApply = this.filePatch.getUnstagePatchForHunk(hunk)
108163
}
109164
} else {
110165
throw new Error(`Unknown stagingStatus: ${this.stagingStatus}`)
111166
}
112167

113-
return this.repository.applyPatchToIndex(patchToApply)
168+
await this.repository.applyPatchToIndex(patchToApply)
169+
return etch.update(this)
114170
}
115171

116172
didUpdateFilePatch () {
117-
etch.update(this)
173+
const hunks = this.filePatch.getHunks()
174+
if (hunks.includes(this.selectedHunk)) {
175+
// retain existing selectedHunk
176+
} else if (hunks[this.selectedHunkIndex]) {
177+
this.selectedHunk = hunks[this.selectedHunkIndex]
178+
} else {
179+
this.selectedHunkIndex = hunks.length - 1
180+
this.selectedHunk = hunks[this.selectedHunkIndex]
181+
}
182+
this.setInitialSelection(this.selectedHunk)
183+
return etch.update(this)
118184
}
119185

120186
didDestroyFilePatch () {

lib/views/hunk-view.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export default class HunkView {
8383
const newLineNumber = line.getNewLineNumber() === -1 ? ' ' : line.getNewLineNumber()
8484
const lineSelectedClass = this.selectedLines.has(line) ? 'is-selected' : ''
8585
return (
86-
<div className={`git-HunkView-line ${lineSelectedClass}`}
86+
<div className={`git-HunkView-line ${lineSelectedClass} ${line.getStatus()}`}
8787
onmousedown={() => this.onMouseDown(line)}
8888
onmousemove={() => this.onMouseMove(line)}
8989
onmouseup={() => this.onMouseUp(line)}>

styles/hunk-view.less

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,28 @@
3939
display:flex;
4040
line-height: 1.5em;
4141

42-
&.is-selected {
43-
background-color: @background-color-selected;
42+
&.is-selected.added, &.is-selected.removed {
43+
background-color: tint(@background-color-selected, 10%);
44+
}
45+
46+
.hunk-line-mixin(@bg; @fg) {
47+
.git-HunkView-oldLineNumber, .git-HunkView-newLineNumber {
48+
background-color: fadeout(shade(@bg, 30%), 80%);
49+
color: tint(@fg, 50%);
50+
}
51+
52+
.git-HunkView-lineContent {
53+
background-color: fadeout(shade(@bg, 30%), 20%);
54+
color: tint(@fg, 50%);
55+
}
56+
}
57+
58+
&.added {
59+
.hunk-line-mixin(@background-color-success, @text-color-success);
60+
}
61+
62+
&.removed {
63+
.hunk-line-mixin(@background-color-error, @text-color-error);
4464
}
4565
}
4666

0 commit comments

Comments
 (0)