@@ -192,17 +192,23 @@ if exists("*searchpairpos")
192
192
return val
193
193
endfunction
194
194
195
- function ! GetClojureIndent ()
195
+ " Returns 1 for opening brackets, -1 for _anything else_.
196
+ function ! s: bracket_type (char)
197
+ return stridx (' ([{' , a: char ) > -1 ? 1 : -1
198
+ endfunction
199
+
200
+ " Returns: [opening-bracket-lnum, indent]
201
+ function ! s: clojure_indent_pos ()
196
202
" Get rid of special case.
197
203
if line (" ." ) == 1
198
- return 0
204
+ return [ 0 , 0 ]
199
205
endif
200
206
201
207
" We have to apply some heuristics here to figure out, whether to use
202
208
" normal lisp indenting or not.
203
209
let i = s: check_for_string ()
204
210
if i > -1
205
- return i + ! ! g: clojure_align_multiline_strings
211
+ return [ 0 , i + ! ! g: clojure_align_multiline_strings]
206
212
endif
207
213
208
214
call cursor (0 , 1 )
@@ -219,19 +225,19 @@ if exists("*searchpairpos")
219
225
" curly indent.
220
226
if curly[0 ] > bracket[0 ] || curly[1 ] > bracket[1 ]
221
227
if curly[0 ] > paren[0 ] || curly[1 ] > paren[1 ]
222
- return curly[ 1 ]
228
+ return curly
223
229
endif
224
230
endif
225
231
226
232
" If the curly was not chosen, we take the bracket indent - if
227
233
" there was one.
228
234
if bracket[0 ] > paren[0 ] || bracket[1 ] > paren[1 ]
229
- return bracket[ 1 ]
235
+ return bracket
230
236
endif
231
237
232
238
" There are neither { nor [ nor (, ie. we are at the toplevel.
233
239
if paren == [0 , 0 ]
234
- return 0
240
+ return paren
235
241
endif
236
242
237
243
" Now we have to reimplement lispindent. This is surprisingly easy, as
@@ -250,12 +256,12 @@ if exists("*searchpairpos")
250
256
call cursor (paren)
251
257
252
258
if s: is_method_special_case (paren)
253
- return paren[1 ] + &shiftwidth - 1
259
+ return [ paren[0 ], paren[ 1 ] + &shiftwidth - 1 ]
254
260
endif
255
261
256
262
" In case we are at the last character, we use the paren position.
257
263
if col (" $" ) - 1 == paren[1 ]
258
- return paren[ 1 ]
264
+ return paren
259
265
endif
260
266
261
267
" In case after the paren is a whitespace, we search for the next word.
@@ -267,14 +273,14 @@ if exists("*searchpairpos")
267
273
" If we moved to another line, there is no word after the (. We
268
274
" use the ( position for indent.
269
275
if line (" ." ) > paren[0 ]
270
- return paren[ 1 ]
276
+ return paren
271
277
endif
272
278
273
279
" We still have to check, whether the keyword starts with a (, [ or {.
274
280
" In that case we use the ( position for indent.
275
281
let w = s: current_word ()
276
- if stridx ( ' ([{ ' , w [0 ]) > - 1
277
- return paren[ 1 ]
282
+ if s: bracket_type ( w [0 ]) == 1
283
+ return paren
278
284
endif
279
285
280
286
" Test words without namespace qualifiers and leading reader macro
@@ -284,23 +290,67 @@ if exists("*searchpairpos")
284
290
let ww = s: strip_namespace_and_macro_chars (w )
285
291
286
292
if &lispwords = ~# ' \V\<' . ww . ' \>'
287
- return paren[1 ] + &shiftwidth - 1
293
+ return [ paren[0 ], paren[ 1 ] + &shiftwidth - 1 ]
288
294
endif
289
295
290
296
if g: clojure_fuzzy_indent
291
297
\ && ! s: match_one (g: clojure_fuzzy_indent_blacklist , ww )
292
298
\ && s: match_one (g: clojure_fuzzy_indent_patterns , ww )
293
- return paren[1 ] + &shiftwidth - 1
299
+ return [ paren[0 ], paren[ 1 ] + &shiftwidth - 1 ]
294
300
endif
295
301
296
302
call search (' \v\_s' , ' cW' )
297
303
call search (' \v\S' , ' W' )
298
304
if paren[0 ] < line (" ." )
299
- return paren[1 ] + (g: clojure_align_subforms ? 0 : &shiftwidth - 1 )
305
+ return [ paren[0 ], paren[ 1 ] + (g: clojure_align_subforms ? 0 : &shiftwidth - 1 )]
300
306
endif
301
307
302
308
call search (' \v\S' , ' bW' )
303
- return virtcol (" ." ) + 1
309
+ return [line (' .' ), virtcol (' .' ) + 1 ]
310
+ endfunction
311
+
312
+ function ! GetClojureIndent ()
313
+ let lnum = line (' .' )
314
+ let [opening_lnum, indent ] = s: clojure_indent_pos ()
315
+
316
+ " Return if there are no previous lines to inherit from
317
+ if opening_lnum < 1 || opening_lnum >= lnum - 1
318
+ return indent
319
+ endif
320
+
321
+ let bracket_count = 0
322
+
323
+ " Take the indent of the first previous non-white line that is
324
+ " at the same sexp level. cf. src/misc1.c:get_lisp_indent()
325
+ while 1
326
+ let lnum = prevnonblank (lnum - 1 )
327
+ let col = 1
328
+
329
+ if lnum <= opening_lnum
330
+ break
331
+ endif
332
+
333
+ call cursor (lnum, col )
334
+
335
+ " Handle bracket counting edge case
336
+ if s: is_paren ()
337
+ let bracket_count += s: bracket_type (s: current_char ())
338
+ endif
339
+
340
+ while 1
341
+ if search (' \v[(\[{}\])]' , ' ' , lnum) < 1
342
+ break
343
+ elseif ! s: ignored_region ()
344
+ let bracket_count += s: bracket_type (s: current_char ())
345
+ endif
346
+ endwhile
347
+
348
+ if bracket_count == 0
349
+ return indent (lnum)
350
+ endif
351
+ endwhile
352
+
353
+ return indent
304
354
endfunction
305
355
306
356
setlocal indentexpr = GetClojureIndent ()
0 commit comments