Skip to content

[editor] Beta 1.3#749

Draft
amadeus wants to merge 118 commits into
mainfrom
beta-1.3
Draft

[editor] Beta 1.3#749
amadeus wants to merge 118 commits into
mainfrom
beta-1.3

Conversation

@amadeus

@amadeus amadeus commented May 29, 2026

Copy link
Copy Markdown
Member

Used to track editor beta versions. Will be periodically rebased on main.

@vercel

vercel Bot commented May 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pierre-docs-diffs Ready Ready Preview Jul 7, 2026 9:31pm
pierre-docs-diffshub Ready Ready Preview Jul 7, 2026 9:31pm
pierre-docs-trees Ready Ready Preview Jul 7, 2026 9:31pm
pierrejs-diff-demo Ready Ready Preview Jul 7, 2026 9:31pm
pierrejs-docs Ready Ready Preview Jul 7, 2026 9:31pm

Request Review

@amadeus amadeus mentioned this pull request May 29, 2026
15 tasks
amadeus and others added 30 commits June 29, 2026 15:35
* Sidequest: Rework how old/new files and parsing works

This was a to do that will make the partial diff hydration work a lot
more reasonable

* Phase 1: Types and helpers

Flesh out the core hydration utility function, setup types for the
loaders, and add tests to make sure hydration works properly

* Phase 2: Rework how `isExpandable` works

* Phase 3 & 4: Hook up the actual hydration actions

* Phase 5: Add basic error throwing

* Phase 6: Rounding out some final tests

* Phase 7: Scaffolding for forgotten bottom region...

* Phase 8: Render the new faux bottom hunk lad

* Phase 9: Add some hardening tests

* Phase 10: Update virtualized components to properly account for final separator

* Phase 11: More tests

And some cleanup

* Fix expansion in CodeView

This was actually a big bug from before, where we didn't properly handle
the changes

* Update demo to test different hydration situations with CodeView

* Phase 12: Make priming awaitable

* Phase 13: Actually prime the cache if there's a worker pool

* Phase 13b: Quick timeout in case the highlight is pathological

* Phase 14: Tests n shit

* Misc fixes

* Codex review fix

* Hopefully fix some flakey tests

* Phase 15: Setup hydration guards

Mostly some prep work to ensure you can never go from non isPartial to
isPartial... since it will create a ton of UX issues

* Phase 16: Add some basic hydration handling for react lifecycle

* Phase 17: New options based callback implementation for React

* Phase 18: Ensure react uses the new hydrated diff

* Phase 19: Some misc wiring to ensure react isn't fully out

* Phase 20: Update/fix tests

* Some more demo improvements for codeview testing

* bugfix: ensure we don't show expansions on new/deleted files

* WIP SLOP

* Add initial support for github tokens

* Misc polish items for the token interface

* Refactor everything to use mutability...

* Refactored implementation

The goal here is to feel a bit less gross around the react components,
therefore I'm relying on mutation for default components normally, but
then for CodeView we opt into a cloned/copied variant

* Naming tweaks

* Misc review cleanup

* Diffshub tweaks:

* only allow expansion if a token is provided (the api rate limits way
  to quick)
* fix some pr feedback, unclear what it was fixing

* Fix base sha fix from code review

* Fix a subtle console.log issue with NextJS and the shared CodeView options prototypes

* Fix for the precise windowing bug i discovered on expansion

* Improve tests a bit more

* Fix bug with url parsing

* Improve cacheKey logic a bit

* Modestly improve re-fetches...

Won't really fix anything in practice because AI is dumb

* Phase 1: Update misc docs surrounding the new null semantics

* Sidequest: Fix up exported types and stuff, harden a few things as well

* Basically realized that the docs were inheriting some pretty garbage
  annotation examples because we weren't properly hydrating.
* Also realized some tests were pretty dumb

* Phase 3: Vanilla JS API docs

* Phase 4: CodeView content updates

* Phase 5: Core types documentation updates

* Phase 7: Few more cacheKey tweaks and stuff

There was no need for phase 6

* Fix types in diffshub with new types rework
…881)

* bugfix: Allow virtualized filediff to accept FileDiffMetadata updates

A pretty big derp with how the diff is resolved lived here, mostly
didn't notice it because CodeView was not susceptible to it...

