diff options
Diffstat (limited to 'indent/purescript.vim')
-rw-r--r-- | indent/purescript.vim | 203 |
1 files changed, 171 insertions, 32 deletions
diff --git a/indent/purescript.vim b/indent/purescript.vim index c456c608..c22da095 100644 --- a/indent/purescript.vim +++ b/indent/purescript.vim @@ -37,9 +37,16 @@ if !exists('g:purescript_indent_let') let g:purescript_indent_let = 4 endif +if !exists('g:purescript_indent_in') + " let x = 0 + " >in + let g:purescript_indent_in = 1 +endif + if !exists('g:purescript_indent_where') - " where f :: Int -> Int - " >>>>>>f x = x + " where + " >>f :: Int -> Int + " >>f x = x let g:purescript_indent_where = 6 endif @@ -49,16 +56,29 @@ if !exists('g:purescript_indent_do') let g:purescript_indent_do = 3 endif +if !exists('g:purescript_indent_dot') + " f + " :: forall a + " >. String + " -> String + let g:purescript_indent_dot = 1 +endif + setlocal indentexpr=GetPurescriptIndent() -setlocal indentkeys=!^F,o,O,},=where,=in +setlocal indentkeys=!^F,o,O,},=where,=in,=::,=->,=→,==>,=⇒ + +function! s:GetSynStack(lnum, col) + return map(synstack(a:lnum, a:col), { key, val -> synIDattr(val, "name") }) +endfunction function! GetPurescriptIndent() + let ppline = getline(v:lnum - 2) let prevline = getline(v:lnum - 1) let line = getline(v:lnum) if line =~ '^\s*\<where\>' - let s = match(prevline, '\S') - return s + 2 + let s = indent(v:lnum - 1) + return max([s, &l:shiftwidth]) endif if line =~ '^\s*\<in\>' @@ -67,72 +87,191 @@ function! GetPurescriptIndent() while s <= 0 && n > 0 let n = n - 1 - let s = match(getline(n),'\<let\>') + let s = match(getline(n), '\<let\>') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') != -1 + let s = -1 + endif endwhile - return s + 1 + return s + g:purescript_indent_in + endif + + let s = match(prevline, '^\s*\zs\(--\|import\)') + if s >= 0 + " comments + " imports + return s + endif + + if prevline =~ '^\S.*::' && line !~ '^\s*\(\.\|->\|→\|=>\|⇒\)' && !~ '^instance' + " f :: String + " -> String + return 0 + endif + + let s = match(prevline, '[[:alnum:][:blank:]]\@<=|[[:alnum:][:blank:]$]') + if s >= 0 && prevline !~ '^class\>' && index(s:GetSynStack(v:lnum - 1, s), "purescriptFunctionDecl") == -1 + " ident pattern guards but not if we are in a type declaration + " what we detect using syntax groups + if prevline =~ '|\s*otherwise\>' + return indent(search('^\s*\k', 'bnW')) + " somehow this pattern does not work :/ + " return indent(search('^\(\s*|\)\@!', 'bnW')) + else + return s + endif + endif + + let s = match(line, '\%(\\.\{-}\)\@<=->') + if s >= 0 + " inline lambda + return indent(v:lnum) + endif + + " indent rules for -> (lambdas and case expressions) + let s = match(line, '->') + let p = match(prevline, '\\') + " protect that we are not in a type signature + " and not in a case expression + if s >= 0 && index(s:GetSynStack(s == 0 ? v:lnum - 1 : v:lnum, max([1, s])), "purescriptFunctionDecl") == -1 + \ && p >= 0 && index(s:GetSynStack(v:lnum - 1, p), "purescriptString") == -1 + return p + endif + + if prevline =~ '^\S' + " start typing signature, function body, data & newtype on next line + return &l:shiftwidth endif - if prevline =~ '[!#$%&*+./<>?@\\^|~-]\s*$' + if ppline =~ '^\S' && prevline =~ '^\s*$' + return 0 + endif + + if line =~ '^\s*\%(::\|∷\)' + return match(prevline, '\S') + &l:shiftwidth + endif + + if prevline =~ '^\s*\(::\|∷\)\s*forall' + return match(prevline, '\S') + g:purescript_indent_dot + endif + + let s = match(prevline, '^\s*\zs\%(::\|∷\|=>\|⇒\|->\|→\)') + let r = match(prevline, '^\s*\zs\.') + if s >= 0 || r >= 0 + if s >= 0 + if line !~ '^\s*\%(::\|∷\|=>\|⇒\|->\|→\)' && line !~ '^\s*$' + return s - 2 + else + return s + endif + elseif r >= 0 + if line !~ '^\s\%(::\|∷\|=>\|⇒\|->\|→\)' + return r - g:purescript_indent_dot + else + return r + endif + endif + endif + + if prevline =~ '[!#$%&*+./<>?@\\^~-]\s*$' let s = match(prevline, '=') if s > 0 - return s + 2 + return s + &l:shiftwidth endif - let s = match(prevline, ':') + let s = match(prevline, '\<:\>') if s > 0 - return s + 3 + return s + &l:shiftwidth else - return match(prevline, '\S') + return match(prevline, '\S') + &l:shiftwidth endif endif if prevline =~ '[{([][^})\]]\+$' + echom "return 1" return match(prevline, '[{([]') endif - if prevline =~ '\<let\>\s\+.\+\(\<in\>\)\?\s*$' + let s = match(prevline, '\<let\>\s\+\zs\S') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 + return s + endif + + let s = match(prevline, '\<let\>\s*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 + return s + g:purescript_indent_let + endif + + let s = match(prevline, '\<let\>\s\+.\+\(\<in\>\)\?\s*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 return match(prevline, '\<let\>') + g:purescript_indent_let endif - if prevline !~ '\<else\>' - let s = match(prevline, '\<if\>.*\&.*\zs\<then\>') - if s > 0 - return s + let s = searchpairpos('\%(--.\{-}\)\@<!\<if\>', '\<then\>', '\<else\>.*\zs$', 'bnrc')[0] + if s > 0 + " this rule ensures that using `=` in visual mode will correctly indent + " `if then else`, but it does not handle lines after `then` and `else` + if line =~ '\<\%(then\|else\)\>' + return match(getline(s), '\<if\>') + &l:shiftwidth endif + endif - let s = match(prevline, '\<if\>') - if s > 0 - return s + g:purescript_indent_if - endif + let p = match(prevline, '\<if\>\%(.\{-}\<then\>.\{-}\<else\>\)\@!') + if p > 0 + return p + &l:shiftwidth + endif + + let s = match(prevline, '=\s*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 + return match(prevline, '\S') + &l:shiftwidth + endif + + let s = match(prevline, '[{([]\s*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 + return match(prevline, '\S') + (line !~ '^\s*[})]]' ? 0 : &l:shiftwidth) + endif + + if prevline =~ '^class' + return &l:shiftwidth + endif + + let s = match(prevline, '\<where\>\s*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 + return match(prevline, '\S') + g:purescript_indent_where endif - if prevline =~ '\(\<where\>\|\<do\>\|=\|[{([]\)\s*$' - return match(prevline, '\S') + &shiftwidth + let s = match(prevline, '\<where\>\s\+\zs\S\+.*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 + return s endif - if prevline =~ '\<where\>\s\+\S\+.*$' - return match(prevline, '\<where\>') + g:purescript_indent_where + let s = match(prevline, '\<do\>\s*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 + return match(prevline, '\S') + g:purescript_indent_do endif - if prevline =~ '\<do\>\s\+\S\+.*$' - return match(prevline, '\<do\>') + g:purescript_indent_do + let s = match(prevline, '\<do\>\s\+\zs\S\+.*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 + return s endif - if prevline =~ '^\s*\<data\>\s\+[^=]\+\s\+=\s\+\S\+.*$' + let s = match(prevline, '^\s*\<data\>\s\+[^=]\+\s\+=\s\+\S\+.*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 return match(prevline, '=') endif - if prevline =~ '\<case\>\s\+.\+\<of\>\s*$' + let s = match(prevline, '\<case\>\s\+.\+\<of\>\s*$') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 return match(prevline, '\<case\>') + g:purescript_indent_case endif if prevline =~ '^\s*\<\data\>\s\+\S\+\s*$' - return match(prevline, '\<data\>') + &shiftwidth + return match(prevline, '\<data\>') + &l:shiftwidth endif - if (line =~ '^\s*}\s*' && prevline !~ '^\s*;') - return match(prevline, '\S') - &shiftwidth + let s = match(prevline, '^\s*[}\]]') + if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 + return match(prevline, '\S') - &l:shiftwidth endif return match(prevline, '\S') |