From cd6a1b626be5930bd3890542d984741100cc9cc0 Mon Sep 17 00:00:00 2001 From: sean <91675054+undont@users.noreply.github.com> Date: Mon, 10 Aug 2026 11:21:27 +0100 Subject: [PATCH 1/2] feat: highlight injected languages in the diff view the syntax pass parsed only a file's own grammar, so anything a query hands to another parser stayed plain: an astro file showed its tags and nothing else, its frontmatter, script and style bodies all being injections. walk the language tree instead of the root alone, host before its injections, each layer one priority above the tree it was lifted from so embedded code wins where the host also covers the region. captures are cached per model, so a layout or context toggle reprojects rather than reparsing both sides. --- lua/differ/syntax/init.lua | 159 ++++++++++++++++++++++++++-------- lua/differ/syntax/project.lua | 3 + test/nvim/syntax_spec.lua | 90 ++++++++++++++++++- test/unit/syntax_spec.lua | 16 ++++ 4 files changed, 231 insertions(+), 37 deletions(-) diff --git a/lua/differ/syntax/init.lua b/lua/differ/syntax/init.lua index cb4790e..22e20ad 100644 --- a/lua/differ/syntax/init.lua +++ b/lua/differ/syntax/init.lua @@ -13,8 +13,16 @@ local M = {} local ns = vim.api.nvim_create_namespace("differ.syntax") -- layering: syntax foreground sits *under* the diff line background (paint --- uses 100) and word-level spans (200), so the diff state always reads on top +-- uses 100) and word-level spans (200), so the diff state always reads on top. +-- an injected layer sits one above its host, capped short of the diff layer, so +-- embedded code wins where the host also captures the region it was lifted from local PRIORITY = 90 +local MAX_DEPTH_BUMP = 9 + +-- ceiling for parsing injections. the primary tree is still parsed above it, so a +-- generated file keeps its tag/keyword level highlighting without paying for +-- injection discovery over the whole tree +local INJECTION_MAX_BYTES = 512 * 1024 -- resolve a treesitter language for `path`, or nil when there's no filetype, no -- mapped language, or the parser isn't installed, in which case the pass is @@ -39,10 +47,88 @@ local function resolve_lang(path) return lang end --- parse `text` and collect highlight captures in source coordinates. mirrors the --- core highlighter: hl group is `@.`, captures named `_…` are --- internal and skipped. multi-line captures are clipped to one entry per line; --- injections (embedded languages) are deferred for v1, only the primary tree +-- treesitter handles are typed `any`: there's no nvim type library on the +-- typecheck path, so naming TSTree/TSNode/Query would only be an undefined alias +---@class differ.SyntaxLayer +---@field tree any -- TSTree +---@field lang string +---@field query any -- vim.treesitter.Query +---@field priority integer + +-- flatten a language tree into paint layers, host before its injections so +-- embedded code is applied over the region the host lifted it from. one injected +-- language holds one layer per region, not one per language, so a file with three +-- `