Skip to content

Commit 4bc7ec2

Browse files
committed
WIP nix
1 parent 7b1c316 commit 4bc7ec2

File tree

7 files changed

+271
-36
lines changed

7 files changed

+271
-36
lines changed

topiary-cli/Cargo.toml

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ name = "topiary-cli"
33
description = "CLI app for Topiary, the universal code formatter."
44
categories = ["command-line-utilities", "development-tools", "text-processing"]
55
keywords = [
6-
"cli",
7-
"code-formatter",
8-
"formatter",
9-
"text",
10-
"tree-sitter",
11-
"utility",
6+
"cli",
7+
"code-formatter",
8+
"formatter",
9+
"text",
10+
"tree-sitter",
11+
"utility",
1212
]
1313
version.workspace = true
1414
edition.workspace = true
@@ -35,7 +35,12 @@ itertools = { workspace = true }
3535
log = { workspace = true }
3636
serde = { workspace = true, features = ["derive"] }
3737
tempfile = { workspace = true }
38-
tokio = { workspace = true, features = ["fs", "rt-multi-thread", "sync", "macros"] }
38+
tokio = { workspace = true, features = [
39+
"fs",
40+
"rt-multi-thread",
41+
"sync",
42+
"macros",
43+
] }
3944
toml = { workspace = true }
4045
topiary-core = { path = "../topiary-core" }
4146
topiary-config = { path = "../topiary-config" }
@@ -58,34 +63,37 @@ predicates = { workspace = true }
5863

5964
[features]
6065
default = [
61-
"contributed",
62-
"json",
63-
"nickel",
64-
"ocaml",
65-
"ocaml_interface",
66-
"ocamllex",
67-
"toml",
68-
"tree_sitter_query"
66+
"contributed",
67+
"json",
68+
"nickel",
69+
"nix",
70+
"ocaml",
71+
"ocaml_interface",
72+
"ocamllex",
73+
"toml",
74+
"tree_sitter_query",
6975
]
7076

7177
# Included by default
72-
contributed = [
73-
"css"
74-
]
78+
contributed = ["css"]
7579

7680
# Excluded by default
77-
experimental = [
78-
"bash",
79-
"rust",
80-
]
81+
experimental = ["bash", "rust"]
8182

83+
nix = ["topiary-config/nix", "topiary-queries/nix"]
8284
bash = ["topiary-config/bash", "topiary-queries/bash"]
8385
css = ["topiary-config/css", "topiary-queries/css"]
8486
json = ["topiary-config/json", "topiary-queries/json"]
8587
nickel = ["topiary-config/nickel", "topiary-queries/nickel"]
8688
ocaml = ["topiary-config/ocaml", "topiary-queries/ocaml"]
87-
ocaml_interface = ["topiary-config/ocaml_interface", "topiary-queries/ocaml_interface"]
89+
ocaml_interface = [
90+
"topiary-config/ocaml_interface",
91+
"topiary-queries/ocaml_interface",
92+
]
8893
ocamllex = ["topiary-config/ocamllex", "topiary-queries/ocamllex"]
8994
rust = ["topiary-config/rust", "topiary-queries/rust"]
9095
toml = ["topiary-config/toml", "topiary-queries/toml"]
91-
tree_sitter_query = ["topiary-config/tree_sitter_query", "topiary-queries/tree_sitter_query"]
96+
tree_sitter_query = [
97+
"topiary-config/tree_sitter_query",
98+
"topiary-queries/tree_sitter_query",
99+
]

topiary-cli/src/io.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ where
350350
#[cfg(feature = "toml")]
351351
"toml" => Ok(topiary_queries::toml().into()),
352352

353+
#[cfg(feature = "nix")]
354+
"nix" => Ok(topiary_queries::nix().into()),
355+
353356
#[cfg(feature = "tree_sitter_query")]
354357
"tree_sitter_query" => Ok(topiary_queries::tree_sitter_query().into()),
355358

topiary-config/Cargo.toml

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ git2.workspace = true
3333
libloading.workspace = true
3434

3535
[features]
36-
default = [ "parallel" ]
36+
default = ["parallel"]
3737