* Fix bug with hydration

* Add a regression test

* Fix hydration derp
* fix(diffs): fix cursor movement handling for backward multi-line selection

* Fix selection merging

* test(diffs): cover backward direction when merging selections

When overlapping selections merge, the result takes its direction from
the most recently created selection, so the merged caret stays where
the user last put it. Two paths had no tests: when the latest selection
is already backward, and when a later bare caret lands on the merged
start and the direction is derived as backward.

Add a test for each so this focus-preserving behavior is locked in.

---------

Co-authored-by: Nicolas Gallagher <239676+necolas@users.noreply.github.com>
* Smol fixes

* Fix styles that will break codeview
* Add an easy commented out field for the dev check

* Prevent rendering of CodeView before worker pool is initialized

* Add test for worker readiness

* Smol corrections for annotation errors

* Be able to handle a failing worker pool gracefully

* PR Review Feedback: Fix up test to use spyOn

* PR review feedback: trigger an initialization for the worker pool if needed
In packages/diffs/src/react/EditorContext.tsx, Editor was imported as a
value but is only ever used in type positions; the sole runtime use is
editor.cleanUp() on the editor parameter, not the Editor class.

Convert it to a type-only import so the binding is guaranteed erased from
the JS output under verbatimModuleSyntax. This removes any static runtime
coupling from @pierre/diffs/react to the editor module graph (and its
top-level Intl.Segmenter side effect in editor/selection.ts) for
consumers that never use the editor. EditorContext/EditorProvider/useEditor
remain functional.

Co-authored-by: Claude <noreply@anthropic.com>
To reproduce, in the diff editor on Safari:

1. Click into the additions side and type text on a line.
2. Press cmd+Backspace.

Nothing is deleted, though cmd+Backspace deletes to the line start in
Chrome.

