neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

php.vim (26422B)


      1 " Language:	PHP
      2 " Author:	John Wellesz <John.wellesz (AT) gmail (DOT) com>
      3 " URL:		https://www.2072productions.com/vim/indent/php.vim
      4 " Home:		https://github.com/2072/PHP-Indenting-for-VIm
      5 " Last Change:	2025 November 16th
      6 " Version:	1.76
      7 "
      8 "
      9 "	Type :help php-indent for available options
     10 "
     11 "	A fully commented version of this file is available on github
     12 "
     13 "
     14 "  If you find a bug, please open a ticket on github.com
     15 "  ( https://github.com/2072/PHP-Indenting-for-VIm/issues ) with an example of
     16 "  code that breaks the algorithm.
     17 "
     18 
     19 " NOTE: This script must be used with PHP syntax ON and with the php syntax
     20 "	script by Lutz Eymers (http://www.isp.de/data/php.vim ) or with the
     21 "	script by Peter Hodge (https://www.vim.org/scripts/script.php?script_id=1571 )
     22 "	the later is bunbdled by default with Vim 7.
     23 "
     24 "
     25 "	In the case you have syntax errors in your script such as HereDoc end
     26 "	identifiers not at col 1 you'll have to indent your file 2 times (This
     27 "	script will automatically put HereDoc end identifiers at col 1 if
     28 "	they are followed by a ';').
     29 "
     30 
     31 " NOTE: If you are editing files in Unix file format and that (by accident)
     32 "	there are '\r' before new lines, this script won't be able to proceed
     33 "	correctly and will make many mistakes because it won't be able to match
     34 "	'\s*$' correctly.
     35 "	So you have to remove those useless characters first with a command like:
     36 "
     37 "	:%s /\r$//g
     38 "
     39 "	or simply 'let' the option PHP_removeCRwhenUnix to 1 and the script will
     40 "	silently remove them when VIM load this script (at each bufread).
     41 
     42 
     43 if exists("b:did_indent")
     44    finish
     45 endif
     46 let b:did_indent = 1
     47 
     48 
     49 let g:php_sync_method = 0
     50 
     51 
     52 if exists("PHP_default_indenting")
     53    let b:PHP_default_indenting = PHP_default_indenting * shiftwidth()
     54 else
     55    let b:PHP_default_indenting = 0
     56 endif
     57 
     58 if exists("PHP_outdentSLComments")
     59    let b:PHP_outdentSLComments = PHP_outdentSLComments * shiftwidth()
     60 else
     61    let b:PHP_outdentSLComments = 0
     62 endif
     63 
     64 if exists("PHP_BracesAtCodeLevel")
     65    let b:PHP_BracesAtCodeLevel = PHP_BracesAtCodeLevel
     66 else
     67    let b:PHP_BracesAtCodeLevel = 0
     68 endif
     69 
     70 
     71 if exists("PHP_autoformatcomment")
     72    let b:PHP_autoformatcomment = PHP_autoformatcomment
     73 else
     74    let b:PHP_autoformatcomment = 1
     75 endif
     76 
     77 if exists("PHP_outdentphpescape")
     78    let b:PHP_outdentphpescape = PHP_outdentphpescape
     79 else
     80    let b:PHP_outdentphpescape = 1
     81 endif
     82 
     83 if exists("PHP_noArrowMatching")
     84    let b:PHP_noArrowMatching = PHP_noArrowMatching
     85 else
     86    let b:PHP_noArrowMatching = 0
     87 endif
     88 
     89 
     90 if exists("PHP_vintage_case_default_indent") && PHP_vintage_case_default_indent
     91    let b:PHP_vintage_case_default_indent = 1
     92 else
     93    let b:PHP_vintage_case_default_indent = 0
     94 endif
     95 
     96 if exists("PHP_IndentFunctionCallParameters")
     97    let b:PHP_IndentFunctionCallParameters = PHP_IndentFunctionCallParameters
     98 else
     99    let b:PHP_IndentFunctionCallParameters = 0
    100 endif
    101 
    102 if exists("PHP_IndentFunctionDeclarationParameters")
    103    let b:PHP_IndentFunctionDeclarationParameters = PHP_IndentFunctionDeclarationParameters
    104 else
    105    let b:PHP_IndentFunctionDeclarationParameters = 0
    106 endif
    107 
    108 let b:PHP_lastindented = 0
    109 let b:PHP_indentbeforelast = 0
    110 let b:PHP_indentinghuge = 0
    111 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
    112 let b:PHP_LastIndentedWasComment = 0
    113 let b:PHP_InsideMultilineComment = 0
    114 let b:InPHPcode = 0
    115 let b:InPHPcode_checked = 0
    116 let b:InPHPcode_and_script = 0
    117 let b:InPHPcode_tofind = ""
    118 let b:PHP_oldchangetick = b:changedtick
    119 let b:UserIsTypingComment = 0
    120 let b:optionsset = 0
    121 
    122 setlocal nosmartindent
    123 setlocal noautoindent
    124 setlocal nocindent
    125 setlocal nolisp
    126 
    127 setlocal indentexpr=GetPhpIndent()
    128 setlocal indentkeys=0{,0},0),0],:,!^F,o,O,e,*<Return>,=?>,=<?,=*/
    129 
    130 let b:undo_indent = "setl ai< cin< inde< indk< lisp< si<"
    131 
    132 let s:searchpairflags = 'bWr'
    133 
    134 if &fileformat == "unix" && exists("PHP_removeCRwhenUnix") && PHP_removeCRwhenUnix
    135    silent! %s/\r$//g
    136 endif
    137 
    138 if exists("*GetPhpIndent")
    139    call ResetPhpOptions()
    140    finish " XXX -- comment this line for easy dev
    141 endif
    142 
    143 
    144 let s:endline = '\s*\%(//.*\|#\[\@!.*\|/\*.*\*/\s*\)\=$'
    145 let s:PHP_validVariable = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
    146 let s:notPhpHereDoc = '\<\%(break\|return\|continue\|exit\|die\|true\|false\|elseif\|else\|end\%(if\|while\|for\|foreach\|match\|switch\)\)\>'
    147 let s:blockstart = '\%(\%(\%(}\s*\)\=else\%(\s\+\)\=\)\=if\>\|\%(}\s*\)\?else\>\|do\>\|while\>\|match\>\|switch\>\|case\>\|default\>\|for\%(each\)\=\>\|declare\>\|class\>\|trait\>\|\%()\s*\)\=use\>\|interface\>\|abstract\>\|final\>\|try\>\|\%(}\s*\)\=catch\>\|\%(}\s*\)\=finally\>\)'
    148 let s:functionDeclPrefix = '\<function\>\%(\s\+&\='.s:PHP_validVariable.'\)\=\s*('
    149 let s:functionDecl = s:functionDeclPrefix.'.*'
    150 let s:multilineFunctionDecl = s:functionDeclPrefix.s:endline
    151 let s:arrayDecl = '\<array\>\s*(.*'
    152 let s:multilineFunctionCall = s:PHP_validVariable.'\s*('.s:endline
    153 let s:unstated = '\%(^\s*'.s:blockstart.'.*)\|\%(//.*\)\@<!\<e'.'lse\>\)'.s:endline
    154 
    155 
    156 let s:terminated = '\%(\%(;\%(\s*\%(?>\|}\)\)\=\|<<<\s*[''"]\=\a\w*[''"]\=$\|^\s*}\|^\s*'.s:PHP_validVariable.':\)'.s:endline.'\)'
    157 let s:PHP_startindenttag = '<?\%(.*?>\)\@!\|<script[^>]*>\%(.*<\/script>\)\@!'
    158 let s:matchStart = 'match\s*(\s*\$\?'.s:PHP_validVariable.'\s*)\s*{'. s:endline
    159 let s:structureHead = '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . s:endline . '\|\<new\s\+class\>\|' . s:matchStart
    160 
    161 
    162 let s:escapeDebugStops = 0
    163 function! DebugPrintReturn(scriptLine)
    164 
    165    if ! s:escapeDebugStops
    166 echo "debug:" . a:scriptLine
    167 let c = getchar()
    168 if c == "\<Del>"
    169     let s:escapeDebugStops = 1
    170 end
    171    endif
    172 
    173 endfunction
    174 
    175 function! GetLastRealCodeLNum(startline) " {{{
    176 
    177    let lnum = a:startline
    178 
    179    if b:GetLastRealCodeLNum_ADD && b:GetLastRealCodeLNum_ADD == lnum + 1
    180 let lnum = b:GetLastRealCodeLNum_ADD
    181    endif
    182 
    183    while lnum > 1
    184 let lnum = prevnonblank(lnum)
    185 let lastline = getline(lnum)
    186 
    187 if b:InPHPcode_and_script && lastline =~ '?>\s*$'
    188     let lnum = lnum - 1
    189 elseif lastline =~ '^\s*?>.*<?\%(php\)\=\s*$'
    190     let lnum = lnum - 1
    191 elseif lastline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)'
    192     let lnum = lnum - 1
    193 elseif lastline =~ '\*/\s*$'
    194     call cursor(lnum, 1)
    195     if lastline !~ '^\*/'
    196 	call search('\*/', 'W')
    197     endif
    198     let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
    199 
    200     let lastline = getline(lnum)
    201     if lastline =~ '^\s*/\*'
    202 	let lnum = lnum - 1
    203     else
    204 	break
    205     endif
    206 
    207 
    208 elseif lastline =~? '\%(//\s*\|?>.*\)\@<!<?\%(php\)\=\s*$\|^\s*<script\>'
    209 
    210     while lastline !~ '\(<?.*\)\@<!?>' && lnum > 1
    211 	let lnum = lnum - 1
    212 	let lastline = getline(lnum)
    213     endwhile
    214     if lastline =~ '^\s*?>'
    215 	let lnum = lnum - 1
    216     else
    217 	break
    218     endif
    219 
    220 
    221 elseif lastline =~? '^\a\w*;\=$' && lastline !~? s:notPhpHereDoc
    222     let tofind=substitute( lastline, '\(\a\w*\);\=', '<<<\\s*[''"]\\=\1[''"]\\=$', '')
    223     while getline(lnum) !~? tofind && lnum > 1
    224 	let lnum = lnum - 1
    225     endwhile
    226 elseif lastline =~ '^\s*[''"`][;,]'.s:endline || (lastline =~ '^[^''"`]*[''"`][;,]'.s:endline && IslinePHP(lnum, "") == "SpecStringEntrails")
    227 
    228     let tofind=substitute( lastline, '^.*\([''"`]\)[;,].*$', '^[^\1]\\+[\1]$\\|^[^\1]\\+[=([]\\s*[\1]', '')
    229     let trylnum = lnum
    230     while getline(trylnum) !~? tofind && trylnum > 1
    231 	let trylnum = trylnum - 1
    232     endwhile
    233 
    234     if trylnum == 1
    235 	break
    236     else
    237 	if lastline =~ ';'.s:endline
    238 	    while getline(trylnum) !~? s:terminated && getline(trylnum) !~? '{'.s:endline && trylnum > 1
    239 		let trylnum = prevnonblank(trylnum - 1)
    240 	    endwhile
    241 
    242 
    243 	    if trylnum == 1
    244 		break
    245 	    end
    246 	end
    247 	let lnum = trylnum
    248     end
    249 else
    250     break
    251 endif
    252    endwhile
    253 
    254    if lnum==1 && getline(lnum) !~ '<?'
    255 let lnum=0
    256    endif
    257 
    258    if b:InPHPcode_and_script && 1 > b:InPHPcode
    259 let b:InPHPcode_and_script = 0
    260    endif
    261 
    262    return lnum
    263 endfunction " }}}
    264 
    265 function! Skippmatch2()
    266 
    267    let line = getline(".")
    268 
    269    if line =~ "\\([\"']\\).*/\\*.*\\1" || line =~ '\%(//\|#\[\@!\).*/\*'
    270 return 1
    271    else
    272 return 0
    273    endif
    274 endfun
    275 
    276 function! Skippmatch()	" {{{
    277    let synname = synIDattr(synID(line("."), col("."), 0), "name")
    278    if synname ==? "Delimiter" || synname ==? "phpRegionDelimiter" || synname =~? "^phpParent" || synname ==? "phpArrayParens" || synname =~? '^php\%(Block\|Brace\)' || synname ==? "javaScriptBraces" || synname =~? '^php\%(Doc\)\?Comment' && b:UserIsTypingComment
    279 return 0
    280    else
    281 return 1
    282    endif
    283 endfun " }}}
    284 
    285 function! FindOpenBracket(lnum, blockStarter) " {{{
    286    call cursor(a:lnum, 1)
    287    let line = searchpair('{', '', '}', 'bW', 'Skippmatch()')
    288 
    289    if a:blockStarter == 1
    290 while line > 1
    291     let linec = getline(line)
    292 
    293     if linec =~ s:terminated || linec =~ s:structureHead
    294 	break
    295     endif
    296 
    297     let line = GetLastRealCodeLNum(line - 1)
    298 endwhile
    299    endif
    300 
    301    return line
    302 endfun " }}}
    303 
    304 let s:blockChars = {'{':1, '[': 1, '(': 1, ')':-1, ']':-1, '}':-1}
    305 let s:blockCharsLUT = {'{':'{', '}':'{',   '[':'[', ']':'[',   '(':'(', ')':'('}
    306 function! BalanceDirection (str)
    307 
    308    let balance = {'{':0, '[': 0, '(': 0, 'none':0}
    309    let director = 'none'
    310 
    311    for c in split(a:str, '\zs')
    312 if has_key(s:blockChars, c)
    313     let balance[s:blockCharsLUT[c]] += s:blockChars[c]
    314 
    315     if balance[s:blockCharsLUT[c]]
    316 	let director = s:blockCharsLUT[c]
    317     endif
    318 endif
    319    endfor
    320 
    321    return balance[director]
    322 endfun
    323 
    324 function! StripEndlineComments (line)
    325 
    326    let cleaned = substitute(a:line,'\v(//|#\[\@!)((([^"'']*(["''])[^"'']*\5)+[^"'']*$)|([^"'']*$))','','')
    327    if cleaned != a:line
    328    endif
    329    return cleaned
    330 endfun
    331 
    332 function! FindArrowIndent (lnum)  " {{{
    333 
    334    let parentArrowPos = -1
    335    let cursorPos = -1
    336    let lnum = a:lnum
    337    while lnum > 1
    338 let last_line = getline(lnum)
    339 if last_line =~ '^\s*->'
    340     let parentArrowPos = indent(a:lnum)
    341     break
    342 else
    343 
    344     if b:PHP_noArrowMatching
    345 	break
    346     endif
    347 
    348     let cleanedLnum = StripEndlineComments(last_line)
    349 
    350     if cleanedLnum =~ ')'.s:endline
    351 	if BalanceDirection(cleanedLnum) <= 0
    352 	    call cursor(lnum, 1)
    353 	    call searchpos(')'.s:endline, 'cW', lnum)
    354 	    let openedparent =  searchpair('(', '', ')', 'bW', 'Skippmatch()')
    355 	    let cursorPos = col(".")
    356 	    if openedparent != lnum
    357 		let lnum = openedparent
    358 		continue
    359 	    else
    360 	    endif
    361 	else
    362 	    let parentArrowPos = -1
    363 	    break
    364 	end
    365     endif
    366 
    367     if cleanedLnum =~ '->'
    368 	call cursor(lnum, cursorPos == -1 ? strwidth(cleanedLnum) : cursorPos)
    369 	let parentArrowPos = searchpos('->', 'cWb', lnum)[1] - 1
    370 
    371 	break
    372     else
    373 	let parentArrowPos = -1
    374 	break
    375     endif
    376 endif
    377    endwhile
    378 
    379    if parentArrowPos == -1
    380 let parentArrowPos = indent(lnum) + shiftwidth()
    381    end
    382 
    383    return parentArrowPos
    384 endfun "}}}
    385 
    386 function! FindTheIfOfAnElse (lnum, StopAfterFirstPrevElse) " {{{
    387 
    388    if getline(a:lnum) =~# '^\s*}\s*else\%(if\)\=\>'
    389 let beforeelse = a:lnum
    390    else
    391 let beforeelse = GetLastRealCodeLNum(a:lnum - 1)
    392    endif
    393 
    394    if !s:level
    395 let s:iftoskip = 0
    396    endif
    397 
    398    if getline(beforeelse) =~# '^\s*\%(}\s*\)\=else\%(\s*if\)\@!\>'
    399 let s:iftoskip = s:iftoskip + 1
    400    endif
    401 
    402    if getline(beforeelse) =~ '^\s*}'
    403 let beforeelse = FindOpenBracket(beforeelse, 0)
    404 
    405 if getline(beforeelse) =~ '^\s*{'
    406     let beforeelse = GetLastRealCodeLNum(beforeelse - 1)
    407 endif
    408    endif
    409 
    410 
    411    if !s:iftoskip && a:StopAfterFirstPrevElse && getline(beforeelse) =~# '^\s*\%([}]\s*\)\=else\%(if\)\=\>'
    412 return beforeelse
    413    endif
    414 
    415    if getline(beforeelse) !~# '^\s*if\>' && beforeelse>1 || s:iftoskip && beforeelse>1
    416 
    417 if s:iftoskip && getline(beforeelse) =~# '^\s*if\>'
    418     let s:iftoskip = s:iftoskip - 1
    419 endif
    420 
    421 let s:level =  s:level + 1
    422 let beforeelse = FindTheIfOfAnElse(beforeelse, a:StopAfterFirstPrevElse)
    423    endif
    424 
    425    return beforeelse
    426 
    427 endfunction " }}}
    428 
    429 let s:defaultORcase = '^\s*\%(default\|case\).*:'
    430 
    431 function! FindTheSwitchIndent (lnum) " {{{
    432 
    433    let test = GetLastRealCodeLNum(a:lnum - 1)
    434 
    435    if test <= 1
    436 return indent(1) - shiftwidth() * b:PHP_vintage_case_default_indent
    437    end
    438 
    439    while getline(test) =~ '^\s*}' && test > 1
    440 let test = GetLastRealCodeLNum(FindOpenBracket(test, 0) - 1)
    441 
    442 if getline(test) =~ '^\s*switch\>'
    443     let test = GetLastRealCodeLNum(test - 1)
    444 endif
    445    endwhile
    446 
    447    if getline(test) =~# '^\s*switch\>'
    448 return indent(test)
    449    elseif getline(test) =~# s:defaultORcase
    450 return indent(test) - shiftwidth() * b:PHP_vintage_case_default_indent
    451    else
    452 return FindTheSwitchIndent(test)
    453    endif
    454 
    455 endfunction "}}}
    456 
    457 let s:SynPHPMatchGroups = {'phpparent':1, 'delimiter':1, 'define':1, 'storageclass':1, 'structure':1, 'exception':1}
    458 function! IslinePHP (lnum, tofind) " {{{
    459    let cline = getline(a:lnum)
    460 
    461    if a:tofind==""
    462 let tofind = "^\\s*[\"'`]*\\s*\\zs\\S"
    463    else
    464 let tofind = a:tofind
    465    endif
    466 
    467    let tofind = tofind . '\c'
    468 
    469    let coltotest = match (cline, tofind) + 1
    470 
    471    let synname = synIDattr(synID(a:lnum, coltotest, 0), "name")
    472 
    473    if synname ==? 'phpStringSingle' || synname ==? 'phpStringDouble' || synname ==? 'phpBacktick'
    474 if cline !~ '^\s*[''"`]' " ??? XXX
    475     return "SpecStringEntrails"
    476 else
    477     return synname
    478 end
    479    end
    480 
    481    if get(s:SynPHPMatchGroups, tolower(synname)) || synname =~ '^php' ||  synname =~? '^javaScript'
    482 return synname
    483    else
    484 return ""
    485    endif
    486 endfunction " }}}
    487 
    488 let s:autoresetoptions = 0
    489 if ! s:autoresetoptions
    490    let s:autoresetoptions = 1
    491 endif
    492 
    493 function! ResetPhpOptions()
    494    if ! b:optionsset && &filetype =~ "php"
    495 if b:PHP_autoformatcomment
    496 
    497     setlocal comments=s1:/*,mb:*,ex:*/,://,f:#[,:#
    498 
    499     setlocal formatoptions-=t
    500     setlocal formatoptions+=q
    501     setlocal formatoptions+=r
    502     setlocal formatoptions+=o
    503     setlocal formatoptions+=c
    504     setlocal formatoptions+=b
    505 endif
    506 let b:optionsset = 1
    507    endif
    508 endfunc
    509 
    510 call ResetPhpOptions()
    511 
    512 function! GetPhpIndentVersion()
    513    return "1.75"
    514 endfun
    515 
    516 function! GetPhpIndent()
    517 
    518    let b:GetLastRealCodeLNum_ADD = 0
    519 
    520    let UserIsEditing=0
    521    if	b:PHP_oldchangetick != b:changedtick
    522 let b:PHP_oldchangetick = b:changedtick
    523 let UserIsEditing=1
    524    endif
    525 
    526    if b:PHP_default_indenting
    527 let b:PHP_default_indenting = g:PHP_default_indenting * shiftwidth()
    528    endif
    529 
    530    let cline = getline(v:lnum)
    531 
    532    if !b:PHP_indentinghuge && b:PHP_lastindented > b:PHP_indentbeforelast
    533 if b:PHP_indentbeforelast
    534     let b:PHP_indentinghuge = 1
    535 endif
    536 let b:PHP_indentbeforelast = b:PHP_lastindented
    537    endif
    538 
    539    if b:InPHPcode_checked && prevnonblank(v:lnum - 1) != b:PHP_lastindented
    540 if b:PHP_indentinghuge
    541     let b:PHP_indentinghuge = 0
    542     let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
    543 endif
    544 let real_PHP_lastindented = v:lnum
    545 let b:PHP_LastIndentedWasComment=0
    546 let b:PHP_InsideMultilineComment=0
    547 let b:PHP_indentbeforelast = 0
    548 
    549 let b:InPHPcode = 0
    550 let b:InPHPcode_checked = 0
    551 let b:InPHPcode_and_script = 0
    552 let b:InPHPcode_tofind = ""
    553 
    554    elseif v:lnum > b:PHP_lastindented
    555 let real_PHP_lastindented = b:PHP_lastindented
    556    else
    557 let real_PHP_lastindented = v:lnum
    558    endif
    559 
    560    let b:PHP_lastindented = v:lnum
    561 
    562 
    563    if !b:InPHPcode_checked " {{{ One time check
    564 let b:InPHPcode_checked = 1
    565 let b:UserIsTypingComment = 0
    566 
    567 let synname = ""
    568 if cline !~ '<?.*?>'
    569     let synname = IslinePHP (prevnonblank(v:lnum), "")
    570 endif
    571 
    572 if synname!=""
    573     if synname ==? "SpecStringEntrails"
    574 	let b:InPHPcode = -1 " thumb down
    575 	let b:InPHPcode_tofind = ""
    576     elseif synname !=? "phpHereDoc" && synname !=? "phpHereDocDelimiter"
    577 	let b:InPHPcode = 1
    578 	let b:InPHPcode_tofind = ""
    579 
    580 	if synname =~? '^php\%(Doc\)\?Comment'
    581 	    let b:UserIsTypingComment = 1
    582 	    let b:InPHPcode_checked = 0
    583 	endif
    584 
    585 	if synname =~? '^javaScript'
    586 	    let b:InPHPcode_and_script = 1
    587 	endif
    588 
    589     else
    590 	let b:InPHPcode = 0
    591 
    592 	let lnum = v:lnum - 1
    593 	while getline(lnum) !~? '<<<\s*[''"]\=\a\w*[''"]\=$' && lnum > 1
    594 	    let lnum = lnum - 1
    595 	endwhile
    596 
    597 	let b:InPHPcode_tofind = substitute( getline(lnum), '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '')
    598     endif
    599 else
    600     let b:InPHPcode = 0
    601     let b:InPHPcode_tofind = s:PHP_startindenttag
    602 endif
    603    endif "!b:InPHPcode_checked }}}
    604 
    605 
    606    " Test if we are indenting PHP code {{{
    607    let lnum = prevnonblank(v:lnum - 1)
    608    let last_line = getline(lnum)
    609    let endline= s:endline
    610 
    611    if b:InPHPcode_tofind!=""
    612 if cline =~? b:InPHPcode_tofind
    613     let b:InPHPcode_tofind = ""
    614     let b:UserIsTypingComment = 0
    615 
    616     if b:InPHPcode == -1
    617 	let b:InPHPcode = 1
    618 	return -1
    619     end
    620 
    621     let b:InPHPcode = 1
    622 
    623     if cline =~ '\*/'
    624 	call cursor(v:lnum, 1)
    625 	if cline !~ '^\*/'
    626 	    call search('\*/', 'W')
    627 	endif
    628 	let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
    629 
    630 	let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
    631 
    632 	let b:PHP_LastIndentedWasComment = 0
    633 
    634 	if cline =~ '^\s*\*/'
    635 	    return indent(lnum) + 1
    636 	else
    637 	    return indent(lnum)
    638 	endif
    639 
    640     elseif cline =~? '<script\>'
    641 	let b:InPHPcode_and_script = 1
    642 	let b:GetLastRealCodeLNum_ADD = v:lnum
    643     endif
    644 endif
    645    endif
    646 
    647    if 1 == b:InPHPcode
    648 
    649 if !b:InPHPcode_and_script && last_line =~ '\%(<?.*\)\@<!?>\%(.*<?\)\@!' && IslinePHP(lnum, '?>')=~?"Delimiter"
    650     if cline !~? s:PHP_startindenttag
    651 	let b:InPHPcode = 0
    652 	let b:InPHPcode_tofind = s:PHP_startindenttag
    653     elseif cline =~? '<script\>'
    654 	let b:InPHPcode_and_script = 1
    655     endif
    656 
    657 elseif last_line =~ '^[^''"`]\+[''"`]$' && last_line !~ '^\s*\%(//\|#\[\@!\|/\*.*\*/\s*$\)' " a string identifier with nothing after it and no other string identifier before
    658     let b:InPHPcode = -1
    659     let b:InPHPcode_tofind = substitute( last_line, '^.*\([''"`]\).*$', '^[^\1]*\1[;,]$', '')
    660 elseif last_line =~? '<<<\s*[''"]\=\a\w*[''"]\=$'
    661     let b:InPHPcode = 0
    662     let b:InPHPcode_tofind = substitute( last_line, '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '')
    663 
    664 elseif !UserIsEditing && cline =~ '^\s*/\*\%(.*\*/\)\@!' && getline(v:lnum + 1) !~ '^\s*\*'
    665     let b:InPHPcode = 0
    666     let b:InPHPcode_tofind = '\*/'
    667 
    668 elseif cline =~? '^\s*</script>'
    669     let b:InPHPcode = 0
    670     let b:InPHPcode_tofind = s:PHP_startindenttag
    671 endif
    672    endif " }}}
    673 
    674 
    675    if 1 > b:InPHPcode && !b:InPHPcode_and_script
    676 return -1
    677    endif
    678 
    679    " Indent successive // or # comment the same way the first is {{{
    680    let addSpecial = 0
    681    if cline =~ '^\s*\%(//\|#\[\@!\|/\*.*\*/\s*$\)'
    682 let addSpecial = b:PHP_outdentSLComments
    683 if b:PHP_LastIndentedWasComment == 1
    684     return indent(real_PHP_lastindented)
    685 endif
    686 let b:PHP_LastIndentedWasComment = 1
    687    else
    688 let b:PHP_LastIndentedWasComment = 0
    689    endif " }}}
    690 
    691    " Indent multiline /* comments correctly {{{
    692 
    693    if b:PHP_InsideMultilineComment || b:UserIsTypingComment
    694 if cline =~ '^\s*\*\%(\/\)\@!'
    695     if last_line =~ '^\s*/\*'
    696 	return indent(lnum) + 1
    697     else
    698 	return indent(lnum)
    699     endif
    700 else
    701     let b:PHP_InsideMultilineComment = 0
    702 endif
    703    endif
    704 
    705    if !b:PHP_InsideMultilineComment && cline =~ '^\s*/\*\%(.*\*/\)\@!'
    706 if getline(v:lnum + 1) !~ '^\s*\*'
    707     return -1
    708 endif
    709 let b:PHP_InsideMultilineComment = 1
    710    endif " }}}
    711 
    712 
    713    " Things always indented at col 1 (PHP delimiter: <?, ?>, Heredoc end) {{{
    714    if cline =~# '^\s*<?' && cline !~ '?>' && b:PHP_outdentphpescape
    715 return 0
    716    endif
    717 
    718    if	cline =~ '^\s*?>' && cline !~# '<?' && b:PHP_outdentphpescape
    719 return 0
    720    endif
    721 
    722    if (cline =~? '^\s*\a\w*;$\|^\a\w*$' || (cline =~? '^\s*[''"`][;,]' && IslinePHP(v:lnum, '[;,]') !~? '^\(phpString[SD]\|phpBacktick\)') ) && cline !~? s:notPhpHereDoc
    723 return 0
    724    endif " }}}
    725 
    726    let s:level = 0
    727 
    728    let lnum = GetLastRealCodeLNum(v:lnum - 1)
    729 
    730    let last_line = getline(lnum)
    731    let ind = indent(lnum)
    732 
    733    if ind==0 && b:PHP_default_indenting
    734 let ind = b:PHP_default_indenting
    735    endif
    736 
    737    if lnum == 0
    738 return b:PHP_default_indenting + addSpecial
    739    endif
    740 
    741 
    742    if cline =~ '^\s*}\%(}}\)\@!'
    743 let ind = indent(FindOpenBracket(v:lnum, 1))
    744 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
    745 if  b:PHP_BracesAtCodeLevel
    746     let ind = ind + shiftwidth()
    747 endif
    748 return ind
    749    endif
    750 
    751    if cline =~ '^\s*\*/'
    752 call cursor(v:lnum, 1)
    753 if cline !~ '^\*/'
    754     call search('\*/', 'W')
    755 endif
    756 let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
    757 
    758 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
    759 
    760 if cline =~ '^\s*\*/'
    761     return indent(lnum) + 1
    762 else
    763     return indent(lnum)
    764 endif
    765    endif
    766 
    767 
    768    if last_line =~ '[;}]'.endline && last_line !~ '^[)\]]' && last_line !~# s:defaultORcase && last_line !~ '^\s*[''"`][;,]'
    769 if ind==b:PHP_default_indenting
    770     return b:PHP_default_indenting + addSpecial
    771 elseif b:PHP_indentinghuge && ind==b:PHP_CurrentIndentLevel && cline !~# '^\s*\%(else\|\%(case\|default\).*:\|[})];\=\)' && last_line !~# '^\s*\%(\%(}\s*\)\=else\)\|^\(\s*\S\+\s*\)\+}'.endline && getline(GetLastRealCodeLNum(lnum - 1))=~';'.endline
    772     return b:PHP_CurrentIndentLevel + addSpecial
    773 endif
    774    endif
    775 
    776    let LastLineClosed = 0
    777 
    778    let terminated = s:terminated
    779 
    780    let unstated  = s:unstated
    781 
    782 
    783    if ind != b:PHP_default_indenting && cline =~# '^\s*else\%(if\)\=\>'
    784 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
    785 return indent(FindTheIfOfAnElse(v:lnum, 1))
    786    elseif cline =~# s:defaultORcase
    787 return FindTheSwitchIndent(v:lnum) + shiftwidth() * b:PHP_vintage_case_default_indent
    788    elseif cline =~ '^\s*)\=\s*{'
    789 let previous_line = last_line
    790 let last_line_num = lnum
    791 
    792 while last_line_num > 1
    793 
    794     if previous_line =~ terminated || previous_line =~ s:structureHead
    795 
    796 	let ind = indent(last_line_num)
    797 
    798 	if  b:PHP_BracesAtCodeLevel
    799 	    let ind = ind + shiftwidth()
    800 	endif
    801 
    802 	return ind
    803     endif
    804 
    805     let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
    806     let previous_line = getline(last_line_num)
    807 endwhile
    808    elseif cline =~ '^\s*->'
    809 return FindArrowIndent(lnum)
    810    elseif last_line =~# unstated && cline !~ '^\s*);\='.endline
    811 let ind = ind + shiftwidth() " we indent one level further when the preceding line is not stated
    812 return ind + addSpecial
    813 
    814    elseif (ind != b:PHP_default_indenting || last_line =~ '^[)\]]' ) && last_line =~ terminated
    815 let previous_line = last_line
    816 let last_line_num = lnum
    817 let LastLineClosed = 1
    818 
    819 let isSingleLineBlock = 0
    820 while 1
    821     if ! isSingleLineBlock && previous_line =~ '^\s*}\|;\s*}'.endline
    822 
    823 	call cursor(last_line_num, 1)
    824 	if previous_line !~ '^}'
    825 	    call search('}\|;\s*}'.endline, 'W')
    826 	end
    827 	let oldLastLine = last_line_num
    828 	let last_line_num = searchpair('{', '', '}', 'bW', 'Skippmatch()')
    829 
    830 	if getline(last_line_num) =~ '^\s*{'
    831 	    let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
    832 	elseif oldLastLine == last_line_num
    833 	    let isSingleLineBlock = 1
    834 	    continue
    835 	endif
    836 
    837 	let previous_line = getline(last_line_num)
    838 
    839 	continue
    840     else
    841 
    842 	if getline(last_line_num) =~# '^\s*else\%(if\)\=\>' && !isSingleLineBlock
    843 	    let last_line_num = FindTheIfOfAnElse(last_line_num, 0)
    844 	    let isSingleLineBlock = 0
    845 	    continue
    846 	endif
    847 
    848 	let isSingleLineBlock = 0
    849 
    850 
    851 	let last_match = last_line_num
    852 
    853 	let one_ahead_indent = indent(last_line_num)
    854 	let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
    855 	let two_ahead_indent = indent(last_line_num)
    856 	let after_previous_line = previous_line
    857 	let previous_line = getline(last_line_num)
    858 
    859 
    860 	if previous_line =~# s:defaultORcase.'\|{'.endline
    861 	    break
    862 	endif
    863 
    864 	if after_previous_line=~# '^\s*'.s:blockstart.'.*)'.endline && previous_line =~# '[;}]'.endline
    865 	    break
    866 	endif
    867 
    868 	if one_ahead_indent == two_ahead_indent || last_line_num < 1
    869 	    if previous_line =~# '\%(;\|^\s*}\)'.endline || last_line_num < 1
    870 		break
    871 	    endif
    872 	endif
    873     endif
    874 endwhile
    875 
    876 if indent(last_match) != ind
    877     let ind = indent(last_match)
    878     let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
    879 
    880     return ind + addSpecial
    881 endif
    882    endif
    883 
    884    if (last_line !~ '^\s*}\%(}}\)\@!')
    885 let plinnum = GetLastRealCodeLNum(lnum - 1)
    886    else
    887 let plinnum = GetLastRealCodeLNum(FindOpenBracket(lnum, 1) - 1)
    888    endif
    889 
    890    let AntepenultimateLine = getline(plinnum)
    891 
    892    let last_line = StripEndlineComments(last_line)
    893 
    894    if ind == b:PHP_default_indenting
    895 if last_line =~ terminated && last_line !~# s:defaultORcase
    896     let LastLineClosed = 1
    897 endif
    898    endif
    899 
    900    if !LastLineClosed
    901 
    902 let openedparent = -1
    903 
    904 
    905 if last_line =~# '[{(\[]'.endline || last_line =~? '\h\w*\s*(.*,$' && AntepenultimateLine !~ '[,(\[]'.endline && BalanceDirection(last_line) > 0
    906 
    907     let dontIndent = 0
    908     if last_line =~ '\S\+\s*{'.endline && last_line !~ '^\s*[)\]]\+\(\s*:\s*'.s:PHP_validVariable.'\)\=\s*{'.endline && last_line !~ s:structureHead
    909 	let dontIndent = 1
    910     endif
    911 
    912     if !dontIndent && (!b:PHP_BracesAtCodeLevel || last_line !~# '^\s*{')
    913 	let ind = ind + shiftwidth()
    914     endif
    915 
    916     if b:PHP_IndentFunctionCallParameters && last_line =~ s:multilineFunctionCall && last_line !~ s:structureHead && last_line !~ s:arrayDecl
    917 	let ind = ind + b:PHP_IndentFunctionCallParameters * shiftwidth()
    918     endif
    919 
    920     if b:PHP_IndentFunctionDeclarationParameters && last_line =~ s:multilineFunctionDecl
    921 	let ind = ind + b:PHP_IndentFunctionDeclarationParameters * shiftwidth()
    922     endif
    923 
    924     if b:PHP_BracesAtCodeLevel || b:PHP_vintage_case_default_indent == 1
    925 	let b:PHP_CurrentIndentLevel = ind
    926 
    927     endif
    928 
    929 elseif last_line =~ '),'.endline && BalanceDirection(last_line) < 0
    930     call cursor(lnum, 1)
    931     call searchpos('),'.endline, 'cW')
    932     let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()')
    933     if openedparent != lnum
    934 	let ind = indent(openedparent)
    935     endif
    936 
    937 elseif last_line =~ s:structureHead
    938     let ind = ind + shiftwidth()
    939 
    940 
    941 elseif AntepenultimateLine =~ '{'.endline && AntepenultimateLine !~? '^\s*use\>' && AntepenultimateLine !~? s:matchStart || AntepenultimateLine =~ terminated || AntepenultimateLine =~# s:defaultORcase
    942     let ind = ind + shiftwidth()
    943 endif
    944 
    945 
    946 if openedparent >= 0
    947     let last_line = StripEndlineComments(getline(openedparent))
    948 endif
    949    endif
    950 
    951    if cline =~ '^\s*[)\]];\='
    952 call cursor(v:lnum, 1)
    953 call searchpos('[)\]]', 'cW')
    954 let matchedBlockChar = cline[col('.')-1]
    955 let openedparent = searchpair('\M'.s:blockCharsLUT[matchedBlockChar], '', '\M'.matchedBlockChar, 'bW', 'Skippmatch()')
    956 if openedparent != v:lnum
    957     let ind = indent(openedparent)
    958 endif
    959 
    960    elseif last_line =~ '^\s*->' && last_line !~? s:structureHead && BalanceDirection(last_line) <= 0
    961 let ind = ind - shiftwidth()
    962    endif
    963 
    964    let b:PHP_CurrentIndentLevel = ind
    965    return ind + addSpecial
    966 endfunction