# HG changeset patch # User vimboss # Date 1121120943 0 # Node ID e6fd82f42ba01614f05cef765b3041f06732490c # Parent 06234af3a8b7df68bfaf0efa87edfed2d743f6c7 updated for version 7.0107 diff --git a/runtime/indent/php.vim b/runtime/indent/php.vim --- a/runtime/indent/php.vim +++ b/runtime/indent/php.vim @@ -1,116 +1,670 @@ " Vim indent file " Language: PHP -" Author: Miles Lott -" URL: http://milosch.dyndns.org/php.vim -" Last Change: 2005 Mar 21 -" Version: 0.6 -" Notes: Close all switches with default:\nbreak; and it will look better. -" Also, open and close brackets should be alone on a line. -" This is my preference, and the only way this will look nice. -" Try an older version if you care less about the formatting of -" switch/case. It is nearly perfect for anyone regardless of your -" stance on brackets. +" Author: John Wellesz +" URL: http://www.2072productions.com/vim/indent/php.vim +" Last Change: 2005 June 30th +" Version: 1.17 +" +" For a complete change log and lots of comments in the code, download the script on +" 2072productions.com at the URI provided above. +" +" +" +" If you find a bug, please e-mail me at John.wellesz (AT) teaser (DOT) fr +" with an example of code that break the algorithm. +" +" +" Thanks a lot for using this script. +" +" +" NOTE: This script must be used with PHP syntax ON and with the php syntax +" script by Lutz Eymers (http://www.isp.de/data/php.vim ) that's the script bundled with Gvim. +" +" +" In the case you have syntax errors in your script such as end of HereDoc +" tags not at col 1 you'll have to indent your file 2 times (This script +" will automatically put HereDoc end tags at col 1). +" +" +" NOTE: If you are editing file in Unix file format and that (by accident) +" there are '\r' before new lines, this script won't be able to proceed +" correctly and will make many mistakes because it won't be able to match +" '\s*$' correctly. +" So you have to remove those useless characters first with a command like: " -" Changes: 0.6 - fix indention for closing bracket (patch from pierre.habouzit@m4x.org) -" 0.5 - fix duplicate indent on open tag, and empty bracketed statements. -" 0.4 - Fixes for closing php tag, switch statement closure, and php_indent_shortopentags -" option from Steffen Bruentjen +" :%s /\r$//g +" +" or simply 'let' the option PHP_removeCRwhenUnix to 1 and the script will +" silently remove them when VIM load this script (at each bufread). + +" Options: PHP_default_indenting = # of sw (default is 0), # of sw will be +" added to the indent of each line of PHP code. +" +" Options: PHP_removeCRwhenUnix = 1 to make the script automatically remove CR +" at end of lines (by default this option is unset), NOTE that you +" MUST remove CR when the fileformat is UNIX else the indentation +" won't be correct... " -" Options: php_noindent_switch=1 -- do not try to indent switch/case statements (version 0.1 behavior) -" php_indent_shortopentags=1 -- indent after short php open tags, too +" Options: PHP_BracesAtCodeLevel = 1 to indent the '{' and '}' at the same +" level than the code they contain. +" Exemple: +" Instead of: +" if ($foo) +" { +" foo(); +" } +" +" You will write: +" if ($foo) +" { +" foo(); +" } +" +" NOTE: The script will be a bit slower if you use this option because +" some optimizations won't be available. -" Only load this indent file when no other was loaded. + if exists("b:did_indent") finish endif let b:did_indent = 1 -setlocal indentexpr=GetPhpIndent() -"setlocal indentkeys+=0=,0),=EO -setlocal indentkeys+=0=,0),=EO,=> +" This script set the option php_sync_method of PHP syntax script to 0 +" (fromstart indenting method) in order to have an accurate syntax. +" If you are using very big PHP files (which is a bad idea) you will +" experience slowings down while editing, if your code contains only PHP +" code you can comment the line below. + +let php_sync_method = 0 + + +if exists("PHP_default_indenting") + let b:PHP_default_indenting = PHP_default_indenting * &sw +else + let b:PHP_default_indenting = 0 +endif + +if exists("PHP_BracesAtCodeLevel") + let b:PHP_BracesAtCodeLevel = PHP_BracesAtCodeLevel +else + let b:PHP_BracesAtCodeLevel = 0 +endif + -" Only define the function once. +let b:PHP_lastindented = 0 +let b:PHP_indentbeforelast = 0 +let b:PHP_indentinghuge = 0 +let b:PHP_CurrentIndentLevel = b:PHP_default_indenting +let b:PHP_LastIndentedWasComment = 0 +let b:PHP_InsideMultilineComment = 0 +let b:InPHPcode = 0 +let b:InPHPcode_checked = 0 +let b:InPHPcode_and_script = 0 +let b:InPHPcode_tofind = "" +let b:PHP_oldchangetick = b:changedtick +let b:UserIsTypingComment = 0 +let b:optionsset = 0 + +setlocal nosmartindent +setlocal noautoindent +setlocal nocindent +setlocal nolisp " autoindent must be on, so this line is also useless... + +setlocal indentexpr=GetPhpIndent() +setlocal indentkeys=0{,0},0),:,!^F,o,O,e,*,=?>,=\)\@!\|]*>\%(.*<\/script>\)\@!' +"setlocal debug=msg " XXX + + +function! GetLastRealCodeLNum(startline) " {{{ + "Inspired from the function SkipJavaBlanksAndComments by Toby Allsopp for indent/java.vim + let lnum = a:startline + let old_lnum = lnum + + while lnum > 1 + let lnum = prevnonblank(lnum) + let lastline = getline(lnum) + + if b:InPHPcode_and_script && lastline =~ '?>\s*$' + let lnum = lnum - 1 + elseif lastline =~ '^\s*?>.*.*\)\@' " skip non php code + + while lastline !~ '\(' && lnum > 1 + let lnum = lnum - 1 + let lastline = getline(lnum) + endwhile + if lastline =~ '^\s*?>' " if line contains nothing but end tag + let lnum = lnum - 1 + else + break " else there is something important before the ?> + endif + + + elseif lastline =~? '^\a\w*;$' && lastline !~? s:notPhpHereDoc " match the end of a heredoc + let tofind=substitute( lastline, '\([^;]\+\);', '<<<\1$', '') + while getline(lnum) !~? tofind && lnum > 1 + let lnum = lnum - 1 + endwhile + else + break " if none of these were true then we are done + endif + endwhile + + if lnum==1 && getline(lnum)!~ '' + let beforeelse = a:lnum " we do this so we can find the opened bracket to speed up the process + else + let beforeelse = GetLastRealCodeLNum(a:lnum - 1) + endif + + if !s:level + let s:iftoskip = 0 + endif + + if getline(beforeelse) =~# '^\s*\%(}\s*\)\=else\%(\s*if\)\@!\>' + let s:iftoskip = s:iftoskip + 1 + endif + + if getline(beforeelse) =~ '^\s*}' + let beforeelse = FindOpenBracket(beforeelse) + + if getline(beforeelse) =~ '^\s*{' + let beforeelse = GetLastRealCodeLNum(beforeelse - 1) + endif + endif + + + if !s:iftoskip && a:StopAfterFirstPrevElse && getline(beforeelse) =~# '^\s*\%([}]\s*\)\=else\%(if\)\=\>' + return beforeelse + endif + + if getline(beforeelse) !~# '^\s*if\>' && beforeelse>1 || s:iftoskip && beforeelse>1 + + if s:iftoskip && getline(beforeelse) =~# '^\s*if\>' + let s:iftoskip = s:iftoskip - 1 + endif + + let s:level = s:level + 1 + let beforeelse = FindTheIfOfAnElse(beforeelse, a:StopAfterFirstPrevElse) + endif + + return beforeelse + +endfunction +" }}} + +function! IslinePHP (lnum, tofind) " {{{ + let cline = getline(a:lnum) + + if a:tofind=="" + let tofind = "^\\s*[\"']*\s*\\zs\\S" " This correct the issue where lines beginning by a + " single or double quote were not indented in some cases. + else + let tofind = a:tofind + endif + + let tofind = tofind . '\c' " ignorecase + + let coltotest = match (cline, tofind) + 1 "find the first non blank char in the current line + + let synname = synIDattr(synID(a:lnum, coltotest, 0), "name") " ask to syntax what is its name + + if synname =~ '^php' || synname=="Delimiter" || synname =~? '^javaScript' + return synname + else + return "" + endif +endfunction +" }}} + +let s:notPhpHereDoc = '\%(break\|return\|continue\|exit\);' +let s:blockstart = '\%(\%(\%(}\s*\)\=else\%(\s\+\)\=\)\=if\>\|while\>\|switch\>\|for\%(each\)\=\>\|declare\>\|[|&]\)' + +let s:autorestoptions = 0 +if ! s:autorestoptions + au BufWinEnter,Syntax *.php,*.php3,*.php4,*.php5 call ResetOptions() + let s:autorestoptions = 1 endif -function GetPhpIndent() - " Find a non-blank line above the current line. +function! ResetOptions() + if ! b:optionsset + setlocal formatoptions=qroc + let b:optionsset = 1 + endif +endfunc + +function! GetPhpIndent() + "############################################## + "########### MAIN INDENT FUNCTION ############# + "############################################## + + let UserIsEditing=0 + if b:PHP_oldchangetick != b:changedtick + let b:PHP_oldchangetick = b:changedtick + let UserIsEditing=1 + endif + + if b:PHP_default_indenting + let b:PHP_default_indenting = g:PHP_default_indenting * &sw + endif + + let cline = getline(v:lnum) " current line + + if !b:PHP_indentinghuge && b:PHP_lastindented > b:PHP_indentbeforelast + if b:PHP_indentbeforelast + let b:PHP_indentinghuge = 1 + echom 'Large indenting detected, speed optimizations engaged' + endif + let b:PHP_indentbeforelast = b:PHP_lastindented + endif + + if b:InPHPcode_checked && prevnonblank(v:lnum - 1) != b:PHP_lastindented + if b:PHP_indentinghuge + echom 'Large indenting deactivated' + let b:PHP_indentinghuge = 0 + let b:PHP_CurrentIndentLevel = b:PHP_default_indenting + endif + let b:PHP_lastindented = v:lnum + let b:PHP_LastIndentedWasComment=0 + let b:PHP_InsideMultilineComment=0 + let b:PHP_indentbeforelast = 0 + + let b:InPHPcode = 0 + let b:InPHPcode_checked = 0 + let b:InPHPcode_and_script = 0 + let b:InPHPcode_tofind = "" + + elseif v:lnum > b:PHP_lastindented " we are indenting line in > order (we can rely on the line before) + let real_PHP_lastindented = b:PHP_lastindented + let b:PHP_lastindented = v:lnum + endif + + + if !b:InPHPcode_checked " {{{ One time check + let b:InPHPcode_checked = 1 + + let synname = IslinePHP (prevnonblank(v:lnum), "") " the line could be blank (if the user presses 'return') + + if synname!="" + if synname != "phpHereDoc" + let b:InPHPcode = 1 + let b:InPHPcode_tofind = "" + + if synname == "phpComment" + let b:UserIsTypingComment = 1 + else + let b:UserIsTypingComment = 0 + endif + + if synname =~? '^javaScript' + let b:InPHPcode_and_script = 1 + endif + + else + let b:InPHPcode = 0 + let b:UserIsTypingComment = 0 + + let lnum = v:lnum - 1 + while getline(lnum) !~? '<<<\a\w*$' && lnum > 1 + let lnum = lnum - 1 + endwhile + + let b:InPHPcode_tofind = substitute( getline(lnum), '^.*<<<\(\a\w*\)\c', '^\\s*\1;$', '') + endif + else " IslinePHP returned "" => we are not in PHP or Javascript + let b:InPHPcode = 0 + let b:UserIsTypingComment = 0 + " Then we have to find a php start tag... + let b:InPHPcode_tofind = '\)\@!\|' + endif + endif "!b:InPHPcode_checked }}} + + let lnum = prevnonblank(v:lnum - 1) - " Hit the start of the file, use zero indent. - if lnum == 0 + let last_line = getline(lnum) + + if b:InPHPcode_tofind!="" + if cline =~? b:InPHPcode_tofind + let b:InPHPcode = 1 + let b:InPHPcode_tofind = "" + let b:UserIsTypingComment = 0 + if cline =~ '\*/' " End comment tags must be indented like start comment tags + call cursor(v:lnum, 1) + call search('\*/\zs', 'W') + let lnum = searchpair('/\*', '', '\*/\zs', s:searchpairflags) " find the most outside /* + + let b:PHP_CurrentIndentLevel = b:PHP_default_indenting + let b:PHP_LastIndentedWasComment = 0 " prevent a problem if multiline /**/ comment are surounded by + " other types of comments + + if cline =~ '^\s*\*/' + return indent(lnum) + 1 + else + return indent(lnum) + endif + + elseif cline =~? '' " a more accurate test is useless since there isn't any other possibility + let b:InPHPcode_and_script = 1 + endif + endif + endif + + + if b:InPHPcode + + if !b:InPHPcode_and_script && last_line =~ '\%(\%(.*')=="Delimiter" + if cline !~? s:PHP_startindenttag + let b:InPHPcode = 0 + let b:InPHPcode_tofind = s:PHP_startindenttag + elseif cline =~? '' + let b:InPHPcode_and_script = 1 + endif + + elseif last_line =~? '<<<\a\w*$' + let b:InPHPcode = 0 + let b:InPHPcode_tofind = substitute( last_line, '^.*<<<\(\a\w*\)\c', '^\\s*\1;$', '') + + elseif !UserIsEditing && cline =~ '^\s*/\*\%(.*\*/\)\@!' && getline(v:lnum + 1) !~ '^\s*\*' " XXX indent comments + let b:InPHPcode = 0 + let b:InPHPcode_tofind = '\*/' + + elseif cline =~? '^\s*' + let b:InPHPcode = 0 + let b:InPHPcode_tofind = s:PHP_startindenttag + endif + endif " }}} + + if !b:InPHPcode && !b:InPHPcode_and_script + return -1 + endif + + + " Indent successive // or # comment the same way the first is {{{ + if cline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)' + if b:PHP_LastIndentedWasComment == 1 + return indent(real_PHP_lastindented) " line replaced in 1.02 + endif + let b:PHP_LastIndentedWasComment = 1 + else + let b:PHP_LastIndentedWasComment = 0 + endif + " }}} + + " Indent multiline /* comments correctly {{{ + + + 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*/\*' " if cline == '/*' + let b:PHP_InsideMultilineComment = 1 + return -1 + endif + " }}} + + if cline =~# '^\s*' " Added the ^\s* part in version 1.03 return 0 endif - let line = getline(lnum) " last line - let cline = getline(v:lnum) " current line - let pline = getline(lnum - 1) " previous to last line - let ind = indent(lnum) + + if cline =~ '^\s*?>' && cline !~# '' - let ind = ind - &sw + + let LastLineClosed = 0 " used to prevent redundant tests in the last part of the script + + let terminated = '\%(;\%(\s*?>\)\=\|<<<\a\w*\|}\)'.endline + + let unstated = '\%(^\s*'.s:blockstart.'.*)\|\%(//.*\)\@\)'.endline + + if ind != b:PHP_default_indenting && cline =~# '^\s*else\%(if\)\=\>' + let b:PHP_CurrentIndentLevel = b:PHP_default_indenting " prevent optimized to work at next call + return indent(FindTheIfOfAnElse(v:lnum, 1)) + elseif last_line =~# unstated && cline !~ '^\s*{\|^\s*);\='.endline + let ind = ind + &sw + return ind + + + elseif ind != b:PHP_default_indenting && last_line =~ terminated + let previous_line = last_line + let last_line_num = lnum + let LastLineClosed = 1 + + + while 1 + if previous_line =~ '^\s*}' + let last_line_num = FindOpenBracket(last_line_num) + + 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 + if getline(last_line_num) =~# '^\s*else\%(if\)\=\>' + let last_line_num = FindTheIfOfAnElse(last_line_num, 0) + continue " re-run the loop (we could find a '}' again) + endif + + + let last_match = last_line_num " remember the 'topest' line we found so far + + 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 previous_line =~# defaultORcase.'\|{'.endline + break + endif + + if after_previous_line=~# '^\s*'.s:blockstart.'.*)'.endline && previous_line =~# '[;}]'.endline + break + endif + + if one_ahead_indent == two_ahead_indent || last_line_num < 1 + if previous_line =~# '[;}]'.endline || last_line_num < 1 + break + endif + endif + endif + endwhile + + if indent(last_match) != ind " if nothing was done lets the old script continue + let ind = indent(last_match) " let's use the indent of the last line matched by the alhorithm above + let b:PHP_CurrentIndentLevel = b:PHP_default_indenting " line added in version 1.02 to prevent optimized mode + " from acting in some special cases + + if cline =~# defaultORcase + let ind = ind - &sw + endif + return ind + endif endif - if exists("b:php_noindent_switch") " version 1 behavior, diy switch/case,etc - " Indent blocks enclosed by {} or () - if line =~ '[{(]\s*\(#[^)}]*\)\=$' + let plinnum = GetLastRealCodeLNum(lnum - 1) + let pline = getline(plinnum) " previous to last line + + let last_line = substitute(last_line,"\\(//\\|#\\)\\(\\(\\([^\"']*\\([\"']\\)[^\"']*\\5\\)\\+[^\"']*$\\)\\|\\([^\"']*$\\)\\)",'','') + + + if ind == b:PHP_default_indenting + if last_line =~ terminated + let LastLineClosed = 1 + endif + endif + + if !LastLineClosed " the last line isn't a .*; or a }$ line + if last_line =~# '[{(]'.endline || last_line =~? '\h\w*\s*(.*,$' && pline !~ '[,(]'.endline + + if !b:PHP_BracesAtCodeLevel || last_line !~# '^\s*{' " XXX mod { + let ind = ind + &sw + endif + + if b:PHP_BracesAtCodeLevel || cline !~# defaultORcase " XXX mod (2) { + " case and default are not indented inside blocks + let b:PHP_CurrentIndentLevel = ind + return ind + endif + + 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 + + elseif cline !~ '^\s*{' && pline =~ '\%(;\%(\s*?>\)\=\|<<<\a\w*\|{\|^\s*'.s:blockstart.'\s*(.*)\)'.endline.'\|^\s*}\|'.defaultORcase + + let ind = ind + &sw + + endif + if b:PHP_BracesAtCodeLevel && cline =~# '^\s*{' " XXX mod { let ind = ind + &sw endif - if cline =~ '^\s*[)}]' - let ind = ind - &sw - endif - return ind - else - " Search the matching bracket (with searchpair()) and set the indent of - " to the indent of the matching line. - if cline =~ '^\s*}' - call cursor(line('.'), 1) - let ind = indent(searchpair('{', '', '}','bW', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"')) - return ind - endif - " Try to indent switch/case statements as well - " Indent blocks enclosed by {} or () or case statements, with some anal requirements - if line =~ 'case.*:\|[{(]\s*\(#[^)}]*\)\=$' - let ind = ind + &sw - " return if the current line is not another case statement of the previous line is a bracket open - if cline !~ '.*case.*:\|default:' || line =~ '[{(]\s*\(#[^)}]*\)\=$' - return ind - endif - endif - if cline =~ '^\s*case.*:\|^\s*default:\|^\s*[)}]' - let ind = ind - &sw - " if the last line is a break or return, or the current line is a close bracket, - " or if the previous line is a default statement, subtract another - if line =~ '^\s*break;\|^\s*return\|' && cline =~ '^\s*[)}]' && pline =~ 'default:' - let ind = ind - &sw - endif - endif - " Search the matching bracket (with searchpair()) and set the indent of cline - " to the indent of the matching line. - if cline =~ '^\s*}' - call cursor(line('. '), 1) - let ind = indent(searchpair('{', '', '}', 'bW', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"')) - return ind - endif + + elseif last_line =~# defaultORcase + let ind = ind + &sw + endif - if line =~ 'default:' - let ind = ind + &sw - endif - return ind + if cline =~ '^\s*);\=' + let ind = ind - &sw + elseif cline =~# defaultORcase + let ind = ind - &sw + endif + + let b:PHP_CurrentIndentLevel = ind + return ind endfunction + " vim: set ts=4 sw=4: +" vim: set ff=unix: diff --git a/runtime/optwin.vim b/runtime/optwin.vim --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -1,7 +1,7 @@ " These commands create the option window. " " Maintainer: Bram Moolenaar -" Last Change: 2005 Jul 06 +" Last Change: 2005 Jul 11 " If there already is an option window, jump to that one. if bufwinnr("option-window") > 0 @@ -380,6 +380,9 @@ if has("syntax") call append("$", "syntax\tname of syntax highlighting used") call append("$", "\t(local to buffer)") call OptionL("syn") + call append("$", "synmaxcol\tmaximum column to look for syntax items") + call append("$", "\t(local to buffer)") + call OptionL("smc") endif call append("$", "highlight\twhich highlighting to use for various occasions") call OptionG("hl", &hl)