Repository navigation
feat(desktop): expand context lines in Files changed - #3762
Merged
Merged
Conversation
…anged The Files changed view led with a strip naming who opened the pull request, its reviewers, and who authored its commits. The Pull request tab's header above it already names the opener and the reviewers, so the strip goes, and the view leads with its files. "Commits by" stood nowhere else, so what only it read goes too: the changes answer's commitAuthors, the service's paged read of the pull request's commits, the co-author trailers read off them, and the App's bot avatar they were drawn by (GitHubApp.botAvatarUrl). Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…scroll Every draw of Files changed rebuilt every file's entry: it parsed each patch again to place review threads, spelled each list patch afresh, and reconciled every header and its two hints, so a J press on a pull request of 300 files spent about 55 ms in React and a scroll redrew the whole tab for each file it passed. Each file's entry is now kept while nothing it is drawn from changed, its parsed lines and list patch are read once per answer, the list's doors stay the same doors across draws, the top file is drawn only while no file is stood on, the threads the Pull request tab hands down are kept while the conversation and the minute stand, and a header mounts its hints only once the pointer or the keyboard comes to it. Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…ader's hint on the first hover Two findings from review of the lazy header hints and the quiet top file: the top file was held back while any file was stood on, even one the filter left out, so the bar named a stale file; and the pointer's first arrival on a fold or a letter mounted its hint without telling it the pointer was there. Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…ter event alone Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Shiki colouring a pull request's files was most of what a scroll through Files changed cost the window's thread: on a pull request of 122 files, about 1.3 s of a 4 s scroll, with frames up to a second long while a large file was highlighted, and again each time a file scrolled back into view. The list now hands highlighting to Pierre's own pool of two workers. The build bundles Pierre's worker whole as one classic script, its WebAssembly engine left out, and hands the diff bundle its text, which each worker is started from as a blob:, the one place the panel's policy admits a worker from. Each patch is read under a name of its own, so the pool's cache hands a file scrolled back into view its colours again. Where no worker can start, the list highlights on the window's own thread as before (@luke/panel/diff-view/highlight-pool). The diff bundle grows by the worker's own copy of Shiki, about 77 KB gzipped; the panel's bundle does not grow. Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
The pool is kept for the window's life, so a list drawn after the diff settings changed was highlighted in the look the pool was first started in. Each list now hands the pool its own look as it is drawn, as a list already did when its look changed while it stood. Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Each gap between a changed file's hunks, and the unchanged lines before the first and after the last, now opens as GitHub's diff does: twenty lines up or down a press, or all of them at once. The file is read whole only the first time one of its gaps is opened, at the pull request's head, through the contents read a File tab already makes (TASKS_FILE, raw, at that commit), and kept for the answer's life. Its text before is turned back from that text and its patch, every line no hunk holds being the same on both sides, so one read stands for both; a text that does not match the patch at every hunk opens no gap rather than drawing lines of another commit. No file is read whole for an agent on no task, or where the task's repository is not the pull request's. Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
luke-agent Bot
added a commit
that referenced
this pull request
Oct 18, 2026
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…hole, and say how they work A file the service never reads whole, a secret one, now offers no arrows on its gaps, and a file whose read the service refused, or whose text is not the one its patch was made against, closes its gaps on the next draw and says why in one quiet line above its first hunk. Pierre offers the arrows only for a file changed in place or moved with changes, so a file whose gaps are closed is told it only moved, which draws its hunks alike. The secret rule moves to @luke/features/task-wire, so the window and the service read one rule. A gap's arrow hangs a hint as the window's controls do: "Show 20 more lines" with "⇧-click for all" on a long gap, "Show these lines" on a short one. Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
luke-agent Bot
added a commit
that referenced
this pull request
Oct 18, 2026
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…nts its patch was made against, line endings kept Two findings from review of reading a file whole. The service reads a pull request's files and its head beside each other, so a push between them could pair a patch with a head whose hunks still match but whose lines between them do not, and those lines were drawn as unchanged on both sides. Each changed file now names the git object its contents after are (blobSha, from GitHub's own listing), and the window opens a file's gaps only where the text it read is that object. And a file whose lines end in a carriage return lost its gaps, because jsdiff drops the return from a patch's lines while the file's text keeps it; the patch is now read as written, each line split at its newline alone, and turned back with its endings as they were. Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…s lines and its refusals Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Oct 19, 2026
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
7 tasks done
14 tasks done
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The developer asked for expandable context lines in the Pull request tab's Files changed, as GitHub and stage-cli have. Every collapsed gap in a changed file now expands: the "N unmodified lines" between hunks, the lines before the first hunk, and the lines after the last. Each press opens 20 lines up or down, and expand-all (or shift-click) opens the whole gap. These are Pierre's own separator controls.
How the window gets the file
ACT_KIND.TASKS_FILE(GET /api/plans/{taskId}/file) withraw: trueandref: headSha, on the App's installation token, under the route's own refusals and 1 MiB bound.headShaalready comes back with the changes answer (feat(desktop,service,features): draw changed images before and after in Files changed #3638).textsOf(@luke/panel/tasks/changes-model): every line outside a hunk is the same on both sides, so the base is the head with each hunk turned back, keeping its context and-lines and dropping its+lines. "No newline at end of file" is handled on either side.blobSha, an optional key on the changes answer). The window opens a file's gaps only when the git blob SHA of the text it read (blobShaOf) matches that blob. The service reads the files and the head side by side, so a push between those reads could otherwise pair a patch with newer lines in its gaps (found by Devin). A service from before this change sends noblobSha, and the hunk check below stands alone.+lines differ from the head text at that hunk's place, the file opens no gap. It never draws lines from another commit.\nonly, so CRLF files keep their\ron both sides (also found by Devin).When the file is read
loadDiffFilesasks for a file the first time one of its gaps is pressed, and hydrates that file's patch in place.No dead arrows
Gaps are offered only where they can open. Pierre offers a gap's arrows only for a file whose kind is "changed in place" or "moved with changes". It draws hunks the same whatever the kind, so a file that must not expand is handed to Pierre told it "only moved" (
drawnAs, with no cache key, so Pierre doesn't reuse a drawing that had arrows). That gives per-file control without patching Pierre.Known up front: secret paths (
.env*) and files not changed in place get no arrows. The secret rule moves to@luke/features/task-wireso the window and the service share one rule.Refused after reading: a file the route refuses ("too large or not plain text"), a file whose head doesn't match its patch, and a failed read all close that file's gaps on the next draw. Each shows one quiet line above the first hunk saying why:
The line sits above the file's first hunk rather than inside each gap, because the separators are Pierre's own markup.
Hint on the arrows: a long gap's arrow says "Show 20 more lines" with "⇧-click for all"; a short gap's arrow says "Show these lines". It's the window's own
TooltipPill, anchored to the arrow inside Pierre's shadow root.Which files can expand
Where nothing is read
planIdnull).Extra GitHub requests: none up front, since
blobShacomes from the file listing GitHub already returns. Each file costs one contents read atheadShaon its first expand. The service keeps the App's reach and installation token cached, so a warm expand is just that one request; a cold one also mints a token, as a File tab read does today.Layout, threads and selection
expandHunkinsideCodeView. It re-measures the item, so sticky headers and the top-file tracking follow.commentLinesis unchanged).Highlighting: hydrated files are highlighted in the worker pool from #3752.
Screenshots
PR #2908's
build.mjsin the realAgentPullRequestTab, drawn by the harness, with a review thread on line 356.A gap's arrow hint, light and dark:
A refused file after its first press: its arrows are gone and it says why (light, dark):
The trailing gap reads "More unchanged context may be available" before the file is read, then opens to the file's end:
Evidence
tsc --noEmitfor desktop and panel: clean../scripts/oxlint.sh: 0 errors.pnpm knip: clean../scripts/repository-checks.sh: passed.biome check .: no errors.vitest run --project desktop --project panel: 222 files, 2254 tests, all passed.packages/service/src/tasksandpackages/features/src: 775 passed.changes-model.test.ts: the base rebuilt correctly wherever the hunks fall (middle, first line, last line, additions only, removals only, hunks far apart); all four newline-at-end cases; a rename turned back; added, deleted and omitted files not turned back; a mismatched context line, added line or short file refused.agent-changes-tab.test.ts:headSha, raw, and only when its gap is first opened. Nothing is read up front, and an added file isn't read.diff-view.jsis 256,351 gzipped bytes, under the 256,515 baseline from perf(desktop): highlight Files changed off the main thread #3752.panel.jsis unchanged within noise.Invariants
blobShaon each file.as.Effect.run*.PRIVACY.mdunchanged. File text was already read through this route.AGENTS.mdchange.Notes
console.errorfor that one load. Its arrows are gone from the next draw.Made with Luke