Skip to content

[editor] Beta 1.3#749

Merged
amadeus merged 189 commits into
mainfrom
beta-1.3
Jul 21, 2026
Merged

[editor] Beta 1.3#749
amadeus merged 189 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-diffshub Ready Ready Preview Jul 21, 2026 9:05pm
pierre-docs-trees Ready Ready Preview Jul 21, 2026 9:05pm
pierrejs-docs Ready Ready Preview Jul 21, 2026 9:05pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
pierre-docs-diffs Skipped Skipped Jul 21, 2026 9:05pm
pierrejs-diff-demo Skipped Skipped Jul 21, 2026 9:05pm

Request Review

@amadeus amadeus mentioned this pull request May 29, 2026
15 tasks
mdo and others added 30 commits July 21, 2026 14:14
* [diffs/edit] Add legacy-editor test suites harvested from monaco and CodeMirror

Ports behavioral edge-case scenarios from microsoft/vscode (MIT) and
CodeMirror 6 (MIT) test suites into two new bun:test suites under
packages/diffs/test/. 139 tests, including 22 test.failing entries that
encode real bugs found during the port (frozen EditStack entries vs
non-history edits, undo coalescing, surrogate-pair edit boundaries,
CRLF line metadata, and others). Test-only change; fixes land separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [diffs/edit] Add atom-legacy-tests suite

Third legacy-editor harvest, from atom/text-buffer and atom/superstring
(both MIT): 56 tests covering search/replace semantics (regex capture
expansion, zero-width-match termination, replace-past-own-output,
anchored patterns on CRLF), selection remapping under partial-overlap
replacements, soft-wrap boundary behavior, history invariant fuzzing,
and malformed-position handling. Includes 8 test.failing entries
encoding newly found bugs, the worst being: an edit with a NaN position
component silently replaces the entire document, and soft-wrap vertical
caret motion can land inside a surrogate pair.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [diffs/edit] Guard ICU-dependent word-segmentation pins with skipIf

Intl.Segmenter's isWordLike classification varies across ICU builds
(underscore joining, bare-digit and Han word-ness differ between
engines/platforms). Two segmenter-side expansion pins now probe the
runtime's segmentation of their own fixture and skip visibly on
divergent ICUs instead of failing. Both tests still execute on our dev
and CI environments, which agree with the pinned segmentation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [diffs/edit] Extend ICU skipIf guards to all segmenter-side CJK pins

Completes the previous commit: the Chinese, Japanese, and Latin-Katakana
double-click expansion pins depend on the same ICU-variable isWordLike
classification (dictionary-based CJK segmentation is the most
engine-dependent of all), so they get the same runtime probe treatment
via a shared wordLikeSegments helper. Delete-word tests are untouched —
the regex classifier is deterministic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [diffs/edit] Consolidate editor-derived tests into the main suite

Per team feedback: the three editor-named test directories are gone and
all 195 tests now live in the existing per-domain files
(editorPieceTable, editorTextDocument, editorApplyEdits, editorEditStack,
editorSelection, editorSearchPanel, editorWrapCaretPosition).
Migration was audited name-by-name before deletion: every test present
exactly once, all 30 test.failing known-bug pins and 5 ICU skipIf guards
preserved. Comments no longer reference other editors; the conventions,
known-bug inventory, coverage-gap additions, and a single provenance
note moved into test/README.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [diffs/edit] Pin block-indent blank-line bug as test.failing

resolveIndentEdits inserts the indent unit at column 0 of every line a
multi-line selection touches, including empty and whitespace-only lines,
injecting trailing whitespace on lines the user never typed on. Outdent
round-trips it away, bounding the damage to the indented state. Brings
the pinned known-bug count to 31.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [diffs/edit] Drop the wiped-region graceful-undo pin

We don't model programmatic edits as a class distinct from local edits,
so the scenario's premise (a dead history entry after an untracked edit
replaced its region) doesn't match the intended design. The remaining
five history-across-untracked-edits pins stand; pinned known-bug count
returns to 30.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [diffs/edit] Reframe history-mixing pins around programmatic==local equivalence

