surshar / claude-code
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.
Built by Anthropic · github.com/anthropics
| @@ -729,6 +729,10 @@ | ||
| 729 | 729 | |
| 730 | 730 | const focus = isListed ? Views.dialogFocusOf(model, e.element) : null |
| 731 | 731 | |
| 732 | + if (focus === 'stay') { | |
| 733 | + return {} | |
| 734 | + } | |
| 735 | + | |
| 732 | 736 | if (!focus || !host) { |
| 733 | 737 | return next(e) |
| 734 | 738 | } |
| @@ -1,3 +1,4 @@ | ||
| 1 | +import Limits from '../../limits' | |
| 1 | 2 | import type PaneState from '../../pane-state' |
| 2 | 3 | import Sections from '../sections' |
| 3 | 4 | import { dialogEntriesOf } from './dialog-entries-of' |
| @@ -7,26 +8,39 @@ | ||
| 7 | 8 | * What the focus ring landing on a dialog row makes of the list: that file |
| 8 | 9 | * selected, the window re-centred, the key of the row drawn where it sits. |
| 9 | 10 | * |
| 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. | |
| 13 | 14 | * |
| 14 | 15 | * @param model the pane's state |
| 15 | 16 | * @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' | |
| 17 | 19 | */ |
| 18 | 20 | export function dialogFocusOf( |
| 19 | 21 | model: PaneState.PaneModel, |
| 20 | 22 | element: string | undefined, |
| 21 | -): PaneState.DialogFocus | null { | |
| 23 | +): PaneState.DialogFocus | 'stay' | null { | |
| 22 | 24 | const entries = dialogEntriesOf(model) |
| 23 | 25 | const paths = entries.map(entry => entry.path) |
| 24 | 26 | const keys = entries.map(entry => Sections.fileKeyOf(entry)) |
| 25 | 27 | 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 | + | |
| 26 | 34 | 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 | |
| 29 | 42 | const isRow = selectedPath !== null && landing !== undefined |
| 43 | + const isWrap = isFar && (isOverEnd || isOverStart) | |
| 30 | 44 | |
| 31 | - return isRow ? { selectedPath, landing } : null | |
| 45 | + return isWrap ? 'stay' : isRow ? { selectedPath, landing } : null | |
| 32 | 46 | } |