Skip to content

Commit 17db2e1

Browse files
committed
diff: the dialog's walk stops at the first and last file as the built-in's does, where the ring would wrap
1 parent 78c94ce commit 17db2e1

2 files changed

Lines changed: 26 additions & 8 deletions

File tree

‎mods/diff/hooks/register.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,10 @@ export function register(on: On) {
729729

730730
const focus = isListed ? Views.dialogFocusOf(model, e.element) : null
731731

732+
if (focus === 'stay') {
733+
return {}
734+
}
735+
732736
if (!focus || !host) {
733737
return next(e)
734738
}
Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Limits from '../../limits'
12
import type PaneState from '../../pane-state'
23
import Sections from '../sections'
34
import { dialogEntriesOf } from './dialog-entries-of'
@@ -7,26 +8,39 @@ import { dialogWindowOf } from './dialog-window-of'
78
* What the focus ring landing on a dialog row makes of the list: that file
89
* selected, the window re-centred, the key of the row drawn where it sits.
910
*
10-
* DiffFileList's selection. The engine keeps its ring by position, so the
11-
* ring is sent to the row that holds the selected file's place once the
12-
* window has moved; null for a key that is none of the listed rows'.
11+
* DiffFileList's selection, which stops at an end where the ring wraps: a
12+
* jump across three or more rows from the first or last file is `stay`.
13+
* The ring goes to the row holding the file's place after the re-centre.
1314
*
1415
* @param model the pane's state
1516
* @param element the key of the element taking the ring
16-
* @returns the selected path and the key to land the ring on, or null
17+
* @returns the selection and the key to land on, `stay`, or null for a key
18+
* that is none of the listed rows'
1719
*/
1820
export function dialogFocusOf(
1921
model: PaneState.PaneModel,
2022
element: string | undefined,
21-
): PaneState.DialogFocus | null {
23+
): PaneState.DialogFocus | 'stay' | null {
2224
const entries = dialogEntriesOf(model)
2325
const paths = entries.map(entry => entry.path)
2426
const keys = entries.map(entry => Sections.fileKeyOf(entry))
2527
const picked = keys.indexOf(element ?? '')
28+
const current = Math.max(0, paths.indexOf(model.selectedPath ?? ''))
29+
const before = dialogWindowOf(model, paths)
30+
31+
const lastDrawn =
32+
Math.min(paths.length, before + Limits.MAX_VISIBLE_FILES) - 1
33+
2634
const selectedPath = paths[picked] ?? null
27-
const after = dialogWindowOf({ selectedPath }, paths)
28-
const landing = keys[dialogWindowOf(model, paths) + picked - after]
35+
36+
const landing =
37+
keys[before + picked - dialogWindowOf({ selectedPath }, paths)]
38+
39+
const isOverStart = current === 0 && picked === lastDrawn
40+
const isOverEnd = current === paths.length - 1 && picked === before
41+
const isFar = lastDrawn - before >= 2
2942
const isRow = selectedPath !== null && landing !== undefined
43+
const isWrap = isFar && (isOverEnd || isOverStart)
3044

31-
return isRow ? { selectedPath, landing } : null
45+
return isWrap ? 'stay' : isRow ? { selectedPath, landing } : null
3246
}

0 commit comments

Comments
 (0)