Design decision: edits applied with updateHistory=false are not a
semantic class distinct from local edits — a mixed sequence must behave
exactly like the same sequence applied all-tracked. The old pins
asserted rebasing semantics (untracked edits surviving undo); all are
flipped to equivalence assertions whose expected values mirror an
all-tracked reference run: undo-to-exhaustion restores the original
text, redo-to-exhaustion the final text. The wiped-region test returns
under the new model, and the coalescing-across-an-untracked-edit pin
flipped from passing to failing because its outcome also deviates from
the all-tracked timeline. Cluster: 7 failing pins; suite total 32.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* sick

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ion (#986)

Math.min/max pass NaN straight through and fractional indexes break the
integer-keyed line-offset lookup, so a NaN (or fractional) line/character
resolved to a NaN offset and the degenerate edit range swallowed the
entire document — an insert with one malformed component silently erased
everything else. normalizePosition now sanitizes before clamping: NaN
and -Infinity act as 0, fractions floor, +Infinity clamps to the max.
Every position-taking API funnels through it (offsetAt, resolveEdit),
so all edit paths are covered. Flips the two malformed-position pins to
permanent regression tests with exact expectations; pinned known-bug
count drops to 30.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Refactor edit resolution logic to improve surrogate pair handling

* fix codex
* [diffs/edit] Fix soft-wrap vertical caret motion

* fix
* Rename popup to popover to be more consistent

* fix codex

* fix e2e testing

---------

Co-authored-by: Je Xia <i@jex.me>
* fix typo

* fix editStack coalescing bugs.
* fix(diffs): Keep editor active line separate from selected lines

Moving the caret in edit mode reused the selected-lines state, which could
replace an existing line selection and disturb its callbacks or gutter
utility.

Track the editor active line independently and derive one visual highlight
where selected lines take precedence. Preserve both states across diff row
refreshes so each retains its latest value.

* fix(diffs): Preserve interactions in edit mode

Entering Edit mode with line selection, gutter utilities, or hover
highlighting enabled currently turns those interactions off and clears
selected lines.

Preserve the configured interaction options while enabling only the
token transformer required by the editor. Keep editor active-line
styling separate from selected-line styling, protect gutter utility
gestures from editor selection handlers, and exercise the behavior
across playground views.

* docs(diffs): Remove obsolete editor option overrides

Update editor documentation and live examples to stop disabling gutter
utilities, line selection, and hover highlighting in edit mode.

Keep useTokenTransformer enabled in prerendered examples because the
editor still requires it, and refresh the generated homepage fixture.

* fix(diffs): Keep text and line selections independent

Dragging a gutter utility now updates the line range and selection
lifecycle even when ordinary line selection is disabled. Ordinary gutter
drags remain disabled, and callbacks retain the completed gesture range
when utility code changes the current selection.

Preserve editor text selections during gutter-owned gestures and render
the cursor line independently from selected diff lines. Retry incomplete
renders, avoid rewriting unchanged ranges, and keep both states visible
across supported themes.

* docs(diffs): Document gutter utility selection callbacks

Clarify that gutter utility gestures emit selection lifecycle callbacks
even when ordinary line selection is disabled.

* fix(docs): Respect editor active lines in Agent UI

Added and deleted gutter numbers kept their base colors on the editor
cursor line because the Agent UI override excluded the obsolete
`data-active` attribute.

Exclude `data-editor-active-line` instead and update the generated demo
snapshot so the editor active-line styling can apply.

* Fix playground with new selection states

* fix(diffs): Compose editor active lines with diff states

Select a line in edit mode and move the cursor onto it: the theme current-line background can obscure the selection and addition or deletion color.

Resolve decoration, diff, selection, editor active, and hover colors as ordered layers. Derive active emphasis from the resolved semantic color, retain theme borders as a fallback cue, and prevent gutter numbers from receiving the selection mix twice.

* fix(diffs): Flush line state after virtualized rerenders

Edit inside a collapsed diff region, then move the caret or update the
line selection: virtualized views can keep showing the previous line
state after rebuilding their rows.

Flush deferred selected and active-line writes after virtualized
managers bind to the rebuilt DOM, and cover the region-changing render
path.
* [diffs/edit] improve picectable performance

50 latency in milliseconds; two warmups and nine measured samples per workload. Lower is better.

| Workload | Baseline | Round 1 | Round 2 | Round 3 | Improvement |
|---|---:|---:|---:|---:|---:|
| Construct large document | 0.549 | 0.503 | 0.548 | 0.501 | +8.7% |
| Sequential typing | 1.649 | 1.547 | 1.706 | 1.555 | +5.7% |
| Scattered inserts | 3.726 | 3.481 | 3.120 | 3.406 | +8.6% |
| Append after fragmentation | 1.003 | 0.995 | 0.629 | 0.784 | +21.9% |
| Batch replacements | 3.302 | 3.139 | 3.042 | 3.254 | +1.5% |
| Position round-trips | 11.630 | 11.497 | 10.759 | 12.414 | −6.7% |
| Fragmented slices | 1.721 | 1.467 | 1.586 | 1.688 | +1.9% |
| Whole-word search | 7.783 | 7.355 | 7.464 | 2.081 | +73.3% |
| **Combined p50** | **31.364** | **29.983** | **28.854** | **25.683** | **+18.1%** |

* another improvement

* another improvement
* First follow up task

An attempt to ensure the edited diff better matches the fully parsed
diff at the end. It's not perfect, and I think it can still break in
certain ways, but I think it's a bit better.

Will need more testing.

I am a little worried about this code, it touches a lot of things, but
it does appear to fix things... It's one of those things that I don't
fully understand, which scares me a little.

* [diffs] Normalize zero-count hunk sides in merge conflict parser

createHunkBuilder seeds each side's start as "next line to consume"
(lines.length + 1), but getHunkSideStartBoundary assumes the unified
N,0 convention where a zero-count side's start names the line the hunk
applies after. A whole-file conflict with an empty side (no context
anywhere) finalized with that start unnormalized, inventing a phantom
collapsedBefore row and inflating split/unified totals by one.

Normalize each zero-count side down by one in finalizeActiveHunk so
emitted hunks match what parsePatchFiles produces from real git
patches (headers now read +0,0/-0,0 like git). Also corrects the
benchmark checksum documented in the file header, which was stale
before this branch (the parser output hasn't changed: parent, HEAD,
and this fix all produce 31314920).

Addresses codex review feedback on #978.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Quick sidequest to help prevent UnresolvedFile's from being editable

* [diffs/edit] Fix stale highlighting after edit-session line-count edits

The cached per-line addition HAST is looked up by line index, but
applyDocumentChange only truncated/appended it — a mid-document insert
or delete never shifted the surviving entries, so rows hidden behind
collapsed context rendered another line's stale tokens once the edit
session ended and they became visible (a duplicated line in the diff).

- realignAdditionHastLines shifts the cached entries to their new
  indexes on a line-count edit (common prefix/suffix preserved, the
  changed window plain-filled for the editor's next tokenize pass).
- refreshHighlightedResult re-highlights the final diff in the
  background at genuine session exit, so plain-filled and shifted lines
  regain color. The current result keeps rendering until the fresh one
  lands, so no interim paint drops highlighting (no un-highlighted
  flash). Called from completeEditSession and the self-heal backstop.
- applyDocumentChange now throws on a partial diff instead of
  half-applying the line rewrite, matching updateRenderCache's guard.

Adds regression tests covering the realign shift and the exit
re-highlight restoring colors without an interim un-highlighted render.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* [diffs] Keep bottom-of-run anchor when a blank slide stops at a hunk edge

slideBlankBoundaryBlocksUp moves a pure blank insert/delete to the top
of its blank run so the change anchors to the content above it (the
caret line after an Enter). When the run outruns the diff context, the
slide was instead stopped by the hunk's leading edge — a context-window
cut, not the run's top — parking the block at an arbitrary mid-run
position that abuts a hunk separator and anchors to nothing.

Make the slide all-or-nothing: skip it when it would consume the hunk's
entire leading context, keeping the diff library's bottom-of-run anchor,
which sits against the content below the run (and matches what plain
git diff shows for the same files). Slides that come to rest beneath
in-hunk content are unchanged. The rule runs inside the shared canonical
parse, so mid-session and exit renderings agree by construction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* PR feedback fix

* Fix playground to not force initial re-renders

* Defensive diffs fix for initialization highlighting flash

* Fix commenting in playground

* only use server rendered code on initial render

* Actually server render the query string params

* Fix css hydration bug with annotations

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* [diffs/edit] fix selection rounded corner rendering

* add e2e testing
* feat(diffs): Create editors per React edit session

Keep EditProvider mounted while File, diff, and CodeView surfaces enter
and leave edit mode. Each session now receives its own editor from the
provider factory without remounting the rendered surface.

Expose edit and editOptions across editable React surfaces, route
CodeView items through the shared context, and migrate docs apps,
examples, generated snapshots, and lifecycle coverage.

* fix(diffs): Validate CodeView editor factories on attachment

An edit-enabled CodeView item could render read-only when no editor
factory was available.

Assert the factory when a mounted item needs a new editor, without
scanning the full item collection. Preserve active sessions when the
factory changes and cover vanilla, React, and virtualized paths.

* fix(diffs): Keep React CodeView selection prop-driven

React CodeView callers could pass selection controls through both props
and options, but the wrapper silently discarded the option values.

Remove the React-managed selection keys from the public options type and
cover controlled, uncontrolled, and provider-mounted selection flows.

* bugfix(UniversalRenderingManager): improve idempotency, add some tests

* fix(diffs): Keep deferred onAttach within its edit session

End an edit session before the next render frame and the queued onAttach
callback could run against a cleaned editor, breaking imperative setup such
as marker installation.

Track pending notifications by attachment generation, cancel them during
cleanup, and only deliver once to a live session. Preserve recycle behavior
and persisted-state restoration across repeated teardown.

* fix(docs): Preserve Live Editing state across layout changes

Edit a diff, then switch between unified and split layouts: Reset became
disabled even though the edited contents remained. An edit immediately
after a reset could also be ignored.

Remove the stale debounce window now that onChange is synchronous. Keep
layout changes within the current session, while Reset and surface switches
still remount from pristine input.

* docs(diffs): Correct React examples and edit guidance

Keep files, diffs, items, and styles stable at module scope while
memoizing component options with useMemo. Correct public type imports
and make the snippets compile under strict TypeScript settings.

Clarify per-surface editor creation and CodeView completion semantics,
including the teardown paths that remain silent. Refresh demo comments
and callback wiring to match the current edit-session lifecycle.

* test(diffs): Strengthen React edit lifecycle coverage

Cover File and FileDiff session creation, option replacement, cleanup,
and instance preservation with the same lifecycle assertions. Keep
wrapper coverage focused on edit-option forwarding and verify sibling
callbacks stay isolated.

Exercise CodeView completion behavior for changed and unchanged
sessions across edit-off, collapse, removal, direct cleanup, and React
unmount.

* docs(diffs): Refresh Agent UI edit callback snapshots

Describe the stable onChange callback consistently in both Agent UI
starter states. Refresh the generated mock session data so its displayed
diff matches the source snapshots.

* lmao fixed
* docs(diffs): Document editable line annotations

Explain how applications retain remapped annotations across
standalone editors and CodeView, including React and vanilla ownership
patterns.

Add typed examples for file and diff annotations, document deletion and
virtualization behavior, and lock final-line deletion semantics with
focused regression tests.

* fix(diffs): Type edit callbacks for file annotations

Edit a standalone file with annotations: onChange delivers side-less
LineAnnotation entries, but its public type only allowed DiffLineAnnotation.
CodeView exposed the same mismatch for file items.

Accept the two homogeneous annotation collections throughout Editor and
CodeView, export guards for narrowing them, and update examples and tests
to preserve remapped annotations for either item type.

* PR Review Fixes
…1011)

Type or scroll in a wrapped file with long lines: every keystroke and
scroll re-measured wrap points character by character for each line,
one Range.getBoundingClientRect() per character, making minified or
long-line files sluggish.

Three changes to wrap measurement and its caching:

- Find each wrap point by binary-searching for the first grapheme
  whose rect top drops to the next visual line (tops are
  non-decreasing with text offset), replacing the per-character scan:
  O(wraps * log chars) measurements instead of O(chars).
- On edits that renumber no lines, invalidate only the lines the edit
  rewrote instead of every line at or after it. Per-edit line deltas
  guard the multi-edit batch whose net delta cancels to zero while
  still shifting lines between the edits.
- Keep wrap offsets across render-range syncs: they depend on line
  text, font metrics, and content width, not on rendered rows. The
  sites where those inputs change (document swap, font load, width
  resize, cleanup) now clear the cache themselves, with a 10k-line
  cap since entries persist across scrolls.
- Binary-searches offset-sorted matches for each rendered line segment.
- Skips virtualized offscreen matches and matches hidden inside collapsed diff gaps.
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.

6 participants