From d96dc724d442bbc9788815ab3da09d9fff0555a9 Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Thu, 12 Sep 2013 16:33:12 +0200 Subject: Add extended php support --- indent/php.vim | 1269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1269 insertions(+) create mode 100644 indent/php.vim (limited to 'indent/php.vim') diff --git a/indent/php.vim b/indent/php.vim new file mode 100644 index 00000000..6286c6b3 --- /dev/null +++ b/indent/php.vim @@ -0,0 +1,1269 @@ +" Vim indent file +" Language: PHP +" Author: John Wellesz +" URL: http://www.2072productions.com/vim/indent/php.vim +" Last Change: 2010 July 26th +" Newsletter: http://www.2072productions.com/?to=php-indent-for-vim-newsletter.php +" Version: 1.33 +" +" +" Changes: 1.33 - Rewrote Switch(){case:default:} handling from +" scratch in a simpler more logical and infallible way... +" - Removed PHP_ANSI_indenting which is no longer +" needed. +" +" +" Changes: 1.32b - Added PHP_ANSI_indenting and PHP_outdentphpescape +" options details to VIm documentation (:help php-indent). +" +" +" Changes: 1.32 - Added a new option: PHP_ANSI_indenting +" +" +" Changes: 1.31a - Added a new option: PHP_outdentphpescape to indent +" PHP tags as the surrounding code. +" +" Changes: 1.30 - Fixed empty case/default indentation again :/ +" - The ResetOptions() function will be called each time +" the ftplugin calls this script, previously it was +" executed on BufWinEnter and Syntax events. +" +" +" Changes: 1.29 - Fixed php file detection for ResetOptions() used for +" comments formatting. It now uses the same tests as +" filetype.vim. ResetOptions() will be correctly +" called for *.phtml, *.ctp and *.inc files. +" +" +" Changes: 1.28 - End HEREDOC delimiters were not considered as such +" if they were not followed by a ';'. +" - Added support for NOWDOC tags ($foo = <<<'bar') +" +" +" Changes: 1.27 - if a "case" was preceded by another "case" on the +" previous line, the second "case" was indented incorrectly. +" +" Changes: 1.26 - '/*' character sequences found on a line +" starting by a '#' were not dismissed by the indenting algorithm +" and could cause indentation problem in some cases. +" +" +" Changes: 1.25 - Fix some indentation errors on multi line conditions +" and multi line statements. +" - Fix when array indenting is broken and a closing +" ');' is placed at the start of the line, following +" lines will be indented correctly. +" - New option: PHP_vintage_case_default_indent (default off) +" - Minor fixes and optimizations. +" +" +" Changes: 1.24 - Added compatibility with the latest version of +" php.vim syntax file by Peter Hodge (http://www.vim.org/scripts/script.php?script_id=1571) +" This fixes wrong indentation and ultra-slow indenting +" on large php files... +" - Fixed spelling in comments. +" +" +" Changes: 1.23 - html tag was preceded by a "?>" it wasn't indented. +" - Some other minor corrections and improvements. +" +" +" Changes: 1.16 - Now starting and ending '*' of multiline '/* */' comments are aligned +" on the '*' of the '/*' comment starter. +" - Some code improvements that make indentation faster. +" +" Changes: 1.15 - Corrected some problems with the indentation of +" multiline "array()" declarations. +" +" Changes: 1.14 - Added auto-formatting for comments (using the Vim option formatoptions=qroc). +" - Added the script option PHP_BracesAtCodeLevel to +" indent the '{' and '}' at the same level than the +" code they contain. +" +" Changes: 1.13 - Some code cleaning and typo corrections (Thanks to +" Emanuele Giaquinta for his patches) +" +" Changes: 1.12 - The bug involving searchpair() and utf-8 encoding in Vim 6.3 will +" not make this script to hang but you'll have to be +" careful to not write '/* */' comments with other '/*' +" inside the comments else the indentation won't be correct. +" NOTE: This is true only if you are using utf-8 and vim 6.3. +" +" Changes: 1.11 - If the "case" of a "switch" wasn't alone on its line +" and if the "switch" was at col 0 (or at default indenting) +" the lines following the "case" were not indented. +" +" Changes: 1.10 - Lines beginning by a single or double quote were +" not indented in some cases. +" +" Changes: 1.09 - JavaScript code was not always directly indented. +" +" Changes: 1.08 - End comment tags '*/' are indented like start tags '/*'. +" - When typing a multiline comment, '}' are indented +" according to other commented '{'. +" - Added a new option 'PHP_removeCRwhenUnix' to +" automatically remove CR at end of lines when the file +" format is Unix. +" - Changed the file format of this very file to Unix. +" - This version seems to correct several issues some people +" had with 1.07. +" +" Changes: 1.07 - Added support for "Here document" tags: +" - HereDoc end tags are indented properly. +" - HereDoc content remains unchanged. +" - All the code that is outside PHP delimiters remains +" unchanged. +" - New feature: The content of html tags is considered as PHP +" and indented according to the surrounding PHP code. +" - "else if" are detected as "elseif". +" - Multiline /**/ are indented when the user types it but +" remain unchanged when indenting from their beginning. +" - Fixed indenting of // and # comments. +" - php_sync_method option is set to 0 (fromstart). +" This is required for complex PHP scripts else the indent +" may fail. +" - Files with non PHP code at the beginning could alter the indent +" of the following PHP code. +" - Other minor improvements and corrections. +" +" Changes: 1.06: - Switch block were no longer indented correctly... +" - Added an option to use a default indenting instead of 0. +" (whereas I still can't find any good reason to use it!) +" - A problem with ^\s*);\= lines where ending a non '{}' +" structure. +" - Changed script local variable to be buffer local +" variable instead. +" +" Changes: 1.05: - Lines containing "" and "?> ,=?>,=\)\@!\|]*>\%(.*<\/script>\)\@!' +"setlocal debug=msg " XXX -- do not comment this line when modifying this file + + +function! GetLastRealCodeLNum(startline) " {{{ + "Inspired from the function SkipJavaBlanksAndComments by Toby Allsopp for indent/java.vim + + let lnum = a:startline + + " Used to indent html tag correctly + if b:GetLastRealCodeLNum_ADD && b:GetLastRealCodeLNum_ADD == lnum + 1 + let lnum = b:GetLastRealCodeLNum_ADD + endif + + let old_lnum = lnum + + while lnum > 1 + let lnum = prevnonblank(lnum) + let lastline = getline(lnum) + + " if we are inside an html ' + let b:InPHPcode = 0 + let b:InPHPcode_tofind = s:PHP_startindenttag + " Note that b:InPHPcode_and_script is still true so that the + " can be indented correctly + endif + endif " }}} + + + " Non PHP code is let as it is + if !b:InPHPcode && !b:InPHPcode_and_script + return -1 + endif + + " Align correctly multi // or # lines + " Indent successive // or # comment the same way the first is {{{ + if cline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)' + if b:PHP_LastIndentedWasComment == 1 + return indent(real_PHP_lastindented) + endif + let b:PHP_LastIndentedWasComment = 1 + else + let b:PHP_LastIndentedWasComment = 0 + endif " }}} + + " Indent multiline /* comments correctly {{{ + + "if we are on the start of a MULTI * beginning comment or if the user is + "currently typing a /* beginning comment. + if b:PHP_InsideMultilineComment || b:UserIsTypingComment + if cline =~ '^\s*\*\%(\/\)\@!' + " if cline == '*' + if last_line =~ '^\s*/\*' + " if last_line == '/*' + return indent(lnum) + 1 + else + return indent(lnum) + endif + else + let b:PHP_InsideMultilineComment = 0 + endif + endif + + if !b:PHP_InsideMultilineComment && cline =~ '^\s*/\*' && cline !~ '\*/\s*$' + " if cline == '/*' and doesn't end with '*/' + if getline(v:lnum + 1) !~ '^\s*\*' + return -1 + endif + let b:PHP_InsideMultilineComment = 1 + endif " }}} + + " Some tags are always indented to col 1 + + " Things always indented at col 1 (PHP delimiter: , Heredoc end) {{{ + " PHP start tags are always at col 1, useless to indent unless the end tag + " is on the same line + if cline =~# '^\s*' && b:PHP_outdentphpescape + return 0 + endif + + " PHP end tags are always at col 1, useless to indent unless if it's + " followed by a start tag on the same line + if cline =~ '^\s*?>' && cline !~# '\)\=\|<<<''\=\a\w*''\=$\|^\s*}\)'.endline + " What is a terminated line? + " - a line terminated by a ";" optionally followed by a "?>" + " - a HEREDOC starter line (the content of such block is never seen by this script) + " - a "}" not followed by a "{" + + let unstated = '\%(^\s*'.s:blockstart.'.*)\|\%(//.*\)\@\)'.endline + " What is an unstated line? + " - an "else" at the end of line + " - a s:blockstart (if while etc...) followed by anything but a ";" at + " the end of line + + " if the current line is an 'else' starting line + " (to match an 'else' preceded by a '}' is irrelevant and futile - see + " code above) + if ind != b:PHP_default_indenting && cline =~# '^\s*else\%(if\)\=\>' + " prevent optimized to work at next call XXX why ? + let b:PHP_CurrentIndentLevel = b:PHP_default_indenting + return indent(FindTheIfOfAnElse(v:lnum, 1)) + elseif cline =~# s:defaultORcase + " case and default need a special treatment + return FindTheSwitchIndent(v:lnum) + &sw * b:PHP_vintage_case_default_indent + elseif cline =~ '^\s*)\=\s*{' + let previous_line = last_line + let last_line_num = lnum + + " let's find the indent of the block starter (if, while, for, etc...) + while last_line_num > 1 + + if previous_line =~ '^\s*\%(' . s:blockstart . '\|\%([a-zA-Z]\s*\)*function\)' + + let ind = indent(last_line_num) + + " If the PHP_BracesAtCodeLevel is set then indent the '{' + if b:PHP_BracesAtCodeLevel + let ind = ind + &sw + endif + + return ind + endif + + let last_line_num = last_line_num - 1 + let previous_line = getline(last_line_num) + endwhile + + elseif last_line =~# unstated && cline !~ '^\s*);\='.endline + let ind = ind + &sw " we indent one level further when the preceding line is not stated + "echo "42" + "call getchar() + return ind + + " If the last line is terminated by ';' or if it's a closing '}' + " We need to check if this isn't the end of a multilevel non '{}' + " structure such as: + " Exemple: + " if ($truc) + " echo 'truc'; + " + " OR + " + " if ($truc) + " while ($truc) { + " lkhlkh(); + " echo 'infinite loop\n'; + " } + " + " OR even (ADDED for version 1.17 - no modification required ) + " + " $thing = + " "something"; + elseif (ind != b:PHP_default_indenting || last_line =~ '^)' ) && last_line =~ terminated " Added || last_line =~ '^)' on 2007-12-30 (array indenting problem broke other things) + " If we are here it means that the previous line is: + " - a *;$ line + " - a [beginning-blanck] } followed by anything but a { $ + let previous_line = last_line + let last_line_num = lnum + let LastLineClosed = 1 + " The idea here is to check if the current line is after a non '{}' + " structure so we can indent it like the top of that structure. + " The top of that structure is characterized by a if (ff)$ style line + " preceded by a stated line. If there is no such structure then we + " just have to find two 'normal' lines following each other with the + " same indentation and with the first of these two lines terminated by + " a ; or by a }... + + while 1 + " let's skip '{}' blocks + if previous_line =~ '^\s*}' + " find the opening '{' + let last_line_num = FindOpenBracket(last_line_num) + + " if the '{' is alone on the line get the line before + if getline(last_line_num) =~ '^\s*{' + let last_line_num = GetLastRealCodeLNum(last_line_num - 1) + endif + + let previous_line = getline(last_line_num) + + continue + else + " At this point we know that the previous_line isn't a closing + " '}' so we can check if we really are in such a structure. + + " it's not a '}' but it could be an else alone... + if getline(last_line_num) =~# '^\s*else\%(if\)\=\>' + let last_line_num = FindTheIfOfAnElse(last_line_num, 0) + " re-run the loop (we could find a '}' again) + continue + endif + + " So now it's ok we can check :-) + " A good quality is to have confidence in oneself so to know + " if yes or no we are in that struct lets test the indent of + " last_line_num and of last_line_num - 1! + " If those are == then we are almost done. + " + " That isn't sufficient, we need to test how the first of + " these 2 lines ends... + + " Remember the 'topest' line we found so far + let last_match = last_line_num + + let one_ahead_indent = indent(last_line_num) + let last_line_num = GetLastRealCodeLNum(last_line_num - 1) + let two_ahead_indent = indent(last_line_num) + let after_previous_line = previous_line + let previous_line = getline(last_line_num) + + + " If we find a '{' or a case/default then we are inside that block so lets + " indent properly... Like the line following that block starter + if previous_line =~# s:defaultORcase.'\|{'.endline + break + endif + + " The 3 lines below are not necessary for the script to work + " but it makes it work a little more faster in some (rare) cases. + " We verify if we are at the top of a non '{}' struct. + if after_previous_line=~# '^\s*'.s:blockstart.'.*)'.endline && previous_line =~# '[;}]'.endline + break + endif + + if one_ahead_indent == two_ahead_indent || last_line_num < 1 + " So the previous line and the line before are at the same + " col. Now we just have to check if the line before is a ;$ or [}]$ ended line + " we always check the most ahead line of the 2 lines so + " it's useless to match ')$' since the lines couldn't have + " the same indent... + if previous_line =~# '\%(;\|^\s*}\)'.endline || last_line_num < 1 + break + endif + endif + endif + endwhile + + if indent(last_match) != ind + " let's use the indent of the last line matched by the algorithm above + let ind = indent(last_match) + " line added in version 1.02 to prevent optimized mode + " from acting in some special cases + let b:PHP_CurrentIndentLevel = b:PHP_default_indenting + + return ind + endif + " if nothing was done lets the old script continue + endif + + let plinnum = GetLastRealCodeLNum(lnum - 1) + " previous to last line + let AntepenultimateLine = getline(plinnum) + + " REMOVE comments at end of line before treatment + " the first part of the regex removes // from the end of line when they are + " followed by a number of '"' which is a multiple of 2. The second part + " removes // that are not followed by any '"' + " Sorry for this unreadable thing... + let last_line = substitute(last_line,"\\(//\\|#\\)\\(\\(\\([^\"']*\\([\"']\\)[^\"']*\\5\\)\\+[^\"']*$\\)\\|\\([^\"']*$\\)\\)",'','') + + + if ind == b:PHP_default_indenting + if last_line =~ terminated + let LastLineClosed = 1 + endif + endif + + " Indent blocks enclosed by {} or () (default indenting) + if !LastLineClosed + "echo "start" + "call getchar() + + " the last line isn't a .*; or a }$ line + " Indent correctly multilevel and multiline '(.*)' things + + " if the last line is a [{(]$ or a multiline function call (or array + " declaration) with already one parameter on the opening ( line + if last_line =~# '[{(]'.endline || last_line =~? '\h\w*\s*(.*,$' && AntepenultimateLine !~ '[,(]'.endline + + if !b:PHP_BracesAtCodeLevel || last_line !~# '^\s*{' + let ind = ind + &sw + endif + + " echo "43" + " call getchar() + if b:PHP_BracesAtCodeLevel || b:PHP_vintage_case_default_indent == 1 + " case and default are not indented inside blocks + let b:PHP_CurrentIndentLevel = ind + + return ind + endif + + " If the last line isn't empty and ends with a '),' then check if the + " ')' was opened on the same line, if not it means it closes a + " multiline '(.*)' thing and that the current line need to be + " de-indented one time. + elseif last_line =~ '\S\+\s*),'.endline + call cursor(lnum, 1) + call search('),'.endline, 'W') + let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()') + if openedparent != lnum + let ind = indent(openedparent) + endif + + " if the line before starts a block then we need to indent the + " current line. + elseif last_line =~ '^\s*'.s:blockstart + let ind = ind + &sw + + "echo cline. " --test 5-- " . ind + "call getchar() + + " In all other cases if the last line isn't terminated indent 1 + " level higher but only if the last line wasn't already indented + " for the same "code event"/reason. IE: if the antepenultimate line is terminated. + " + " 2nd explanation: + " - Test if the antepenultimate line is terminated or is + " a default/case if yes indent else let since it must have + " been indented correctly already + + "elseif cline !~ '^\s*{' && AntepenultimateLine =~ '\%(;\%(\s*?>\)\=\|<<<\a\w*\|{\|^\s*'.s:blockstart.'.*)\)'.endline.'\|^\s*}\|'.s:defaultORcase + elseif AntepenultimateLine =~ '\%(;\%(\s*?>\)\=\|<<<''\=\a\w*''\=$\|^\s*}\|{\)'.endline . '\|' . s:defaultORcase + let ind = ind + &sw + "echo pline. " --test 2-- " . ind + "call getchar() + endif + + endif + + "echo "end" + "call getchar() + " If the current line closes a multiline function call or array def + if cline =~ '^\s*);\=' + let ind = ind - &sw + endif + + let b:PHP_CurrentIndentLevel = ind + return ind +endfunction + +" vim: set ts=8 sw=4 sts=4: -- cgit v1.2.3