From 5b77877888162f4e415fe9a7b8c5e9fb5dfb6ee1 Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Wed, 27 Sep 2017 20:43:42 +0200 Subject: Add syntax files from upstream vim repository --- indent/aap.vim | 16 + indent/ada.vim | 312 +++++++++++ indent/ant.vim | 16 + indent/automake.vim | 15 + indent/awk.vim | 236 ++++++++ indent/bib.vim | 19 + indent/bst.vim | 79 +++ indent/bzl.vim | 98 ++++ indent/c.vim | 19 + indent/cdl.vim | 133 +++++ indent/ch.vim | 22 + indent/chaiscript.vim | 54 ++ indent/changelog.vim | 18 + indent/clojure.vim | 398 +++++++++++++ indent/cmake.vim | 93 ++++ indent/cobol.vim | 220 ++++++++ indent/config.vim | 86 +++ indent/context.vim | 40 ++ indent/cpp.vim | 19 + indent/cs.vim | 19 + indent/css.vim | 88 +++ indent/cucumber.vim | 79 +++ indent/cuda.vim | 19 + indent/d.vim | 26 + indent/dictconf.vim | 17 + indent/dictdconf.vim | 17 + indent/docbk.vim | 19 + indent/dtd.vim | 329 +++++++++++ indent/dtrace.vim | 21 + indent/dylan.vim | 94 ++++ indent/eiffel.vim | 119 ++++ indent/erlang.vim | 1394 ++++++++++++++++++++++++++++++++++++++++++++++ indent/eruby.vim | 109 ++++ indent/eterm.vim | 40 ++ indent/falcon.vim | 455 +++++++++++++++ indent/fortran.vim | 222 ++++++++ indent/framescript.vim | 45 ++ indent/gitconfig.vim | 42 ++ indent/gitolite.vim | 49 ++ indent/go.vim | 70 +++ indent/haml.vim | 78 +++ indent/hamster.vim | 59 ++ indent/hog.vim | 81 +++ indent/html.vim | 1056 +++++++++++++++++++++++++++++++++++ indent/htmldjango.vim | 16 + indent/idlang.vim | 66 +++ indent/ishd.vim | 72 +++ indent/j.vim | 54 ++ indent/java.vim | 154 +++++ indent/javascript.vim | 453 +++++++++++++++ indent/json.vim | 172 ++++++ indent/jsp.vim | 21 + indent/ld.vim | 88 +++ indent/less.vim | 17 + indent/lifelines.vim | 28 + indent/liquid.vim | 67 +++ indent/lisp.vim | 19 + indent/logtalk.vim | 65 +++ indent/lua.vim | 67 +++ indent/mail.vim | 17 + indent/make.vim | 120 ++++ indent/matlab.vim | 78 +++ indent/mf.vim | 10 + indent/mma.vim | 79 +++ indent/mp.vim | 364 ++++++++++++ indent/objc.vim | 83 +++ indent/ocaml.vim | 277 +++++++++ indent/occam.vim | 191 +++++++ indent/pascal.vim | 232 ++++++++ indent/perl.vim | 184 ++++++ indent/perl6.vim | 136 +++++ indent/php.vim | 853 ++++++++++++++++++++++++++++ indent/postscr.vim | 72 +++ indent/pov.vim | 88 +++ indent/prolog.vim | 62 +++ indent/pyrex.vim | 17 + indent/python.vim | 202 +++++++ indent/r.vim | 525 +++++++++++++++++ indent/readline.vim | 40 ++ indent/rhelp.vim | 112 ++++ indent/rmd.vim | 51 ++ indent/rnoweb.vim | 51 ++ indent/rpl.vim | 67 +++ indent/rrst.vim | 51 ++ indent/rst.vim | 63 +++ indent/ruby.vim | 699 +++++++++++++++++++++++ indent/rust.vim | 217 ++++++++ indent/sas.vim | 142 +++++ indent/sass.vim | 42 ++ indent/scala.vim | 613 ++++++++++++++++++++ indent/scheme.vim | 15 + indent/scss.vim | 16 + indent/sdl.vim | 97 ++++ indent/sh.vim | 203 +++++++ indent/sml.vim | 221 ++++++++ indent/sql.vim | 43 ++ indent/sqlanywhere.vim | 397 +++++++++++++ indent/systemd.vim | 14 + indent/systemverilog.vim | 234 ++++++++ indent/tcl.vim | 79 +++ indent/tcsh.vim | 53 ++ indent/teraterm.vim | 59 ++ indent/tex.vim | 421 ++++++++++++++ indent/tf.vim | 76 +++ indent/tilde.vim | 40 ++ indent/treetop.vim | 42 ++ indent/vb.vim | 82 +++ indent/verilog.vim | 233 ++++++++ indent/vhdl.vim | 438 +++++++++++++++ indent/vim.vim | 106 ++++ indent/vroom.vim | 25 + indent/xf86conf.vim | 41 ++ indent/xhtml.vim | 16 + indent/xinetd.vim | 59 ++ indent/xml.vim | 111 ++++ indent/xsd.vim | 17 + indent/xslt.vim | 17 + indent/yacc.vim | 45 ++ indent/yaml.vim | 159 ++++++ indent/zimbu.vim | 132 +++++ indent/zsh.vim | 18 + 121 files changed, 17046 insertions(+) create mode 100644 indent/aap.vim create mode 100644 indent/ada.vim create mode 100644 indent/ant.vim create mode 100644 indent/automake.vim create mode 100644 indent/awk.vim create mode 100644 indent/bib.vim create mode 100644 indent/bst.vim create mode 100644 indent/bzl.vim create mode 100644 indent/c.vim create mode 100644 indent/cdl.vim create mode 100644 indent/ch.vim create mode 100644 indent/chaiscript.vim create mode 100644 indent/changelog.vim create mode 100644 indent/cmake.vim create mode 100644 indent/cobol.vim create mode 100644 indent/config.vim create mode 100644 indent/context.vim create mode 100644 indent/cpp.vim create mode 100644 indent/cs.vim create mode 100644 indent/css.vim create mode 100644 indent/cuda.vim create mode 100644 indent/d.vim create mode 100644 indent/dictconf.vim create mode 100644 indent/dictdconf.vim create mode 100644 indent/docbk.vim create mode 100644 indent/dtd.vim create mode 100644 indent/dtrace.vim create mode 100644 indent/dylan.vim create mode 100644 indent/eiffel.vim create mode 100644 indent/eterm.vim create mode 100644 indent/falcon.vim create mode 100644 indent/fortran.vim create mode 100644 indent/framescript.vim create mode 100644 indent/gitolite.vim create mode 100644 indent/hamster.vim create mode 100644 indent/hog.vim create mode 100644 indent/htmldjango.vim create mode 100644 indent/idlang.vim create mode 100644 indent/ishd.vim create mode 100644 indent/j.vim create mode 100644 indent/java.vim create mode 100644 indent/jsp.vim create mode 100644 indent/ld.vim create mode 100644 indent/lifelines.vim create mode 100644 indent/lisp.vim create mode 100644 indent/logtalk.vim create mode 100644 indent/mail.vim create mode 100644 indent/make.vim create mode 100644 indent/matlab.vim create mode 100644 indent/mf.vim create mode 100644 indent/mma.vim create mode 100644 indent/mp.vim create mode 100644 indent/objc.vim create mode 100644 indent/occam.vim create mode 100644 indent/pascal.vim create mode 100644 indent/perl6.vim create mode 100644 indent/php.vim create mode 100644 indent/postscr.vim create mode 100644 indent/pov.vim create mode 100644 indent/prolog.vim create mode 100644 indent/pyrex.vim create mode 100644 indent/r.vim create mode 100644 indent/readline.vim create mode 100644 indent/rhelp.vim create mode 100644 indent/rmd.vim create mode 100644 indent/rnoweb.vim create mode 100644 indent/rpl.vim create mode 100644 indent/rrst.vim create mode 100644 indent/rst.vim create mode 100644 indent/sas.vim create mode 100644 indent/sass.vim create mode 100644 indent/scheme.vim create mode 100644 indent/scss.vim create mode 100644 indent/sdl.vim create mode 100644 indent/sh.vim create mode 100644 indent/sml.vim create mode 100644 indent/sql.vim create mode 100644 indent/sqlanywhere.vim create mode 100644 indent/systemd.vim create mode 100644 indent/systemverilog.vim create mode 100644 indent/tcl.vim create mode 100644 indent/tcsh.vim create mode 100644 indent/teraterm.vim create mode 100644 indent/tf.vim create mode 100644 indent/tilde.vim create mode 100644 indent/treetop.vim create mode 100644 indent/vb.vim create mode 100644 indent/verilog.vim create mode 100644 indent/vhdl.vim create mode 100644 indent/vim.vim create mode 100644 indent/vroom.vim create mode 100644 indent/xf86conf.vim create mode 100644 indent/xhtml.vim create mode 100644 indent/xinetd.vim create mode 100644 indent/xml.vim create mode 100644 indent/xsd.vim create mode 100644 indent/xslt.vim create mode 100644 indent/yacc.vim create mode 100644 indent/yaml.vim create mode 100644 indent/zimbu.vim create mode 100644 indent/zsh.vim (limited to 'indent') diff --git a/indent/aap.vim b/indent/aap.vim new file mode 100644 index 00000000..cddf5225 --- /dev/null +++ b/indent/aap.vim @@ -0,0 +1,16 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Aap recipe +" Maintainer: Bram Moolenaar +" Last Change: 2005 Jun 24 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif + +" Works mostly like Python. +runtime! indent/python.vim + +endif diff --git a/indent/ada.vim b/indent/ada.vim new file mode 100644 index 00000000..76d2395a --- /dev/null +++ b/indent/ada.vim @@ -0,0 +1,312 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +"------------------------------------------------------------------------------ +" Description: Vim Ada indent file +" Language: Ada (2005) +" $Id: ada.vim 887 2008-07-08 14:29:01Z krischik $ +" Copyright: Copyright (C) 2006 Martin Krischik +" Maintainer: Martin Krischik +" Neil Bird +" Ned Okie +" $Author: krischik $ +" $Date: 2008-07-08 16:29:01 +0200 (Di, 08 Jul 2008) $ +" Version: 4.6 +" $Revision: 887 $ +" $HeadURL: https://gnuada.svn.sourceforge.net/svnroot/gnuada/trunk/tools/vim/indent/ada.vim $ +" History: 24.05.2006 MK Unified Headers +" 16.07.2006 MK Ada-Mode as vim-ball +" 15.10.2006 MK Bram's suggestion for runtime integration +" 05.11.2006 MK Bram suggested to save on spaces +" 19.09.2007 NO g: missing before ada#Comment +" Help Page: ft-vim-indent +"------------------------------------------------------------------------------ +" ToDo: +" Verify handling of multi-line exprs. and recovery upon the final ';'. +" Correctly find comments given '"' and "" ==> " syntax. +" Combine the two large block-indent functions into one? +"------------------------------------------------------------------------------ + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") || version < 700 + finish +endif + +let b:did_indent = 45 + +setlocal indentexpr=GetAdaIndent() +setlocal indentkeys-=0{,0} +setlocal indentkeys+=0=~then,0=~end,0=~elsif,0=~when,0=~exception,0=~begin,0=~is,0=~record + +" Only define the functions once. +if exists("*GetAdaIndent") + finish +endif +let s:keepcpo= &cpo +set cpo&vim + +if exists("g:ada_with_gnat_project_files") + let s:AdaBlockStart = '^\s*\(if\>\|while\>\|else\>\|elsif\>\|loop\>\|for\>.*\<\(loop\|use\)\>\|declare\>\|begin\>\|type\>.*\[^;]*$\|\(type\>.*\)\=\\|procedure\>\|function\>\|accept\>\|do\>\|task\>\|package\>\|project\>\|then\>\|when\>\|is\>\)' +else + let s:AdaBlockStart = '^\s*\(if\>\|while\>\|else\>\|elsif\>\|loop\>\|for\>.*\<\(loop\|use\)\>\|declare\>\|begin\>\|type\>.*\[^;]*$\|\(type\>.*\)\=\\|procedure\>\|function\>\|accept\>\|do\>\|task\>\|package\>\|then\>\|when\>\|is\>\)' +endif + +" Section: s:MainBlockIndent {{{1 +" +" Try to find indent of the block we're in +" prev_indent = the previous line's indent +" prev_lnum = previous line (to start looking on) +" blockstart = expr. that indicates a possible start of this block +" stop_at = if non-null, if a matching line is found, gives up! +" No recursive previous block analysis: simply look for a valid line +" with a lesser or equal indent than we currently (on prev_lnum) have. +" This shouldn't work as well as it appears to with lines that are currently +" nowhere near the correct indent (e.g., start of line)! +" Seems to work OK as it 'starts' with the indent of the /previous/ line. +function s:MainBlockIndent (prev_indent, prev_lnum, blockstart, stop_at) + let lnum = a:prev_lnum + let line = substitute( getline(lnum), g:ada#Comment, '', '' ) + while lnum > 1 + if a:stop_at != '' && line =~ '^\s*' . a:stop_at && indent(lnum) < a:prev_indent + return a:prev_indent + elseif line =~ '^\s*' . a:blockstart + let ind = indent(lnum) + if ind < a:prev_indent + return ind + endif + endif + + let lnum = prevnonblank(lnum - 1) + " Get previous non-blank/non-comment-only line + while 1 + let line = substitute( getline(lnum), g:ada#Comment, '', '' ) + if line !~ '^\s*$' && line !~ '^\s*#' + break + endif + let lnum = prevnonblank(lnum - 1) + if lnum <= 0 + return a:prev_indent + endif + endwhile + endwhile + " Fallback - just move back one + return a:prev_indent - shiftwidth() +endfunction MainBlockIndent + +" Section: s:EndBlockIndent {{{1 +" +" Try to find indent of the block we're in (and about to complete), +" including handling of nested blocks. Works on the 'end' of a block. +" prev_indent = the previous line's indent +" prev_lnum = previous line (to start looking on) +" blockstart = expr. that indicates a possible start of this block +" blockend = expr. that indicates a possible end of this block +function s:EndBlockIndent( prev_indent, prev_lnum, blockstart, blockend ) + let lnum = a:prev_lnum + let line = getline(lnum) + let ends = 0 + while lnum > 1 + if getline(lnum) =~ '^\s*' . a:blockstart + let ind = indent(lnum) + if ends <= 0 + if ind < a:prev_indent + return ind + endif + else + let ends = ends - 1 + endif + elseif getline(lnum) =~ '^\s*' . a:blockend + let ends = ends + 1 + endif + + let lnum = prevnonblank(lnum - 1) + " Get previous non-blank/non-comment-only line + while 1 + let line = getline(lnum) + let line = substitute( line, g:ada#Comment, '', '' ) + if line !~ '^\s*$' + break + endif + let lnum = prevnonblank(lnum - 1) + if lnum <= 0 + return a:prev_indent + endif + endwhile + endwhile + " Fallback - just move back one + return a:prev_indent - shiftwidth() +endfunction EndBlockIndent + +" Section: s:StatementIndent {{{1 +" +" Return indent of previous statement-start +" (after we've indented due to multi-line statements). +" This time, we start searching on the line *before* the one given (which is +" the end of a statement - we want the previous beginning). +function s:StatementIndent( current_indent, prev_lnum ) + let lnum = a:prev_lnum + while lnum > 0 + let prev_lnum = lnum + let lnum = prevnonblank(lnum - 1) + " Get previous non-blank/non-comment-only line + while 1 + let line = substitute( getline(lnum), g:ada#Comment, '', '' ) + + if line !~ '^\s*$' && line !~ '^\s*#' + break + endif + let lnum = prevnonblank(lnum - 1) + if lnum <= 0 + return a:current_indent + endif + endwhile + " Leave indent alone if our ';' line is part of a ';'-delineated + " aggregate (e.g., procedure args.) or first line after a block start. + if line =~ s:AdaBlockStart || line =~ '(\s*$' + return a:current_indent + endif + if line !~ '[.=(]\s*$' + let ind = indent(prev_lnum) + if ind < a:current_indent + return ind + endif + endif + endwhile + " Fallback - just use current one + return a:current_indent +endfunction StatementIndent + + +" Section: GetAdaIndent {{{1 +" +" Find correct indent of a new line based upon what went before +" +function GetAdaIndent() + " Find a non-blank line above the current line. + let lnum = prevnonblank(v:lnum - 1) + let ind = indent(lnum) + let package_line = 0 + + " Get previous non-blank/non-comment-only/non-cpp line + while 1 + let line = substitute( getline(lnum), g:ada#Comment, '', '' ) + if line !~ '^\s*$' && line !~ '^\s*#' + break + endif + let lnum = prevnonblank(lnum - 1) + if lnum <= 0 + return ind + endif + endwhile + + " Get default indent (from prev. line) + let ind = indent(lnum) + let initind = ind + + " Now check what's on the previous line + if line =~ s:AdaBlockStart || line =~ '(\s*$' + " Check for false matches to AdaBlockStart + let false_match = 0 + if line =~ '^\s*\(procedure\|function\|package\)\>.*\' + " Generic instantiation + let false_match = 1 + elseif line =~ ')\s*;\s*$' || line =~ '^\([^(]*([^)]*)\)*[^(]*;\s*$' + " forward declaration + let false_match = 1 + endif + " Move indent in + if ! false_match + let ind = ind + shiftwidth() + endif + elseif line =~ '^\s*\(case\|exception\)\>' + " Move indent in twice (next 'when' will move back) + let ind = ind + 2 * shiftwidth() + elseif line =~ '^\s*end\s*record\>' + " Move indent back to tallying 'type' preceeding the 'record'. + " Allow indent to be equal to 'end record's. + let ind = s:MainBlockIndent( ind+shiftwidth(), lnum, 'type\>', '' ) + elseif line =~ '\(^\s*new\>.*\)\@' + " Multiple line generic instantiation ('package blah is\nnew thingy') + let ind = s:StatementIndent( ind - shiftwidth(), lnum ) + elseif line =~ ';\s*$' + " Statement end (but not 'end' ) - try to find current statement-start indent + let ind = s:StatementIndent( ind, lnum ) + endif + + " Check for potential argument list on next line + let continuation = (line =~ '[A-Za-z0-9_]\s*$') + + + " Check current line; search for simplistic matching start-of-block + let line = getline(v:lnum) + if line =~ '^\s*#' + " Start of line for ada-pp + let ind = 0 + elseif continuation && line =~ '^\s*(' + " Don't do this if we've already indented due to the previous line + if ind == initind + let ind = ind + shiftwidth() + endif + elseif line =~ '^\s*\(begin\|is\)\>' + let ind = s:MainBlockIndent( ind, lnum, '\(procedure\|function\|declare\|package\|task\)\>', 'begin\>' ) + elseif line =~ '^\s*record\>' + let ind = s:MainBlockIndent( ind, lnum, 'type\>\|for\>.*\', '' ) + shiftwidth() + elseif line =~ '^\s*\(else\|elsif\)\>' + let ind = s:MainBlockIndent( ind, lnum, 'if\>', '' ) + elseif line =~ '^\s*when\>' + " Align 'when' one /in/ from matching block start + let ind = s:MainBlockIndent( ind, lnum, '\(case\|exception\)\>', '' ) + shiftwidth() + elseif line =~ '^\s*end\>\s*\' + " End of if statements + let ind = s:EndBlockIndent( ind, lnum, 'if\>', 'end\>\s*\' ) + elseif line =~ '^\s*end\>\s*\' + " End of loops + let ind = s:EndBlockIndent( ind, lnum, '\(\(while\|for\)\>.*\)\?\', 'end\>\s*\' ) + elseif line =~ '^\s*end\>\s*\' + " End of records + let ind = s:EndBlockIndent( ind, lnum, '\(type\>.*\)\=\', 'end\>\s*\' ) + elseif line =~ '^\s*end\>\s*\' + " End of procedures + let ind = s:EndBlockIndent( ind, lnum, 'procedure\>.*\', 'end\>\s*\' ) + elseif line =~ '^\s*end\>\s*\' + " End of case statement + let ind = s:EndBlockIndent( ind, lnum, 'case\>.*\', 'end\>\s*\' ) + elseif line =~ '^\s*end\>' + " General case for end + let ind = s:MainBlockIndent( ind, lnum, '\(if\|while\|for\|loop\|accept\|begin\|record\|case\|exception\|package\)\>', '' ) + elseif line =~ '^\s*exception\>' + let ind = s:MainBlockIndent( ind, lnum, 'begin\>', '' ) + elseif line =~ '^\s*then\>' + let ind = s:MainBlockIndent( ind, lnum, 'if\>', '' ) + endif + + return ind +endfunction GetAdaIndent + +let &cpo = s:keepcpo +unlet s:keepcpo + +finish " 1}}} + +"------------------------------------------------------------------------------ +" Copyright (C) 2006 Martin Krischik +" +" Vim is Charityware - see ":help license" or uganda.txt for licence details. +"------------------------------------------------------------------------------ +" vim: textwidth=78 wrap tabstop=8 shiftwidth=3 softtabstop=3 noexpandtab +" vim: foldmethod=marker + +endif diff --git a/indent/ant.vim b/indent/ant.vim new file mode 100644 index 00000000..b555c6a2 --- /dev/null +++ b/indent/ant.vim @@ -0,0 +1,16 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: ANT files +" Maintainer: David Fishburn +" Last Change: Thu May 15 2003 10:02:54 PM + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif + +" Use XML formatting rules +runtime! indent/xml.vim + +endif diff --git a/indent/automake.vim b/indent/automake.vim new file mode 100644 index 00000000..3ec6f83c --- /dev/null +++ b/indent/automake.vim @@ -0,0 +1,15 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: automake +" Previous Maintainer: Nikolai Weibull +" Latest Revision: 2006-04-19 + +if exists("b:did_indent") + finish +endif + +" same as makefile indenting for now. +runtime! indent/make.vim + +endif diff --git a/indent/awk.vim b/indent/awk.vim new file mode 100644 index 00000000..8637dd53 --- /dev/null +++ b/indent/awk.vim @@ -0,0 +1,236 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" vim: set sw=3 sts=3: + +" Awk indent script. It can handle multi-line statements and expressions. +" It works up to the point where the distinction between correct/incorrect +" and personal taste gets fuzzy. Drop me an e-mail for bug reports and +" reasonable style suggestions. +" +" Bugs: +" ===== +" - Some syntax errors may cause erratic indentation. +" - Same for very unusual but syntacticly correct use of { } +" - In some cases it's confused by the use of ( and { in strings constants +" - This version likes the closing brace of a multiline pattern-action be on +" character position 1 before the following pattern-action combination is +" formatted + +" Author: +" ======= +" Erik Janssen, ejanssen@itmatters.nl +" +" History: +" ======== +" 26-04-2002 Got initial version working reasonably well +" 29-04-2002 Fixed problems in function headers and max line width +" Added support for two-line if's without curly braces +" Fixed hang: 2011 Aug 31 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif + +let b:did_indent = 1 + +setlocal indentexpr=GetAwkIndent() +" Mmm, copied from the tcl indent program. Is this okay? +setlocal indentkeys-=:,0# + +" Only define the function once. +if exists("*GetAwkIndent") + finish +endif + +" This function contains a lot of exit points. It checks for simple cases +" first to get out of the function as soon as possible, thereby reducing the +" number of possibilities later on in the difficult parts + +function! GetAwkIndent() + + " Find previous line and get it's indentation + let prev_lineno = s:Get_prev_line( v:lnum ) + if prev_lineno == 0 + return 0 + endif + let prev_data = getline( prev_lineno ) + let ind = indent( prev_lineno ) + + " Increase indent if the previous line contains an opening brace. Search + " for this brace the hard way to prevent errors if the previous line is a + " 'pattern { action }' (simple check match on /{/ increases the indent then) + + if s:Get_brace_balance( prev_data, '{', '}' ) > 0 + return ind + shiftwidth() + endif + + let brace_balance = s:Get_brace_balance( prev_data, '(', ')' ) + + " If prev line has positive brace_balance and starts with a word (keyword + " or function name), align the current line on the first '(' of the prev + " line + + if brace_balance > 0 && s:Starts_with_word( prev_data ) + return s:Safe_indent( ind, s:First_word_len(prev_data), getline(v:lnum)) + endif + + " If this line starts with an open brace bail out now before the line + " continuation checks. + + if getline( v:lnum ) =~ '^\s*{' + return ind + endif + + " If prev line seems to be part of multiline statement: + " 1. Prev line is first line of a multiline statement + " -> attempt to indent on first ' ' or '(' of prev line, just like we + " indented the positive brace balance case above + " 2. Prev line is not first line of a multiline statement + " -> copy indent of prev line + + let continue_mode = s:Seems_continuing( prev_data ) + if continue_mode > 0 + if s:Seems_continuing( getline(s:Get_prev_line( prev_lineno )) ) + " Case 2 + return ind + else + " Case 1 + if continue_mode == 1 + " Need continuation due to comma, backslash, etc + return s:Safe_indent( ind, s:First_word_len(prev_data), getline(v:lnum)) + else + " if/for/while without '{' + return ind + shiftwidth() + endif + endif + endif + + " If the previous line doesn't need continuation on the current line we are + " on the start of a new statement. We have to make sure we align with the + " previous statement instead of just the previous line. This is a bit + " complicated because the previous statement might be multi-line. + " + " The start of a multiline statement can be found by: + " + " 1 If the previous line contains closing braces and has negative brace + " balance, search backwards until cumulative brace balance becomes zero, + " take indent of that line + " 2 If the line before the previous needs continuation search backward + " until that's not the case anymore. Take indent of one line down. + + " Case 1 + if prev_data =~ ')' && brace_balance < 0 + while brace_balance != 0 && prev_lineno > 0 + let prev_lineno = s:Get_prev_line( prev_lineno ) + let prev_data = getline( prev_lineno ) + let brace_balance=brace_balance+s:Get_brace_balance(prev_data,'(',')' ) + endwhile + let ind = indent( prev_lineno ) + else + " Case 2 + if s:Seems_continuing( getline( prev_lineno - 1 ) ) + let prev_lineno = prev_lineno - 2 + let prev_data = getline( prev_lineno ) + while prev_lineno > 0 && (s:Seems_continuing( prev_data ) > 0) + let prev_lineno = s:Get_prev_line( prev_lineno ) + let prev_data = getline( prev_lineno ) + endwhile + let ind = indent( prev_lineno + 1 ) + endif + endif + + " Decrease indent if this line contains a '}'. + if getline(v:lnum) =~ '^\s*}' + let ind = ind - shiftwidth() + endif + + return ind +endfunction + +" Find the open and close braces in this line and return how many more open- +" than close braces there are. It's also used to determine cumulative balance +" across multiple lines. + +function! s:Get_brace_balance( line, b_open, b_close ) + let line2 = substitute( a:line, a:b_open, "", "g" ) + let openb = strlen( a:line ) - strlen( line2 ) + let line3 = substitute( line2, a:b_close, "", "g" ) + let closeb = strlen( line2 ) - strlen( line3 ) + return openb - closeb +endfunction + +" Find out whether the line starts with a word (i.e. keyword or function +" call). Might need enhancements here. + +function! s:Starts_with_word( line ) + if a:line =~ '^\s*[a-zA-Z_0-9]\+\s*(' + return 1 + endif + return 0 +endfunction + +" Find the length of the first word in a line. This is used to be able to +" align a line relative to the 'print ' or 'if (' on the previous line in case +" such a statement spans multiple lines. +" Precondition: only to be used on lines where 'Starts_with_word' returns 1. + +function! s:First_word_len( line ) + let white_end = matchend( a:line, '^\s*' ) + if match( a:line, '^\s*func' ) != -1 + let word_end = matchend( a:line, '[a-z]\+\s\+[a-zA-Z_0-9]\+[ (]*' ) + else + let word_end = matchend( a:line, '[a-zA-Z_0-9]\+[ (]*' ) + endif + return word_end - white_end +endfunction + +" Determine if 'line' completes a statement or is continued on the next line. +" This one is far from complete and accepts illegal code. Not important for +" indenting, however. + +function! s:Seems_continuing( line ) + " Unfinished lines + if a:line =~ '\(--\|++\)\s*$' + return 0 + endif + if a:line =~ '[\\,\|\&\+\-\*\%\^]\s*$' + return 1 + endif + " if/for/while (cond) eol + if a:line =~ '^\s*\(if\|while\|for\)\s*(.*)\s*$' || a:line =~ '^\s*else\s*' + return 2 + endif + return 0 +endfunction + +" Get previous relevant line. Search back until a line is that is no +" comment or blank and return the line number + +function! s:Get_prev_line( lineno ) + let lnum = a:lineno - 1 + let data = getline( lnum ) + while lnum > 0 && (data =~ '^\s*#' || data =~ '^\s*$') + let lnum = lnum - 1 + let data = getline( lnum ) + endwhile + return lnum +endfunction + +" This function checks whether an indented line exceeds a maximum linewidth +" (hardcoded 80). If so and it is possible to stay within 80 positions (or +" limit num of characters beyond linewidth) by decreasing the indent (keeping +" it > base_indent), do so. + +function! s:Safe_indent( base, wordlen, this_line ) + let line_base = matchend( a:this_line, '^\s*' ) + let line_len = strlen( a:this_line ) - line_base + let indent = a:base + if (indent + a:wordlen + line_len) > 80 + " Simple implementation good enough for the time being + let indent = indent + 3 + endif + return indent + a:wordlen +endfunction + +endif diff --git a/indent/bib.vim b/indent/bib.vim new file mode 100644 index 00000000..413591f6 --- /dev/null +++ b/indent/bib.vim @@ -0,0 +1,19 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: BibTeX +" Maintainer: Dorai Sitaram +" URL: http://www.ccs.neu.edu/~dorai/vimplugins/vimplugins.html +" Last Change: 2005 Mar 28 + +" Only do this when not done yet for this buffer +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal cindent + +let b:undo_indent = "setl cin<" + +endif diff --git a/indent/bst.vim b/indent/bst.vim new file mode 100644 index 00000000..b11924b9 --- /dev/null +++ b/indent/bst.vim @@ -0,0 +1,79 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: bst +" Author: Tim Pope +" $Id: bst.vim,v 1.1 2007/05/05 18:11:12 vimboss Exp $ + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal expandtab +setlocal indentexpr=GetBstIndent(v:lnum) +"setlocal smartindent +setlocal cinkeys& +setlocal cinkeys-=0# +setlocal indentkeys& +"setlocal indentkeys+=0% + +" Only define the function once. +if exists("*GetBstIndent") + finish +endif + +function! s:prevgood(lnum) + " Find a non-blank line above the current line. + " Skip over comments. + let lnum = a:lnum + while lnum > 0 + let lnum = prevnonblank(lnum - 1) + if getline(lnum) !~ '^\s*%.*$' + break + endif + endwhile + return lnum +endfunction + +function! s:strip(lnum) + let line = getline(a:lnum) + let line = substitute(line,'"[^"]*"','""','g') + let line = substitute(line,'%.*','','') + let line = substitute(line,'^\s\+','','') + return line +endfunction + +function! s:count(string,char) + let str = substitute(a:string,'[^'.a:char.']','','g') + return strlen(str) +endfunction + +function! GetBstIndent(lnum) abort + if a:lnum == 1 + return 0 + endif + let lnum = s:prevgood(a:lnum) + if lnum <= 0 + return indent(a:lnum - 1) + endif + let line = s:strip(lnum) + let cline = s:strip(a:lnum) + if cline =~ '^}' && exists("b:current_syntax") + call cursor(a:lnum,indent(a:lnum)) + if searchpair('{','','}','bW',"synIDattr(synID(line('.'),col('.'),1),'name') =~? 'comment\\|string'") + if col('.')+1 == col('$') + return indent('.') + else + return virtcol('.')-1 + endif + endif + endif + let fakeline = substitute(line,'^}','','').matchstr(cline,'^}') + let ind = indent(lnum) + let ind = ind + shiftwidth() * s:count(line,'{') + let ind = ind - shiftwidth() * s:count(fakeline,'}') + return ind +endfunction + +endif diff --git a/indent/bzl.vim b/indent/bzl.vim new file mode 100644 index 00000000..838cf006 --- /dev/null +++ b/indent/bzl.vim @@ -0,0 +1,98 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Bazel (http://bazel.io) +" Maintainer: David Barnett (https://github.com/google/vim-ft-bzl) +" Last Change: 2017 Jun 13 + +if exists('b:did_indent') + finish +endif + +" Load base python indent. +if !exists('*GetPythonIndent') + runtime! indent/python.vim +endif + +let b:did_indent = 1 + +" Only enable bzl google indent if python google indent is enabled. +if !get(g:, 'no_google_python_indent') + setlocal indentexpr=GetBzlIndent(v:lnum) +endif + +if exists('*GetBzlIndent') + finish +endif + +let s:save_cpo = &cpo +set cpo-=C + +" Maximum number of lines to look backwards. +let s:maxoff = 50 + +"" +" Determine the correct indent level given an {lnum} in the current buffer. +function GetBzlIndent(lnum) abort + let l:use_recursive_indent = !get(g:, 'no_google_python_recursive_indent') + if l:use_recursive_indent + " Backup and override indent setting variables. + if exists('g:pyindent_nested_paren') + let l:pyindent_nested_paren = g:pyindent_nested_paren + endif + if exists('g:pyindent_open_paren') + let l:pyindent_open_paren = g:pyindent_open_paren + endif + let g:pyindent_nested_paren = 'shiftwidth() * 2' + let g:pyindent_open_paren = 'shiftwidth() * 2' + endif + + let l:indent = -1 + + " Indent inside parens. + " Align with the open paren unless it is at the end of the line. + " E.g. + " open_paren_not_at_EOL(100, + " (200, + " 300), + " 400) + " open_paren_at_EOL( + " 100, 200, 300, 400) + call cursor(a:lnum, 1) + let [l:par_line, l:par_col] = searchpairpos('(\|{\|\[', '', ')\|}\|\]', 'bW', + \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" . + \ " synIDattr(synID(line('.'), col('.'), 1), 'name')" . + \ " =~ '\\(Comment\\|String\\)$'") + if l:par_line > 0 + call cursor(l:par_line, 1) + if l:par_col != col('$') - 1 + let l:indent = l:par_col + endif + endif + + " Delegate the rest to the original function. + if l:indent == -1 + let l:indent = GetPythonIndent(a:lnum) + endif + + if l:use_recursive_indent + " Restore global variables. + if exists('l:pyindent_nested_paren') + let g:pyindent_nested_paren = l:pyindent_nested_paren + else + unlet g:pyindent_nested_paren + endif + if exists('l:pyindent_open_paren') + let g:pyindent_open_paren = l:pyindent_open_paren + else + unlet g:pyindent_open_paren + endif + endif + + return l:indent +endfunction + +let &cpo = s:save_cpo +unlet s:save_cpo + +endif diff --git a/indent/c.vim b/indent/c.vim new file mode 100644 index 00000000..2237af3e --- /dev/null +++ b/indent/c.vim @@ -0,0 +1,19 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: C +" Maintainer: Bram Moolenaar +" Last Change: 2005 Mar 27 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" C indenting is built-in, thus this is very simple +setlocal cindent + +let b:undo_indent = "setl cin<" + +endif diff --git a/indent/cdl.vim b/indent/cdl.vim new file mode 100644 index 00000000..76716666 --- /dev/null +++ b/indent/cdl.vim @@ -0,0 +1,133 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Description: Comshare Dimension Definition Language (CDL) +" Author: Raul Segura Acevedo +" Last Change: Fri Nov 30 13:35:48 2001 CST + +if exists("b:did_indent") + "finish +endif +let b:did_indent = 1 + +setlocal indentexpr=CdlGetIndent(v:lnum) +setlocal indentkeys& +setlocal indentkeys+==~else,=~endif,=~then,;,),= + +" Only define the function once. +if exists("*CdlGetIndent") + "finish +endif + +" find out if an "...=..." expresion is an assignment (or a conditional) +" it scans 'line' first, and then the previos lines +fun! CdlAsignment(lnum, line) + let f = -1 + let lnum = a:lnum + let line = a:line + while lnum > 0 && f == -1 + " line without members [a] of [b]:[c]... + let inicio = 0 + while 1 + " keywords that help to decide + let inicio = matchend(line, '\c\<\(expr\|\a*if\|and\|or\|not\|else\|then\|memberis\|\k\+of\)\>\|[<>;]', inicio) + if inicio < 0 + break + endif + " it's formula if there's a ';', 'elsE', 'theN', 'enDif' or 'expr' + " conditional if there's a '<', '>', 'elseif', 'if', 'and', 'or', 'not', + " 'memberis', 'childrenof' and other \k\+of funcions + let f = line[inicio-1] =~? '[en;]' || strpart(line, inicio-4, 4) =~? 'ndif\|expr' + endw + let lnum = prevnonblank(lnum-1) + let line = substitute(getline(lnum), '\c\(\[[^]]*]\(\s*of\s*\|:\)*\)\+', ' ', 'g') + endw + " if we hit the start of the file then f = -1, return 1 (formula) + return f != 0 +endf + +fun! CdlGetIndent(lnum) + let thisline = getline(a:lnum) + if match(thisline, '^\s*\(\k\+\|\[[^]]*]\)\s*\(,\|;\s*$\)') >= 0 + " it's an attributes line + return shiftwidth() + elseif match(thisline, '^\c\s*\([{}]\|\/[*/]\|dimension\|schedule\|group\|hierarchy\|class\)') >= 0 + " it's a header or '{' or '}' or a comment + return 0 + end + + let lnum = prevnonblank(a:lnum-1) + " Hit the start of the file, use zero indent. + if lnum == 0 + return 0 + endif + + " PREVIOUS LINE + let ind = indent(lnum) + let line = getline(lnum) + let f = -1 " wether a '=' is a conditional or a asignment, -1 means we don't know yet + " one 'closing' element at the beginning of the line has already reduced the + " indent, but 'else', 'elseif' & 'then' increment it for the next line + " '=' at the beginning has already de right indent (increased for asignments) + let inicio = matchend(line, '^\c\s*\(else\a*\|then\|endif\|/[*/]\|[);={]\)') + if inicio > 0 + let c = line[inicio-1] + " ')' and '=' don't change indent and are useless to set 'f' + if c == '{' + return shiftwidth() + elseif c != ')' && c != '=' + let f = 1 " all but 'elseif' are followed by a formula + if c ==? 'n' || c ==? 'e' " 'then', 'else' + let ind = ind + shiftwidth() + elseif strpart(line, inicio-6, 6) ==? 'elseif' " elseif, set f to conditional + let ind = ind + shiftwidth() + let f = 0 + end + end + end + + " remove members [a] of [b]:[c]... (inicio remainds valid) + let line = substitute(line, '\c\(\[[^]]*]\(\s*of\s*\|:\)*\)\+', ' ', 'g') + while 1 + " search for the next interesting element + let inicio=matchend(line, '\c\= 0 + let ind = ind - shiftwidth() + elseif match(thisline, '^\s*=') >= 0 + if f == -1 " we don't know yet if is an asignment, find out + let f = CdlAsignment(lnum, "") + end + if f == 1 " formula increase it + let ind = ind + shiftwidth() + end + end + + return ind +endfun + +endif diff --git a/indent/ch.vim b/indent/ch.vim new file mode 100644 index 00000000..bdaf531a --- /dev/null +++ b/indent/ch.vim @@ -0,0 +1,22 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Ch +" Maintainer: SoftIntegration, Inc. +" URL: http://www.softintegration.com/download/vim/indent/ch.vim +" Last change: 2006 Apr 30 +" Created based on cpp.vim +" +" Ch is a C/C++ interpreter with many high level extensions + + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" Ch indenting is built-in, thus this is very simple +setlocal cindent + +endif diff --git a/indent/chaiscript.vim b/indent/chaiscript.vim new file mode 100644 index 00000000..9c8b2283 --- /dev/null +++ b/indent/chaiscript.vim @@ -0,0 +1,54 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: ChaiScript +" Maintainer: Jason Turner + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentexpr=GetChaiScriptIndent() +setlocal autoindent + +" Only define the function once. +if exists("*GetChaiScriptIndent") + finish +endif + +function! GetChaiScriptIndent() + " Find a non-blank line above the current line. + let lnum = prevnonblank(v:lnum - 1) + + " Hit the start of the file, use zero indent. + if lnum == 0 + return 0 + endif + + " Add a 'shiftwidth' after lines that start a block: + " lines containing a { + let ind = indent(lnum) + let flag = 0 + let prevline = getline(lnum) + if prevline =~ '^.*{.*' + let ind = ind + shiftwidth() + let flag = 1 + endif + + " Subtract a 'shiftwidth' after lines containing a { followed by a } + " to keep it balanced + if flag == 1 && prevline =~ '.*{.*}.*' + let ind = ind - shiftwidth() + endif + + " Subtract a 'shiftwidth' on lines ending with } + if getline(v:lnum) =~ '^\s*\%(}\)' + let ind = ind - shiftwidth() + endif + + return ind +endfunction + +endif diff --git a/indent/changelog.vim b/indent/changelog.vim new file mode 100644 index 00000000..872692dd --- /dev/null +++ b/indent/changelog.vim @@ -0,0 +1,18 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: generic Changelog file +" Maintainer: noone +" Last Change: 2005 Mar 29 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal ai + +let b:undo_indent = "setl ai<" + +endif diff --git a/indent/clojure.vim b/indent/clojure.vim index f538195a..5d982e4a 100644 --- a/indent/clojure.vim +++ b/indent/clojure.vim @@ -1,3 +1,401 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Clojure +" Author: Meikel Brandmeyer +" URL: http://kotka.de/projects/clojure/vimclojure.html +" +" Maintainer: Sung Pae +" URL: https://github.com/guns/vim-clojure-static +" License: Same as Vim +" Last Change: 18 July 2016 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +let s:save_cpo = &cpo +set cpo&vim + +let b:undo_indent = 'setlocal autoindent< smartindent< expandtab< softtabstop< shiftwidth< indentexpr< indentkeys<' + +setlocal noautoindent nosmartindent +setlocal softtabstop=2 shiftwidth=2 expandtab +setlocal indentkeys=!,o,O + +if exists("*searchpairpos") + + if !exists('g:clojure_maxlines') + let g:clojure_maxlines = 100 + endif + + if !exists('g:clojure_fuzzy_indent') + let g:clojure_fuzzy_indent = 1 + endif + + if !exists('g:clojure_fuzzy_indent_patterns') + let g:clojure_fuzzy_indent_patterns = ['^with', '^def', '^let'] + endif + + if !exists('g:clojure_fuzzy_indent_blacklist') + let g:clojure_fuzzy_indent_blacklist = ['-fn$', '\v^with-%(meta|out-str|loading-context)$'] + endif + + if !exists('g:clojure_special_indent_words') + let g:clojure_special_indent_words = 'deftype,defrecord,reify,proxy,extend-type,extend-protocol,letfn' + endif + + if !exists('g:clojure_align_multiline_strings') + let g:clojure_align_multiline_strings = 0 + endif + + if !exists('g:clojure_align_subforms') + let g:clojure_align_subforms = 0 + endif + + function! s:syn_id_name() + return synIDattr(synID(line("."), col("."), 0), "name") + endfunction + + function! s:ignored_region() + return s:syn_id_name() =~? '\vstring|regex|comment|character' + endfunction + + function! s:current_char() + return getline('.')[col('.')-1] + endfunction + + function! s:current_word() + return getline('.')[col('.')-1 : searchpos('\v>', 'n', line('.'))[1]-2] + endfunction + + function! s:is_paren() + return s:current_char() =~# '\v[\(\)\[\]\{\}]' && !s:ignored_region() + endfunction + + " Returns 1 if string matches a pattern in 'patterns', which may be a + " list of patterns, or a comma-delimited string of implicitly anchored + " patterns. + function! s:match_one(patterns, string) + let list = type(a:patterns) == type([]) + \ ? a:patterns + \ : map(split(a:patterns, ','), '"^" . v:val . "$"') + for pat in list + if a:string =~# pat | return 1 | endif + endfor + endfunction + + function! s:match_pairs(open, close, stopat) + " Stop only on vector and map [ resp. {. Ignore the ones in strings and + " comments. + if a:stopat == 0 + let stopat = max([line(".") - g:clojure_maxlines, 0]) + else + let stopat = a:stopat + endif + + let pos = searchpairpos(a:open, '', a:close, 'bWn', "!s:is_paren()", stopat) + return [pos[0], col(pos)] + endfunction + + function! s:clojure_check_for_string_worker() + " Check whether there is the last character of the previous line is + " highlighted as a string. If so, we check whether it's a ". In this + " case we have to check also the previous character. The " might be the + " closing one. In case the we are still in the string, we search for the + " opening ". If this is not found we take the indent of the line. + let nb = prevnonblank(v:lnum - 1) + + if nb == 0 + return -1 + endif + + call cursor(nb, 0) + call cursor(0, col("$") - 1) + if s:syn_id_name() !~? "string" + return -1 + endif + + " This will not work for a " in the first column... + if s:current_char() == '"' + call cursor(0, col("$") - 2) + if s:syn_id_name() !~? "string" + return -1 + endif + if s:current_char() != '\\' + return -1 + endif + call cursor(0, col("$") - 1) + endif + + let p = searchpos('\(^\|[^\\]\)\zs"', 'bW') + + if p != [0, 0] + return p[1] - 1 + endif + + return indent(".") + endfunction + + function! s:check_for_string() + let pos = getpos('.') + try + let val = s:clojure_check_for_string_worker() + finally + call setpos('.', pos) + endtry + return val + endfunction + + function! s:strip_namespace_and_macro_chars(word) + return substitute(a:word, "\\v%(.*/|[#'`~@^,]*)(.*)", '\1', '') + endfunction + + function! s:clojure_is_method_special_case_worker(position) + " Find the next enclosing form. + call search('\S', 'Wb') + + " Special case: we are at a '(('. + if s:current_char() == '(' + return 0 + endif + call cursor(a:position) + + let next_paren = s:match_pairs('(', ')', 0) + + " Special case: we are now at toplevel. + if next_paren == [0, 0] + return 0 + endif + call cursor(next_paren) + + call search('\S', 'W') + let w = s:strip_namespace_and_macro_chars(s:current_word()) + if g:clojure_special_indent_words =~# '\V\<' . w . '\>' + return 1 + endif + + return 0 + endfunction + + function! s:is_method_special_case(position) + let pos = getpos('.') + try + let val = s:clojure_is_method_special_case_worker(a:position) + finally + call setpos('.', pos) + endtry + return val + endfunction + + " Check if form is a reader conditional, that is, it is prefixed by #? + " or @#? + function! s:is_reader_conditional_special_case(position) + if getline(a:position[0])[a:position[1] - 3 : a:position[1] - 2] == "#?" + return 1 + endif + + return 0 + endfunction + + " Returns 1 for opening brackets, -1 for _anything else_. + function! s:bracket_type(char) + return stridx('([{', a:char) > -1 ? 1 : -1 + endfunction + + " Returns: [opening-bracket-lnum, indent] + function! s:clojure_indent_pos() + " Get rid of special case. + if line(".") == 1 + return [0, 0] + endif + + " We have to apply some heuristics here to figure out, whether to use + " normal lisp indenting or not. + let i = s:check_for_string() + if i > -1 + return [0, i + !!g:clojure_align_multiline_strings] + endif + + call cursor(0, 1) + + " Find the next enclosing [ or {. We can limit the second search + " to the line, where the [ was found. If no [ was there this is + " zero and we search for an enclosing {. + let paren = s:match_pairs('(', ')', 0) + let bracket = s:match_pairs('\[', '\]', paren[0]) + let curly = s:match_pairs('{', '}', bracket[0]) + + " In case the curly brace is on a line later then the [ or - in + " case they are on the same line - in a higher column, we take the + " curly indent. + if curly[0] > bracket[0] || curly[1] > bracket[1] + if curly[0] > paren[0] || curly[1] > paren[1] + return curly + endif + endif + + " If the curly was not chosen, we take the bracket indent - if + " there was one. + if bracket[0] > paren[0] || bracket[1] > paren[1] + return bracket + endif + + " There are neither { nor [ nor (, ie. we are at the toplevel. + if paren == [0, 0] + return paren + endif + + " Now we have to reimplement lispindent. This is surprisingly easy, as + " soon as one has access to syntax items. + " + " - Check whether we are in a special position after a word in + " g:clojure_special_indent_words. These are special cases. + " - Get the next keyword after the (. + " - If its first character is also a (, we have another sexp and align + " one column to the right of the unmatched (. + " - In case it is in lispwords, we indent the next line to the column of + " the ( + sw. + " - If not, we check whether it is last word in the line. In that case + " we again use ( + sw for indent. + " - In any other case we use the column of the end of the word + 2. + call cursor(paren) + + if s:is_method_special_case(paren) + return [paren[0], paren[1] + shiftwidth() - 1] + endif + + if s:is_reader_conditional_special_case(paren) + return paren + endif + + " In case we are at the last character, we use the paren position. + if col("$") - 1 == paren[1] + return paren + endif + + " In case after the paren is a whitespace, we search for the next word. + call cursor(0, col('.') + 1) + if s:current_char() == ' ' + call search('\v\S', 'W') + endif + + " If we moved to another line, there is no word after the (. We + " use the ( position for indent. + if line(".") > paren[0] + return paren + endif + + " We still have to check, whether the keyword starts with a (, [ or {. + " In that case we use the ( position for indent. + let w = s:current_word() + if s:bracket_type(w[0]) == 1 + return paren + endif + + " Test words without namespace qualifiers and leading reader macro + " metacharacters. + " + " e.g. clojure.core/defn and #'defn should both indent like defn. + let ww = s:strip_namespace_and_macro_chars(w) + + if &lispwords =~# '\V\<' . ww . '\>' + return [paren[0], paren[1] + shiftwidth() - 1] + endif + + if g:clojure_fuzzy_indent + \ && !s:match_one(g:clojure_fuzzy_indent_blacklist, ww) + \ && s:match_one(g:clojure_fuzzy_indent_patterns, ww) + return [paren[0], paren[1] + shiftwidth() - 1] + endif + + call search('\v\_s', 'cW') + call search('\v\S', 'W') + if paren[0] < line(".") + return [paren[0], paren[1] + (g:clojure_align_subforms ? 0 : shiftwidth() - 1)] + endif + + call search('\v\S', 'bW') + return [line('.'), col('.') + 1] + endfunction + + function! GetClojureIndent() + let lnum = line('.') + let orig_lnum = lnum + let orig_col = col('.') + let [opening_lnum, indent] = s:clojure_indent_pos() + + " Account for multibyte characters + if opening_lnum > 0 + let indent -= indent - virtcol([opening_lnum, indent]) + endif + + " Return if there are no previous lines to inherit from + if opening_lnum < 1 || opening_lnum >= lnum - 1 + call cursor(orig_lnum, orig_col) + return indent + endif + + let bracket_count = 0 + + " Take the indent of the first previous non-white line that is + " at the same sexp level. cf. src/misc1.c:get_lisp_indent() + while 1 + let lnum = prevnonblank(lnum - 1) + let col = 1 + + if lnum <= opening_lnum + break + endif + + call cursor(lnum, col) + + " Handle bracket counting edge case + if s:is_paren() + let bracket_count += s:bracket_type(s:current_char()) + endif + + while 1 + if search('\v[(\[{}\])]', '', lnum) < 1 + break + elseif !s:ignored_region() + let bracket_count += s:bracket_type(s:current_char()) + endif + endwhile + + if bracket_count == 0 + " Check if this is part of a multiline string + call cursor(lnum, 1) + if s:syn_id_name() !~? '\vstring|regex' + call cursor(orig_lnum, orig_col) + return indent(lnum) + endif + endif + endwhile + + call cursor(orig_lnum, orig_col) + return indent + endfunction + + setlocal indentexpr=GetClojureIndent() + +else + + " In case we have searchpairpos not available we fall back to + " normal lisp indenting. + setlocal indentexpr= + setlocal lisp + let b:undo_indent .= '| setlocal lisp<' + +endif + +let &cpo = s:save_cpo +unlet! s:save_cpo + +" vim:sts=8:sw=8:ts=8:noet + +endif if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'clojure') == -1 " Vim indent file diff --git a/indent/cmake.vim b/indent/cmake.vim new file mode 100644 index 00000000..f67a14d2 --- /dev/null +++ b/indent/cmake.vim @@ -0,0 +1,93 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: CMake (ft=cmake) +" Author: Andy Cedilnik +" Maintainer: Dimitri Merejkowsky +" Former Maintainer: Karthik Krishnan +" Last Change: 2017 Aug 30 +" +" Licence: The CMake license applies to this file. See +" https://cmake.org/licensing +" This implies that distribution with Vim is allowed + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal et +setlocal indentexpr=CMakeGetIndent(v:lnum) +setlocal indentkeys+==ENDIF(,ENDFOREACH(,ENDMACRO(,ELSE(,ELSEIF(,ENDWHILE( + +" Only define the function once. +if exists("*CMakeGetIndent") + finish +endif +let s:keepcpo= &cpo +set cpo&vim + +fun! CMakeGetIndent(lnum) + let this_line = getline(a:lnum) + + " Find a non-blank line above the current line. + let lnum = a:lnum + let lnum = prevnonblank(lnum - 1) + let previous_line = getline(lnum) + + " Hit the start of the file, use zero indent. + if lnum == 0 + return 0 + endif + + let ind = indent(lnum) + + let or = '\|' + " Regular expressions used by line indentation function. + let cmake_regex_comment = '#.*' + let cmake_regex_identifier = '[A-Za-z][A-Za-z0-9_]*' + let cmake_regex_quoted = '"\([^"\\]\|\\.\)*"' + let cmake_regex_arguments = '\(' . cmake_regex_quoted . + \ or . '\$(' . cmake_regex_identifier . ')' . + \ or . '[^()\\#"]' . or . '\\.' . '\)*' + + let cmake_indent_comment_line = '^\s*' . cmake_regex_comment + let cmake_indent_blank_regex = '^\s*$' + let cmake_indent_open_regex = '^\s*' . cmake_regex_identifier . + \ '\s*(' . cmake_regex_arguments . + \ '\(' . cmake_regex_comment . '\)\?$' + + let cmake_indent_close_regex = '^' . cmake_regex_arguments . + \ ')\s*' . + \ '\(' . cmake_regex_comment . '\)\?$' + + let cmake_indent_begin_regex = '^\s*\(IF\|MACRO\|FOREACH\|ELSE\|ELSEIF\|WHILE\|FUNCTION\)\s*(' + let cmake_indent_end_regex = '^\s*\(ENDIF\|ENDFOREACH\|ENDMACRO\|ELSE\|ELSEIF\|ENDWHILE\|ENDFUNCTION\)\s*(' + + " Add + if previous_line =~? cmake_indent_comment_line " Handle comments + let ind = ind + else + if previous_line =~? cmake_indent_begin_regex + let ind = ind + &sw + endif + if previous_line =~? cmake_indent_open_regex + let ind = ind + &sw + endif + endif + + " Subtract + if this_line =~? cmake_indent_end_regex + let ind = ind - &sw + endif + if previous_line =~? cmake_indent_close_regex + let ind = ind - &sw + endif + + return ind +endfun + +let &cpo = s:keepcpo +unlet s:keepcpo + +endif diff --git a/indent/cobol.vim b/indent/cobol.vim new file mode 100644 index 00000000..3d261f15 --- /dev/null +++ b/indent/cobol.vim @@ -0,0 +1,220 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: cobol +" Author: Tim Pope +" $Id: cobol.vim,v 1.1 2007/05/05 18:08:19 vimboss Exp $ + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal expandtab +setlocal indentexpr=GetCobolIndent(v:lnum) +setlocal indentkeys& +setlocal indentkeys+=0<*>,0/,0$,0=01,=~division,=~section,0=~end,0=~then,0=~else,0=~when,*,. + +" Only define the function once. +if exists("*GetCobolIndent") + finish +endif + +let s:skip = 'getline(".") =~ "^.\\{6\\}[*/$-]\\|\"[^\"]*\""' + +function! s:prevgood(lnum) + " Find a non-blank line above the current line. + " Skip over comments. + let lnum = a:lnum + while lnum > 0 + let lnum = prevnonblank(lnum - 1) + let line = getline(lnum) + if line !~? '^\s*[*/$-]' && line !~? '^.\{6\}[*/$CD-]' + break + endif + endwhile + return lnum +endfunction + +function! s:stripped(lnum) + return substitute(strpart(getline(a:lnum),0,72),'^\s*','','') +endfunction + +function! s:optionalblock(lnum,ind,blocks,clauses) + let ind = a:ind + let clauses = '\c\<\%(\' + let beginfull = begin.'\ze.*\%(\n\%(\s*\%([*/$-].*\)\=\n\)*\)\=\s*\%('.clauses.'\)' + let end = '\c\\|\%(\.\%( \|$\)\)\@=' + let cline = s:stripped(a:lnum) + let line = s:stripped(s:prevgood(a:lnum)) + if cline =~? clauses "&& line !~? '^search\>' + call cursor(a:lnum,1) + let lastclause = searchpair(beginfull,clauses,end,'bWr',s:skip) + if getline(lastclause) =~? clauses && s:stripped(lastclause) !~? '^'.begin + let ind = indent(lastclause) + elseif lastclause > 0 + let ind = indent(lastclause) + shiftwidth() + "let ind = ind + shiftwidth() + endif + elseif line =~? clauses && cline !~? end + let ind = ind + shiftwidth() + endif + return ind +endfunction + +function! GetCobolIndent(lnum) abort + let minshft = 6 + let ashft = minshft + 1 + let bshft = ashft + 4 + " (Obsolete) numbered lines + if getline(a:lnum) =~? '^\s*\d\{6\}\%($\|[ */$CD-]\)' + return 0 + endif + let cline = s:stripped(a:lnum) + " Comments, etc. must start in the 7th column + if cline =~? '^[*/$-]' + return minshft + elseif cline =~# '^[CD]' && indent(a:lnum) == minshft + return minshft + endif + " Divisions, sections, and file descriptions start in area A + if cline =~? '\<\(DIVISION\|SECTION\)\%($\|\.\)' || cline =~? '^[FS]D\>' + return ashft + endif + " Fields + if cline =~? '^0*\(1\|77\)\>' + return ashft + endif + if cline =~? '^\d\+\>' + let cnum = matchstr(cline,'^\d\+\>') + let default = 0 + let step = -1 + while step < 2 + let lnum = a:lnum + while lnum > 0 && lnum < line('$') && lnum > a:lnum - 500 && lnum < a:lnum + 500 + let lnum = step > 0 ? nextnonblank(lnum + step) : prevnonblank(lnum + step) + let line = getline(lnum) + let lindent = indent(lnum) + if line =~? '^\s*\d\+\>' + let num = matchstr(line,'^\s*\zs\d\+\>') + if 0+cnum == num + return lindent + elseif 0+cnum > num && default < lindent + shiftwidth() + let default = lindent + shiftwidth() + endif + elseif lindent < bshft && lindent >= ashft + break + endif + endwhile + let step = step + 2 + endwhile + return default ? default : bshft + endif + let lnum = s:prevgood(a:lnum) + " Hit the start of the file, use "zero" indent. + if lnum == 0 + return ashft + endif + " Initial spaces are ignored + let line = s:stripped(lnum) + let ind = indent(lnum) + " Paragraphs. There may be some false positives. + if cline =~? '^\(\a[A-Z0-9-]*[A-Z0-9]\|\d[A-Z0-9-]*\a\)\.' "\s*$' + if cline !~? '^EXIT\s*\.' && line =~? '\.\s*$' + return ashft + endif + endif + " Paragraphs in the identification division. + "if cline =~? '^\(PROGRAM-ID\|AUTHOR\|INSTALLATION\|' . + "\ 'DATE-WRITTEN\|DATE-COMPILED\|SECURITY\)\>' + "return ashft + "endif + if line =~? '\.$' + " XXX + return bshft + endif + if line =~? '^PERFORM\>' + let perfline = substitute(line, '\c^PERFORM\s*', "", "") + if perfline =~? '^\%(\k\+\s\+TIMES\)\=\s*$' + let ind = ind + shiftwidth() + elseif perfline =~? '^\%(WITH\s\+TEST\|VARYING\|UNTIL\)\>.*[^.]$' + let ind = ind + shiftwidth() + endif + endif + if line =~? '^\%(IF\|THEN\|ELSE\|READ\|EVALUATE\|SEARCH\|SELECT\)\>' + let ind = ind + shiftwidth() + endif + let ind = s:optionalblock(a:lnum,ind,'ADD\|COMPUTE\|DIVIDE\|MULTIPLY\|SUBTRACT','ON\s\+SIZE\s\+ERROR') + let ind = s:optionalblock(a:lnum,ind,'STRING\|UNSTRING\|ACCEPT\|DISPLAY\|CALL','ON\s\+OVERFLOW\|ON\s\+EXCEPTION') + if cline !~? '^AT\s\+END\>' || line !~? '^SEARCH\>' + let ind = s:optionalblock(a:lnum,ind,'DELETE\|REWRITE\|START\|WRITE\|READ','INVALID\s\+KEY\|AT\s\+END\|NO\s\+DATA\|AT\s\+END-OF-PAGE') + endif + if cline =~? '^WHEN\>' + call cursor(a:lnum,1) + " We also search for READ so that contained AT ENDs are skipped + let lastclause = searchpair('\c-\@','\c\<\%(WHEN\|AT\s\+END\)\>','\c\','bW',s:skip) + let g:foo = s:stripped(lastclause) + if s:stripped(lastclause) =~? '\c\<\%(WHEN\|AT\s\+END\)\>' + "&& s:stripped(lastclause) !~? '^\%(SEARCH\|EVALUATE\|READ\)\>' + let ind = indent(lastclause) + elseif lastclause > 0 + let ind = indent(lastclause) + shiftwidth() + endif + elseif line =~? '^WHEN\>' + let ind = ind + shiftwidth() + endif + "I'm not sure why I had this + "if line =~? '^ELSE\>-\@!' && line !~? '\.$' + "let ind = indent(s:prevgood(lnum)) + "endif + if cline =~? '^\(END\)\>-\@!' + " On lines with just END, 'guess' a simple shift left + let ind = ind - shiftwidth() + elseif cline =~? '^\(END-IF\|THEN\|ELSE\)\>-\@!' + call cursor(a:lnum,indent(a:lnum)) + let match = searchpair('\c-\@','\c-\@','\c-\@\zs','bnW',s:skip) + if match > 0 + let ind = indent(match) + endif + elseif cline =~? '^END-[A-Z]' + let beginword = matchstr(cline,'\c\','','\c\<'.endword.'\>\zs','bnW'.(first? 'r' : ''),s:skip) + if match > 0 + let ind = indent(match) + elseif cline =~? '^\(END-\(READ\|EVALUATE\|SEARCH\|PERFORM\)\)\>' + let ind = ind - shiftwidth() + endif + endif + return ind < bshft ? bshft : ind +endfunction + +endif diff --git a/indent/config.vim b/indent/config.vim new file mode 100644 index 00000000..a49741ca --- /dev/null +++ b/indent/config.vim @@ -0,0 +1,86 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Autoconf configure.{ac,in} file +" Previous Maintainer: Nikolai Weibull +" Latest Revision: 2006-12-20 +" TODO: how about nested [()]'s in one line +" what's wrong with '\\\@!'? + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif + +runtime! indent/sh.vim " will set b:did_indent + +setlocal indentexpr=GetConfigIndent() +setlocal indentkeys=!^F,o,O,=then,=do,=else,=elif,=esac,=fi,=fin,=fil,=done +setlocal nosmartindent + +" Only define the function once. +if exists("*GetConfigIndent") + finish +endif + +" get the offset (indent) of the end of the match of 'regexp' in 'line' +function s:GetOffsetOf(line, regexp) + let end = matchend(a:line, a:regexp) + let width = 0 + let i = 0 + while i < end + if a:line[i] != "\t" + let width = width + 1 + else + let width = width + &ts - (width % &ts) + endif + let i = i + 1 + endwhile + return width +endfunction + +function GetConfigIndent() + " Find a non-blank line above the current line. + let lnum = prevnonblank(v:lnum - 1) + + " Hit the start of the file, use zero indent. + if lnum == 0 + return 0 + endif + + " where to put this + let ind = GetShIndent() + let line = getline(lnum) + + " if previous line has unmatched, unescaped opening parentheses, + " indent to its position. TODO: not failsafe if multiple ('s + if line =~ '\\\@ +" Last Change: 2016 Oct 15 + +if exists("b:did_indent") + finish +endif + +if !get(b:, 'context_metapost', get(g:, 'context_metapost', 1)) + finish +endif + +" Load MetaPost indentation script +runtime! indent/mp.vim + +let s:keepcpo= &cpo +set cpo&vim + +setlocal indentexpr=GetConTeXtIndent() + +let b:undo_indent = "setl indentexpr<" + +function! GetConTeXtIndent() + " Use MetaPost rules inside MetaPost graphic environments + if len(synstack(v:lnum, 1)) > 0 && + \ synIDattr(synstack(v:lnum, 1)[0], "name") ==# 'contextMPGraphic' + return GetMetaPostIndent() + endif + return -1 +endfunc + +let &cpo = s:keepcpo +unlet s:keepcpo + +" vim:sw=2 + +endif diff --git a/indent/cpp.vim b/indent/cpp.vim new file mode 100644 index 00000000..e6bbfc63 --- /dev/null +++ b/indent/cpp.vim @@ -0,0 +1,19 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: C++ +" Maintainer: Bram Moolenaar +" Last Change: 2008 Nov 29 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" C++ indenting is built-in, thus this is very simple +setlocal cindent + +let b:undo_indent = "setl cin<" + +endif diff --git a/indent/cs.vim b/indent/cs.vim new file mode 100644 index 00000000..bd04c1e9 --- /dev/null +++ b/indent/cs.vim @@ -0,0 +1,19 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: C# +" Maintainer: Johannes Zellner +" Last Change: Fri, 15 Mar 2002 07:53:54 CET + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" C# is like indenting C +setlocal cindent + +let b:undo_indent = "setl cin<" + +endif diff --git a/indent/css.vim b/indent/css.vim new file mode 100644 index 00000000..bf26f77b --- /dev/null +++ b/indent/css.vim @@ -0,0 +1,88 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: CSS +" Maintainer: Nikolai Weibull +" Latest Revision: 2012-05-30 +" Use of shiftwidth() added by Oleg Zubchenko. + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentexpr=GetCSSIndent() +setlocal indentkeys=0{,0},!^F,o,O +setlocal nosmartindent + +let b:undo_indent = "setl smartindent< indentkeys< indentexpr<" + +if exists("*GetCSSIndent") + finish +endif +let s:keepcpo= &cpo +set cpo&vim + +function s:prevnonblanknoncomment(lnum) + let lnum = a:lnum + while lnum > 1 + let lnum = prevnonblank(lnum) + let line = getline(lnum) + if line =~ '\*/' + while lnum > 1 && line !~ '/\*' + let lnum -= 1 + endwhile + if line =~ '^\s*/\*' + let lnum -= 1 + else + break + endif + else + break + endif + endwhile + return lnum +endfunction + +function s:count_braces(lnum, count_open) + let n_open = 0 + let n_close = 0 + let line = getline(a:lnum) + let pattern = '[{}]' + let i = match(line, pattern) + while i != -1 + if synIDattr(synID(a:lnum, i + 1, 0), 'name') !~ 'css\%(Comment\|StringQ\{1,2}\)' + if line[i] == '{' + let n_open += 1 + elseif line[i] == '}' + if n_open > 0 + let n_open -= 1 + else + let n_close += 1 + endif + endif + endif + let i = match(line, pattern, i + 1) + endwhile + return a:count_open ? n_open : n_close +endfunction + +function GetCSSIndent() + let line = getline(v:lnum) + if line =~ '^\s*\*' + return cindent(v:lnum) + endif + + let pnum = s:prevnonblanknoncomment(v:lnum - 1) + if pnum == 0 + return 0 + endif + + return indent(pnum) + s:count_braces(pnum, 1) * shiftwidth() + \ - s:count_braces(v:lnum, 0) * shiftwidth() +endfunction + +let &cpo = s:keepcpo +unlet s:keepcpo + +endif diff --git a/indent/cucumber.vim b/indent/cucumber.vim index 03f11dc8..a6b745c0 100644 --- a/indent/cucumber.vim +++ b/indent/cucumber.vim @@ -1,3 +1,82 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Cucumber +" Maintainer: Tim Pope +" Last Change: 2017 Jun 13 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetCucumberIndent() +setlocal indentkeys=o,O,*,<:>,0,0#,=,!^F + +let b:undo_indent = 'setl ai< inde< indk<' + +" Only define the function once. +if exists("*GetCucumberIndent") + finish +endif + +function! s:syn(lnum) + return synIDattr(synID(a:lnum,1+indent(a:lnum),1),'name') +endfunction + +function! GetCucumberIndent() + let line = getline(prevnonblank(v:lnum-1)) + let cline = getline(v:lnum) + let nline = getline(nextnonblank(v:lnum+1)) + let sw = exists('*shiftwidth') ? shiftwidth() : shiftwidth() + let syn = s:syn(prevnonblank(v:lnum-1)) + let csyn = s:syn(v:lnum) + let nsyn = s:syn(nextnonblank(v:lnum+1)) + if csyn ==# 'cucumberFeature' || cline =~# '^\s*Feature:' + " feature heading + return 0 + elseif csyn ==# 'cucumberExamples' || cline =~# '^\s*\%(Examples\|Scenarios\):' + " examples heading + return 2 * sw + elseif csyn =~# '^cucumber\%(Background\|Scenario\|ScenarioOutline\)$' || cline =~# '^\s*\%(Background\|Scenario\|Scenario Outline\):' + " background, scenario or outline heading + return sw + elseif syn ==# 'cucumberFeature' || line =~# '^\s*Feature:' + " line after feature heading + return sw + elseif syn ==# 'cucumberExamples' || line =~# '^\s*\%(Examples\|Scenarios\):' + " line after examples heading + return 3 * sw + elseif syn =~# '^cucumber\%(Background\|Scenario\|ScenarioOutline\)$' || line =~# '^\s*\%(Background\|Scenario\|Scenario Outline\):' + " line after background, scenario or outline heading + return 2 * sw + elseif cline =~# '^\s*[@#]' && (nsyn == 'cucumberFeature' || nline =~# '^\s*Feature:' || indent(prevnonblank(v:lnum-1)) <= 0) + " tag or comment before a feature heading + return 0 + elseif cline =~# '^\s*@' + " other tags + return sw + elseif cline =~# '^\s*[#|]' && line =~# '^\s*|' + " mid-table + " preserve indent + return indent(prevnonblank(v:lnum-1)) + elseif cline =~# '^\s*|' && line =~# '^\s*[^|]' + " first line of a table, relative indent + return indent(prevnonblank(v:lnum-1)) + sw + elseif cline =~# '^\s*[^|]' && line =~# '^\s*|' + " line after a table, relative unindent + return indent(prevnonblank(v:lnum-1)) - sw + elseif cline =~# '^\s*#' && getline(v:lnum-1) =~ '^\s*$' && (nsyn =~# '^cucumber\%(Background\|Scenario\|ScenarioOutline\)$' || nline =~# '^\s*\%(Background\|Scenario\|Scenario Outline\):') + " comments on scenarios + return sw + endif + return indent(prevnonblank(v:lnum-1)) +endfunction + +" vim:set sts=2 sw=2: + +endif if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'cucumber') == -1 " Vim indent file diff --git a/indent/cuda.vim b/indent/cuda.vim new file mode 100644 index 00000000..d120eda7 --- /dev/null +++ b/indent/cuda.vim @@ -0,0 +1,19 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: CUDA +" Maintainer: Bram Moolenaar +" Last Change: 2008 Nov 29 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" It's just like C indenting +setlocal cindent + +let b:undo_indent = "setl cin<" + +endif diff --git a/indent/d.vim b/indent/d.vim new file mode 100644 index 00000000..c44e7352 --- /dev/null +++ b/indent/d.vim @@ -0,0 +1,26 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file for the D programming language (version 0.137). +" +" Language: D +" Maintainer: Jason Mills +" Last Change: 2005 Nov 22 +" Version: 0.1 +" +" Please email me with bugs, comments, and suggestion. Put vim in the subject +" to ensure the email will not be marked has spam. +" + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif + +let b:did_indent = 1 + +" D indenting is a lot like the built-in C indenting. +setlocal cindent + +" vim: ts=8 noet + +endif diff --git a/indent/dictconf.vim b/indent/dictconf.vim new file mode 100644 index 00000000..193d8ba5 --- /dev/null +++ b/indent/dictconf.vim @@ -0,0 +1,17 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: dict(1) configuration file +" Previous Maintainer: Nikolai Weibull +" Latest Revision: 2006-12-20 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentkeys=0{,0},!^F,o,O cinwords= autoindent smartindent +setlocal nosmartindent +inoremap # X# + +endif diff --git a/indent/dictdconf.vim b/indent/dictdconf.vim new file mode 100644 index 00000000..1aa5fd3e --- /dev/null +++ b/indent/dictdconf.vim @@ -0,0 +1,17 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: dictd(8) configuration file +" Previous Maintainer: Nikolai Weibull +" Latest Revision: 2006-12-20 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentkeys=0{,0},!^F,o,O cinwords= autoindent smartindent +setlocal nosmartindent +inoremap # X# + +endif diff --git a/indent/docbk.vim b/indent/docbk.vim new file mode 100644 index 00000000..8a671f42 --- /dev/null +++ b/indent/docbk.vim @@ -0,0 +1,19 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: DocBook Documentation Format +" Previous Maintainer: Nikolai Weibull +" Latest Revision: 2006-04-19 + +if exists("b:did_indent") + finish +endif + +" Same as XML indenting for now. +runtime! indent/xml.vim + +if exists('*XmlIndentGet') + setlocal indentexpr=XmlIndentGet(v:lnum,0) +endif + +endif diff --git a/indent/dtd.vim b/indent/dtd.vim new file mode 100644 index 00000000..eb2665b4 --- /dev/null +++ b/indent/dtd.vim @@ -0,0 +1,329 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: DTD (Document Type Definition for XML) +" Previous Maintainer: Nikolai Weibull +" Latest Revision: 2011-07-08 + +let s:cpo_save = &cpo +set cpo&vim + +setlocal indentexpr=GetDTDIndent() +setlocal indentkeys=!^F,o,O,> +setlocal nosmartindent + +if exists("*GetDTDIndent") + finish +endif + +" TODO: Needs to be adjusted to stop at [, <, and ]. +let s:token_pattern = '^[^[:space:]]\+' + +function s:lex1(input, start, ...) + let pattern = a:0 > 0 ? a:1 : s:token_pattern + let start = matchend(a:input, '^\_s*', a:start) + if start == -1 + return ["", a:start] + endif + let end = matchend(a:input, pattern, start) + if end == -1 + return ["", a:start] + endif + let token = strpart(a:input, start, end - start) + return [token, end] +endfunction + +function s:lex(input, start, ...) + let pattern = a:0 > 0 ? a:1 : s:token_pattern + let info = s:lex1(a:input, a:start, pattern) + while info[0] == '--' + let info = s:lex1(a:input, info[1], pattern) + while info[0] != "" && info[0] != '--' + let info = s:lex1(a:input, info[1], pattern) + endwhile + if info[0] == "" + return info + endif + let info = s:lex1(a:input, info[1], pattern) + endwhile + return info +endfunction + +function s:indent_to_innermost_parentheses(line, end) + let token = '(' + let end = a:end + let parentheses = [end - 1] + while token != "" + let [token, end] = s:lex(a:line, end, '^\%([(),|]\|[A-Za-z0-9_-]\+\|#P\=CDATA\|%[A-Za-z0-9_-]\+;\)[?*+]\=') + if token[0] == '(' + call add(parentheses, end - 1) + elseif token[0] == ')' + if len(parentheses) == 1 + return [-1, end] + endif + call remove(parentheses, -1) + endif + endwhile + return [parentheses[-1] - strridx(a:line, "\n", parentheses[-1]), end] +endfunction + +" TODO: Line and end could be script global (think OO members). +function GetDTDIndent() + if v:lnum == 1 + return 0 + endif + + " Begin by searching back for a " + return indent + endif + endwhile + return -1 + elseif declaration == 'ELEMENT' + " Check for element name. If none exists, indent one level. + let [name, end] = s:lex(line, end) + if name == "" + return indent + shiftwidth() + endif + + " Check for token following element name. This can be a specification of + " whether the start or end tag may be omitted. If nothing is found, indent + " one level. + let [token, end] = s:lex(line, end, '^\%([-O(]\|ANY\|EMPTY\)') + let n = 0 + while token =~ '[-O]' && n < 2 + let [token, end] = s:lex(line, end, '^\%([-O(]\|ANY\|EMPTY\)') + let n += 1 + endwhile + if token == "" + return indent + shiftwidth() + endif + + " Next comes the content model. If the token we’ve found isn’t a + " parenthesis it must be either ANY, EMPTY or some random junk. Either + " way, we’re done indenting this element, so set it to that of the first + " line so that the terminating “>†winds up having the same indention. + if token != '(' + return indent + endif + + " Now go through the content model. We need to keep track of the nesting + " of parentheses. As soon as we hit 0 we’re done. If that happens we must + " have a complete content model. Thus set indention to be the same as that + " of the first line so that the terminating “>†winds up having the same + " indention. Otherwise, we’ll indent to the innermost parentheses not yet + " matched. + let [indent_of_innermost, end] = s:indent_to_innermost_parentheses(line, end) + if indent_of_innermost != -1 + return indent_of_innermost + endif + + " Finally, look for any additions and/or exceptions to the content model. + " This is defined by a “+†or “-†followed by another content model + " declaration. + " TODO: Can the “-†be separated by whitespace from the “(â€? + let seen = { '+(': 0, '-(': 0 } + while 1 + let [additions_exceptions, end] = s:lex(line, end, '^[+-](') + if additions_exceptions != '+(' && additions_exceptions != '-(' + let [token, end] = s:lex(line, end) + if token == '>' + return indent + endif + " TODO: Should use s:lex here on getline(v:lnum) and check for >. + return getline(v:lnum) =~ '^\s*>' || count(values(seen), 0) == 0 ? indent : (indent + shiftwidth()) + endif + + " If we’ve seen an addition or exception already and this is of the same + " kind, the user is writing a broken DTD. Time to bail. + if seen[additions_exceptions] + return indent + endif + let seen[additions_exceptions] = 1 + + let [indent_of_innermost, end] = s:indent_to_innermost_parentheses(line, end) + if indent_of_innermost != -1 + return indent_of_innermost + endif + endwhile + elseif declaration == 'ATTLIST' + " Check for element name. If none exists, indent one level. + let [name, end] = s:lex(line, end) + if name == "" + return indent + shiftwidth() + endif + + " Check for any number of attributes. + while 1 + " Check for attribute name. If none exists, indent one level, unless the + " current line is a lone “>â€, in which case we indent to the same level + " as the first line. Otherwise, if the attribute name is “>â€, we have + " actually hit the end of the attribute list, in which case we indent to + " the same level as the first line. + let [name, end] = s:lex(line, end) + if name == "" + " TODO: Should use s:lex here on getline(v:lnum) and check for >. + return getline(v:lnum) =~ '^\s*>' ? indent : (indent + shiftwidth()) + elseif name == ">" + return indent + endif + + " Check for attribute value declaration. If none exists, indent two + " levels. Otherwise, if it’s an enumerated value, check for nested + " parentheses and indent to the innermost one if we don’t reach the end + " of the listc. Otherwise, just continue with looking for the default + " attribute value. + " TODO: Do validation of keywords + " (CDATA|NMTOKEN|NMTOKENS|ID|IDREF|IDREFS|ENTITY|ENTITIES)? + let [value, end] = s:lex(line, end, '^\%((\|[^[:space:]]\+\)') + if value == "" + return indent + shiftwidth() * 2 + elseif value == 'NOTATION' + " If this is a enumerated value based on notations, read another token + " for the actual value. If it doesn’t exist, indent three levels. + " TODO: If validating according to above, value must be equal to '('. + let [value, end] = s:lex(line, end, '^\%((\|[^[:space:]]\+\)') + if value == "" + return indent + shiftwidth() * 3 + endif + endif + + if value == '(' + let [indent_of_innermost, end] = s:indent_to_innermost_parentheses(line, end) + if indent_of_innermost != -1 + return indent_of_innermost + endif + endif + + " Finally look for the attribute’s default value. If non exists, indent + " two levels. + let [default, end] = s:lex(line, end, '^\%("\_[^"]*"\|#\(REQUIRED\|IMPLIED\|FIXED\)\)') + if default == "" + return indent + shiftwidth() * 2 + elseif default == '#FIXED' + " We need to look for the fixed value. If non exists, indent three + " levels. + let [default, end] = s:lex(line, end, '^"\_[^"]*"') + if default == "" + return indent + shiftwidth() * 3 + endif + endif + endwhile + elseif declaration == 'ENTITY' + " Check for entity name. If none exists, indent one level. Otherwise, if + " the name actually turns out to be a percent sign, “%â€, this is a + " parameter entity. Read another token to determine the entity name and, + " again, if none exists, indent one level. + let [name, end] = s:lex(line, end) + if name == "" + return indent + shiftwidth() + elseif name == '%' + let [name, end] = s:lex(line, end) + if name == "" + return indent + shiftwidth() + endif + endif + + " Now check for the entity value. If none exists, indent one level. If it + " does exist, indent to same level as first line, as we’re now done with + " this entity. + " + " The entity value can be a string in single or double quotes (no escapes + " to worry about, as entities are used instead). However, it can also be + " that this is an external unparsed entity. In that case we have to look + " further for (possibly) a public ID and an URI followed by the NDATA + " keyword and the actual notation name. For the public ID and URI, indent + " two levels, if they don’t exist. If the NDATA keyword doesn’t exist, + " indent one level. Otherwise, if the actual notation name doesn’t exist, + " indent two level. If it does, indent to same level as first line, as + " we’re now done with this entity. + let [value, end] = s:lex(line, end) + if value == "" + return indent + shiftwidth() + elseif value == 'SYSTEM' || value == 'PUBLIC' + let [quoted_string, end] = s:lex(line, end, '\%("[^"]\+"\|''[^'']\+''\)') + if quoted_string == "" + return indent + shiftwidth() * 2 + endif + + if value == 'PUBLIC' + let [quoted_string, end] = s:lex(line, end, '\%("[^"]\+"\|''[^'']\+''\)') + if quoted_string == "" + return indent + shiftwidth() * 2 + endif + endif + + let [ndata, end] = s:lex(line, end) + if ndata == "" + return indent + shiftwidth() + endif + + let [name, end] = s:lex(line, end) + return name == "" ? (indent + shiftwidth() * 2) : indent + else + return indent + endif + elseif declaration == 'NOTATION' + " Check for notation name. If none exists, indent one level. + let [name, end] = s:lex(line, end) + if name == "" + return indent + shiftwidth() + endif + + " Now check for the external ID. If none exists, indent one level. + let [id, end] = s:lex(line, end) + if id == "" + return indent + shiftwidth() + elseif id == 'SYSTEM' || id == 'PUBLIC' + let [quoted_string, end] = s:lex(line, end, '\%("[^"]\+"\|''[^'']\+''\)') + if quoted_string == "" + return indent + shiftwidth() * 2 + endif + + if id == 'PUBLIC' + let [quoted_string, end] = s:lex(line, end, '\%("[^"]\+"\|''[^'']\+''\|>\)') + if quoted_string == "" + " TODO: Should use s:lex here on getline(v:lnum) and check for >. + return getline(v:lnum) =~ '^\s*>' ? indent : (indent + shiftwidth() * 2) + elseif quoted_string == '>' + return indent + endif + endif + endif + + return indent + endif + + " TODO: Processing directives could be indented I suppose. But perhaps it’s + " just as well to let the user decide how to indent them (perhaps extending + " this function to include proper support for whatever processing directive + " language they want to use). + + " Conditional sections are simply passed along to let Vim decide what to do + " (and hence the user). + return -1 +endfunction + +let &cpo = s:cpo_save +unlet s:cpo_save + +endif diff --git a/indent/dtrace.vim b/indent/dtrace.vim new file mode 100644 index 00000000..3d9d4e07 --- /dev/null +++ b/indent/dtrace.vim @@ -0,0 +1,21 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: D script as described in "Solaris Dynamic Tracing Guide", +" http://docs.sun.com/app/docs/doc/817-6223 +" Last Change: 2008/03/20 +" Version: 1.2 +" Maintainer: Nicolas Weber + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" Built-in C indenting works nicely for dtrace. +setlocal cindent + +let b:undo_indent = "setl cin<" + +endif diff --git a/indent/dylan.vim b/indent/dylan.vim new file mode 100644 index 00000000..4858ea84 --- /dev/null +++ b/indent/dylan.vim @@ -0,0 +1,94 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Dylan +" Version: 0.01 +" Last Change: 2017 Jun 13 +" Maintainer: Brent A. Fulgham + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentkeys+==~begin,=~block,=~case,=~cleanup,=~define,=~end,=~else,=~elseif,=~exception,=~for,=~finally,=~if,=~otherwise,=~select,=~unless,=~while + +" Define the appropriate indent function but only once +setlocal indentexpr=DylanGetIndent() +if exists("*DylanGetIndent") + finish +endif + +function DylanGetIndent() + " Get the line to be indented + let cline = getline(v:lnum) + + " Don't reindent comments on first column + if cline =~ '^/\[/\*]' + return 0 + endif + + "Find the previous non-blank line + let lnum = prevnonblank(v:lnum - 1) + "Use zero indent at the top of the file + if lnum == 0 + return 0 + endif + + let prevline=getline(lnum) + let ind = indent(lnum) + let chg = 0 + + " If previous line was a comment, use its indent + if prevline =~ '^\s*//' + return ind + endif + + " If previous line was a 'define', indent + if prevline =~? '\(^\s*\(begin\|block\|case\|define\|else\|elseif\|for\|finally\|if\|select\|unless\|while\)\|\s*\S*\s*=>$\)' + let chg = shiftwidth() + " local methods indent the shift-width, plus 6 for the 'local' + elseif prevline =~? '^\s*local' + let chg = shiftwidth() + 6 + " If previous line was a let with no closing semicolon, indent + elseif prevline =~? '^\s*let.*[^;]\s*$' + let chg = shiftwidth() + " If previous line opened a parenthesis, and did not close it, indent + elseif prevline =~ '^.*(\s*[^)]*\((.*)\)*[^)]*$' + return = match( prevline, '(.*\((.*)\|[^)]\)*.*$') + 1 + "elseif prevline =~ '^.*(\s*[^)]*\((.*)\)*[^)]*$' + elseif prevline =~ '^[^(]*)\s*$' + " This line closes a parenthesis. Find opening + let curr_line = prevnonblank(lnum - 1) + while curr_line >= 0 + let str = getline(curr_line) + if str !~ '^.*(\s*[^)]*\((.*)\)*[^)]*$' + let curr_line = prevnonblank(curr_line - 1) + else + break + endif + endwhile + if curr_line < 0 + return -1 + endif + let ind = indent(curr_line) + " Although we found the closing parenthesis, make sure this + " line doesn't start with an indentable command: + let curr_str = getline(curr_line) + if curr_str =~? '^\s*\(begin\|block\|case\|define\|else\|elseif\|for\|finally\|if\|select\|unless\|while\)' + let chg = shiftwidth() + endif + endif + + " If a line starts with end, un-indent (even if we just indented!) + if cline =~? '^\s*\(cleanup\|end\|else\|elseif\|exception\|finally\|otherwise\)' + let chg = chg - shiftwidth() + endif + + return ind + chg +endfunction + +" vim:sw=2 tw=130 + +endif diff --git a/indent/eiffel.vim b/indent/eiffel.vim new file mode 100644 index 00000000..d5967022 --- /dev/null +++ b/indent/eiffel.vim @@ -0,0 +1,119 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Eiffel +" Maintainer: Jocelyn Fiat +" Previous-Maintainer: David Clarke +" Contributions from: Takuya Fujiwara +" Contributions from: Thilo Six +" $Date: 2017/03/08 06:00:00 $ +" $Revision: 1.4 $ +" URL: https://github.com/eiffelhub/vim-eiffel + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentexpr=GetEiffelIndent() +setlocal nolisp +setlocal nosmartindent +setlocal nocindent +setlocal autoindent +setlocal comments=:-- +setlocal indentkeys+==end,=else,=ensure,=require,=check,=loop,=until +setlocal indentkeys+==creation,=feature,=inherit,=class,=is,=redefine,=rename,=variant +setlocal indentkeys+==invariant,=do,=local,=export + +let b:undo_indent = "setl smartindent< indentkeys< indentexpr< autoindent< comments< " + +" Define some stuff +" keywords grouped by indenting +let s:trust_user_indent = '\(+\)\(\s*\(--\).*\)\=$' +let s:relative_indent = '^\s*\(deferred\|class\|feature\|creation\|inherit\|loop\|from\|across\|until\|if\|else\|elseif\|ensure\|require\|check\|do\|local\|invariant\|variant\|rename\|redefine\|do\|export\)\>' +let s:outdent = '^\s*\(else\|invariant\|variant\|do\|require\|until\|loop\|local\)\>' +let s:no_indent = '^\s*\(class\|feature\|creation\|inherit\)\>' +let s:single_dent = '^[^-]\+[[:alnum:]]\+ is\(\s*\(--\).*\)\=$' +let s:inheritance_dent = '\s*\(redefine\|rename\|export\)\>' + + +" Only define the function once. +if exists("*GetEiffelIndent") + finish +endif + +let s:keepcpo= &cpo +set cpo&vim + +function GetEiffelIndent() + + " Eiffel Class indenting + " + " Find a non-blank line above the current line. + let lnum = prevnonblank(v:lnum - 1) + + " At the start of the file use zero indent. + if lnum == 0 + return 0 + endif + + " trust the user's indenting + if getline(lnum) =~ s:trust_user_indent + return -1 + endif + + " Add a 'shiftwidth' after lines that start with an indent word + let ind = indent(lnum) + if getline(lnum) =~ s:relative_indent + let ind = ind + shiftwidth() + endif + + " Indent to single indent + if getline(v:lnum) =~ s:single_dent && getline(v:lnum) !~ s:relative_indent + \ && getline(v:lnum) !~ '\s*\<\(and\|or\|implies\)\>' + let ind = shiftwidth() + endif + + " Indent to double indent + if getline(v:lnum) =~ s:inheritance_dent + let ind = 2 * shiftwidth() + endif + + " Indent line after the first line of the function definition + if getline(lnum) =~ s:single_dent + let ind = ind + shiftwidth() + endif + + " The following should always be at the start of a line, no indenting + if getline(v:lnum) =~ s:no_indent + let ind = 0 + endif + + " Subtract a 'shiftwidth', if this isn't the first thing after the 'is' + " or first thing after the 'do' + if getline(v:lnum) =~ s:outdent && getline(v:lnum - 1) !~ s:single_dent + \ && getline(v:lnum - 1) !~ '^\s*do\>' + let ind = ind - shiftwidth() + endif + + " Subtract a shiftwidth for end statements + if getline(v:lnum) =~ '^\s*end\>' + let ind = ind - shiftwidth() + endif + + " set indent of zero end statements that are at an indent of 3, this should + " only ever be the class's end. + if getline(v:lnum) =~ '^\s*end\>' && ind == shiftwidth() + let ind = 0 + endif + + return ind +endfunction + +let &cpo = s:keepcpo +unlet s:keepcpo + +" vim:sw=2 + +endif diff --git a/indent/erlang.vim b/indent/erlang.vim index 64525bbd..efd4ba47 100644 --- a/indent/erlang.vim +++ b/indent/erlang.vim @@ -1,3 +1,1397 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Erlang (http://www.erlang.org) +" Author: Csaba Hoch +" Contributors: Edwin Fine +" Pawel 'kTT' Salata +" Ricardo Catalinas Jiménez +" Last Update: 2013-Jul-21 +" License: Vim license +" URL: https://github.com/hcs42/vim-erlang + +" Note About Usage: +" This indentation script works best with the Erlang syntax file created by +" KreÄ…imir Marľić (Kresimir Marzic) and maintained by Csaba Hoch. + +" Notes About Implementation: +" +" - LTI = Line to indent. +" - The index of the first line is 1, but the index of the first column is 0. + + +" Initialization {{{1 +" ============== + +" Only load this indent file when no other was loaded +" Vim 7 or later is needed +if exists("b:did_indent") || version < 700 + finish +else + let b:did_indent = 1 +endif + +setlocal indentexpr=ErlangIndent() +setlocal indentkeys+=0=end,0=of,0=catch,0=after,0=when,0=),0=],0=},0=>> + +" Only define the functions once +if exists("*ErlangIndent") + finish +endif + +let s:cpo_save = &cpo +set cpo&vim + +" Logging library {{{1 +" =============== + +" Purpose: +" Logs the given string using the ErlangIndentLog function if it exists. +" Parameters: +" s: string +function! s:Log(s) + if exists("*ErlangIndentLog") + call ErlangIndentLog(a:s) + endif +endfunction + +" Line tokenizer library {{{1 +" ====================== + +" Indtokens are "indentation tokens". + +" Purpose: +" Calculate the new virtual column after the given segment of a line. +" Parameters: +" line: string +" first_index: integer -- the index of the first character of the segment +" last_index: integer -- the index of the last character of the segment +" vcol: integer -- the virtual column of the first character of the token +" tabstop: integer -- the value of the 'tabstop' option to be used +" Returns: +" vcol: integer +" Example: +" " index: 0 12 34567 +" " vcol: 0 45 89 +" s:CalcVCol("\t'\tx', b", 1, 4, 4) -> 10 +function! s:CalcVCol(line, first_index, last_index, vcol, tabstop) + + " We copy the relevent segment of the line, otherwise if the line were + " e.g. `"\t", term` then the else branch below would consume the `", term` + " part at once. + let line = a:line[a:first_index : a:last_index] + + let i = 0 + let last_index = a:last_index - a:first_index + let vcol = a:vcol + + while 0 <= i && i <= last_index + + if line[i] ==# "\t" + " Example (when tabstop == 4): + " + " vcol + tab -> next_vcol + " 0 + tab -> 4 + " 1 + tab -> 4 + " 2 + tab -> 4 + " 3 + tab -> 4 + " 4 + tab -> 8 + " + " next_i - i == the number of tabs + let next_i = matchend(line, '\t*', i + 1) + let vcol = (vcol / a:tabstop + (next_i - i)) * a:tabstop + call s:Log('new vcol after tab: '. vcol) + else + let next_i = matchend(line, '[^\t]*', i + 1) + let vcol += next_i - i + call s:Log('new vcol after other: '. vcol) + endif + let i = next_i + endwhile + + return vcol +endfunction + +" Purpose: +" Go through the whole line and return the tokens in the line. +" Parameters: +" line: string -- the line to be examined +" string_continuation: bool +" atom_continuation: bool +" Returns: +" indtokens = [indtoken] +" indtoken = [token, vcol, col] +" token = string (examples: 'begin', '', '}') +" vcol = integer (the virtual column of the first character of the token) +" col = integer +function! s:GetTokensFromLine(line, string_continuation, atom_continuation, + \tabstop) + + let linelen = strlen(a:line) " The length of the line + let i = 0 " The index of the current character in the line + let vcol = 0 " The virtual column of the current character + let indtokens = [] + + if a:string_continuation + let i = matchend(a:line, '^\%([^"\\]\|\\.\)*"', 0) + if i ==# -1 + call s:Log(' Whole line is string continuation -> ignore') + return [] + else + let vcol = s:CalcVCol(a:line, 0, i - 1, 0, a:tabstop) + call add(indtokens, ['', vcol, i]) + endif + elseif a:atom_continuation + let i = matchend(a:line, "^\\%([^'\\\\]\\|\\\\.\\)*'", 0) + if i ==# -1 + call s:Log(' Whole line is quoted atom continuation -> ignore') + return [] + else + let vcol = s:CalcVCol(a:line, 0, i - 1, 0, a:tabstop) + call add(indtokens, ['', vcol, i]) + endif + endif + + while 0 <= i && i < linelen + + let next_vcol = '' + + " Spaces + if a:line[i] ==# ' ' + let next_i = matchend(a:line, ' *', i + 1) + + " Tabs + elseif a:line[i] ==# "\t" + let next_i = matchend(a:line, '\t*', i + 1) + + " See example in s:CalcVCol + let next_vcol = (vcol / a:tabstop + (next_i - i)) * a:tabstop + + " Comment + elseif a:line[i] ==# '%' + let next_i = linelen + + " String token: "..." + elseif a:line[i] ==# '"' + let next_i = matchend(a:line, '\%([^"\\]\|\\.\)*"', i + 1) + if next_i ==# -1 + call add(indtokens, ['', vcol, i]) + else + let next_vcol = s:CalcVCol(a:line, i, next_i - 1, vcol, a:tabstop) + call add(indtokens, ['', vcol, i]) + endif + + " Quoted atom token: '...' + elseif a:line[i] ==# "'" + let next_i = matchend(a:line, "\\%([^'\\\\]\\|\\\\.\\)*'", i + 1) + if next_i ==# -1 + call add(indtokens, ['', vcol, i]) + else + let next_vcol = s:CalcVCol(a:line, i, next_i - 1, vcol, a:tabstop) + call add(indtokens, ['', vcol, i]) + endif + + " Keyword or atom or variable token or number + elseif a:line[i] =~# '[a-zA-Z_@0-9]' + let next_i = matchend(a:line, + \'[[:alnum:]_@:]*\%(\s*#\s*[[:alnum:]_@:]*\)\=', + \i + 1) + call add(indtokens, [a:line[(i):(next_i - 1)], vcol, i]) + + " Character token: $ (as in: $a) + elseif a:line[i] ==# '$' + call add(indtokens, ['$.', vcol, i]) + let next_i = i + 2 + + " Dot token: . + elseif a:line[i] ==# '.' + + let next_i = i + 1 + + if i + 1 ==# linelen || a:line[i + 1] =~# '[[:blank:]%]' + " End of clause token: . (as in: f() -> ok.) + call add(indtokens, ['', vcol, i]) + + else + " Possibilities: + " - Dot token in float: . (as in: 3.14) + " - Dot token in record: . (as in: #myrec.myfield) + call add(indtokens, ['.', vcol, i]) + endif + + " Equal sign + elseif a:line[i] ==# '=' + " This is handled separately so that "=<<" will be parsed as + " ['=', '<<'] instead of ['=<', '<']. Although Erlang parses it + " currently in the latter way, that may be fixed some day. + call add(indtokens, [a:line[i], vcol, i]) + let next_i = i + 1 + + " Three-character tokens + elseif i + 1 < linelen && + \ index(['=:=', '=/='], a:line[i : i + 1]) != -1 + call add(indtokens, [a:line[i : i + 1], vcol, i]) + let next_i = i + 2 + + " Two-character tokens + elseif i + 1 < linelen && + \ index(['->', '<<', '>>', '||', '==', '/=', '=<', '>=', '++', '--', + \ '::'], + \ a:line[i : i + 1]) != -1 + call add(indtokens, [a:line[i : i + 1], vcol, i]) + let next_i = i + 2 + + " Other character: , ; < > ( ) [ ] { } # + - * / : ? = ! | + else + call add(indtokens, [a:line[i], vcol, i]) + let next_i = i + 1 + + endif + + if next_vcol ==# '' + let vcol += next_i - i + else + let vcol = next_vcol + endif + + let i = next_i + + endwhile + + return indtokens + +endfunction + +" TODO: doc, handle "not found" case +function! s:GetIndtokenAtCol(indtokens, col) + let i = 0 + while i < len(a:indtokens) + if a:indtokens[i][2] ==# a:col + return [1, i] + elseif a:indtokens[i][2] > a:col + return [0, s:IndentError('No token at col ' . a:col . ', ' . + \'indtokens = ' . string(a:indtokens), + \'', '')] + endif + let i += 1 + endwhile + return [0, s:IndentError('No token at col ' . a:col . ', ' . + \'indtokens = ' . string(a:indtokens), + \'', '')] +endfunction + +" Stack library {{{1 +" ============= + +" Purpose: +" Push a token onto the parser's stack. +" Parameters: +" stack: [token] +" token: string +function! s:Push(stack, token) + call s:Log(' Stack Push: "' . a:token . '" into ' . string(a:stack)) + call insert(a:stack, a:token) +endfunction + +" Purpose: +" Pop a token from the parser's stack. +" Parameters: +" stack: [token] +" token: string +" Returns: +" token: string -- the removed element +function! s:Pop(stack) + let head = remove(a:stack, 0) + call s:Log(' Stack Pop: "' . head . '" from ' . string(a:stack)) + return head +endfunction + +" Library for accessing and storing tokenized lines {{{1 +" ================================================= + +" The Erlang token cache: an `lnum -> indtokens` dictionary that stores the +" tokenized lines. +let s:all_tokens = {} +let s:file_name = '' +let s:last_changedtick = -1 + +" Purpose: +" Clear the Erlang token cache if we have a different file or the file has +" been changed since the last indentation. +function! s:ClearTokenCacheIfNeeded() + let file_name = expand('%:p') + if file_name != s:file_name || + \ b:changedtick != s:last_changedtick + let s:file_name = file_name + let s:last_changedtick = b:changedtick + let s:all_tokens = {} + endif +endfunction + +" Purpose: +" Return the tokens of line `lnum`, if that line is not empty. If it is +" empty, find the first non-empty line in the given `direction` and return +" the tokens of that line. +" Parameters: +" lnum: integer +" direction: 'up' | 'down' +" Returns: +" result: [] -- the result is an empty list if we hit the beginning or end +" of the file +" | [lnum, indtokens] +" lnum: integer -- the index of the non-empty line that was found and +" tokenized +" indtokens: [indtoken] -- the tokens of line `lnum` +function! s:TokenizeLine(lnum, direction) + + call s:Log('Tokenizing starts from line ' . a:lnum) + if a:direction ==# 'up' + let lnum = prevnonblank(a:lnum) + else " a:direction ==# 'down' + let lnum = nextnonblank(a:lnum) + endif + + " We hit the beginning or end of the file + if lnum ==# 0 + let indtokens = [] + call s:Log(' We hit the beginning or end of the file.') + + " The line has already been parsed + elseif has_key(s:all_tokens, lnum) + let indtokens = s:all_tokens[lnum] + call s:Log('Cached line ' . lnum . ': ' . getline(lnum)) + call s:Log(" Tokens in the line:\n - " . join(indtokens, "\n - ")) + + " The line should be parsed now + else + + " Parse the line + let line = getline(lnum) + let string_continuation = s:IsLineStringContinuation(lnum) + let atom_continuation = s:IsLineAtomContinuation(lnum) + let indtokens = s:GetTokensFromLine(line, string_continuation, + \atom_continuation, &tabstop) + let s:all_tokens[lnum] = indtokens + call s:Log('Tokenizing line ' . lnum . ': ' . line) + call s:Log(" Tokens in the line:\n - " . join(indtokens, "\n - ")) + + endif + + return [lnum, indtokens] +endfunction + +" Purpose: +" As a helper function for PrevIndToken and NextIndToken, the FindIndToken +" function finds the first line with at least one token in the given +" direction. +" Parameters: +" lnum: integer +" direction: 'up' | 'down' +" Returns: +" result: [] -- the result is an empty list if we hit the beginning or end +" of the file +" | indtoken +function! s:FindIndToken(lnum, dir) + let lnum = a:lnum + while 1 + let lnum += (a:dir ==# 'up' ? -1 : 1) + let [lnum, indtokens] = s:TokenizeLine(lnum, a:dir) + if lnum ==# 0 + " We hit the beginning or end of the file + return [] + elseif !empty(indtokens) + return indtokens[a:dir ==# 'up' ? -1 : 0] + endif + endwhile +endfunction + +" Purpose: +" Find the token that directly precedes the given token. +" Parameters: +" lnum: integer -- the line of the given token +" i: the index of the given token within line `lnum` +" Returns: +" result = [] -- the result is an empty list if the given token is the first +" token of the file +" | indtoken +function! s:PrevIndToken(lnum, i) + call s:Log(' PrevIndToken called: lnum=' . a:lnum . ', i =' . a:i) + + " If the current line has a previous token, return that + if a:i > 0 + return s:all_tokens[a:lnum][a:i - 1] + else + return s:FindIndToken(a:lnum, 'up') + endif +endfunction + +" Purpose: +" Find the token that directly succeeds the given token. +" Parameters: +" lnum: integer -- the line of the given token +" i: the index of the given token within line `lnum` +" Returns: +" result = [] -- the result is an empty list if the given token is the last +" token of the file +" | indtoken +function! s:NextIndToken(lnum, i) + call s:Log(' NextIndToken called: lnum=' . a:lnum . ', i =' . a:i) + + " If the current line has a next token, return that + if len(s:all_tokens[a:lnum]) > a:i + 1 + return s:all_tokens[a:lnum][a:i + 1] + else + return s:FindIndToken(a:lnum, 'down') + endif +endfunction + +" ErlangCalcIndent helper functions {{{1 +" ================================= + +" Purpose: +" This function is called when the parser encounters a syntax error. +" +" If we encounter a syntax error, we return +" g:erlang_unexpected_token_indent, which is -1 by default. This means that +" the indentation of the LTI will not be changed. +" Parameter: +" msg: string +" token: string +" stack: [token] +" Returns: +" indent: integer +function! s:IndentError(msg, token, stack) + call s:Log('Indent error: ' . a:msg . ' -> return') + call s:Log(' Token = ' . a:token . ', ' . + \' stack = ' . string(a:stack)) + return g:erlang_unexpected_token_indent +endfunction + +" Purpose: +" This function is called when the parser encounters an unexpected token, +" and the parser will return the number given back by UnexpectedToken. +" +" If we encounter an unexpected token, we return +" g:erlang_unexpected_token_indent, which is -1 by default. This means that +" the indentation of the LTI will not be changed. +" Parameter: +" token: string +" stack: [token] +" Returns: +" indent: integer +function! s:UnexpectedToken(token, stack) + call s:Log(' Unexpected token ' . a:token . ', stack = ' . + \string(a:stack) . ' -> return') + return g:erlang_unexpected_token_indent +endfunction + +if !exists('g:erlang_unexpected_token_indent') + let g:erlang_unexpected_token_indent = -1 +endif + +" Purpose: +" Return whether the given line starts with a string continuation. +" Parameter: +" lnum: integer +" Returns: +" result: bool +" Example: +" f() -> % IsLineStringContinuation = false +" "This is a % IsLineStringContinuation = false +" multiline % IsLineStringContinuation = true +" string". % IsLineStringContinuation = true +function! s:IsLineStringContinuation(lnum) + if has('syntax_items') + return synIDattr(synID(a:lnum, 1, 0), 'name') =~# '^erlangString' + else + return 0 + endif +endfunction + +" Purpose: +" Return whether the given line starts with an atom continuation. +" Parameter: +" lnum: integer +" Returns: +" result: bool +" Example: +" 'function with % IsLineAtomContinuation = true, but should be false +" weird name'() -> % IsLineAtomContinuation = true +" ok. % IsLineAtomContinuation = false +function! s:IsLineAtomContinuation(lnum) + if has('syntax_items') + return synIDattr(synID(a:lnum, 1, 0), 'name') =~# '^erlangQuotedAtom' + else + return 0 + endif +endfunction + +" Purpose: +" Return whether the 'catch' token (which should be the `i`th token in line +" `lnum`) is standalone or part of a try-catch block, based on the preceding +" token. +" Parameters: +" lnum: integer +" i: integer +" Return: +" is_standalone: bool +function! s:IsCatchStandalone(lnum, i) + call s:Log(' IsCatchStandalone called: lnum=' . a:lnum . ', i=' . a:i) + let prev_indtoken = s:PrevIndToken(a:lnum, a:i) + + " If we hit the beginning of the file, it is not a catch in a try block + if prev_indtoken == [] + return 1 + endif + + let prev_token = prev_indtoken[0] + + if prev_token =~# '[A-Z_@0-9]' + let is_standalone = 0 + elseif prev_token =~# '[a-z]' + if index(['after', 'and', 'andalso', 'band', 'begin', 'bnot', 'bor', 'bsl', + \ 'bsr', 'bxor', 'case', 'catch', 'div', 'not', 'or', 'orelse', + \ 'rem', 'try', 'xor'], prev_token) != -1 + " If catch is after these keywords, it is standalone + let is_standalone = 1 + else + " If catch is after another keyword (e.g. 'end') or an atom, it is + " part of try-catch. + " + " Keywords: + " - may precede 'catch': end + " - may not precede 'catch': fun if of receive when + " - unused: cond let query + let is_standalone = 0 + endif + elseif index([')', ']', '}', '', '', '', + \ '', '$.'], prev_token) != -1 + let is_standalone = 0 + else + " This 'else' branch includes the following tokens: + " -> == /= =< < >= > =:= =/= + - * / ++ -- :: < > ; ( [ { ? = ! . | + let is_standalone = 1 + endif + + call s:Log(' "catch" preceded by "' . prev_token . '" -> catch ' . + \(is_standalone ? 'is standalone' : 'belongs to try-catch')) + return is_standalone + +endfunction + +" Purpose: +" This function is called when a begin-type element ('begin', 'case', +" '[', '<<', etc.) is found. It asks the caller to return if the stack +" Parameters: +" stack: [token] +" token: string +" curr_vcol: integer +" stored_vcol: integer +" sw: integer -- number of spaces to be used after the begin element as +" indentation +" Returns: +" result: [should_return, indent] +" should_return: bool -- if true, the caller should return `indent` to Vim +" indent -- integer +function! s:BeginElementFoundIfEmpty(stack, token, curr_vcol, stored_vcol, sw) + if empty(a:stack) + if a:stored_vcol ==# -1 + call s:Log(' "' . a:token . '" directly preceeds LTI -> return') + return [1, a:curr_vcol + a:sw] + else + call s:Log(' "' . a:token . + \'" token (whose expression includes LTI) found -> return') + return [1, a:stored_vcol] + endif + else + return [0, 0] + endif +endfunction + +" Purpose: +" This function is called when a begin-type element ('begin', 'case', '[', +" '<<', etc.) is found, and in some cases when 'after' and 'when' is found. +" It asks the caller to return if the stack is already empty. +" Parameters: +" stack: [token] +" token: string +" curr_vcol: integer +" stored_vcol: integer +" end_token: end token that belongs to the begin element found (e.g. if the +" begin element is 'begin', the end token is 'end') +" sw: integer -- number of spaces to be used after the begin element as +" indentation +" Returns: +" result: [should_return, indent] +" should_return: bool -- if true, the caller should return `indent` to Vim +" indent -- integer +function! s:BeginElementFound(stack, token, curr_vcol, stored_vcol, end_token, sw) + + " Return 'return' if the stack is empty + let [ret, res] = s:BeginElementFoundIfEmpty(a:stack, a:token, a:curr_vcol, + \a:stored_vcol, a:sw) + if ret | return [ret, res] | endif + + if a:stack[0] ==# a:end_token + call s:Log(' "' . a:token . '" pops "' . a:end_token . '"') + call s:Pop(a:stack) + if !empty(a:stack) && a:stack[0] ==# 'align_to_begin_element' + call s:Pop(a:stack) + if empty(a:stack) + return [1, a:curr_vcol] + else + return [1, s:UnexpectedToken(a:token, a:stack)] + endif + else + return [0, 0] + endif + else + return [1, s:UnexpectedToken(a:token, a:stack)] + endif +endfunction + +" Purpose: +" This function is called when we hit the beginning of a file or an +" end-of-clause token -- i.e. when we found the beginning of the current +" clause. +" +" If the stack contains an '->' or 'when', this means that we can return +" now, since we were looking for the beginning of the clause. +" Parameters: +" stack: [token] +" token: string +" stored_vcol: integer +" Returns: +" result: [should_return, indent] +" should_return: bool -- if true, the caller should return `indent` to Vim +" indent -- integer +function! s:BeginningOfClauseFound(stack, token, stored_vcol) + if !empty(a:stack) && a:stack[0] ==# 'when' + call s:Log(' BeginningOfClauseFound: "when" found in stack') + call s:Pop(a:stack) + if empty(a:stack) + call s:Log(' Stack is ["when"], so LTI is in a guard -> return') + return [1, a:stored_vcol + shiftwidth() + 2] + else + return [1, s:UnexpectedToken(a:token, a:stack)] + endif + elseif !empty(a:stack) && a:stack[0] ==# '->' + call s:Log(' BeginningOfClauseFound: "->" found in stack') + call s:Pop(a:stack) + if empty(a:stack) + call s:Log(' Stack is ["->"], so LTI is in function body -> return') + return [1, a:stored_vcol + shiftwidth()] + elseif a:stack[0] ==# ';' + call s:Pop(a:stack) + if empty(a:stack) + call s:Log(' Stack is ["->", ";"], so LTI is in a function head ' . + \'-> return') + return [0, a:stored_vcol] + else + return [1, s:UnexpectedToken(a:token, a:stack)] + endif + else + return [1, s:UnexpectedToken(a:token, a:stack)] + endif + else + return [0, 0] + endif +endfunction + +let g:erlang_indent_searchpair_timeout = 2000 + +" TODO +function! s:SearchPair(lnum, curr_col, start, middle, end) + call cursor(a:lnum, a:curr_col + 1) + let [lnum_new, col1_new] = + \searchpairpos(a:start, a:middle, a:end, 'bW', + \'synIDattr(synID(line("."), col("."), 0), "name") ' . + \'=~? "string\\|quotedatom\\|todo\\|comment\\|' . + \'erlangmodifier"', + \0, g:erlang_indent_searchpair_timeout) + return [lnum_new, col1_new - 1] +endfunction + +function! s:SearchEndPair(lnum, curr_col) + return s:SearchPair( + \ a:lnum, a:curr_col, + \ '\C\<\%(case\|try\|begin\|receive\|if\)\>\|' . + \ '\\%(\s\|\n\|%.*$\)*(', + \ '', + \ '\') +endfunction + +" ErlangCalcIndent {{{1 +" ================ + +" Purpose: +" Calculate the indentation of the given line. +" Parameters: +" lnum: integer -- index of the line for which the indentation should be +" calculated +" stack: [token] -- initial stack +" Return: +" indent: integer -- if -1, that means "don't change the indentation"; +" otherwise it means "indent the line with `indent` +" number of spaces or equivalent tabs" +function! s:ErlangCalcIndent(lnum, stack) + let res = s:ErlangCalcIndent2(a:lnum, a:stack) + call s:Log("ErlangCalcIndent returned: " . res) + return res +endfunction + +function! s:ErlangCalcIndent2(lnum, stack) + + let lnum = a:lnum + let stored_vcol = -1 " Virtual column of the first character of the token that + " we currently think we might align to. + let mode = 'normal' + let stack = a:stack + let semicolon_abscol = '' + + " Walk through the lines of the buffer backwards (starting from the + " previous line) until we can decide how to indent the current line. + while 1 + + let [lnum, indtokens] = s:TokenizeLine(lnum, 'up') + + " Hit the start of the file + if lnum ==# 0 + let [ret, res] = s:BeginningOfClauseFound(stack, 'beginning_of_file', + \stored_vcol) + if ret | return res | endif + + return 0 + endif + + let i = len(indtokens) - 1 + let last_token_of_line = 1 + + while i >= 0 + + let [token, curr_vcol, curr_col] = indtokens[i] + call s:Log(' Analyzing the following token: ' . string(indtokens[i])) + + if len(stack) > 256 " TODO: magic number + return s:IndentError('Stack too long', token, stack) + endif + + if token ==# '' + let [ret, res] = s:BeginningOfClauseFound(stack, token, stored_vcol) + if ret | return res | endif + + if stored_vcol ==# -1 + call s:Log(' End of clause directly preceeds LTI -> return') + return 0 + else + call s:Log(' End of clause (but not end of line) -> return') + return stored_vcol + endif + + elseif stack == ['prev_term_plus'] + if token =~# '[a-zA-Z_@]' || + \ token ==# '' || token ==# '' || + \ token ==# '' || token ==# '' + call s:Log(' previous token found: curr_vcol + plus = ' . + \curr_vcol . " + " . plus) + return curr_vcol + plus + endif + + elseif token ==# 'begin' + let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, + \stored_vcol, 'end', shiftwidth()) + if ret | return res | endif + + " case EXPR of BRANCHES end + " try EXPR catch BRANCHES end + " try EXPR after BODY end + " try EXPR catch BRANCHES after BODY end + " try EXPR of BRANCHES catch BRANCHES end + " try EXPR of BRANCHES after BODY end + " try EXPR of BRANCHES catch BRANCHES after BODY end + " receive BRANCHES end + " receive BRANCHES after BRANCHES end + + " This branch is not Emacs-compatible + elseif (index(['of', 'receive', 'after', 'if'], token) != -1 || + \ (token ==# 'catch' && !s:IsCatchStandalone(lnum, i))) && + \ !last_token_of_line && + \ (empty(stack) || stack ==# ['when'] || stack ==# ['->'] || + \ stack ==# ['->', ';']) + + " If we are after of/receive, but these are not the last + " tokens of the line, we want to indent like this: + " + " % stack == [] + " receive stored_vcol, + " LTI + " + " % stack == ['->', ';'] + " receive stored_vcol -> + " B; + " LTI + " + " % stack == ['->'] + " receive stored_vcol -> + " LTI + " + " % stack == ['when'] + " receive stored_vcol when + " LTI + + " stack = [] => LTI is a condition + " stack = ['->'] => LTI is a branch + " stack = ['->', ';'] => LTI is a condition + " stack = ['when'] => LTI is a guard + if empty(stack) || stack == ['->', ';'] + call s:Log(' LTI is in a condition after ' . + \'"of/receive/after/if/catch" -> return') + return stored_vcol + elseif stack == ['->'] + call s:Log(' LTI is in a branch after ' . + \'"of/receive/after/if/catch" -> return') + return stored_vcol + shiftwidth() + elseif stack == ['when'] + call s:Log(' LTI is in a guard after ' . + \'"of/receive/after/if/catch" -> return') + return stored_vcol + shiftwidth() + else + return s:UnexpectedToken(token, stack) + endif + + elseif index(['case', 'if', 'try', 'receive'], token) != -1 + + " stack = [] => LTI is a condition + " stack = ['->'] => LTI is a branch + " stack = ['->', ';'] => LTI is a condition + " stack = ['when'] => LTI is in a guard + if empty(stack) + " pass + elseif (token ==# 'case' && stack[0] ==# 'of') || + \ (token ==# 'if') || + \ (token ==# 'try' && (stack[0] ==# 'of' || + \ stack[0] ==# 'catch' || + \ stack[0] ==# 'after')) || + \ (token ==# 'receive') + + " From the indentation point of view, the keyword + " (of/catch/after/end) before the LTI is what counts, so + " when we reached these tokens, and the stack already had + " a catch/after/end, we didn't modify it. + " + " This way when we reach case/try/receive (i.e. now), + " there is at most one of/catch/after/end token in the + " stack. + if token ==# 'case' || token ==# 'try' || + \ (token ==# 'receive' && stack[0] ==# 'after') + call s:Pop(stack) + endif + + if empty(stack) + call s:Log(' LTI is in a condition; matching ' . + \'"case/if/try/receive" found') + let stored_vcol = curr_vcol + shiftwidth() + elseif stack[0] ==# 'align_to_begin_element' + call s:Pop(stack) + let stored_vcol = curr_vcol + elseif len(stack) > 1 && stack[0] ==# '->' && stack[1] ==# ';' + call s:Log(' LTI is in a condition; matching ' . + \'"case/if/try/receive" found') + call s:Pop(stack) + call s:Pop(stack) + let stored_vcol = curr_vcol + shiftwidth() + elseif stack[0] ==# '->' + call s:Log(' LTI is in a branch; matching ' . + \'"case/if/try/receive" found') + call s:Pop(stack) + let stored_vcol = curr_vcol + 2 * shiftwidth() + elseif stack[0] ==# 'when' + call s:Log(' LTI is in a guard; matching ' . + \'"case/if/try/receive" found') + call s:Pop(stack) + let stored_vcol = curr_vcol + 2 * shiftwidth() + 2 + endif + + endif + + let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, + \stored_vcol, 'end', shiftwidth()) + if ret | return res | endif + + elseif token ==# 'fun' + let next_indtoken = s:NextIndToken(lnum, i) + call s:Log(' Next indtoken = ' . string(next_indtoken)) + + if !empty(next_indtoken) && next_indtoken[0] ==# '(' + " We have an anonymous function definition + " (e.g. "fun () -> ok end") + + " stack = [] => LTI is a condition + " stack = ['->'] => LTI is a branch + " stack = ['->', ';'] => LTI is a condition + " stack = ['when'] => LTI is in a guard + if empty(stack) + call s:Log(' LTI is in a condition; matching "fun" found') + let stored_vcol = curr_vcol + shiftwidth() + elseif len(stack) > 1 && stack[0] ==# '->' && stack[1] ==# ';' + call s:Log(' LTI is in a condition; matching "fun" found') + call s:Pop(stack) + call s:Pop(stack) + elseif stack[0] ==# '->' + call s:Log(' LTI is in a branch; matching "fun" found') + call s:Pop(stack) + let stored_vcol = curr_vcol + 2 * shiftwidth() + elseif stack[0] ==# 'when' + call s:Log(' LTI is in a guard; matching "fun" found') + call s:Pop(stack) + let stored_vcol = curr_vcol + 2 * shiftwidth() + 2 + endif + + let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, + \stored_vcol, 'end', shiftwidth()) + if ret | return res | endif + else + " Pass: we have a function reference (e.g. "fun f/0") + endif + + elseif token ==# '[' + " Emacs compatibility + let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, + \stored_vcol, ']', 1) + if ret | return res | endif + + elseif token ==# '<<' + " Emacs compatibility + let [ret, res] = s:BeginElementFound(stack, token, curr_vcol, + \stored_vcol, '>>', 2) + if ret | return res | endif + + elseif token ==# '(' || token ==# '{' + + let end_token = (token ==# '(' ? ')' : + \token ==# '{' ? '}' : 'error') + + if empty(stack) + " We found the opening paren whose block contains the LTI. + let mode = 'inside' + elseif stack[0] ==# end_token + call s:Log(' "' . token . '" pops "' . end_token . '"') + call s:Pop(stack) + + if !empty(stack) && stack[0] ==# 'align_to_begin_element' + " We found the opening paren whose closing paren + " starts LTI + let mode = 'align_to_begin_element' + else + " We found the opening pair for a closing paren that + " was already in the stack. + let mode = 'outside' + endif + else + return s:UnexpectedToken(token, stack) + endif + + if mode ==# 'inside' || mode ==# 'align_to_begin_element' + + if last_token_of_line && i != 0 + " Examples: {{{ + " + " mode == 'inside': + " + " my_func( + " LTI + " + " [Variable, { + " LTI + " + " mode == 'align_to_begin_element': + " + " my_func( + " Params + " ) % LTI + " + " [Variable, { + " Terms + " } % LTI + " }}} + let stack = ['prev_term_plus'] + let plus = (mode ==# 'inside' ? 2 : 1) + call s:Log(' "' . token . + \'" token found at end of line -> find previous token') + elseif mode ==# 'align_to_begin_element' + " Examples: {{{ + " + " mode == 'align_to_begin_element' && !last_token_of_line + " + " my_func(stored_vcol + " ) % LTI + " + " [Variable, {stored_vcol + " } % LTI + " + " mode == 'align_to_begin_element' && i == 0 + " + " ( + " stored_vcol + " ) % LTI + " + " { + " stored_vcol + " } % LTI + " }}} + call s:Log(' "' . token . '" token (whose closing token ' . + \'starts LTI) found -> return') + return curr_vcol + elseif stored_vcol ==# -1 + " Examples: {{{ + " + " mode == 'inside' && stored_vcol == -1 && !last_token_of_line + " + " my_func( + " LTI + " [Variable, { + " LTI + " + " mode == 'inside' && stored_vcol == -1 && i == 0 + " + " ( + " LTI + " + " { + " LTI + " }}} + call s:Log(' "' . token . + \'" token (which directly precedes LTI) found -> return') + return curr_vcol + 1 + else + " Examples: {{{ + " + " mode == 'inside' && stored_vcol != -1 && !last_token_of_line + " + " my_func(stored_vcol, + " LTI + " + " [Variable, {stored_vcol, + " LTI + " + " mode == 'inside' && stored_vcol != -1 && i == 0 + " + " (stored_vcol, + " LTI + " + " {stored_vcol, + " LTI + " }}} + call s:Log(' "' . token . + \'" token (whose block contains LTI) found -> return') + return stored_vcol + endif + endif + + elseif index(['end', ')', ']', '}', '>>'], token) != -1 + + " If we can be sure that there is synchronization in the Erlang + " syntax, we use searchpair to make the script quicker. Otherwise we + " just push the token onto the stack and keep parsing. + + " No synchronization -> no searchpair optimization + if !exists('b:erlang_syntax_synced') + call s:Push(stack, token) + + " We don't have searchpair optimization for '>>' + elseif token ==# '>>' + call s:Push(stack, token) + + elseif token ==# 'end' + let [lnum_new, col_new] = s:SearchEndPair(lnum, curr_col) + + if lnum_new ==# 0 + return s:IndentError('Matching token for "end" not found', + \token, stack) + else + if lnum_new != lnum + call s:Log(' Tokenize for "end" <<<<') + let [lnum, indtokens] = s:TokenizeLine(lnum_new, 'up') + call s:Log(' >>>> Tokenize for "end"') + endif + + let [success, i] = s:GetIndtokenAtCol(indtokens, col_new) + if !success | return i | endif + let [token, curr_vcol, curr_col] = indtokens[i] + call s:Log(' Match for "end" in line ' . lnum_new . ': ' . + \string(indtokens[i])) + endif + + else " token is one of the following: ')', ']', '}' + + call s:Push(stack, token) + + " We have to escape '[', because this string will be interpreted as a + " regexp + let open_paren = (token ==# ')' ? '(' : + \token ==# ']' ? '\[' : + \ '{') + + let [lnum_new, col_new] = s:SearchPair(lnum, curr_col, + \open_paren, '', token) + + if lnum_new ==# 0 + return s:IndentError('Matching token not found', + \token, stack) + else + if lnum_new != lnum + call s:Log(' Tokenize the opening paren <<<<') + let [lnum, indtokens] = s:TokenizeLine(lnum_new, 'up') + call s:Log(' >>>>') + endif + + let [success, i] = s:GetIndtokenAtCol(indtokens, col_new) + if !success | return i | endif + let [token, curr_vcol, curr_col] = indtokens[i] + call s:Log(' Match in line ' . lnum_new . ': ' . + \string(indtokens[i])) + + " Go back to the beginning of the loop and handle the opening paren + continue + endif + endif + + elseif token ==# ';' + + if empty(stack) + call s:Push(stack, ';') + elseif index([';', '->', 'when', 'end', 'after', 'catch'], + \stack[0]) != -1 + " Pass: + " + " - If the stack top is another ';', then one ';' is + " enough. + " - If the stack top is an '->' or a 'when', then we + " should keep that, because they signify the type of the + " LTI (branch, condition or guard). + " - From the indentation point of view, the keyword + " (of/catch/after/end) before the LTI is what counts, so + " if the stack already has a catch/after/end, we don't + " modify it. This way when we reach case/try/receive, + " there will be at most one of/catch/after/end token in + " the stack. + else + return s:UnexpectedToken(token, stack) + endif + + elseif token ==# '->' + + if empty(stack) && !last_token_of_line + call s:Log(' LTI is in expression after arrow -> return') + return stored_vcol + elseif empty(stack) || stack[0] ==# ';' || stack[0] ==# 'end' + " stack = [';'] -> LTI is either a branch or in a guard + " stack = ['->'] -> LTI is a condition + " stack = ['->', ';'] -> LTI is a branch + call s:Push(stack, '->') + elseif index(['->', 'when', 'end', 'after', 'catch'], stack[0]) != -1 + " Pass: + " + " - If the stack top is another '->', then one '->' is + " enough. + " - If the stack top is a 'when', then we should keep + " that, because this signifies that LTI is a in a guard. + " - From the indentation point of view, the keyword + " (of/catch/after/end) before the LTI is what counts, so + " if the stack already has a catch/after/end, we don't + " modify it. This way when we reach case/try/receive, + " there will be at most one of/catch/after/end token in + " the stack. + else + return s:UnexpectedToken(token, stack) + endif + + elseif token ==# 'when' + + " Pop all ';' from the top of the stack + while !empty(stack) && stack[0] ==# ';' + call s:Pop(stack) + endwhile + + if empty(stack) + if semicolon_abscol != '' + let stored_vcol = semicolon_abscol + endif + if !last_token_of_line + " Example: + " when A, + " LTI + let [ret, res] = s:BeginElementFoundIfEmpty(stack, token, curr_vcol, + \stored_vcol, shiftwidth()) + if ret | return res | endif + else + " Example: + " when + " LTI + call s:Push(stack, token) + endif + elseif index(['->', 'when', 'end', 'after', 'catch'], stack[0]) != -1 + " Pass: + " - If the stack top is another 'when', then one 'when' is + " enough. + " - If the stack top is an '->' or a 'when', then we + " should keep that, because they signify the type of the + " LTI (branch, condition or guard). + " - From the indentation point of view, the keyword + " (of/catch/after/end) before the LTI is what counts, so + " if the stack already has a catch/after/end, we don't + " modify it. This way when we reach case/try/receive, + " there will be at most one of/catch/after/end token in + " the stack. + else + return s:UnexpectedToken(token, stack) + endif + + elseif token ==# 'of' || token ==# 'after' || + \ (token ==# 'catch' && !s:IsCatchStandalone(lnum, i)) + + if token ==# 'after' + " If LTI is between an 'after' and the corresponding + " 'end', then let's return + let [ret, res] = s:BeginElementFoundIfEmpty(stack, token, curr_vcol, + \stored_vcol, shiftwidth()) + if ret | return res | endif + endif + + if empty(stack) || stack[0] ==# '->' || stack[0] ==# 'when' + call s:Push(stack, token) + elseif stack[0] ==# 'catch' || stack[0] ==# 'after' || stack[0] ==# 'end' + " Pass: From the indentation point of view, the keyword + " (of/catch/after/end) before the LTI is what counts, so + " if the stack already has a catch/after/end, we don't + " modify it. This way when we reach case/try/receive, + " there will be at most one of/catch/after/end token in + " the stack. + else + return s:UnexpectedToken(token, stack) + endif + + elseif token ==# '||' && empty(stack) && !last_token_of_line + + call s:Log(' LTI is in expression after "||" -> return') + return stored_vcol + + else + call s:Log(' Misc token, stack unchanged = ' . string(stack)) + + endif + + if empty(stack) || stack[0] ==# '->' || stack[0] ==# 'when' + let stored_vcol = curr_vcol + let semicolon_abscol = '' + call s:Log(' Misc token when the stack is empty or has "->" ' . + \'-> setting stored_vcol to ' . stored_vcol) + elseif stack[0] ==# ';' + let semicolon_abscol = curr_vcol + call s:Log(' Setting semicolon-stored_vcol to ' . stored_vcol) + endif + + let i -= 1 + call s:Log(' Token processed. stored_vcol=' . stored_vcol) + + let last_token_of_line = 0 + + endwhile " iteration on tokens in a line + + call s:Log(' Line analyzed. stored_vcol=' . stored_vcol) + + if empty(stack) && stored_vcol != -1 && + \ (!empty(indtokens) && indtokens[0][0] != '' && + \ indtokens[0][0] != '') + call s:Log(' Empty stack at the beginning of the line -> return') + return stored_vcol + endif + + let lnum -= 1 + + endwhile " iteration on lines + +endfunction + +" ErlangIndent function {{{1 +" ===================== + +function! ErlangIndent() + + call s:ClearTokenCacheIfNeeded() + + let currline = getline(v:lnum) + call s:Log('Indenting line ' . v:lnum . ': ' . currline) + + if s:IsLineStringContinuation(v:lnum) || s:IsLineAtomContinuation(v:lnum) + call s:Log('String or atom continuation found -> ' . + \'leaving indentation unchanged') + return -1 + endif + + let ml = matchlist(currline, + \'^\(\s*\)\(\%(end\|of\|catch\|after\)\>\|[)\]}]\|>>\)') + + " If the line has a special beginning, but not a standalone catch + if !empty(ml) && !(ml[2] ==# 'catch' && s:IsCatchStandalone(v:lnum, 0)) + + let curr_col = len(ml[1]) + + " If we can be sure that there is synchronization in the Erlang + " syntax, we use searchpair to make the script quicker. + if ml[2] ==# 'end' && exists('b:erlang_syntax_synced') + + let [lnum, col] = s:SearchEndPair(v:lnum, curr_col) + + if lnum ==# 0 + return s:IndentError('Matching token for "end" not found', + \'end', []) + else + call s:Log(' Tokenize for "end" <<<<') + let [lnum, indtokens] = s:TokenizeLine(lnum, 'up') + call s:Log(' >>>> Tokenize for "end"') + + let [success, i] = s:GetIndtokenAtCol(indtokens, col) + if !success | return i | endif + let [token, curr_vcol, curr_col] = indtokens[i] + call s:Log(' Match for "end" in line ' . lnum . ': ' . + \string(indtokens[i])) + return curr_vcol + endif + + else + + call s:Log(" Line type = 'end'") + let new_col = s:ErlangCalcIndent(v:lnum - 1, + \[ml[2], 'align_to_begin_element']) + endif + else + call s:Log(" Line type = 'normal'") + + let new_col = s:ErlangCalcIndent(v:lnum - 1, []) + if currline =~# '^\s*when\>' + let new_col += 2 + endif + endif + + if new_col < -1 + call s:Log('WARNING: returning new_col == ' . new_col) + return g:erlang_unexpected_token_indent + endif + + return new_col + +endfunction + +" Cleanup {{{1 +" ======= + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: sw=2 et fdm=marker + +endif if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'erlang') == -1 " Vim indent file diff --git a/indent/eruby.vim b/indent/eruby.vim index 6fd76600..3bae537e 100644 --- a/indent/eruby.vim +++ b/indent/eruby.vim @@ -1,3 +1,112 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: eRuby +" Maintainer: Tim Pope +" URL: https://github.com/vim-ruby/vim-ruby +" Release Coordinator: Doug Kearns + +if exists("b:did_indent") + finish +endif + +runtime! indent/ruby.vim +unlet! b:did_indent +setlocal indentexpr= + +if exists("b:eruby_subtype") + exe "runtime! indent/".b:eruby_subtype.".vim" +else + runtime! indent/html.vim +endif +unlet! b:did_indent + +" Force HTML indent to not keep state. +let b:html_indent_usestate = 0 + +if &l:indentexpr == '' + if &l:cindent + let &l:indentexpr = 'cindent(v:lnum)' + else + let &l:indentexpr = 'indent(prevnonblank(v:lnum-1))' + endif +endif +let b:eruby_subtype_indentexpr = &l:indentexpr + +let b:did_indent = 1 + +setlocal indentexpr=GetErubyIndent() +setlocal indentkeys=o,O,*,<>>,{,},0),0],o,O,!^F,=end,=else,=elsif,=rescue,=ensure,=when + +" Only define the function once. +if exists("*GetErubyIndent") + finish +endif + +" this file uses line continuations +let s:cpo_sav = &cpo +set cpo&vim + +function! GetErubyIndent(...) + " The value of a single shift-width + let sw = shiftwidth() + + if a:0 && a:1 == '.' + let v:lnum = line('.') + elseif a:0 && a:1 =~ '^\d' + let v:lnum = a:1 + endif + let vcol = col('.') + call cursor(v:lnum,1) + let inruby = searchpair('<%','','%>','W') + call cursor(v:lnum,vcol) + if inruby && getline(v:lnum) !~ '^<%\|^\s*[-=]\=%>' + let ind = GetRubyIndent(v:lnum) + else + exe "let ind = ".b:eruby_subtype_indentexpr + + " Workaround for Andy Wokula's HTML indent. This should be removed after + " some time, since the newest version is fixed in a different way. + if b:eruby_subtype_indentexpr =~# '^HtmlIndent(' + \ && exists('b:indent') + \ && type(b:indent) == type({}) + \ && has_key(b:indent, 'lnum') + " Force HTML indent to not keep state + let b:indent.lnum = -1 + endif + endif + let lnum = prevnonblank(v:lnum-1) + let line = getline(lnum) + let cline = getline(v:lnum) + if cline =~# '^\s*<%[-=]\=\s*\%(}\|end\|else\|\%(ensure\|rescue\|elsif\|when\).\{-\}\)\s*\%([-=]\=%>\|$\)' + let ind = ind - sw + endif + if line =~# '\S\s*<%[-=]\=\s*\%(}\|end\).\{-\}\s*\%([-=]\=%>\|$\)' + let ind = ind - sw + endif + if line =~# '\%({\|\' + let ind = ind + sw + elseif line =~# '<%[-=]\=\s*\%(module\|class\|def\|if\|for\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure\|rescue\)\>.*%>' + let ind = ind + sw + endif + if line =~# '^\s*<%[=#-]\=\s*$' && cline !~# '^\s*end\>' + let ind = ind + sw + endif + if line !~# '^\s*<%' && line =~# '%>\s*$' && line !~# '^\s*end\>' + let ind = ind - sw + endif + if cline =~# '^\s*[-=]\=%>\s*$' + let ind = ind - sw + endif + return ind +endfunction + +let &cpo = s:cpo_sav +unlet! s:cpo_sav + +" vim:set sw=2 sts=2 ts=8 noet: + +endif if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'ruby') == -1 " Vim indent file diff --git a/indent/eterm.vim b/indent/eterm.vim new file mode 100644 index 00000000..df80c058 --- /dev/null +++ b/indent/eterm.vim @@ -0,0 +1,40 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Eterm configuration file +" Previous Maintainer: Nikolai Weibull +" Latest Revision: 2006-12-20 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentexpr=GetEtermIndent() +setlocal indentkeys=!^F,o,O,=end +setlocal nosmartindent + +if exists("*GetEtermIndent") + finish +endif + +function GetEtermIndent() + let lnum = prevnonblank(v:lnum - 1) + if lnum == 0 + return 0 + endif + + let ind = indent(lnum) + + if getline(lnum) =~ '^\s*begin\>' + let ind = ind + shiftwidth() + endif + + if getline(v:lnum) =~ '^\s*end\>' + let ind = ind - shiftwidth() + endif + + return ind +endfunction + +endif diff --git a/indent/falcon.vim b/indent/falcon.vim new file mode 100644 index 00000000..4d17d33d --- /dev/null +++ b/indent/falcon.vim @@ -0,0 +1,455 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Falcon +" Maintainer: Steven Oliver +" Website: https://steveno@github.com/steveno/falconpl-vim.git +" Credits: This is, to a great extent, a copy n' paste of ruby.vim. + +" 1. Setup {{{1 +" ============ + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal nosmartindent + +" Setup indent function and when to use it +setlocal indentexpr=FalconGetIndent(v:lnum) +setlocal indentkeys=0{,0},0),0],!^F,o,O,e +setlocal indentkeys+==~case,=~catch,=~default,=~elif,=~else,=~end,=~\" + +" Define the appropriate indent function but only once +if exists("*FalconGetIndent") + finish +endif + +let s:cpo_save = &cpo +set cpo&vim + +" 2. Variables {{{1 +" ============ + +" Regex of syntax group names that are strings AND comments +let s:syng_strcom = '\' + +" Regex of syntax group names that are strings +let s:syng_string = '\' + +" Regex that defines blocks. +" +" Note that there's a slight problem with this regex and s:continuation_regex. +" Code like this will be matched by both: +" +" method_call do |(a, b)| +" +" The reason is that the pipe matches a hanging "|" operator. +" +let s:block_regex = + \ '\%(\\|%\@ 0 + " Go in and out of blocks comments as necessary. + " If the line isn't empty (with opt. comment) or in a string, end search. + let line = getline(lnum) + if line =~ '^=begin' + if in_block + let in_block = 0 + else + break + endif + elseif !in_block && line =~ '^=end' + let in_block = 1 + elseif !in_block && line !~ '^\s*#.*$' && !(s:IsInStringOrComment(lnum, 1) + \ && s:IsInStringOrComment(lnum, strlen(line))) + break + endif + let lnum = prevnonblank(lnum - 1) + endwhile + return lnum +endfunction + +" Find line above 'lnum' that started the continuation 'lnum' may be part of. +function s:GetMSL(lnum) + " Start on the line we're at and use its indent. + let msl = a:lnum + let msl_body = getline(msl) + let lnum = s:PrevNonBlankNonString(a:lnum - 1) + while lnum > 0 + " If we have a continuation line, or we're in a string, use line as MSL. + " Otherwise, terminate search as we have found our MSL already. + let line = getline(lnum) + + if s:Match(line, s:non_bracket_continuation_regex) && + \ s:Match(msl, s:non_bracket_continuation_regex) + " If the current line is a non-bracket continuation and so is the + " previous one, keep its indent and continue looking for an MSL. + " + " Example: + " method_call one, + " two, + " three + " + let msl = lnum + elseif s:Match(lnum, s:non_bracket_continuation_regex) && + \ (s:Match(msl, s:bracket_continuation_regex) || s:Match(msl, s:block_continuation_regex)) + " If the current line is a bracket continuation or a block-starter, but + " the previous is a non-bracket one, respect the previous' indentation, + " and stop here. + " + " Example: + " method_call one, + " two { + " three + " + return lnum + elseif s:Match(lnum, s:bracket_continuation_regex) && + \ (s:Match(msl, s:bracket_continuation_regex) || s:Match(msl, s:block_continuation_regex)) + " If both lines are bracket continuations (the current may also be a + " block-starter), use the current one's and stop here + " + " Example: + " method_call( + " other_method_call( + " foo + return msl + elseif s:Match(lnum, s:block_regex) && + \ !s:Match(msl, s:continuation_regex) && + \ !s:Match(msl, s:block_continuation_regex) + " If the previous line is a block-starter and the current one is + " mostly ordinary, use the current one as the MSL. + " + " Example: + " method_call do + " something + " something_else + return msl + else + let col = match(line, s:continuation_regex) + 1 + if (col > 0 && !s:IsInStringOrComment(lnum, col)) + \ || s:IsInString(lnum, strlen(line)) + let msl = lnum + else + break + endif + endif + + let msl_body = getline(msl) + let lnum = s:PrevNonBlankNonString(lnum - 1) + endwhile + return msl +endfunction + +" Check if line 'lnum' has more opening brackets than closing ones. +function s:ExtraBrackets(lnum) + let opening = {'parentheses': [], 'braces': [], 'brackets': []} + let closing = {'parentheses': [], 'braces': [], 'brackets': []} + + let line = getline(a:lnum) + let pos = match(line, '[][(){}]', 0) + + " Save any encountered opening brackets, and remove them once a matching + " closing one has been found. If a closing bracket shows up that doesn't + " close anything, save it for later. + while pos != -1 + if !s:IsInStringOrComment(a:lnum, pos + 1) + if line[pos] == '(' + call add(opening.parentheses, {'type': '(', 'pos': pos}) + elseif line[pos] == ')' + if empty(opening.parentheses) + call add(closing.parentheses, {'type': ')', 'pos': pos}) + else + let opening.parentheses = opening.parentheses[0:-2] + endif + elseif line[pos] == '{' + call add(opening.braces, {'type': '{', 'pos': pos}) + elseif line[pos] == '}' + if empty(opening.braces) + call add(closing.braces, {'type': '}', 'pos': pos}) + else + let opening.braces = opening.braces[0:-2] + endif + elseif line[pos] == '[' + call add(opening.brackets, {'type': '[', 'pos': pos}) + elseif line[pos] == ']' + if empty(opening.brackets) + call add(closing.brackets, {'type': ']', 'pos': pos}) + else + let opening.brackets = opening.brackets[0:-2] + endif + endif + endif + + let pos = match(line, '[][(){}]', pos + 1) + endwhile + + " Find the rightmost brackets, since they're the ones that are important in + " both opening and closing cases + let rightmost_opening = {'type': '(', 'pos': -1} + let rightmost_closing = {'type': ')', 'pos': -1} + + for opening in opening.parentheses + opening.braces + opening.brackets + if opening.pos > rightmost_opening.pos + let rightmost_opening = opening + endif + endfor + + for closing in closing.parentheses + closing.braces + closing.brackets + if closing.pos > rightmost_closing.pos + let rightmost_closing = closing + endif + endfor + + return [rightmost_opening, rightmost_closing] +endfunction + +function s:Match(lnum, regex) + let col = match(getline(a:lnum), '\C'.a:regex) + 1 + return col > 0 && !s:IsInStringOrComment(a:lnum, col) ? col : 0 +endfunction + +function s:MatchLast(lnum, regex) + let line = getline(a:lnum) + let col = match(line, '.*\zs' . a:regex) + while col != -1 && s:IsInStringOrComment(a:lnum, col) + let line = strpart(line, 0, col) + let col = match(line, '.*' . a:regex) + endwhile + return col + 1 +endfunction + +" 4. FalconGetIndent Routine {{{1 +" ============ + +function FalconGetIndent(...) + " For the current line, use the first argument if given, else v:lnum + let clnum = a:0 ? a:1 : v:lnum + + " Use zero indent at the top of the file + if clnum == 0 + return 0 + endif + + let line = getline(clnum) + let ind = -1 + + " If we got a closing bracket on an empty line, find its match and indent + " according to it. For parentheses we indent to its column - 1, for the + " others we indent to the containing line's MSL's level. Return -1 if fail. + let col = matchend(line, '^\s*[]})]') + if col > 0 && !s:IsInStringOrComment(clnum, col) + call cursor(clnum, col) + let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2) + if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0 + if line[col-1]==')' && col('.') != col('$') - 1 + let ind = virtcol('.') - 1 + else + let ind = indent(s:GetMSL(line('.'))) + endif + endif + return ind + endif + + " If we have a deindenting keyword, find its match and indent to its level. + " TODO: this is messy + if s:Match(clnum, s:falcon_deindent_keywords) + call cursor(clnum, 1) + if searchpair(s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'bW', + \ s:end_skip_expr) > 0 + let msl = s:GetMSL(line('.')) + let line = getline(line('.')) + + if strpart(line, 0, col('.') - 1) =~ '=\s*$' && + \ strpart(line, col('.') - 1, 2) !~ 'do' + let ind = virtcol('.') - 1 + elseif getline(msl) =~ '=\s*\(#.*\)\=$' + let ind = indent(line('.')) + else + let ind = indent(msl) + endif + endif + return ind + endif + + " If we are in a multi-line string or line-comment, don't do anything to it. + if s:IsInString(clnum, matchend(line, '^\s*') + 1) + return indent('.') + endif + + " Find a non-blank, non-multi-line string line above the current line. + let lnum = s:PrevNonBlankNonString(clnum - 1) + + " If the line is empty and inside a string, use the previous line. + if line =~ '^\s*$' && lnum != prevnonblank(clnum - 1) + return indent(prevnonblank(clnum)) + endif + + " At the start of the file use zero indent. + if lnum == 0 + return 0 + endif + + " Set up variables for the previous line. + let line = getline(lnum) + let ind = indent(lnum) + + " If the previous line ended with a block opening, add a level of indent. + if s:Match(lnum, s:block_regex) + return indent(s:GetMSL(lnum)) + shiftwidth() + endif + + " If it contained hanging closing brackets, find the rightmost one, find its + " match and indent according to that. + if line =~ '[[({]' || line =~ '[])}]\s*\%(#.*\)\=$' + let [opening, closing] = s:ExtraBrackets(lnum) + + if opening.pos != -1 + if opening.type == '(' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0 + if col('.') + 1 == col('$') + return ind + shiftwidth() + else + return virtcol('.') + endif + else + let nonspace = matchend(line, '\S', opening.pos + 1) - 1 + return nonspace > 0 ? nonspace : ind + shiftwidth() + endif + elseif closing.pos != -1 + call cursor(lnum, closing.pos + 1) + normal! % + + if s:Match(line('.'), s:falcon_indent_keywords) + return indent('.') + shiftwidth() + else + return indent('.') + endif + else + call cursor(clnum, vcol) + end + endif + + " If the previous line ended with an "end", match that "end"s beginning's + " indent. + let col = s:Match(lnum, '\%(^\|[^.:@$]\)\\s*\%(#.*\)\=$') + if col > 0 + call cursor(lnum, col) + if searchpair(s:end_start_regex, '', s:end_end_regex, 'bW', + \ s:end_skip_expr) > 0 + let n = line('.') + let ind = indent('.') + let msl = s:GetMSL(n) + if msl != n + let ind = indent(msl) + end + return ind + endif + end + + let col = s:Match(lnum, s:falcon_indent_keywords) + if col > 0 + call cursor(lnum, col) + let ind = virtcol('.') - 1 + shiftwidth() + " TODO: make this better (we need to count them) (or, if a searchpair + " fails, we know that something is lacking an end and thus we indent a + " level + if s:Match(lnum, s:end_end_regex) + let ind = indent('.') + endif + return ind + endif + + " Set up variables to use and search for MSL to the previous line. + let p_lnum = lnum + let lnum = s:GetMSL(lnum) + + " If the previous line wasn't a MSL and is continuation return its indent. + " TODO: the || s:IsInString() thing worries me a bit. + if p_lnum != lnum + if s:Match(p_lnum, s:non_bracket_continuation_regex) || s:IsInString(p_lnum,strlen(line)) + return ind + endif + endif + + " Set up more variables, now that we know we wasn't continuation bound. + let line = getline(lnum) + let msl_ind = indent(lnum) + + " If the MSL line had an indenting keyword in it, add a level of indent. + " TODO: this does not take into account contrived things such as + " module Foo; class Bar; end + if s:Match(lnum, s:falcon_indent_keywords) + let ind = msl_ind + shiftwidth() + if s:Match(lnum, s:end_end_regex) + let ind = ind - shiftwidth() + endif + return ind + endif + + " If the previous line ended with [*+/.,-=], but wasn't a block ending or a + " closing bracket, indent one extra level. + if s:Match(lnum, s:non_bracket_continuation_regex) && !s:Match(lnum, '^\s*\([\])}]\|end\)') + if lnum == p_lnum + let ind = msl_ind + shiftwidth() + else + let ind = msl_ind + endif + return ind + endif + + return ind +endfunction + +" }}}1 + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: set sw=4 sts=4 et tw=80 : + +endif diff --git a/indent/fortran.vim b/indent/fortran.vim new file mode 100644 index 00000000..a7732d11 --- /dev/null +++ b/indent/fortran.vim @@ -0,0 +1,222 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77) +" Version: 47 +" Last Change: 2016 Oct. 29 +" Maintainer: Ajit J. Thakkar ; +" Usage: For instructions, do :help fortran-indent from Vim +" Credits: +" Useful suggestions were made, in chronological order, by: +" Albert Oliver Serra, Takuya Fujiwara and Philipp Edelmann. + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +let s:cposet=&cpoptions +set cpoptions&vim + +setlocal indentkeys+==~end,=~case,=~if,=~else,=~do,=~where,=~elsewhere,=~select +setlocal indentkeys+==~endif,=~enddo,=~endwhere,=~endselect,=~elseif +setlocal indentkeys+==~type,=~interface,=~forall,=~associate,=~block,=~enum +setlocal indentkeys+==~endforall,=~endassociate,=~endblock,=~endenum +if exists("b:fortran_indent_more") || exists("g:fortran_indent_more") + setlocal indentkeys+==~function,=~subroutine,=~module,=~contains,=~program + setlocal indentkeys+==~endfunction,=~endsubroutine,=~endmodule + setlocal indentkeys+==~endprogram +endif + +" Determine whether this is a fixed or free format source file +" if this hasn't been done yet using the priority: +" buffer-local value +" > global value +" > file extension as in Intel ifort, gcc (gfortran), NAG, Pathscale, and Cray compilers +if !exists("b:fortran_fixed_source") + if exists("fortran_free_source") + " User guarantees free source form + let b:fortran_fixed_source = 0 + elseif exists("fortran_fixed_source") + " User guarantees fixed source form + let b:fortran_fixed_source = 1 + elseif expand("%:e") ==? "f\<90\|95\|03\|08\>" + " Free-form file extension defaults as in Intel ifort, gcc(gfortran), NAG, Pathscale, and Cray compilers + let b:fortran_fixed_source = 0 + elseif expand("%:e") ==? "f\|f77\|for" + " Fixed-form file extension defaults + let b:fortran_fixed_source = 1 + else + " Modern fortran still allows both fixed and free source form + " Assume fixed source form unless signs of free source form + " are detected in the first five columns of the first s:lmax lines. + " Detection becomes more accurate and time-consuming if more lines + " are checked. Increase the limit below if you keep lots of comments at + " the very top of each file and you have a fast computer. + let s:lmax = 500 + if ( s:lmax > line("$") ) + let s:lmax = line("$") + endif + let b:fortran_fixed_source = 1 + let s:ln=1 + while s:ln <= s:lmax + let s:test = strpart(getline(s:ln),0,5) + if s:test !~ '^[Cc*]' && s:test !~ '^ *[!#]' && s:test =~ '[^ 0-9\t]' && s:test !~ '^[ 0-9]*\t' + let b:fortran_fixed_source = 0 + break + endif + let s:ln = s:ln + 1 + endwhile + endif +endif + +" Define the appropriate indent function but only once +if (b:fortran_fixed_source == 1) + setlocal indentexpr=FortranGetFixedIndent() + if exists("*FortranGetFixedIndent") + finish + endif +else + setlocal indentexpr=FortranGetFreeIndent() + if exists("*FortranGetFreeIndent") + finish + endif +endif + +function FortranGetIndent(lnum) + let ind = indent(a:lnum) + let prevline=getline(a:lnum) + " Strip tail comment + let prevstat=substitute(prevline, '!.*$', '', '') + let prev2line=getline(a:lnum-1) + let prev2stat=substitute(prev2line, '!.*$', '', '') + + "Indent do loops only if they are all guaranteed to be of do/end do type + if exists("b:fortran_do_enddo") || exists("g:fortran_do_enddo") + if prevstat =~? '^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*do\>' + let ind = ind + shiftwidth() + endif + if getline(v:lnum) =~? '^\s*\(\d\+\s\)\=\s*end\s*do\>' + let ind = ind - shiftwidth() + endif + endif + + "Add a shiftwidth to statements following if, else, else if, case, class, + "where, else where, forall, type, interface and associate statements + if prevstat =~? '^\s*\(case\|class\|else\|else\s*if\|else\s*where\)\>' + \ ||prevstat=~? '^\s*\(type\|interface\|associate\|enum\)\>' + \ ||prevstat=~?'^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*\(forall\|where\|block\)\>' + \ ||prevstat=~? '^\s*\(\d\+\s\)\=\s*\(\a\w*\s*:\)\=\s*if\>' + let ind = ind + shiftwidth() + " Remove unwanted indent after logical and arithmetic ifs + if prevstat =~? '\' && prevstat !~? '\' + let ind = ind - shiftwidth() + endif + " Remove unwanted indent after type( statements + if prevstat =~? '^\s*type\s*(' + let ind = ind - shiftwidth() + endif + endif + + "Indent program units unless instructed otherwise + if !exists("b:fortran_indent_less") && !exists("g:fortran_indent_less") + let prefix='\(\(pure\|impure\|elemental\|recursive\)\s\+\)\{,2}' + let type='\(\(integer\|real\|double\s\+precision\|complex\|logical' + \.'\|character\|type\|class\)\s*\S*\s\+\)\=' + if prevstat =~? '^\s*\(contains\|submodule\|program\)\>' + \ ||prevstat =~? '^\s*'.'module\>\(\s*\procedure\)\@!' + \ ||prevstat =~? '^\s*'.prefix.'subroutine\>' + \ ||prevstat =~? '^\s*'.prefix.type.'function\>' + \ ||prevstat =~? '^\s*'.type.prefix.'function\>' + let ind = ind + shiftwidth() + endif + if getline(v:lnum) =~? '^\s*contains\>' + \ ||getline(v:lnum)=~? '^\s*end\s*' + \ .'\(function\|subroutine\|module\|submodule\|program\)\>' + let ind = ind - shiftwidth() + endif + endif + + "Subtract a shiftwidth from else, else if, elsewhere, case, class, end if, + " end where, end select, end forall, end interface, end associate, + " end enum, end type, end block and end type statements + if getline(v:lnum) =~? '^\s*\(\d\+\s\)\=\s*' + \. '\(else\|else\s*if\|else\s*where\|case\|class\|' + \. 'end\s*\(if\|where\|select\|interface\|' + \. 'type\|forall\|associate\|enum\|block\)\)\>' + let ind = ind - shiftwidth() + " Fix indent for case statement immediately after select + if prevstat =~? '\' + let ind = ind + shiftwidth() + endif + endif + + "First continuation line + if prevstat =~ '&\s*$' && prev2stat !~ '&\s*$' + let ind = ind + shiftwidth() + endif + "Line after last continuation line + if prevstat !~ '&\s*$' && prev2stat =~ '&\s*$' && prevstat !~? '\' + let ind = ind - shiftwidth() + endif + + return ind +endfunction + +function FortranGetFreeIndent() + "Find the previous non-blank line + let lnum = prevnonblank(v:lnum - 1) + + "Use zero indent at the top of the file + if lnum == 0 + return 0 + endif + + let ind=FortranGetIndent(lnum) + return ind +endfunction + +function FortranGetFixedIndent() + let currline=getline(v:lnum) + "Don't indent comments, continuation lines and labelled lines + if strpart(currline,0,6) =~ '[^ \t]' + let ind = indent(v:lnum) + return ind + endif + + "Find the previous line which is not blank, not a comment, + "not a continuation line, and does not have a label + let lnum = v:lnum - 1 + while lnum > 0 + let prevline=getline(lnum) + if (prevline =~ "^[C*!]") || (prevline =~ "^\s*$") + \ || (strpart(prevline,5,1) !~ "[ 0]") + " Skip comments, blank lines and continuation lines + let lnum = lnum - 1 + else + let test=strpart(prevline,0,5) + if test =~ "[0-9]" + " Skip lines with statement numbers + let lnum = lnum - 1 + else + break + endif + endif + endwhile + + "First line must begin at column 7 + if lnum == 0 + return 6 + endif + + let ind=FortranGetIndent(lnum) + return ind +endfunction + +let &cpoptions=s:cposet +unlet s:cposet + +" vim:sw=2 tw=130 + +endif diff --git a/indent/framescript.vim b/indent/framescript.vim new file mode 100644 index 00000000..872d390c --- /dev/null +++ b/indent/framescript.vim @@ -0,0 +1,45 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: FrameScript +" Previous Maintainer: Nikolai Weibull +" Latest Revision: 2008-07-19 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentexpr=GetFrameScriptIndent() +setlocal indentkeys=!^F,o,O,0=~Else,0=~EndIf,0=~EndLoop,0=~EndSub +setlocal nosmartindent + +if exists("*GetFrameScriptIndent") + finish +endif + +function GetFrameScriptIndent() + let lnum = prevnonblank(v:lnum - 1) + + if lnum == 0 + return 0 + endif + + if getline(v:lnum) =~ '^\s*\*' + return cindent(v:lnum) + endif + + let ind = indent(lnum) + + if getline(lnum) =~? '^\s*\%(If\|Loop\|Sub\)' + let ind = ind + shiftwidth() + endif + + if getline(v:lnum) =~? '^\s*\%(Else\|End\%(If\|Loop\|Sub\)\)' + let ind = ind - shiftwidth() + endif + + return ind +endfunction + +endif diff --git a/indent/gitconfig.vim b/indent/gitconfig.vim index e0e4a456..cc6330c1 100644 --- a/indent/gitconfig.vim +++ b/indent/gitconfig.vim @@ -1,3 +1,45 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: git config file +" Maintainer: Tim Pope +" Last Change: 2017 Jun 13 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetGitconfigIndent() +setlocal indentkeys=o,O,*,0[,],0;,0#,=,!^F + +let b:undo_indent = 'setl ai< inde< indk<' + +" Only define the function once. +if exists("*GetGitconfigIndent") + finish +endif + +function! GetGitconfigIndent() + let sw = shiftwidth() + let line = getline(prevnonblank(v:lnum-1)) + let cline = getline(v:lnum) + if line =~ '\\\@ +" Last Change: 2017 Jun 13 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetGitoliteIndent() +setlocal indentkeys=o,O,*,!^F,=repo,\",= + +" Only define the function once. +if exists("*GetGitoliteIndent") + finish +endif + +let s:cpo_save = &cpo +set cpo&vim + +function! GetGitoliteIndent() + let prevln = prevnonblank(v:lnum-1) + let pline = getline(prevln) + let cline = getline(v:lnum) + + if cline =~ '^\s*\(C\|R\|RW\|RW+\|RWC\|RW+C\|RWD\|RW+D\|RWCD\|RW+CD\|-\)[ \t=]' + return shiftwidth() + elseif cline =~ '^\s*config\s' + return shiftwidth() + elseif pline =~ '^\s*repo\s' && cline =~ '^\s*\(#.*\)\?$' + return shiftwidth() + elseif cline =~ '^\s*#' + return indent(prevln) + elseif cline =~ '^\s*$' + return -1 + else + return 0 + endif +endfunction + +let &cpo = s:cpo_save +unlet s:cpo_save + +endif diff --git a/indent/go.vim b/indent/go.vim index fd973e45..98e42a8b 100644 --- a/indent/go.vim +++ b/indent/go.vim @@ -1,3 +1,73 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Go +" Maintainer: David Barnett (https://github.com/google/vim-ft-go) +" Last Change: 2017 Jun 13 +" +" TODO: +" - function invocations split across lines +" - general line splits (line ends in an operator) + +if exists('b:did_indent') + finish +endif +let b:did_indent = 1 + +" C indentation is too far off useful, mainly due to Go's := operator. +" Let's just define our own. +setlocal nolisp +setlocal autoindent +setlocal indentexpr=GoIndent(v:lnum) +setlocal indentkeys+=<:>,0=},0=) + +if exists('*GoIndent') + finish +endif + +function! GoIndent(lnum) + let l:prevlnum = prevnonblank(a:lnum-1) + if l:prevlnum == 0 + " top of file + return 0 + endif + + " grab the previous and current line, stripping comments. + let l:prevl = substitute(getline(l:prevlnum), '//.*$', '', '') + let l:thisl = substitute(getline(a:lnum), '//.*$', '', '') + let l:previ = indent(l:prevlnum) + + let l:ind = l:previ + + if l:prevl =~ '[({]\s*$' + " previous line opened a block + let l:ind += shiftwidth() + endif + if l:prevl =~# '^\s*\(case .*\|default\):$' + " previous line is part of a switch statement + let l:ind += shiftwidth() + endif + " TODO: handle if the previous line is a label. + + if l:thisl =~ '^\s*[)}]' + " this line closed a block + let l:ind -= shiftwidth() + endif + + " Colons are tricky. + " We want to outdent if it's part of a switch ("case foo:" or "default:"). + " We ignore trying to deal with jump labels because (a) they're rare, and + " (b) they're hard to disambiguate from a composite literal key. + if l:thisl =~# '^\s*\(case .*\|default\):$' + let l:ind -= shiftwidth() + endif + + return l:ind +endfunction + +" vim: sw=2 sts=2 et + +endif if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'go') == -1 " Copyright 2011 The Go Authors. All rights reserved. diff --git a/indent/haml.vim b/indent/haml.vim index c251a4c4..dcfc1168 100644 --- a/indent/haml.vim +++ b/indent/haml.vim @@ -1,3 +1,81 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Haml +" Maintainer: Tim Pope +" Last Change: 2017 Jun 13 + +if exists("b:did_indent") + finish +endif +runtime! indent/ruby.vim +unlet! b:did_indent +let b:did_indent = 1 + +setlocal autoindent sw=2 et +setlocal indentexpr=GetHamlIndent() +setlocal indentkeys=o,O,*,},],0),!^F,=end,=else,=elsif,=rescue,=ensure,=when + +" Only define the function once. +if exists("*GetHamlIndent") + finish +endif + +let s:attributes = '\%({.\{-\}}\|\[.\{-\}\]\)' +let s:tag = '\%([%.#][[:alnum:]_-]\+\|'.s:attributes.'\)*[<>]*' + +if !exists('g:haml_self_closing_tags') + let g:haml_self_closing_tags = 'base|link|meta|br|hr|img|input' +endif + +function! GetHamlIndent() + let lnum = prevnonblank(v:lnum-1) + if lnum == 0 + return 0 + endif + let line = substitute(getline(lnum),'\s\+$','','') + let cline = substitute(substitute(getline(v:lnum),'\s\+$','',''),'^\s\+','','') + let lastcol = strlen(line) + let line = substitute(line,'^\s\+','','') + let indent = indent(lnum) + let cindent = indent(v:lnum) + let sw = shiftwidth() + if cline =~# '\v^-\s*%(elsif|else|when)>' + let indent = cindent < indent ? cindent : indent - sw + endif + let increase = indent + sw + if indent == indent(lnum) + let indent = cindent <= indent ? -1 : increase + endif + + let group = synIDattr(synID(lnum,lastcol,1),'name') + + if line =~ '^!!!' + return indent + elseif line =~ '^/\%(\[[^]]*\]\)\=$' + return increase + elseif group == 'hamlFilter' + return increase + elseif line =~ '^'.s:tag.'[&!]\=[=~-]\s*\%(\%(if\|else\|elsif\|unless\|case\|when\|while\|until\|for\|begin\|module\|class\|def\)\>\%(.*\\)\@!\|.*do\%(\s*|[^|]*|\)\=\s*$\)' + return increase + elseif line =~ '^'.s:tag.'[&!]\=[=~-].*,\s*$' + return increase + elseif line == '-#' + return increase + elseif group =~? '\v^(hamlSelfCloser)$' || line =~? '^%\v%('.g:haml_self_closing_tags.')>' + return indent + elseif group =~? '\v^%(hamlTag|hamlAttributesDelimiter|hamlObjectDelimiter|hamlClass|hamlId|htmlTagName|htmlSpecialTagName)$' + return increase + elseif synIDattr(synID(v:lnum,1,1),'name') ==? 'hamlRubyFilter' + return GetRubyIndent() + else + return indent + endif +endfunction + +" vim:set sw=2: + +endif if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'haml') == -1 " Vim indent file diff --git a/indent/hamster.vim b/indent/hamster.vim new file mode 100644 index 00000000..35f33fb1 --- /dev/null +++ b/indent/hamster.vim @@ -0,0 +1,59 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: Hamster Script +" Version: 2.0.6.0 +" Last Change: Wed Nov 08 2006 12:02:42 PM +" Maintainer: David Fishburn + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal indentkeys+==~if,=~else,=~endif,=~endfor,=~endwhile +setlocal indentkeys+==~do,=~until,=~while,=~repeat,=~for,=~loop +setlocal indentkeys+==~sub,=~endsub + +" Define the appropriate indent function but only once +setlocal indentexpr=HamGetFreeIndent() +if exists("*HamGetFreeIndent") + finish +endif + +function HamGetIndent(lnum) + let ind = indent(a:lnum) + let prevline=getline(a:lnum) + + " Add a shiftwidth to statements following if, else, elseif, + " case, select, default, do, until, while, for, start + if prevline =~? '^\s*\<\(if\|else\%(if\)\?\|for\|repeat\|do\|while\|sub\)\>' + let ind = ind + shiftwidth() + endif + + " Subtract a shiftwidth from else, elseif, end(if|while|for), until + let line = getline(v:lnum) + if line =~? '^\s*\(else\|elseif\|loop\|until\|end\%(if\|while\|for\|sub\)\)\>' + let ind = ind - shiftwidth() + endif + + return ind +endfunction + +function HamGetFreeIndent() + " Find the previous non-blank line + let lnum = prevnonblank(v:lnum - 1) + + " Use zero indent at the top of the file + if lnum == 0 + return 0 + endif + + let ind=HamGetIndent(lnum) + return ind +endfunction + +" vim:sw=2 tw=80 + +endif diff --git a/indent/hog.vim b/indent/hog.vim new file mode 100644 index 00000000..e86bc181 --- /dev/null +++ b/indent/hog.vim @@ -0,0 +1,81 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent file +" Language: hog (Snort.conf) +" Maintainer: Victor Roemer, +" Last Change: Mar 7, 2013 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 +let b:undo_indent = 'setlocal smartindent< indentexpr< indentkeys<' + +setlocal nosmartindent +setlocal indentexpr=GetHogIndent() +setlocal indentkeys+=!^F,o,O,0# + +" Only define the function once. +if exists("*GetHogIndent") + finish +endif + +let s:cpo_save = &cpo +set cpo&vim + +let s:syn_blocks = '\' + +function s:IsInBlock(lnum) + return synIDattr(synID(a:lnum, 1, 1), 'name') =~ s:syn_blocks +endfunction + +function GetHogIndent() + let prevlnum = prevnonblank(v:lnum-1) + + " Comment blocks have identical indent + if getline(v:lnum) =~ '^\s*#' && getline(prevlnum) =~ '^\s*#' + return indent(prevlnum) + endif + + " Ignore comment lines when calculating indent + while getline(prevlnum) =~ '^\s*#' + let prevlnum = prevnonblank(prevlnum-1) + if !prevlnum + return previndent + endif + endwhile + + " Continuation of a line that wasn't indented + let prevline = getline(prevlnum) + if prevline =~ '^\k\+.*\\\s*$' + return shiftwidth() + endif + + " Continuation of a line that was indented + if prevline =~ '\k\+.*\\\s*$' + return indent(prevlnum) + endif + + " Indent the next line if previous line contained a start of a block + " definition ('{' or '('). + if prevline =~ '^\k\+[^#]*{}\@!\s*$' " TODO || prevline =~ '^\k\+[^#]*()\@!\s*$' + return shiftwidth() + endif + + " Match inside of a block + if s:IsInBlock(v:lnum) + if prevline =~ "^\k\+.*$" + return shiftwidth() + else + return indent(prevlnum) + endif + endif + + return 0 +endfunction + +let &cpo = s:cpo_save +unlet s:cpo_save + +endif diff --git a/indent/html.vim b/indent/html.vim index 1e5691f7..9fb6886a 100644 --- a/indent/html.vim +++ b/indent/html.vim @@ -1,3 +1,1059 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vim') == -1 + +" Vim indent script for HTML +" Header: "{{{ +" Maintainer: Bram Moolenaar +" Original Author: Andy Wokula +" Last Change: 2017 Jun 13 +" Version: 1.0 +" Description: HTML indent script with cached state for faster indenting on a +" range of lines. +" Supports template systems through hooks. +" Supports Closure stylesheets. +" +" Credits: +" indent/html.vim (2006 Jun 05) from J. Zellner +" indent/css.vim (2006 Dec 20) from N. Weibull +" +" History: +" 2014 June (v1.0) overhaul (Bram) +" 2012 Oct 21 (v0.9) added support for shiftwidth() +" 2011 Sep 09 (v0.8) added HTML5 tags (thx to J. Zuckerman) +" 2008 Apr 28 (v0.6) revised customization +" 2008 Mar 09 (v0.5) fixed 'indk' issue (thx to C.J. Robinson) +"}}} + +" Init Folklore, check user settings (2nd time ++) +if exists("b:did_indent") "{{{ + finish +endif + +" Load the Javascript indent script first, it defines GetJavascriptIndent(). +" Undo the rest. +" Load base python indent. +if !exists('*GetJavascriptIndent') + runtime! indent/javascript.vim +endif +let b:did_indent = 1 + +setlocal indentexpr=HtmlIndent() +setlocal indentkeys=o,O,,<>>,{,},!^F + +" Needed for % to work when finding start/end of a tag. +setlocal matchpairs+=<:> + +let b:undo_indent = "setlocal inde< indk<" + +" b:hi_indent keeps state to speed up indenting consecutive lines. +let b:hi_indent = {"lnum": -1} + +"""""" Code below this is loaded only once. """"" +if exists("*HtmlIndent") && !exists('g:force_reload_html') + call HtmlIndent_CheckUserSettings() + finish +endif + +" Allow for line continuation below. +let s:cpo_save = &cpo +set cpo-=C +"}}} + +" Check and process settings from b:html_indent and g:html_indent... variables. +" Prefer using buffer-local settings over global settings, so that there can +" be defaults for all HTML files and exceptions for specific types of HTML +" files. +func! HtmlIndent_CheckUserSettings() + "{{{ + let inctags = '' + if exists("b:html_indent_inctags") + let inctags = b:html_indent_inctags + elseif exists("g:html_indent_inctags") + let inctags = g:html_indent_inctags + endif + let b:hi_tags = {} + if len(inctags) > 0 + call s:AddITags(b:hi_tags, split(inctags, ",")) + endif + + let autotags = '' + if exists("b:html_indent_autotags") + let autotags = b:html_indent_autotags + elseif exists("g:html_indent_autotags") + let autotags = g:html_indent_autotags + endif + let b:hi_removed_tags = {} + if len(autotags) > 0 + call s:RemoveITags(b:hi_removed_tags, split(autotags, ",")) + endif + + " Syntax names indicating being inside a string of an attribute value. + let string_names = [] + if exists("b:html_indent_string_names") + let string_names = b:html_indent_string_names + elseif exists("g:html_indent_string_names") + let string_names = g:html_indent_string_names + endif + let b:hi_insideStringNames = ['htmlString'] + if len(string_names) > 0 + for s in string_names + call add(b:hi_insideStringNames, s) + endfor + endif + + " Syntax names indicating being inside a tag. + let tag_names = [] + if exists("b:html_indent_tag_names") + let tag_names = b:html_indent_tag_names + elseif exists("g:html_indent_tag_names") + let tag_names = g:html_indent_tag_names + endif + let b:hi_insideTagNames = ['htmlTag', 'htmlScriptTag'] + if len(tag_names) > 0 + for s in tag_names + call add(b:hi_insideTagNames, s) + endfor + endif + + let indone = {"zero": 0 + \,"auto": "indent(prevnonblank(v:lnum-1))" + \,"inc": "b:hi_indent.blocktagind + shiftwidth()"} + + let script1 = '' + if exists("b:html_indent_script1") + let script1 = b:html_indent_script1 + elseif exists("g:html_indent_script1") + let script1 = g:html_indent_script1 + endif + if len(script1) > 0 + let b:hi_js1indent = get(indone, script1, indone.zero) + else + let b:hi_js1indent = 0 + endif + + let style1 = '' + if exists("b:html_indent_style1") + let style1 = b:html_indent_style1 + elseif exists("g:html_indent_style1") + let style1 = g:html_indent_style1 + endif + if len(style1) > 0 + let b:hi_css1indent = get(indone, style1, indone.zero) + else + let b:hi_css1indent = 0 + endif + + if !exists('b:html_indent_line_limit') + if exists('g:html_indent_line_limit') + let b:html_indent_line_limit = g:html_indent_line_limit + else + let b:html_indent_line_limit = 200 + endif + endif +endfunc "}}} + +" Init Script Vars +"{{{ +let b:hi_lasttick = 0 +let b:hi_newstate = {} +let s:countonly = 0 + "}}} + +" Fill the s:indent_tags dict with known tags. +" The key is "tagname" or "/tagname". {{{ +" The value is: +" 1 opening tag +" 2 "pre" +" 3 "script" +" 4 "style" +" 5 comment start +" 6 conditional comment start +" -1 closing tag +" -2 "/pre" +" -3 "/script" +" -4 "/style" +" -5 comment end +" -6 conditional comment end +let s:indent_tags = {} +let s:endtags = [0,0,0,0,0,0,0] " long enough for the highest index +"}}} + +" Add a list of tag names for a pair of to "tags". +func! s:AddITags(tags, taglist) + "{{{ + for itag in a:taglist + let a:tags[itag] = 1 + let a:tags['/' . itag] = -1 + endfor +endfunc "}}} + +" Take a list of tag name pairs that are not to be used as tag pairs. +func! s:RemoveITags(tags, taglist) + "{{{ + for itag in a:taglist + let a:tags[itag] = 1 + let a:tags['/' . itag] = 1 + endfor +endfunc "}}} + +" Add a block tag, that is a tag with a different kind of indenting. +func! s:AddBlockTag(tag, id, ...) + "{{{ + if !(a:id >= 2 && a:id < len(s:endtags)) + echoerr 'AddBlockTag ' . a:id + return + endif + let s:indent_tags[a:tag] = a:id + if a:0 == 0 + let s:indent_tags['/' . a:tag] = -a:id + let s:endtags[a:id] = "" + else + let s:indent_tags[a:1] = -a:id + let s:endtags[a:id] = a:1 + endif +endfunc "}}} + +" Add known tag pairs. +" Self-closing tags and tags that are sometimes {{{ +" self-closing (e.g.,

) are not here (when encountering

we can find +" the matching

, but not the other way around). +" Old HTML tags: +call s:AddITags(s:indent_tags, [ + \ 'a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big', + \ 'blockquote', 'body', 'button', 'caption', 'center', 'cite', 'code', + \ 'colgroup', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', + \ 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', + \ 'i', 'iframe', 'ins', 'kbd', 'label', 'legend', 'li', + \ 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', + \ 'optgroup', 'q', 's', 'samp', 'select', 'small', 'span', 'strong', 'sub', + \ 'sup', 'table', 'textarea', 'title', 'tt', 'u', 'ul', 'var', 'th', 'td', + \ 'tr', 'tbody', 'tfoot', 'thead']) + +" New HTML5 elements: +call s:AddITags(s:indent_tags, [ + \ 'area', 'article', 'aside', 'audio', 'bdi', 'canvas', + \ 'command', 'data', 'datalist', 'details', 'embed', 'figcaption', + \ 'figure', 'footer', 'header', 'keygen', 'mark', 'meter', 'nav', 'output', + \ 'progress', 'rp', 'rt', 'ruby', 'section', 'source', 'summary', 'svg', + \ 'time', 'track', 'video', 'wbr']) + +" Tags added for web components: +call s:AddITags(s:indent_tags, [ + \ 'content', 'shadow', 'template']) +"}}} + +" Add Block Tags: these contain alien content +"{{{ +call s:AddBlockTag('pre', 2) +call s:AddBlockTag('script', 3) +call s:AddBlockTag('style', 4) +call s:AddBlockTag('') +call s:AddBlockTag('') +"}}} + +" Return non-zero when "tagname" is an opening tag, not being a block tag, for +" which there should be a closing tag. Can be used by scripts that include +" HTML indenting. +func! HtmlIndent_IsOpenTag(tagname) + "{{{ + if get(s:indent_tags, a:tagname) == 1 + return 1 + endif + return get(b:hi_tags, a:tagname) == 1 +endfunc "}}} + +" Get the value for "tagname", taking care of buffer-local tags. +func! s:get_tag(tagname) + "{{{ + let i = get(s:indent_tags, a:tagname) + if (i == 1 || i == -1) && get(b:hi_removed_tags, a:tagname) != 0 + return 0 + endif + if i == 0 + let i = get(b:hi_tags, a:tagname) + endif + return i +endfunc "}}} + +" Count the number of start and end tags in "text". +func! s:CountITags(text) + "{{{ + " Store the result in s:curind and s:nextrel. + let s:curind = 0 " relative indent steps for current line [unit &sw]: + let s:nextrel = 0 " relative indent steps for next line [unit &sw]: + let s:block = 0 " assume starting outside of a block + let s:countonly = 1 " don't change state + call substitute(a:text, '<\zs/\=\w\+\(-\w\+\)*\>\|\|', '\=s:CheckTag(submatch(0))', 'g') + let s:countonly = 0 +endfunc "}}} + +" Count the number of start and end tags in text. +func! s:CountTagsAndState(text) + "{{{ + " Store the result in s:curind and s:nextrel. Update b:hi_newstate.block. + let s:curind = 0 " relative indent steps for current line [unit &sw]: + let s:nextrel = 0 " relative indent steps for next line [unit &sw]: + + let s:block = b:hi_newstate.block + let tmp = substitute(a:text, '<\zs/\=\w\+\(-\w\+\)*\>\|\|', '\=s:CheckTag(submatch(0))', 'g') + if s:block == 3 + let b:hi_newstate.scripttype = s:GetScriptType(matchstr(tmp, '\C.*\zs[^>]*')) + endif + let b:hi_newstate.block = s:block +endfunc "}}} + +" Used by s:CountITags() and s:CountTagsAndState(). +func! s:CheckTag(itag) + "{{{ + " Returns an empty string or "SCRIPT". + " a:itag can be "tag" or "/tag" or "" + if (s:CheckCustomTag(a:itag)) + return "" + endif + let ind = s:get_tag(a:itag) + if ind == -1 + " closing tag + if s:block != 0 + " ignore itag within a block + return "" + endif + if s:nextrel == 0 + let s:curind -= 1 + else + let s:nextrel -= 1 + endif + elseif ind == 1 + " opening tag + if s:block != 0 + return "" + endif + let s:nextrel += 1 + elseif ind != 0 + " block-tag (opening or closing) + return s:CheckBlockTag(a:itag, ind) + " else ind==0 (other tag found): keep indent + endif + return "" +endfunc "}}} + +" Used by s:CheckTag(). Returns an empty string or "SCRIPT". +func! s:CheckBlockTag(blocktag, ind) + "{{{ + if a:ind > 0 + " a block starts here + if s:block != 0 + " already in a block (nesting) - ignore + " especially ignore comments after other blocktags + return "" + endif + let s:block = a:ind " block type + if s:countonly + return "" + endif + let b:hi_newstate.blocklnr = v:lnum + " save allover indent for the endtag + let b:hi_newstate.blocktagind = b:hi_indent.baseindent + (s:nextrel + s:curind) * shiftwidth() + if a:ind == 3 + return "SCRIPT" " all except this must be lowercase + " line is to be checked again for the type attribute + endif + else + let s:block = 0 + " we get here if starting and closing a block-tag on the same line + endif + return "" +endfunc "}}} + +" Used by s:CheckTag(). +func! s:CheckCustomTag(ctag) + "{{{ + " Returns 1 if ctag is the tag for a custom element, 0 otherwise. + " a:ctag can be "tag" or "/tag" or "" + let pattern = '\%\(\w\+-\)\+\w\+' + if match(a:ctag, pattern) == -1 + return 0 + endif + if matchstr(a:ctag, '\/\ze.\+') == "/" + " closing tag + if s:block != 0 + " ignore ctag within a block + return 1 + endif + if s:nextrel == 0 + let s:curind -= 1 + else + let s:nextrel -= 1 + endif + else + " opening tag + if s:block != 0 + return 1 + endif + let s:nextrel += 1 + endif + return 1 +endfunc "}}} + +" Return the