diff --git a/README.md b/README.md index 797c05b..e321df5 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Optionally download one of the [releases](https://github.com/sheerun/vim-polyglo - [groovy](https://github.com/vim-scripts/groovy.vim) (syntax) - [haml](https://github.com/tpope/vim-haml) (syntax, indent, compiler, ftplugin, ftdetect) - [handlebars](https://github.com/mustache/vim-mustache-handlebars) (syntax, ftplugin, ftdetect) -- [haskell](https://github.com/raichoo/haskell-vim) () +- [haskell](https://github.com/neovimhaskell/haskell-vim) (syntax, indent, ftplugin, ftdetect) - [haxe](https://github.com/yaymukund/vim-haxe) (syntax, ftdetect) - [html5](https://github.com/othree/html5.vim) (syntax, indent, autoload, ftplugin) - [jade](https://github.com/digitaltoad/vim-jade) (syntax, indent, ftplugin, ftdetect) diff --git a/after/ftplugin/cabal.vim b/after/ftplugin/cabal.vim new file mode 100644 index 0000000..a4f042b --- /dev/null +++ b/after/ftplugin/cabal.vim @@ -0,0 +1,8 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1 + +setlocal comments=s1fl:{-,mb:-,ex:-},:-- +setlocal formatoptions-=cro formatoptions+=j +setlocal iskeyword+=-,.,* +setlocal commentstring=--\ %s + +endif diff --git a/after/ftplugin/haskell.vim b/after/ftplugin/haskell.vim new file mode 100644 index 0000000..387ffe7 --- /dev/null +++ b/after/ftplugin/haskell.vim @@ -0,0 +1,7 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1 + +setlocal comments=s1fl:{-,mb:-,ex:-},:-- +setlocal formatoptions-=cro formatoptions+=j +setlocal iskeyword+=' + +endif diff --git a/build b/build index d92a0e1..a8ac750 100755 --- a/build +++ b/build @@ -116,7 +116,7 @@ PACKS=" groovy:vim-scripts/groovy.vim haml:tpope/vim-haml handlebars:mustache/vim-mustache-handlebars - haskell:raichoo/haskell-vim + haskell:neovimhaskell/haskell-vim haxe:yaymukund/vim-haxe html5:othree/html5.vim jade:digitaltoad/vim-jade diff --git a/ftdetect/polyglot.vim b/ftdetect/polyglot.vim index f61491b..dad893b 100644 --- a/ftdetect/polyglot.vim +++ b/ftdetect/polyglot.vim @@ -114,6 +114,10 @@ autocmd BufNewFile,BufRead *.haml,*.hamlbars,*.hamlc setf haml autocmd BufNewFile,BufRead *.sass setf sass autocmd BufNewFile,BufRead *.scss setf scss endif +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1 + +au BufRead,BufNewFile *.hsc set filetype=haskell +endif if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haxe') == -1 autocmd BufNewFile,BufRead *.hx setf haxe diff --git a/ftplugin/cabal.vim b/ftplugin/cabal.vim new file mode 100644 index 0000000..0942397 --- /dev/null +++ b/ftplugin/cabal.vim @@ -0,0 +1,69 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1 + +if exists("g:loaded_haskellvim_cabal") + finish +endif + +let g:loaded_haskellvim_cabal = 1 + +function! s:makeSection(content) + return "\n" . join(a:content, "\n") +endfunction + +function! s:exeTmpl(name, src) + let l:exetmpl = [ 'executable ' . a:name, + \ '-- ghc-options:', + \ 'main-is: ' . a:src, + \ '-- other-modules:', + \ '-- other-extensions:', + \ 'build-depends: base', + \ '-- hs-source-dirs:', + \ 'default-language: Haskell2010' + \ ] + + return s:makeSection(l:exetmpl) +endfunction + +function! s:libTmpl() + let l:libtmpl = [ 'library', + \ '-- ghc-options:', + \ '-- other-modules:', + \ '-- other-extensions:', + \ 'build-depends: base', + \ '-- hs-source-dirs:', + \ 'default-language: Haskell2010' + \ ] + + return s:makeSection(l:libtmpl) +endfunction + +function! s:flagTmpl(name) + let l:flagtmpl = [ 'flag ' . a:name, + \ 'description:', + \ 'default: False', + \ 'manual: True', + \ ] + + return s:makeSection(l:flagtmpl) +endfunction + +function! cabal#addExecutable() + let l:name = input("Enter executable name: ") + let l:src = input("Enter source file: ") + exe "normal Go" . s:exeTmpl(l:name, l:src) +endfunction + +function! cabal#addLibrary() + exe "normal Go" . s:libTmpl() +endfunction + +function! cabal#addFlag() + let l:name = input("Enter flag name: ") + exe "normal Go" . s:flagTmpl(l:name) +endfunction + +command! -buffer CabalAddExecutable call cabal#addExecutable() +command! -buffer CabalAddLibrary call cabal#addLibrary() +command! -buffer CabalAddFlag call cabal#addFlag() + +endif diff --git a/ftplugin/haskell.vim b/ftplugin/haskell.vim new file mode 100644 index 0000000..3e9c43f --- /dev/null +++ b/ftplugin/haskell.vim @@ -0,0 +1,25 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1 + +if exists("g:loaded_haskellvim_haskell") + finish +endif + +let g:loaded_haskellvim_haskell = 1 + +function! haskell#makeModuleCommentBlock() + let l:commenttmpl = [ '{-|', + \ 'Module : ', + \ 'Description : ', + \ 'Copyright : ', + \ 'License : ', + \ 'Maintainer : ', + \ 'Stability : ', + \ 'Portability : ', + \ '-}'] + + exe "normal ggO" . join(l:commenttmpl, "\n") +endfunction + +command! -buffer -nargs=0 HaskellAddModuleComment call haskell#makeModuleCommentBlock() + +endif diff --git a/indent/cabal.vim b/indent/cabal.vim new file mode 100644 index 0000000..b2089a5 --- /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, + +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 new file mode 100644 index 0000000..b69a19c --- /dev/null +++ b/indent/haskell.vim @@ -0,0 +1,189 @@ +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 +" 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 +endif + +let b:did_indent = 1 + +if !exists('g:haskell_indent_if') + " if bool + " >>>then ... + " >>>else ... + let g:haskell_indent_if = 3 +endif + +if !exists('g:haskell_indent_case') + " case xs of + " >>[] -> ... + " >>(y:ys) -> ... + let g:haskell_indent_case = 2 +endif + +if !exists('g:haskell_indent_let') + " let x = 0 in + " >>>>x + let g:haskell_indent_let = 4 +endif + +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 + +if !exists('g:haskell_indent_in') + " let x = 1 + " >in x + 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=\=>,,0} + +function! GetHaskellIndent() + let l:prevline = getline(v:lnum - 1) + + if l:prevline =~ '^\s*--' + return match(l:prevline, '\S') + endif + + 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 + + if l:prevline =~ '^\s*$' + return 0 + endif + + let l:line = getline(v:lnum) + + if l:line =~ '\C^\s*\' + let l:s = match(l:prevline, '\S') + return l:s + &shiftwidth + endif + + if l:line =~ '\C^\s*\' + let l:s = match(l:prevline, '\C\<\(newtype\|data\)\>') + if l:s >= 0 + return l:s + &shiftwidth + endif + endif + + if l:line =~ '\C^\s*\' + let l:s = match(l:prevline, '\C\') + if l:s != 0 + return l:s + endif + endif + + if l:line =~ '\C^\s*\' + let l:s = match(l:prevline, '\C\') + 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 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 l:line =~ '^\s*[=-]>' + let l:s = match(l:prevline, ' :: ') + if l:s >= 0 + return l:s + 1 + endif + endif + + if l:prevline =~ '\s\+[!#$%&*+./<>?@\\^|~-]\+\s*$' + let l:s = match(l:prevline, '\S') + if l:s > 0 + return l:s + &shiftwidth + endif + endif + + if l:prevline =~ '[{([][^})\]]\+$' + return match(l:prevline, '[{([]') + endif + + if l:prevline =~ '\C\\s\+[^=]\+=\s*$' + return match(l:prevline, '\C\') + g:haskell_indent_let + &shiftwidth + endif + + if l:prevline =~ '\C\\s\+.\+\(\\)\?\s*$' + return match(l:prevline, '\C\') + g:haskell_indent_let + endif + + if l:prevline !~ '\C\' + let l:s = match(l:prevline, '\C\.*\&.*\zs\') + if l:s > 0 + return l:s + endif + + let l:s = match(l:prevline, '\C\') + if l:s > 0 + return l:s + g:haskell_indent_if + endif + endif + + if l:prevline =~ '\C\(\\|\\|=\|[{([]\)\s*$' + return match(l:prevline, '\S') + &shiftwidth + endif + + if l:prevline =~ '\C\\s\+\S\+.*$' + return match(l:prevline, '\C\') + g:haskell_indent_where + endif + + if l:prevline =~ '\C\\s\+\S\+.*$' + return match(l:prevline, '\C\') + g:haskell_indent_do + endif + + if l:prevline =~ '\C^\s*\\s\+[^=]\+\s\+=\s\+\S\+.*$' + if l:line =~ '^\s*|' + return match(l:prevline, '=') + endif + endif + + if l:prevline =~ '\C\\s\+.\+\\s*$' + return match(l:prevline, '\C\') + g:haskell_indent_case + endif + + if l:prevline =~ '\C^\s*\<\data\>\s\+\S\+\s*$' + return match(l:prevline, '\C\') + &shiftwidth + endif + + return match(l:prevline, '\S') +endfunction + +endif diff --git a/syntax/cabal.vim b/syntax/cabal.vim new file mode 100644 index 0000000..7a48a63 --- /dev/null +++ b/syntax/cabal.vim @@ -0,0 +1,55 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1 + +" syntax highlighting for cabal +" +" author: raichoo (raichoo@googlemail.com) + +if version < 600 + syn clear +elseif exists("b:current_syntax") + finish +endif + +syn match cabalLineComment "---*\([^-!#$%&\*\+./<=>\?@\\^|~].*\)\?$" contains=@Spell +syn match cabalIdentifier "[A-Za-z\-]*" contained +syn match cabalOperator "[<=>&|!]" +syn match cabalColon ":" contained +syn match cabalNumber "\<[0-9][0-9\.*]*\>" +syn match cabalDelimiter "[,()]" +syn keyword cabalBool True False +syn keyword cabalConditional if else +syn match cabalCompilerFlag "\s\+-[^ -][^ ]*" +syn match cabalDocBulletPoint "^\s\+\*" +syn match cabalDocHeadline "^\s\+=.*$" +syn match cabalDocCode "^\s\+>.*$" +syn match cabalDocNewline "^\s\+\.\s*$" +syn match cabalSection "^\c\(executable\|library\|flag\|source-repository\|test-suite\|benchmark\)" +syn match cabalEntry "^\s*[A-Za-z][a-zA-Z\-]*:" contains=cabalIdentifier,cabalColon + +syn region cabalDescription start="^\s*[dD]escription:" end="^\<" keepend + \ contains= + \ cabalEntry, + \ cabalLineComment, + \ cabalDocBulletPoint, + \ cabalDocHeadline, + \ cabalDocNewline, + \ cabalDocCode + +highlight def link cabalIdentifier Identifier +highlight def link cabalLineComment Comment +highlight def link cabalOperator Operator +highlight def link cabalColon Operator +highlight def link cabalNumber Number +highlight def link cabalSection Structure +highlight def link cabalDelimiter Delimiter +highlight def link cabalBool Boolean +highlight def link cabalCompilerFlag Macro +highlight def link cabalConditional Conditional +highlight def link cabalDocBulletPoint Structure +highlight def link cabalDocHeadline Include +highlight def link cabalDocNewline Operator +highlight def link cabalDocCode Macro + +let b:current_syntax = "cabal" + +endif diff --git a/syntax/haskell.vim b/syntax/haskell.vim new file mode 100644 index 0000000..c8048ca --- /dev/null +++ b/syntax/haskell.vim @@ -0,0 +1,180 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haskell') == -1 + +" syntax highlighting for haskell +" +" Heavily modified version of the haskell syntax +" highlighter to support haskell. +" +" author: raichoo (raichoo@googlemail.com) + +if version < 600 + syn clear +elseif exists("b:current_syntax") + finish +endif + +syn match haskellRecordField contained containedin=haskellBlock + \ "[_a-z][a-zA-Z0-9_']*\(,\s*[_a-z][a-zA-Z0-9_']*\)*\(\s*::\|\n\s\+::\)" + \ contains= + \ haskellIdentifier, + \ haskellOperators, + \ haskellSeparator, + \ haskellParens, +syn match haskellTypeSig + \ "^\s*\(where\s\+\|let\s\+\|default\s\+\)\?[_a-z][a-zA-Z0-9_']*\(,\s*[_a-z][a-zA-Z0-9_']*\)*\(\s*::\|\n\s\+::\)" + \ contains= + \ haskellWhere, + \ haskellLet, + \ haskellIdentifier, + \ haskellOperators, + \ haskellSeparator, + \ haskellParens, +syn keyword haskelLWhere where +syn keyword haskellLet let +syn keyword haskellDeclKeyword module class instance newtype deriving in +syn match haskellDecl "\<\(type\|data\)\>\s\+\(\\)\?" +syn keyword haskellDefault default +syn keyword haskellImportKeywords import qualified safe as hiding contained +syn keyword haskellForeignKeywords foreign export import ccall safe unsafe interruptible capi prim contained +syn region haskellForeignImport start="\" end="::" keepend + \ contains= + \ haskellString, + \ haskellOperators, + \ haskellForeignKeywords, + \ haskellIdentifier +syn match haskellImport "^\\s\+\(\\s\+\)\?\(\\s\+\)\?.\+\(\s\+\\s\+.\+\)\?\(\s\+\\)\?" + \ contains= + \ haskellParens, + \ haskellOperators, + \ haskellImportKeywords, + \ haskellType, + \ haskellLineComment, + \ haskellBlockComment, + \ haskellPragma, +syn keyword haskellStatement do case of +if exists('g:haskell_enable_static_pointers') && g:haskell_enable_static_pointers == 1 + syn keyword haskellStatic static +endif +syn keyword haskellConditional if then else +syn match haskellNumber "\<[0-9]\+\>\|\<0[xX][0-9a-fA-F]\+\>\|\<0[oO][0-7]\+\>\|\<0[bB][10]\+\>" +syn match haskellFloat "\<[0-9]\+\.[0-9]\+\([eE][-+]\=[0-9]\+\)\=\>" +syn match haskellSeparator "[,;]" +syn region haskellParens matchgroup=haskellDelimiter start="(" end=")" contains=TOP,haskellTypeSig +syn region haskellBrackets matchgroup=haskellDelimiter start="\[" end="]" contains=TOP,haskellTypeSig +syn region haskellBlock matchgroup=haskellDelimiter start="{" end="}" contains=TOP +syn keyword haskellInfix infix infixl infixr +syn keyword haskellBottom undefined error +syn match haskellOperators "[-!#$%&\*\+/<=>\?@\\^|~:.]\+\|\<_\>" +syn match haskellQuote "\<'\+" contained +syn match haskellQuotedType "[A-Z][a-zA-Z0-9_']*\>" contained +syn region haskellQuoted start="\<'\+" end="\>" + \ contains= + \ haskellType, + \ haskellQuote, + \ haskellQuotedType, + \ haskellSeparator, + \ haskellParens, + \ haskellOperators, + \ haskellIdentifier +syn match haskellLineComment "---*\([^-!#$%&\*\+./<=>\?@\\^|~].*\)\?$" + \ contains= + \ haskellTodo, + \ @Spell +syn match haskellBacktick "`[A-Za-z_][A-Za-z0-9_\.']*`" +syn region haskellString start=+"+ skip=+\\\\\|\\"+ end=+"+ + \ contains=@Spell +syn match haskellIdentifier "[_a-z][a-zA-z0-9_']*" contained +syn match haskellChar "\<'[^'\\]'\|'\\.'\|'\\u[0-9a-fA-F]\{4}'\>" +syn match haskellType "\<[A-Z][a-zA-Z0-9_']*\>" +syn region haskellBlockComment start="{-" end="-}" + \ contains= + \ haskellBlockComment, + \ haskellTodo, + \ @Spell +syn region haskellPragma start="{-#" end="#-}" +syn match haskellQuasiQuoted "." containedin=haskellQuasiQuote contained +syn region haskellQuasiQuote matchgroup=haskellTH start="\[[_a-z][a-zA-z0-9_']*|" end="|\]" +syn region haskellTHBlock matchgroup=haskellTH start="\[\(d\|t\|p\)\?|" end="|]" contains=TOP +syn region haskellTHDoubleBlock matchgroup=haskellTH start="\[||" end="||]" contains=TOP +syn match haskellPreProc "^#.*$" +syn keyword haskellTodo TODO FIXME contained +" Treat a shebang line at the start of the file as a comment +syn match haskellShebang "\%^#!.*$" +if exists('g:haskell_enable_typeroles') && g:haskell_enable_typeroles == 1 + syn keyword haskellTypeRoles phantom representational nominal contained + syn region haskellTypeRoleBlock matchgroup=haskellTypeRoles start="type\s\+role" end="$" keepend + \ contains= + \ haskellType, + \ haskellTypeRoles +endif +if exists('g:haskell_enable_quantification') && g:haskell_enable_quantification == 1 + syn keyword haskellForall forall +endif +if exists('g:haskell_enable_recursivedo') && g:haskell_enable_recursivedo == 1 + syn keyword haskellRecursiveDo mdo rec +endif +if exists('g:haskell_enable_arrowsyntax') && g:haskell_enable_arrowsyntax == 1 + syn keyword haskellArrowSyntax proc +endif +if exists('g:haskell_enable_pattern_synonyms') && g:haskell_enable_pattern_synonyms == 1 + syn keyword haskellPatternKeyword pattern +endif + +highlight def link haskellBottom Macro +highlight def link haskellTH Boolean +highlight def link haskellBlockKeywords Structure +highlight def link haskellIdentifier Identifier +highlight def link haskellForeignKeywords Structure +highlight def link haskellDeriving Structure +highlight def link haskellStatement Statement +highlight def link haskellDefault Statement +highlight def link haskellConditional Conditional +highlight def link haskellNumber Number +highlight def link haskellFloat Float +highlight def link haskellSeparator Delimiter +highlight def link haskellDelimiter Delimiter +highlight def link haskellInfix PreProc +highlight def link haskellOperators Operator +highlight def link haskellQuote Operator +highlight def link haskellQuotedType Include +highlight def link haskellType Include +highlight def link haskellShebang Comment +highlight def link haskellLineComment Comment +highlight def link haskellBlockComment Comment +highlight def link haskellPragma SpecialComment +highlight def link haskellString String +highlight def link haskellChar String +highlight def link haskellBacktick Operator +highlight def link haskellPreProc Macro +highlight def link haskellTodo Todo +highlight def link haskellAssocType Structure +highlight def link haskellImportBlock Delimiter +highlight def link haskellImportKeywords Structure +highlight def link haskellDeclKeyword Structure +highlight def link haskellDecl Structure +highlight def link haskellWhere Structure +highlight def link haskellLet Structure +highlight def link haskellQuasiQuoted String + +if exists('g:haskell_enable_quantification') && g:haskell_enable_quantification == 1 + highlight def link haskellForall Operator +endif +if exists('g:haskell_enable_recursivedo') && g:haskell_enable_recursivedo == 1 + highlight def link haskellRecursiveDo Operator +endif +if exists('g:haskell_enable_arrowsyntax') && g:haskell_enable_arrowsyntax == 1 + highlight def link haskellArrowSyntax Operator +endif +if exists('g:haskell_enable_pattern_synonyms') && g:haskell_enable_pattern_synonyms == 1 + highlight def link haskellPatternKeyword Structure +endif +if exists('g:haskell_enable_typeroles') && g:haskell_enable_typeroles == 1 + highlight def link haskellTypeRoles Structure +endif +if exists('g:haskell_enable_static_pointers') && g:haskell_enable_static_pointers == 1 + highlight def link haskellStatic Statement +endif + +let b:current_syntax = "haskell" + +endif