diff --git a/README.md b/README.md index b88c54e..2e9b101 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of language packs for Vim. > One to rule them all, one to find them, one to bring them all and in the darkness bind them. - It **won't affect your startup time**, as scripts are loaded only on demand\*. -- It **installs and updates 100+ times faster** than the 117 packages it consists of. +- It **installs and updates 100+ times faster** than the 118 packages it consists of. - Solid syntax and indentation support (other features skipped). Only the best language packs. - All unnecessary files are ignored (like enormous documentation from php support). - No support for esoteric languages, only most popular ones (modern too, like `slim`). @@ -116,6 +116,7 @@ If you need full functionality of any plugin, please use it directly with your p - [pgsql](https://github.com/exu/pgsql.vim) (syntax) - [php](https://github.com/StanAngeloff/php.vim) (syntax) - [plantuml](https://github.com/aklt/plantuml-syntax) (syntax, indent, ftplugin) +- [pony](https://github.com/jakwings/vim-pony) (syntax, indent, autoload, ftplugin) - [powershell](https://github.com/PProvost/vim-ps1) (syntax, indent, ftplugin) - [protobuf](https://github.com/uarun/vim-protobuf) (syntax, indent) - [pug](https://github.com/digitaltoad/vim-pug) (syntax, indent, ftplugin) diff --git a/autoload/pony.vim b/autoload/pony.vim new file mode 100644 index 0000000..51568aa --- /dev/null +++ b/autoload/pony.vim @@ -0,0 +1,536 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'pony') == -1 + +" Vim plugin file +" Language: Pony +" Maintainer: Jak Wings + +" TODO: Make sure echomsg is off for release. +let s:cpo_save = &cpo +set cpo&vim + + +"let s:skip = 'InCommentOrLiteral(line("."), col("."))' +let s:skip2 = 'InLiteral(line("."), col(".")) || InComment(line("."), col(".")) == 1' +let s:skip3 = '!InKeyword(line("."), col("."))' +let s:skip4 = '!InBracket(line("."), col("."))' +let s:cfstart = '\v<%(ifdef|if|match|while|for|repeat|try|with|recover|object|lambda|iftype)>' +let s:cfmiddle = '\v<%(then|elseif|else|until|do|in|elseiftype)>|\|' +let s:cfend = '\v' +let s:bstartp = '\v<%(ifdef|if|then|elseif|else|(match)|while|for|in|do|try|with|recover|repeat|until|(object)|lambda|iftype|elseiftype)>' + +function! pony#Indent() + if v:lnum <= 1 + return 0 + endif + + call cursor(v:lnum, 1) + let l:pnzpos = searchpos('.', 'cbnW') + if l:pnzpos == [0, 0] + return 0 + endif + + if s:InComment2(l:pnzpos) > 1 + "echomsg 'Comment' (l:pnzpos[0] . '-' . v:lnum) -1 + return cindent(v:lnum) + endif + + if s:InLiteral2(l:pnzpos) + "echomsg 'String' (l:pnzpos[0] . '-' . v:lnum) -1 + return -1 + endif + + unlet! l:pnzpos + + " NOTE: Lines started in comments and strings are checked already. + + let l:pnblnum = s:PrevNonblank(v:lnum - 1) + if l:pnblnum < 1 + return 0 + endif + + let l:pnbline = getline(l:pnblnum) + let l:pnbindent = indent(l:pnblnum) + + let l:line = getline(v:lnum) + let l:indent = l:pnbindent + let l:shiftwidth = shiftwidth() + + " FIXME? + let l:continuing = 0 + " If the previous line ends with a unary or binary operator, + if s:IsContinued(l:pnblnum) + let l:contlnum = l:pnblnum + let l:ppcontinued = 0 + let l:ppnblnum = s:PrevNonblank(l:pnblnum - 1) + while s:IsContinued(l:ppnblnum) + let l:ppcontinued += 1 + let l:contlnum = l:ppnblnum + let l:ppnblnum = s:PrevNonblank(l:ppnblnum - 1) + endwhile + "echomsg 'Continued1' l:pnblnum l:contlnum + " If the previous line is also continuing another line, + if l:ppcontinued + let l:continuing = 1 + if getline(l:contlnum) =~# '\v^\s*%(actor|class|struct|primitive|trait|type|interface)>' + " reset the indent level. + "echomsg 'Continuing0' (l:contlnum . '-' . v:lnum) (l:shiftwidth * 2) + let l:indent = l:shiftwidth * 2 + else + " keep using the previous indent. + "echomsg 'Continuing1' (l:pnblnum . '-' . v:lnum) l:pnbindent + let l:indent = l:pnbindent + endif + " if the previous line is part of the definition of a class, + elseif l:pnbline =~# '\v^\s*%(actor|class|struct|primitive|trait|type|interface)>' + " reset the indent level. + "echomsg 'Continuing2' (l:pnblnum . '-' . v:lnum) (l:shiftwidth * 2) + let l:continuing = 1 + let l:indent = l:shiftwidth * 2 + " if the previous line is part of the definition of a method, + elseif l:pnbline =~# '\v^\s*%(fun|new|be)>' + " reset the indent level. + "echomsg 'Continuing3' (l:pnblnum . '-' . v:lnum) (l:pnbindent + l:shiftwidth) + let l:continuing = 1 + let l:indent = l:pnbindent + l:shiftwidth + " if the previous line is the start of a definition body, + elseif l:pnbline =~# '=>\s*$' + " indent this line. + "echomsg 'Continuing4' (l:pnblnum . '-' . v:lnum) (l:pnbindent + l:shiftwidth) + let l:continuing = 1 + let l:indent = l:pnbindent + l:shiftwidth + else + " indent this line twice as far. + "echomsg 'Continuing5' (l:pnblnum . '-' . v:lnum) (l:pnbindent + l:shiftwidth * 2) + let l:continuing = 1 + let l:indent = l:pnbindent + l:shiftwidth * 2 + endif + + unlet! l:contlnum l:ppnblnum l:ppcontinued + endif + + " If this line starts a document string, + if !l:continuing && l:line =~# '^\s*"""' + let l:ppnblnum = s:PrevNonblank(l:pnblnum - 1) + if s:IsContinued(l:ppnblnum) + let l:contlnum = l:ppnblnum + while s:IsContinued(l:ppnblnum) + let l:contlnum = l:ppnblnum + let l:ppnblnum = s:PrevNonblank(l:ppnblnum - 1) + endwhile + if getline(l:contlnum) =~# '\v^\s*%(actor|class|struct|primitive|trait|type|interface)>' + " reset the indent level. + "echomsg 'DocString' (l:contlnum . '-' . v:lnum) l:shiftwidth + return l:shiftwidth + endif + endif + + unlet! l:contlnum l:ppnblnum + endif + + " If the previous line contains an unmatched opening bracket + if !l:continuing && l:pnbline =~# '[{[(]' + " if the line ends with an opening bracket, + if l:pnbline =~# '[{[(]\s*$' && !s:InCommentOrLiteral(l:pnblnum, col([l:pnblnum, '$']) - 1) + " indent this line. + let l:indent += l:shiftwidth + else + " find the unmatched opening bracket, + let l:start = [0, 0] + let l:end = col([l:pnblnum, '$']) - 1 + call cursor(l:pnblnum, l:end) + while l:end > 0 + let l:start = s:OuterPos(l:start, searchpairpos('(', '', ')', 'bnW', s:skip4, l:pnblnum)) + let l:start = s:OuterPos(l:start, searchpairpos('\[', '', '\]', 'bnW', s:skip4, l:pnblnum)) + let l:start = s:OuterPos(l:start, searchpairpos('{', '', '}', 'bnW', s:skip4, l:pnblnum)) + if l:start == [0, 0] + break + endif + " find the matched closing bracket on the same line, + call cursor(l:start[0], l:start[1]) + let l:c = s:CharAtCursor(l:start[0], l:start[1]) + if searchpair(escape(l:c, '['), '', escape(tr(l:c, '([{', ')]}'), ']'), + \ 'znW', s:skip4, l:pnblnum) < 1 + " the unmatched opening bracket is found, + break + endif + let l:end = l:start[1] + let l:start = [0, 0] + endwhile + if l:start != [0, 0] + " indent this line. + "echomsg 'Open bracket' (l:pnblnum . '-' . v:lnum) (l:indent + l:shiftwidth) + let l:indent += l:shiftwidth + endif + endif + + unlet! l:start l:end l:c + endif + + " If there is a matched closing bracket on the previous line, + " NOTE: + " >|[ + " | (1 - + " | 1) * 2] + " | command + " ^ + if !l:continuing + call cursor(l:pnblnum, 1) + " find the last closing bracket, + let l:end = [0, 0] + let l:end = s:OuterPos(l:end, searchpairpos('(', '', ')', 'zncr', s:skip4, l:pnblnum)) + let l:end = s:OuterPos(l:end, searchpairpos('\[', '', '\]', 'zncr', s:skip4, l:pnblnum)) + let l:end = s:OuterPos(l:end, searchpairpos('{', '', '}', 'zncr', s:skip4, l:pnblnum)) + if l:end != [0, 0] + " find the matched opening bracket on another line, + let l:c = s:CharAtCursor(l:end[0], l:end[1]) + let l:start = searchpairpos(escape(tr(l:c, ')]}', '([{'), '['), '', escape(l:c, ']'), 'nbW', s:skip4) + if l:start[0] != l:end[0] + " and then this line has the same indent as the line the matched bracket stays. + "echomsg 'Matched bracket' (l:start[0] . '-' . v:lnum) indent(l:start[0]) + let l:indent = indent(l:start[0]) + endif + endif + + unlet! l:start l:end l:c + endif + + " If there is a matched closing bracket on this line, + " NOTE: + " |[ + " >| (1 - + " | 1) * 2 + " |] + " ^ ^ + if l:line =~# '^\s*[)\]}]' + " find the first closing bracket, + call cursor(v:lnum, 1) + let l:end = [0, 0] + let l:end = s:InnerPos(l:end, searchpairpos('(', '', ')', 'zncW', s:skip4, v:lnum)) + let l:end = s:InnerPos(l:end, searchpairpos('\[', '', '\]', 'zncW', s:skip4, v:lnum)) + let l:end = s:InnerPos(l:end, searchpairpos('{', '', '}', 'zncW', s:skip4, v:lnum)) + if l:end != [0, 0] + " find the matched opening bracket on another line, + let l:c = s:CharAtCursor(l:end[0], l:end[1]) + let l:start = searchpairpos(escape(tr(l:c, ')]}', '([{'), '['), '', escape(l:c, ']'), 'nbW', s:skip4) + if l:start[0] != l:end[0] + " and then this line has the same indent as the line the matched bracket stays. + "echomsg 'Closing Bracket' (l:start[0] . '-' . v:lnum) indent(l:start[0]) + let l:indent = indent(l:start[0]) + endif + endif + + unlet! l:start l:end l:c + endif + + " If this line starts the definition of a method, closure or match case, + if l:line =~# '^\s*=>' + " find the start of the definition, + call cursor(v:lnum, 1) + let l:start = searchpairpos('\v<%(new|be|fun|lambda)>|\|', '', '=>\zs', 'bnW', s:skip3) + if l:start != [0, 0] + " then this line has the same indent as the start. + "echomsg 'Method body' (l:start[0] . '-' . v:lnum) indent(l:start[0]) + return indent(l:start[0]) + endif + + unlet! l:start + endif + + " If this line starts a class definition or starts an alias, + if l:line =~# '\v^\s*%(actor|class|struct|primitive|trait|interface|use|type)>' + " reset the indent level. + return 0 + endif + + " If this line starts a method definition, + if l:line =~# '\v^\s*%(new|be|fun)>' + call cursor(v:lnum, 1) + let l:start = searchpairpos(s:cfstart, s:cfmiddle, s:cfend, 'bW', s:skip3) + if l:start != [0, 0] + let l:start = searchpos(s:bstartp, 'zcnpW', l:start[0]) + " see if it is in an object block, + if l:start[2] == 3 + "echomsg 'Method in object' (l:start[0] . '-' . v:lnum) (l:shiftwidth + indent(l:start[0])) + return l:shiftwidth + indent(l:start[0]) + endif + endif + return l:shiftwidth + endif + + " If this line starts a match case, + call cursor(v:lnum, 1) + if l:line =~# '^\s*|' && s:InKeyword(searchpos('|', 'znW', v:lnum)) + " find the start or the previous case of the match block, + let l:start = searchpairpos(s:cfstart, s:cfmiddle, s:cfend, 'bnW', s:skip3) + if l:start != [0, 0] + " then this line has the same indent as the start. + "echomsg 'Match case' (l:start[0] . '-' . v:lnum) indent(l:start[0]) + return indent(l:start[0]) + endif + + unlet! l:start + endif + + " If this line ends (part of) a control flow, + if l:line =~# '\v^\s*%(end|elseif|else|then|in|do|until|elseiftype)>' + " find the start or middle of the control block, + call cursor(v:lnum, 1) + let l:start = searchpairpos(s:cfstart, s:cfmiddle, s:cfend, 'bnW', s:skip3) + if l:start != [0, 0] + " then this line has the same indent as the start. + "echomsg 'Block end' (l:start[0] . '-' . v:lnum) indent(l:start[0]) + return indent(l:start[0]) + endif + + unlet! l:start + endif + + " If the previous line starts a class definition, + if l:pnbline =~# '\v^\s*%(actor|class|struct|primitive|trait|type|interface)>' + " reset the indent level. + if s:IsContinued(l:pnblnum) + return l:shiftwidth * 2 + else + return l:shiftwidth + endif + endif + + " If the previous line starts a method definition, + if l:pnbline =~# '\v^\s*%(new|be|fun)>' + return l:pnbindent + l:shiftwidth + endif + + " If the previous line starts (part of) a control flow, + call cursor(l:pnblnum, 1) + while 1 + " find the start of the control block, + let l:start = searchpos(s:bstartp, 'zcepW', l:pnblnum) + if l:start[2] == 0 + break + endif + if !s:InKeyword(l:start[0:1]) + call cursor(l:pnblnum, l:start[1] + 3) + continue + endif + let l:index = l:start[2] + " find the end of the control block on the same line, + let l:end = searchpair(s:cfstart, '', s:cfend, 'znW', s:skip3, l:pnblnum) + " if the control block is not ended, + if l:end < 1 + " if this line is a case for a match, + if l:index == 2 && l:line =~# '^\s*|' + " then this line has the same indent as the start of the match block. + return l:pnbindent + else + " then indent this line. + "echomsg 'Block start' (l:pnblnum . '-' . v:lnum) (l:pnbindent + l:shiftwidth) + return l:pnbindent + l:shiftwidth + endif + endif + endwhile + + unlet! l:start l:end l:index + + return l:indent +endfunction + +function! s:PrevNonblank(lnum) + let l:lnum = prevnonblank(a:lnum) + while l:lnum > 0 && (s:InComment2(l:lnum, 1) || s:InLiteral2(l:lnum, 1)) + let l:lnum = prevnonblank(l:lnum - 1) + endwhile + return l:lnum +endfunction + +" NOTE: +" v +" |1 /* comment */ +" |2 +function! s:IsContinued(lnum) + let l:lnum = s:PrevNonblank(a:lnum) + if l:lnum < 1 + return 0 + endif + let l:line = getline(l:lnum) + let l:width = strwidth(substitute(l:line, '\s*$', '', '')) + " FIXME? + " | 1 + // + " | // + " | 2 + return !s:InCommentOrLiteral(a:lnum, l:width) + \ && (l:line =~# '\v<%(and|or|xor|is|isnt|as|not|consume|addressof|digestof)\s*$' + \ || l:line =~# '\v%([=\-.]\>|[]\=\~?|\<\<\~?|\>\>\~?|\<:|[+\-*/%<>]\~?|[.,|:@~])\s*$' + \ ) +endfunction + +function! s:InCommentOrLiteral(...) + return call('s:InComment', a:000) || call('s:InLiteral', a:000) +endfunction + +function! s:InKeyword(...) + let [l:lnum, l:col] = (type(a:1) == type([]) ? a:1 : a:000) + for id in s:Or(synstack(l:lnum, l:col), []) + if synIDattr(id, 'name') =~# '^ponyKw' + return 1 + endif + endfor + return 0 +endfunction + +function! s:InBracket(...) + let [l:lnum, l:col] = (type(a:1) == type([]) ? a:1 : a:000) + for id in s:Or(synstack(l:lnum, l:col), []) + if synIDattr(id, 'name') ==# 'ponyBracket' + return 1 + endif + endfor + return 0 +endfunction + +function! s:InComment(...) + let [l:lnum, l:col] = (type(a:1) == type([]) ? a:1 : a:000) + let l:stack = synstack(l:lnum, l:col) + let l:i = len(l:stack) + while l:i > 0 + let l:sname = synIDattr(l:stack[l:i - 1], 'name') + if l:sname =~# '^ponyNestedCommentX\?$' + return 1 + l:i - (l:sname =~# 'X$') + elseif l:sname =~# '^ponyCommentX\?$' + return 1 + endif + let l:i -= 1 + endwhile + return 0 +endfunction + +function! s:InLiteral(...) + let [l:lnum, l:col] = (type(a:1) == type([]) ? a:1 : a:000) + let l:stack = synstack(l:lnum, l:col) + let l:i = len(l:stack) + while l:i > 0 + let l:sname = synIDattr(l:stack[l:i - 1], 'name') + if l:sname =~# '^ponyDocumentStringX\?$' + return 3 + elseif l:sname =~# '^ponyStringX\?$' + return 2 + elseif l:sname =~# '^ponyCharacterX\?$' + return 1 + endif + let l:i -= 1 + endwhile + return 0 +endfunction + +" NOTE: +" |// //inside +" ^^^^^^^^^^ +" |/* /*inside*/ */ +" ^^^^^^^^^^^^^^ +function! s:InComment2(...) + let [l:lnum, l:col] = (type(a:1) == type([]) ? a:1 : a:000) + let l:stack = synstack(l:lnum, l:col) + let l:i = len(l:stack) + while l:i > 0 + let l:sname = synIDattr(l:stack[l:i - 1], 'name') + if l:sname ==# 'ponyNestedComment' + return 1 + l:i + elseif l:sname ==# 'ponyComment' + return 1 + elseif l:sname =~# '\v^pony%(Nested)?CommentX$' + return 0 + endif + let l:i -= 1 + endwhile + return 0 +endfunction + +" NOTE: +" |"inside" +" ^^^^^^ +" |"""inside""""" +" ^^^^^^^^^^^^ +function! s:InLiteral2(...) + let [l:lnum, l:col] = (type(a:1) == type([]) ? a:1 : a:000) + let l:stack = synstack(l:lnum, l:col) + let l:i = len(l:stack) + while l:i > 0 + let l:sname = synIDattr(l:stack[l:i - 1], 'name') + if l:sname ==# 'ponyDocumentString' + return 3 + elseif l:sname ==# 'ponyString' + return 2 + elseif l:sname ==# 'ponyCharacter' + return 1 + elseif l:sname =~# '\v^pony%(DocumentString|String|Character)X$' + return 0 + endif + let l:i -= 1 + endwhile + return 0 +endfunction + +function! s:CharAtCursor(...) + let [l:lnum, l:col] = (type(a:1) == type([]) ? a:1 : a:000) + return matchstr(getline(l:lnum), '\%' . l:col . 'c.') +endfunction + +function! s:Or(x, y) + return !empty(a:x) ? a:x : a:y +endfunction + +function! s:InnerPos(x, y) + if a:x == [0, 0] + return a:y + elseif a:y == [0, 0] + return a:x + else + return a:x[1] < a:y[1] ? a:x : a:y + end +endfunction + +function! s:OuterPos(x, y) + if a:x == [0, 0] + return a:y + elseif a:y == [0, 0] + return a:x + else + return a:x[1] > a:y[1] ? a:x : a:y + end +endfunction + +function! pony#ClearTrailingSpace(all, alt, ...) + let l:force = (a:0 > 0 ? a:1 : 0) + if !l:force && (&readonly || !&modifiable || !&modified) + return + endif + if a:all + for lnum in range(1, line('$')) + let l:line = getline(lnum) + let l:end = col([lnum, '$']) - 1 + if l:end > 0 && l:line =~# '\s$' && !s:InLiteral(lnum, l:end) + if a:alt + call setline(lnum, substitute(l:line, '\S\@<=\s\s*$', '', '')) + else + call setline(lnum, substitute(l:line, '\s\+$', '', '')) + endif + endif + endfor + else + let l:lnum = line('.') + let l:end = col('$') - 1 + let l:line = getline(l:lnum) + if l:line =~# '\s$' && !s:InLiteral(l:lnum, l:end) + if a:alt + call setline(l:lnum, substitute(l:line, '\s\+$', '', '')) + else + call setline(l:lnum, substitute(l:line, '\S\@<=\s\s*$', '', '')) + endif + endif + endif +endfunction + + +let &cpo = s:cpo_save +unlet s:cpo_save + +endif diff --git a/build b/build index 8346a91..9b5d6f1 100755 --- a/build +++ b/build @@ -225,6 +225,7 @@ PACKS=" pgsql:exu/pgsql.vim php:StanAngeloff/php.vim plantuml:aklt/plantuml-syntax + pony:jakwings/vim-pony powershell:PProvost/vim-ps1 protobuf:uarun/vim-protobuf pug:digitaltoad/vim-pug diff --git a/ftdetect/polyglot.vim b/ftdetect/polyglot.vim index 62aaf3a..888f78e 100644 --- a/ftdetect/polyglot.vim +++ b/ftdetect/polyglot.vim @@ -795,6 +795,13 @@ au BufNewFile,BufRead *.pgsql setf pgsql augroup end endif +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'pony') == -1 + augroup filetypedetect + " pony, from pony.vim in jakwings/vim-pony +autocmd BufRead,BufNewFile *.pony setf pony + augroup end +endif + if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'powershell') == -1 augroup filetypedetect " powershell, from ps1.vim in PProvost/vim-ps1 diff --git a/ftplugin/pony.vim b/ftplugin/pony.vim new file mode 100644 index 0000000..eef6824 --- /dev/null +++ b/ftplugin/pony.vim @@ -0,0 +1,44 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'pony') == -1 + +" Vim filetype plugin file +" Language: Pony +" Maintainer: Jak Wings + +if exists('b:did_ftplugin') + finish +endif + +let s:cpo_save = &cpo +set cpo&vim + + +setlocal comments=://,nsr:/*,mb:*,ex:*/ +setlocal commentstring=/*%s*/ +setlocal formatoptions-=t fo+=c fo+=r fo+=o fo+=q fo+=l fo+=j + +"setlocal path= +"setlocal includeexpr= +setlocal include=\\v^\\s*use\\_s+%(\\i+\\_s*\\=\\_s*)?"\\zs[^"]*\\ze" +setlocal define=\\v^\\s*%(actor\|class\|struct\|primitive\|trait\|interface\|type\|new\|be\|fun\|let\|var\|embed\|use\|for\\_s+%(\\i+\\_s*,\\_s*)*\|with\\_s+%(\\i+\\_s*,\\_s*)*)\|(<\\i+\\_s*:\\_s*\\i+)@= +setlocal isident=@,48-57,_,39 +setlocal iskeyword=@,48-57,_,39 +setlocal suffixesadd=.pony +setlocal matchpairs=(:),{:},[:] + +let b:match_ignorecase = 0 +let b:match_skip = 's:Comment\|String\|Character\|CaseGuard' +let b:match_words = '\v<%(ifdef|if|match|while|for|repeat|try|with|recover|object|lambda|iftype)>\m:\v<%(then|elseif|else|until|do|in|elseiftype)>|\|\m:\,(:),\[:\],{:}' +" TODO: for more concise behavior +"let b:match_words = 'pony#GetMatchWords()' +source $VIMRUNTIME/macros/matchit.vim + +let b:undo_ftplugin = 'set comments< commentstring< formatoptions< path< include< includeexpr< define< isident< iskeyword< suffixesadd< matchpairs<' + \ . ' | unlet! b:match_ignorecase b:match_skip b:match_words' + + +let &cpo = s:cpo_save +unlet s:cpo_save + +let b:did_ftplugin = 1 + +endif diff --git a/indent/pony.vim b/indent/pony.vim new file mode 100644 index 0000000..613dae6 --- /dev/null +++ b/indent/pony.vim @@ -0,0 +1,41 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'pony') == -1 + +" Vim indent file +" Language: Pony +" Maintainer: Jak Wings + +if exists('b:did_indent') + finish +endif + +let s:cpo_save = &cpo +set cpo&vim + + +setlocal nolisp +setlocal nocindent +setlocal nosmartindent +setlocal autoindent +setlocal indentexpr=pony#Indent() +setlocal indentkeys=!^F,o,O,0\|,0(,0),0[,0],0{,0},0==>,0=\"\"\",0=end,0=then,0=else,0=in,0=do,0=until,0=actor,0=class,0=struct,0=primitive,0=trait,0=interface,0=new,0=be,0=fun,0=type,0=use +setlocal cinkeys=!^F,o,O,0\|,0(,0),0[,0],0{,0},0==>,0=\"\"\",0=end,0=then,0=else,0=in,0=do,0=until,0=actor,0=class,0=struct,0=primitive,0=trait,0=interface,0=new,0=be,0=fun,0=type,0=use +setlocal cinwords=ifdef,if,match,while,for,repeat,try,with,recover,object,lambda,then,elseif,else,until,do,actor,class,struct,primitive,trait,interface,new,be,fun,iftype,elseiftype + +augroup pony + autocmd! * + autocmd CursorHold call pony#ClearTrailingSpace(1, 1) + "autocmd InsertEnter call pony#ClearTrailingSpace(0, 0) + autocmd InsertLeave call pony#ClearTrailingSpace(0, 1) + autocmd BufWritePre call pony#ClearTrailingSpace(1, 0, 1) +augroup END + +let b:undo_indent = 'set lisp< cindent< autoindent< smartindent< indentexpr< indentkeys< cinkeys< cinwords<' + \ . ' | execute("autocmd! pony * ")' + + +let &cpo = s:cpo_save +unlet s:cpo_save + +let b:did_indent = 1 + +endif diff --git a/syntax/pony.vim b/syntax/pony.vim new file mode 100644 index 0000000..56899f8 --- /dev/null +++ b/syntax/pony.vim @@ -0,0 +1,231 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'pony') == -1 + +" Vim syntax file +" Language: Pony +" Maintainer: Jak Wings + +if exists('b:current_syntax') + finish +endif + +let s:cpo_save = &cpo +set cpo&vim + + +syn case match + +syn sync match ponySync grouphere NONE /\v^\s*%(actor|class|struct|primitive|trait|interface|new|be|fun|let|var|embed|use)>/ + +syn match ponyErrSymbol /['^!$&\`]/ +hi def link ponyErrSymbol Error + +syn match ponyErrNumGroup /__\+/ contained +hi def link ponyErrNumGroup Error + +syn match ponyPeriodComma /,/ nextgroup=ponyEllipsis,ponyErrOperator skipwhite +syn match ponyPeriodComma /\./ nextgroup=ponyTupleIndex,ponyErrOperator skipwhite +syn match ponyPeriodComma /;/ nextgroup=ponyErrOperator skipwhite +hi def link ponyPeriodComma Operator + +syn match ponyBracket /[{[()\]}]/ + +syn match ponyErrNormal /\v_>|<%([^_a-z]|_[^a-z])|__+/ contained +hi def link ponyErrNormal Error +syn match ponyNormal /\v_?[_a-z]\w*'*/ contains=ponyErrNormal nextgroup=ponyGeneric skipwhite + +syn match ponyInteger /\v%(\d+_*)+/ contains=ponyErrNumGroup +syn match ponyErrIntDec /\v(0[xX])@<=[_.g-zG-Z]/ +syn match ponyErrIntHex /[.g-zG-Z]/ contained +syn match ponyInteger /\v0[xX]%(\x+_*)+/ contains=ponyErrNumGroup nextgroup=ponyErrIntHex +syn match ponyErrIntDec /\v(0[bB])@<=[_2-9a-zA-Z]/ +syn match ponyErrIntBin /[2-9.a-zA-Z]/ contained +syn match ponyInteger /\v0[bB]%([01]+_*)+/ contains=ponyErrNumGroup nextgroup=ponyErrIntBin +hi def link ponyErrIntDec Error +hi def link ponyErrIntHex Error +hi def link ponyErrIntBin Error +hi def link ponyInteger Number + +syn match ponyFloat /\v%(\d+_*)+[eE][-+]?%(\d+_*)+/ contains=ponyErrNumGroup +syn match ponyFloat /\v%(\d+_*)+\.%(\d+_*)+%([eE][-+]?%(\d+_*)+)?/ contains=ponyErrNumGroup +hi def link ponyFloat Float + +syn match ponyErrUserVariable /\v_>|<%([^_a-z]|_[^a-z])|__+/ contained +hi def link ponyErrUserVariable Error +syn match ponyUserVariable /\v[_a-zA-Z]\w*'*/ contained contains=ponyErrUserVariable +hi def link ponyUserVariable Identifier +syn match ponyErrUserPackage /\<[^a-z]/ contained +hi def link ponyErrUserPackage Error +syn match ponyUserPackage /\v[_a-zA-Z]\w*/ contained contains=ponyErrUserPackage +hi def link ponyUserPackage Identifier +syn match ponyErrUserType /\v_>|\a@<=_|<%([^_A-Z]|_[^A-Z])/ contained +hi def link ponyErrUserType Error +syn match ponyUserType2 /\v[_a-zA-Z]\w*/ contained contains=ponyErrUserType nextgroup=ponyTypeSuffix,ponyTypeOperator2,ponyKwOperatorT,ponyGeneric,ponyArgument skipwhite +syn match ponyUserType /\v_?[A-Z]\w*/ contains=ponyErrUserType nextgroup=ponyTypeSuffix,ponyTypeOperator2,ponyKwOperatorT,ponyGeneric,ponyArgument skipwhite +syn match ponyErrUserMethod /\v_>|<%([^_a-z]|_[^a-z])|__+/ contained +hi def link ponyErrUserMethod Error +syn match ponyUserMethod /\v[_a-zA-Z]\w*/ contained contains=ponyErrUserMethod nextgroup=ponyGeneric,ponyArgument,ponyBracketT2 skipwhite +hi def link ponyUserMethod Function +syn match ponyForeignFunction /\v[_a-zA-Z]\w*/ contained nextgroup=ponyGeneric skipwhite +hi def link ponyForeignFunction Macro +syn match ponyErrTupleIndex /\v_0+>/ contained +hi def link ponyErrTupleIndex Error +syn match ponyTupleIndex /\v_\d+\w@!/ contained contains=ponyErrTupleIndex +hi def link ponyTupleIndex Normal + +syn keyword ponyBoolean true false +hi def link ponyBoolean Boolean + +syn region ponyBracketT1 matchgroup=ponyBracket start=/(/ end=/)/ contained contains=@ponyComments,@ponyKeyword,@ponyType,@ponyBracketT,@ponyTypeOperator,ponySymbol,ponyPeriodComma nextgroup=ponyTypeSuffix,ponyTypeOperator2,ponyKwOperatorT,ponyArgument skipwhite +syn region ponyBracketT2 matchgroup=ponyBracket start=/\[/ end=/\]/ contained contains=@ponyComments,@ponyKeyword,@ponyType,@ponyBracketT,@ponyTypeOperator,ponySymbol,ponyPeriodComma nextgroup=ponyTypeSuffix,ponyTypeOperator2,ponyKwOperatorT,ponyArgument skipwhite +syn region ponyBracketT3 matchgroup=ponyBracket start=/{/ end=/}/ contained contains=@ponyComments,@ponyKeyword,@ponyType,@ponyBracketT,@ponyTypeOperator,ponySymbol,ponyPeriodComma nextgroup=ponyTypeSuffix,ponyTypeOperator2,ponyKwOperatorT,ponyArgument skipwhite +syn cluster ponyBracketT contains=ponyBracketT\d + +syn region ponyGeneric matchgroup=ponyBracketT2 start=/\[/ end=/\]/ contained contains=@ponyComments,@ponyKeyword,@ponyType,@ponyBracketT,@ponyTypeOperator,ponySymbol,ponyPeriodComma nextgroup=ponyTypeSuffix,ponyTypeOperator2,ponyKwOperatorT,ponyArgument skipwhite + +syn region ponyArgument matchgroup=ponyBracket start=/(/ end=/)/ contained contains=TOP nextgroup=ponyArgument skipwhite + +syn match ponyTypeSuffix /[!^]/ contained nextgroup=ponyArgument,ponyKwOperatorT skipwhite +hi def link ponyTypeSuffix StorageClass + +syn match ponyTypeOperator1 /[&|]/ contained nextgroup=@ponyBracketT,@ponyKeyword,@ponyType skipwhite skipempty +hi def link ponyTypeOperator1 Operator + +syn match ponyTypeOperator2 /->\|<:/ contained nextgroup=@ponyBracketT,@ponyKeyword,@ponyType skipwhite skipempty +hi def link ponyTypeOperator2 Operator + +syn cluster ponyTypeOperator contains=ponyTypeOperator\d + +syn match ponyErrOperator /[-.]>\|<:\|\%(==\|!=\|<<\|>>\|<=\|>=\|[+*/%<>]\)\~\?\|[~.,]/ contained nextgroup=ponyErrOperator skipwhite +hi def link ponyErrOperator Error + +syn match ponyObjectOperator /\%(==\|!=\|<<\|>>\|<=\|>=\|[+\-*/%<>]\)\~\?\|\~\|\.>/ nextgroup=ponyErrOperator skipwhite +hi def link ponyObjectOperator Operator + +syn keyword ponyKwOperatorT is contained nextgroup=@ponyBracketT,@ponyKeyword,@ponyType skipwhite skipempty +hi def link ponyKwOperatorT Operator + +syn keyword ponyKwOperator as nextgroup=@ponyBracketT,@ponyKeyword,@ponyType skipwhite skipempty +syn keyword ponyKwOperator and or xor not is isnt consume addressof digestof +hi def link ponyKwOperator Operator + +syn match ponySymbol /=>\|[?#]/ +syn match ponySymbol /@/ nextgroup=ponyForeignFunction skipwhite skipempty +syn match ponySymbol /:/ nextgroup=@ponyKeyword,@ponyType,@ponyBracketT skipwhite skipempty +hi def link ponySymbol Special + +syn match ponyEllipsis /\.\{3}/ contained containedin=ponyArgument +hi def link ponyEllipsis Special + +syn region ponyLambda matchgroup=ponyBracketLambda start=/{/ end=/}/ contains=ponyArgument,@ponyComments,@ponyKeyword,@ponyType,@ponyTypeOperator,ponySymbol,ponyPeriodComma,ponyLambdaBody nextgroup=ponyArgument skipwhite +syn match ponyLambdaBody /=>\_.*}/me=e-1 contained contains=TOP +hi def link ponyBracketLambda Special + +" $scripts/gen_id.sh $packages/builtin +syn keyword ponyBuiltinType AmbientAuth Any Array ArrayKeys ArrayPairs + \ ArrayValues AsioEvent AsioEventID + \ AsioEventNotify Bool ByteSeq ByteSeqIter + \ Comparable Compare DisposableActor + \ DoNotOptimise Env Equal Equatable F32 F64 + \ Float FloatingPoint Greater HasEq I128 I16 I32 + \ I64 I8 ILong ISize Int Integer Iterator Less + \ MaybePointer None Number OutStream Platform + \ Pointer ReadElement ReadSeq Real Seq Signed + \ SourceLoc StdStream Stdin StdinNotify String + \ StringBytes StringRunes Stringable U128 U16 + \ U32 U64 U8 ULong USize Unsigned + \ nextgroup=ponyTypeSuffix,ponyTypeOperator2,ponyKwOperatorT,ponyGeneric,ponyArgument skipwhite +hi def link ponyBuiltinType Type + +syn keyword ponyKwControl end if else do then elseif match while for in + \ repeat until ifdef try with recover return + \ break continue error compile_intrinsic + \ compile_error iftype elseiftype +hi def link ponyKwControl Keyword + +syn keyword ponyCaseGuard if contained containedin=ponyMatchCase +hi def link ponyCaseGuard Keyword + +syn region ponyMatchCase matchgroup=ponyKwBranchHead start=/|/ matchgroup=ponySymbol end=/=>/ contains=TOP +hi def link ponyKwBranchHead Keyword + +syn keyword ponyKwAtom this nextgroup=ponyTypeOperator2 skipwhite skipempty +syn keyword ponyKwAtom object __loc +syn keyword ponyKwAtom lambda nextgroup=ponyArgument skipwhite +hi def link ponyKwAtom Keyword + +syn keyword ponyKwField let var embed nextgroup=@ponyKeyword,ponyUserVariable skipwhite skipempty +hi def link ponyKwField Keyword + +syn keyword ponyKwUse use nextgroup=ponyString,@ponyKeyword,ponyUserPackage skipwhite skipempty +hi def link ponyKwUse Include + +syn keyword ponyKwWhere where +hi def link ponyKwWhere Keyword + +syn keyword ponyKwTypedef type nextgroup=@ponyKeyword,@ponyType2 skipwhite skipempty +hi def link ponyKwTypedef Typedef + +syn match ponyKwCapability /\v#%(read|send|share|alias|any)>/ nextgroup=ponyTypeSuffix,ponyTypeOperator2,ponyKwOperatorT skipwhite +syn keyword ponyKwCapability ref val tag iso box trn nextgroup=ponyTypeSuffix,ponyTypeOperator2,ponyKwOperatorT,ponyArgument skipwhite +hi def link ponyKwCapability StorageClass + +syn keyword ponyKwClass actor class struct primitive trait interface nextgroup=@ponyKeyword,@ponyType2 skipwhite skipempty +hi def link ponyKwClass Structure + +syn keyword ponyKwFnCapability ref val tag iso box trn contained nextgroup=@ponyKeyword,ponyUserMethod skipwhite skipempty +hi def link ponyKwFnCapability StorageClass +syn keyword ponyKwFunction new be fun nextgroup=ponyKwFnCapability,@ponyKeyword,ponyUserMethod skipwhite skipempty +hi def link ponyKwFunction Keyword + +syn cluster ponyKeyword contains=ponyKw.*,ponyBoolean,ponyBuiltinType remove=ponyKwOperatorT,ponyKwFnCapability,ponyKwBranchHead +syn cluster ponyType contains=ponyBuiltinType,ponyUserType,ponyNormal +syn cluster ponyType2 contains=ponyBuiltinType,ponyUserType2 +syn cluster ponyComments contains=ponyNestedComment,ponyComment + +syn match ponyErrEscape /\\\_.\?\_s*/ contained +hi def link ponyErrEscape Error +syn match ponyEscapeSQuote /\\'/ contained +hi def link ponyEscapeSQuote SpecialChar +syn match ponyEscapeDQuote /\\"/ contained +hi def link ponyEscapeDQuote SpecialChar +syn match ponyEscape /\\[abefnrtv\\0]/ contained +syn match ponyEscape /\v\\x\x{2}/ contained +syn match ponyEscape /\v\\u\x{4}/ contained +syn match ponyEscape /\v\\U\x{6}/ contained +hi def link ponyEscape SpecialChar + +syn region ponyCharacter matchgroup=ponyCharacterX start=/\w\@