pmacs/builtin/runtime
Levi Neuwirth f300b77533 fix(highlight): PR #116 round 1 — shebang precedence, pinned grammar, env operands
Three review findings, all in builtin/runtime/syntax.lua.

1. [P1] Syntax bypassed extension precedence and grammar availability.
   attach_for_active_buffer resolved `language_for_path or shebang`, but
   language_for_path knows only grammar-backed extensions — so a `.py`
   file opening with `#!/bin/sh` fell through to the shebang and got a
   bash parse tree, and an extensionless `#!/usr/bin/env python3` script
   dispatched "python" (no grammar) and raised "unknown language". A new
   resolve_active_language walks the full precedence chain — grammar
   extension -> LSP filetype map -> shebang — consulting the shebang only
   when the extension is unrecognized (a recognized non-grammar extension
   like .py is authoritative). Dispatch is then gated on
   pmacs.parse._has_language(lang), so grammarless languages are skipped
   silently. The extension parts stay keyed on buf:name() (unchanged from
   before), so path-less buffers that resolve a grammar by name — e.g.
   generated markdown buffers — are unaffected.

2. [P2] Editing an open script's shebang left parsing/highlighting stale.
   The after-edit path re-sniffed the mutable shebang: sh -> python
   raised "unknown language" while leaving the old bash tree, and
   sh -> lua swapped the parse tree under a highlight overlay still
   holding the original grammar's query. Reparse now uses the language
   pinned at first attach (parse_lang_by_buffer), never re-resolving —
   a language change needs a close/reopen, as it does for extensions.

3. [P2] `env` options with operands were mistaken for interpreters.
   `#!/usr/bin/env -u FOO python3` skipped `-u` but took `FOO`. The env
   walk now skips the operand of the operand-consuming GNU-env options
   (-u/--unset, -C/--chdir, -a/--argv0) before selecting the interpreter.
   -S/--split-string stays excluded (its string carries the interpreter).

Tests (bite-verified against pre-fix syntax.lua — each fails without its
fix; scripts/bite HEAD builtin/runtime/syntax.lua):
- m4_shebang_does_not_override_extension now also asserts _has_view is
  false (no bash grammar tree for a `.py` + `#!/bin/sh`), not only the
  LSP language.
- m4_shebang_extensionless_grammarless_language_is_silent — extensionless
  python resolves for LSP, gets no grammar view, and records no error.
- m4_shebang_edit_keeps_pinned_grammar — rewriting a `#!/bin/sh` script's
  shebang to lua keeps the bash tree and reports no error.
- m4_shebang_resolver_maps_interpreters — added the env-operand cases
  (`-u FOO`, `-C /tmp`, combined).

Gates: fmt; clippy -D warnings; m4_acceptance --skip basedpyright; GPU;
git diff --check all green. The only sweep failure is the pre-existing
editor::composition_overhead_under_ten_percent render microbenchmark
(ratio hovers at the 1.10 cutoff; flakes ~1/3 even isolated single-
threaded, already asserted-off on macOS) — a pure-Rust render loop this
Lua-only change cannot touch. Change is Lua-only plus the acceptance
tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJ9FQ832QwftJXCD9LeFan
2026-07-14 15:02:59 +01:00
..
async.lua V0.2-prerequisite pull-forward + M10.11 clean audit round 2026-05-18 10:31:31 -04:00
autosave.lua fix(persistence): adopt clears the old owner's skip cache; failing sweeps are loud 2026-07-09 12:06:49 -04:00
comment.lua feat(edit): comment/uncomment toggle on M-; (Arc 2) 2026-07-09 22:56:44 -04:00
compile.lua fix(compile): PR #113 round 5 — buffer-level span translation, fragment preservation, tracked line start 2026-07-13 22:07:01 +01:00
completion.lua fix(completion): address TUI-validation findings (LSP query gaps, scoping, prefix keys, window scope) 2026-07-07 16:54:14 -04:00
desktop.lua fix(persistence): reliable daemon gate, unarm, per-pane after-load 2026-07-08 22:27:24 -04:00
editops.lua fix(edit): PR #111 round 1 — scalar-valid UTF-8, per-word capitalize, trim error reporting 2026-07-12 16:34:18 +01:00
fs.lua V0.2-prerequisite pull-forward + M10.11 clean audit round 2026-05-18 10:31:31 -04:00
indent.lua fix(edit): PR #109 round 1 — shared search invalidation, daemon anchor clear, bounded indent scan 2026-07-10 15:46:36 -04:00
killring.lua feat(edit): editing-conveniences pack (editops) 2026-07-12 15:33:17 +01:00
listview.lua feat(panels): listview module, Q#P6 round-trip seam, references panel 2026-07-07 20:15:46 -04:00
lsp.lua feat(highlight): shebang-based language detection for extensionless scripts 2026-07-14 14:33:06 +01:00
mcp.lua M9 ship gate 2026-05-09 15:04:23 -04:00
pair.lua fix(edit): PR #110 round 2 — UTF-8 well-formedness, source-buffer relevance, non-table sets 2026-07-12 15:54:16 +01:00
recentf.lua fix(persistence): symlink confinement, real test-inertness, view_top restore 2026-07-08 18:21:46 -04:00
saveplace.lua fix(persistence): symlink confinement, real test-inertness, view_top restore 2026-07-08 18:21:46 -04:00
syntax.lua fix(highlight): PR #116 round 1 — shebang precedence, pinned grammar, env operands 2026-07-14 15:02:59 +01:00