plugins/treesitter: switch to mkNeovimPlugin

This commit is contained in:
Austin Horstman 2024-07-01 23:00:34 -05:00
parent c0ea106b4b
commit 435ef287ab
No known key found for this signature in database
3 changed files with 386 additions and 193 deletions

View file

@ -0,0 +1,17 @@
;; extends
(binding
attrpath: (attrpath (identifier) @_path)
expression: [
(string_expression (string_fragment) @lua)
(indented_string_expression (string_fragment) @lua)
]
(#match? @_path "^extraConfigLua(Pre|Post)?$"))
(binding
attrpath: (attrpath (identifier) @_path)
expression: [
(string_expression (string_fragment) @vim)
(indented_string_expression (string_fragment) @vim)
]
(#match? @_path "^extraConfigVim(Pre|Post)?$"))

View file

@ -6,210 +6,309 @@
... ...
}: }:
with lib; with lib;
let helpers.neovim-plugin.mkNeovimPlugin config {
cfg = config.plugins.treesitter; name = "treesitter";
in originalName = "nvim-treesitter";
{ luaName = "nvim-treesitter.configs";
options = { defaultPackage = pkgs.vimPlugins.nvim-treesitter;
plugins.treesitter = {
enable = mkEnableOption "tree-sitter syntax highlighting";
package = mkOption { maintainers = [ lib.maintainers.khaneliman ];
type = types.package;
default = pkgs.vimPlugins.nvim-treesitter;
description = "Plugin to use for nvim-treesitter. If using nixGrammars, it should include a `withPlugins` function";
};
nixGrammars = mkOption { # TODO introduced 2024-07-06: remove after 24.11
type = types.bool; optionsRenamedToSettings = [
default = true; "ensureInstalled"
description = "Install grammars with Nix"; "ignoreInstall"
}; "parserInstallDir"
[
"incrementalSelection"
"enable"
]
[
"incrementalSelection"
"keymaps"
"initSelection"
"nodeDecremental"
]
[
"incrementalSelection"
"keymaps"
"initSelection"
"nodeIncremental"
]
[
"incrementalSelection"
"keymaps"
"initSelection"
"scopeIncremental"
]
];
ensureInstalled = mkOption { imports =
type = let
with types; basePluginPath = [
oneOf [ "plugins"
(enum [ "all" ]) "treesitter"
(listOf str) ];
]; settingsPath = basePluginPath ++ [ "settings" ];
default = "all"; in
description = "Either \"all\" or a list of languages"; [
}; (lib.mkRenamedOptionModule (basePluginPath ++ [ "moduleConfig" ]) settingsPath)
(lib.mkRenamedOptionModule (basePluginPath ++ [ "customCaptures" ]) (
settingsPath
++ [
"highlight"
"custom_captures"
]
))
(lib.mkRenamedOptionModule (basePluginPath ++ [ "disabledLanguages" ]) (
settingsPath
++ [
"highlight"
"disable"
]
))
(lib.mkRenamedOptionModule (basePluginPath ++ [ "indent" ]) (
settingsPath
++ [
"indent"
"enable"
]
))
];
gccPackage = helpers.mkPackageOption { settingsOptions = {
default = if cfg.nixGrammars then null else pkgs.gcc; auto_install = helpers.defaultNullOpts.mkBool false ''
description = '' Whether to automatically install missing parsers when entering a buffer.
Which package (if any) to be added as the GCC compiler. '';
This is required to build grammars if you are not using `nixGrammars`.
To disable the installation of GCC, set this option to `null`.
'';
};
parserInstallDir = mkOption { highlight = {
type = types.nullOr types.str; additional_vim_regex_highlighting =
default = if cfg.nixGrammars then null else "$XDG_DATA_HOME/nvim/treesitter"; helpers.defaultNullOpts.mkNullableWithRaw
description = '' (with helpers.nixvimTypes; either bool (listOf (maybeRaw str)))
Location of the parsers to be installed by the plugin (only needed when nixGrammars is disabled). false
This default might not work on your own install, please make sure that $XDG_DATA_HOME is set if you want to use the default. Otherwise, change it to something that will work for you! ''
''; Setting this to true will run `syntax` and tree-sitter at the same time. \
}; Set this to `true` if you depend on 'syntax' being enabled (e.g. for indentation). \
See `:h syntax`.
ignoreInstall = mkOption { Using this option may slow down your editor, and you may see some duplicate highlights. \
type = types.listOf types.str; Instead of true, it can also be a list of languages.
default = [ ]; '';
description = "List of parsers to ignore installing (for \"all\")";
};
disabledLanguages = mkOption { enable = helpers.defaultNullOpts.mkBool false ''
type = types.listOf types.str; Whether to enable treesitter highlighting.
default = [ ]; '';
description = "A list of languages to disable";
};
customCaptures = mkOption { disable =
type = types.attrsOf types.str; helpers.defaultNullOpts.mkStrLuaFnOr (with helpers.nixvimTypes; listOf (maybeRaw str)) null
default = { }; ''
description = "Custom capture group highlighting"; Can either be a list of the names of parsers you wish to disable or
}; a lua function that returns a boolean indicating the parser should be disabled.
'';
incrementalSelection = custom_captures = helpers.defaultNullOpts.mkAttrsOf types.str { } ''
Custom capture group highlighting.
'';
};
incremental_selection = {
enable = helpers.defaultNullOpts.mkBool false ''
Incremental selection based on the named nodes from the grammar.
'';
keymaps =
let let
keymap = mkKeymap = default: helpers.defaultNullOpts.mkStr default "Key shortcut";
default:
mkOption {
type = types.str;
inherit default;
description = "Key shortcut";
};
in in
{ {
enable = mkEnableOption "incremental selection based on the named nodes from the grammar"; init_selection = mkKeymap "gnn";
keymaps = { node_incremental = mkKeymap "grn";
initSelection = keymap "gnn"; scope_incremental = mkKeymap "grc";
nodeIncremental = keymap "grn"; node_decremental = mkKeymap "grm";
scopeIncremental = keymap "grc";
nodeDecremental = keymap "grm";
};
}; };
};
indent = mkEnableOption "tree-sitter based indentation"; indent = {
enable = helpers.defaultNullOpts.mkBool false ''
Whether to enable treesitter indentation.
'';
};
folding = mkEnableOption "tree-sitter based folding"; ensure_installed = helpers.defaultNullOpts.mkListOf types.str [ ] ''
Either "all" or a list of languages to ensure installing.
'';
languageRegister = mkOption { ignore_install = helpers.defaultNullOpts.mkListOf types.str [ ] ''
type = with types; attrsOf (either str (listOf str)); List of parsers to ignore installing. Used when `ensure_installed` is set to "all".
description = '' '';
This is a wrapping of the `vim.treesitter.language.register` function.
Register specific parsers to one or several filetypes. parser_install_dir = helpers.defaultNullOpts.mkStr "$XDG_DATA_HOME/nvim/treesitter" ''
The keys are the parser names and the values are either one or several filetypes. Location of the parsers to be installed by the plugin (only needed when `nixGrammars` is disabled).
'';
default = { }; This default might not work on your own install, please make sure that `$XDG_DATA_HOME` is set if you want to use the default.
example = { Otherwise, change it to something that will work for you!
cpp = "onelab"; '';
python = [
"myFiletype" sync_install = helpers.defaultNullOpts.mkBool false ''
"anotherFiletype" Install parsers synchronously (only applied to `ensure_installed`).
]; '';
}; };
settingsExample = {
additional_vim_regex_highlighting = true;
ensure_installed = true;
ignore_install = [ "rust" ];
indent = true;
parser_install_dir = "$XDG_DATA_HOME/nvim/treesitter";
highlight = {
enable = true;
disable = [ "rust" ];
custom_captures = { };
};
incremental_selection = {
enable = true;
keymaps = {
init_selection = "gnn";
node_incremental = "grn";
scope_incremental = "grc";
node_decremental = "grm";
}; };
grammarPackages = mkOption {
type = with types; listOf package;
default = cfg.package.passthru.allGrammars;
description = "Grammar packages to install";
};
moduleConfig = mkOption {
type = types.attrsOf types.anything;
default = { };
description = "This is the configuration for extra modules. It should not be used directly";
};
nixvimInjections = mkEnableOption "nixvim specific injections, like lua highlighting in extraConfigLua";
}; };
}; };
config = extraOptions = {
let folding = mkOption {
tsOptions = { type = types.bool;
highlight = { default = true;
inherit (cfg) enable; example = false;
disable = if (cfg.disabledLanguages != [ ]) then cfg.disabledLanguages else null; description = "Whether to enable treesitter folding.";
};
custom_captures = if (cfg.customCaptures != { }) then cfg.customCaptures else null; gccPackage = helpers.mkPackageOption {
}; name = "gcc";
default = pkgs.gcc;
defaultText = literalExpression "pkgs.gcc";
example = literalExpression "pkgs.gcc14";
description = ''
Which package (if any) to be added as the GCC compiler.
incremental_selection = This is required to build grammars if you are not using `nixGrammars`.
if cfg.incrementalSelection.enable then To disable the installation of GCC, set this option to `null`.
{ '';
enable = true; };
keymaps = {
init_selection = cfg.incrementalSelection.keymaps.initSelection;
node_incremental = cfg.incrementalSelection.keymaps.nodeIncremental;
scope_incremental = cfg.incrementalSelection.keymaps.scopeIncremental;
node_decremental = cfg.incrementalSelection.keymaps.nodeDecremental;
};
}
else
null;
indent = if cfg.indent then { enable = true; } else null; grammarPackages = mkOption {
type = with types; listOf package;
default = config.plugins.treesitter.package.passthru.allGrammars;
example = literalExpression "pkgs.vimPlugins.nvim-treesitter.passthru.allGrammars";
defaultText = literalExpression "config.plugins.treesitter.package.passthru.allGrammars";
description = "Grammar packages to install";
};
ensure_installed = if cfg.nixGrammars then [ ] else cfg.ensureInstalled; # TODO: Implement rawLua support to be passed into extraConfigLua.
ignore_install = cfg.ignoreInstall; languageRegister = mkOption {
parser_install_dir = cfg.parserInstallDir; type = with types; attrsOf (coercedTo str toList (listOf str));
} // cfg.moduleConfig; default = { };
in example = {
mkIf cfg.enable { cpp = "onelab";
extraConfigLua = python = [
(optionalString (cfg.parserInstallDir != null) '' "foo"
vim.opt.runtimepath:append("${cfg.parserInstallDir}") "bar"
'') ];
+ '' };
require('nvim-treesitter.configs').setup(${helpers.toLuaObject tsOptions}) description = ''
'' This is a wrapping of the `vim.treesitter.language.register` function.
+ (optionalString (cfg.languageRegister != { }) ''
__parserFiletypeMappings = ${helpers.toLuaObject cfg.languageRegister} Register specific parsers to one or several filetypes.
The keys are the parser names and the values are either one or several filetypes.
'';
};
nixGrammars = mkOption {
type = types.bool;
default = true;
example = false;
description = "Whether to install grammars defined in `grammarPackages`.";
};
nixvimInjections = mkOption {
type = types.bool;
default = true;
example = false;
description = "Whether to enable Nixvim injections, e.g. highlighting `extraConfigLua` as lua.";
};
nodejsPackage = helpers.mkPackageOption {
name = "nodejs";
default = pkgs.nodejs;
defaultText = literalExpression "pkgs.nodejs";
example = literalExpression "pkgs.nodejs_22";
description = ''
Which package (if any) to be added as the nodejs package.
This is required to build grammars if you are not using `nixGrammars`.
To disable the installation of NodeJS, set this option to `null`.
'';
};
treesitterPackage = helpers.mkPackageOption {
name = "tree-sitter";
default = pkgs.tree-sitter;
defaultText = literalExpression "pkgs.tree-sitter";
description = ''
Which package (if any) to be added as the tree-sitter binary.
This is required to build grammars if you are not using `nixGrammars`.
To disable the installation of tree-sitter, set this option to `null`.
'';
};
};
# NOTE: We call setup manually below.
callSetup = false;
# NOTE: We install cfg.package manually so we can install grammars using it.
installPackage = false;
extraConfig = cfg: {
extraConfigLua =
# NOTE: Upstream state that the parser MUST be at the beginning of runtimepath.
# Otherwise the parsers from Neovim takes precedent, which may be incompatible with some queries.
(optionalString (cfg.settings.parser_install_dir != null) ''
vim.opt.runtimepath:prepend("${cfg.settings.parser_install_dir}")
'')
+ ''
require('nvim-treesitter.configs').setup(${helpers.toLuaObject cfg.settings})
''
+ (optionalString (cfg.languageRegister != { }) ''
do
local __parserFiletypeMappings = ${helpers.toLuaObject cfg.languageRegister}
for parser_name, ft in pairs(__parserFiletypeMappings) do for parser_name, ft in pairs(__parserFiletypeMappings) do
require('vim.treesitter.language').register(parser_name, ft) require('vim.treesitter.language').register(parser_name, ft)
end end
''); end
'');
extraFiles = mkIf cfg.nixvimInjections { extraFiles = mkIf cfg.nixvimInjections { "queries/nix/injections.scm".source = ./injections.scm; };
"queries/nix/injections.scm".text = ''
;; extends
(binding extraPlugins = mkIf (cfg.package != null) [
attrpath: (attrpath (identifier) @_path) (mkIf cfg.nixGrammars (cfg.package.withPlugins (_: cfg.grammarPackages)))
expression: [ (mkIf (!cfg.nixGrammars) cfg.package)
(string_expression (string_fragment) @lua) ];
(indented_string_expression (string_fragment) @lua)
]
(#match? @_path "^extraConfigLua(Pre|Post)?$"))
(binding extraPackages = [
attrpath: (attrpath (identifier) @_path) cfg.gccPackage
expression: [ cfg.nodejsPackage
(string_expression (string_fragment) @vim) cfg.treesitterPackage
(indented_string_expression (string_fragment) @vim) ];
]
(#match? @_path "^extraConfigVim(Pre|Post)?$"))
'';
};
extraPlugins = opts = mkIf cfg.folding (mkDefault {
if cfg.nixGrammars then [ (cfg.package.withPlugins (_: cfg.grammarPackages)) ] else [ cfg.package ]; foldmethod = "expr";
extraPackages = with pkgs; [ foldexpr = "nvim_treesitter#foldexpr()";
tree-sitter });
nodejs };
cfg.gccPackage
];
opts = mkIf cfg.folding {
foldmethod = "expr";
foldexpr = "nvim_treesitter#foldexpr()";
};
};
} }

View file

@ -1,18 +1,70 @@
{ pkgs, ... }:
{ {
default = {
plugins.treesitter = {
enable = true;
settings = {
auto_install = false;
ensure_installed = [ ];
ignore_install = [ ];
parser_install_dir = null;
sync_install = false;
highlight = {
additional_vim_regex_highlighting = false;
enable = false;
custom_captures = { };
disable = null;
};
incremental_selection = {
enable = false;
keymaps = {
init_selection = "gnn";
node_incremental = "grn";
scope_incremental = "grc";
node_decremental = "grm";
};
};
indent = {
enable = false;
};
};
};
};
empty = { empty = {
plugins.treesitter.enable = true; plugins.treesitter.enable = true;
}; };
nonix = { empty-grammar-packages = {
# TODO: See if we can build parsers (legacy way)
tests.dontRun = true;
plugins.treesitter = { plugins.treesitter = {
enable = true; enable = true;
nixGrammars = false;
grammarPackages = [ ];
}; };
}; };
nixvimInjections = { highlight-disable-function = {
plugins.treesitter = {
enable = true;
settings = {
highlight = {
enable = true;
disable = ''
function(lang, bufnr)
return api.nvim_buf_line_count(bufnr) > 50000
end
'';
};
};
};
};
nixvim-injections = {
plugins.treesitter = { plugins.treesitter = {
enable = true; enable = true;
nixvimInjections = true; nixvimInjections = true;
@ -27,18 +79,43 @@
}; };
}; };
# This needs a custom input no-nix = {
# custom = { # TODO: See if we can build parsers (legacy way)
# plugins.treesitter = { tests.dontRun = true;
# enable = true; plugins.treesitter = {
# nixGrammars = true; enable = true;
# grammarPackages = [ nixGrammars = false;
# (build-ts.lib.buildGrammar pkgs { };
# language = "gleam"; };
# version = "0.25.0";
# source = gleam; specific-grammars = {
# }) plugins.treesitter = {
# ]; enable = true;
# };
# }; grammarPackages = with pkgs.vimPlugins.nvim-treesitter.builtGrammars; [
bash
git_config
git_rebase
gitattributes
gitcommit
gitignore
json
jsonc
lua
make
markdown
meson
ninja
nix
readline
regex
ssh-config
toml
vim
vimdoc
xml
yaml
];
};
};
} }