1fa13eef3SBram Moolenaar" Vim indent file 2fa13eef3SBram Moolenaar" Language: Clojure 3*113cb513SBram Moolenaar" Maintainer: Alex Vear <[email protected]> 4942db23cSBram Moolenaar" Former Maintainers: Sung Pae <[email protected]> 5942db23cSBram Moolenaar" Meikel Brandmeyer <[email protected]> 6942db23cSBram Moolenaar" URL: https://github.com/clojure-vim/clojure.vim 7942db23cSBram Moolenaar" License: Vim (see :h license) 8*113cb513SBram Moolenaar" Last Change: 2021-10-26 9baca7f70SBram Moolenaar 10fa13eef3SBram Moolenaarif exists("b:did_indent") 11fa13eef3SBram Moolenaar finish 12fa13eef3SBram Moolenaarendif 13fa13eef3SBram Moolenaarlet b:did_indent = 1 14fa13eef3SBram Moolenaar 15fa13eef3SBram Moolenaarlet s:save_cpo = &cpo 16fa13eef3SBram Moolenaarset cpo&vim 17fa13eef3SBram Moolenaar 18a6878375SBram Moolenaarlet b:undo_indent = 'setlocal autoindent< smartindent< expandtab< softtabstop< shiftwidth< indentexpr< indentkeys<' 19fa13eef3SBram Moolenaar 20fa13eef3SBram Moolenaarsetlocal noautoindent nosmartindent 21fa13eef3SBram Moolenaarsetlocal softtabstop=2 shiftwidth=2 expandtab 22fa13eef3SBram Moolenaarsetlocal indentkeys=!,o,O 23fa13eef3SBram Moolenaar 24fa13eef3SBram Moolenaarif exists("*searchpairpos") 25fa13eef3SBram Moolenaar 26fa13eef3SBram Moolenaar if !exists('g:clojure_maxlines') 27*113cb513SBram Moolenaar let g:clojure_maxlines = 300 28fa13eef3SBram Moolenaar endif 29fa13eef3SBram Moolenaar 30fa13eef3SBram Moolenaar if !exists('g:clojure_fuzzy_indent') 31fa13eef3SBram Moolenaar let g:clojure_fuzzy_indent = 1 32fa13eef3SBram Moolenaar endif 33fa13eef3SBram Moolenaar 34fa13eef3SBram Moolenaar if !exists('g:clojure_fuzzy_indent_patterns') 35fa13eef3SBram Moolenaar let g:clojure_fuzzy_indent_patterns = ['^with', '^def', '^let'] 36fa13eef3SBram Moolenaar endif 37fa13eef3SBram Moolenaar 38fa13eef3SBram Moolenaar if !exists('g:clojure_fuzzy_indent_blacklist') 39fa13eef3SBram Moolenaar let g:clojure_fuzzy_indent_blacklist = ['-fn$', '\v^with-%(meta|out-str|loading-context)$'] 40fa13eef3SBram Moolenaar endif 41fa13eef3SBram Moolenaar 42fa13eef3SBram Moolenaar if !exists('g:clojure_special_indent_words') 43fa13eef3SBram Moolenaar let g:clojure_special_indent_words = 'deftype,defrecord,reify,proxy,extend-type,extend-protocol,letfn' 44fa13eef3SBram Moolenaar endif 45fa13eef3SBram Moolenaar 46fa13eef3SBram Moolenaar if !exists('g:clojure_align_multiline_strings') 47fa13eef3SBram Moolenaar let g:clojure_align_multiline_strings = 0 48fa13eef3SBram Moolenaar endif 49fa13eef3SBram Moolenaar 50438f67a0SBram Moolenaar if !exists('g:clojure_align_subforms') 51438f67a0SBram Moolenaar let g:clojure_align_subforms = 0 52438f67a0SBram Moolenaar endif 53438f67a0SBram Moolenaar 546f1d9a09SBram Moolenaar function! s:syn_id_name() 55fa13eef3SBram Moolenaar return synIDattr(synID(line("."), col("."), 0), "name") 56fa13eef3SBram Moolenaar endfunction 57fa13eef3SBram Moolenaar 586f1d9a09SBram Moolenaar function! s:ignored_region() 596f1d9a09SBram Moolenaar return s:syn_id_name() =~? '\vstring|regex|comment|character' 606f1d9a09SBram Moolenaar endfunction 616f1d9a09SBram Moolenaar 626f1d9a09SBram Moolenaar function! s:current_char() 63fa13eef3SBram Moolenaar return getline('.')[col('.')-1] 64fa13eef3SBram Moolenaar endfunction 65fa13eef3SBram Moolenaar 666f1d9a09SBram Moolenaar function! s:current_word() 67fa13eef3SBram Moolenaar return getline('.')[col('.')-1 : searchpos('\v>', 'n', line('.'))[1]-2] 68fa13eef3SBram Moolenaar endfunction 69fa13eef3SBram Moolenaar 706f1d9a09SBram Moolenaar function! s:is_paren() 716f1d9a09SBram Moolenaar return s:current_char() =~# '\v[\(\)\[\]\{\}]' && !s:ignored_region() 72fa13eef3SBram Moolenaar endfunction 73fa13eef3SBram Moolenaar 74*113cb513SBram Moolenaar " Returns 1 if string matches a pattern in 'patterns', which should be 75*113cb513SBram Moolenaar " a list of patterns. 766f1d9a09SBram Moolenaar function! s:match_one(patterns, string) 77*113cb513SBram Moolenaar for pat in a:patterns 7876f3b1adSBram Moolenaar if a:string =~# pat | return 1 | endif 79fa13eef3SBram Moolenaar endfor 80fa13eef3SBram Moolenaar endfunction 81fa13eef3SBram Moolenaar 826f1d9a09SBram Moolenaar function! s:match_pairs(open, close, stopat) 83fa13eef3SBram Moolenaar " Stop only on vector and map [ resp. {. Ignore the ones in strings and 84fa13eef3SBram Moolenaar " comments. 85942db23cSBram Moolenaar if a:stopat == 0 && g:clojure_maxlines > 0 86fa13eef3SBram Moolenaar let stopat = max([line(".") - g:clojure_maxlines, 0]) 87fa13eef3SBram Moolenaar else 88fa13eef3SBram Moolenaar let stopat = a:stopat 89fa13eef3SBram Moolenaar endif 90fa13eef3SBram Moolenaar 916f1d9a09SBram Moolenaar let pos = searchpairpos(a:open, '', a:close, 'bWn', "!s:is_paren()", stopat) 926f1d9a09SBram Moolenaar return [pos[0], col(pos)] 93fa13eef3SBram Moolenaar endfunction 94fa13eef3SBram Moolenaar 956f1d9a09SBram Moolenaar function! s:clojure_check_for_string_worker() 96fa13eef3SBram Moolenaar " Check whether there is the last character of the previous line is 97fa13eef3SBram Moolenaar " highlighted as a string. If so, we check whether it's a ". In this 98fa13eef3SBram Moolenaar " case we have to check also the previous character. The " might be the 99fa13eef3SBram Moolenaar " closing one. In case the we are still in the string, we search for the 100fa13eef3SBram Moolenaar " opening ". If this is not found we take the indent of the line. 101fa13eef3SBram Moolenaar let nb = prevnonblank(v:lnum - 1) 102fa13eef3SBram Moolenaar 103fa13eef3SBram Moolenaar if nb == 0 104fa13eef3SBram Moolenaar return -1 105fa13eef3SBram Moolenaar endif 106fa13eef3SBram Moolenaar 107fa13eef3SBram Moolenaar call cursor(nb, 0) 108fa13eef3SBram Moolenaar call cursor(0, col("$") - 1) 1096f1d9a09SBram Moolenaar if s:syn_id_name() !~? "string" 110fa13eef3SBram Moolenaar return -1 111fa13eef3SBram Moolenaar endif 112fa13eef3SBram Moolenaar 113fa13eef3SBram Moolenaar " This will not work for a " in the first column... 1146f1d9a09SBram Moolenaar if s:current_char() == '"' 115fa13eef3SBram Moolenaar call cursor(0, col("$") - 2) 1166f1d9a09SBram Moolenaar if s:syn_id_name() !~? "string" 117fa13eef3SBram Moolenaar return -1 118fa13eef3SBram Moolenaar endif 119942db23cSBram Moolenaar if s:current_char() != '\' 120fa13eef3SBram Moolenaar return -1 121fa13eef3SBram Moolenaar endif 122fa13eef3SBram Moolenaar call cursor(0, col("$") - 1) 123fa13eef3SBram Moolenaar endif 124fa13eef3SBram Moolenaar 125fa13eef3SBram Moolenaar let p = searchpos('\(^\|[^\\]\)\zs"', 'bW') 126fa13eef3SBram Moolenaar 127fa13eef3SBram Moolenaar if p != [0, 0] 128fa13eef3SBram Moolenaar return p[1] - 1 129fa13eef3SBram Moolenaar endif 130fa13eef3SBram Moolenaar 131fa13eef3SBram Moolenaar return indent(".") 132fa13eef3SBram Moolenaar endfunction 133fa13eef3SBram Moolenaar 1346f1d9a09SBram Moolenaar function! s:check_for_string() 135baca7f70SBram Moolenaar let pos = getpos('.') 136fa13eef3SBram Moolenaar try 1376f1d9a09SBram Moolenaar let val = s:clojure_check_for_string_worker() 138fa13eef3SBram Moolenaar finally 139baca7f70SBram Moolenaar call setpos('.', pos) 140fa13eef3SBram Moolenaar endtry 141fa13eef3SBram Moolenaar return val 142fa13eef3SBram Moolenaar endfunction 143fa13eef3SBram Moolenaar 1446f1d9a09SBram Moolenaar function! s:strip_namespace_and_macro_chars(word) 14576f3b1adSBram Moolenaar return substitute(a:word, "\\v%(.*/|[#'`~@^,]*)(.*)", '\1', '') 14676f3b1adSBram Moolenaar endfunction 14776f3b1adSBram Moolenaar 1486f1d9a09SBram Moolenaar function! s:clojure_is_method_special_case_worker(position) 149fa13eef3SBram Moolenaar " Find the next enclosing form. 150fa13eef3SBram Moolenaar call search('\S', 'Wb') 151fa13eef3SBram Moolenaar 152fa13eef3SBram Moolenaar " Special case: we are at a '(('. 1536f1d9a09SBram Moolenaar if s:current_char() == '(' 154fa13eef3SBram Moolenaar return 0 155fa13eef3SBram Moolenaar endif 156fa13eef3SBram Moolenaar call cursor(a:position) 157fa13eef3SBram Moolenaar 1586f1d9a09SBram Moolenaar let next_paren = s:match_pairs('(', ')', 0) 159fa13eef3SBram Moolenaar 160fa13eef3SBram Moolenaar " Special case: we are now at toplevel. 1616f1d9a09SBram Moolenaar if next_paren == [0, 0] 162fa13eef3SBram Moolenaar return 0 163fa13eef3SBram Moolenaar endif 1646f1d9a09SBram Moolenaar call cursor(next_paren) 165fa13eef3SBram Moolenaar 166fa13eef3SBram Moolenaar call search('\S', 'W') 1676f1d9a09SBram Moolenaar let w = s:strip_namespace_and_macro_chars(s:current_word()) 168942db23cSBram Moolenaar 16976f3b1adSBram Moolenaar if g:clojure_special_indent_words =~# '\V\<' . w . '\>' 170942db23cSBram Moolenaar 171942db23cSBram Moolenaar " `letfn` is a special-special-case. 172942db23cSBram Moolenaar if w ==# 'letfn' 173942db23cSBram Moolenaar " Earlier code left the cursor at: 174942db23cSBram Moolenaar " (letfn [...] ...) 175942db23cSBram Moolenaar " ^ 176942db23cSBram Moolenaar 177942db23cSBram Moolenaar " Search and get coordinates of first `[` 178942db23cSBram Moolenaar " (letfn [...] ...) 179942db23cSBram Moolenaar " ^ 180942db23cSBram Moolenaar call search('\[', 'W') 181942db23cSBram Moolenaar let pos = getcurpos() 182942db23cSBram Moolenaar let letfn_bracket = [pos[1], pos[2]] 183942db23cSBram Moolenaar 184942db23cSBram Moolenaar " Move cursor to start of the form this function was 185942db23cSBram Moolenaar " initially called on. Grab the coordinates of the 186942db23cSBram Moolenaar " closest outer `[`. 187942db23cSBram Moolenaar call cursor(a:position) 188942db23cSBram Moolenaar let outer_bracket = s:match_pairs('\[', '\]', 0) 189942db23cSBram Moolenaar 190942db23cSBram Moolenaar " If the located square brackets are not the same, 191942db23cSBram Moolenaar " don't use special-case formatting. 192942db23cSBram Moolenaar if outer_bracket != letfn_bracket 193942db23cSBram Moolenaar return 0 194942db23cSBram Moolenaar endif 195942db23cSBram Moolenaar endif 196942db23cSBram Moolenaar 197fa13eef3SBram Moolenaar return 1 198fa13eef3SBram Moolenaar endif 199fa13eef3SBram Moolenaar 200fa13eef3SBram Moolenaar return 0 201fa13eef3SBram Moolenaar endfunction 202fa13eef3SBram Moolenaar 2036f1d9a09SBram Moolenaar function! s:is_method_special_case(position) 204baca7f70SBram Moolenaar let pos = getpos('.') 205fa13eef3SBram Moolenaar try 2066f1d9a09SBram Moolenaar let val = s:clojure_is_method_special_case_worker(a:position) 207fa13eef3SBram Moolenaar finally 208baca7f70SBram Moolenaar call setpos('.', pos) 209fa13eef3SBram Moolenaar endtry 210fa13eef3SBram Moolenaar return val 211fa13eef3SBram Moolenaar endfunction 212fa13eef3SBram Moolenaar 2136f1d9a09SBram Moolenaar " Check if form is a reader conditional, that is, it is prefixed by #? 214*113cb513SBram Moolenaar " or #?@ 2156f1d9a09SBram Moolenaar function! s:is_reader_conditional_special_case(position) 216942db23cSBram Moolenaar return getline(a:position[0])[a:position[1] - 3 : a:position[1] - 2] == "#?" 217*113cb513SBram Moolenaar \|| getline(a:position[0])[a:position[1] - 4 : a:position[1] - 2] == "#?@" 2186f1d9a09SBram Moolenaar endfunction 2196f1d9a09SBram Moolenaar 2206f1d9a09SBram Moolenaar " Returns 1 for opening brackets, -1 for _anything else_. 2216f1d9a09SBram Moolenaar function! s:bracket_type(char) 2226f1d9a09SBram Moolenaar return stridx('([{', a:char) > -1 ? 1 : -1 2236f1d9a09SBram Moolenaar endfunction 2246f1d9a09SBram Moolenaar 2256f1d9a09SBram Moolenaar " Returns: [opening-bracket-lnum, indent] 2266f1d9a09SBram Moolenaar function! s:clojure_indent_pos() 227fa13eef3SBram Moolenaar " Get rid of special case. 228fa13eef3SBram Moolenaar if line(".") == 1 2296f1d9a09SBram Moolenaar return [0, 0] 230fa13eef3SBram Moolenaar endif 231fa13eef3SBram Moolenaar 232fa13eef3SBram Moolenaar " We have to apply some heuristics here to figure out, whether to use 233fa13eef3SBram Moolenaar " normal lisp indenting or not. 2346f1d9a09SBram Moolenaar let i = s:check_for_string() 235fa13eef3SBram Moolenaar if i > -1 2366f1d9a09SBram Moolenaar return [0, i + !!g:clojure_align_multiline_strings] 237fa13eef3SBram Moolenaar endif 238fa13eef3SBram Moolenaar 239fa13eef3SBram Moolenaar call cursor(0, 1) 240fa13eef3SBram Moolenaar 241fa13eef3SBram Moolenaar " Find the next enclosing [ or {. We can limit the second search 242fa13eef3SBram Moolenaar " to the line, where the [ was found. If no [ was there this is 243fa13eef3SBram Moolenaar " zero and we search for an enclosing {. 2446f1d9a09SBram Moolenaar let paren = s:match_pairs('(', ')', 0) 2456f1d9a09SBram Moolenaar let bracket = s:match_pairs('\[', '\]', paren[0]) 2466f1d9a09SBram Moolenaar let curly = s:match_pairs('{', '}', bracket[0]) 247fa13eef3SBram Moolenaar 248fa13eef3SBram Moolenaar " In case the curly brace is on a line later then the [ or - in 249fa13eef3SBram Moolenaar " case they are on the same line - in a higher column, we take the 250fa13eef3SBram Moolenaar " curly indent. 251fa13eef3SBram Moolenaar if curly[0] > bracket[0] || curly[1] > bracket[1] 252fa13eef3SBram Moolenaar if curly[0] > paren[0] || curly[1] > paren[1] 2536f1d9a09SBram Moolenaar return curly 254fa13eef3SBram Moolenaar endif 255fa13eef3SBram Moolenaar endif 256fa13eef3SBram Moolenaar 257fa13eef3SBram Moolenaar " If the curly was not chosen, we take the bracket indent - if 258fa13eef3SBram Moolenaar " there was one. 259fa13eef3SBram Moolenaar if bracket[0] > paren[0] || bracket[1] > paren[1] 2606f1d9a09SBram Moolenaar return bracket 261fa13eef3SBram Moolenaar endif 262fa13eef3SBram Moolenaar 263fa13eef3SBram Moolenaar " There are neither { nor [ nor (, ie. we are at the toplevel. 264fa13eef3SBram Moolenaar if paren == [0, 0] 2656f1d9a09SBram Moolenaar return paren 266fa13eef3SBram Moolenaar endif 267fa13eef3SBram Moolenaar 268fa13eef3SBram Moolenaar " Now we have to reimplement lispindent. This is surprisingly easy, as 269fa13eef3SBram Moolenaar " soon as one has access to syntax items. 270fa13eef3SBram Moolenaar " 271fa13eef3SBram Moolenaar " - Check whether we are in a special position after a word in 272fa13eef3SBram Moolenaar " g:clojure_special_indent_words. These are special cases. 273fa13eef3SBram Moolenaar " - Get the next keyword after the (. 274fa13eef3SBram Moolenaar " - If its first character is also a (, we have another sexp and align 275fa13eef3SBram Moolenaar " one column to the right of the unmatched (. 276fa13eef3SBram Moolenaar " - In case it is in lispwords, we indent the next line to the column of 277fa13eef3SBram Moolenaar " the ( + sw. 278fa13eef3SBram Moolenaar " - If not, we check whether it is last word in the line. In that case 279fa13eef3SBram Moolenaar " we again use ( + sw for indent. 280fa13eef3SBram Moolenaar " - In any other case we use the column of the end of the word + 2. 281fa13eef3SBram Moolenaar call cursor(paren) 282fa13eef3SBram Moolenaar 2836f1d9a09SBram Moolenaar if s:is_method_special_case(paren) 284942db23cSBram Moolenaar return [paren[0], paren[1] + &shiftwidth - 1] 2856f1d9a09SBram Moolenaar endif 2866f1d9a09SBram Moolenaar 2876f1d9a09SBram Moolenaar if s:is_reader_conditional_special_case(paren) 2886f1d9a09SBram Moolenaar return paren 289fa13eef3SBram Moolenaar endif 290fa13eef3SBram Moolenaar 291fa13eef3SBram Moolenaar " In case we are at the last character, we use the paren position. 292fa13eef3SBram Moolenaar if col("$") - 1 == paren[1] 2936f1d9a09SBram Moolenaar return paren 294fa13eef3SBram Moolenaar endif 295fa13eef3SBram Moolenaar 296fa13eef3SBram Moolenaar " In case after the paren is a whitespace, we search for the next word. 297baca7f70SBram Moolenaar call cursor(0, col('.') + 1) 2986f1d9a09SBram Moolenaar if s:current_char() == ' ' 299baca7f70SBram Moolenaar call search('\v\S', 'W') 300fa13eef3SBram Moolenaar endif 301fa13eef3SBram Moolenaar 302fa13eef3SBram Moolenaar " If we moved to another line, there is no word after the (. We 303fa13eef3SBram Moolenaar " use the ( position for indent. 304fa13eef3SBram Moolenaar if line(".") > paren[0] 3056f1d9a09SBram Moolenaar return paren 306fa13eef3SBram Moolenaar endif 307fa13eef3SBram Moolenaar 308fa13eef3SBram Moolenaar " We still have to check, whether the keyword starts with a (, [ or {. 309fa13eef3SBram Moolenaar " In that case we use the ( position for indent. 3106f1d9a09SBram Moolenaar let w = s:current_word() 3116f1d9a09SBram Moolenaar if s:bracket_type(w[0]) == 1 3126f1d9a09SBram Moolenaar return paren 313fa13eef3SBram Moolenaar endif 314fa13eef3SBram Moolenaar 315942db23cSBram Moolenaar " If the keyword begins with #, check if it is an anonymous 316942db23cSBram Moolenaar " function or set, in which case we indent by the shiftwidth 317942db23cSBram Moolenaar " (minus one if g:clojure_align_subforms = 1), or if it is 318942db23cSBram Moolenaar " ignored, in which case we use the ( position for indent. 319942db23cSBram Moolenaar if w[0] == "#" 320942db23cSBram Moolenaar " TODO: Handle #=() and other rare reader invocations? 321942db23cSBram Moolenaar if w[1] == '(' || w[1] == '{' 322942db23cSBram Moolenaar return [paren[0], paren[1] + (g:clojure_align_subforms ? 0 : &shiftwidth - 1)] 323942db23cSBram Moolenaar elseif w[1] == '_' 324942db23cSBram Moolenaar return paren 325942db23cSBram Moolenaar endif 326942db23cSBram Moolenaar endif 327942db23cSBram Moolenaar 328fa13eef3SBram Moolenaar " Test words without namespace qualifiers and leading reader macro 329fa13eef3SBram Moolenaar " metacharacters. 330fa13eef3SBram Moolenaar " 331fa13eef3SBram Moolenaar " e.g. clojure.core/defn and #'defn should both indent like defn. 3326f1d9a09SBram Moolenaar let ww = s:strip_namespace_and_macro_chars(w) 333fa13eef3SBram Moolenaar 33476f3b1adSBram Moolenaar if &lispwords =~# '\V\<' . ww . '\>' 335942db23cSBram Moolenaar return [paren[0], paren[1] + &shiftwidth - 1] 336fa13eef3SBram Moolenaar endif 337fa13eef3SBram Moolenaar 338fa13eef3SBram Moolenaar if g:clojure_fuzzy_indent 3396f1d9a09SBram Moolenaar \ && !s:match_one(g:clojure_fuzzy_indent_blacklist, ww) 3406f1d9a09SBram Moolenaar \ && s:match_one(g:clojure_fuzzy_indent_patterns, ww) 341942db23cSBram Moolenaar return [paren[0], paren[1] + &shiftwidth - 1] 342fa13eef3SBram Moolenaar endif 343fa13eef3SBram Moolenaar 344baca7f70SBram Moolenaar call search('\v\_s', 'cW') 345baca7f70SBram Moolenaar call search('\v\S', 'W') 346fa13eef3SBram Moolenaar if paren[0] < line(".") 347942db23cSBram Moolenaar return [paren[0], paren[1] + (g:clojure_align_subforms ? 0 : &shiftwidth - 1)] 348fa13eef3SBram Moolenaar endif 349fa13eef3SBram Moolenaar 350baca7f70SBram Moolenaar call search('\v\S', 'bW') 3516f1d9a09SBram Moolenaar return [line('.'), col('.') + 1] 3526f1d9a09SBram Moolenaar endfunction 3536f1d9a09SBram Moolenaar 3546f1d9a09SBram Moolenaar function! GetClojureIndent() 3556f1d9a09SBram Moolenaar let lnum = line('.') 3566f1d9a09SBram Moolenaar let orig_lnum = lnum 3576f1d9a09SBram Moolenaar let orig_col = col('.') 3586f1d9a09SBram Moolenaar let [opening_lnum, indent] = s:clojure_indent_pos() 3596f1d9a09SBram Moolenaar 3606f1d9a09SBram Moolenaar " Account for multibyte characters 3616f1d9a09SBram Moolenaar if opening_lnum > 0 3626f1d9a09SBram Moolenaar let indent -= indent - virtcol([opening_lnum, indent]) 3636f1d9a09SBram Moolenaar endif 3646f1d9a09SBram Moolenaar 3656f1d9a09SBram Moolenaar " Return if there are no previous lines to inherit from 3666f1d9a09SBram Moolenaar if opening_lnum < 1 || opening_lnum >= lnum - 1 3676f1d9a09SBram Moolenaar call cursor(orig_lnum, orig_col) 3686f1d9a09SBram Moolenaar return indent 3696f1d9a09SBram Moolenaar endif 3706f1d9a09SBram Moolenaar 3716f1d9a09SBram Moolenaar let bracket_count = 0 3726f1d9a09SBram Moolenaar 3736f1d9a09SBram Moolenaar " Take the indent of the first previous non-white line that is 3746f1d9a09SBram Moolenaar " at the same sexp level. cf. src/misc1.c:get_lisp_indent() 3756f1d9a09SBram Moolenaar while 1 3766f1d9a09SBram Moolenaar let lnum = prevnonblank(lnum - 1) 3776f1d9a09SBram Moolenaar let col = 1 3786f1d9a09SBram Moolenaar 3796f1d9a09SBram Moolenaar if lnum <= opening_lnum 3806f1d9a09SBram Moolenaar break 3816f1d9a09SBram Moolenaar endif 3826f1d9a09SBram Moolenaar 3836f1d9a09SBram Moolenaar call cursor(lnum, col) 3846f1d9a09SBram Moolenaar 3856f1d9a09SBram Moolenaar " Handle bracket counting edge case 3866f1d9a09SBram Moolenaar if s:is_paren() 3876f1d9a09SBram Moolenaar let bracket_count += s:bracket_type(s:current_char()) 3886f1d9a09SBram Moolenaar endif 3896f1d9a09SBram Moolenaar 3906f1d9a09SBram Moolenaar while 1 3916f1d9a09SBram Moolenaar if search('\v[(\[{}\])]', '', lnum) < 1 3926f1d9a09SBram Moolenaar break 3936f1d9a09SBram Moolenaar elseif !s:ignored_region() 3946f1d9a09SBram Moolenaar let bracket_count += s:bracket_type(s:current_char()) 3956f1d9a09SBram Moolenaar endif 3966f1d9a09SBram Moolenaar endwhile 3976f1d9a09SBram Moolenaar 3986f1d9a09SBram Moolenaar if bracket_count == 0 3996f1d9a09SBram Moolenaar " Check if this is part of a multiline string 4006f1d9a09SBram Moolenaar call cursor(lnum, 1) 4016f1d9a09SBram Moolenaar if s:syn_id_name() !~? '\vstring|regex' 4026f1d9a09SBram Moolenaar call cursor(orig_lnum, orig_col) 4036f1d9a09SBram Moolenaar return indent(lnum) 4046f1d9a09SBram Moolenaar endif 4056f1d9a09SBram Moolenaar endif 4066f1d9a09SBram Moolenaar endwhile 4076f1d9a09SBram Moolenaar 4086f1d9a09SBram Moolenaar call cursor(orig_lnum, orig_col) 4096f1d9a09SBram Moolenaar return indent 410fa13eef3SBram Moolenaar endfunction 411fa13eef3SBram Moolenaar 412fa13eef3SBram Moolenaar setlocal indentexpr=GetClojureIndent() 413fa13eef3SBram Moolenaar 414fa13eef3SBram Moolenaarelse 415fa13eef3SBram Moolenaar 416fa13eef3SBram Moolenaar " In case we have searchpairpos not available we fall back to 417fa13eef3SBram Moolenaar " normal lisp indenting. 418fa13eef3SBram Moolenaar setlocal indentexpr= 419fa13eef3SBram Moolenaar setlocal lisp 420fa13eef3SBram Moolenaar let b:undo_indent .= '| setlocal lisp<' 421fa13eef3SBram Moolenaar 422fa13eef3SBram Moolenaarendif 423fa13eef3SBram Moolenaar 424fa13eef3SBram Moolenaarlet &cpo = s:save_cpo 425fa13eef3SBram Moolenaarunlet! s:save_cpo 426fa13eef3SBram Moolenaar 427baca7f70SBram Moolenaar" vim:sts=8:sw=8:ts=8:noet 428