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: 2017 Jun 13 7" Version: 1.62 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.org 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 85 86if exists("PHP_vintage_case_default_indent") && PHP_vintage_case_default_indent 87 let b:PHP_vintage_case_default_indent = 1 88else 89 let b:PHP_vintage_case_default_indent = 0 90endif 91 92 93 94let b:PHP_lastindented = 0 95let b:PHP_indentbeforelast = 0 96let b:PHP_indentinghuge = 0 97let b:PHP_CurrentIndentLevel = b:PHP_default_indenting 98let b:PHP_LastIndentedWasComment = 0 99let b:PHP_InsideMultilineComment = 0 100let b:InPHPcode = 0 101let b:InPHPcode_checked = 0 102let b:InPHPcode_and_script = 0 103let b:InPHPcode_tofind = "" 104let b:PHP_oldchangetick = b:changedtick 105let b:UserIsTypingComment = 0 106let b:optionsset = 0 107 108setlocal nosmartindent 109setlocal noautoindent 110setlocal nocindent 111setlocal nolisp 112 113setlocal indentexpr=GetPhpIndent() 114setlocal indentkeys=0{,0},0),0],:,!^F,o,O,e,*<Return>,=?>,=<?,=*/ 115 116 117 118let s:searchpairflags = 'bWr' 119 120if &fileformat == "unix" && exists("PHP_removeCRwhenUnix") && PHP_removeCRwhenUnix 121 silent! %s/\r$//g 122endif 123 124if exists("*GetPhpIndent") 125 call ResetPhpOptions() 126 finish 127endif 128 129 130let s:PHP_validVariable = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*' 131let s:notPhpHereDoc = '\%(break\|return\|continue\|exit\|die\|else\)' 132let 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\>\)' 133let s:functionDecl = '\<function\>\%(\s\+'.s:PHP_validVariable.'\)\=\s*(.*' 134let s:endline = '\s*\%(//.*\|#.*\|/\*.*\*/\s*\)\=$' 135let s:unstated = '\%(^\s*'.s:blockstart.'.*)\|\%(//.*\)\@<!\<e'.'lse\>\)'.s:endline 136 137 138let s:terminated = '\%(\%(;\%(\s*\%(?>\|}\)\)\=\|<<<\s*[''"]\=\a\w*[''"]\=$\|^\s*}\|^\s*'.s:PHP_validVariable.':\)'.s:endline.'\)' 139let s:PHP_startindenttag = '<?\%(.*?>\)\@!\|<script[^>]*>\%(.*<\/script>\)\@!' 140let s:structureHead = '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . s:endline . '\|\<new\s\+class\>' 141 142 143 144let s:escapeDebugStops = 0 145function! DebugPrintReturn(scriptLine) 146 147 if ! s:escapeDebugStops 148 echo "debug:" . a:scriptLine 149 let c = getchar() 150 if c == "\<Del>" 151 let s:escapeDebugStops = 1 152 end 153 endif 154 155endfunction 156 157function! GetLastRealCodeLNum(startline) " {{{ 158 159 let lnum = a:startline 160 161 if b:GetLastRealCodeLNum_ADD && b:GetLastRealCodeLNum_ADD == lnum + 1 162 let lnum = b:GetLastRealCodeLNum_ADD 163 endif 164 165 while lnum > 1 166 let lnum = prevnonblank(lnum) 167 let lastline = getline(lnum) 168 169 if b:InPHPcode_and_script && lastline =~ '?>\s*$' 170 let lnum = lnum - 1 171 elseif lastline =~ '^\s*?>.*<?\%(php\)\=\s*$' 172 let lnum = lnum - 1 173 elseif lastline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)' 174 let lnum = lnum - 1 175 elseif lastline =~ '\*/\s*$' 176 call cursor(lnum, 1) 177 if lastline !~ '^\*/' 178 call search('\*/', 'W') 179 endif 180 let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()') 181 182 let lastline = getline(lnum) 183 if lastline =~ '^\s*/\*' 184 let lnum = lnum - 1 185 else 186 break 187 endif 188 189 190 elseif lastline =~? '\%(//\s*\|?>.*\)\@<!<?\%(php\)\=\s*$\|^\s*<script\>' 191 192 while lastline !~ '\(<?.*\)\@<!?>' && lnum > 1 193 let lnum = lnum - 1 194 let lastline = getline(lnum) 195 endwhile 196 if lastline =~ '^\s*?>' 197 let lnum = lnum - 1 198 else 199 break 200 endif 201 202 203 elseif lastline =~? '^\a\w*;\=$' && lastline !~? s:notPhpHereDoc 204 let tofind=substitute( lastline, '\(\a\w*\);\=', '<<<\\s*[''"]\\=\1[''"]\\=$', '') 205 while getline(lnum) !~? tofind && lnum > 1 206 let lnum = lnum - 1 207 endwhile 208 elseif lastline =~ '^[^''"`]*[''"`][;,]'.s:endline 209 210 let tofind=substitute( lastline, '^.*\([''"`]\)[;,].*$', '^[^\1]\\+[\1]$\\|^[^\1]\\+[=([]\\s*[\1]', '') 211 let trylnum = lnum 212 while getline(trylnum) !~? tofind && trylnum > 1 213 let trylnum = trylnum - 1 214 endwhile 215 216 if trylnum == 1 217 break 218 else 219 if lastline =~ ';'.s:endline 220 while getline(trylnum) !~? s:terminated && getline(trylnum) !~? '{'.s:endline && trylnum > 1 221 let trylnum = prevnonblank(trylnum - 1) 222 endwhile 223 224 225 if trylnum == 1 226 break 227 end 228 end 229 let lnum = trylnum 230 end 231 else 232 break 233 endif 234 endwhile 235 236 if lnum==1 && getline(lnum) !~ '<?' 237 let lnum=0 238 endif 239 240 if b:InPHPcode_and_script && 1 > b:InPHPcode 241 let b:InPHPcode_and_script = 0 242 endif 243 244 return lnum 245endfunction " }}} 246 247function! Skippmatch2() 248 249 let line = getline(".") 250 251 if line =~ "\\([\"']\\).*/\\*.*\\1" || line =~ '\%(//\|#\).*/\*' 252 return 1 253 else 254 return 0 255 endif 256endfun 257 258function! Skippmatch() " {{{ 259 let synname = synIDattr(synID(line("."), col("."), 0), "name") 260 if synname == "Delimiter" || synname == "phpRegionDelimiter" || synname =~# "^phpParent" || synname == "phpArrayParens" || synname =~# '^php\%(Block\|Brace\)' || synname == "javaScriptBraces" || synname =~# '^php\%(Doc\)\?Comment' && b:UserIsTypingComment 261 return 0 262 else 263 return 1 264 endif 265endfun " }}} 266 267function! FindOpenBracket(lnum, blockStarter) " {{{ 268 call cursor(a:lnum, 1) 269 let line = searchpair('{', '', '}', 'bW', 'Skippmatch()') 270 271 if a:blockStarter == 1 272 while line > 1 273 let linec = getline(line) 274 275 if linec =~ s:terminated || linec =~ s:structureHead 276 break 277 endif 278 279 let line = GetLastRealCodeLNum(line - 1) 280 endwhile 281 endif 282 283 return line 284endfun " }}} 285 286let s:blockChars = {'{':1, '[': 1, '(': 1, ')':-1, ']':-1, '}':-1} 287function! BalanceDirection (str) 288 289 let balance = 0 290 291 for c in split(a:str, '\zs') 292 if has_key(s:blockChars, c) 293 let balance += s:blockChars[c] 294 endif 295 endfor 296 297 return balance 298endfun 299 300function! FindTheIfOfAnElse (lnum, StopAfterFirstPrevElse) " {{{ 301 302 if getline(a:lnum) =~# '^\s*}\s*else\%(if\)\=\>' 303 let beforeelse = a:lnum 304 else 305 let beforeelse = GetLastRealCodeLNum(a:lnum - 1) 306 endif 307 308 if !s:level 309 let s:iftoskip = 0 310 endif 311 312 if getline(beforeelse) =~# '^\s*\%(}\s*\)\=else\%(\s*if\)\@!\>' 313 let s:iftoskip = s:iftoskip + 1 314 endif 315 316 if getline(beforeelse) =~ '^\s*}' 317 let beforeelse = FindOpenBracket(beforeelse, 0) 318 319 if getline(beforeelse) =~ '^\s*{' 320 let beforeelse = GetLastRealCodeLNum(beforeelse - 1) 321 endif 322 endif 323 324 325 if !s:iftoskip && a:StopAfterFirstPrevElse && getline(beforeelse) =~# '^\s*\%([}]\s*\)\=else\%(if\)\=\>' 326 return beforeelse 327 endif 328 329 if getline(beforeelse) !~# '^\s*if\>' && beforeelse>1 || s:iftoskip && beforeelse>1 330 331 if s:iftoskip && getline(beforeelse) =~# '^\s*if\>' 332 let s:iftoskip = s:iftoskip - 1 333 endif 334 335 let s:level = s:level + 1 336 let beforeelse = FindTheIfOfAnElse(beforeelse, a:StopAfterFirstPrevElse) 337 endif 338 339 return beforeelse 340 341endfunction " }}} 342 343let s:defaultORcase = '^\s*\%(default\|case\).*:' 344 345function! FindTheSwitchIndent (lnum) " {{{ 346 347 let test = GetLastRealCodeLNum(a:lnum - 1) 348 349 if test <= 1 350 return indent(1) - shiftwidth() * b:PHP_vintage_case_default_indent 351 end 352 353 while getline(test) =~ '^\s*}' && test > 1 354 let test = GetLastRealCodeLNum(FindOpenBracket(test, 0) - 1) 355 356 if getline(test) =~ '^\s*switch\>' 357 let test = GetLastRealCodeLNum(test - 1) 358 endif 359 endwhile 360 361 if getline(test) =~# '^\s*switch\>' 362 return indent(test) 363 elseif getline(test) =~# s:defaultORcase 364 return indent(test) - shiftwidth() * b:PHP_vintage_case_default_indent 365 else 366 return FindTheSwitchIndent(test) 367 endif 368 369endfunction "}}} 370 371let s:SynPHPMatchGroups = {'phpParent':1, 'Delimiter':1, 'Define':1, 'Storageclass':1, 'StorageClass':1, 'Structure':1, 'Exception':1} 372function! IslinePHP (lnum, tofind) " {{{ 373 let cline = getline(a:lnum) 374 375 if a:tofind=="" 376 let tofind = "^\\s*[\"'`]*\\s*\\zs\\S" 377 else 378 let tofind = a:tofind 379 endif 380 381 let tofind = tofind . '\c' 382 383 let coltotest = match (cline, tofind) + 1 384 385 let synname = synIDattr(synID(a:lnum, coltotest, 0), "name") 386 387 if synname == 'phpStringSingle' || synname == 'phpStringDouble' || synname == 'phpBacktick' 388 if cline !~ '^\s*[''"`]' 389 return "SpecStringEntrails" 390 else 391 return synname 392 end 393 end 394 395 if get(s:SynPHPMatchGroups, synname) || synname =~ '^php' || synname =~? '^javaScript' 396 return synname 397 else 398 return "" 399 endif 400endfunction " }}} 401 402let s:autoresetoptions = 0 403if ! s:autoresetoptions 404 let s:autoresetoptions = 1 405endif 406 407function! ResetPhpOptions() 408 if ! b:optionsset && &filetype =~ "php" 409 if b:PHP_autoformatcomment 410 411 setlocal comments=s1:/*,mb:*,ex:*/,://,:# 412 413 setlocal formatoptions-=t 414 setlocal formatoptions+=q 415 setlocal formatoptions+=r 416 setlocal formatoptions+=o 417 setlocal formatoptions+=c 418 setlocal formatoptions+=b 419 endif 420 let b:optionsset = 1 421 endif 422endfunc 423 424call ResetPhpOptions() 425 426function! GetPhpIndent() 427 428 let b:GetLastRealCodeLNum_ADD = 0 429 430 let UserIsEditing=0 431 if b:PHP_oldchangetick != b:changedtick 432 let b:PHP_oldchangetick = b:changedtick 433 let UserIsEditing=1 434 endif 435 436 if b:PHP_default_indenting 437 let b:PHP_default_indenting = g:PHP_default_indenting * shiftwidth() 438 endif 439 440 let cline = getline(v:lnum) 441 442 if !b:PHP_indentinghuge && b:PHP_lastindented > b:PHP_indentbeforelast 443 if b:PHP_indentbeforelast 444 let b:PHP_indentinghuge = 1 445 endif 446 let b:PHP_indentbeforelast = b:PHP_lastindented 447 endif 448 449 if b:InPHPcode_checked && prevnonblank(v:lnum - 1) != b:PHP_lastindented 450 if b:PHP_indentinghuge 451 let b:PHP_indentinghuge = 0 452 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting 453 endif 454 let real_PHP_lastindented = v:lnum 455 let b:PHP_LastIndentedWasComment=0 456 let b:PHP_InsideMultilineComment=0 457 let b:PHP_indentbeforelast = 0 458 459 let b:InPHPcode = 0 460 let b:InPHPcode_checked = 0 461 let b:InPHPcode_and_script = 0 462 let b:InPHPcode_tofind = "" 463 464 elseif v:lnum > b:PHP_lastindented 465 let real_PHP_lastindented = b:PHP_lastindented 466 else 467 let real_PHP_lastindented = v:lnum 468 endif 469 470 let b:PHP_lastindented = v:lnum 471 472 473 if !b:InPHPcode_checked " {{{ One time check 474 let b:InPHPcode_checked = 1 475 let b:UserIsTypingComment = 0 476 477 let synname = "" 478 if cline !~ '<?.*?>' 479 let synname = IslinePHP (prevnonblank(v:lnum), "") 480 endif 481 482 if synname!="" 483 if synname == "SpecStringEntrails" 484 let b:InPHPcode = -1 " thumb down 485 let b:InPHPcode_tofind = "" 486 elseif synname != "phpHereDoc" && synname != "phpHereDocDelimiter" 487 let b:InPHPcode = 1 488 let b:InPHPcode_tofind = "" 489 490 if synname =~# '^php\%(Doc\)\?Comment' 491 let b:UserIsTypingComment = 1 492 let b:InPHPcode_checked = 0 493 endif 494 495 if synname =~? '^javaScript' 496 let b:InPHPcode_and_script = 1 497 endif 498 499 else 500 let b:InPHPcode = 0 501 502 let lnum = v:lnum - 1 503 while getline(lnum) !~? '<<<\s*[''"]\=\a\w*[''"]\=$' && lnum > 1 504 let lnum = lnum - 1 505 endwhile 506 507 let b:InPHPcode_tofind = substitute( getline(lnum), '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '') 508 endif 509 else 510 let b:InPHPcode = 0 511 let b:InPHPcode_tofind = s:PHP_startindenttag 512 endif 513 endif "!b:InPHPcode_checked }}} 514 515 516 " Test if we are indenting PHP code {{{ 517 let lnum = prevnonblank(v:lnum - 1) 518 let last_line = getline(lnum) 519 let endline= s:endline 520 521 if b:InPHPcode_tofind!="" 522 if cline =~? b:InPHPcode_tofind 523 let b:InPHPcode_tofind = "" 524 let b:UserIsTypingComment = 0 525 526 if b:InPHPcode == -1 527 let b:InPHPcode = 1 528 return -1 529 end 530 531 let b:InPHPcode = 1 532 533 if cline =~ '\*/' 534 call cursor(v:lnum, 1) 535 if cline !~ '^\*/' 536 call search('\*/', 'W') 537 endif 538 let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()') 539 540 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting 541 542 let b:PHP_LastIndentedWasComment = 0 543 544 if cline =~ '^\s*\*/' 545 return indent(lnum) + 1 546 else 547 return indent(lnum) 548 endif 549 550 elseif cline =~? '<script\>' 551 let b:InPHPcode_and_script = 1 552 let b:GetLastRealCodeLNum_ADD = v:lnum 553 endif 554 endif 555 endif 556 557 if 1 == b:InPHPcode 558 559 if !b:InPHPcode_and_script && last_line =~ '\%(<?.*\)\@<!?>\%(.*<?\)\@!' && IslinePHP(lnum, '?>')=~"Delimiter" 560 if cline !~? s:PHP_startindenttag 561 let b:InPHPcode = 0 562 let b:InPHPcode_tofind = s:PHP_startindenttag 563 elseif cline =~? '<script\>' 564 let b:InPHPcode_and_script = 1 565 endif 566 567 elseif last_line =~ '^[^''"`]\+[''"`]$' " a string identifier with nothing after it and no other string identifier before 568 let b:InPHPcode = -1 569 let b:InPHPcode_tofind = substitute( last_line, '^.*\([''"`]\).*$', '^[^\1]*\1[;,]$', '') 570 elseif last_line =~? '<<<\s*[''"]\=\a\w*[''"]\=$' 571 let b:InPHPcode = 0 572 let b:InPHPcode_tofind = substitute( last_line, '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '') 573 574 elseif !UserIsEditing && cline =~ '^\s*/\*\%(.*\*/\)\@!' && getline(v:lnum + 1) !~ '^\s*\*' 575 let b:InPHPcode = 0 576 let b:InPHPcode_tofind = '\*/' 577 578 elseif cline =~? '^\s*</script>' 579 let b:InPHPcode = 0 580 let b:InPHPcode_tofind = s:PHP_startindenttag 581 endif 582 endif " }}} 583 584 585 if 1 > b:InPHPcode && !b:InPHPcode_and_script 586 return -1 587 endif 588 589 " Indent successive // or # comment the same way the first is {{{ 590 let addSpecial = 0 591 if cline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)' 592 let addSpecial = b:PHP_outdentSLComments 593 if b:PHP_LastIndentedWasComment == 1 594 return indent(real_PHP_lastindented) 595 endif 596 let b:PHP_LastIndentedWasComment = 1 597 else 598 let b:PHP_LastIndentedWasComment = 0 599 endif " }}} 600 601 " Indent multiline /* comments correctly {{{ 602 603 if b:PHP_InsideMultilineComment || b:UserIsTypingComment 604 if cline =~ '^\s*\*\%(\/\)\@!' 605 if last_line =~ '^\s*/\*' 606 return indent(lnum) + 1 607 else 608 return indent(lnum) 609 endif 610 else 611 let b:PHP_InsideMultilineComment = 0 612 endif 613 endif 614 615 if !b:PHP_InsideMultilineComment && cline =~ '^\s*/\*\%(.*\*/\)\@!' 616 if getline(v:lnum + 1) !~ '^\s*\*' 617 return -1 618 endif 619 let b:PHP_InsideMultilineComment = 1 620 endif " }}} 621 622 623 " Things always indented at col 1 (PHP delimiter: <?, ?>, Heredoc end) {{{ 624 if cline =~# '^\s*<?' && cline !~ '?>' && b:PHP_outdentphpescape 625 return 0 626 endif 627 628 if cline =~ '^\s*?>' && cline !~# '<?' && b:PHP_outdentphpescape 629 return 0 630 endif 631 632 if cline =~? '^\s*\a\w*;$\|^\a\w*$\|^\s*[''"`][;,]' && cline !~? s:notPhpHereDoc 633 return 0 634 endif " }}} 635 636 let s:level = 0 637 638 let lnum = GetLastRealCodeLNum(v:lnum - 1) 639 640 let last_line = getline(lnum) 641 let ind = indent(lnum) 642 643 if ind==0 && b:PHP_default_indenting 644 let ind = b:PHP_default_indenting 645 endif 646 647 if lnum == 0 648 return b:PHP_default_indenting + addSpecial 649 endif 650 651 652 if cline =~ '^\s*}\%(}}\)\@!' 653 let ind = indent(FindOpenBracket(v:lnum, 1)) 654 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting 655 return ind 656 endif 657 658 if cline =~ '^\s*\*/' 659 call cursor(v:lnum, 1) 660 if cline !~ '^\*/' 661 call search('\*/', 'W') 662 endif 663 let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()') 664 665 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting 666 667 if cline =~ '^\s*\*/' 668 return indent(lnum) + 1 669 else 670 return indent(lnum) 671 endif 672 endif 673 674 675 if last_line =~ '[;}]'.endline && last_line !~ '^[)\]]' && last_line !~# s:defaultORcase 676 if ind==b:PHP_default_indenting 677 return b:PHP_default_indenting + addSpecial 678 elseif b:PHP_indentinghuge && ind==b:PHP_CurrentIndentLevel && cline !~# '^\s*\%(else\|\%(case\|default\).*:\|[})];\=\)' && last_line !~# '^\s*\%(\%(}\s*\)\=else\)' && getline(GetLastRealCodeLNum(lnum - 1))=~';'.endline 679 return b:PHP_CurrentIndentLevel + addSpecial 680 endif 681 endif 682 683 let LastLineClosed = 0 684 685 let terminated = s:terminated 686 687 let unstated = s:unstated 688 689 690 if ind != b:PHP_default_indenting && cline =~# '^\s*else\%(if\)\=\>' 691 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting 692 return indent(FindTheIfOfAnElse(v:lnum, 1)) 693 elseif cline =~# s:defaultORcase 694 return FindTheSwitchIndent(v:lnum) + shiftwidth() * b:PHP_vintage_case_default_indent 695 elseif cline =~ '^\s*)\=\s*{' 696 let previous_line = last_line 697 let last_line_num = lnum 698 699 while last_line_num > 1 700 701 if previous_line =~ terminated || previous_line =~ s:structureHead 702 703 let ind = indent(last_line_num) 704 705 if b:PHP_BracesAtCodeLevel 706 let ind = ind + shiftwidth() 707 endif 708 709 return ind 710 endif 711 712 let last_line_num = GetLastRealCodeLNum(last_line_num - 1) 713 let previous_line = getline(last_line_num) 714 endwhile 715 716 elseif last_line =~# unstated && cline !~ '^\s*);\='.endline 717 let ind = ind + shiftwidth() " we indent one level further when the preceding line is not stated 718 return ind + addSpecial 719 720 elseif (ind != b:PHP_default_indenting || last_line =~ '^[)\]]' ) && last_line =~ terminated 721 let previous_line = last_line 722 let last_line_num = lnum 723 let LastLineClosed = 1 724 725 let isSingleLineBlock = 0 726 while 1 727 if ! isSingleLineBlock && previous_line =~ '^\s*}\|;\s*}'.endline " XXX 728 729 call cursor(last_line_num, 1) 730 if previous_line !~ '^}' 731 call search('}\|;\s*}'.endline, 'W') 732 end 733 let oldLastLine = last_line_num 734 let last_line_num = searchpair('{', '', '}', 'bW', 'Skippmatch()') 735 736 if getline(last_line_num) =~ '^\s*{' 737 let last_line_num = GetLastRealCodeLNum(last_line_num - 1) 738 elseif oldLastLine == last_line_num 739 let isSingleLineBlock = 1 740 continue 741 endif 742 743 let previous_line = getline(last_line_num) 744 745 continue 746 else 747 let isSingleLineBlock = 0 748 749 if getline(last_line_num) =~# '^\s*else\%(if\)\=\>' 750 let last_line_num = FindTheIfOfAnElse(last_line_num, 0) 751 continue 752 endif 753 754 755 let last_match = last_line_num 756 757 let one_ahead_indent = indent(last_line_num) 758 let last_line_num = GetLastRealCodeLNum(last_line_num - 1) 759 let two_ahead_indent = indent(last_line_num) 760 let after_previous_line = previous_line 761 let previous_line = getline(last_line_num) 762 763 764 if previous_line =~# s:defaultORcase.'\|{'.endline 765 break 766 endif 767 768 if after_previous_line=~# '^\s*'.s:blockstart.'.*)'.endline && previous_line =~# '[;}]'.endline 769 break 770 endif 771 772 if one_ahead_indent == two_ahead_indent || last_line_num < 1 773 if previous_line =~# '\%(;\|^\s*}\)'.endline || last_line_num < 1 774 break 775 endif 776 endif 777 endif 778 endwhile 779 780 if indent(last_match) != ind 781 let ind = indent(last_match) 782 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting 783 784 return ind + addSpecial 785 endif 786 endif 787 788 if (last_line !~ '^\s*}\%(}}\)\@!') 789 let plinnum = GetLastRealCodeLNum(lnum - 1) 790 else 791 let plinnum = GetLastRealCodeLNum(FindOpenBracket(lnum, 1) - 1) 792 endif 793 794 let AntepenultimateLine = getline(plinnum) 795 796 let last_line = substitute(last_line,"\\(//\\|#\\)\\(\\(\\([^\"']*\\([\"']\\)[^\"']*\\5\\)\\+[^\"']*$\\)\\|\\([^\"']*$\\)\\)",'','') 797 798 799 if ind == b:PHP_default_indenting 800 if last_line =~ terminated && last_line !~# s:defaultORcase 801 let LastLineClosed = 1 802 endif 803 endif 804 805 if !LastLineClosed 806 807 808 if last_line =~# '[{(\[]'.endline || last_line =~? '\h\w*\s*(.*,$' && AntepenultimateLine !~ '[,(\[]'.endline && BalanceDirection(last_line) > 0 809 810 let dontIndent = 0 811 if last_line =~ '\S\+\s*{'.endline && last_line !~ '^\s*[)\]]\+\s*{'.endline && last_line !~ s:structureHead 812 let dontIndent = 1 813 endif 814 815 if !dontIndent && (!b:PHP_BracesAtCodeLevel || last_line !~# '^\s*{') 816 let ind = ind + shiftwidth() 817 endif 818 819 if b:PHP_BracesAtCodeLevel || b:PHP_vintage_case_default_indent == 1 820 let b:PHP_CurrentIndentLevel = ind 821 822 return ind + addSpecial 823 endif 824 825 elseif last_line =~ '\S\+\s*),'.endline && BalanceDirection(last_line) < 0 826 call cursor(lnum, 1) 827 call search('),'.endline, 'W') " line never begins with ) so no need for 'c' flag 828 let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()') 829 if openedparent != lnum 830 let ind = indent(openedparent) 831 endif 832 833 elseif last_line =~ '^\s*'.s:blockstart 834 let ind = ind + shiftwidth() 835 836 837 elseif AntepenultimateLine =~ '{'.endline && AntepenultimateLine !~? '^\s*use\>' || AntepenultimateLine =~ terminated || AntepenultimateLine =~# s:defaultORcase 838 let ind = ind + shiftwidth() 839 endif 840 841 endif 842 843 if cline =~ '^\s*[)\]];\=' 844 let ind = ind - shiftwidth() 845 endif 846 847 let b:PHP_CurrentIndentLevel = ind 848 return ind + addSpecial 849endfunction 850