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