citadel

My dotfiles, scripts and nix configs
git clone git://jb55.com/citadel
Log | Files | Refs | README | LICENSE

clojure.vim (5448B)


      1 " Vim indent file
      2 " Language:      Clojure
      3 " Maintainer:    Meikel Brandmeyer <mb@kotka.de>
      4 " URL:           http://kotka.de/projects/clojure/vimclojure.html
      5 
      6 " Only load this indent file when no other was loaded.
      7 if exists("b:did_indent")
      8 	finish
      9 endif
     10 let b:did_indent = 1
     11 
     12 let s:save_cpo = &cpo
     13 set cpo&vim
     14 
     15 let b:undo_indent = "setlocal ai< si< lw< et< sts< sw< inde< indk<"
     16 
     17 setlocal autoindent expandtab nosmartindent
     18 
     19 setlocal softtabstop=2
     20 setlocal shiftwidth=2
     21 
     22 setlocal indentkeys=!,o,O
     23 
     24 if exists("*searchpairpos")
     25 
     26 function! s:MatchPairs(open, close, stopat)
     27 	" Stop only on vector and map [ resp. {. Ignore the ones in strings and
     28 	" comments.
     29 	return searchpairpos(a:open, '', a:close, 'bWn',
     30 				\ 'vimclojure#SynIdName() !~ "clojureParen\\d"',
     31 				\ a:stopat)
     32 endfunction
     33 
     34 function! VimClojureCheckForStringWorker()
     35 	" Check whether there is the last character of the previous line is
     36 	" highlighted as a string. If so, we check whether it's a ". In this
     37 	" case we have to check also the previous character. The " might be the
     38 	" closing one. In case the we are still in the string, we search for the
     39 	" opening ". If this is not found we take the indent of the line.
     40 	let nb = prevnonblank(v:lnum - 1)
     41 
     42 	if nb == 0
     43 		return -1
     44 	endif
     45 
     46 	call cursor(nb, 0)
     47 	call cursor(0, col("$") - 1)
     48 	if vimclojure#SynIdName() != "clojureString"
     49 		return -1
     50 	endif
     51 
     52 	" This will not work for a " in the first column...
     53 	if vimclojure#Yank('l', 'normal! "lyl') == '"'
     54 		call cursor(0, col("$") - 2)
     55 		if vimclojure#SynIdName() != "clojureString"
     56 			return -1
     57 		endif
     58 		if vimclojure#Yank('l', 'normal! "lyl') != '\\'
     59 			return -1
     60 		endif
     61 		call cursor(0, col("$") - 1)
     62 	endif
     63 
     64 	let p = searchpos('\(^\|[^\\]\)\zs"', 'bW')
     65 
     66 	if p != [0, 0]
     67 		return p[1] - 1
     68 	endif
     69 
     70 	return indent(".")
     71 endfunction
     72 
     73 function! VimClojureCheckForString()
     74 	return vimclojure#WithSavedPosition({'f': function("VimClojureCheckForStringWorker")})
     75 endfunction
     76 
     77 function! GetClojureIndent()
     78 	" Get rid of special case.
     79 	if line(".") == 1
     80 		return 0
     81 	endif
     82 
     83 	" We have to apply some heuristics here to figure out, whether to use
     84 	" normal lisp indenting or not.
     85 	let i = VimClojureCheckForString()
     86 	if i > -1
     87 		return i
     88 	endif
     89 
     90 	call cursor(0, 1)
     91 
     92 	" Find the next enclosing [ or {. We can limit the second search
     93 	" to the line, where the [ was found. If no [ was there this is
     94 	" zero and we search for an enclosing {.
     95 	let paren = s:MatchPairs('(', ')', 0)
     96 	let bracket = s:MatchPairs('\[', '\]', paren[0])
     97 	let curly = s:MatchPairs('{', '}', bracket[0])
     98 
     99 	" In case the curly brace is on a line later then the [ or - in
    100 	" case they are on the same line - in a higher column, we take the
    101 	" curly indent.
    102 	if curly[0] > bracket[0] || curly[1] > bracket[1]
    103 		if curly[0] > paren[0] || curly[1] > paren[1]
    104 			return curly[1]
    105 		endif
    106 	endif
    107 
    108 	" If the curly was not chosen, we take the bracket indent - if
    109 	" there was one.
    110 	if bracket[0] > paren[0] || bracket[1] > paren[1]
    111 		return bracket[1]
    112 	endif
    113 
    114 	" There are neither { nor [ nor (, ie. we are at the toplevel.
    115 	if paren == [0, 0]
    116 		return 0
    117 	endif
    118 
    119 	" Now we have to reimplement lispindent. This is surprisingly easy, as
    120 	" soon as one has access to syntax items.
    121 	"
    122 	" - Get the next keyword after the (.
    123 	" - If its first character is also a (, we have another sexp and align
    124 	"   one column to the right of the unmatched (.
    125 	" - In case it is in lispwords, we indent the next line to the column of
    126 	"   the ( + sw.
    127 	" - If not, we check whether it is last word in the line. In that case
    128 	"   we again use ( + sw for indent.
    129 	" - In any other case we use the column of the end of the word + 2.
    130 	call cursor(paren[0] , paren[1])
    131 
    132 	" In case we are at the last character, we use the paren position.
    133 	if col("$") - 1 == paren[1]
    134 		return paren[1]
    135 	endif
    136 
    137 	" In case after the paren is a whitespace, we search for the next word.
    138 	normal! l
    139 	let reg = getreg("l")
    140 	normal! "lyl
    141 	if getreg("l") == ' '
    142 		normal! w
    143 	endif
    144 	call setreg("l", reg)
    145 
    146 	" If we moved to another line, there is no word after the (. We
    147 	" use the ( position for indent.
    148 	if line(".") > paren[0]
    149 		return paren[1]
    150 	endif
    151 
    152 	" We still have to check, whether the keyword starts with a (, [ or {.
    153 	" In that case we use the ( position for indent.
    154 	let reg = getreg("l")
    155 	normal! "lye
    156 	let w = getreg("l")
    157 	call setreg("l", reg)
    158 	if stridx('([{', w[0]) > 0
    159 		return paren[1]
    160 	endif
    161 
    162 	if &lispwords =~ '\<' . w . '\>'
    163 		return paren[1] + &shiftwidth - 1
    164 	endif
    165 
    166 	normal! w
    167 	if paren[0] < line(".")
    168 		return paren[1] + &shiftwidth - 1
    169 	endif
    170 
    171 	normal! ge
    172 	return col(".") + 1
    173 endfunction
    174 
    175 setlocal indentexpr=GetClojureIndent()
    176 
    177 else
    178 
    179 	" In case we have searchpairpos not available we fall back to
    180 	" normal lisp indenting.
    181 	setlocal indentexpr=
    182 	setlocal lisp
    183 	let b:undo_indent .= " lisp<"
    184 
    185 endif
    186 
    187 " Defintions:
    188 setlocal lispwords=def,def-,defn,defn-,defmacro,defmacro-,defmethod,defmulti
    189 setlocal lispwords+=defonce,defvar,defvar-,defunbound,let,fn,letfn,binding,proxy
    190 setlocal lispwords+=defnk
    191 
    192 " Conditionals and Loops:
    193 setlocal lispwords+=if,if-not,if-let,when,when-not,when-let,when-first
    194 setlocal lispwords+=cond,condp,loop,dotimes,for,while
    195 
    196 " Blocks:
    197 setlocal lispwords+=do,doto,try,catch,locking,with-in-str,with-out-str,with-open
    198 setlocal lispwords+=dosync,with-local-vars,doseq,dorun,doall,->,future
    199 
    200 " Namespaces:
    201 setlocal lispwords+=ns,clojure.core/ns
    202 
    203 " Java Classes:
    204 setlocal lispwords+=gen-class,gen-interface
    205 
    206 let &cpo = s:save_cpo