spacehub

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

diff tests and README: the walk selects and the window followsBrowse files
poteat authored on Sep 13, 2026 parent df23590 · commit 01e6ae421fc1
5 changed files+46 -13compared with df23590
Mmods/diff/README.md
Mmods/diff/tests/fixtures/in-repository.ts
Mmods/diff/tests/fixtures/index.ts
Amods/diff/tests/fixtures/ring-onto.ts
Mmods/diff/tests/views.test.ts
@@ -22,9 +22,10 @@
2222 layout (`CLAUDE_CODE_NO_FLICKER=0`, which `/diff` learns from the command's
2323 `presentation`) the pane opens inline at any width, focused and as tall
2424 as its content (the open's `rows`), in the built-in dialog's shape: the
25-title, the count, five file rows at a time between `more files` rows that
26-page them, the key hints; the arrows walk the rows, Enter shows that
27-file's hunks alone,
25+title, the count, five file rows at a time round the selected one (`❯`,
26+where the focus ring starts; the plugin follows the ring's walk through
27+`ui.focus` and re-centres the rows as the built-in does), the key hints;
28+Enter shows that file's hunks alone,
2829 Escape backs out to the list and then closes, leaving `Diff dialog
2930 dismissed`; toasts are held while it is up. A file's ask button arms that
3031 file: its hunks ride the next prompt as context, once.
@@ -52,6 +53,7 @@
5253 | `command.run` of `diff` | Opens or closes the pane (focused and closing on Escape without the fullscreen layout), says which, and remembers the choice. |
5354 | `ui.close` of the pane | Backs out of the dialog's detail view instead of closing; else remembers the person's close as `/diff`'s. |
5455 | `ui.scroll` of the pane | Docked, moves the hunks under the pinned header and list (three rows a wheel tick, a page a page key), or the list when the wheel is over it, and keeps the engine's window still. |
56+| `ui.focus` in the pane | In the dialog's list, selects the file the ring lands on, re-centres the five rows on it, and lands the ring where that row now sits. |
5557 | `command.run` of `clear`, `resume` | Closes the pane and forgets the session's state. |
5658 | `tool.call` of `Edit`, `Write`, `NotebookEdit` | After the edit, refreshes an open pane; the session's first successful edit opens it. |
5759 | `tool.call` of `Bash`, `PowerShell` | After the command, refreshes an open pane. |
@@ -22,6 +22,7 @@
2222 answers: Readonly<Record<string, string>> = REPOSITORY,
2323 ) {
2424 const runs: Args<'process.run'>[] = []
25+ const focused: Args<'ui.focus'>[] = []
2526 const opened = keeping<Args<'ui.open'>>()
2627 const closed = keeping<Args<'ui.close'>>()
2728 const clock = startsSession(on)
@@ -32,6 +33,12 @@
3233 return { value: gitIn(e.argv, answers) }
3334 })
3435
36+ on('ui.focus', (_engine, e) => {
37+ focused.push(e)
38+
39+ return {}
40+ })
41+
3542 on('ui.open', opened.hook)
3643 on('ui.close', closed.hook)
3744 on('ui.invalidate', () => ({ value: undefined }))
@@ -39,5 +46,5 @@
3946 on('session.messages', () => ({ value: [] }))
4047 mock.store(on)
4148
42- return { runs, opened: opened.kept, closed: closed.kept, clock }
49+ return { runs, focused, opened: opened.kept, closed: closed.kept, clock }
4350 }
@@ -19,6 +19,7 @@
1919 export * from './renamed.js'
2020 export * from './repository.js'
2121 export * from './repository-of.js'
22+export * from './ring-onto.js'
2223 export * from './session.js'
2324 export * from './settle-ms.js'
2425 export * from './starts-session.js'
@@ -1,0 +1,18 @@
1+import type { UiFocusInput } from 'claude-code'
2+
3+import { PANE } from './pane.js'
4+
5+/**
6+ * The person walking the pane's focus ring onto one of the plugin's
7+ * elements, as the engine raises it before the ring moves.
8+ *
9+ * @param key the element's key
10+ * @returns the `ui.focus` input
11+ */
12+export const ringOnto = (key: string): UiFocusInput => ({
13+ component: 'Pane',
14+ requestId: PANE.requestId,
15+ plugin: 'diff',
16+ element: key,
17+ origin: { kind: 'person' },
18+})
@@ -140,7 +140,7 @@
140140
141141 expect(drawn).toContain('Uncommitted changes (git diff HEAD)')
142142 expect(drawn).toContain('2 files changed +3 -1')
143- expect(drawn).toContain(' app.ts')
143+ expect(drawn).toContain('\u276f app.ts')
144144 expect(drawn).toContain(' lib.ts')
145145 expect(drawn).not.toContain('+const a = 2')
146146
@@ -171,7 +171,7 @@
171171 )
172172 })
173173
174- test('off fullscreen, forty files list five at a time', async ($, on) => {
174+ test('off fullscreen, the window follows the walk', async ($, on) => {
175175 const world = Fixtures.inRepository(on, Fixtures.MANY_FILES)
176176
177177 await $.session.start(Fixtures.SESSION)
@@ -180,19 +180,24 @@
180180
181181 const drawn = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE))
182182
183+ expect(drawn).toContain('\u276f file0.ts')
183184 expect(drawn).toContain(' file4.ts')
184185 expect(drawn).not.toContain('file5.ts')
185186 expect(drawn).toContain(' \u2193 5 more files')
187+ expect(await $.ui.focus(Fixtures.ringOnto('file:file3.ts'))).toEqual({})
186188
187- expect(await $.ui.press({ plugin: 'diff', key: 'files-down' })).toEqual({
188- element: 'files-down',
189- })
189+ expect(
190+ world.focused.map(focus => focus.element),
191+ 'its row once centred',
192+ ).toEqual(['file:file2.ts'])
190193
191- const paged = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE))
194+ const walked = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE))
192195
193- expect(paged).toContain(' \u2191 5 more files')
194- expect(paged).toContain(' file9.ts')
195- expect(paged).not.toContain('file4.ts')
196+ expect(walked).toContain(' \u2191 1 more file')
197+ expect(walked).toContain('\u276f file3.ts')
198+ expect(walked).toContain(' file5.ts')
199+ expect(walked).toContain(' \u2193 4 more files')
200+ expect(walked).not.toContain('file0.ts')
196201 })
197202
198203 test('off fullscreen, the dialog draws at any width', async ($, on) => {