Skip to content

Commit 208ff9f

Browse files
committed
Improved accuracy of first function argument detection in indentation
Indentation improvements: - Fixed escape character detection `s:IsEscaped`. - Improved accuracy of first function argument detection.
1 parent 55543c4 commit 208ff9f

File tree

7 files changed

+286
-12
lines changed

7 files changed

+286
-12
lines changed

clj/resources/indent-test-cases/s-expr_standard/in.clj

+43
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,46 @@ bar
9595
(import '(java.io File
9696
IOException)
9797
'(clojure.lang PersistentQueue))
98+
99+
((if true + -) 1
100+
3)
101+
102+
((if true
103+
+
104+
-)
105+
1
106+
3)
107+
108+
(#'if (even? 1)
109+
2
110+
3)
111+
112+
(#(foo) bar
113+
biz)
114+
115+
("foo bar" biz
116+
baz)
117+
118+
(~@foo
119+
~bar)
120+
121+
(~@foo ~bar
122+
biz)
123+
124+
(o bar
125+
biz)
126+
127+
({foo \} bar biz} foo
128+
biz)
129+
130+
('foo bar
131+
'biz)
132+
133+
('#{foo bar} 1
134+
2)
135+
136+
(foo ; bar
137+
biz)
138+
139+
'(\" \b
140+
\c)

clj/resources/indent-test-cases/s-expr_standard/out.clj

+43
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,46 @@
9595
(import '(java.io File
9696
IOException)
9797
'(clojure.lang PersistentQueue))
98+
99+
((if true + -) 1
100+
3)
101+
102+
((if true
103+
+
104+
-)
105+
1
106+
3)
107+
108+
(#'if (even? 1)
109+
2
110+
3)
111+
112+
(#(foo) bar
113+
biz)
114+
115+
("foo bar" biz
116+
baz)
117+
118+
(~@foo
119+
~bar)
120+
121+
(~@foo ~bar
122+
biz)
123+
124+
(o bar
125+
biz)
126+
127+
({foo \} bar biz} foo
128+
biz)
129+
130+
('foo bar
131+
'biz)
132+
133+
('#{foo bar} 1
134+
2)
135+
136+
(foo ; bar
137+
biz)
138+
139+
'(\" \b
140+
\c)

clj/resources/indent-test-cases/s-expr_traditional/in.clj

+43
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,46 @@ bar
9595
(import '(java.io File
9696
IOException)
9797
'(clojure.lang PersistentQueue))
98+
99+
((if true + -) 1
100+
3)
101+
102+
((if true
103+
+
104+
-)
105+
1
106+
3)
107+
108+
(#'if (even? 1)
109+
2
110+
3)
111+
112+
(#(foo) bar
113+
biz)
114+
115+
("foo bar" biz
116+
baz)
117+
118+
(~@foo
119+
~bar)
120+
121+
(~@foo ~bar
122+
biz)
123+
124+
(o bar
125+
biz)
126+
127+
({foo \} bar biz} foo
128+
biz)
129+
130+
('foo bar
131+
'biz)
132+
133+
('#{foo bar} 1
134+
2)
135+
136+
(foo ; bar
137+
biz)
138+
139+
'(\" \b
140+
\c)

clj/resources/indent-test-cases/s-expr_traditional/out.clj

+43
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,46 @@
9595
(import '(java.io File
9696
IOException)
9797
'(clojure.lang PersistentQueue))
98+
99+
((if true + -) 1
100+
3)
101+
102+
((if true
103+
+
104+
-)
105+
1
106+
3)
107+
108+
(#'if (even? 1)
109+
2
110+
3)
111+
112+
(#(foo) bar
113+
biz)
114+
115+
("foo bar" biz
116+
baz)
117+
118+
(~@foo
119+
~bar)
120+
121+
(~@foo ~bar
122+
biz)
123+
124+
(o bar
125+
biz)
126+
127+
({foo \} bar biz} foo
128+
biz)
129+
130+
('foo bar
131+
'biz)
132+
133+
('#{foo bar} 1
134+
2)
135+
136+
(foo ; bar
137+
biz)
138+
139+
'(\" \b
140+
\c)

clj/resources/indent-test-cases/s-expr_uniform/in.clj

