neovim/queries: init and add an example injection

This commit is contained in:
Snoweuph 2026-04-19 15:26:48 +02:00
commit 6fe9ecd995
No known key found for this signature in database
GPG key ID: BEFC41DA223CEC55
6 changed files with 181 additions and 4 deletions

View file

@ -21,4 +21,5 @@ configuring/keybinds.md
configuring/dags.md
configuring/dag-entries.md
configuring/autocmds.md
configuring/queries.md
```

View file

@ -0,0 +1,46 @@
# Queries (`vim.treesitter.queries`)
Queries allow you to change Neovim's behavior based on Tree-sitter.\
Read more about it in the
[neovim docs](https://neovim.io/doc/user/treesitter/#_treesitter-queries).
**Example:**
In the following example, we are creating a custom injection, to highlight the
Lua string after `mkLuaInline`.
```nix
foo = mkLuaInline ''
function bar()
return 'foobar'
end
'';
```
```nix
{
vim.treesitter.queries = [{
type = "injections";
filetypes = ["nix"];
content = ''
;; extends
((apply_expression
function: (variable_expression
name: (identifier) @_func
(#eq? @_func "mkLuaInline"))
argument: (indented_string_expression
(string_fragment) @injection.content)
(#set! injection.language "lua")
(#set! injection.combined)))
'';
}];
}
```
This will generate a `queries/nix/injections.scm` in a Neovim runtime directory.
> [!NOTE]
> When multiple queries match the same `filetype` and `type`, they are merged.

View file

@ -271,6 +271,11 @@
[Snoweuph](https://github.com/snoweuph)
- Added {option}`vim.treesitter.queries` to support adding custom queries.
- Added injections for `vim.treesitter.queries.*.content` as `query` and
`mkLualine ""` as `lua`.
- Added `vim.lsp.presets.<name>` to contain LSP configurations. This allows for
more flexibility in nvf and reuse of LSPs across languages. Dropped
`deprecatedSingleOrListOf` in favor of `listOf` for the affected LSP options.

View file

@ -128,8 +128,74 @@ in {
}
(mkIf cfg.treesitter.enable {
vim.treesitter.enable = true;
vim.treesitter.grammars = [cfg.treesitter.package];
vim.treesitter = {
enable = true;
grammars = [cfg.treesitter.package];
queries = [
# vim.treesitter.queries.*.content
{
type = "injections";
filetypes = ["nix"];
content = ''
;; extends
(
(binding
attrpath: (attrpath
(identifier) @_a
(identifier) @_b
(identifier)? @_c)
(#eq? @_a "vim")
(#any-of? @_b "treesitter")
(#any-of? @_c "queries")
expression: (attrset_expression
(binding_set
(binding
attrpath: (attrpath
(identifier) @_queries)
(#eq? @_queries "queries")
expression: (list_expression
(attrset_expression
(binding_set
(binding
attrpath: (attrpath
(identifier) @_field)
(#eq? @_field "content")
expression: [
(string_expression
(string_fragment) @injection.content)
(indented_string_expression
(string_fragment) @injection.content)
]
(#set! injection.language "query")
(#set! injection.combined)))))))))
)
'';
}
# mkLuaInline = lua
{
type = "injections";
filetypes = ["nix"];
content = ''
;; extends
((apply_expression
function: (variable_expression
name: (identifier) @_func
(#eq? @_func "mkLuaInline"))
argument: (indented_string_expression
(string_fragment) @injection.content)
(#set! injection.language "lua")
(#set! injection.combined)))
'';
}
];
};
})
(mkIf cfg.lsp.enable {

View file

@ -1,9 +1,10 @@
{
config,
lib,
pkgs,
...
}: let
inherit (lib.modules) mkIf;
inherit (lib) mkIf foldl' mapAttrsToList;
inherit (lib.strings) optionalString;
inherit (lib.lists) optionals;
inherit (lib.nvim.dag) entryAfter;
@ -66,6 +67,40 @@ in {
})
''}
'';
additionalRuntimePaths = mkIf (cfg.queries != []) [
(let
grouped =
foldl'
(
acc: query:
foldl'
(
inner: filetype: let
path = "queries/${filetype}/${query.type}.scm";
prev = inner.${path} or "";
in
inner
// {
${path} = prev + query.content;
}
)
acc
query.filetypes
)
{}
cfg.queries;
files =
mapAttrsToList
(path: content: {
name = path;
path = pkgs.writeText path content;
})
grouped;
in
pkgs.linkFarm "treesitter-queries" files)
];
};
};
}

View file

@ -4,7 +4,25 @@
...
}: let
inherit (lib.options) mkOption mkEnableOption literalExpression;
inherit (lib.types) listOf nullOr package bool str oneOf;
inherit (lib.types) listOf nullOr package bool str lines enum submodule oneOf;
queriesType = submodule {
options = {
type = mkOption {
type = enum ["injections" "highlights" "folds" "locals" "indents"];
description = "The kind of query to register.";
};
filetypes = mkOption {
type = listOf str;
default = [];
description = "The filetypes for which the query should be registered.";
};
content = mkOption {
type = lines;
description = "The queries scm script.";
};
};
};
in {
options.vim.treesitter = {
enable = mkEnableOption "treesitter, also enabled automatically through language options";
@ -87,5 +105,11 @@ in {
};
highlight = {enable = mkEnableOption "highlighting with treesitter" // {default = true;};};
queries = mkOption {
type = listOf queriesType;
default = [];
description = "A list of Neovim treesitter queries to be registered.";
};
};
}