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