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

claude-code / mods / diff / README.md
105 lines · 7.1 KBPreviewCodeRaw
1# diff
2
3The diff pane as a plugin: `/diff` opens the session's uncommitted changes
4beside the transcript, one row per changed file and every file's hunks
5beneath, and closes it again; each toggle leaves `Diff panel shown` or
6`Diff panel hidden` in the transcript. The header, the file list and its
7toggles stay put while the wheel moves the hunks under them three rows a
8tick, or the list a file a tick while the wheel is over a list longer than
9its eight rows (the plugin answers the pane's `ui.scroll` itself); a row's
10click puts that file's hunks at the top; the list also scrolls under the
11built-in's list keys (`ctrl+up`/`ctrl+down`, `opt+up`/`opt+down`), and
12`ctrl+x b` moves the comparison base on, as the built-in's chord does: both
13through Buttons that declare the engine's own actions. The pane refreshes
14as Claude edits and runs shell commands, and while it is open it polls
15the repository's HEAD so a commit or checkout made elsewhere shows too.
16The main loop's first successful edit of a session the diff has a file to
17list for opens the pane by itself, as the built-in panel opens on its first
18checkpoint: where the layout docks it beside the transcript (the fullscreen
19layout, which each drawing's `viewport` says), the terminal is wide enough
20(144 columns when the person never chose, 110 when they kept it open
21before; a person who closed it is left alone) and file checkpointing is on;
22a subagent's edit opens nothing, and where the surface does not say,
23nothing opens by itself. An edit to a file outside the repository, or one
24after which the diff lists nothing or cannot be read, opens nothing and
25leaves the opening to a later edit. A docked pane fetches before it opens,
26as the built-in panel primes its data, so it never lands on
27`Loading diff…`; an open the engine leaves waiting undrawn is withdrawn, so
28no later resize seats it, and the next edit asks again. A session resumed
29or continued whose transcript already holds such an edit opens the pane on
30the same terms as soon as the width is known, as the built-in opens on the
31history it restores.
32
33Under the fullscreen layout a terminal under 110 columns gets the
34built-in's line asking for a wider one and nothing opens. Without that
35layout (`CLAUDE_CODE_NO_FLICKER=0`, which `/diff` learns from the command's
36`presentation`) the pane opens inline at any width, focused and as tall
37as its content (the open's `rows`), in the built-in dialog's shape: the
38title, the count, five file rows at a time round the selected one (`❯`,
39where the focus ring starts; the plugin follows the ring's walk through
40`ui.focus` and re-centres the rows as the built-in does), the key hints;
41Enter shows that file's hunks alone,
42Escape backs out to the list and then closes, leaving `Diff dialog
43dismissed`; toasts are held while it is up. A file's ask button arms that
44file: its hunks ride the next prompt as context, once.
45
46The pane compares the working tree against HEAD, split at the session's
47start (the default; the start the engine gives in `$.session.usage()`, so a
48resumed session keeps its first and `/clear` begins anew), against HEAD
49plainly, or against the merge-base with
50the default branch; the base line under the header names a base other than
51the session's, and the choice is kept per repository in the plugin's store.
52A picker shows one earlier turn's edits instead of the working tree, read
53from the session's messages. Files that changed before the session started
54(by their timestamp, among the paths already dirty when the pane first
55read the repository), and noise (lockfiles, generated and test files), are
56listed apart and folded until asked for; a rename lists as git prints it.
57Outside a git repository `/diff` says so and does nothing else.
58
59Git runs when the built-in panel's would: nothing at the session's start;
60one `git rev-parse`, in the directory the session started in, when `/diff`
61or the first edit a pane has room to open on first needs the repository
62(an answer of no repository is kept too, until `/clear` or `/resume`
63forgets it); and the working tree is read only by a fetch for a pane that
64is open, after an edit that landed or a shell command that ran, or by the
65fetch each edit inside the repository, with room for a pane, makes until
66one lists a file and the pane opens on it. The one read the built-in has
67no counterpart for is a `git status` at the first of those fetches, which
68stands in for the change time the built-in dates a moved file by.
69
70`hooks/register.ts` is the module; everything under `hooks/` is its parts.
71
72## What it hooks
73
74| event | what the hook does |
75| --- | --- |
76| `session.start` | Binds the engine once and registers `/diff` (a session where another `/diff` is listed leaves the plugin idle); asks nothing of the repository, which `/diff` or the first edit pins when it comes; off its dispatch, reads the transcript, and for a resumed session whose turns edited opens the pane as the first edit would. |
77| `ui.render` of `PromptHint` | Reads the terminal's width and whether its layout docks a pane, which decide whether the first edit may open the pane. |
78| `ui.render` of `Pane` | Draws the pane: docked, the header, base line, source picker, file list and toggles over the window of hunks; inline, the dialog. |
79| `command.run` of `diff` | Pins the repository when none is, opens or closes the pane (focused and closing on Escape without the fullscreen layout), says which, and remembers the choice. |
80| `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. |
81| `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. |
82| `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. |
83| `command.run` of `clear`, `resume` | Closes the pane and forgets the session's state, the pinned repository with it. |
84| `tool.call` of `Edit`, `Write`, `NotebookEdit` | After an edit that landed (not refused, not failed), refreshes an open pane; the main loop's first such edit inside the repository whose fetch lists a file opens it on that fetch, pinning the repository then if the terminal has the room and checkpointing is on. |
85| `tool.call` of `Bash`, `PowerShell` | After a command that was not refused, failed and interrupted ones too, refreshes an open pane. |
86| `prompt.submit` | Adds the armed file's hunks to the prompt's context and disarms. |
87
88## What it calls on `$`
89
90`clock.after`, `clock.every`, `clock.now`, `command.register`, `env.get`
91(`CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING`), `fs.list`, `fs.read`, `fs.stat`,
92`process.run` (git, read-only), `session.id`, `session.messages`,
93`settings.read`, `store.get`, `store.set`, `telemetry.log`, `telemetry.mark`,
94`ui.close`, `ui.invalidate`, `ui.log`, `ui.open`, `ui.resolve`, `ui.status`.
95
96`$.telemetry` is the telemetry plugin's noun; where it is absent the rows
97are dropped and nothing else changes.
98
99## Try it
100
101```sh
102claude --plugin-dir /path/to/diff
103```
104
105then `/diff` inside a git repository with a modified file.