From 35433aa23c6f7753fe96c67ed2ffdbb5291085a0 Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Thu, 12 Sep 2013 17:17:14 +0200 Subject: [PATCH] vim-haskell -> hasksyn --- after/ftplugin/haskell.vim | 9 + build.sh | 2 +- ftdetect/haskell.vim | 2 - ftplugin/haskell.vim | 13 -- indent/haskell.vim | 325 ++++++++++++++++++++++----- syntax/cabal.vim | 147 +++++++++++++ syntax/haskell.vim | 437 ++++++++++--------------------------- 7 files changed, 544 insertions(+), 391 deletions(-) create mode 100644 after/ftplugin/haskell.vim delete mode 100644 ftdetect/haskell.vim delete mode 100644 ftplugin/haskell.vim create mode 100644 syntax/cabal.vim diff --git a/after/ftplugin/haskell.vim b/after/ftplugin/haskell.vim new file mode 100644 index 0000000..536e84b --- /dev/null +++ b/after/ftplugin/haskell.vim @@ -0,0 +1,9 @@ +" Vim ftplugin file +" Language: Haskell +" Maintainer: Tristan Ravitch + +" I don't fully understand what the vim-default ftplugin does, but I do know +" that the three-part comment entry really messes up this indenter (I also +" hate the leading '-'s it puts in on each line). Disable it here. +setlocal comments& +setlocal comments=:-- diff --git a/build.sh b/build.sh index 4ad42e0..bbc57c3 100755 --- a/build.sh +++ b/build.sh @@ -49,7 +49,6 @@ syntax 'groenewege/vim-less' & syntax 'wavded/vim-stylus' & syntax 'tpope/vim-cucumber' & syntax 'jrk/vim-ocaml' & -syntax 'wlangstroth/vim-haskell' & syntax 'slim-template/vim-slim' & syntax 'vim-scripts/XSLT-syntax' & syntax 'vim-scripts/python.vim--Vasiliev' & @@ -59,6 +58,7 @@ syntax 'spf13/PIV' & syntax 'briancollins/vim-jst' & syntax 'derekwyatt/vim-scala' & syntax 'derekwyatt/vim-sbt' & +syntax 'travitch/hasksyn' & wait diff --git a/ftdetect/haskell.vim b/ftdetect/haskell.vim deleted file mode 100644 index 1f51141..0000000 --- a/ftdetect/haskell.vim +++ /dev/null @@ -1,2 +0,0 @@ -" autocommand -au BufRead,BufNewFile *.hs set comments=sl:{-,mb:--,elx:-} diff --git a/ftplugin/haskell.vim b/ftplugin/haskell.vim deleted file mode 100644 index 9025b0e..0000000 --- a/ftplugin/haskell.vim +++ /dev/null @@ -1,13 +0,0 @@ -" -" general Haskell source settings -" (shared functions are in autoload/haskellmode.vim) -" -" (Claus Reinke, last modified: 28/04/2009) -" -" part of haskell plugins: http://projects.haskell.org/haskellmode-vim -" please send patches to - -" try gf on import line, or ctrl-x ctrl-i, or [I, [i, .. -setlocal include=^import\\s*\\(qualified\\)\\?\\s* -setlocal includeexpr=substitute(v:fname,'\\.','/','g').'.' -setlocal suffixesadd=hs,lhs,hsc \ No newline at end of file diff --git a/indent/haskell.vim b/indent/haskell.vim index 4e6a1ef..c584e94 100644 --- a/indent/haskell.vim +++ b/indent/haskell.vim @@ -1,85 +1,296 @@ " Vim indent file -" Language: Haskell -" Author: motemen -" Version: 0.1 -" Last Change: 2007-07-25 -" -" 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 +" Language: Haskell +" Maintainer: Tristan Ravitch if exists('b:did_indent') - finish + finish endif let b:did_indent = 1 -if !exists('g:haskell_indent_if') - " if bool - " >>>then ... - " >>>else ... - let g:haskell_indent_if = 2 +if !exists('g:hasksyn_indent_search_backward') + let g:hasksyn_indent_search_backward = 100 endif -if !exists('g:haskell_indent_case') - " case xs of - " >>>>>[] -> ... - " >>>>>(y:ys) -> ... - let g:haskell_indent_case = 2 +if !exists('g:hasksyn_dedent_after_return') + let g:hasksyn_dedent_after_return = 1 endif -setlocal indentexpr=GetHaskellIndent() -setlocal indentkeys=!^F,o,O +if !exists('g:hasksyn_dedent_after_catchall_case') + let g:hasksyn_dedent_after_catchall_case = 1 +endif -function! GetHaskellIndent() - let line = substitute(getline(getpos('.')[1] - 1), '\t', repeat(' ', &tabstop), 'g') +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+= +setlocal indentkeys+=0\, - if line =~ '[!#$%&*+./<=>?@\\^|~-]$\|\\|=>\)\s*' + let tokPos = s:BackwardPatternSearch(a:lnum, '\(::\|->\|=>\)') + if tokPos != -1 + return tokPos + endif + endif + + if prevl =~ '\Wof\s*$' || prevl =~ '\Wdo\s*$' + return previ + &sw + 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 - if line =~ '{$' - return match(line, '\s*where \zs\|\S') + &shiftwidth + let bmatch = match(prevl, '\({\|\[\)') + if bmatch != -1 + return bmatch + endif + 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 + 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 + 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\).*\)\@ ..., 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 + endif + + " On the other hand, if the previous line is a where with some bindings + " following it on the same line, accommodate and align with the first non-ws + " char after the where + if prevl =~ '\Wwhere\s\+\w' + let bindStart = match(prevl, '\(\Wwhere\s\+\)\@<=\w') + if bindStart != -1 + return bindStart endif - if line !~ '\' - let s = match(line, '\.*\&.*\zs\') - if s > 0 - return s - endif + return previ + &sw + endif - let s = match(line, '\') - if s > 0 - return s + g:haskell_indent_if - endif + return previ +endfunction + +" Search backwards for a token from the cursor position +function! s:FindTokenNotInCommentOrString(tok) + return search('\(--.*\|"\([^"]\|\\"\)*\)\@= openCommPos + return 0 + 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 + endif + + let lnum = a:lnum - 1 + + while 1 + if lnum == 0 + return 0 endif - let s = match(line, '\ 0 - return s + 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, '"\([^"]\|\\"\)*"', 's', '') + 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 + +" 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 - let s = match(line, '\') - if s > 0 - return s + g:haskell_indent_case + 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 +endfunction - return match(line, '\S') -endfunction \ No newline at end of file diff --git a/syntax/cabal.vim b/syntax/cabal.vim new file mode 100644 index 0000000..d051009 --- /dev/null +++ b/syntax/cabal.vim @@ -0,0 +1,147 @@ +" Vim syntax file +" Language: Cabal +" Author: Tristan Ravitch +" Version: 0.0.1 + +if version < 600 + syntax clear +elseif exists('b:current_syntax') + finish +endif + +syn sync minlines=50 maxlines=200 +syn case ignore + +" Top-level package keywords +syn match cabalKey '^name:' +syn match cabalKey '^version:' +syn match cabalKey '^cabal-version:' +syn match cabalKey '^build-type:' +syn match cabalKey '^license:' +syn match cabalKey '^license-file:' +syn match cabalKey '^copyright:' +syn match cabalKey '^author:' +syn match cabalKey '^maintainer:' +syn match cabalKey '^stability:' +syn match cabalKey '^homepage:' +syn match cabalKey '^bug-reports:' +syn match cabalKey '^package-url:' +syn match cabalKey '^synopsis:' +syn match cabalKey '^description:' +syn match cabalKey '^category:' +syn match cabalKey '^tested-with:' +syn match cabalKey '^data-files:' +syn match cabalKey '^data-dir:' +syn match cabalKey '^extra-source-files:' +syn match cabalKey '^extra-tmp-files:' + +" Other keywords +syn match cabalLit '\(:\s*\)\@<=\(true\|false\)' + +" Library-specifics +syn region cabalLibraryR start='^library\(\s\|$\)\@=' end='^\w' transparent keepend contains=cabalLibrayKey,cabalBuildKey,cabalCondition,cabalOperator +syn match cabalLibraryKey '^library\(\s\|$\)\@=' +syn match cabalLibraryKey '\(^\s\+\)\@<=exposed-modules:' +syn match cabalLibraryKey '\(^\s\+\)\@<=exposed:' + +" Executable-specifics +syn region cabalExeR start='^executable\s\@=' end='^\w' transparent keepend contains=cabalExeKey,cabalBuildKey,cabalCondition,cabalOperator,cabalBuildableName +syn match cabalExeKey '^executable\s\@=' +syn match cabalExeKey '\(^\s\+\)\@<=main-is:' + +" Test-specifics +syn region cabalTestR start='^test-suite\s\@=' end='^\w' transparent keepend contains=cabalTestKey,cabalBuildKey,cabalCondition,cabalOperator,cabalBuildableName +syn match cabalTestKey '^test-suite\s\@=' +syn match cabalTestKey '\(^\s\+\)\@<=type:' +syn match cabalTestKey '\(^\s\+\)\@<=main-is:' +syn match cabalTestKey '\(^\s\+\)\@<=test-module:' + +" Benchmark-specifics +syn region cabalBenchR start='^benchmark\s\@=' end='^\w' transparent keepend contains=cabalBenchKey,cabalBuildKey,cabalCondition,cabalOperator,cabalBuildableName +syn match cabalBenchKey '^benchmark\s\@=' +syn match cabalBenchKey '\(^\s\+\)\@<=type:' +syn match cabalBenchKey '\(^\s\+\)\@<=main-is:' + +syn match cabalBuildableName '\(^\(^benchmark\|test-suite\|executable\)\s\+\)\@<=\w\+' + +" General build info +syn match cabalBuildKey '\(^\s\+\)\@<=default-language:' +syn match cabalBuildKey '\(^\s\+\)\@<=build-depends:' +syn match cabalBuildKey '\(^\s\+\)\@<=other-modules:' +syn match cabalBuildKey '\(^\s\+\)\@<=hs-source-dirs:' +syn match cabalBuildKey '\(^\s\+\)\@<=extensions:' +syn match cabalBuildKey '\(^\s\+\)\@<=build-tools:' +syn match cabalBuildKey '\(^\s\+\)\@<=buildable:' +syn match cabalBuildKey '\(^\s\+\)\@<=ghc-options:' +syn match cabalBuildKey '\(^\s\+\)\@<=ghc-prof-options:' +syn match cabalBuildKey '\(^\s\+\)\@<=ghc-shared-options:' +syn match cabalBuildKey '\(^\s\+\)\@<=hugs-options:' +syn match cabalBuildKey '\(^\s\+\)\@<=nch98-options:' +syn match cabalBuildKey '\(^\s\+\)\@<=includes:' +syn match cabalBuildKey '\(^\s\+\)\@<=install-includes:' +syn match cabalBuildKey '\(^\s\+\)\@<=include-dirs:' +syn match cabalBuildKey '\(^\s\+\)\@<=c-sources:' +syn match cabalBuildKey '\(^\s\+\)\@<=extra-libraries:' +syn match cabalBuildKey '\(^\s\+\)\@<=extra-lib-dirs:' +syn match cabalBuildKey '\(^\s\+\)\@<=cc-options:' +syn match cabalBuildKey '\(^\s\+\)\@<=cpp-options:' +syn match cabalBuildKey '\(^\s\+\)\@<=ld-options:' +syn match cabalBuildKey '\(^\s\+\)\@<=pkgconfig-depends:' +syn match cabalBuildKey '\(^\s\+\)\@<=frameworks:' + +syn region cabalFlagR start='^flag\s\@=' end='^\w' transparent keepend contains=cabalFlagKey,cabalCondition,cabalFlag +syn match cabalFlagKey '^flag\s\@=' +syn match cabalFlagKey '\(^\s\+\)\@<=description:' +syn match cabalFlagKey '\(^\s\+\)\@<=default:' +syn match cabalFlagKey '\(^\s\+\)\@<=manual:' +syn match cabalFlag '\(flag\s\+\)\@<=\w\+' +syn match cabalFlag '\(flag(\)\@<=\w\+)\@=' + +syn region cabalSourceR start='^source-repository' end='^\w' transparent keepend contains=cabalSourceKey +syn match cabalSourceKey '^source-repository\s\@=' +syn match cabalSourceKey '\(^\s\+\)\@<=type:' +syn match cabalSourceKey '\(^\s\+\)\@<=location:' +syn match cabalSourceKey '\(^\s\+\)\@<=module:' +syn match cabalSourceKey '\(^\s\+\)\@<=branch:' +syn match cabalSourceKey '\(^\s\+\)\@<=tag:' +syn match cabalSourceKey '\(^\s\+\)\@<=subdir:' + +syn match cabalCondition '\(^\s\+\)\@<=if\((\|\s\)\@=' +syn match cabalCondition '\(^\s\+\)\@<=else\($\|\s\)\@=' +syn match cabalCondition '\(^\s\+\)\@<=if\((\|\s\)\@=' +syn match cabalCondition '\(^\s\+\)\@<=else\($\|\s\)\@=' +syn match cabalOperator '\W\@<=os\((.\+)\)\@=' +syn match cabalOperator '\W\@<=arch\((.\+)\)\@=' +syn match cabalOperator '\W\@<=impl\((.\+)\)\@=' +syn match cabalOperator '\W\@<=flag\((.\+)\)\@=' +syn match cabalOperator '\(^\s*--.*\)\@\|=\|||\|&&\)' + +syn match cabalComment '\s\@<=--.*$' + +if version >= 508 || !exists('did_cabal_syntax_inits') + if version < 508 + let did_cabal_syntax_inits = 1 + command -nargs=+ HiLink hi link + else + command -nargs=+ HiLink hi def link + endif + + HiLink cabalBuildableName Structure + HiLink cabalFlag Special + HiLink cabalComment Comment + HiLink cabalCondition Conditional + HiLink cabalSourceKey Keyword + HiLink cabalOperator Operator + HiLink cabalKey Keyword + HiLink cabalLibraryKey Keyword + HiLink cabalTestKey Keyword + HiLink cabalExeKey Keyword + HiLink cabalBenchKey Keyword + HiLink cabalBuildKey Keyword + HiLink cabalFlagKey Keyword + HiLink cabalLit Constant + + delcommand HiLink +endif + +let b:current_syntax = 'cabal' diff --git a/syntax/haskell.vim b/syntax/haskell.vim index 7ac0fe2..17f4817 100644 --- a/syntax/haskell.vim +++ b/syntax/haskell.vim @@ -1,265 +1,115 @@ " Vim syntax file -" -" Modification of vims Haskell syntax file: -" - match types using regular expression -" - highlight toplevel functions -" - use "syntax keyword" instead of "syntax match" where appropriate -" - functions and types in import and module declarations are matched -" - removed hs_highlight_more_types (just not needed anymore) -" - enable spell checking in comments and strings only -" - FFI highlighting -" - QuasiQuotation -" - top level Template Haskell slices -" - PackageImport -" -" TODO: find out which vim versions are still supported -" -" From Original file: -" =================== -" -" Language: Haskell -" Maintainer: Haskell Cafe mailinglist -" Last Change: 2010 Feb 21 -" Original Author: John Williams -" -" Thanks to Ryan Crumley for suggestions and John Meacham for -" pointing out bugs. Also thanks to Ian Lynagh and Donald Bruce Stewart -" for providing the inspiration for the inclusion of the handling -" of C preprocessor directives, and for pointing out a bug in the -" end-of-line comment handling. -" -" Options-assign a value to these variables to turn the option on: -" -" hs_highlight_delimiters - Highlight delimiter characters--users -" with a light-colored background will -" probably want to turn this on. -" hs_highlight_boolean - Treat True and False as keywords. -" hs_highlight_types - Treat names of primitive types as keywords. -" hs_highlight_debug - Highlight names of debugging functions. -" hs_allow_hash_operator - Don't highlight seemingly incorrect C -" preprocessor directives but assume them to be -" operators -" -" +" Language: Haskell +" Author: Tristan Ravitch +" Maintainer: Tristan Ravitch +" Version: 0.0.1 if version < 600 - syn clear -elseif exists("b:current_syntax") + syntax clear +elseif exists('b:current_syntax') finish endif -"syntax sync fromstart "mmhhhh.... is this really ok to do so? -syntax sync linebreaks=15 minlines=50 maxlines=500 +syn sync minlines=50 maxlines=200 -syn match hsSpecialChar contained "\\\([0-9]\+\|o[0-7]\+\|x[0-9a-fA-F]\+\|[\"\\'&\\abfnrtv]\|^[A-Z^_\[\\\]]\)" -syn match hsSpecialChar contained "\\\(NUL\|SOH\|STX\|ETX\|EOT\|ENQ\|ACK\|BEL\|BS\|HT\|LF\|VT\|FF\|CR\|SO\|SI\|DLE\|DC1\|DC2\|DC3\|DC4\|NAK\|SYN\|ETB\|CAN\|EM\|SUB\|ESC\|FS\|GS\|RS\|US\|SP\|DEL\)" -syn match hsSpecialCharError contained "\\&\|'''\+" -sy region hsString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=hsSpecialChar,@Spell -sy match hsCharacter "[^a-zA-Z0-9_']'\([^\\]\|\\[^']\+\|\\'\)'"lc=1 contains=hsSpecialChar,hsSpecialCharError -sy match hsCharacter "^'\([^\\]\|\\[^']\+\|\\'\)'" contains=hsSpecialChar,hsSpecialCharError +" These basic lexical definitions are taken from the orignal haskell syntax +" description from vim 7.3. +syn match hsSpecialChar contained "\\\([0-9]\+\|o[0-7]\+\|x[0-9a-fA-F]\+\|[\"\\'&\\abfnrtv]\|^[A-Z^_\[\\\]]\)" +syn match hsSpecialChar contained "\\\(NUL\|SOH\|STX\|ETX\|EOT\|ENQ\|ACK\|BEL\|BS\|HT\|LF\|VT\|FF\|CR\|SO\|SI\|DLE\|DC1\|DC2\|DC3\|DC4\|NAK\|SYN\|ETB\|CAN\|EM\|SUB\|ESC\|FS\|GS\|RS\|US\|SP\|DEL\)" +syn match hsSpecialCharError contained "\\&\|'''\+" +syn region hsString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=hsSpecialChar +syn match hsCharacter "[^a-zA-Z0-9_']'\([^\\]\|\\[^']\+\|\\'\)'"lc=1 contains=hsSpecialChar,hsSpecialCharError +syn match hsCharacter "^'\([^\\]\|\\[^']\+\|\\'\)'" contains=hsSpecialChar,hsSpecialCharError +syn match hsNumber "\<[0-9]\+\>\|\<0[xX][0-9a-fA-F]\+\>\|\<0[oO][0-7]\+\>" +syn match hsFloat "\<[0-9]\+\.[0-9]\+\([eE][-+]\=[0-9]\+\)\=\>" -" (Qualified) identifiers (no default highlighting) -syn match ConId "\(\<[A-Z][a-zA-Z0-9_']*\.\)\=\<[A-Z][a-zA-Z0-9_']*\>" -syn match VarId "\(\<[A-Z][a-zA-Z0-9_']*\.\)\=\<[a-z][a-zA-Z0-9_']*\>" +" This case matches the names of types and constructors: names beginning with +" a capital letter. Note that this also handles the case of @M.lookup@ where +" M is a qualified import. There is a big negative lookbehind assertion here +" so that we don't highlight import and module statements oddly. +syn match hsTypeName "\(^import\s.*\|^module\s.*\)\@\?@\\^|~.][-!#$%&\*\+/<=>\?@\\^|~:.]*" -syn match hsConSym "\(\<[A-Z][a-zA-Z0-9_']*\.\)\=:[-!#$%&\*\+./<=>\?@\\^|~:]*" -syn match hsVarSym "`\(\<[A-Z][a-zA-Z0-9_']*\.\)\=[a-z][a-zA-Z0-9_']*`" -syn match hsConSym "`\(\<[A-Z][a-zA-Z0-9_']*\.\)\=[A-Z][a-zA-Z0-9_']*`" +" These are keywords that are only highlighted if they are in comments. +syn keyword hsFIXME contained FIXME TODO XXX BUG NOTE -" Toplevel Template Haskell support -"sy match hsTHTopLevel "^[a-z]\(\(.\&[^=]\)\|\(\n[^a-zA-Z0-9]\)\)*" -sy match hsTHIDTopLevel "^[a-z]\S*" -sy match hsTHTopLevel "^\$(\?" nextgroup=hsTHTopLevelName -sy match hsTHTopLevelName "[a-z]\S*" contained - -" Reserved symbols--cannot be overloaded. -syn match hsDelimiter "(\|)\|\[\|\]\|,\|;\|_\|{\|}" - -sy region hsInnerParen start="(" end=")" contained contains=hsInnerParen,hsConSym,hsType,hsVarSym -sy region hs_InfixOpFunctionName start="^(" end=")\s*[^:`]\(\W\&\S\&[^'\"`()[\]{}@]\)\+"re=s - \ contained keepend contains=hsInnerParen,hs_HlInfixOp - -sy match hs_hlFunctionName "[a-z_]\(\S\&[^,\(\)\[\]]\)*" contained -sy match hs_FunctionName "^[a-z_]\(\S\&[^,\(\)\[\]]\)*" contained contains=hs_hlFunctionName -sy match hs_HighliteInfixFunctionName "`[a-z_][^`]*`" contained -sy match hs_InfixFunctionName "^\S[^=]*`[a-z_][^`]*`"me=e-1 contained contains=hs_HighliteInfixFunctionName,hsType,hsConSym,hsVarSym,hsString,hsCharacter -sy match hs_HlInfixOp "\(\W\&\S\&[^`(){}'[\]]\)\+" contained contains=hsString -sy match hs_InfixOpFunctionName "^\(\(\w\|[[\]{}]\)\+\|\(\".*\"\)\|\('.*'\)\)\s*[^:]=*\(\W\&\S\&[^='\"`()[\]{}@]\)\+" - \ contained contains=hs_HlInfixOp,hsCharacter - -sy match hs_OpFunctionName "(\(\W\&[^(),\"]\)\+)" contained -"sy region hs_Function start="^["'a-z_([{]" end="=\(\s\|\n\|\w\|[([]\)" keepend extend -sy region hs_Function start="^["'a-zA-Z_([{]\(\(.\&[^=]\)\|\(\n\s\)\)*=" end="\(\s\|\n\|\w\|[([]\)" - \ contains=hs_OpFunctionName,hs_InfixOpFunctionName,hs_InfixFunctionName,hs_FunctionName,hsType,hsConSym,hsVarSym,hsString,hsCharacter - -sy match hs_TypeOp "::" -sy match hs_DeclareFunction "^[a-z_(]\S*\(\s\|\n\)*::" contains=hs_FunctionName,hs_OpFunctionName,hs_TypeOp - -" hi hs_TypeOp guibg=red - -" hi hs_InfixOpFunctionName guibg=yellow -" hi hs_Function guibg=green -" hi hs_InfixFunctionName guibg=red -" hi hs_DeclareFunction guibg=red - -sy keyword hsStructure data family class where instance default deriving -sy keyword hsTypedef type newtype - -sy keyword hsInfix infix infixl infixr -sy keyword hsStatement do case of let in -sy keyword hsConditional if then else - -"if exists("hs_highlight_types") - " Primitive types from the standard prelude and libraries. - sy match hsType "\<[A-Z]\(\S\&[^,.]\)*\>" - sy match hsType "()" -"endif - -" Not real keywords, but close. -if exists("hs_highlight_boolean") - " Boolean constants from the standard prelude. - syn keyword hsBoolean True False -endif - -syn region hsPackageString start=+L\="+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=cSpecial contained -sy match hsModuleName excludenl "\([A-Z]\w*\.\?\)*" contained - -sy match hsImport "\\s\+\(qualified\s\+\)\?\(\<\(\w\|\.\)*\>\)" - \ contains=hsModuleName,hsImportLabel - \ nextgroup=hsImportParams,hsImportIllegal skipwhite -sy keyword hsImportLabel import qualified contained - -sy match hsImportIllegal "\w\+" contained - -sy keyword hsAsLabel as contained -sy keyword hsHidingLabel hiding contained - -sy match hsImportParams "as\s\+\(\w\+\)" contained - \ contains=hsModuleName,hsAsLabel - \ nextgroup=hsImportParams,hsImportIllegal skipwhite -sy match hsImportParams "hiding" contained - \ contains=hsHidingLabel - \ nextgroup=hsImportParams,hsImportIllegal skipwhite -sy region hsImportParams start="(" end=")" contained - \ contains=hsBlockComment,hsLineComment, hsType,hsDelimTypeExport,hs_hlFunctionName,hs_OpFunctionName - \ nextgroup=hsImportIllegal skipwhite - -" hi hsImport guibg=red -"hi hsImportParams guibg=bg -"hi hsImportIllegal guibg=bg -"hi hsModuleName guibg=bg - -"sy match hsImport "\\(.\|[^(]\)*\((.*)\)\?" -" \ contains=hsPackageString,hsImportLabel,hsImportMod,hsModuleName,hsImportList -"sy keyword hsImportLabel import contained -"sy keyword hsImportMod as qualified hiding contained -"sy region hsImportListInner start="(" end=")" contained keepend extend contains=hs_OpFunctionName -"sy region hsImportList matchgroup=hsImportListParens start="("rs=s+1 end=")"re=e-1 -" \ contained -" \ keepend extend -" \ contains=hsType,hsLineComment,hsBlockComment,hs_hlFunctionName,hsImportListInner +" Comment stuff +syn region hsPragma start='{-#' end='#-}' +syn region hsBlockComment start='{-' end='-}' fold contains=hsFIXME,hsBlockComment +" FIXME: haddock block comments should be able to contain hsBlockComments, but +" it doesn't seem to work at the moment. +syn region hsHaddockComment start='{-|' end='-}' contains=hsFIXME +syn match hsLineComment "--.*$" contains=hsFIXME +" Line-based haddock comments are trickier - they continue until +" the next line that isn't part of the same block of comments. +syn region hsHaddockComment start='-- |' end='^\(\s*--\)\@!' contains=hsFIXME +syn region hsHaddockComment start='-- \$\w\+' end='^\(\s*--\)\@!' contains=hsFIXME +syn region hsHaddockComment start='-- ^' end='^\(\s*--\)\@!' contains=hsFIXME +" Haddock sections for import lists +syn match hsHaddockSection '-- \*.*$' +" Named documentation chunks (also for import lists) +syn match hsHaddockSection '-- \$.*$' +" Keywords appearing in expressions, plus a few top-level keywords +syn keyword hsKeyword do let in _ where +syn keyword hsKeyword infix infixl infixr +syn keyword hsKeyword forall foreign +syn match hsKeyword '\(^\(data\|type\)\s\+\)\@<=family\(\W\)\@=' -" new module highlighting -syn region hsDelimTypeExport start="\<[A-Z]\(\S\&[^,.]\)*\>(" end=")" contained - \ contains=hsType +" Vim has a special syntax category for conditionals, so here are all of the +" haskell conditionals. These are just keywords with a slightly more flexible +" coloring. +syn keyword hsConditional case of if then else -sy keyword hsExportModuleLabel module contained -sy match hsExportModule "\\(\s\|\t\|\n\)*\([A-Z]\w*\.\?\)*" contained contains=hsExportModuleLabel,hsModuleName +" We define a region for module NNNN (...) where so that haddock section +" headers (-- *) can be highlighted specially only within this context. +syn region hsModuleHeader start="^module\s" end="where" contains=hsHaddockSection keepend fold transparent +" Treat Module imports as the #include category; it maps reasonably well +syn keyword hsImport import qualified as hiding module -sy keyword hsModuleStartLabel module contained -sy keyword hsModuleWhereLabel where contained +syn keyword hsTypeDecls class instance data newtype type deriving default +" FIXME: Maybe we can do something fancy for data/type families? 'family' is +" only a keyword if it follows data/type... -syn match hsModuleStart "^module\(\s\|\n\)*\(\<\(\w\|\.\)*\>\)\(\s\|\n\)*" - \ contains=hsModuleStartLabel,hsModuleName - \ nextgroup=hsModuleCommentA,hsModuleExports,hsModuleWhereLabel +" This is uglier than I'd like. We want to let '-' participate in operators, +" but we can't let it match '--' because that interferes with comments. Hacks +" for now - just include some common operators with '-'. +syn match hsOperator "<-\|->\|-->\|-\(-\)\@!\|[%\~\&\*/\$\^|@:+=#!\?]\+" +" A bare . is an operator (but not surrounded by alnum chars) +syn match hsOperator "\s\@<=\.\s\@=" +" . is also an operator if adjacent to some other operator char +syn match hsOperator "[%\~\&\*\$\^|@:+=#!\?]\+\.[%\~\&\*\$\^|@:+<\.!>=#!\?]*" +syn match hsOperator "[%\~\&\*\$\^|@:+=#!\?]*\.[%\~\&\*\$\^|@:+\.=#!\?]\+" +" Include support for infix functions as operators +syn match hsOperator "`[a-zA-Z0-9\.]\+`" -syn region hsModuleCommentA start="{-" end="-}" - \ contains=hsModuleCommentA,hsCommentTodo,@Spell contained - \ nextgroup=hsModuleCommentA,hsModuleExports,hsModuleWhereLabel skipwhite skipnl +" Highlight function/value names in type signatures. Looks ahead to find a :: +" after a name. This allows whitespace before the name so that it can match +" in a 'where,' but it won't match local type annotations on random little +" things. +syn match hsFunctionList "^\s*\([a-z][a-zA-Z0-9']*[[:space:]\n,]\+\)*[a-z][a-zA-Z0-9']*[[:space:]\n]*::" contains=hsFunction +syn match hsFunction "\s*[a-z][a-zA-Z0-9']*[[:space:]\n]*\(::\|,\)\@=" contained +" Also support the style where the first where binding is on the same line as +" the where keyword. +syn match hsFunction "\(^\s\+where\s\+\)\@<=[a-z][a-zA-Z0-9']*\(\s*::\)\@=" -syn match hsModuleCommentA "--.*\n" - \ contains=hsCommentTodo,@Spell contained - \ nextgroup=hsModuleCommentA,hsModuleExports,hsModuleWhereLabel skipwhite skipnl +" FIXME Ignoring proc for now, also mdo and rec -syn region hsModuleExports start="(" end=")" contained - \ nextgroup=hsModuleCommentB,hsModuleWhereLabel skipwhite skipnl - \ contains=hsBlockComment,hsLineComment,hsType,hsDelimTypeExport,hs_hlFunctionName,hs_OpFunctionName,hsExportModule +" Give undefined a bit of special treatment +syn keyword hsScary undefined -syn match hsModuleCommentB "--.*\n" - \ contains=hsCommentTodo,@Spell contained - \ nextgroup=hsModuleCommentB,hsModuleWhereLabel skipwhite skipnl +" C Preprocessor stuff +syn match hsCPP '\(^\s*\)\@<=#\(warning\|pragma\|error\)\W\@=' +syn match hsCPPCond '\(^\s*\)\@<=#\(if\|ifdef\|elif\)\W\@=' +syn match hsCPPCond '\(^\s*\)\@<=#\(endif\|else\)\(\s*$\|\W\)\@=' +syn match hsCPPInclude '\(^\s*\)\@<=#include\W\@=' +syn match hsCPPDefine '\(^\s*\)\@<=#define\W\@=' +syn match hsCPPDefined '\(^\s*.*\W\)\@<=defined(\w\+)' -syn region hsModuleCommentB start="{-" end="-}" - \ contains=hsModuleCommentB,hsCommentTodo,@Spell contained - \ nextgroup=hsModuleCommentB,hsModuleWhereLabel skipwhite skipnl -" end module highlighting - -" FFI support -sy keyword hsFFIForeign foreign contained -"sy keyword hsFFIImportExport import export contained -sy keyword hsFFIImportExport export contained -sy keyword hsFFICallConvention ccall stdcall contained -sy keyword hsFFISafety safe unsafe contained -sy region hsFFIString start=+"+ skip=+\\\\\|\\"+ end=+"+ contained contains=hsSpecialChar -sy match hsFFI excludenl "\\(.\&[^\"]\)*\"\(.\)*\"\(\s\|\n\)*\(.\)*::" - \ keepend - \ contains=hsFFIForeign,hsFFIImportExport,hsFFICallConvention,hsFFISafety,hsFFIString,hs_OpFunctionName,hs_hlFunctionName - - -sy match hsNumber "\<[0-9]\+\>\|\<0[xX][0-9a-fA-F]\+\>\|\<0[oO][0-7]\+\>" -sy match hsFloat "\<[0-9]\+\.[0-9]\+\([eE][-+]\=[0-9]\+\)\=\>" - -" Comments -sy keyword hsCommentTodo TODO FIXME XXX TBD contained -sy match hsLineComment "---*\([^-!#$%&\*\+./<=>\?@\\^|~].*\)\?$" contains=hsCommentTodo,@Spell -sy region hsBlockComment start="{-" end="-}" contains=hsBlockComment,hsCommentTodo,@Spell -sy region hsPragma start="{-#" end="#-}" - -" QuasiQuotation -sy region hsQQ start="\[\$" end="|\]"me=e-2 keepend contains=hsQQVarID,hsQQContent nextgroup=hsQQEnd -sy region hsQQNew start="\[\(.\&[^|]\&\S\)*|" end="|\]"me=e-2 keepend contains=hsQQVarIDNew,hsQQContent nextgroup=hsQQEnd -sy match hsQQContent ".*" contained -sy match hsQQEnd "|\]" contained -sy match hsQQVarID "\[\$\(.\&[^|]\)*|" contained -sy match hsQQVarIDNew "\[\(.\&[^|]\)*|" contained - -if exists("hs_highlight_debug") - " Debugging functions from the standard prelude. - syn keyword hsDebug undefined error trace -endif - - -" C Preprocessor directives. Shamelessly ripped from c.vim and trimmed -" First, see whether to flag directive-like lines or not -if (!exists("hs_allow_hash_operator")) - syn match cError display "^\s*\(%:\|#\).*$" -endif -" Accept %: for # (C99) -syn region cPreCondit start="^\s*\(%:\|#\)\s*\(if\|ifdef\|ifndef\|elif\)\>" skip="\\$" end="$" end="//"me=s-1 contains=cComment,cCppString,cCommentError -syn match cPreCondit display "^\s*\(%:\|#\)\s*\(else\|endif\)\>" -syn region cCppOut start="^\s*\(%:\|#\)\s*if\s\+0\+\>" end=".\@=\|$" contains=cCppOut2 -syn region cCppOut2 contained start="0" end="^\s*\(%:\|#\)\s*\(endif\>\|else\>\|elif\>\)" contains=cCppSkip -syn region cCppSkip contained start="^\s*\(%:\|#\)\s*\(if\>\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\(%:\|#\)\s*endif\>" contains=cCppSkip -syn region cIncluded display contained start=+"+ skip=+\\\\\|\\"+ end=+"+ -syn match cIncluded display contained "<[^>]*>" -syn match cInclude display "^\s*\(%:\|#\)\s*include\>\s*["<]" contains=cIncluded -syn cluster cPreProcGroup contains=cPreCondit,cIncluded,cInclude,cDefine,cCppOut,cCppOut2,cCppSkip,cCommentStartError -syn region cDefine matchgroup=cPreCondit start="^\s*\(%:\|#\)\s*\(define\|undef\)\>" skip="\\$" end="$" -syn region cPreProc matchgroup=cPreCondit start="^\s*\(%:\|#\)\s*\(pragma\>\|line\>\|warning\>\|warn\>\|error\>\)" skip="\\$" end="$" keepend - -syn region cComment matchgroup=cCommentStart start="/\*" end="\*/" contains=cCommentStartError,cSpaceError contained -syntax match cCommentError display "\*/" contained -syntax match cCommentStartError display "/\*"me=e-1 contained -syn region cCppString start=+L\="+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=cSpecial contained - - -if version >= 508 || !exists("did_hs_syntax_inits") +if version >= 508 || !exists('did_hs_syntax_inits') if version < 508 let did_hs_syntax_inits = 1 command -nargs=+ HiLink hi link @@ -267,91 +117,42 @@ if version >= 508 || !exists("did_hs_syntax_inits") command -nargs=+ HiLink hi def link endif - HiLink hs_hlFunctionName Function - HiLink hs_HighliteInfixFunctionName Function - HiLink hs_HlInfixOp Function - HiLink hs_OpFunctionName Function - HiLink hsTypedef Typedef - HiLink hsVarSym hsOperator - HiLink hsConSym hsOperator - if exists("hs_highlight_delimiters") - " Some people find this highlighting distracting. - HiLink hsDelimiter Delimiter - endif + " CPP + HiLink hsCPP PreProc + HiLink hsCPPCond PreCondit + HiLink hsCPPInclude Include + HiLink hsCPPDefine Define + HiLink hsCPPDefined PreProc - HiLink hsModuleStartLabel Structure - HiLink hsExportModuleLabel Keyword - HiLink hsModuleWhereLabel Structure - HiLink hsModuleName Normal - - HiLink hsImportIllegal Error - HiLink hsAsLabel hsImportLabel - HiLink hsHidingLabel hsImportLabel - HiLink hsImportLabel Include - HiLink hsImportMod Include - HiLink hsPackageString hsString + " Comments + HiLink hsLineComment Comment + HiLink hsBlockComment Comment + HiLink hsPragma Comment + HiLink hsHaddockComment SpecialComment + HiLink hsHaddockSection SpecialComment - HiLink hsOperator Operator + HiLink hsKeyword Keyword + HiLink hsConditional Conditional + HiLink hsImport Include + HiLink hsTypeDecls Keyword - HiLink hsInfix Keyword - HiLink hsStructure Structure - HiLink hsStatement Statement - HiLink hsConditional Conditional + HiLink hsFIXME Todo - HiLink hsSpecialCharError Error - HiLink hsSpecialChar SpecialChar - HiLink hsString String - HiLink hsFFIString String - HiLink hsCharacter Character - HiLink hsNumber Number - HiLink hsFloat Float + HiLink hsOperator Operator - HiLink hsLiterateComment hsComment - HiLink hsBlockComment hsComment - HiLink hsLineComment hsComment - HiLink hsModuleCommentA hsComment - HiLink hsModuleCommentB hsComment - HiLink hsComment Comment - HiLink hsCommentTodo Todo - HiLink hsPragma SpecialComment - HiLink hsBoolean Boolean + HiLink hsModuleQualifier StorageClass - if exists("hs_highlight_types") - HiLink hsDelimTypeExport hsType - HiLink hsType Type - endif + HiLink hsFunction Function + HiLink hsTypeName Type - HiLink hsDebug Debug + " Literals + HiLink hsSpecialChar SpecialChar + HiLink hsFloat Float + HiLink hsNumber Number + HiLink hsCharacter Character + HiLink hsString String - HiLink hs_TypeOp hsOperator - - HiLink cCppString hsString - HiLink cCommentStart hsComment - HiLink cCommentError hsError - HiLink cCommentStartError hsError - HiLink cInclude Include - HiLink cPreProc PreProc - HiLink cDefine Macro - HiLink cIncluded hsString - HiLink cError Error - HiLink cPreCondit PreCondit - HiLink cComment Comment - HiLink cCppSkip cCppOut - HiLink cCppOut2 cCppOut - HiLink cCppOut Comment - - HiLink hsFFIForeign Keyword - HiLink hsFFIImportExport Structure - HiLink hsFFICallConvention Keyword - HiLink hsFFISafety Keyword - - HiLink hsTHIDTopLevel Macro - HiLink hsTHTopLevelName Macro - - HiLink hsQQVarID Keyword - HiLink hsQQVarIDNew Keyword - HiLink hsQQEnd Keyword - HiLink hsQQContent String + HiLink hsScary Todo delcommand HiLink endif