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

Skip to content

Commit 6661e03

Browse files
committed
Implement focusNextHunkLine & focusPreviousHunkLine, bind to core:move-up/down
1 parent b18892a commit 6661e03

File tree

2 files changed

+91
-16
lines changed

2 files changed

+91
-16
lines changed

lib/views/file-patch-view.js

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,21 @@ export default class FilePatchView {
2121
this.props = props
2222
this.selectionMode = 'hunk'
2323
const hunkLineLists = props.hunks.map(hunk => {
24-
return { key: hunk, items: hunk.getLines() }
24+
return { key: hunk, items: hunk.getLines().filter(l => l.isChanged()) }
2525
})
2626
this.multiList = new MultiList(hunkLineLists)
2727
this.setInitialSelection(this.multiList.getSelectedListKey())
2828
etch.initialize(this)
2929
this.subscriptions = atom.commands.add(this.element, {
3030
'git:toggle-patch-selection-mode': this.togglePatchSelectionMode.bind(this),
31-
'git:focus-next-hunk': this.focusNextHunk.bind(this),
32-
'git:focus-previous-hunk': this.focusPreviousHunk.bind(this)
31+
'git:focus-next-hunk': () => this.focusNextHunk({wrap: true}),
32+
'git:focus-previous-hunk': () => this.focusPreviousHunk({wrap: true}),
33+
'core:move-up': () => {
34+
this.selectionMode === 'hunk' ? this.focusPreviousHunk() : this.focusPreviousHunkLine()
35+
},
36+
'core:move-down': () => {
37+
this.selectionMode === 'hunk' ? this.focusNextHunk() : this.focusNextHunkLine()
38+
}
3339
})
3440
}
3541

@@ -45,22 +51,38 @@ export default class FilePatchView {
4551
this.selectedLines = new Set(lines.filter(l => l.isChanged()))
4652
}
4753

