Merge pull request #268619 from tweag/lib-descriptions
[NixPkgs.git] / pkgs / development / tools / parsing / tree-sitter / default.nix
blob0412a059a999597e65f18581b113a7f48a247789
1 { lib
2 , stdenv
3 , fetchgit
4 , fetchFromGitHub
5 , runCommand
6 , which
7 , rustPlatform
8 , emscripten
9 , Security
10 , callPackage
11 , linkFarm
12 , CoreServices
13 , enableShared ? !stdenv.hostPlatform.isStatic
14 , enableStatic ? stdenv.hostPlatform.isStatic
15 , webUISupport ? false
16 , extraGrammars ? { }
19 let
20   # to update:
21   # 1) change all these hashes
22   # 2) nix-build -A tree-sitter.updater.update-all-grammars
23   # 3) Set GITHUB_TOKEN env variable to avoid api rate limit (Use a Personal Access Token from https://github.com/settings/tokens It does not need any permissions)
24   # 4) run the ./result script that is output by that (it updates ./grammars)
25   version = "0.20.8";
26   sha256 = "sha256-278zU5CLNOwphGBUa4cGwjBqRJ87dhHMzFirZB09gYM=";
27   cargoSha256 = "sha256-0avy53pmR7CztDrL+5WAmlqpZwd/EA3Fh10hfPXyXZc=";
29   src = fetchFromGitHub {
30     owner = "tree-sitter";
31     repo = "tree-sitter";
32     rev = "v${version}";
33     inherit sha256;
34     fetchSubmodules = true;
35   };
37   update-all-grammars = callPackage ./update.nix { };
39   fetchGrammar = (v: fetchgit { inherit (v) url rev sha256 fetchSubmodules; });
41   grammars =
42     runCommand "grammars" { } (''
43       mkdir $out
44     '' + (lib.concatStrings (lib.mapAttrsToList
45       (name: grammar: "ln -s ${if grammar ? src then grammar.src else fetchGrammar grammar} $out/${name}\n")
46       (import ./grammars { inherit lib; }))));
48   buildGrammar = callPackage ./grammar.nix { };
50   builtGrammars =
51     let
52       build = name: grammar:
53         buildGrammar {
54           language = grammar.language or name;
55           inherit version;
56           src = grammar.src or (fetchGrammar grammar);
57           location = grammar.location or null;
58           generate = grammar.generate or false;
59         };
60       grammars' = import ./grammars { inherit lib; } // extraGrammars;
61       grammars = grammars' //
62         { tree-sitter-ocaml = grammars'.tree-sitter-ocaml // { location = "ocaml"; }; } //
63         { tree-sitter-ocaml-interface = grammars'.tree-sitter-ocaml // { location = "interface"; }; } //
64         { tree-sitter-org-nvim = grammars'.tree-sitter-org-nvim // { language = "org"; }; } //
65         { tree-sitter-typescript = grammars'.tree-sitter-typescript // { location = "typescript"; }; } //
66         { tree-sitter-tsx = grammars'.tree-sitter-typescript // { location = "tsx"; }; } //
67         { tree-sitter-typst = grammars'.tree-sitter-typst // { generate = true; }; } //
68         { tree-sitter-markdown = grammars'.tree-sitter-markdown // { location = "tree-sitter-markdown"; }; } //
69         { tree-sitter-markdown-inline = grammars'.tree-sitter-markdown // { language = "markdown_inline"; location = "tree-sitter-markdown-inline"; }; } //
70         { tree-sitter-wing = grammars'.tree-sitter-wing // { location = "libs/tree-sitter-wing"; generate = true; }; };
71     in
72     lib.mapAttrs build (grammars);
74   # Usage:
75   # pkgs.tree-sitter.withPlugins (p: [ p.tree-sitter-c p.tree-sitter-java ... ])
76   #
77   # or for all grammars:
78   # pkgs.tree-sitter.withPlugins (_: allGrammars)
79   # which is equivalent to
80   # pkgs.tree-sitter.withPlugins (p: builtins.attrValues p)
81   withPlugins = grammarFn:
82     let
83       grammars = grammarFn builtGrammars;
84     in
85     linkFarm "grammars"
86       (map
87         (drv:
88           let
89             name = lib.strings.getName drv;
90           in
91           {
92             name =
93               (lib.strings.replaceStrings [ "-" ] [ "_" ]
94                 (lib.strings.removePrefix "tree-sitter-"
95                   (lib.strings.removeSuffix "-grammar" name)))
96               + ".so";
97             path = "${drv}/parser";
98           }
99         )
100         grammars);
102   allGrammars = builtins.attrValues builtGrammars;
105 rustPlatform.buildRustPackage {
106   pname = "tree-sitter";
107   inherit src version cargoSha256;
109   buildInputs =
110     lib.optionals stdenv.isDarwin [ Security CoreServices ];
111   nativeBuildInputs =
112     [ which ]
113     ++ lib.optionals webUISupport [ emscripten ];
115   postPatch = lib.optionalString (!webUISupport) ''
116     # remove web interface
117     sed -e '/pub mod playground/d' \
118         -i cli/src/lib.rs
119     sed -e 's/playground,//' \
120         -e 's/playground::serve(&current_dir.*$/println!("ERROR: web-ui is not available in this nixpkgs build; enable the webUISupport"); std::process::exit(1);/' \
121         -i cli/src/main.rs
122   '';
124   # Compile web assembly with emscripten. The --debug flag prevents us from
125   # minifying the JavaScript; passing it allows us to side-step more Node
126   # JS dependencies for installation.
127   preBuild = lib.optionalString webUISupport ''
128     mkdir -p .emscriptencache
129     export EM_CACHE=$(pwd)/.emscriptencache
130     bash ./script/build-wasm --debug
131   '';
133   postInstall = ''
134     PREFIX=$out make install
135     ${lib.optionalString (!enableShared) "rm $out/lib/*.so{,.*}"}
136     ${lib.optionalString (!enableStatic) "rm $out/lib/*.a"}
137   '';
139   # test result: FAILED. 120 passed; 13 failed; 0 ignored; 0 measured; 0 filtered out
140   doCheck = false;
142   passthru = {
143     updater = {
144       inherit update-all-grammars;
145     };
146     inherit grammars buildGrammar builtGrammars withPlugins allGrammars;
148     tests = {
149       # make sure all grammars build
150       builtGrammars = lib.recurseIntoAttrs builtGrammars;
151     };
152   };
154   meta = with lib; {
155     homepage = "https://github.com/tree-sitter/tree-sitter";
156     description = "A parser generator tool and an incremental parsing library";
157     longDescription = ''
158       Tree-sitter is a parser generator tool and an incremental parsing library.
159       It can build a concrete syntax tree for a source file and efficiently update the syntax tree as the source file is edited.
161       Tree-sitter aims to be:
163       * General enough to parse any programming language
164       * Fast enough to parse on every keystroke in a text editor
165       * Robust enough to provide useful results even in the presence of syntax errors
166       * Dependency-free so that the runtime library (which is written in pure C) can be embedded in any application
167     '';
168     license = licenses.mit;
169     maintainers = with maintainers; [ Profpatsch ];
170   };