--- a/vim/indent/lisp.vim Sat Feb 20 13:18:08 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,374 +0,0 @@
-" lisp.vim:
-" Lisp indent plugin for Slimv
-" Version: 0.9.5
-" Last Change: 21 Feb 2012
-" Maintainer: Tamas Kovacs <kovisoft at gmail dot com>
-" License: This file is placed in the public domain.
-" No warranty, express or implied.
-" *** *** Use At-Your-Own-Risk! *** ***
-"
-" =====================================================================
-"
-" Load Once:
-if exists("b:did_indent")
- finish
-endif
-
-" Handle cases when lisp dialects explicitly use the lisp indent plugins
-if &ft == "clojure" && exists("g:slimv_disable_clojure")
- finish
-endif
-
-if &ft == "scheme" && exists("g:slimv_disable_scheme")
- finish
-endif
-
-
-" Maximum number of lines searched backwards for indenting special forms
-if !exists( 'g:slimv_indent_maxlines' )
- let g:slimv_indent_maxlines = 50
-endif
-
-" Special indentation for keyword lists
-if !exists( 'g:slimv_indent_keylists' )
- let g:slimv_indent_keylists = 1
-endif
-
-let s:skip_sc = 'synIDattr(synID(line("."), col("."), 0), "name") =~ "[Ss]tring\\|[Cc]omment"'
- " Skip matches inside string or comment
-let s:skip_q = 'getline(".")[col(".")-2] == "\\"' " Skip escaped double quote characters in matches
-
-let s:indent = '' " Most recent indentation info
-let s:spec_indent = 'flet\|labels\|macrolet\|symbol-macrolet'
- " List of symbols need special indenting
-let s:spec_param = 'defmacro' " List of symbols with special parameter list
-
-let s:binding_form = 'let\|let\*' " List of symbols with binding list
-
-" Get the filetype (Lisp dialect) used by Slimv
-function! SlimvGetFiletype()
- if &ft != ''
- " Return Vim filetype if defined
- return &ft
- endif
-
- if match( tolower( g:slimv_lisp ), 'clojure' ) >= 0 || match( tolower( g:slimv_lisp ), 'clj' ) >= 0
- " Must be Clojure
- return 'clojure'
- endif
-
- " We have no clue, guess its lisp
- return 'lisp'
-endfunction
-
-" Some multi-byte characters screw up the built-in lispindent()
-" This function is a wrapper that tries to fix it
-" TODO: implement custom indent procedure and omit lispindent()
-function! SlimvLispindent( lnum )
- set lisp
- let li = lispindent( a:lnum )
- set nolisp
- let backline = max([a:lnum-g:slimv_indent_maxlines, 1])
- let oldpos = getpos( '.' )
- call cursor( oldpos[1], 1 )
- " Find containing form
- let [lhead, chead] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
- if lhead == 0
- " No containing form, lispindent() is OK
- call cursor( oldpos[1], oldpos[2] )
- return li
- endif
- " Find outer form
- let [lparent, cparent] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
- call cursor( oldpos[1], oldpos[2] )
- if lparent == 0 || lhead != lparent
- " No outer form or starting above inner form, lispindent() is OK
- return li
- endif
- " Count extra bytes before the function header
- let header = strpart( getline( lparent ), 0 )
- let total_extra = 0
- let extra = 0
- let c = 0
- while a:lnum > 0 && c < chead-1
- let bytes = byteidx( header, c+1 ) - byteidx( header, c )
- if bytes > 1
- let total_extra = total_extra + bytes - 1
- if c >= cparent && extra < 10
- " Extra bytes in the outer function header
- let extra = extra + bytes - 1
- endif
- endif
- let c = c + 1
- endwhile
- if total_extra == 0
- " No multi-byte character, lispindent() is OK
- return li
- endif
- " In some cases ending spaces add up to lispindent() if there are multi-byte characters
- let ending_sp = len( matchstr( getline( lparent ), ' *$' ) )
- " Determine how wrong lispindent() is based on the number of extra bytes
- " These values were determined empirically
- if lparent == a:lnum - 1
- " Function header is in the previous line
- if extra == 0 && total_extra > 1
- let ending_sp = ending_sp + 1
- endif
- return li + [0, 1, 0, -3, -3, -3, -5, -5, -7, -7, -8][extra] - ending_sp
- else
- " Function header is in an upper line
- if extra == 0 || total_extra == extra
- let ending_sp = 0
- endif
- return li + [0, 1, 0, -2, -2, -3, -3, -3, -3, -3, -3][extra] - ending_sp
- endif
-endfunction
-
-" Return Lisp source code indentation at the given line
-function! SlimvIndent( lnum )
- if &autoindent == 0 || a:lnum <= 1
- " Start of the file
- return 0
- endif
- let pnum = prevnonblank(a:lnum - 1)
- if pnum == 0
- " Hit the start of the file, use zero indent.
- return 0
- endif
- let oldpos = getpos( '.' )
- let linenum = a:lnum
-
- " Handle multi-line string
- let plen = len( getline( pnum ) )
- if synIDattr( synID( pnum, plen, 0), 'name' ) =~ '[Ss]tring' && getline(pnum)[plen-1] != '"'
- " Previous non-blank line ends with an unclosed string, so this is a multi-line string
- let [l, c] = searchpairpos( '"', '', '"', 'bnW', s:skip_q )
- if l == pnum && c > 0
- " Indent to the opening double quote (if found)
- return c
- else
- return SlimvLispindent( linenum )
- endif
- endif
- if synIDattr( synID( pnum, 1, 0), 'name' ) =~ '[Ss]tring' && getline(pnum)[0] != '"'
- " Previous non-blank line is the last line of a multi-line string
- call cursor( pnum, 1 )
- " First find the end of the multi-line string (omit \" characters)
- let [lend, cend] = searchpos( '[^\\]"', 'nW' )
- if lend > 0 && strpart(getline(lend), cend+1) =~ '(\|)\|\[\|\]\|{\|}'
- " Structural change after the string, no special handling
- else
- " Find the start of the multi-line string (omit \" characters)
- let [l, c] = searchpairpos( '"', '', '"', 'bnW', s:skip_q )
- if l > 0 && strpart(getline(l), 0, c-1) =~ '^\s*$'
- " Nothing else before the string: indent to the opening "
- return c - 1
- endif
- if l > 0
- " Pretend that we are really after the first line of the multi-line string
- let pnum = l
- let linenum = l + 1
- endif
- endif
- call cursor( oldpos[1], oldpos[2] )
- endif
-
- " Handle special indentation style for flet, labels, etc.
- " When searching for containing forms, don't go back
- " more than g:slimv_indent_maxlines lines.
- let backline = max([pnum-g:slimv_indent_maxlines, 1])
- let indent_keylists = g:slimv_indent_keylists
-
- " Check if the previous line actually ends with a multi-line subform
- let parent = pnum
- let [l, c] = searchpos( ')', 'bW' )
- if l == pnum
- let [l, c] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
- if l > 0
- " Make sure it is not a top level form and the containing form starts in the same line
- let [l2, c2] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
- if l2 == l
- " Remember the first line of the multi-line form
- let parent = l
- endif
- endif
- endif
-
- " Find beginning of the innermost containing form
- call cursor( oldpos[1], 1 )
- let [l, c] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
- if l > 0
- if SlimvGetFiletype() =~ '.*\(clojure\|scheme\|racket\).*'
- " Is this a clojure form with [] binding list?
- call cursor( oldpos[1], oldpos[2] )
- let [lb, cb] = searchpairpos( '\[', '', '\]', 'bW', s:skip_sc, backline )
- if lb >= l && (lb > l || cb > c)
- return cb
- endif
- endif
- " Is this a form with special indentation?
- let line = strpart( getline(l), c-1 )
- if match( line, '\c^(\s*\('.s:spec_indent.'\)\>' ) >= 0
- " Search for the binding list and jump to its end
- if search( '(' ) > 0
- call searchpair( '(', '', ')', '', s:skip_sc )
- if line('.') == pnum
- " We are indenting the first line after the end of the binding list
- return c + 1
- endif
- endif
- elseif l == pnum
- " If the containing form starts above this line then find the
- " second outer containing form (possible start of the binding list)
- let [l2, c2] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
- if l2 > 0
- let line2 = strpart( getline(l2), c2-1 )
- if match( line2, '\c^(\s*\('.s:spec_param.'\)\>' ) >= 0
- if search( '(' ) > 0
- if line('.') == l && col('.') == c
- " This is the parameter list of a special form
- return c
- endif
- endif
- endif
- if SlimvGetFiletype() !~ '.*clojure.*'
- if l2 == l && match( line2, '\c^(\s*\('.s:binding_form.'\)\>' ) >= 0
- " Is this a lisp form with binding list?
- return c
- endif
- if match( line2, '\c^(\s*cond\>' ) >= 0 && match( line, '\c^(\s*t\>' ) >= 0
- " Is this the 't' case for a 'cond' form?
- return c
- endif
- if match( line2, '\c^(\s*defpackage\>' ) >= 0
- let indent_keylists = 0
- endif
- endif
- " Go one level higher and check if we reached a special form
- let [l3, c3] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
- if l3 > 0
- " Is this a form with special indentation?
- let line3 = strpart( getline(l3), c3-1 )
- if match( line3, '\c^(\s*\('.s:spec_indent.'\)\>' ) >= 0
- " This is the first body-line of a binding
- return c + 1
- endif
- if match( line3, '\c^(\s*defsystem\>' ) >= 0
- let indent_keylists = 0
- endif
- " Finally go to the topmost level to check for some forms with special keyword indenting
- let [l4, c4] = searchpairpos( '(', '', ')', 'brW', s:skip_sc, backline )
- if l4 > 0
- let line4 = strpart( getline(l4), c4-1 )
- if match( line4, '\c^(\s*defsystem\>' ) >= 0
- let indent_keylists = 0
- endif
- endif
- endif
- endif
- endif
- endif
-
- " Restore all cursor movements
- call cursor( oldpos[1], oldpos[2] )
-
- " Check if the current form started in the previous nonblank line
- if l == parent
- " Found opening paren in the previous line
- let line = getline(l)
- let form = strpart( line, c )
- " Determine the length of the function part up to the 1st argument
- let funclen = matchend( form, '\s*\S*\s*' ) + 1
- " Contract strings, remove comments
- let form = substitute( form, '".\{-}[^\\]"', '""', 'g' )
- let form = substitute( form, ';.*$', '', 'g' )
- " Contract subforms by replacing them with a single character
- let f = ''
- while form != f
- let f = form
- let form = substitute( form, '([^()]*)', '0', 'g' )
- let form = substitute( form, '([^()]*$', '0', 'g' )
- let form = substitute( form, '\[[^\[\]]*\]', '0', 'g' )
- let form = substitute( form, '\[[^\[\]]*$', '0', 'g' )
- let form = substitute( form, '{[^{}]*}', '0', 'g' )
- let form = substitute( form, '{[^{}]*$', '0', 'g' )
- endwhile
- " Find out the function name
- let func = matchstr( form, '\<\k*\>' )
- " If it's a keyword, keep the indentation straight
- if indent_keylists && strpart(func, 0, 1) == ':'
- if form =~ '^:\S*\s\+\S'
- " This keyword has an associated value in the same line
- return c
- else
- " The keyword stands alone in its line with no associated value
- return c + 1
- endif
- endif
- if SlimvGetFiletype() =~ '.*clojure.*'
- " Fix clojure specific indentation issues not handled by the default lisp.vim
- if match( func, 'defn$' ) >= 0
- return c + 1
- endif
- else
- if match( func, 'defgeneric$' ) >= 0 || match( func, 'defsystem$' ) >= 0 || match( func, 'aif$' ) >= 0
- return c + 1
- endif
-
- if match( func, 'define-' ) >= 0
- return c + 1
- endif
- endif
- " Remove package specification
- let func = substitute(func, '^.*:', '', '')
- if func != '' && s:swank_connected
- " Look how many arguments are on the same line
- " If an argument is actually a multi-line subform, then replace it with a single character
- let form = substitute( form, "([^()]*$", '0', 'g' )
- let form = substitute( form, "[()\\[\\]{}#'`,]", '', 'g' )
- let args_here = len( split( form ) ) - 1
- " Get swank indent info
- let s:indent = ''
- silent execute 'python get_indent_info("' . func . '")'
- if s:indent != '' && s:indent == args_here
- " The next one is an &body argument, so indent by 2 spaces from the opening '('
- return c + 1
- endif
- let llen = len( line )
- if synIDattr( synID( l, llen, 0), 'name' ) =~ '[Ss]tring' && line[llen-1] != '"'
- " Parent line ends with a multi-line string
- " lispindent() fails to handle it correctly
- if s:indent == '' && args_here > 0
- " No &body argument, ignore lispindent() and indent to the 1st argument
- return c + funclen - 1
- endif
- endif
- endif
- endif
-
- " Use default Lisp indenting
- let li = SlimvLispindent(linenum)
- let line = strpart( getline(linenum-1), li-1 )
- let gap = matchend( line, '^(\s\+\S' )
- if gap >= 0
- " Align to the gap between the opening paren and the first atom
- return li + gap - 2
- endif
- return li
-endfunction
-
-" Convert indent value to spaces or a mix of tabs and spaces
-" depending on the value of 'expandtab'
-function! s:MakeIndent( indent )
- if &expandtab
- return repeat( ' ', a:indent )
- else
- return repeat( "\<Tab>", a:indent / &tabstop ) . repeat( ' ', a:indent % &tabstop )
- endif
-endfunction
-
-
-setlocal nolisp
-setlocal autoindent
-setlocal expandtab
-setlocal indentexpr=SlimvIndent(v:lnum)