Safari reports cmd+Backspace as the deleteHardLineBackward input type
where Chrome reports deleteSoftLineBackward; the editor only handled the
latter, so Safari's cmd+Backspace was dropped. Route both to the same
handler. They differ only on a wrapped line (hard deletes to the logical
line start, soft to the visual one), and Chrome's soft behavior is the
one we match.
…ed wait) (#919)

* diffs: deflake editor active-line-highlight test (poll instead of fixed wait)

The active-line-highlight tests asserted the highlight DOM after a fixed
10ms wait. Under load the async shiki + decoration pass hadn't applied the
data-selected-line attributes (or even initialized the editor's text
document) within 10ms, so the assertions saw empty results and flaked.

Add a poll-until-settled waitFor helper to the test harness and replace the
fixed waits before each highlight assertion (and the fixture's post-edit
wait) with polls on the actual expected DOM condition. Test-only change; no
production code touched.

* diffs: gate active-line-highlight selection setup on editor doc init

The deflake poll waited only for rendered content rows before
setSelections(). But fileDiff.render() renders rows synchronously
(from a worker/render cache or a plain-text fallback) while the
editor's text document is created later, inside the async
initializeHighlighter().then(editor.__syncRenderView) callback in
FileDiff.syncRenderViewToEditor(). Until that callback runs,
setSelections() throws "Text document is not initialized", so a slow
highlighter load could still flake CI.

__syncRenderView sets contentEditable = 'true' on the [data-content]
element in the same synchronous block that assigns the text document,
so poll on the content element becoming contenteditable (with rows
present) — a direct proxy for the document being initialized and
setSelections being safe.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Open the editor docs page (/edit) and, a moment after it loads, the
page scrolls itself down to the find-and-replace demo instead of
staying at the top.

The demo opened the find panel and seeded a query on load. Running
that search makes the editor reveal the first match with
scrollIntoView, which scrolls every ancestor up to the page, so
while the demo sat below the fold the page jumped down to it. Leave
the search input blank instead: with no query there is no match to
scroll to, so nothing moves. The panel still opens empty as the
reader reaches it, ready to type.
* [diffs/editor] fix page jitter when add/removel line

* Fix refreshDiffView function

* Fix `moveCursorToDocEnd` command for diff edit

* Fix scrollToLine method

* Refactor

* render separators

* refactor

* fix render range

* fix scroll to end line

* fix `recomputeEmptyDocumentDiff` function

* Remove 'rerenderFromDocument'  logic, force use file name as the cache key

* fix updateRenderCache method

* fix cache key

* fix testings

* refactor

* fix test

* fix test

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix `isLineVisible` for diff view

* Improve `isLineVisible` method

* fix caret scrolling

* Improve `applyDocumentChange` method

* Enhance `getDocumentBoundarySelection` to correctly handle trailing blank lines and add corresponding unit tests

* rebase onto beta-1.3

* Add `ensureCacheKey` method to streamline cacheKey assignment logic

* revert chnages on  test/editorDisplayOptionResync.test.ts

* fix rebase

* Update playground

* Fix live edtting demo

* refactor

* Refactor EditorTokenizer to centralize grammar loading logic with #ensureGrammar method and add unit test for dynamic grammar loading

* fix(diffs): render edits after the editor detaches and re-attaches

On the /edit demo, toggle Edit mode off and back on, or switch the
surface between File and Diff, then type: the caret appears but the
typed characters never show up, even though the document records them.

Detaching the editor (cleanUp) tears down the tokenizer but left the
parsed document and its file identity in place. On re-attach,
__syncRenderView saw the same file name, lang, and cacheKey, treated
the file as unchanged, and skipped the rebuild that recreates the
tokenizer; with none, #rerender bailed before painting. Release the
document and file info in cleanUp so the next edit() rebuilds both
from the host's current contents.

Also drop a stale LiveEditing comment about recreating the editor per
control change, which the dependency array no longer does.

* Fix & refactor

- alway ensure change even no editor attended
- remove `applyContentEdit` and `recomputeContentHunks`

* fxi setSelectedLines function

* Fix find demo

* Fix scrolling of setSelections

---------

Co-authored-by: Nicolas Gallagher <239676+necolas@users.noreply.github.com>
* v2 of agent ui fullscreen

* make it nice

* tweaks

* better

* feedback

* fix transition
* Blend the edit mode backgrounds

* trim comments

* fix(diffs): recompute selection corner masks after theme changes

Rounded selection corner masks capture the resolved line-background color
when the selection is drawn, so a theme swap (light/dark toggle or theme
name change) left them showing wrong-colored corners on diff-colored lines
until the selection moved. The tokenizer now fires an onThemeChange callback
from #emitThemeChange (covering the system observer, matchMedia, and
syncTheme paths, and the editor re-renders the selection overlay on the
next frame so the corners recompute against the new colors.
EOF
)
…uard usage (#914)

Move the monorepo browser baseline to browsers with native Intl.Segmenter
support, which the diffs editor relies on. Firefox 125 is the binding
constraint (Chrome 87+, Edge 87+, Safari 14.1+ are already covered), so
bump firefox >= 120 to firefox >= 125 in .browserslistrc.

Make the editor's Intl.Segmenter usage safe at import time so importing
the editor never throws on engines without it:

- Add createSegmenter() (feature-detected) and a lazily-cached
  getGraphemeSegmenter() in editor/utils.ts, replacing the module
  top-level grapheme segmenter in selection.ts.
- Guard every segmenter call site (word + grapheme in selection.ts, two
  grapheme in textMeasure.ts) with a minimal code-point/regex fallback
  for engines lacking Intl.Segmenter. Behavior is unchanged on supported
  browsers.

Co-authored-by: Claude <noreply@anthropic.com>
* rename

* fix height
To reproduce, in the diff editor on Safari:

1. Click into the additions side.
2. Select all (cmd+a), then press Backspace or Delete.

Nothing is deleted — the additions can't be cleared — though it works
in Chrome.

The editor paints selections with an overlay and leaves the native
selection a collapsed caret. After select-all the caret sits at the
document start, and Safari fires no delete beforeinput when nothing
precedes the caret, so the delete is dropped; Chrome fires it anyway
and deletes via the editor's own selection. Give WebKit a
non-collapsed native selection so it emits the delete; the edit still
runs on #selections, which spans the whole document.

Only rendered lines resolve to DOM nodes and the diff is virtualized,
so anchor the native range to the editable lines currently on screen
rather than the document bounds — otherwise it stays offscreen in a
long file and Safari drops the delete again. A one-shot guard keeps
the resulting selectionchange from reading that shorter range back
over #selections; the next keydown or pointer press (mouse, touch, or
pen) clears it.
* Misc fixes
* Stable updates
* [diffs/editor] Support `moveLineUp` and `moveLineDown` commands

