Skip to content

Commit 5706ea3

Browse files
committed
Double (or better) indent performance!
By utilising some ugly mutable state, this change more than doubles the performance of the indentation code. You can expect even further benefits in larger code blocks. This should completely eliminate any need for the `clojure_maxlines` configuration option.
1 parent 7d6bdd7 commit 5706ea3

File tree

1 file changed

+28
-16
lines changed

1 file changed

+28
-16
lines changed

indent/clojure.vim

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function! s:SyntaxMatch(pattern, line, col)
4141
endfunction
4242

4343
function! s:IgnoredRegion()
44-
return s:SyntaxMatch('\vstring|regex|comment|character', line('.'), col('.'))
44+
return s:SyntaxMatch('\(string\|regex\|comment\|character\)', line('.'), col('.'))
4545
endfunction
4646

4747
function! s:NotAStringDelimiter()
@@ -80,47 +80,59 @@ function! s:ClosestMatch(match1, match2)
8080
endif
8181
endfunction
8282

83+
" Wrapper around "searchpairpos" that will automatically set "s:best_match" to
84+
" the closest pair match and continuously optimise the "stopline" value for
85+
" later searches. This results in a significant performance gain by reducing
86+
" the number of syntax lookups that need to take place.
87+
function! s:CheckPair(name, start, end, skipfn)
88+
let pos = searchpairpos(a:start, '', a:end, 'bznW', a:skipfn, s:best_match[1][0])
89+
let s:best_match = s:ClosestMatch(s:best_match, [a:name, pos])
90+
endfunction
91+
8392
" Only need to search up. Never down.
8493
function! s:GetClojureIndent()
8594
let lnum = v:lnum
8695

8796
" Move cursor to the first column of the line we want to indent.
8897
cursor(lnum, 0)
8998

90-
let matches = [
91-
\ ['lst', searchpairpos( '(', '', ')', 'bznW', function('<SID>IgnoredRegion'))],
92-
\ ['vec', searchpairpos('\[', '', '\]', 'bznW', function('<SID>IgnoredRegion'))],
93-
\ ['map', searchpairpos( '{', '', '}', 'bznW', function('<SID>IgnoredRegion'))],
94-
\ ['reg', s:IsInRegex() ? searchpairpos('#\zs"', '', '"', 'bznW', function('<SID>NotARegexpDelimiter')) : [0, 0]],
95-
\ ['str', s:IsInString() ? searchpairpos('"', '', '"', 'bznW', function('<SID>NotAStringDelimiter')) : [0, 0]]
96-
\ ]
97-
echom 'Matches' matches
99+
let s:best_match = ['top', [0, 0]]
100+
101+
call s:CheckPair('lst', '(', ')', function('<SID>IgnoredRegion'))
102+
call s:CheckPair('vec', '\[', '\]', function('<SID>IgnoredRegion'))
103+
call s:CheckPair('map', '{', '}', function('<SID>IgnoredRegion'))
104+
105+
if s:IsInString()
106+
call s:CheckPair('str', '"', '"', function('<SID>NotAStringDelimiter'))
107+
elseif s:IsInRegex()
108+
call s:CheckPair('reg', '#\zs"', '"', function('<SID>NotARegexpDelimiter'))
109+
endif
98110

99111
" Find closest matching higher form.
100-
let [formtype, coord] = reduce(matches, function('<SID>ClosestMatch'), ['top', [0, 0]])
101-
echom 'Match' formtype coord
112+
let [formtype, coord] = s:best_match
113+
" echom 'Match' formtype coord
102114

103115
if formtype == 'top'
104116
" At the top level, no indent.
105-
echom 'At the top level!'
117+
" echom 'At the top level!'
106118
return 0
107119
elseif formtype == 'lst'
108-
echom 'Special format rules!'
120+
" echom 'Special format rules!'
109121
" TODO
110122
" Grab text!
111-
echom getline(coord[0], lnum - 1)
123+
" echom getline(coord[0], lnum - 1)
112124
" Begin lexing!
113125
return coord[1] + 1
114126
elseif formtype == 'vec' || formtype == 'map'
115127
" Inside a vector, map or set.
116128
return coord[1]
117129
elseif formtype == 'reg'
118130
" Inside a regex.
119-
echom 'Inside a regex!'
131+
" echom 'Inside a regex!'
120132
return coord[1] - (s:ShouldAlignMultiLineStrings() ? 0 : 2)
121133
elseif formtype == 'str'
122134
" Inside a string.
123-
echom 'Inside a string!'
135+
" echom 'Inside a string!'
124136
return coord[1] - (s:ShouldAlignMultiLineStrings() ? 0 : 1)
125137
endif
126138

0 commit comments

Comments
 (0)