diff options
| author | Adam Stankiewicz <sheerun@sher.pl> | 2015-07-18 23:22:55 +0200 | 
|---|---|---|
| committer | Adam Stankiewicz <sheerun@sher.pl> | 2015-07-18 23:22:55 +0200 | 
| commit | cf1e53bc39c96b9f5586a68efa118a13c615da13 (patch) | |
| tree | eb6c96a71098df7fc2a38df4606f32a3bfcc925e /indent | |
| parent | 92ab75408df8bff49bb29e113b3cc159d1ac3105 (diff) | |
| download | vim-polyglot-cf1e53bc39c96b9f5586a68efa118a13c615da13.tar.gz vim-polyglot-cf1e53bc39c96b9f5586a68efa118a13c615da13.zip | |
Changed haskell provider to raichoo/haskell-vim, closes #63
Diffstat (limited to 'indent')
| -rw-r--r-- | indent/cabal.vim | 35 | ||||
| -rw-r--r-- | indent/haskell.vim | 348 | 
2 files changed, 149 insertions, 234 deletions
| diff --git a/indent/cabal.vim b/indent/cabal.vim new file mode 100644 index 00000000..b2089a5e --- /dev/null +++ b/indent/cabal.vim @@ -0,0 +1,35 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1 +   +" indentation for cabal +" +" author: raichoo (raichoo@googlemail.com) +" +if exists('b:did_indent') +  finish +endif + +let b:did_indent = 1 + +if !exists('g:cabal_indent_section') +  "executable name +  ">>main-is:           Main.hs +  ">>hs-source-dirs:    src +  let g:cabal_indent_section = 2 +elseif exists('g:cabal_indent_section') && g:cabal_indent_section > 4 +  let g:cabal_indent_section = 4 +endif + +setlocal indentexpr=GetCabalIndent() +setlocal indentkeys=!^F,o,O,<CR> + +function! GetCabalIndent() +  let l:prevline = getline(v:lnum - 1) + +  if l:prevline =~ '\C^\(executable\|library\|flag\|source-repository\|test-suite\|benchmark\)' +    return g:cabal_indent_section +  else +    return match(l:prevline, '\S') +  endif +endfunction + +endif diff --git a/indent/haskell.vim b/indent/haskell.vim index 6a16e735..8af1aedd 100644 --- a/indent/haskell.vim +++ b/indent/haskell.vim @@ -1,8 +1,15 @@  if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1 -" Vim indent file -" Language: Haskell -" Maintainer: Tristan Ravitch +" indentation for haskell +" +" Based on idris indentation +" +" author: raichoo (raichoo@googlemail.com) +" +" Modify g:haskell_indent_if and g:haskell_indent_case to +" change indentation for `if'(default 3) and `case'(default 5). +" Example (in .vimrc): +" > let g:haskell_indent_if = 2  if exists('b:did_indent')    finish @@ -10,291 +17,164 @@ endif  let b:did_indent = 1 -if !exists('g:hasksyn_indent_search_backward') -  let g:hasksyn_indent_search_backward = 100 +if !exists('g:haskell_indent_if') +  " if bool +  " >>>then ... +  " >>>else ... +  let g:haskell_indent_if = 3  endif -if !exists('g:hasksyn_dedent_after_return') -  let g:hasksyn_dedent_after_return = 1 +if !exists('g:haskell_indent_case') +  " case xs of +  " >>[]     -> ... +  " >>(y:ys) -> ... +  let g:haskell_indent_case = 2  endif -if !exists('g:hasksyn_dedent_after_catchall_case') -  let g:hasksyn_dedent_after_catchall_case = 1 +if !exists('g:haskell_indent_let') +  " let x = 0 in +  " >>>>x +  let g:haskell_indent_let = 4  endif -setlocal noautoindent -setlocal indentexpr=HIndent(v:lnum) -setlocal indentkeys+=0=where -setlocal indentkeys+=0=-> -setlocal indentkeys+=0==> -setlocal indentkeys+=0=in -setlocal indentkeys+=0=class,0=instance,0=import -setlocal indentkeys+=<Bar> -setlocal indentkeys+=0\, - -if exists("*HIndent") -  finish +if !exists('g:haskell_indent_where') +  " where f :: Int -> Int +  " >>>>>>f x = x +  let g:haskell_indent_where = 6  endif +if !exists('g:haskell_indent_do') +  " do x <- a +  " >>>y <- b +  let g:haskell_indent_do = 3 +endif -function! HIndent(lnum) -  " Don't do anything boneheaded if we are inside of a block comment -  if s:IsInBlockComment() -    return -1 -  endif +if !exists('g:haskell_indent_in') +  " let x = 1 +  " >in x +  let g:haskell_indent_in = 1 +endif -  let plnum = s:PrevNonCommentLineNum(a:lnum) -  if plnum == 0 -    return 0 -  endif +setlocal indentexpr=GetHaskellIndent() +setlocal indentkeys=!^F,o,O,0\|,0=where,0=in,0=let,0=deriving,0=->,0=\=>,<CR>,0} -  let prevl = s:GetAndStripTrailingComments(plnum) -  let thisl = s:GetAndStripTrailingComments(a:lnum) -  let previ = indent(plnum) - -  " If this is a bare where clause, indent it one step.  where as part of an -  " instance should be unaffected unless you put it in an odd place. -  " This is the wrong thing if you are deeply indented already and want to put -  " a where clause on the top-level construct, but there isn't much that can -  " be done about that case... -  if thisl =~ '^\s*where\s*' -    return previ + &sw -  endif +function! GetHaskellIndent() +  let l:prevline = getline(v:lnum - 1) -  " If we start a new line for a type signature, see if we can line it up with -  " the previous line. -  if thisl =~ '^\s*\(->\|=>\)\s*' -    let tokPos = s:BackwardPatternSearch(a:lnum, '\(::\|->\|=>\)') -    if tokPos != -1 -      return tokPos -    endif +  if l:prevline =~ '^\s*--' +    return match(l:prevline, '\S')    endif -  if prevl =~ '\Wof\s*$' || prevl =~ '\Wm\=do\s*$' -    return previ + &sw +  if l:prevline =~ '^\s*$' +      return 0    endif -  " Now for commas.  Commas will align pretty naturally for simple pattern -  " guards, so don't worry about that for now.  If we see the line is just a -  " comma, search up for something to align it to.  In the easy case, look -  " for a [ or { (the last in their line).  Also consider other commas that -  " are preceeded only by whitespace.  This isn't just a previous line check -  " necessarily, though that would cover most cases. -  if thisl =~ '^\s*,' -    let cmatch = match(prevl, '\(^\s*\)\@<=,') -    if cmatch != -1 -      return cmatch -    endif +  let l:line = getline(v:lnum) -    let bmatch = match(prevl, '\({\|\[\)') -    if bmatch != -1 -      return bmatch -    endif +  if l:line =~ '\C^\s*\<where\>' +    let l:s = match(l:prevline, '\S') +    return l:s + &shiftwidth    endif -  " Match an 'in' keyword with the corresponding let.  Unfortunately, if the -  " name of your next binding happens to start with 'in', this will muck with -  " it.  Not sure if there is a workaround because we can't force an -  " auto-indent after 'in ' as far as I can see. -  if thisl =~ '\s*in$' -    let letStart = s:BackwardPatternSearch(a:lnum, '\(\W\)\@<=let\W') -    if letStart != -1 -      return letStart +  if l:line =~ '\C^\s*\<deriving\>' +    let l:s = match(l:prevline, '\C\<\(newtype\|data\)\>') +    if l:s >= 0 +      return l:s + &shiftwidth      endif    endif -  " We don't send data or type to column zero because they can be indented -  " inside of 'class' definitions for data/type families -  if thisl =~ '^\s*\(class\|instance\|newtype\|import\)' -    return 0 -  endif - -  " FIXME: Only do this if the previous line was not already indented for the -  " same reason.  Also be careful of -> in type signatures.  Make sure we have -  " an earlier rule to line those up properly. -  if prevl =~ '[=>\$\.\^+\&`(-]\s*$' -    return previ + &sw +  if l:line =~ '\C^\s*\<let\>' +    let l:s = match(l:prevline, '\C\<let\>') +    if l:s != 0 +      return l:s +    endif    endif -  " We have a special case for dealing with trailing '*' operators.  If the * -  " is the end of a kind signature in a type family/associated type, we don't -  " want to indent the next line.  We do if it is just being a * operator in -  " an expression, though. -  if prevl =~ '\(\(type\|data\).*\)\@<!\*\s*$' -    return previ + &sw +  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    endif -  " If the previous line ends in a where, indent us a step -  if prevl =~ '\Wwhere\s*$' -    return previ + &sw +  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 +      endif +    endif    endif -  " If we see a |, first try to line it up with the pipe on the previous line. -  " Search backward on nearby lines, giving up if we hit a line with a \w at -  " column 0. Otherwise, indent it relative to the previous line -  " -  " Here we can also handle the case of lining up data declarations.  The -  " backwards pipe search will fail for a data declaration (since data is at -  " column 0), so we can have an extra check after the pipe search for -  " data..=. -  if thisl =~ '^\s*|$' -    let nearestPipeIndex = s:BackwardPatternSearch(a:lnum, '\(^\s*\)\@<=|') -    if nearestPipeIndex != -1 -      return nearestPipeIndex +  if l:line =~ '^\s*[=-]>' +    let l:s = match(l:prevline, ' :: ') +    if l:s >= 0 +      return l:s + 1      endif +  endif -    let dataEquals = match(prevl, '\(data.*\)\@<==') -    if dataEquals != -1 -      return dataEquals +  if l:prevline =~ '\s\+[!#$%&*+./<>?@\\^|~-]\+\s*$' +    let l:s = match(l:prevline, '\S') +    if l:s > 0 +      return l:s + &shiftwidth      endif - -    return previ + &sw    endif -  " If the previous line has a let, line the cursor up with the start of the -  " first binding name.  Autoindent handles subsequent cases. -  " -  " This should come after the 'in' aligner so that 'in' is not treated as -  " just something to be aligned to the previous binding. -  let lbindStart = match(prevl, '\(\Wlet\s\+\)\@<=\w') -  if lbindStart != -1 -    return lbindStart +  if l:prevline =~ '[{([][^})\]]\+$' +    return match(l:prevline, '[{([]')    endif -  " If requested, dedent from a bare return (presumably in a do block). -  " This comes after the trailing operator case - hopefully that will avoid -  " returns on lines by themselves but not really in a do block.  This is a -  " heuristic. -  if g:hasksyn_dedent_after_return && prevl =~ '^\s*return\W' -    return previ - &sw +  if l:prevline =~ '\C\<let\>\s\+[^=]\+=\s*$' +    return match(l:prevline, '\C\<let\>') + g:haskell_indent_let + &shiftwidth    endif -  " Similar to the return dedent - after a catchall case _ -> ..., we can -  " almost certainly dedent.  Again, it comes after the line continuation -  " heuristic so we don't dedent while someone is making an obviously -  " multi-line construct -  if g:hasksyn_dedent_after_catchall_case && prevl =~ '^\s*_\s*->\W' -    return previ - &sw +  if l:prevline =~ '\C\<let\>\s\+.\+\(\<in\>\)\?\s*$' +    return match(l:prevline, '\C\<let\>') + g:haskell_indent_let    endif -  " On the other hand, if the previous line is a do or where with some bindings -  " following it on the same line, accommodate and align with the first non-ws -  " char after the where -  if prevl =~ '\W\(do\|where\)\s\+\w' -    let bindStart = match(prevl, '\(\W\(do\|where\)\s\+\)\@<=\w') -    if bindStart != -1 -      return bindStart +  if l:prevline !~ '\C\<else\>' +    let l:s = match(l:prevline, '\C\<if\>.*\&.*\zs\<then\>') +    if l:s > 0 +      return l:s      endif -    return previ + &sw +    let l:s = match(l:prevline, '\C\<if\>') +    if l:s > 0 +      return l:s + g:haskell_indent_if +    endif    endif -  return previ -endfunction - -" Search backwards for a token from the cursor position -function! s:FindTokenNotInCommentOrString(tok) -  return search('\(--.*\|"\([^"]\|\\"\)*\)\@<!' . tok, 'bcnW') -endfunction - -" Should return -1 if the given line is inside of an unclosed block comment. -" This is meant to let us exit early from the indenter if we are in a comment. -" Look for the nearest -} and {- such that they are not between "" or in a -" line comment -" -" Note: we may need to restrict how far back this will search.  On the other -" hand, the native vim 'search' function might be efficient enough to support -" entire buffers. -function! s:IsInBlockComment() -  let openCommPos = s:FindTokenNotInCommentOrString('{-') -  " If there is no open comment, then we don't have to look for a close -  if openCommPos == 0 -    return 0 +  if l:prevline =~ '\C\(\<where\>\|\<do\>\|=\|[{([]\)\s*$' +    return match(l:prevline, '\S') + &shiftwidth    endif -  " Or if there is a close comment marker that comes after the open marker, we -  " are not in a comment.  Note that we potentially need to check the position -  " in the line if they are both on the same line.  I'll fix it later. -  let closeCommPos = s:FindTokenNotInCommentOrString('-}') -  if closeCommPos >= openCommPos -    return 0 +  if l:prevline =~ '\C\<where\>\s\+\S\+.*$' +    return match(l:prevline, '\C\<where\>') + g:haskell_indent_where    endif -  return 1 -endfunction - -" Get the previous line that is not a comment.  Pass in the *current* line -" number.  Also skips blank lines. -function! s:PrevNonCommentLineNum(lnum) -  if a:lnum <= 1 -    return 0 +  if l:prevline =~ '\C\<do\>\s\+\S\+.*$' +    return match(l:prevline, '\C\<do\>') + g:haskell_indent_do    endif -  let lnum = a:lnum - 1 - -  while 1 -    if lnum == 0 -      return 0 +  if l:prevline =~ '\C^\s*\<data\>\s\+[^=]\+\s\+=\s\+\S\+.*$' +    if l:line =~ '^\s*|' +      return match(l:prevline, '=')      endif - -    let aline = getline(lnum) -    if aline =~ '^\s*--' -      let lnum = lnum - 1 -    else -      return lnum -    endif -  endwhile -endfunction - -function! s:GetAndStripTrailingComments(lnum) -  let aline = getline(a:lnum) -  " We can't just remove the string literal since that leaves us with a -  " trailing operator (=), so replace it with a fake identifier -  let noStrings = substitute(aline, '"\([^"]\|\\"\)*"', '\=repeat("s", len(submatch(0)))', '') -  let noLineCom = substitute(noStrings, '--.*$', '', '') - -  " If there are no fancy block comments involved, skip some of this extra -  " work -  if noLineCom !~ '\({-\|-}\)' -    return noLineCom    endif -  " We stripped line comments, now we need to strip out any relevant multiline -  " comments.  This includes comments starting much earlier but ending on this -  " line or comments starting on this line and continuing to the next.  This -  " is probably easiest in two steps: {- to (-}|$) and then ^ to -}. -  " Note we are using a non-greedy match here so that only the minimal {- -} -  " pair is consumed. -  let noBlock1 = substitute(noLineComm, '{-.\{-}-}', '', '') -  let noBlock2 = substitute(noBlock1, '{-.\{-}$', '', '') -  let noBlock3 = substitute(noBlock2, '^.\{-}-}', '', '') -  return noBlock3 -endfunction +  if l:prevline =~ '\C\<case\>\s\+.\+\<of\>\s*$' +    return match(l:prevline, '\C\<case\>') + g:haskell_indent_case +  endif -" Search backwards from lnum for pat, returning the starting index if found -" within the search range or -1 if not found.  Stops searching at lines -" starting at column 0 with an identifier character. -function! s:BackwardPatternSearch(lnum, pat) -  let lnum = s:PrevNonCommentLineNum(a:lnum) -  while 1 -    let aline = s:GetAndStripTrailingComments(lnum) -    if a:lnum - lnum > g:hasksyn_indent_search_backward -      return -1 -    endif +  if l:prevline =~ '\C^\s*\<\data\>\s\+\S\+\s*$' +    return match(l:prevline, '\C\<data\>') + &shiftwidth +  endif -    let theMatch = match(aline, a:pat) -    if theMatch != -1 -      return theMatch -    else -      " We want to be able to consider lines starting in column 0, but we don't -      " want to search back past them. -      if aline =~ '^\w' -        return -1 -      endif -      let lnum = s:PrevNonCommentLineNum(lnum) -    endif -  endwhile +  return match(l:prevline, '\S')  endfunction -  endif | 
