1{
2 lib,
3 callPackage,
4 tree-sitter,
5 neovim,
6 neovimUtils,
7 runCommand,
8 vimPlugins,
9 tree-sitter-grammars,
10 writableTmpDirAsHomeHook,
11}:
12
13self: super:
14
15let
16 inherit (neovimUtils) grammarToPlugin;
17
18 overrides = prev: {
19 };
20
21 generatedGrammars =
22 let
23 generated = callPackage ./generated.nix {
24 inherit (tree-sitter) buildGrammar;
25 };
26 in
27 lib.overrideExisting generated (overrides generated);
28
29 generatedDerivations = lib.filterAttrs (_: lib.isDerivation) generatedGrammars;
30
31 # add aliases so grammars from `tree-sitter` are overwritten in `withPlugins`
32 # for example, for ocaml_interface, the following aliases will be added
33 # ocaml-interface
34 # tree-sitter-ocaml-interface
35 # tree-sitter-ocaml_interface
36 builtGrammars =
37 generatedGrammars
38 // lib.concatMapAttrs (
39 k: v:
40 let
41 replaced = lib.replaceStrings [ "_" ] [ "-" ] k;
42 in
43 {
44 "tree-sitter-${k}" = v;
45 }
46 // lib.optionalAttrs (k != replaced) {
47 ${replaced} = v;
48 "tree-sitter-${replaced}" = v;
49 }
50 ) generatedDerivations;
51
52 allGrammars = lib.attrValues generatedDerivations;
53
54 # Usage:
55 # pkgs.vimPlugins.nvim-treesitter.withPlugins (p: [ p.c p.java ... ])
56 # or for all grammars:
57 # pkgs.vimPlugins.nvim-treesitter.withAllGrammars
58 withPlugins =
59 f:
60 self.nvim-treesitter.overrideAttrs {
61 passthru.dependencies = map grammarToPlugin (f (tree-sitter.builtGrammars // builtGrammars));
62 };
63
64 withAllGrammars = withPlugins (_: allGrammars);
65in
66
67{
68 postPatch = ''
69 rm -r parser
70 '';
71
72 passthru = (super.nvim-treesitter.passthru or { }) // {
73 inherit
74 builtGrammars
75 allGrammars
76 grammarToPlugin
77 withPlugins
78 withAllGrammars
79 ;
80
81 grammarPlugins = lib.mapAttrs (_: grammarToPlugin) generatedDerivations;
82
83 tests = {
84 check-queries =
85 let
86 nvimWithAllGrammars = neovim.override {
87 configure.packages.all.start = [ withAllGrammars ];
88 };
89 in
90 runCommand "nvim-treesitter-check-queries"
91 {
92 nativeBuildInputs = [
93 nvimWithAllGrammars
94 writableTmpDirAsHomeHook
95 ];
96 CI = true;
97 }
98 ''
99 touch $out
100 ln -s ${withAllGrammars}/CONTRIBUTING.md .
101 export ALLOWED_INSTALLATION_FAILURES=ipkg,norg,verilog
102
103 nvim --headless "+luafile ${withAllGrammars}/scripts/check-queries.lua" | tee log
104
105 if grep -q Warning log; then
106 echo "WARNING: warnings were emitted by the check"
107 echo "Check if they were expected warnings!"
108 fi
109 '';
110
111 tree-sitter-queries-are-present-for-custom-grammars =
112 let
113 pluginsToCheck =
114 builtins.map (grammar: grammarToPlugin grammar)
115 # true is here because there is `recurseForDerivations = true`
116 (lib.remove true (lib.attrValues tree-sitter-grammars));
117 in
118 runCommand "nvim-treesitter-test-queries-are-present-for-custom-grammars" { CI = true; } ''
119 function check_grammar {
120 EXPECTED_FILES="$2/parser/$1.so `ls $2/queries/$1/*.scm`"
121
122 echo
123 echo expected files for $1:
124 echo $EXPECTED_FILES
125
126 # the derivation has only symlinks, and `find` doesn't count them as files
127 # so we cannot use `-type f`
128 for file in `find $2 -not -type d`; do
129 echo checking $file
130 # see https://stackoverflow.com/a/8063284
131 if ! echo "$EXPECTED_FILES" | grep -wqF "$file"; then
132 echo $file is unexpected, exiting
133 exit 1
134 fi
135 done
136 }
137
138 ${lib.concatLines (lib.forEach pluginsToCheck (g: "check_grammar \"${g.grammarName}\" \"${g}\""))}
139 touch $out
140 '';
141
142 no-queries-for-official-grammars =
143 let
144 pluginsToCheck =
145 # true is here because there is `recurseForDerivations = true`
146 (lib.remove true (lib.attrValues vimPlugins.nvim-treesitter-parsers));
147 in
148 runCommand "nvim-treesitter-test-no-queries-for-official-grammars" { CI = true; } ''
149 touch $out
150
151 function check_grammar {
152 echo checking $1...
153 if [ -d $2/queries ]; then
154 echo Queries dir exists in $1
155 echo This is unexpected, see https://github.com/NixOS/nixpkgs/pull/344849#issuecomment-2381447839
156 exit 1
157 fi
158 }
159
160 ${lib.concatLines (lib.forEach pluginsToCheck (g: "check_grammar \"${g.grammarName}\" \"${g}\""))}
161 '';
162 };
163 };
164
165 meta =
166 with lib;
167 (super.nvim-treesitter.meta or { })
168 // {
169 license = licenses.asl20;
170 maintainers = with maintainers; [ figsoda ];
171 };
172}