* fix "Clamp moved selections at EOF"

* fix performance: 60ms -> 0.3ms (m4 pro)
1. Open a diff editor with an annotation on an added line.
2. Delete that line, or delete the newline immediately above it.
3. Undo and redo the edit, or insert another line above it.
4. The annotation disappears or fails to return with history.

The annotation mapper only used the aggregate line delta for an edit batch.
That made it guess deleted ranges, drop annotations on deleted lines, and
skip net-zero batches where one edit added lines and another removed them.

Record per-edit line changes on TextDocumentChange and map annotations
through each line edit in order. Keep annotations by moving them to the
nearest surviving line, and refresh touched annotation lists so undo and
redo restore the right annotation state.
A user can trigger the lag like this:
1. Focus an editable diff.
2. Hold Cmd+V or Ctrl+V with text on the clipboard.
3. The editor accepts each repeated paste keydown.
4. Each paste can add lines and make the page fall behind.

The root cause is that a held paste key produces repeat keydown events.
Each accepted repeat can lead to another paste and another expensive diff
update. For multi-line text, that update can recompute diff state from
the full edited document.

Suppress repeated paste keydowns and let the first keydown keep the
existing behavior. This keeps normal paste, including custom clipboard
providers, while blocking the runaway repeat path.
* Phase 1: Add basic CodeView accounting for header/footer

* DOM reconcilation stuff
* Various math-ing stuff
* Lots of verbose comments by claude

* Phase 2: Resize observer/measurement handling

Cleaned up some slop from earlier on the initial measure, but then also
added the ResizeObserver stuff

* Phase 3: Start fleshing out vanilla JS apis

* Phase 4: The React APIs

Took a bit of back and forth from the robot to get on the right solution
that worked within the same confines of before.

* Misc fixes

* Prevent scroll fixing if scrolled to the top and a header component is
  added lazily
* Scroll to should take the header into account

* demo: Add header/footer methods to codeview tests

* tests: add CodeView header/footer tests

* type -> kind

Dunno why, i just prefer that...

* review: ensure height is cleaned up properly

* React re-rendering fixes for react compiler

* PR review

* Fix bugs with missing llms.txt content

* First pass at content for headers/footers
* Slop phase 1

* Slop phase 2

* Phase 1: Adding types for codeview editor support

* Phase 2.1: Add recycling support to editor

* Phase 2.n: The rest of Phase 2's functionality for vanilla JS etc

* Phase 3: React API tweaks

* Phase 4: CodeView edit tests

* Phase 5, Part 1: Fix a variety of issues with the initial CodeView
implemention

* First pass at getting a somewhat editable flow in virtualizer/codeview

* Fix WorkerPool related settings

* Fix up annotations in the new views

* Fix virtualizer strict mode bug

Also adds a test for it

* Add window/element virtualizer variants

It's important to test both versions

* PR review fix

* PR Review Fixes:

Fix some virtualization invalidation issues with Files

* PR Review Fixes 2:

Fix scenarios where a controlled element is removed from CodeView to
ensure it properly fires onItemEditComplete

* Removing some useless ai comments, & code polish

* Fix expandUnchanged jumps that can occur during edit

* Fix a virtualizer out of screen height issue

* fix(diffs/editor): Exclude virtualized host offset from caret scroll-margin

.getScrollMargin folded `fileInstance.top` into the primary caret's
scroll-margin-top. For the original non-virtualized editor that value
was always 0, but on virtualized hosts
(VirtualizedFile/VirtualizedFileDiff, CodeView items) `top` is the
item's offset in scroll content — a coordinate, not a margin. Once
scrolled down a list, the caret carried a scroll-margin-top of thousands
of pixels, so every caret reveal (`scrollIntoView` with block:
'nearest') treated the caret as an oversized box and mis-scrolled —
typically pinning the line being edited to the bottom of the scroll
view, or suppressing the reveal entirely.

The margin now only reserves real viewport space above/beside the caret
(search panel height, gutter width), with a comment explaining why the
host offset must never be folded back in.
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.

5 participants