Skip to content

Pull request view: the rest of T3 Code (code options, checkout, stacks, workflow approvals, tabs) - #293

Merged
stippi merged 9 commits into
mainfrom
feature/pr-view-t3-gaps
Oct 30, 2026
Merged

stippi merged 9 commits into
mainfrom
feature/pr-view-t3-gaps

Conversation

@stippi

@stippi stippi commented Oct 30, 2026

Copy link
Copy Markdown
Owner

Closes the remaining gaps between the pull request view (#292) and T3 Code's, except the Guide tab. Each part follows T3's behaviour and texts; docs/pull-request-view.md describes all of it.

Code tab

  • Stacked | split (remembered): split rows pair a hunk's removed and added runs, old numbers left, new right; new and deleted files stay one column; threads and comments go below the row showing their line.
  • Hide whitespace changes (on by default, like T3): GitHub's API has no whitespace-free diff, so like T3 each hunk is diffed again without whitespace, per page off the UI thread.
  • Wrap (remembered): unwrapped rows scroll sideways together per file; the line numbers stay put.
  • Expand context: gaps between hunks and the unknown tail get T3's buttons (100 lines up or down, or all; shift-click for all). The first click reads the file through pull_request_file_contents, one read per file at a time, and highlights both whole sides.
  • File tree (right side, remembered): folders with a single child folder are drawn as one row; files are tinted by their change with its letter. A click unfolds the file and scrolls to it.
  • On narrow toolbars, the whitespace, wrap and layout options fold into a menu.
  • DiffRows now draws one or two cells per row and selects by flat line, which a split chunk needs.

Check out

  • Works like gh pr checkout (git::pull_request):
    • The head comes from the PR repository's remote.
    • A fork's head is fetched as refs/pull/N/head, without adding a remote. It tracks the fork's branch when maintainers may push, otherwise the PR ref.
    • A fork branch named like the default (or base) branch becomes owner/branch.
    • An existing branch only fast-forwards.
  • In a separate worktree reuses the branch's worktree or creates one beside the project. A new session for the project works in it, knows the PR as its own, and opens with the PR beside it.
  • In this repository refuses to switch when there are tracked changes (as T3 does); the session follows its new branch.

Stacked pull requests

  • github reads stacks via repos/o/n/stacks?pull_request=N, revalidated with ETags; 404 means no stack.
  • On github.com, listings mark which rows sit in a stack.
  • Merging a stack uses merge-async and polls until GitHub settles.
  • A rebase first checks the stack is unchanged and every branch is writable. git::stack_rebase then replays the layers in a scratch repository and pushes with a lease. The credential only goes through GIT_CONFIG_*.
  • In the UI:
    • The header gets T3's stack menu (layers, base, Merge stack / Rebase stack) and a "Merge stack" button. Both ask for confirmation over the panel.
    • While a PR is in a stack, or its stack isn't known yet, the single-PR merge controls are hidden.
    • List rows get the "⧉ 2/3" popover, which reads the stack only once opened.

Workflow approvals

  • For an open fork PR, the detail read lists the runs waiting for approval and shows them as checks. The checks poll also revalidates the fork's runs.
  • "Approve workflows to run" takes the checks' place on the Summary tab (two clicks). Before approving it re-reads the head, and it refuses a head that another open PR shares.
  • The checks popover now orders checks the way T3 does: attention first, then running, then completed behind "Show all", each with a "Details" link.

Tabs

  • Each opened PR gets its own tab next to the list tab. You can:
    • close a tab with the button, a middle click, or the context menu (others / to the right / all);
    • reorder tabs by drag and drop;
    • scroll the tab row with arrows when it overflows.
  • Each tab keeps its page (scroll position, sub-tab, drafts). Only the visible tab reads data and polls.
  • Open tabs are remembered per session. The back arrow is gone, since the list is one tab away.

Verification

  • cargo fmt --check, cargo clippy --all-targets --all-features -D warnings and cargo deny check are clean, and the workspace tests pass. Three code_assistant_core tests (browser and recovery timing) failed only under a full parallel run and pass when run alone.
  • Tried in the running app against stippi/code-assistant, with an isolated config and data copy and a scratch clone as the project:
  • Not tried live:
    • Stack merge/rebase: no stacks exist in these repositories. Covered by tests with the fake transport and a local git remote.
    • Clicking "Approve workflows": no runs were waiting, and I didn't approve anything on GitHub.

GitHub holds the workflow runs of a fork's pull request until a
maintainer approves them. Like T3 Code, the detail read lists the runs
of the head waiting for approval (actions/runs?status=action_required)
and shows them as checks; the checks poll revalidates the fork's runs
with ETags too. The Summary tab offers "Approve workflows to run" in
place of the checks while there are some (two clicks); approving reads
the head again before each run and refuses a head other pull requests
share. The checks popover lists the checks needing attention first,
then the running ones, the completed ones behind "Show all".
DiffRows paints a row as one cell (stacked) or two (split: the old
file's line left, the new file's right, an empty side filled), and
either wraps the lines or keeps each on one row, scrolled sideways by
an HScroll all rows of a file share while the line numbers stay. The
selection and comment marks name flat lines instead of rows of a
chunk, since a split chunk's lines are not contiguous. diff::split
pairs a hunk's removed and added runs and cuts the rows into chunks
that end where something goes below a line.
The rest of T3 Code's Code tab options:

- Stacked | split (remembered): split rows pair a hunk's removed and
  added runs side by side with old and new line numbers; new and
  deleted files stay one column. Threads and comments sit below the row
  showing their line.
- Hide whitespace changes (on by default, as in T3): each hunk's sides
  are diffed again without whitespace, client-side like T3 (GitHub's
  API has no such diff); parsed once per page, off the UI thread.
- Wrap (remembered): unwrapped lines scroll sideways together per file,
  the line numbers stay.
- Expanding context: the gaps between hunks and the unknown tail get
  T3's buttons (100 lines up / down, or all; shift-click all). The
  first click reads the file's text through pull_request_file_contents,
  one read per file at a time, and parses both sides for highlighting.
- The file tree on the right (remembered): folders holding one folder
  drawn as one row, files tinted by their change with its letter; a
  click unfolds the file and scrolls to its header; more pages load
  from its footer.
- Narrow toolbars fold whitespace, wrap and layout into one menu.
"Check out ▾" now checks out, as gh pr checkout does (git::pull_request):
the head branch fetched from the base repository's remote, a fork's head
as refs/pull/N/head without adding a remote, tracking the fork's branch
when maintainers may push (else the pull request's ref); a fork's branch
named like the default branch becomes owner/branch; an existing branch
only fast-forwards.

- In a separate worktree: the branch's worktree is reused, else one is
  made beside the project; a new session for the project works in it,
  knows the pull request as its own and is shown at once.
- In this repository: tracked changes refuse it (as in T3 Code); the
  session follows its new branch.

The page says where it landed in T3's words, or warns when the checkout
is not on the pull request's head. Gpui::open_session replaces three
copies of the make-current-and-load sequence.
Ported from T3 Code: Client::stack reads the stack a pull request is a
layer of (repos/o/n/stacks?pull_request=N, ETag-revalidated, then the
stack's own read for titles, drafts and heads; 404 means none); listings
on github.com mark where their rows sit in a stack (aliased
PullRequestStackMembership, failing quietly); merge_stack merges through
one layer with merge-async and polls until GitHub settles; stack_rebase
checks the stack is as the viewer saw it and every open branch may be
pushed to, and hands back what a rebase needs.

git::stack_rebase replays each layer onto the rebased one below in a
scratch repository and pushes it with a lease on the head it had; the
credential goes through GIT_CONFIG_* in the environment.
The core reads a pull request's stack through the cache (60 s, like T3)
and runs stack actions: merging the stack through a layer, or rebasing
it from its top in a scratch repository; either way every layer is read
anew (PullRequestPart::Stack).

The page shows T3 Code's stack controls in the header: "⧉ 2/3" with the
stack's menu (Stack #N and whether it may be stale, the layers top first
with their state, a click showing that pull request, the base, Merge
stack (k) / Rebase stack with T3's hint), "Merge stack" beside it, and
"Retry stack lookup" after a failed read. A confirmation over the panel
says what will happen in T3's words. While the pull request is in a
stack, or its stack is not known yet, the single merge controls stay
away. Listed pull requests in a stack (github.com) show "⧉ 2/3"; its
popover reads the stack only when opened.
Like T3 Code's right panel tabs, the panel keeps a tab per opened pull
request next to the list's: opening one that is open shows it, closing
the shown one shows its right neighbour (else the last, else the list);
tabs close by their button (which replaces the state glyph under the
pointer), a middle click or the context menu (others, to the right,
all), and move by drag and drop; too many scroll sideways with arrows.

Each tab keeps its page while open, so scroll, sub-tab and drafts
survive switching; only the shown page reads and polls (a page starts
hidden now). The open tabs and their sub-tabs are remembered per session
and come back with it; without any, the session's own pull request
opens. The back arrow is gone: the list is a tab away.
Found trying it in the app:
- Switching layout, wrap or whitespace rebuilt every row and the list
  jumped to the top; the row (or file) at the top now stays there.
- A gap shown whole still drew its section row; it goes with the gap.
- A pull request checked out into a worktree opens its session with the
  pull request beside it.
@stippi
stippi merged commit 83f2ce7 into main Oct 30, 2026
6 checks passed
@stippi
stippi deleted the feature/pr-view-t3-gaps branch October 30, 2026 14:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant