Merge pull request #37 from levineuwirth/worktree-tui-tree-sitter-cpp-dual-authority
tree-sitter-cpp/c + dual-authority styling (real C++ colors)
This commit is contained in:
commit
f98a885014
|
|
@ -1264,6 +1264,8 @@ dependencies = [
|
|||
"thiserror 2.0.18",
|
||||
"toml",
|
||||
"tree-sitter",
|
||||
"tree-sitter-c",
|
||||
"tree-sitter-cpp",
|
||||
"tree-sitter-lua",
|
||||
"tree-sitter-md",
|
||||
"tree-sitter-rust",
|
||||
|
|
@ -2039,6 +2041,26 @@ dependencies = [
|
|||
"tree-sitter-language",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-c"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9b2eb57a55fed6b00812912e730b7a275cf4fe98bfd6a5d76263d4438371728"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"tree-sitter-language",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-cpp"
|
||||
version = "0.23.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df2196ea9d47b4ab4a31b9297eaa5a5d19a0b121dceb9f118f6790ad0ab94743"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"tree-sitter-language",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-language"
|
||||
version = "0.1.7"
|
||||
|
|
|
|||
|
|
@ -101,6 +101,14 @@ tree-sitter = "0.26"
|
|||
# `crate::syntax::BUILTIN_LANGUAGES`.
|
||||
tree-sitter-rust = "0.24"
|
||||
tree-sitter-lua = "0.5"
|
||||
# T M_B3 — C / C++. Bundled so opening a `.c`/`.cpp`/header file in
|
||||
# the grid TUI gets lexical highlighting (keywords/strings/operators)
|
||||
# via tree-sitter, with `LspStyleView` layered on top for semantic
|
||||
# refinement (functions/types/macros via clangd's semantic tokens).
|
||||
# `.h` is ambiguous C / C++; the `c` entry below claims it by default,
|
||||
# matching the LSP filetype map in `builtin/runtime/lsp.lua`.
|
||||
tree-sitter-c = "0.24"
|
||||
tree-sitter-cpp = "0.23"
|
||||
# T M9.7: markdown grammar so prompt result buffers with
|
||||
# `_meta.format = "markdown"` get structured highlighting through the
|
||||
# same M4 path as rust/lua — no special-case painter in Lua.
|
||||
|
|
|
|||
|
|
@ -347,16 +347,17 @@ local function attach_buffer(buf)
|
|||
-- did_open is a notification; the manager queues it cleanly even
|
||||
-- while the server is in `starting` / `initializing`.
|
||||
pcall(pmacs.lsp.did_open, sid, uri, rec.version, active_buffer_text())
|
||||
-- M_B1: policy A — when this buffer has no bundled tree-sitter
|
||||
-- grammar (C/C++, …), push the LSP-driven style overlay onto the
|
||||
-- active window so the grid TUI gets cell coloring from LSP
|
||||
-- semantic tokens. Grammar-backed languages already have
|
||||
-- `SyntaxHighlightView`; never both authorities on one buffer.
|
||||
-- `language_for_path` returning nil is the grammar-less signal
|
||||
-- (the LSP filetype map is consulted independently above).
|
||||
if not styled_buffers[key]
|
||||
and not pmacs.parse.language_for_path(path)
|
||||
then
|
||||
-- M_B3: dual-authority styling. Always push the LSP style overlay
|
||||
-- when an LSP server is up — whether or not the buffer has a
|
||||
-- bundled tree-sitter grammar. When the grammar exists too,
|
||||
-- `SyntaxHighlightView` paints first (lexical: keywords, strings,
|
||||
-- operators) and `LspStyleView` paints after (semantic: function /
|
||||
-- type / macro / namespace identifiers from clangd's tokens); their
|
||||
-- styles compose via `crate::overlay::merge_styles`, so the final
|
||||
-- cell carries both authorities' contributions. This replaces
|
||||
-- M_B1's policy-A exclusivity, which left grammar-backed languages
|
||||
-- (Rust, C, C++) without LSP semantic refinement.
|
||||
if not styled_buffers[key] then
|
||||
local ok, attached = pcall(pmacs.lsp._attach_style, buf)
|
||||
if ok and attached then styled_buffers[key] = true end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -464,13 +464,28 @@ pub fn is_default_style(style: Style) -> bool {
|
|||
// LspStyleView
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// View that paints LSP semantic-token styling into cells for buffers
|
||||
/// with **no bundled tree-sitter grammar** (C/C++, …). Sibling of
|
||||
/// [`SyntaxHighlightView`] for the same policy-A "one styling
|
||||
/// authority per language" rule that `SemanticRenderState` applies on
|
||||
/// the semantic-frontend side — but feeding the grid TUI's existing
|
||||
/// cell-painter pipeline instead. Closes the visible "no syntax
|
||||
/// coloring for grammar-less languages in the TUI" gap.
|
||||
/// View that paints LSP semantic-token styling into cells, layered
|
||||
/// **alongside** [`SyntaxHighlightView`] when both exist for a
|
||||
/// buffer. The grid TUI's `View::render` composition stack means
|
||||
/// tree-sitter paints first (lexical: keywords, strings, operators,
|
||||
/// the things a parser identifies from the source's *shape*) and
|
||||
/// `LspStyleView` paints after (semantic: function vs variable,
|
||||
/// macro vs constant, the things a language server identifies from
|
||||
/// program *meaning*). Their styles compose through
|
||||
/// [`crate::overlay::merge_styles`], so the final cell carries both
|
||||
/// authorities' contributions — the `VSCode` / `Zed` "`TextMate` +
|
||||
/// LSP semantic tokens" model, on a terminal grid.
|
||||
///
|
||||
/// For languages with no bundled tree-sitter grammar (Python, Go,
|
||||
/// languages added later via LSP only), `LspStyleView` is the *sole*
|
||||
/// styling source and still works — the merge with an absent
|
||||
/// tree-sitter overlay is identity.
|
||||
///
|
||||
/// `M_B3` (this) dropped the earlier policy-A exclusivity gate in
|
||||
/// `lsp.lua` that restricted attachment to grammar-less buffers. The
|
||||
/// previous gate left grammar-backed languages (Rust, C, C++) without
|
||||
/// LSP semantic refinement; dual-authority delivers richer coloring
|
||||
/// without conflict.
|
||||
///
|
||||
/// Holds shared handles only (`SharedLspManager` + `ThemeHandle`), so
|
||||
/// it survives buffer renames and LSP server restarts: every `render`
|
||||
|
|
@ -763,9 +778,11 @@ mod tests {
|
|||
let state = EditorState::new();
|
||||
let buffer_id = state.core.borrow().active_window().buffer_id;
|
||||
|
||||
// Seed the buffer: one line, `.cpp` path (no bundled grammar →
|
||||
// SyntaxHighlightView never attaches, the LSP path owns the
|
||||
// styling per policy A).
|
||||
// Seed the buffer: one line, `.cpp` path. The test renders
|
||||
// `LspStyleView` directly (no `SyntaxHighlightView` attached
|
||||
// alongside in this fixture), so the asserted cells reflect
|
||||
// the LSP authority alone — M_B3's dual-authority composition
|
||||
// is exercised end-to-end by Lua's `attach_buffer`, not here.
|
||||
{
|
||||
let mut core = state.core.borrow_mut();
|
||||
core.registry
|
||||
|
|
|
|||
|
|
@ -377,6 +377,33 @@ pub const BUILTIN_LANGUAGES: &[LanguageEntry] = &[
|
|||
loader: || tree_sitter_md::LANGUAGE.into(),
|
||||
highlights_query: tree_sitter_md::HIGHLIGHT_QUERY_BLOCK,
|
||||
},
|
||||
// T M_B3 — C / C++. Lexical highlighting (keywords / strings /
|
||||
// operators) so the grid TUI shows code-shaped C++ on first open.
|
||||
// `LspStyleView` layers on top with semantic refinement
|
||||
// (functions / types / macros / namespaces) from clangd's
|
||||
// semantic tokens — the two views' styles merge via
|
||||
// `crate::overlay::merge_styles`.
|
||||
//
|
||||
// `.h` is ambiguous C / C++; the `c` entry below claims it
|
||||
// (matches the LSP filetype map's default in `lsp.lua`). Users
|
||||
// who want `.h` parsed as C++ can override via Lua.
|
||||
// Note the const names: `tree-sitter-c` and `tree-sitter-cpp`
|
||||
// expose `HIGHLIGHT_QUERY` (singular), matching the `tree-sitter-md`
|
||||
// crate's `HIGHLIGHT_QUERY_BLOCK` style; `tree-sitter-rust` and
|
||||
// `tree-sitter-lua` use `HIGHLIGHTS_QUERY` (plural). No semantic
|
||||
// difference — same bundled `highlights.scm` either way.
|
||||
LanguageEntry {
|
||||
name: "c",
|
||||
extensions: &["c", "h"],
|
||||
loader: || tree_sitter_c::LANGUAGE.into(),
|
||||
highlights_query: tree_sitter_c::HIGHLIGHT_QUERY,
|
||||
},
|
||||
LanguageEntry {
|
||||
name: "cpp",
|
||||
extensions: &["cpp", "cc", "cxx", "hpp", "hh", "hxx", "ipp", "inl", "cppm"],
|
||||
loader: || tree_sitter_cpp::LANGUAGE.into(),
|
||||
highlights_query: tree_sitter_cpp::HIGHLIGHT_QUERY,
|
||||
},
|
||||
];
|
||||
|
||||
/// Registry that the Lua surface ([`crate::lua_bindings::install_parse`])
|
||||
|
|
@ -712,6 +739,38 @@ mod tests {
|
|||
bundle
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_languages_include_c_and_cpp() {
|
||||
// M_B3 regression guard: a future refactor must not silently
|
||||
// drop C / C++ tree-sitter coverage — the dual-authority
|
||||
// styling in the TUI depends on these entries existing and
|
||||
// claiming their canonical extensions.
|
||||
let c = BUILTIN_LANGUAGES
|
||||
.iter()
|
||||
.find(|l| l.name == "c")
|
||||
.expect("`c` language entry must be present");
|
||||
assert!(c.extensions.contains(&"c"), "`c` claims `.c`");
|
||||
assert!(
|
||||
c.extensions.contains(&"h"),
|
||||
"`c` claims `.h` (matches the LSP filetype map's default)"
|
||||
);
|
||||
assert!(
|
||||
!c.highlights_query.is_empty(),
|
||||
"`c` ships a non-empty highlights query"
|
||||
);
|
||||
let cpp = BUILTIN_LANGUAGES
|
||||
.iter()
|
||||
.find(|l| l.name == "cpp")
|
||||
.expect("`cpp` language entry must be present");
|
||||
for ext in ["cpp", "cc", "cxx", "hpp", "hh", "hxx"] {
|
||||
assert!(cpp.extensions.contains(&ext), "`cpp` claims `.{ext}`");
|
||||
}
|
||||
assert!(
|
||||
!cpp.highlights_query.is_empty(),
|
||||
"`cpp` ships a non-empty highlights query"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn byte_to_point_handles_first_line() {
|
||||
let src = b"hello world";
|
||||
|
|
|
|||
Loading…
Reference in New Issue