Commit Graph

5 Commits

Author SHA1 Message Date
Levi Neuwirth f7267cd720 T M4.5 L1: cross-file nav foundations — per-buffer file_path, jump ring, x-file go-to-def
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>
2026-05-19 09:53:29 -04:00
Levi Neuwirth 80c0679a5b T M4.5: documentSymbol / workspace symbol / documentHighlight
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>
2026-05-18 22:15:03 -04:00
Levi Neuwirth 071e79ffee M11.4: segment diffing for StyleSpans/Decorations
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>
2026-05-18 21:04:49 -04:00
Levi Neuwirth efa8f6f8ed M11.3: Decorations projection (selection + diagnostics)
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>
2026-05-18 20:47:18 -04:00
Levi Neuwirth 4ba6fd7bb8 M11.2: semantic projection seam (SemanticRenderState)
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>
2026-05-18 20:14:08 -04:00