48-
focusNextHunk () {
49-
this.multiList.selectNextList({wrap: true})
54+
getSelectedLines () {
55+
return this.selectedLines
56+
}
57+
58+
focusNextHunk ({wrap} = {}) {
59+
this.multiList.selectNextList({wrap})
5060
this.setInitialSelection(this.multiList.getSelectedListKey())
5161
return etch.update(this)
5262
}
5363

54-
focusPreviousHunk () {
55-
this.multiList.selectPreviousList({wrap: true})
64+
focusPreviousHunk ({wrap} = {}) {
65+
this.multiList.selectPreviousList({wrap})
5666
this.setInitialSelection(this.multiList.getSelectedListKey())
5767
return etch.update(this)
5868
}
5969

70+
focusPreviousHunkLine () {
71+
this.multiList.selectPreviousItem()
72+
this.selectNonContextLines([this.multiList.getSelectedItem()])
73+
return etch.update(this)
74+
}
75+
76+
focusNextHunkLine () {
77+
this.multiList.selectNextItem()
78+
this.selectNonContextLines([this.multiList.getSelectedItem()])
79+
return etch.update(this)
80+
}
81+
6082
update (props) {
6183
this.props = props
6284
const hunkLineLists = props.hunks.map(hunk => {
63-
return { key: hunk, items: hunk.getLines() }
85+
return { key: hunk, items: hunk.getLines().filter(l => l.isChanged()) }
6486
})
6587
this.multiList.updateLists(hunkLineLists)
6688
this.setInitialSelection(this.multiList.getSelectedListKey())

test/views/file-patch-view.test.js

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,30 +117,83 @@ describe('FilePatchView', () => {
117117
})
118118
})
119119

120-
describe('focusNextHunk() and focusPreviousHunk()', () => {
121-
it('focuses next/previous hunk and wraps at the end/beginning', async () => {
120+
describe('focusNextHunk({wrap}) and focusPreviousHunk({wrap})', () => {
121+
it('focuses next/previous hunk, and wraps at the end/beginning if wrap is true', async () => {
122122
const hunk1 = new Hunk(5, 5, 2, 1, [new HunkLine('line-1', 'added', -1, 5)])
123123
const hunk2 = new Hunk(8, 8, 1, 1, [new HunkLine('line-5', 'removed', 8, -1)])
124124
const hunk3 = new Hunk(8, 8, 1, 1, [new HunkLine('line-10', 'added', -1, 10)])
125125
const hunkViewsByHunk = new Map()
126126
const view = new FilePatchView({hunks: [hunk1, hunk2, hunk3], registerHunkView: (hunk, view) => hunkViewsByHunk.set(hunk, view)})
127127

128-
assert.deepEqual(view.multiList.getSelectedListKey(), hunk1)
128+
assert.isTrue(hunkViewsByHunk.get(hunk1).props.isSelected)
129129

130130
await view.focusNextHunk()
131-
assert.deepEqual(view.multiList.getSelectedListKey(), hunk2)
131+
assert.isTrue(hunkViewsByHunk.get(hunk2).props.isSelected)
132132

133133
await view.focusNextHunk()
134-
assert.deepEqual(view.multiList.getSelectedListKey(), hunk3)
134+
assert.isTrue(hunkViewsByHunk.get(hunk3).props.isSelected)
135135

136136
await view.focusNextHunk()
137-
assert.deepEqual(view.multiList.getSelectedListKey(), hunk1)
137+
assert.isTrue(hunkViewsByHunk.get(hunk3).props.isSelected)
138+
139+
await view.focusNextHunk({wrap: true})
140+
assert.isTrue(hunkViewsByHunk.get(hunk1).props.isSelected)
138141

139142
await view.focusPreviousHunk()
140-
assert.deepEqual(view.multiList.getSelectedListKey(), hunk3)
143+
assert.isTrue(hunkViewsByHunk.get(hunk1).props.isSelected)
144+
145+
await view.focusPreviousHunk({wrap: true})
146+
assert.isTrue(hunkViewsByHunk.get(hunk3).props.isSelected)
141147

142148
await view.focusPreviousHunk()
143-
assert.deepEqual(view.multiList.getSelectedListKey(), hunk2)
149+
assert.isTrue(hunkViewsByHunk.get(hunk2).props.isSelected)
150+
151+
await view.focusPreviousHunk()
152+
assert.isTrue(hunkViewsByHunk.get(hunk1).props.isSelected)
153+
})
154+
})
155+
156+
describe('focusNextHunkLine() and focusPreviousHunkLine()', () => {
157+
it('focuses next/previous non-context hunk line, crossing hunk boundaries but not wrapping', async () => {
158+
const line1 = new HunkLine('line-1', 'unchanged', 5, 5) // context lines won't be selected
159+
const line2 = new HunkLine('line-2', 'removed', 6, -1)
160+
const line3 = new HunkLine('line-3', 'removed', 7, -1)
161+
162+
const line4 = new HunkLine('line-4', 'unchanged', 8, 8) // context lines won't be selected
163+
const line5 = new HunkLine('line-5', 'added', -1, 9)
164+
const line6 = new HunkLine('line-6', 'unchanged', 9, 10) // context lines won't be selected
165+
166+
const hunk1 = new Hunk(5, 5, 2, 0, [line1, line2, line3])
167+
const hunk2 = new Hunk(8, 8, 1, 2, [line4, line5, line6])
168+
const hunkViewsByHunk = new Map()
169+
const view = new FilePatchView({hunks: [hunk1, hunk2], registerHunkView: (hunk, view) => hunkViewsByHunk.set(hunk, view)})
170+
171+
view.togglePatchSelectionMode()
172+
173+
assert.isTrue(hunkViewsByHunk.get(hunk1).props.isSelected)
174+
assertSelectedLines(view, [line2])
175+
176+
await view.focusNextHunkLine()
177+
assertSelectedLines(view, [line3])
178+
179+
await view.focusNextHunkLine()
180+
assertSelectedLines(view, [line5])
181+
182+
await view.focusNextHunkLine()
183+
assertSelectedLines(view, [line5])
184+
185+
await view.focusPreviousHunkLine()
186+
assertSelectedLines(view, [line3])
187+
188+
await view.focusPreviousHunkLine()
189+
assertSelectedLines(view, [line2])
190+
191+
await view.focusPreviousHunkLine()
192+
assertSelectedLines(view, [line2])
144193
})
145194
})
146195
})
196+
197+
function assertSelectedLines (view, lines) {
198+
assert.deepEqual([...view.getSelectedLines()], lines)
199+
}

0 commit comments

Comments
 (0)