Lays the groundwork for WorkspaceEdit/rename (L2+) by making
navigation cross-file-correct.
- Relocate file_path/file_meta from the EditorCore global onto
Buffer itself, so each buffer keeps its own filesystem identity
across cross-file navigation. Accessors + registry/editor/lua/
semantic_render call sites migrated; zero behavioural change for
single-file flows.
- uri->path: project_index::uri_to_path made pub; pmacs.lsp.path_for_uri.
- find-or-open: BufferRegistry::find_by_path + pmacs.buffer.find_or_open
dedups an already-open file instead of spawning a duplicate buffer
(SP-4 Gap A).
- Bounded jump ring on EditorCore (cap 64, oldest-evict, stale-buffer
skip): push_jump/jump_back + pmacs.editor.* bindings + lsp.jump-back
command bound to M-,.
- pmacs.lsp.go_to_definition cross-file branch: decode URI ->
push_jump -> find_or_open -> reposition, with a failure path that
unwinds the pushed origin. ensure_server now passes cfg.env through.
Tests: 5 jump-ring unit tests; m4_12_cross_file_go_to_definition_and_
jump_back end-to-end via a new `defenv` fake-LSP mode. All gates green
(lib 1262/0, m4 67/0, m8_1/m8_9/m8_10, m9_1, m11_5 --features crdt 2/0).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Completes the read-only LSP feature set (everything except edits).
Same request→store→Lua pattern as the nav batch; these three need
new parsing (new response shapes), so they were deliberately split
from the Location-family PR (#16).
- src/symbol.rs: one flat Symbol type for both symbol requests.
from_lsp_value handles BOTH LSP shapes — hierarchical
DocumentSymbol[] (flattened with depth + parent chain) and flat
SymbolInformation[]/WorkspaceSymbol[] (location.uri, range
optional for WorkspaceSymbol). Scope-keyed (Document(uri) vs
Workspace(query)) so an outline and a query don't collide.
- src/document_highlight.rs: range + DocumentHighlightKind (absent
defaults to Text=1 per spec), (server,uri)-keyed.
- lsp.rs: three ResponseRoute variants + absorb arms + request
methods. documentSymbol/documentHighlight ranges convert via the
requested-doc codec; workspace/symbol results are cross-file →
route uri "" → non-destructive passthrough (same rule as
cross-file definition).
- Lua: raw bindings + pmacs.document_symbol / .workspace_symbol /
.document_highlight read surfaces (the new LSP Symbol is aliased
to avoid the pre-existing project_index::Symbol name clash);
lsp.lua wrappers + an lsp.document-symbols command on C-c o
(modeline summary; outline buffer is future UX).
- Tests: 6 parser unit tests (hierarchical depth/parent, flat
SymbolInformation, range-less WorkspaceSymbol, highlight kind
default, scope non-collision) + an e2e driving all three through
the async bridge asserting shape correctness.
Also includes a pre-existing rustfmt normalization of the #15
semantic-frontend files (protocol.rs / semantic_client.rs /
semantic_render.rs) — main was not rustfmt-clean there after the #15
merge; bundled here per operator decision so the fmt gate is green.
Gate: fmt clean; clippy --all-targets -D warnings clean; lib
1257/0; m4_acceptance 66/0; m9_1 18/0; m8_1/m8_9/m8_10 green.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the M11.2/M11.3 coarse whole-payload suppression with a
CellDelta-style diff lifted from positional cells to byte-anchored
ranges.
- protocol.rs: StyleSpans/Decorations refined to
{ buffer_id, generation, full: bool, segments: Vec<...Segment> }.
New StyleSegment{range,spans} / DecorationSegment{range,decorations}.
full=true → frontend discards prior state for the buffer; full=false
→ replace styling only within each segment's range, bytes in no
segment keep prior state. Decorations gains generation for parity.
Each segment carries ALL current items intersecting its range
(clipped), so an unchanged span overlapping a dirty range is
reconstructed. ResourceOffer stays an honest stub (no producer).
- semantic_render.rs: LastFrame baseline per buffer (viewport region
+ full item set). full on first frame / viewport-region change;
else symmetric-difference the ordered sets, coalesce changed ranges
into maximal disjoint dirty intervals, emit one segment per
interval with current items clipped to it; suppress when no dirty
interval. Independent baselines for styling vs decorations.
Byte offsets cascade on edits (an insert shifts later spans), so an
incremental post-edit frame dirties [edit, viewport_end) — bounded;
no-edit frames (cursor/scroll/selection-only) still cost nothing.
10 semantic_render tests (full-on-first/viewport-change, incremental
dirty intervals, independent suppression, unchanged-overlapping
reconstruction) + updated protocol round-trip. Lib (1397 crdt / 1242
non-crdt) + integration green both flavors; clippy -D warnings clean
both.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SemanticRenderState now also projects InstanceMessage::Decorations
from the instance-side state pmacs actually has.
- Selection: per-window byte-native state via active_window_for(fid)
(SemanticRenderState now carries the session FrontendId), gated to
the declared buffer and clipped to the viewport →
DecorationKind::Selection.
- Diagnostics: the shared DiagnosticStore keyed by file URI. Made
lsp::path_to_file_uri pub(crate) (byte-identical to the Lua
file_uri_for) so the projection reproduces the exact store key from
core.file_path. LSP (line,col) -> byte via a line-start scan
against the buffer source; severity -> DiagnosticError/Warning/
Info/Hint. Clipped to the viewport.
- StyleSpans and Decorations suppress unchanged frames independently
(separate last_* maps): a selection move doesn't force a styling
re-send and vice versa.
- Deliberately NOT emitted: SearchMatch/SearchMatchActive (no
instance search-hit store), CurrentLine (frontend derives from
CursorByte; emitting it would breach the contract boundary).
- InlineAdornments/BlockAdornments/FoldState remain unproduced by
design — no inlay/blame/lens/fold/diff source exists in pmacs yet.
Honest stubs (the M11.1 "declared, not yet wired" discipline), not
empty messages every frame.
Dispatcher updated for SemanticRenderState::new(frontend_id). Lib
(1394 crdt / 1239 non-crdt) + integration green on both feature
flavors; clippy -D warnings clean on both.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The first real producer of the semantic-frontend arc. The instance
projects syntax styling to semantic_render sessions without
rasterizing to a cell grid.
- src/semantic_render.rs: SemanticRenderState, sibling of
instance_render::RenderState. Reads the same EditorState, emits
InstanceMessage::StyleSpans (tree-sitter spans via the active
Theme), scoped + clipped to the FrontendEvent::Viewport byte range.
Emits nothing until a viewport is declared; suppresses
byte-identical frames (per-span delta encoding deferred to M11.4).
- CrdtState::version_scalar(): oplog version vector summed to a
monotonic non-decreasing u64 — the StyleSpans.generation anchor.
- daemon dispatcher: semantic_states map parallel to render_states;
projection selected per session. Semantic sessions get StyleSpans +
CursorByte + BufferSnapshot + CrdtOp + presence, never CellDelta /
grid Cursor. FrontendEvent::Viewport consumed (routed by
authenticated source). SessionEstablished body extracted to
handle_session_established (clippy 100-line ceiling). Grid-less
sessions no longer panic the _ => apply_event arm.
- InstanceCapabilities default semantic_render flipped to
cfg!(feature = "crdt") — the "M11.2 enables semantic" moment,
analogous to the M10.8 Day-4 flip. M11.1 negotiation test comment
updated for the flip (frontend-side default still false keeps M10.7
outcomes unperturbed).
Lib (1392 crdt / 1237 non-crdt) + integration suites green on both
feature flavors; clippy -D warnings clean on both.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>