Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
2 tasks
Repro (diffs /playground, edit mode):
1. Select all text in the editor.
2. Press delete/backspace.
Before this fix the editor breaks: split mode collapses to a
single uneditable view and undo does nothing; unified mode keeps
the view but you can no longer type.
The editor's text document always keeps one (empty) line, but
splitFileContents('') returns [], so emptying the editable side
recomputed the diff with zero addition lines. The additions
column then rendered no line elements, leaving the attached
editor with nothing to host its caret.
Now an emptied document is represented as one empty editable
line: diff the unchanged deletions against a single empty line
and store the addition as [''] so it still joins back to the
editor's empty document. Covered by model- and DOM-level
regression tests in both split and unified modes.
When the editor is emptied, the recompute diffs the deletions against a single empty line to place one editable row. If the old side was itself a single blank line, that diff was a no-op (zero hunks), so iterateOverDiff emitted nothing and the row was still missing. Pick a sentinel that always differs from the deletion side so a hunk is produced; its text is discarded by the [''] override. Covered by the empty-document regression tests.
Turn on word wrap in an editable diff and type in a line until it grows long enough to wrap onto another row. Now click a line below it, or select text there: the caret and the selection highlight land a row too high, sitting on the wrapped line's extra row instead of the line you clicked. The editor caches each line's vertical position and only refreshed it when the number of lines changed. Wrapping a line adds a visual row without changing the line count, so the cached positions of the lines below it stayed stale, and the caret and selection drawn from them rendered a row too high. Refresh the cached positions after an edit whenever wrap is on, matching how the wrap offsets are already invalidated. This corrects only the vertical position of overlays on the lines below a wrap. Selecting a word on the wrapped line itself still mispaints the highlight horizontally; that is a separate bug.
Steps to reproduce: 1. Scroll a long file so the visible lines sit inside an unclosed block comment or template literal. 2. Delete the line directly above the viewport. 3. The visible lines lose their comment color and render as if they were plain code. The tokenizer read the loop's grammar state before the offscreen flush rebuilt the cached state stack up to the viewport's first line, so it captured INITIAL. The visible lines were then tokenized as if outside the construct — corrected by a later background pass, or never when the viewport reaches the end of the document and no background pass is scheduled. Seed the loop state after the offscreen flush instead. This reuses the state the flush already computed, so it adds no tokenization work and only changes the delete-reaches-viewport case; far-above edits with a gap stay seeded from INITIAL and are corrected by the background pass as before.
Paste inserted clipboard text verbatim, so a Windows clipboard (CRLF or CR) left mixed line endings in a file that otherwise uses one style, showing up as spurious diff noise. Rewrite clipboard line breaks to the document's detected EOL before inserting, matching what copy already does. Expose the line ending as TextDocument.eol with a normalizeEol() helper and move the generic endsWithLineBreak() predicate into editor utils, so this logic no longer sits among the selection helpers.
Repro: 1. Open the editor on a large file, or make many scattered edits so the document accumulates many internal fragments. 2. Keep typing; each keystroke gets progressively slower. Every edit (typing, deleting, applyEdits) rebuilt the editor's whole text structure from scratch, so a single edit cost time proportional to how fragmented the document had become; in a heavily edited file each keystroke paid for the entire document. That structure (a piece table) keeps text as a list of "pieces" indexed by a tree. The tree is now a treap: a binary search tree that also keeps each node's random priority in heap order, so it stays balanced without an explicit rebalancing pass. An edit now splits the tree at the edit, drops the removed part, and merges the new text in, touching one root-to-leaf path (O(log P)) instead of rebuilding all P pieces. Reads and editor behavior are unchanged.
Steps to reproduce: 1. Scroll a long file so the editor virtualizes (only a window of lines is rendered). 2. With a caret near the window bottom, insert lines there - press Enter on the last rendered line, or paste a few lines. 3. The just-typed line, and its caret, are missing from the window until the next scroll. #applyChange widened the render range only when the caret was exactly at the window's end, and never persisted the widened range, so a following edit read a stale renderRangeEndLine, treated the caret as past the window, and #rerender (clamped to the range) never built the new row; #isLineVisible/#renderCaret read the stale range and dropped the caret too. (Only edits that carry a caret reach this path - it is guarded on `selections` - so a bare programmatic applyEdits with no active selection is unaffected; the real triggers are typing and paste at the window bottom.) Widen the range to cover the caret line for inserts that reach the window's bottom edge and persist it to #renderRange so consecutive edits stay accurate and the caret draws. Bound that widening two ways so it can't defeat virtualization or render a gap. Cap it at twice the bounded window the virtualizer last synced (captured in __syncRenderView as #viewportWindowLines): a large insert at the caret - most often a big multi-line paste - can drop the caret far below the window, and widening to reach it would build a row per inserted line synchronously, risking a freeze. And skip widening when the edit starts below the window, since #rerender only builds rows from change.startLine - widening there would leave the intervening rows unbuilt while reporting them visible, mispositioning the new rows. Past either limit, keep the bounded window and only recompute the buffer, leaving the far region for the scroll that follows a focused edit (or the next user scroll) to render. Capturing the window at sync time also stops consecutive edits from ratcheting the cap up. Add editorVirtualizedEdit.test.ts: consecutive newlines and a small multi-line insert at the window bottom render; a 1000-line insert, a run of consecutive inserts, and an edit starting below the window all keep the rendered window bounded and contiguous.
Open a split diff with word wrap on and edit a line so it wraps onto several rows. Double-click a word on a wrapped row: the word is selected and the caret lands correctly, but the highlight is drawn at the row's left edge instead of over the word. Selecting whole lines across a multi-line range shows the same shift. In a split diff the editable panel sits to the right of the deletion panel. The caret math adds this horizontal panel offset, but the selection-highlight math did not, so every highlight was pulled left by the offset (its width stayed correct). Add the same content offset when computing the highlight's left edge, for both wrapped rows and selections that start at the beginning of a line.
In a split diff with word wrap on, edit a line so it wraps, then turn word wrap off. Select a whole line from its start: the highlight either vanishes or jumps far to the right of the text. #contentOffset caches the split panel's horizontal shift but is only set in a split + wrap diff and never cleared, so toggling wrap off leaves a stale value on the same editor. The selection start added that stale offset while the end (from #getCharX) did not, giving a negative width. Read the offset through a getter that returns it only while the live layout still applies, so caret, selection, and line-Y math all ignore a stale value.
* Phase 1: Setup the new slot architecture * Phase 2: Vanilla API shenanery * Phase 3: React implementation * Phase 4: Add CodeView support * Add demo-ability * Phase 5: Adding misc tests * Phase 6: Adding docs Both for the new API and also some forgotten docs for header prefix
[diffs/editor] Updated `editor.css` for marker popups to improve layout and responsiveness
Steps to reproduce: 1. Open a diff in edit mode and edit a line (e.g. rename a symbol). 2. Toggle any display option - word wrap, theme, diff style, line numbers. 3. The edit vanishes and the line shows its original text again; it only reappears on the next keystroke. When an editor is attached, its document is the source of truth for the content, but the host passes a static fileDiff. A display-option change forces a full re-render that rebuilds the diff rows from that fileDiff, so the in-progress edits are painted over with the original content - and inserted or deleted lines are lost. After a full re-render, when the editor's document survived it and the rendered rows no longer match it, re-render the diff from the document: rerenderFromDocument re-derives the diff and clears the render cache so the rebuild re-highlights from the edited contents. One pass restores text, syntax colors, and line count, with no per-row reconciliation. The diff is mutated in place so its cacheKey is kept and the editor's document and undo history survive. Gated to full re-renders (a scroll's partial render reuses the existing rows) and to components with a document-backed re-render (FileDiff; the plain File has no such path yet). Host-agnostic: this holds whether or not the host sets a cacheKey. Adds a regression test covering the toggle, further typing, an inserted line via both render APIs, and downstream block-comment highlighting - all with no cacheKey. Co-authored-by: Je Xia <i@jex.me>
* chore: empty commit for beta branch * Prevent transparent borders * Fix the editing example * fix cursor jumping in history demo * wip * updates * button fixes, history improvement * refactor(diffs): show the selection action in a floating popover Selecting text in an editable surface used to surface a lightning icon in the gutter; clicking it inserted the consumer's action element as a new inline row, which reflowed the document and took two interactions. Replace that with a floating popover that appears automatically once a ranged selection settles, anchored just below the selection's head and mounted in the overlay layer so it never reflows the content. The `renderSelectionAction` API is unchanged, and its handlers now read the live primary selection so keyboard-extending a selection keeps acting on the current range. Drop the now-unused gutter icon, its `quick` sprite, and the inline-row styling. * docs(docs): rebuild the selection action demo as "Add to chat" The edit page's selection demo wrapped the selection in t() or shouted it in caps from a toolbar. Rebuild it around the new popover: selecting code pops an indigo "Add to chat" action (plus a secondary copy) that sends the snippet to a mock chat panel beside the editor, complete with an inert composer mirroring the homepage agent UI. Snippets render with a read-only File. The page's shared worker pool is wired for the editable surface and doesn't highlight a dynamically mounted read-only File, so opt these out with disableWorkerPool and highlight on the main thread. The panel is height-matched to the editor so the list scrolls while the header and composer stay put. * docs(docs): describe the selection action popover Update the editor docs and copy to match the new behavior: the action appears in a floating popover anchored to the selection instead of a gutter icon you click, and it can hold any number of actions. Refresh the edit-page blurb, the Editor guide prose, and the option comment, and drop the selection action from the standalone EditorDemo so it stays focused on plain editing. * chore(demo): match the renamed selection action popover hook The selection action now renders as a popover, so target the new [data-selection-action-popover] selector and drop the inline margin that spaced the old inline action row. * test(diffs): cover selection action popover lifecycle Add cases for the popover's auto show/teardown: it disappears once the selection collapses, and it never renders (nor calls the consumer's callback) when enabledSelectionAction is left off. * feature updates * New replace and replaceall icons * better search shortcuts * Update keyboard shorcuts table * refactor search, fix some nits, redo icons in search, combine marker severity styles * remove labels * use claude to restore the delta between X's and my changes, then reapply to markers and popovers * improve focus, rearrange * localize the padding/margin for now --------- Co-authored-by: Amadeus Demarzi <amadeusdemarzi@gmail.com>
* Revamp some AUI demo code, streamline a few things, update selection action * streamline the aui * fix playground theme flash when toggling review/edit * Track live diff stats in AgentUi Changes tree Recompute each file's added/removed line counts from in-editor edits and update the +/- decorations in the Changes tree so they reflect the live diff rather than the static snapshot counts. * fix(docs): render heading anchor inline with FeatureHeader titles Drop the flex layout on the FeatureHeader h2 so the injected "#" anchor flows inline after the title text instead of floating beside wrapped multi-line headings. * fix hint coloring on light mode, plus fix playground theme flash
more mobile related bugs
In edit mode, click or drag to select code on either side of a split or unified diff. A caret highlights only its own line, on the side it sits on, instead of also lighting up the paired line in the read-only deletions pane. Selecting text drops the full-line background and keeps only the caret line's number highlighted, so the selection itself is the line-level marker. Deleted text is selectable and copyable: clicking a line number selects that whole line's text on either side, and in split view dragging across the deletion line numbers selects the block, the same as on the additions side. Previously the active-line highlight leaked onto the read-only deletions pane, the full-line background competed with a text selection, deleted text could not be selected, and line-number gestures behaved differently per side. The editor now confines the active-line highlight to the caret's side, paints deleted-text selection with the native selection (revealed only while selecting deleted text), highlights just the focus line's number during a gutter drag, and stops a transparent-span rule from hiding the word-level diff highlights.
fix(diffs): clear bufferBefore and bufferAfter on reset
* Bug fixes
The diff editor's "system" themeType follows the OS prefers-color-scheme (its shadow root declares `color-scheme: light dark`), so it drifted from the app whenever the app theme differed from the OS. Resolve "system" to the app's scheme from @pierre/theming so the editor stays in sync; the switcher stays editor-only and "light"/"dark" remain independent overrides.
Rename the useTheme() binding and every consumer to the controller's vocabulary so the docs match the library, not just one file: resolvedTheme -> resolvedColorScheme theme -> colorMode setTheme -> setColorMode systemTheme -> systemColorScheme themes -> colorModes Also rename the playground's local switcher state (themeType -> colorMode, the diffs `themeType` option key is unchanged) and the pre-paint bootstrap script's locals. Pure rename — no behavior change.
Editing a scrolled unified diff snaps the view back to the top. To reproduce: 1. Open the editor on a unified diff. 2. Scroll down within the editor. 3. Edit a visible line (type a character, press Enter, etc.). The view jumps to the top of the diff instead of staying where you were. Split diffs are unaffected. On every edit a unified diff re-renders its rows in place: FileDiff.refreshDiffView rewrites the content column's innerHTML, which detaches the line elements the editor cached for caret geometry. The editor then measures a detached row (offsetTop 0) and places the caret at the top, so the follow-up scrollIntoView pulls the viewport up to it. Reset the editor's line-geometry caches after a diff rebuilds its rows, so the caret re-measures against the fresh DOM and the viewport stays put.
On the homepage editor demo, scroll a changed file down, then open a different file from the Changes list: it opens scrolled to the previous file's offset instead of at the top. The demo reuses one FileDiff surface across files (never remounted, so the prerendered markup survives), and the scroll lives on the host `.aui-surface-wrap` container, which nothing reset on a file switch. Reset its scrollTop to 0 whenever the active file changes, in a layout effect so the new diff never paints at the old offset.
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.
Used to track editor beta versions. Will be periodically rebased on main.