Skip to content

improve the cm teardrop, scrolls, quality-of-life overhaul etc#1971

Merged
bajrangCoder merged 19 commits intoAcode-Foundation:mainfrom
bajrangCoder:cm-improvements
Mar 27, 2026
Merged

improve the cm teardrop, scrolls, quality-of-life overhaul etc#1971
bajrangCoder merged 19 commits intoAcode-Foundation:mainfrom
bajrangCoder:cm-improvements

Conversation

@bajrangCoder
Copy link
Copy Markdown
Member

No description provided.

@bajrangCoder bajrangCoder marked this pull request as ready for review March 27, 2026 06:36
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 27, 2026

Greptile Summary

This PR is a broad quality-of-life overhaul across the CodeMirror layer: it removes the custom teardrop cursor handles and replaces them with a lightweight context-menu-only touch controller, reworks indent guides to use CSS background-image marks instead of heavy DOM widgets, defers expensive decoration rebuilds to requestAnimationFrame, adds custom hover/signature tooltip extensions that close properly on pointer/touch/scroll, expands LSP initialization with an initializationOptions injection mechanism, and bumps several @codemirror/* packages.\n\nKey changes:\n- Touch selection — all start/end/cursor drag handles removed; the new TouchSelectionMenuController only tracks pointer up/down events and positions the context menu from a computed selection anchor. Teardrop size/timeout settings are removed from the settings file and editor UI.\n- Indent guides — replaced per-guide WidgetType DOM nodes with a single Decoration.mark over leading whitespace; guide positions rendered via CSS background-image linear-gradients at pixel offsets computed from defaultCharacterWidth.\n- LSP improvementsconnectClient monkey-patches requestInner to inject initializationOptions into the initialize request; hover/signature tooltips moved to a custom tooltipExtensions.ts that closes on pointer/touch/scroll; diagnostics debounced and equality-checked to skip no-op UI updates; inlay hints default to opt-in; verbose LSP logging gated behind a debug build flag.\n- Android — versioned flag file prevents re-running the Java patch unless patchVersion changes; new ActionMode overrides in SystemWebView suppress the native floating toolbar without reflection.\n- Two issues identified: (1) the requestInner patch in connectClient is removed inside a finally block right after connect() returns — if the LSP client sends initialize asynchronously, initializationOptions will never reach the server; (2) the viewport-culling loop in documentHighlights.ts uses a monotonic range pointer that breaks when highlights are returned out of order and multiple visible viewport bands are present.

Confidence Score: 3/5

Mostly safe with two P1 issues that could silently regress LSP init-options injection and document highlight rendering in edge cases.

The majority of changes are well-structured refactors with clear improvements (rAF deferral, CSS guides, simplified touch menu). Two P1 logic issues remain: the connectClient requestInner patch may be removed before the async initialize request fires, and the document-highlights culling loop can skip visible highlights when unsorted. Both are silent failures with no crash, making them harder to catch in manual testing.

src/cm/lsp/clientManager.ts (connectClient timing) and src/cm/lsp/documentHighlights.ts (unsorted highlights + multi-range culling)

Important Files Changed

Filename Overview
src/cm/lsp/clientManager.ts Adds connectClient helper that monkey-patches requestInner to inject initializationOptions into the LSP initialize request; gates verbose logging behind a debug flag; defaults inlay hints to off.
src/cm/lsp/documentHighlights.ts Adds viewport culling to buildDecos; removes the sort of decos before RangeSet.of. The culling algorithm assumes sorted highlights, creating a potential bug when language servers return unsorted highlights and multiple visible ranges are present.
src/cm/lsp/tooltipExtensions.ts New file: custom hoverTooltips and signatureHelp implementations that add pointer/touch/scroll close-on-interaction.
src/cm/touchSelectionMenu.js Major refactor: removes all teardrop handles; retains the context menu pop-up logic, repositioned using an anchor computed from selection/caret coords.
src/cm/indentGuides.ts Replaces per-guide DOM widgets with a single Decoration.mark on leading whitespace; uses CSS background-image linear-gradients for guide lines; defers builds to rAF.
src/cm/lsp/diagnostics.ts Removes forceLinting; adds sameDiagnostics equality check; debounces the diagnostics event via a module-level timer; suppresses markers/tooltips on coarse-pointer devices.
src/lib/editorManager.js Adopts createMainEditorExtensions; adds onScrollStart/onScrollEnd lifecycle to touch selection controller; increases autocomplete delay on coarse-pointer devices.
hooks/modify-java-files.js Adds versioned flag file; injects ActionMode overrides into SystemWebView.java to suppress the native long-press floating toolbar.
src/cm/mainEditorExtensions.ts New helper that centralises editor extension assembly in a typed options object; includes fixedHeightTheme and scrollPastEnd() unconditionally.
src/settings/lspServerDetail.js Adds isBuiltinFeatureEnabled that treats inlayHints as opt-in while all other builtins remain opt-out.

Sequence Diagram

sequenceDiagram
    participant EM as editorManager.js
    participant LCM as LspClientManager
    participant CC as connectClient()
    participant LSP as LSPClient (lib)
    participant SRV as LSP Server

    EM->>LCM: startServer()
    LCM->>LCM: await transportHandle.ready
    LCM->>CC: connectClient(client, transport, initOpts)
    Note over CC: patches requestInner
    CC->>LSP: client.connect(transport)
    alt initialize sent synchronously inside connect()
        LSP->>CC: requestInner(initialize, params)
        CC->>CC: merge initializationOptions
        CC->>SRV: initialize with initOpts
    else initialize sent asynchronously
        LSP-->>CC: returns
        CC->>CC: finally restores requestInner - patch removed too early
        Note over SRV: initializationOptions never received
    end
    LCM->>LSP: await client.initializing

    EM->>EM: scroll event
    EM->>TouchMenu: onScrollStart()
    TouchMenu->>TouchMenu: hideMenu()
    EM->>EM: 100 ms debounce
    EM->>TouchMenu: onScrollEnd()
    TouchMenu->>TouchMenu: scheduleMenuShow() if selection
Loading

Comments Outside Diff (4)

  1. src/cm/lsp/documentHighlights.ts, line 1481-1499 (link)

    P1 Unsorted highlights break multi-range viewport culling

    The culling loop uses rangeIndex as a monotonically-increasing cursor into visibleRanges, which is only correct when highlights is also sorted by position. The old code sorted decos before calling RangeSet.of; that sort was removed here.

    When a language server returns highlights out of order and there are multiple visible ranges (e.g. after a scroll that leaves two disjoint rendered bands), a later highlight with a smaller offset will find rangeIndex already advanced past its containing range, causing h.to <= visible.from to be true and silently skipping a visible decoration.

    Minimal reproduction:

    highlights = [{from:50,to:55}, {from:10,to:15}]   // unsorted
    visibleRanges = [{from:0,to:40}, {from:60,to:200}]
    
    h={50-55}: while advances rangeIndex to 1; h.to(55)<=visible.from(60) → skip ✓
    h={10-15}: rangeIndex is STILL 1; h.to(15)<=visible.from(60) → INCORRECTLY skipped ✗
    

    Fix: sort highlights before the loop.

  2. src/cm/lsp/clientManager.ts, line 1135-1171 (link)

    P1 requestInner patch removed before initialize is sent

    The try/finally block restores the original requestInner immediately after client.connect(transport) returns. The initialize LSP request needs to be sent by connect() within its synchronous call frame for the patch to take effect.

    Since client.initializing is a Promise (awaited on the very next line), initialization is asynchronous. If @codemirror/lsp-client defers calling requestInner('initialize', ...) to a microtask or async tick inside connect(), the patch will already be removed when the call actually happens — meaning initializationOptions is silently never applied.

    Consider persisting the patch until after client.initializing resolves:

    client.connect(transport);
    try {
        await client.initializing;
    } finally {
        patchedClient.requestInner = originalRequestInner;
    }

    You would then await connectClient(...) at the call site.

  3. src/cm/indentGuides.ts, line 990-1001 (link)

    P2 RAF deferral leaves decorations one frame stale

    scheduleBuild defers this.decorations = buildDecorations(...) to the next animation frame. CodeMirror reads plugin.decorations synchronously during every layout pass that follows an update() call. Between the update() return and the rAF callback, the decoration set is stale, which can cause a visible flicker of guides when the document or viewport changes (e.g., fast typing or large paste).

    This pattern is safe when decorations are purely cosmetic and transient staleness is acceptable, but it is worth explicitly noting the one-frame delay as a known trade-off. The same pattern in colorView.ts and rainbowBrackets.ts carries the same caveat.

  4. src/cm/lsp/diagnostics.ts, line 1379-1385 (link)

    P2 Module-level timer never cancelled on editor destroy

    diagnosticsEventTimer is module-level and shared across all editor instances. When an editor is torn down while this timer is pending, the timer will still fire and call emitDiagnosticsUpdated(). In addition, because the guard is if (diagnosticsEventTimer) return, a diagnostic update from a second editor while the timer is pending will be coalesced/delayed until the current 32 ms window expires.

    Both are minor in a single-editor session, but if multiple tabs each have an LSP connection, consider exporting a cleanup helper or scoping the timer to a properly lifecycle-managed singleton.

Reviews (1): Last reviewed commit: "Merge branch 'main' into cm-improvements" | Re-trigger Greptile

@bajrangCoder bajrangCoder changed the title improve the cm teardrop and scrolls etc improve the cm teardrop, scrolls, quality-of-life overhaul etc Mar 27, 2026
@bajrangCoder bajrangCoder merged commit 0d6ed31 into Acode-Foundation:main Mar 27, 2026
6 checks passed
@bajrangCoder bajrangCoder deleted the cm-improvements branch March 27, 2026 06:57
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