Skip to content

Syntax highlighting gets stale after external edits to a Rust file #222

Description

@JDonaghy

Repro

  1. Open a Rust file in vimcode (e.g. `src/foo.rs`).
  2. Without closing it, edit the file in another editor (or have `cargo fmt` / `rustfmt` rewrite it, or pull a branch via `git pull`).
  3. Let vimcode reload the buffer (file watcher refresh, or close/reopen the buffer if reload-on-change isn't kicking in).

Observed: Syntax highlighting for the reloaded file is wrong / stale. Identifiers that should be coloured as types/keywords/macros render as plain identifiers, or older spans persist on lines that have new content underneath them.

Expected: After a buffer reload, the highlighting matches the new content as it does on a fresh open.

Suspected cause

Two suspect surfaces:

  1. Tree-sitter parse tree. `Buffer` reload may be replacing the rope contents without doing a full tree-sitter reparse from scratch. Incremental edits expect prior-tree + edit deltas; a wholesale buffer swap should invalidate the tree completely and re-parse, otherwise spans computed against the old tree leak through.
  2. LSP semantic tokens. Per the Session 131 work, semantic tokens override tree-sitter on Rust buffers. After an external edit the cached `BufferState.semantic_tokens` is stale until the next `textDocument/semanticTokens/full` round-trip — and the request might not be re-issued on reload, leaving the renderer painting stale token spans.

Both can be true at once and either alone produces visible drift.

Likely fix

  • On buffer reload, drop the previous tree-sitter `Tree` and reparse from scratch (rather than the incremental-edit path used for normal edits).
  • On buffer reload, clear `BufferState.semantic_tokens` AND issue a fresh `textDocument/didChange` (full sync) + `semanticTokens/full` so rust-analyzer agrees with the current contents.

Files

  • `src/core/buffer_manager.rs` — buffer reload path; ensure both tree + semantic_tokens are invalidated.
  • `src/core/syntax.rs` — confirm parse-from-scratch path is used on reload.
  • `src/core/engine/buffers.rs` — file-change reload entry point + LSP didChange dispatch.
  • `src/core/engine/lsp_ops.rs` — `lsp_request_semantic_tokens` should be called after reload.

Surfaced by

Day-to-day editing — running `cargo fmt` from a terminal while a file is open is the easiest repro.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions