diff --git a/README.md b/README.md index 2cfca33..b691109 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Optionally download one of the [releases](https://github.com/sheerun/vim-polyglo - [cucumber](https://github.com/tpope/vim-cucumber) (syntax, indent, compiler, ftplugin, ftdetect) - [dart](https://github.com/dart-lang/dart-vim-plugin) (syntax, indent, ftplugin, ftdetect) - [dockerfile](https://github.com/honza/dockerfile.vim) (syntax, ftdetect) +- [elm](https://github.com/lambdatoast/elm.vim) (syntax, indent, autoload, ftplugin, ftdetect) - [elixir](https://github.com/elixir-lang/vim-elixir) (syntax, indent, compiler, ftplugin, ftdetect) - [emberscript](https://github.com/heartsentwined/vim-ember-script) (syntax, indent, ftplugin, ftdetect) - [emblem](https://github.com/heartsentwined/vim-emblem) (syntax, indent, ftplugin, ftdetect) diff --git a/autoload/elm/io.vim b/autoload/elm/io.vim new file mode 100644 index 0000000..509a8f6 --- /dev/null +++ b/autoload/elm/io.vim @@ -0,0 +1,12 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elm') == -1 + +" System IO + +" Craft a system command and run it, returning the output. +function! elm#io#system(program, args) + let cmd ="which " . a:program . " && " . a:program . " " . a:args + return system(cmd) +endfunction + + +endif diff --git a/build b/build index 589a04b..533da3a 100755 --- a/build +++ b/build @@ -107,6 +107,7 @@ PACKS=" cucumber:tpope/vim-cucumber dart:dart-lang/dart-vim-plugin dockerfile:honza/dockerfile.vim + elm:lambdatoast/elm.vim elixir:elixir-lang/vim-elixir emberscript:heartsentwined/vim-ember-script emblem:heartsentwined/vim-emblem diff --git a/ftdetect/polyglot.vim b/ftdetect/polyglot.vim index 2ef84c9..9bd0f1c 100644 --- a/ftdetect/polyglot.vim +++ b/ftdetect/polyglot.vim @@ -58,6 +58,10 @@ function! s:DetectElixir() endfunction autocmd BufNewFile,BufRead * call s:DetectElixir() endif +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elm') == -1 + +au BufNewFile,BufRead *.elm set filetype=elm +endif if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'emberscript') == -1 autocmd BufNewFile,BufRead *.em set filetype=ember-script diff --git a/ftplugin/elm.vim b/ftplugin/elm.vim new file mode 100644 index 0000000..7f12152 --- /dev/null +++ b/ftplugin/elm.vim @@ -0,0 +1,86 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elm') == -1 + +" elm.vim - Plugin for the Elm programming language +" Maintainer: Alexander Noriega +" Version: 0.4.3 + +" Plugin setup stuff + +if exists("b:did_ftplugin") + finish +endif + +let b:did_ftplugin = 1 + +" Compilation + +function! ElmMake(file) + let args = a:file + return elm#io#system("elm-make", args) +endfunction + +function! ElmMakeCurrentFile() + echo ElmMake(expand("%")) +endfunction + +function! ElmMakeMain() + echo ElmMake("Main.elm") +endfunction + +function! ElmMakeFile(file) + echo ElmMake(a:file) +endfunction + +" REPL + +function! ElmRepl() + !elm-repl +endfunction + +" Evaluation + +function! ElmEvalLine() + return ElmEval(getline(".")) +endfunction + +function! ElmEvalSelection() + let savedReg = @z + normal! `"zy + let res = ElmEval(substitute(getreg("z"), "\n", "\\\n", "g")) + let @z = savedReg + normal! gv +endfunction + +function! ElmEval(sourceCode) + let currentLine = a:sourceCode + let args = "echo '" . currentLine . "' | elm-repl" + let result = elm#io#system("echo", args) + let cleanResult = "-- " . join(s:Filtered(function("s:IsUsefulReplOutput"), split(result, "\n")), "") + put =cleanResult +endfunction + +function! s:IsUsefulReplOutput(str) + return a:str !~ "^Elm REPL" && a:str !~ "Type :help" && a:str !~ ">\\s*$" +endfunction + +" List processing + +function! s:Filtered(fn, l) + let new_list = deepcopy(a:l) + call filter(new_list, string(a:fn) . '(v:val)') + return new_list +endfunction + +command -buffer ElmEvalLine call ElmEvalLine() +command -buffer ElmEvalSelection call ElmEvalSelection() +command -buffer ElmMakeMain call ElmMakeMain() +command -buffer -nargs=1 ElmMakeFile call ElmMakeFile +command -buffer ElmMakeCurrentFile call ElmMakeCurrentFile() +command -buffer ElmRepl call ElmRepl() + +" Define comment convention + +setlocal comments=:-- +setlocal commentstring=--%s + +endif diff --git a/indent/elm.vim b/indent/elm.vim new file mode 100644 index 0000000..48e96d7 --- /dev/null +++ b/indent/elm.vim @@ -0,0 +1,129 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elm') == -1 + +" Vim indent file +" Language: Haskell +" Maintainer: lilydjwg +" Version: 1.0 +" References: http://en.wikibooks.org/wiki/Haskell/Indentation +" http://book.realworldhaskell.org/read/ +" See Also: The Align plugin http://www.vim.org/scripts/script.php?script_id=294 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentexpr=HaskellIndent() +for i in split('0{,:,0#,e', ',') + exec "setlocal indentkeys-=" . i +endfor +setlocal indentkeys+=0=else,0=in,0=where,0),0 +setlocal tabstop=8 +setlocal expandtab + +if !exists('g:Haskell_no_mapping') + inoremap =HaskellDedent(1) + inoremap =HaskellDedent(0) +endif + +" Only define the functions once. +if exists("*HaskellIndent") + finish +endif + +let s:align_map = { + \ 'in': '\', + \ '\': '\', + \ ',': '\v%(\s|\w|^)@<=[[{]%(\s|\w|"|$)@=' + \ } +let s:indent_self = ['='] +let s:indent_next = ['let', 'in', 'where', 'do', 'if'] +let s:indent_if_final = ['=', 'do', '->', 'of', 'where'] + +function HaskellIndent() + let lnum = v:lnum - 1 + + " Hit the start of the file, use zero indent. + if lnum == 0 + return 0 + endif + + let ind = indent(lnum) + let prevline = getline(lnum) + let curline = getline(v:lnum) + let curwords = split(curline) + if len(curwords) > 0 + if has_key(s:align_map, curwords[0]) + let word = s:align_map[curwords[0]] + let m = -1 + let line = v:lnum + while m == -1 + let line -= 1 + if line <= 0 + return -1 + endif + let m = match(getline(line), word) + endwhile + return m + elseif index(s:indent_self, curwords[0]) != -1 + return ind + &sw + elseif curwords[0] == '|' + return match(prevline, '\v%(\s|\w|^)@<=[|=]%(\s|\w)@=') + elseif index([')', '}'], curwords[0]) != -1 + return ind - &sw + elseif curwords[0] == 'where' + if prevline =~ '\v^\s+\|%(\s|\w)@=' + return ind - 1 + endif + endif + endif + + let prevwords = split(prevline) + if len(prevwords) == 0 + return 0 + endif + + if prevwords[-1] == 'where' && prevwords[0] == 'module' + return 0 + elseif index(s:indent_if_final, prevwords[-1]) != -1 + return ind + &sw + elseif prevwords[-1] =~ '\v%(\s|\w|^)@<=[[{(]$' + return ind + &sw + else + for word in reverse(prevwords) + if index(s:indent_next, word) != -1 + return match(prevline, '\<'.word.'\>') + len(word) + 1 + endif + endfor + endif + + if len(curwords) > 0 && curwords[0] == 'where' + return ind + &sw + endif + + return ind +endfunction + +function s:HaskellDedent(isbs) + if a:isbs && strpart(getline('.'), 0, col('.')-1) !~ '^\s\+$' + return "\" + endif + + let curind = indent('.') + let line = line('.') - 1 + while curind > 0 && line > 0 + let ind = indent(line) + if ind >= curind + let line -= 1 + else + echomsg curind ind + call setline('.', repeat(' ', ind) . + \ substitute(getline('.'), '^\s\+', '', '')) + return '' + endif + endwhile + return a:isbs ? "\" : '' +endfunction + +endif diff --git a/syntax/elm.vim b/syntax/elm.vim new file mode 100644 index 0000000..5825e22 --- /dev/null +++ b/syntax/elm.vim @@ -0,0 +1,81 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elm') == -1 + +" Vim syntax file +" Language: Elm (http://elm-lang.org/) +" Maintainer: Alexander Noriega +" Latest Revision: 19 April 2015 + +if exists("b:current_syntax") + finish +endif + +" Keywords +syn keyword elmKeyword alias as case else exposing if import in let module of port then type where + +" Builtin operators +syn match elmBuiltinOp "\~" +syn match elmBuiltinOp "||" +syn match elmBuiltinOp "|>" +syn match elmBuiltinOp "|" +syn match elmBuiltinOp "`" +syn match elmBuiltinOp "\^" +syn match elmBuiltinOp "\\" +syn match elmBuiltinOp ">>" +syn match elmBuiltinOp ">=" +syn match elmBuiltinOp ">" +syn match elmBuiltinOp "==" +syn match elmBuiltinOp "=" +syn match elmBuiltinOp "<\~" +syn match elmBuiltinOp "<|" +syn match elmBuiltinOp "<=" +syn match elmBuiltinOp "<<" +syn match elmBuiltinOp "<-" +syn match elmBuiltinOp "<" +syn match elmBuiltinOp "::" +syn match elmBuiltinOp ":" +syn match elmBuiltinOp "/=" +syn match elmBuiltinOp "//" +syn match elmBuiltinOp "/" +syn match elmBuiltinOp "\.\." +syn match elmBuiltinOp "\." +syn match elmBuiltinOp "->" +syn match elmBuiltinOp "-" +syn match elmBuiltinOp "++" +syn match elmBuiltinOp "+" +syn match elmBuiltinOp "*" +syn match elmBuiltinOp "&&" +syn match elmBuiltinOp "%" + +" Special names +syntax match specialName "^main " + +" Comments +syn match elmTodo "[tT][oO][dD][oO]\|FIXME\|XXX" contained +syn match elmLineComment "--.*" contains=elmTodo,@spell +syn region elmComment matchgroup=elmComment start="{-|\=" end="-}" contains=elmTodo,elmComment,@spell + +" String literals +syn region elmString start="\"" skip="\\\"" end="\"" contains=elmStringEscape +syn match elmStringEscape "\\u[0-9a-fA-F]\{4}" contained +syn match elmStringEscape "\\[nrfvbt\\\"]" contained + +" Number literals +syn match elmNumber "\(\<\d\+\>\)" +syn match elmNumber "\(\<\d\+\.\d\+\>\)" + +" Types +syn match elmType "\<[A-Z][0-9A-Za-z_'-]*" + +let b:current_syntax = "elm" + +hi def link elmKeyword Keyword +hi def link elmBuiltinOp Special +hi def link elmType Type +hi def link elmTodo Todo +hi def link elmLineComment Comment +hi def link elmComment Comment +hi def link elmString String +hi def link elmNumber Number +hi def link specialName Special + +endif