Add Nix language support (#2781)

Mikayla Maki created

This adds rudimentary language support for the Nix expression language,
through tree-sitter-nix.

I spent a little bit of time trying to add support for one of the Nix
language servers too, but wasn't able to get any of them running
reliably without crashing, and so I've opted to stick to just the
tree-sitter grammar for now.


![image](https://github.com/zed-industries/zed/assets/285821/c770f3d8-6fa0-4083-9bf3-239cc78ca307)

Change summary

Cargo.lock                                  | 10 ++
Cargo.toml                                  |  1 
crates/zed/Cargo.toml                       |  1 
crates/zed/src/languages.rs                 |  2 
crates/zed/src/languages/nix/config.toml    | 11 ++
crates/zed/src/languages/nix/highlights.scm | 89 +++++++++++++++++++++++
6 files changed, 114 insertions(+)

Detailed changes

Cargo.lock 🔗

@@ -8387,6 +8387,15 @@ dependencies = [
  "tree-sitter",
 ]
 
+[[package]]
+name = "tree-sitter-nix"
+version = "0.0.1"
+source = "git+https://github.com/nix-community/tree-sitter-nix?rev=66e3e9ce9180ae08fc57372061006ef83f0abde7#66e3e9ce9180ae08fc57372061006ef83f0abde7"
+dependencies = [
+ "cc",
+ "tree-sitter",
+]
+
 [[package]]
 name = "tree-sitter-php"
 version = "0.19.1"
@@ -9933,6 +9942,7 @@ dependencies = [
  "tree-sitter-json 0.20.0",
  "tree-sitter-lua",
  "tree-sitter-markdown",
+ "tree-sitter-nix",
  "tree-sitter-php",
  "tree-sitter-python",
  "tree-sitter-racket",

Cargo.toml 🔗

@@ -131,6 +131,7 @@ tree-sitter-svelte = { git = "https://github.com/Himujjal/tree-sitter-svelte", r
 tree-sitter-racket = { git = "https://github.com/zed-industries/tree-sitter-racket", rev = "eb010cf2c674c6fd9a6316a84e28ef90190fe51a"}
 tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "f545a41f57502e1b5ddf2a6668896c1b0620f930"}
 tree-sitter-lua = "0.0.14"
+tree-sitter-nix = { git = "https://github.com/nix-community/tree-sitter-nix", rev = "66e3e9ce9180ae08fc57372061006ef83f0abde7" }
 
 [patch.crates-io]
 tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "1c65ca24bc9a734ab70115188f465e12eecf224e" }

crates/zed/Cargo.toml 🔗

@@ -128,6 +128,7 @@ tree-sitter-svelte.workspace = true
 tree-sitter-racket.workspace = true
 tree-sitter-yaml.workspace = true
 tree-sitter-lua.workspace = true
+tree-sitter-nix.workspace = true
 
 url = "2.2"
 urlencoding = "2.1.2"

crates/zed/src/languages.rs 🔗

@@ -152,8 +152,10 @@ pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
         tree_sitter_php::language(),
         vec![Arc::new(php::IntelephenseLspAdapter::new(node_runtime))],
     );
+
     language("elm", tree_sitter_elm::language(), vec![]);
     language("glsl", tree_sitter_glsl::language(), vec![]);
+    language("nix", tree_sitter_nix::language(), vec![]);
 }
 
 #[cfg(any(test, feature = "test-support"))]

crates/zed/src/languages/nix/config.toml 🔗

@@ -0,0 +1,11 @@
+name = "Nix"
+path_suffixes = ["nix"]
+line_comment = "# "
+block_comment = ["/* ", " */"]
+autoclose_before = ";:.,=}])>` \n\t\""
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+    { start = "<", end = ">", close = true, newline = true },
+]

crates/zed/src/languages/nix/highlights.scm 🔗

@@ -0,0 +1,95 @@
+(comment) @comment
+
+[
+  "if"
+  "then"
+  "else"
+  "let"
+  "inherit"
+  "in"
+  "rec"
+  "with"
+  "assert"
+  "or"
+] @keyword
+
+[
+ (string_expression)
+ (indented_string_expression)
+] @string
+
+[
+  (path_expression)
+  (hpath_expression)
+  (spath_expression)
+] @string.special.path
+
+(uri_expression) @link_uri
+
+[
+  (integer_expression)
+  (float_expression)
+] @number
+
+(interpolation
+  "${" @punctuation.special
+  "}" @punctuation.special) @embedded
+
+(escape_sequence) @escape
+(dollar_escape) @escape
+
+(function_expression
+  universal: (identifier) @parameter
+)
+
+(formal
+  name: (identifier) @parameter
+  "?"? @punctuation.delimiter)
+
+(select_expression
+  attrpath: (attrpath (identifier)) @property)
+
+(apply_expression
+  function: [
+    (variable_expression (identifier)) @function
+    (select_expression
+      attrpath: (attrpath
+        attr: (identifier) @function .))])
+
+(unary_expression
+  operator: _ @operator)
+
+(binary_expression
+  operator: _ @operator)
+
+(variable_expression (identifier) @variable)
+
+(binding
+  attrpath: (attrpath (identifier)) @property)
+
+"=" @operator
+
+[
+  ";"
+  "."
+  ","
+] @punctuation.delimiter
+
+[
+  "("
+  ")"
+  "["
+  "]"
+  "{"
+  "}"
+] @punctuation.bracket
+
+(identifier) @variable
+
+((identifier) @function.builtin