3838
# Enabling the `parallel` feature enables parallel computation where possible.
3939
# At the moment, this is only in grammar prefetching
40-
parallel = [ "dep:rayon" ]
40+
parallel = ["dep:rayon"]
4141

4242
bash = []
4343
css = []
@@ -46,21 +46,23 @@ nickel = []
4646
ocaml = []
4747
ocaml_interface = []
4848
ocamllex = []
49+
nix = []
4950
rust = []
5051
toml = []
5152
tree_sitter_query = []
5253

5354
# This a convenience for the sake of downstream applications which don't
5455
# wish to cherry-pick grammars (e.g., the playground)
5556
all = [
56-
"bash",
57-
"css",
58-
"json",
59-
"nickel",
60-
"ocaml",
61-
"ocaml_interface",
62-
"ocamllex",
63-
"rust",
64-
"toml",
65-
"tree_sitter_query"
57+
"bash",
58+
"css",
59+
"json",
60+
"nickel",
61+
"ocaml",
62+
"ocaml_interface",
63+
"ocamllex",
64+
"rust",
65+
"nix",
66+
"toml",
67+
"tree_sitter_query",
6668
]

topiary-config/languages.ncl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@
1616
},
1717
},
1818

19+
nix = {
20+
extensions = ["nix"],
21+
grammar = {
22+
git = "https://github.com/nix-community/tree-sitter-nix",
23+
rev = "456b14a2fa6315abc7e02fcffaf4a1f35d4955d3",
24+
},
25+
},
26+
1927
json = {
2028
extensions = [
2129
"json",

topiary-queries/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ ocaml_interface = []
2424
ocamllex = []
2525
rust = []
2626
toml = []
27+
nix = []
2728
tree_sitter_query = []

topiary-queries/queries/nix.scm

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
;; Nix Formatter based on RFC 166
2+
3+
; Leaf nodes (strings, paths, etc.) should be preserved as-is
4+
[ (string)
5+
(indented_string)
6+
(path)
7+
] @leaf
8+
9+
; Comments
10+
(comment) @comment
11+
12+
; Convert single-line /* */ comments to #
13+
(comment) @convert_to_hash_comment
14+
15+
; Preserve multiline comments
16+
(comment) @preserve_multiline_comment
17+
18+
; Append space after specific tokens
19+
":" @append_space
20+
"=" @append_space
21+
"," @append_spaced_softline
22+
23+
; Handle indentation and line breaks
24+
; Define softline breaks and indentation starts/ends
25+
"{" @append_spaced_softline @append_indent_start
26+
"}" @prepend_spaced_softline @prepend_indent_end
27+
"[" @append_spaced_softline @append_indent_start
28+
"]" @prepend_spaced_softline @prepend_indent_end
29+
30+
; Functions
31+
32+
(function
33+
parameters: (formals
34+
"(" @append_spaced_softline @append_indent_start
35+
(formal_parameter) @formal_param
36+
")" @prepend_spaced_softline @prepend_indent_end
37+
)
38+
body: (_) @function_body
39+
) @function_declaration
40+
41+
; Ensure each parameter is on a new line with proper indentation
42+
(formal_parameter) @prepend_spaced_softline
43+
44+
; Attribute Sets
45+
46+
(attrset
47+
"{" @append_spaced_softline @append_indent_start
48+
(binding) @attr_binding
49+
"}" @prepend_spaced_softline @prepend_indent_end
50+
) @attribute_set
51+
52+
; Ensure each key-value pair is on its own line
53+
(binding
54+
attrpath: (_) @attr_key
55+
"=" @append_space
56+
value: (_) @attr_value
57+
";" @append_spaced_softline
58+
)
59+
60+
; Lists
61+
62+
(list
63+
"[" @append_spaced_softline @append_indent_start
64+
(_) @list_item
65+
"]" @prepend_spaced_softline @prepend_indent_end
66+
) @list
67+
68+
; Ensure each list element is on its own line
69+
(list
70+
"," @append_spaced_softline
71+
)
72+
73+
; If-Then-Else Expressions
74+
75+
(if_expression
76+
"if" @keyword_if @append_space @prepend_spaced_softline
77+
condition: (_) @if_condition
78+
"then" @keyword_then @append_space @prepend_spaced_softline @append_indent_start
79+
body: (_) @if_body @append_indent_end
80+
"else" @keyword_else @append_space @prepend_spaced_softline @append_indent_start
81+
alternative: (_) @else_body @append_indent_end
82+
)
83+
84+
; Let-In Expressions
85+
86+
(let_expression
87+
"let" @keyword_let @append_spaced_softline @append_indent_start
88+
(binding
89+
attrpath: (_) @let_binding_name
90+
"=" @append_space
91+
value: (_) @let_binding_value
92+
";" @append_spaced_softline
93+
)+
94+
"in" @keyword_in @prepend_spaced_softline @prepend_indent_end @append_spaced_softline
95+
body: (_) @let_body
96+
)
97+
98+
; With Expressions
99+
100+
(with_expression
101+
"with" @keyword_with @append_space
102+
(_) @with_expression
103+
";" @append_spaced_softline
104+
body: (_) @with_body
105+
)
106+
107+
; Assert Expressions
108+
109+
(assert_expression
110+
"assert" @keyword_assert @append_space
111+
(_) @assert_condition
112+
";" @append_spaced_softline
113+
body: (_) @assert_body
114+
)
115+
116+
; Operator Formatting
117+
118+
(binary_expression
119+
left: (_) @op_left
120+
operator: (_) @op_symbol
121+
right: (_) @op_right
122+
)
123+
124+
; Ensure operators start on new lines if they don't fit on a single line
125+
(binary_expression
126+
operator: (_) @prepend_spaced_softline
127+
)
128+
129+
; Inherit Statements
130+
131+
(inherit
132+
"inherit" @keyword_inherit @append_space
133+
(inherited_attrs
134+
(attrpath) @inherit_item
135+
)+
136+
";" @inherit_semicolon
137+
)
138+
139+
; Handle inherit with source
140+
(inherit
141+
"inherit" @keyword_inherit @append_space
142+
"(" @inherit_parentheses_start
143+
(_) @inherit_source
144+
")" @inherit_parentheses_end
145+
(inherited_attrs
146+
(attrpath) @inherit_item
147+
)+
148+
";" @inherit_semicolon
149+
)
150+
151+
; Empty Objects and Arrays
152+
153+
(attrset
154+
"{" @object_open
155+
"}" @object_close
156+
) @empty_attribute_set
157+
158+
(list
159+
"[" @array_open
160+
"]" @array_close
161+
) @empty_array
162+
163+
; String Interpolation
164+
165+
(interpolation
166+
"${" @interp_start
167+
(_) @interp_content
168+
"}" @interp_end
169+
)
170+
171+
; Additional Rules
172+
173+
; Handle let bindings indentation
174+
(let_expression
175+
(binding) @let_binding_indent
176+
)
177+
178+
; Handle assertions
179+
(assert_expression
180+
"assert" @keyword_assert @append_space
181+
(_) @assert_condition
182+
";" @assert_semicolon
183+
)
184+
185+
; Handle comments within expressions
186+
(comment) @comment_within_expr
187+
188+
; Leaf Nodes Preservation
189+
(_) @leaf
190+
191+
; Handle semicolon placement in bindings
192+
(binding
193+
";" @semicolon_end
194+
)
195+
196+
; Handle indentation for nested attribute sets
197+
(attrset
198+
(binding
199+
value: (attrset) @nested_attribute_set
200+
)
201+
)
202+
203+
; Handle newline preservation rules
204+
(ERROR) @collapse_empty_lines
205+
206+
; Ensure consistent indentation levels
207+
(_) @indent_block

topiary-queries/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ pub fn toml() -> &'static str {
5252
include_str!("../queries/toml.scm")
5353
}
5454

55+
/// Returns the Topiary-compatible query file for Nix.
56+
#[cfg(feature = "nix")]
57+
pub fn nix() -> &'static str {
58+
include_str!("../queries/nix.scm")
59+
}
60+
5561
/// Returns the Topiary-compatible query file for the
5662
/// Tree-sitter query language.
5763
#[cfg(feature = "tree_sitter_query")]

0 commit comments

Comments
 (0)