Skip to content

Commit 27c75fd

Browse files
committed
Implement comprehensive indentation configuration for Julia
This commit adds both regex-based and Tree-sitter-based indentation rules to provide a smooth editing experience for Julia coding in Zed. Motivation - this didn't work properly before: ```julia if x elseif y else # <- wouldn't auto-outdent end ``` Changes: - Add `increase_indent_pattern` for Julia block keywords - Add `decrease_indent_patterns` with context-aware `valid_after` rules - Add `@start.suffix` captures in indents.scm for tracking block beginnings (required for `decrease_indent_patterns` to be functional) - Update `@outdent` patterns to work with specific keywords The dual approach (regex + Tree-sitter) is intentional, following Zed's design pattern established for Python (see zed-industries/zed#29625, zed-industries/zed#33370).
1 parent 42bb269 commit 27c75fd

File tree

2 files changed

+65
-6
lines changed

2 files changed

+65
-6
lines changed

languages/julia/config.toml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,50 @@ brackets = [
1717
]
1818
collapsed_placeholder = "# ..."
1919
tab_size = 4
20+
21+
# Indentation Configuration
22+
# ========================
23+
# Zed uses BOTH regex patterns (`config.toml`) and Tree-sitter queries (`indents.scm`) for indentation.
24+
#
25+
# Why Both Are Needed:
26+
# Based on Zed's Python implementation (PR #29625, #33370), regex patterns were introduced because:
27+
# 1. Tree-sitter has upstream parsing inconsistencies (e.g., Python issue #33238 with comments)
28+
# 2. The previous `significant_indentation` approach was "unnecessarily complicated to maintain"
29+
# 3. Tree-sitter alone cannot provide immediate feedback while typing incomplete code
30+
# 4. Complex nested structures need context-aware outdenting that's simpler with regex
31+
#
32+
# For Julia, we face similar challenges. Consider this case:
33+
# ```julia
34+
# if x
35+
# elseif y
36+
# elseif z| <- just finished typing `z`
37+
# end
38+
# ```
39+
# Here, Tree-sitter might not recognize the incomplete line as an `elseif_clause` yet,
40+
# so `@outdent` won't trigger. The regex pattern matches immediately and outdents.
41+
#
42+
# This dual approach is intentional - Tree-sitter provides structural understanding
43+
# for complete code, while regex patterns handle the interactive typing experience:
44+
#
45+
# 1. `increase_indent_pattern`: Regex that matches lines after which indentation should increase
46+
# - Applied when you press Enter after these patterns
47+
# - Also tracks which keyword started each block (for use with `decrease_indent_patterns`)
48+
#
49+
# 2. `decrease_indent_patterns`: Context-aware outdenting with `valid_after`
50+
# - REQUIRES corresponding `@start.suffix` captures in `indents.scm` (e.g., `@start.if`, `@start.function`)
51+
# - REQUIRES `valid_after` to be specified - won't work without it
52+
# - Aligns the matched line with the most recent valid predecessor
53+
# - Example: `else` with `valid_after=["if","elseif"]` aligns to the nearest `if`/`elseif`
54+
#
55+
# Note: `decrease_indent_patterns` without `valid_after` will NOT work - this is by design in Zed.
56+
# It needs to know which block to align with, not just "decrease by one level".
57+
58+
increase_indent_pattern = "^\\s*(function|if|elseif|else|for|while|begin|let|do|try|catch|finally|struct|mutable\\s+struct|quote|macro|module|baremodule|abstract\\s+type|primitive\\s+type)\\b.*$"
59+
60+
decrease_indent_patterns = [
61+
{ pattern = "^\\s*elseif\\b.*", valid_after = ["if", "elseif"] },
62+
{ pattern = "^\\s*else\\b.*", valid_after = ["if", "elseif", "try", "catch"] },
63+
{ pattern = "^\\s*catch\\b.*", valid_after = ["try"] },
64+
{ pattern = "^\\s*finally\\b.*", valid_after = ["try", "catch"] },
65+
{ pattern = "^\\s*end\\b.*", valid_after = ["function", "if", "for", "while", "begin", "let", "do", "try", "struct", "macro", "quote"] }
66+
]

languages/julia/indents.scm

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,38 @@
1+
; `@start.xxx` marks where these clauses start for `valid_after` matching in config.toml
2+
13
[
24
(struct_definition
5+
"struct" @start.struct
36
"end" @end)
47
(macro_definition
8+
"macro" @start.macro
59
"end" @end)
610
(function_definition
11+
"function" @start.function
712
"end" @end)
813
(compound_statement
14+
"begin" @start.begin
915
"end" @end)
1016
(if_statement
17+
"if" @start.if
1118
"end" @end)
1219
(try_statement
20+
"try" @start.try
1321
"end" @end)
1422
(for_statement
23+
"for" @start.for
1524
"end" @end)
1625
(while_statement
26+
"while" @start.while
1727
"end" @end)
1828
(let_statement
29+
"let" @start.let
1930
"end" @end)
2031
(quote_statement
32+
"quote" @start.quote
2133
"end" @end)
2234
(do_clause
35+
"do" @start.do
2336
"end" @end)
2437
(assignment)
2538
(for_binding)
@@ -35,9 +48,8 @@
3548
(_ "{" "}" @end) @indent
3649
(_ "(" ")" @end) @indent
3750

38-
[
39-
(else_clause)
40-
(elseif_clause)
41-
(catch_clause)
42-
(finally_clause)
43-
] @outdent
51+
; `@start.xxx` marks where these clauses start for `valid_after` matching in config.toml
52+
(else_clause "else" @start.else) @outdent
53+
(elseif_clause "elseif" @start.elseif) @outdent
54+
(catch_clause "catch" @start.catch) @outdent
55+
(finally_clause "finally" @start.finally) @outdent

0 commit comments

Comments
 (0)