1+ import Limits from '../../limits'
12import type PaneState from '../../pane-state'
23import Sections from '../sections'
34import { 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 */
1820export 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