Skip to content

feat(fork): files reopen where the reader stopped - #163

Open
orbitingflea wants to merge 1 commit into
mainfrom
feat/file-reading-position
Open

orbitingflea wants to merge 1 commit into
mainfrom
feat/file-reading-position

Conversation

@orbitingflea

@orbitingflea orbitingflea commented Nov 15, 2026 •

Copy link
Copy Markdown
Owner

This pull request makes a file in the right panel open where the reader stopped.

改了什么行为

Behaviour change: yes, a web or desktop user who scrolls a code file, a rendered Markdown file or a PDF.js document in the right panel finds it at the same place after switching tabs, closing and reopening it, or reloading or restarting the app (same browser profile, for 30 days); a citation that names a line still jumps to that line.

  • A citation jumps once. After it has landed, a tab switch or a reload brings back the reader's later place, and the cited line stays highlighted as before.
  • Closing a cited tab and opening the same citation again now jumps to the line. Before, this did nothing while the panel stayed open.
  • Large text files, CSV/TSV tables, HTML pages, the browser's own PDF viewer and attachments still open at the top.

Why

Two file tabs of one workspace share one file panel, and each viewer is keyed by path. So a tab switch mounted a fresh scroll container at the top, and nothing saved where the reader was.

Checks

  • Unit tests for the store: expiry, the entry cap, corrupt and wrong-version entries, a full quota, storage that throws, and reveal receipts through the real panel store.
  • Browser tests: tab switch and panel remount with an offset inside a line, a citation over a saved place, an unrelated tab closed, shorter contents, rendered Markdown with its custom scrollbar, and close and reopen of a code and a Markdown citation. The reopen tests fail on main.
  • The repo's checks for changed files pass. In the running app, a file scrolled to 6000 px came back to 6000 px after a tab switch and after a reload, for code and rendered Markdown, at desktop and phone size. Before the change it came back at 0.

How to undo

Revert the commit. The saved positions stay in the browser under the t3code.fileReading.v1: and t3code.fileReveal.v1: keys and are ignored.

Design notes
  • fileReadingStore.ts is the storage, with no DOM: one localStorage key per file and view, decoded entry by entry, 30-day expiry, at most 300 positions and 200 reveal receipts. An in-memory age index evicts on insert. A full quota drops expired entries and the oldest half once, then keeps positions in memory for the page.
  • A position is an anchor, not a pixel offset: a line plus the offset into it (from Pierre's getNumericScrollAnchor) for code, and a top-level block plus a fraction for Markdown. PDF.js reuses its own view state.
  • Only scrolls that follow reader input are saved, so a restore, a reveal or a late layout reset never overwrites a saved place. A restore holds its anchor for at most one second, and input stops it.
  • Which reveal wins: within a page load, the panel store builds a new surface object for every openFile. So a reveal is shown once its object has landed. The reveal hook gets a number per object instead of the store's request id, which restarts at 1 after a close. Receipts carry the shown state across reloads. A read-only store subscription forgets the receipts of closed tabs. The change makes no write to the right panel store. A settleFileReveal store action, like the one for pull requests, would let most of this go later.
  • fileReadingSave.ts holds the PDF part, so the chat view's PDF frame does not load Pierre's file classes.
  • Upstream lines: FilePreviewPanel.tsx +34 −9 and BrowserDocumentFrame.tsx +11 −2. The README's fork list gains one line.
  • No mobile change. The mobile app has its own file viewer.

A file tab scrolled halfway opened at the top again after a switch to
another tab, a reopen or a reload, because each viewer remounts with a
fresh scroll container.

The source and rendered Markdown viewers now save the reader's place in
localStorage (one key per file and view, 30-day expiry, 300-entry cap)
and restore it on mount. PDF.js seeds its view from the same store.
Only scrolls after reader input are saved. A line reveal still wins
until it has landed once; a new request always reveals, even when the
panel store restarts its id at 1 after a tab was closed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted Author is trusted by repo permissions or the VOUCHED list. size:XL labels Nov 15, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL vouch:trusted Author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant