summaryrefslogtreecommitdiffstats
path: root/indent/haskell.vim
diff options
context:
space:
mode:
authorAdam Stankiewicz <sheerun@sher.pl>2016-05-02 10:42:37 +0200
committerAdam Stankiewicz <sheerun@sher.pl>2016-05-02 10:42:37 +0200
commit5dd1a7e83966c92d220073185f1738dfe441f59e (patch)
tree9c4bee389a51a9bb111dcc894c9db0f6d1809d81 /indent/haskell.vim
parentbc098370c1bb81840734f5764f431dee270e75ce (diff)
downloadvim-polyglot-5dd1a7e83966c92d220073185f1738dfe441f59e.tar.gz
vim-polyglot-5dd1a7e83966c92d220073185f1738dfe441f59e.zip
Update
Diffstat (limited to 'indent/haskell.vim')
-rw-r--r--indent/haskell.vim402
1 files changed, 328 insertions, 74 deletions
diff --git a/indent/haskell.vim b/indent/haskell.vim
index b69a19c2..b72ee23d 100644
--- a/indent/haskell.vim
+++ b/indent/haskell.vim
@@ -2,8 +2,6 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1
" indentation for haskell
"
-" Based on idris indentation
-"
" author: raichoo (raichoo@googlemail.com)
"
" Modify g:haskell_indent_if and g:haskell_indent_case to
@@ -18,7 +16,7 @@ endif
let b:did_indent = 1
if !exists('g:haskell_indent_if')
- " if bool
+ " if x
" >>>then ...
" >>>else ...
let g:haskell_indent_if = 3
@@ -55,96 +53,130 @@ if !exists('g:haskell_indent_in')
let g:haskell_indent_in = 1
endif
-setlocal indentexpr=GetHaskellIndent()
-setlocal indentkeys=!^F,o,O,0\|,0=where,0=in,0=let,0=deriving,0=->,0=\=>,<CR>,0}
-
-function! GetHaskellIndent()
- let l:prevline = getline(v:lnum - 1)
+if !exists('g:haskell_indent_guard')
+ " f x y
+ " >>|
+ let g:haskell_indent_guard = 2
+endif
- if l:prevline =~ '^\s*--'
- return match(l:prevline, '\S')
- endif
+setlocal indentexpr=GetHaskellIndent()
+setlocal indentkeys=0{,0},0(,0),0[,0],!^F,o,O,0\=,0=where,0=let,0=deriving,0\,,<space>
- if synIDattr(synID(line("."), col("."), 1), "name") == 'haskellBlockComment'
- for l:c in range(v:lnum - 1, 0, -1)
- let l:bline = getline(l:c)
- if l:bline =~ '{-'
- return 1 + match(l:bline, '{-')
- endfor
- return 1
- endif
+function! s:isInBlock(hlstack)
+ return index(a:hlstack, 'haskellParens') > -1 || index(a:hlstack, 'haskellBrackets') > -1 || index(a:hlstack, 'haskellBlock') > -1
+endfunction
- if l:prevline =~ '^\s*$'
- return 0
- endif
+function! s:getNesting(hlstack)
+ return filter(a:hlstack, 'v:val == "haskellBlock" || v:val == "haskellBrackets" || v:val == "haskellParens"')
+endfunction
- let l:line = getline(v:lnum)
+function! s:getHLStack()
+ return map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")')
+endfunction
- if l:line =~ '\C^\s*\<where\>'
- let l:s = match(l:prevline, '\S')
- return l:s + &shiftwidth
- endif
+" indent matching character
+function! s:indentMatching(char)
+ normal! 0
+ call search(a:char, 'cW')
+ normal! %
+ return col('.') - 1
+endfunction
- if l:line =~ '\C^\s*\<deriving\>'
- let l:s = match(l:prevline, '\C\<\(newtype\|data\)\>')
- if l:s >= 0
- return l:s + &shiftwidth
+" backtrack to find guard clause
+function! s:indentGuard(pos, prevline)
+ let l:l = a:prevline
+ let l:c = 1
+
+ while v:lnum != l:c
+ " empty line, stop looking
+ if l:l =~ '^$'
+ return a:pos
+ " guard found
+ elseif l:l =~ '^\s*|\s\+'
+ return match(l:l, '|')
+ " found less deeper indentation (not starting with `,` or `=`)
+ " stop looking
+ else
+ let l:m = match(l:l, '\S')
+ if l:l !~ '^\s*[=,]' && l:m <= a:pos
+ return l:m + g:haskell_indent_guard
+ endif
endif
- endif
+ let l:c += 1
+ let l:l = getline(v:lnum - l:c)
+ endwhile
- if l:line =~ '\C^\s*\<let\>'
- let l:s = match(l:prevline, '\C\<let\>')
- if l:s != 0
- return l:s
- endif
- endif
+ return -1
+endfunction
- if l:line =~ '\C^\s*\<in\>'
- let l:s = match(l:prevline, '\C\<let\>')
- if l:s >= 0
- return l:s + g:haskell_indent_in
- elseif match(l:prevline, '=') > 0
- let l:s = match(l:prevline, '\S')
- return l:s - (4 - g:haskell_indent_in)
- endif
+function! GetHaskellIndent()
+ let l:hlstack = s:getHLStack()
+
+ " do not indent in strings and quasiquotes
+ if index(l:hlstack, 'haskellString') > -1 || index(l:hlstack, 'haskellQuasiQuote') > -1
+ return -1
endif
- if l:line =~ '^\s*|'
- if match(l:prevline, '^\s*data') < 0
- if match(l:prevline, '^\s*|\s') >= 0
- return match(l:prevline, '|')
- else
- return &shiftwidth
+ " blockcomment handling
+ if index(l:hlstack, 'haskellBlockComment') > -1
+ for l:c in range(v:lnum - 1, 0, -1)
+ let l:line = getline(l:c)
+ if l:line =~ '{-'
+ return 1 + match(l:line, '{-')
endif
- endif
+ endfor
+ return 1
endif
- if l:line =~ '^\s*[=-]>'
- let l:s = match(l:prevline, ' :: ')
- if l:s >= 0
- return l:s + 1
- endif
+ let l:prevline = getline(v:lnum - 1)
+ let l:line = getline(v:lnum)
+
+ " reset
+ if l:prevline =~ '^\s*$' && l:line !~ '^\s*\S'
+ return 0
endif
- if l:prevline =~ '\s\+[!#$%&*+./<>?@\\^|~-]\+\s*$'
- let l:s = match(l:prevline, '\S')
- if l:s > 0
- return l:s + &shiftwidth
- endif
+ " comment indentation
+ if l:prevline =~ '^\s*--'
+ return match(l:prevline, '\S')
endif
- if l:prevline =~ '[{([][^})\]]\+$'
- return match(l:prevline, '[{([]')
+ " operator at end of previous line
+ if l:prevline =~ '[!#$%&*+./<>?@\\^|~-]\s*$'
+ return match(l:prevline, '\S') + &shiftwidth
endif
+ " let foo =
+ " >>>>>>bar
if l:prevline =~ '\C\<let\>\s\+[^=]\+=\s*$'
return match(l:prevline, '\C\<let\>') + g:haskell_indent_let + &shiftwidth
endif
- if l:prevline =~ '\C\<let\>\s\+.\+\(\<in\>\)\?\s*$'
+ " let x = 1 in
+ " >>>>x
+ if l:prevline =~ '\C\<let\>\s\+.\+\<in\>\?$' && l:line !~ '\C^\s*\<in\>'
return match(l:prevline, '\C\<let\>') + g:haskell_indent_let
endif
+ " let x = 1
+ " let y = 2
+ "
+ " let x = 1
+ " >in x
+ "
+ " let x = 1
+ " >>>>y = 2
+ if l:prevline =~ '\C\<let\>\s\+.\+$'
+ if l:line =~ '\C^\s*\<let\>'
+ return match(l:prevline, '\C\<let\>')
+ elseif l:line =~ '\C^\s*\<in\>'
+ return match(l:prevline, '\C\<let\>') + g:haskell_indent_in
+ else
+ return match(l:prevline, '\C\<let\>') + g:haskell_indent_let
+ endif
+ endif
+
+ " if handling
if l:prevline !~ '\C\<else\>'
let l:s = match(l:prevline, '\C\<if\>.*\&.*\zs\<then\>')
if l:s > 0
@@ -157,30 +189,252 @@ function! GetHaskellIndent()
endif
endif
- if l:prevline =~ '\C\(\<where\>\|\<do\>\|=\|[{([]\)\s*$'
+ " where
+ " >>foo
+ "
+ " do
+ " >>foo
+ "
+ " foo =
+ " >>bar
+ if l:prevline =~ '\C\(\<where\>\|\<do\>\|=\)\s*$'
return match(l:prevline, '\S') + &shiftwidth
endif
+ "" where foo
+ "" >>>>>>bar
if l:prevline =~ '\C\<where\>\s\+\S\+.*$'
- return match(l:prevline, '\C\<where\>') + g:haskell_indent_where
+ if l:line =~ '^\s*[=-]>\s' && l:prevline =~ ' :: '
+ return match(l:prevline, ':: ')
+ else
+ return match(l:prevline, '\C\<where\>') + g:haskell_indent_where
+ endif
endif
+ " do foo
+ " >>>bar
if l:prevline =~ '\C\<do\>\s\+\S\+.*$'
return match(l:prevline, '\C\<do\>') + g:haskell_indent_do
endif
- if l:prevline =~ '\C^\s*\<data\>\s\+[^=]\+\s\+=\s\+\S\+.*$'
- if l:line =~ '^\s*|'
+ " case foo of
+ " >>bar -> quux
+ if l:prevline =~ '\C\<case\>.\+\<of\>\s*$'
+ return match(l:prevline, '\C\<case\>') + g:haskell_indent_case
+ endif
+
+ " newtype Foo = Foo
+ " >>deriving
+ if l:prevline =~ '\C\s*\<\(newtype\|data\)\>[^{]\+' && l:line =~ '\C^\s*\<deriving\>'
+ return match(l:prevline, '\S') + &shiftwidth
+ endif
+
+ " foo :: Int
+ " >>>>-> Int
+ "
+ " foo
+ " :: Int
+ " foo
+ if l:prevline =~ '\s::\s'
+ if l:line =~ '^\s*[-=]>'
+ return match(l:prevline, '::\s')
+ elseif match(l:prevline, '^\s\+::') > -1
+ return match(l:prevline, '::\s') - &shiftwidth
+ endif
+ endif
+
+ " foo :: Int
+ " -> Int
+ " foo x
+ "
+ " foo
+ " :: Int
+ " -> Int
+ " foo x
+ if l:prevline =~ '^\s*[-=]>' && l:line !~ '^\s*[-=]>'
+ if s:isInBlock(l:hlstack)
+ return match(l:prevline, '[^\s-=>]')
+ else
+ let l:m = matchstr(l:line, '^\s*\zs\<\S\+\>\ze')
+ let l:l = l:prevline
+ let l:c = 1
+
+ while v:lnum != l:c
+ " fun decl
+ let l:s = match(l:l, l:m)
+ if l:s >= 0
+ if match(l:l, '\C^\s*\<default\>') > -1
+ return l:s - 8
+ else
+ return l:s
+ endif
+ " empty line, stop looking
+ elseif l:l =~ '^$'
+ return 0
+ endif
+ let l:c += 1
+ let l:l = getline(v:lnum - l:c)
+ endwhile
+
+ return 0
+ endif
+ endif
+
+ " | otherwise = ...
+ " foo
+ "
+ " | foo
+ " >>, bar
+ "
+ " | foo
+ " >>= bar
+ "
+ " | Foo
+ " >>deriving
+ if l:prevline =~ '^\s\+|' && !s:isInBlock(l:hlstack)
+ if l:line =~ '\s*[,=]'
+ return match(l:prevline, '|')
+ elseif l:line =~ '\C^\s*\<deriving\>'
+ return match(l:prevline, '|')
+ elseif l:line !~ '^\s*|'
+ return match(l:prevline, '|') - g:haskell_indent_guard
+ endif
+ endif
+
+ " foo :: ( Monad m
+ " , Functor f
+ " )
+ ">>>>>=> Int
+ if l:prevline =~ '^\s*)' && l:line =~ '^\s*=>'
+ let l:s = match(l:prevline, ')')
+ return l:s - (&shiftwidth + 1)
+ endif
+
+ " module Foo
+ " >>( bar
+ if l:prevline =~ '\C^\<module\>'
+ return &shiftwidth
+ endif
+
+ " foo
+ " >>{
+ if l:line =~ '^\s*{' && l:prevline !~ '^{'
+ return match(l:prevline, '\S') + &shiftwidth
+ endif
+
+ " in foo
+ " where bar
+ if l:line =~ '\C^\s*\<where\>'
+ if match(l:prevline, '\C^\s\+in\s\+') == 0
+ return match(l:prevline, 'in') - g:haskell_indent_in
+ endif
+
+ return match(l:prevline, '\S') + &shiftwidth
+ endif
+
+ " let x = 1
+ " y = 2
+ " >in x + 1
+ if l:line =~ '\C^\s*\<in\>'
+ return match(l:prevline, '\S') - (4 - g:haskell_indent_in)
+ endif
+
+ " data Foo
+ " >>= Bar
+ "
+ " |
+ " ...
+ " >>=
+ "
+ " foo
+ " >>=
+ if l:line =~ '^\s*='
+ if l:prevline =~ '\C^\<data\>\s\+[^=]\+\s*$'
+ return match(l:prevline, '\C\<data\>') + &shiftwidth
+ else
+ let l:s = s:indentGuard(match(l:line, '='), l:prevline)
+ if l:s > 0
+ return l:s
+ else
+ return &shiftwidth
+ endif
+ endif
+ endif
+
+ " { foo :: Int
+ " >>,
+ "
+ " |
+ " ...
+ " >>,
+ if l:line =~ '^\s*,'
+ if s:isInBlock(l:hlstack)
+ normal! 0
+ call search(',', 'cW')
+ let l:n = s:getNesting(s:getHLStack())
+ call search('[(\[{]', 'bW')
+
+ while l:n != s:getNesting(s:getHLStack())
+ call search('[(\[{]', 'bW')
+ endwhile
+
+ return col('.') - 1
+ else
+ let l:s = s:indentGuard(match(l:line, ','), l:prevline)
+ if l:s > -1
+ return l:s
+ end
+ endif
+ endif
+
+ " |
+ " ...
+ " >>|
+ "
+ " data Foo = Bar
+ " >>>>>>>>>|
+ if l:line =~ '^\s*|\s'
+ if l:prevline =~ '\C^\s*\<data\>.\+=.\+$'
return match(l:prevline, '=')
+ else
+ let l:s = s:indentGuard(match(l:line, '|'), l:prevline)
+ if l:s > -1
+ return l:s
+ endif
endif
endif
- if l:prevline =~ '\C\<case\>\s\+.\+\<of\>\s*$'
- return match(l:prevline, '\C\<case\>') + g:haskell_indent_case
+ " foo
+ " >>:: Int
+ if l:line =~ '^\s*::\s'
+ return match(l:prevline, '\S') + &shiftwidth
+ endif
+
+ " indent closing brace, paren or bracket
+ if l:line =~ '^\s*}'
+ return s:indentMatching('}')
+ endif
+
+ if l:line =~ '^\s*)'
+ return s:indentMatching(')')
+ endif
+
+ if l:line =~ '^\s*]'
+ return s:indentMatching(']')
+ endif
+ "
+ " indent import
+ if l:line =~ '\C^\s*import'
+ return 0
+ endif
+
+ " do not reindent indented lines
+ if match(l:prevline, '\S') < match(l:line, '\S')
+ return -1
endif
- if l:prevline =~ '\C^\s*\<\data\>\s\+\S\+\s*$'
- return match(l:prevline, '\C\<data\>') + &shiftwidth
+ if l:line !~ '^\s*[=-]>\s' && l:line =~ '^\s*[!#$%&*+./<>?@\\^|~-]\+'
+ return -1
endif
return match(l:prevline, '\S')