+43
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,46 @@ bar
9595
(import '(java.io File
9696
IOException)
9797
'(clojure.lang PersistentQueue))
98+
99+
((if true + -) 1
100+
3)
101+
102+
((if true
103+
+
104+
-)
105+
1
106+
3)
107+
108+
(#'if (even? 1)
109+
2
110+
3)
111+
112+
(#(foo) bar
113+
biz)
114+
115+
("foo bar" biz
116+
baz)
117+
118+
(~@foo
119+
~bar)
120+
121+
(~@foo ~bar
122+
biz)
123+
124+
(o bar
125+
biz)
126+
127+
({foo \} bar biz} foo
128+
biz)
129+
130+
('foo bar
131+
'biz)
132+
133+
('#{foo bar} 1
134+
2)
135+
136+
(foo ; bar
137+
biz)
138+
139+
'(\" \b
140+
\c)

clj/resources/indent-test-cases/s-expr_uniform/out.clj

+43
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,46 @@
9595
(import '(java.io File
9696
IOException)
9797
'(clojure.lang PersistentQueue))
98+
99+
((if true + -) 1
100+
3)
101+
102+
((if true
103+
+
104+
-)
105+
1
106+
3)
107+
108+
(#'if (even? 1)
109+
2
110+
3)
111+
112+
(#(foo) bar
113+
biz)
114+
115+
("foo bar" biz
116+
baz)
117+
118+
(~@foo
119+
~bar)
120+
121+
(~@foo ~bar
122+
biz)
123+
124+
(o bar
125+
biz)
126+
127+
({foo \} bar biz} foo
128+
biz)
129+
130+
('foo bar
131+
'biz)
132+
133+
('#{foo bar} 1
134+
2)
135+
136+
(foo ; bar
137+
biz)
138+
139+
'(\" \b
140+
\c)

indent/clojure.vim

+28-12
Original file line numberDiff line numberDiff line change
@@ -73,24 +73,40 @@ call s:SConf('clojure_indent_rules', {
7373
" Returns "1" if position "i_char" in "line_str" is preceded by an odd number
7474
" of backslash characters (i.e. escaped).
7575
function! s:IsEscaped(line_str, i_char)
76-
return ! strlen(trim(a:line_str[: a:i_char - 1], '\', 2)) % 2
76+
let ln = a:line_str[: a:i_char - 1]
77+
return (strlen(ln) - strlen(trim(ln, '\', 2))) % 2
78+
endfunction
79+
80+
" Variation of "s:IsEscaped" which can be used within "search(pair)pos".
81+
function! s:SkipIfEscaped()
82+
let pos = getcursorcharpos()
83+
return s:IsEscaped(getline(pos[1]), pos[2] - 1)
7784
endfunction
7885

7986
" Used during list function indentation. Returns the position of the first
8087
" operand in the list on the first line of the form at "pos".
8188
function! s:FirstFnArgPos(pos)
82-
" TODO: ignore comments and handle escaped characters!
83-
let lnr = a:pos[0]
84-
let s:in_form_current_form = a:pos
85-
call cursor(lnr, a:pos[1] + 1)
86-
return searchpos('\m[ ,]\+\zs', 'z', lnr, 0, function('<SID>IsSubForm'))
87-
endfunction
89+
let [lnr, base_idx] = a:pos
90+
let ln = getline(lnr)
91+
call cursor([lnr, base_idx + 1])
92+
93+
if ln[base_idx] =~# '["\\,[:space:]]' | return [0, 0] | endif
94+
95+
" Find first collection delimiter or char preceeding whitespace.
96+
let pos = searchpos('\([{\[(]\|.[[:space:],]\)', 'cWz', lnr)
97+
if pos == [0, 0] | return pos | endif
98+
99+
" If at collection delimiter, jump to end delimiter.
100+
let ch = ln[pos[1] - 1]
101+
if has_key(s:pairs, ch)
102+
let pos = searchpairpos('\V' . ch, '', '\V' . get(s:pairs, ch), 'Wz', function('s:SkipIfEscaped'), lnr)
103+
" If end not on same line: no arg.
104+
if pos == [0, 0] | return pos | endif
105+
endif
88106

89-
" Used by "s:FirstFnArgPos" function to skip over subforms as the first value
90-
" in a list form.
91-
function! s:IsSubForm()
92-
let pos = searchpairpos('\m[([{"]', '', '\m[)\]}"]', 'b')
93-
return pos != [0, 0] && pos != s:in_form_current_form
107+
" Search forwards for first non-whitespace/comment char on line.
108+
let pos = searchpos('[^[:space:],]', 'Wz', lnr)
109+
return ln[pos[1] - 1] ==# ';' ? [0, 0] : pos
94110
endfunction
95111

96112
" Converts a cursor position into a characterwise cursor column position (to

0 commit comments

Comments
 (0)