]> git.pld-linux.org Git - packages/vim.git/blame - php.vim
- up to 1.12
[packages/vim.git] / php.vim
CommitLineData
8fffc476
AM
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
1d607244
AM
5" Last Change: 2005 May 31th
6" Version: 1.12
7"
8" Changes: 1.12 - The bug involving searchpair() and utf-8 encoding in Vim 6.3 will
9" not make this script to hang but you'll have to be
10" careful to not write '/* */' comments with other '/*'
11" inside the comments else the indentation won't be correct.
12" NOTE: This is true only if you are using utf-8 and vim 6.3.
13"
14" Changes: 1.11 - If the "case" of a "switch" wasn't alone on its line
15" and if the "switch" was at col 0 (or at default indenting)
16" the lines following the "case" were not indented.
0ae4014d
AM
17"
18" Changes: 1.10 - Lines beginning by a single or double quote were
19" not indented in some cases.
20"
21" Changes: 1.09 - JavaScript code was not always directly indented.
a4c85cb5
AM
22"
23" Changes: 1.08 - End comment tags '*/' are indented like start tags '/*'.
24" - When typing a multiline comment, '}' are indented
25" according to other commented '{'.
26" - Added a new option 'PHP_removeCRwhenUnix' to
27" automatically remove CR at end of lines when the file
28" format is Unix.
29" - Changed the file format of this very file to Unix.
30" - This version seems to correct several issues some people
31" had with 1.07.
8fffc476
AM
32"
33" Changes: 1.07 - Added support for "Here document" tags:
34" - HereDoc end tags are indented properly.
35" - HereDoc content remains unchanged.
36" - All the code that is outside PHP delimiters remains
37" unchanged.
38" - New feature: The content of <script.*> html tags is considered as PHP
39" and indented according to the surrounding PHP code.
40" - "else if" are detected as "elseif".
41" - Multiline /**/ are indented when the user types it but
42" remain unchanged when indenting from their beginning.
43" - Fixed indenting of // and # comments.
44" - php_sync_method option is set to 0 (fromstart).
45" This is required for complex PHP scripts else the indent
46" may fail.
47" - Files with non PHP code at the beginning could alter the indent
48" of the following PHP code.
49" - Other minor improvements and corrections.
50"
8fffc476
AM
51" Changes: 1.06: - Switch block were no longer indented correctly...
52" - Added an option to use a default indenting instead of 0.
53" (whereas I still can't find any good reason to use it!)
54" - A problem with ^\s*);\= lines where ending a non '{}'
55" structure.
56" - Changed script local variable to be buffer local
57" variable instead.
58"
59" Changes: 1.05: - Lines containing "<?php ?>" and "?> <?php"
60" (start and end tag on the same line) are no
61" longer indented at col 1 but as normal code.
62"
8fffc476
AM
63" Changes: 1.04: - Strings containing "//" could break the indenting
64" algorithm.
65" - When a '{}' block was at col 1, the second line of the
66" block was not indented at all (because of a stupid
67" optimization coupled with a bug).
68"
69" Changes: 1.03: - Some indenting problems corrected: end of non '{}'
70" structures was not detected in some cases. The part of
71" code concerned have been re-written
72" - PHP start tags were not indented at col 1
73" - Wrong comment in the code have been corrected
74"
75" Changes: 1.02: - The bug I was talking about in version 1.01 (right below) has
76" been corrected :)
77" - Also corrected another bug that could occur in
78" some special cases.
79" - I removed the debug mode left in 1.01 that could
80" cause some Vim messages at loading if other script were
81" bugged.
82"
83" Changes: 1.01: - Some little bug corrections reguarding automatic optimized
84" mode that missed some tests and could break the indenting.
8fffc476
AM
85" - There is also a problem with complex non bracked structures, when several
86" else are following each other, the algorithm do not indent the way it
87" should.
88" That will be corrected in the next version.
89"
8fffc476
AM
90" If you find a bug, please e-mail me at John.wellesz (AT) teaser (DOT) fr
91" with an example of code that break the algorithm.
92"
93"
94" Thanks a lot for using this script.
95"
96
97" NOTE: This script must be used with PHP syntax ON and with the php syntax
a4c85cb5 98" script by Lutz Eymers (http://www.isp.de/data/php.vim ) that's the script bundled with Gvim.
8fffc476
AM
99"
100" This script set the option php_sync_method of PHP syntax script to 0
101" (fromstart indenting method) in order to have an accurate syntax.
a4c85cb5
AM
102" If you are using very big PHP files (which is a bad idea) you will
103" experience slowings down while editing, if your code contains only PHP
104" code you can comment the line below.
105
106let php_sync_method = 0
107
8fffc476
AM
108"
109" In the case you have syntax errors in your script such as end of HereDoc
110" tags not at col 1 you'll have to indent your file 2 times (This script
111" will automatically put HereDoc end tags at col 1).
112"
113
a4c85cb5
AM
114" NOTE: If you are editing file in Unix file format and that (by accident)
115" there are '\r' before new lines, this script won't be able to proceed
116" correctly and will make many mistakes because it won't be able to match
117" '\s*$' correctly.
118" So you have to remove those useless characters first with a command like:
119"
120" :%s /\r$//g
121"
122" or simply 'let' the option PHP_removeCRwhenUnix to 1 and the script will
123" silently remove them when VIM load this script (at each bufread).
8fffc476 124
a4c85cb5
AM
125" Options: PHP_default_indenting = # of sw (default is 0), # of sw will be
126" added to the indent of each line of PHP code.
127"
128" Options: PHP_removeCRwhenUnix = 1 to make the script automatically remove CR
129" at end of lines (by default this option is unset), NOTE that you
130" MUST remove CR when the fileformat is UNIX else the indentation
131" won't be correct...
132
1d607244
AM
133setlocal nosmartindent
134setlocal nolisp
135
136"This will prevent a bug involving searchpair(), its 'r' flag, utf-8 and vim 6.3
137"from occurring but will forbid you to write other '/*' inside a '/* */' comment.
138if version <= 603 && &encoding == 'utf-8'
139 let s:searchpairflags = 'bW'
140else
141 let s:searchpairflags = 'bWr'
142endif
143
144
a4c85cb5
AM
145if &fileformat == "unix" && exists("PHP_removeCRwhenUnix") && PHP_removeCRwhenUnix
146 let myul=&ul
147 silent! %s/\r$//g
148endif
8fffc476
AM
149
150if exists("PHP_default_indenting")
151 let b:PHP_default_indenting = PHP_default_indenting * &sw
152else
153 let b:PHP_default_indenting = 0
154endif
155" Only load this indent file when no other was loaded. But reset those state
a4c85cb5 156" variables
8fffc476
AM
157
158let b:PHP_lastindented = 0
159let b:PHP_indentbeforelast = 0
160let b:PHP_indentinghuge = 0
161let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
162let b:PHP_LastIndentedWasComment = 0
163" PHP code detect variables
164let b:InPHPcode = 0
165let b:InPHPcode_checked = 0
166let b:InPHPcode_and_script = 0
167let b:InPHPcode_tofind = ""
168let b:PHP_oldchangetick = b:changedtick
a4c85cb5 169let b:UserIsTypingComment = 0
8fffc476
AM
170
171if exists("b:did_indent")
172 finish
173endif
174
175let b:did_indent = 1
8fffc476 176
1d607244 177setlocal nosmartindent
8fffc476 178setlocal nolisp
1d607244
AM
179setlocal nocindent
180setlocal autoindent
181
8fffc476 182setlocal indentexpr=GetPhpIndent()
a4c85cb5 183setlocal indentkeys=0{,0},0),:,!^F,o,O,e,*<Return>,=?>,=<?,=*/
8fffc476
AM
184
185" Only define the function once.
186if exists("*GetPhpIndent")
1d607244 187 finish " XXX
8fffc476
AM
188endif
189
190let s:endline= '\s*\%(//.*\|#.*\|/\*.*\*/\s*\)\=$'
191let s:PHP_startindenttag = '<?\%(.*?>\)\@!\|<script[^>]*>\%(.*<\/script>\)\@!'
1d607244 192"setlocal debug=msg " XXX
8fffc476
AM
193
194
195function! GetLastRealCodeLNum(startline) " {{{
196 "Inspired from the function SkipJavaBlanksAndComments by Toby Allsopp for indent/java.vim
197 let lnum = a:startline
198 let old_lnum = lnum
199
200 while lnum > 1
201 let lnum = prevnonblank(lnum)
202 let lastline = getline(lnum)
203
204 " if we are inside an html <script> we must skip ?> tags to indent
205 " everything as php
206 if b:InPHPcode_and_script && lastline =~ '?>\s*$'
207 let lnum = lnum - 1
208
209
210 elseif lastline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)' " if line is under comment
211 let lnum = lnum - 1
212 elseif lastline =~ '\*/\s*$' " skip multiline comments
213 call cursor(lnum, 1)
1d607244
AM
214 call search('\*/\zs', 'W') " positition the cursor after the first */
215 let lnum = searchpair('/\*', '', '\*/\zs', s:searchpairflags, '') " find the most outside /*
216 "echo 'lnum skipnonphp= ' . lnum
217 "call getchar()
8fffc476
AM
218
219 let lastline = getline(lnum)
220 if lastline =~ '^\s*/\*' " if line contains nothing but comment
221 let lnum = lnum - 1 " do the job again on the line before (a comment can hide another...)
222 else
223 break
224 endif
225
226
227 elseif lastline =~? '\%(//\s*\|?>.*\)\@<!<?\%(php\)\=\s*$\|^\s*<script\>' " skip non php code
228 " call cursor(lnum, 1)
1d607244
AM
229 " call search('<?', 'W')
230 " let lnum = searchpair('?>', '', '<?\zs', 'bW', 'getline(".") =~ "<?.*?>"')
8fffc476
AM
231
232 " let lastline = getline(lnum)
233 while lastline !~ '\(<?.*\)\@<!?>' && lnum > 1
234 let lnum = lnum - 1
235 let lastline = getline(lnum)
236 endwhile
237 if lastline =~ '^\s*?>' " if line contains nothing but end tag
238 let lnum = lnum - 1
239 else
240 break " else there is something important before the ?>
241 endif
242
243
244 " Manage "here document" tags
245 elseif lastline =~? '^\a\w*;$' && lastline !~? s:notPhpHereDoc " match the end of a heredoc
246 let tofind=substitute( lastline, '\([^;]\+\);', '<<<\1$', '')
247 while getline(lnum) !~? tofind && lnum > 1
248 let lnum = lnum - 1
249 endwhile
250 else
251 break " if none of these were true then we are done
252 endif
253 endwhile
254
255 if lnum==1 && getline(lnum)!~ '<?'
256 let lnum=0
257 endif
258 return lnum
259endfunction
260" }}}
261
262function! Skippmatch() " {{{
263 " the slowest instruction of this script, remove it and the script is 3
264 " times faster but you may have troubles with '{' inside comments or strings
265 " that will break the indent algorithm...
266 let synname = synIDattr(synID(line("."), col("."), 0), "name")
a4c85cb5 267 if synname == "phpParent" || synname == "javaScriptBraces" || synname == "phpComment" && b:UserIsTypingComment
8fffc476 268 return 0
8fffc476
AM
269 else
270 return 1
8fffc476
AM
271 endif
272endfun
273" }}}
274
275function! FindOpenBracket(lnum) " {{{
276 call cursor(a:lnum, 1) " set the cursor to the start of the lnum line
277 return searchpair('{', '', '}', 'bW', 'Skippmatch()')
278endfun
279" }}}
280
281function! FindTheIfOfAnElse (lnum, StopAfterFirstPrevElse) " {{{
282" A very clever recoursive function created by me (John Wellesz) that find the "if" corresponding to an
283" "else". This function can easily be adapted for other languages :)
284
285 if getline(a:lnum) =~# '^\s*}\s*else\%(if\)\=\>'
286 let beforeelse = a:lnum " we do this so we can find the opened bracket to speed up the process
287 else
288 let beforeelse = GetLastRealCodeLNum(a:lnum - 1)
289 endif
290
291 if !s:level
292 let s:iftoskip = 0
293 endif
294
295 " If we found another "else" then it means we need to skip the next "if"
296 " we'll found. (since version 1.02)
297 if getline(beforeelse) =~# '^\s*\%(}\s*\)\=else\%(\s*if\)\@!\>'
298 let s:iftoskip = s:iftoskip + 1
299 endif
300
301 " A closing bracket? let skip the whole block to save some recursive calls
302 if getline(beforeelse) =~ '^\s*}' " .s:endline
303 let beforeelse = FindOpenBracket(beforeelse)
304
305 " Put us on the block starter
306 if getline(beforeelse) =~ '^\s*{'
307 let beforeelse = GetLastRealCodeLNum(beforeelse - 1)
308 endif
309 endif
310
311
312 if !s:iftoskip && a:StopAfterFirstPrevElse && getline(beforeelse) =~# '^\s*\%([}]\s*\)\=else\%(if\)\=\>'
313 return beforeelse
314 endif
a4c85cb5 315
8fffc476
AM
316 " if there was an else, then there is a if...
317 if getline(beforeelse) !~# '^\s*if\>' && beforeelse>1 || s:iftoskip && beforeelse>1
318
319 if s:iftoskip && getline(beforeelse) =~# '^\s*if\>'
320 let s:iftoskip = s:iftoskip - 1
321 endif
322
323 let s:level = s:level + 1
324 let beforeelse = FindTheIfOfAnElse(beforeelse, a:StopAfterFirstPrevElse)
325 endif
326
327 return beforeelse
328
329endfunction
330" }}}
331
332function! IslinePHP (lnum, tofind) " {{{
333 " This function asks to the syntax if the pattern 'tofind' on the line
334 " number 'lnum' is PHP code (very slow...).
335 let cline = getline(a:lnum)
336
337 if a:tofind==""
0ae4014d
AM
338 let tofind = "^\\s*[\"']*\s*\\zs\\S" " This correct the issue where lines beginning by a
339 " single or double quote were not indented in some cases.
8fffc476
AM
340 else
341 let tofind = a:tofind
342 endif
343
344 let tofind = tofind . '\c' " ignorecase
345
346 let coltotest = match (cline, tofind) + 1 "find the first non blank char in the current line
347
348 let synname = synIDattr(synID(a:lnum, coltotest, 0), "name") " ask to syntax what is its name
0ae4014d 349 "echo synname
8fffc476 350
0ae4014d
AM
351 " if matchstr(synname, '^...') == "php" || synname=="Delimiter" || synname =~? '^javaScript'
352 if synname =~ '^php' || synname=="Delimiter" || synname =~? '^javaScript'
8fffc476
AM
353 return synname
354 else
355 return ""
356 endif
357endfunction
358" }}}
359
360let s:notPhpHereDoc = '\%(break\|return\|continue\|exit\);'
361let s:blockstart = '\%(\%(\%(}\s*\)\=else\%(\s\+\)\=\)\=if\>\|while\>\|for\%(each\)\=\>\|declare\|||\|&&\>\)'
362
363function! GetPhpIndent()
364 "##############################################
365 "########### MAIN INDENT FUNCTION #############
366 "##############################################
367
368 " This detect if the user is currently typing text between each call
369 let UserIsEditing=0
370 if b:PHP_oldchangetick != b:changedtick
371 let b:PHP_oldchangetick = b:changedtick
372 let UserIsEditing=1
373 endif
374
8fffc476
AM
375 if b:PHP_default_indenting
376 let b:PHP_default_indenting = g:PHP_default_indenting * &sw
377 endif
378
379 let cline = getline(v:lnum) " current line
380
381 " Let's detect if we are indenting just one line or more than 3 lines
382 " in the last case we can slightly optimize our algorithm
383 if !b:PHP_indentinghuge && b:PHP_lastindented > b:PHP_indentbeforelast
384 if b:PHP_indentbeforelast
385 let b:PHP_indentinghuge = 1
386 echom 'Large indenting detected, speed optimizations engaged'
387 endif
388 let b:PHP_indentbeforelast = b:PHP_lastindented
389 endif
390
391 " If the line we are indenting isn't directly under the previous non-blank
392 " line of the file then deactivate the optimization procedures and reset
393 " status variable (we restart for scratch)
394 if b:InPHPcode_checked && prevnonblank(v:lnum - 1) != b:PHP_lastindented
395 if b:PHP_indentinghuge
396 echom 'Large indenting deactivated'
397 let b:PHP_indentinghuge = 0
398 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
399 endif
400 let b:PHP_lastindented = v:lnum
401 let b:PHP_LastIndentedWasComment=0
402 let b:PHP_indentbeforelast = 0
403
8fffc476
AM
404 let b:InPHPcode = 0
405 let b:InPHPcode_checked = 0
406 let b:InPHPcode_and_script = 0
407 let b:InPHPcode_tofind = ""
408
409 elseif v:lnum > b:PHP_lastindented " we are indenting line in > order (we can rely on the line before)
410 let real_PHP_lastindented = b:PHP_lastindented
411 let b:PHP_lastindented = v:lnum
412 endif
413
414 " We must detect if we are in PHPCODE or not, but one time only, then
415 " we will detect php end and start tags, comments /**/ and HereDoc
416 " tags
417
418 if !b:InPHPcode_checked " {{{ One time check
419 let b:InPHPcode_checked = 1
420
421 let synname = IslinePHP (prevnonblank(v:lnum), "") " the line could be blank (if the user presses 'return')
422
423 if synname!=""
424 if synname != "phpHereDoc"
425 let b:InPHPcode = 1
426 let b:InPHPcode_tofind = ""
0ae4014d 427
a4c85cb5
AM
428 if synname == "phpComment"
429 let b:UserIsTypingComment = 1
430 else
431 let b:UserIsTypingComment = 0
432 endif
0ae4014d
AM
433
434 if synname =~? '^javaScript'
435 let b:InPHPcode_and_script = 1
436 endif
437
8fffc476
AM
438 else
439 let b:InPHPcode = 0
a4c85cb5 440 let b:UserIsTypingComment = 0
8fffc476
AM
441
442 let lnum = v:lnum - 1
a4c85cb5 443 while getline(lnum) !~? '<<<\a\w*$' && lnum > 1
8fffc476
AM
444 let lnum = lnum - 1
445 endwhile
446
447 let b:InPHPcode_tofind = substitute( getline(lnum), '^.*<<<\(\a\w*\)\c', '^\\s*\1;$', '')
448 endif
0ae4014d 449 else " IslinePHP returned "" => we are not in PHP or Javascript
8fffc476 450 let b:InPHPcode = 0
a4c85cb5 451 let b:UserIsTypingComment = 0
8fffc476
AM
452 " Then we have to find a php start tag...
453 let b:InPHPcode_tofind = '<?\%(.*?>\)\@!\|<script.*>'
454 endif
455 endif "!b:InPHPcode_checked }}}
456
457 " Now we know where we are so we can verify the line right above the
458 " current one to see if we have to stop or restart php indenting
0ae4014d 459
8fffc476
AM
460 " Test if we are indenting PHP code {{{
461 " Find an executable php code line above the current line.
462 let lnum = prevnonblank(v:lnum - 1)
463 let last_line = getline(lnum)
464
465 " If we aren't in php code, then there is something we have to find
466 if b:InPHPcode_tofind!=""
467 if cline =~? b:InPHPcode_tofind
468 let b:InPHPcode = 1
469 let b:InPHPcode_tofind = ""
a4c85cb5
AM
470 let b:UserIsTypingComment = 0
471 if cline =~ '\*/' " End comment tags must be indented like start comment tags
472 call cursor(v:lnum, 1)
473 call search('\*/\zs', 'W')
1d607244 474 let lnum = searchpair('/\*', '', '\*/\zs', s:searchpairflags, '') " find the most outside /*
a4c85cb5 475 return indent(lnum)
8fffc476
AM
476 elseif cline =~? '<script\>' " a more accurate test is useless since there isn't any other possibility
477 let b:InPHPcode_and_script = 1
478 endif
479 endif
480 endif
481
482 " ### If we are in PHP code, we test the line before to see if we have to stop indenting
483
484 if b:InPHPcode
485
486 " Was last line containing a PHP end tag ?
487 if !b:InPHPcode_and_script && last_line =~ '\%(<?.*\)\@<!?>\%(.*<?\)\@!' && IslinePHP(lnum, '?>')=="Delimiter"
488 if cline !~? s:PHP_startindenttag
489 let b:InPHPcode = 0
490 let b:InPHPcode_tofind = s:PHP_startindenttag
491 elseif cline =~? '<script\>'
492 let b:InPHPcode_and_script = 1
493 endif
494
495 " Was last line the start of a HereDoc ?
496 elseif last_line =~? '<<<\a\w*$'
0ae4014d 497 " \&& IslinePHP(lnum, '\a\w*$')=="Delimiter"
8fffc476
AM
498 let b:InPHPcode = 0
499 let b:InPHPcode_tofind = substitute( last_line, '^.*<<<\(\a\w*\)\c', '^\\s*\1;$', '')
500
501 " Skip /* \n+ */ comments execept when the user is currently
502 " writting them
503 elseif !UserIsEditing && cline =~ '^\s*/\*\%(.*\*/\)\@!'
0ae4014d 504 " \ && IslinePHP(v:lnum, '/\*')=="phpComment"
8fffc476
AM
505 let b:InPHPcode = 0
506 let b:InPHPcode_tofind = '\*/'
507
508 " is current line the end of a HTML script ? (we indent script the
509 " same as php code)
510 elseif cline =~? '^\s*</script>'
511 let b:InPHPcode = 0
512 " let b:InPHPcode_and_script = 0
513 let b:InPHPcode_tofind = s:PHP_startindenttag
514 endif
515 endif " }}}
516
517 " Non PHP code is let as it is
518 if !b:InPHPcode && !b:InPHPcode_and_script
519 return -1
520 elseif !b:InPHPcode
521 let b:InPHPcode_and_script = 0
522 endif
523
524 " Align correctly multi // or # lines
525
526 " Indent successive // or # comment the same way the first is {{{
527 if cline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)'
528 if b:PHP_LastIndentedWasComment == 1
529 return indent(real_PHP_lastindented) " line replaced in 1.02
530 endif
531 let b:PHP_LastIndentedWasComment = 1
532 else
533 let b:PHP_LastIndentedWasComment = 0
534 endif
535 " }}}
536
537 " Some tags are always indented to col 1
538
539 " Things always indented at col 1 (PHP delimiter: <?, ?>, Heredoc end) {{{
540 " PHP start tags are always at col 1, useless to indent unless the end tag
541 " is on the same line
542 if cline =~# '^\s*<?' && cline !~ '?>' " Added the ^\s* part in version 1.03
543 return 0
544 endif
545
546 " PHP end tags are always at col 1, useless to indent unless if it's
547 " followed by a start tag on the same line
548 if cline =~ '^\s*?>' && cline !~# '<?'
549 return 0
550 endif
551
552 " put HereDoc end tags at start of lines
553 if cline =~? '^\s*\a\w*;$' && cline !~? s:notPhpHereDoc
554 return 0
555 endif
556 " }}}
557
558 let s:level = 0
559
560 " Find an executable php code line above the current line.
561 let lnum = GetLastRealCodeLNum(v:lnum - 1)
562 let last_line = getline(lnum) " last line
563 let ind = indent(lnum) " by default
564 let endline= s:endline
565
566 if ind==0 && b:PHP_default_indenting
567 let ind = b:PHP_default_indenting
568 endif
569
570 " Hit the start of the file, use default indent.
571 if lnum == 0
572 return b:PHP_default_indenting
573 endif
574
575 " if the last line is a stated line and it's not indented then why should
576 " we indent this one??
577 " if optimized mode is active and nor current or previous line are an 'else'
578 " or the end of a possible bracketless thing then indent the same as the previous
579 " line
1d607244 580 if last_line =~ '[;}]'.endline && last_line !~# '^\s*\%(default\|case\).*:'
8fffc476
AM
581 if ind==b:PHP_default_indenting
582 return b:PHP_default_indenting
583 elseif b:PHP_indentinghuge && ind==b:PHP_CurrentIndentLevel && cline !~# '^\s*\%(else\|\%(case\|default\).*:\|[})];\=\)' && last_line !~# '^\s*\%(\%(}\s*\)\=else\)' && getline(GetLastRealCodeLNum(lnum - 1))=~';'.endline
584 return b:PHP_CurrentIndentLevel
585 endif
586 endif
587
588 " Search the matching open bracket (with searchpair()) and set the indent of cline
589 " to the indent of the matching line.
590 if cline =~ '^\s*}\%(}}\)\@!'
591 let ind = indent(FindOpenBracket(v:lnum))
592 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
593 return ind
594 endif
595
a4c85cb5
AM
596 " While editing check for end of comment and indent it like its beginning
597 if UserIsEditing && cline =~ '\*/' " End comment tags must be indented like start comment tags
598 call cursor(v:lnum, 1)
599 call search('\*/\zs', 'W')
1d607244 600 let lnum = searchpair('/\*', '', '\*/\zs', s:searchpairflags, '') " find the most outside /*
a4c85cb5
AM
601 return indent(lnum)
602 endif
0ae4014d 603
8fffc476
AM
604 let LastLineClosed = 0 " used to prevent redundant tests in the last part of the script
605
606 let unstated='\%(^\s*'.s:blockstart.'.*)\|\%(//.*\)\@<!\<e'.'lse\>\)'.endline
607 " What is an unstated line?
608 " - an "else" at the end of line
609 " - a s:blockstart (if while etc...) followed by anything and a ")" at
610 " the end of line
611
612 " if the current line is an 'else' starting line
613 " (to match an 'else' preceded by a '}' is irrelevant and futile - see
614 " code above)
615 if ind != b:PHP_default_indenting && cline =~# '^\s*else\%(if\)\=\>'
616 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting " prevent optimized to work at next call
617 return indent(FindTheIfOfAnElse(v:lnum, 1))
618 elseif last_line =~# unstated && cline !~ '^\s*{\|^\s*);\='.endline
619 let ind = ind + &sw
620 return ind
621
622 " If the last line is terminated by ';' or if it's a closing '}'
623 " We need to check if this isn't the end of a multilevel non '{}'
624 " structure such as:
625 " Exemple:
626 " if ($truc)
627 " echo 'truc';
628 "
629 " OR
630 "
631 " if ($truc)
632 " while ($truc) {
633 " lkhlkh();
634 " echo 'infinite loop\n';
635 " }
636 elseif ind != b:PHP_default_indenting && last_line =~ ';'.endline.'\|^\s*}\%(.*{'. endline.'\)\@!'
637 " If we are here it means that the previous line is:
638 " - a *;$ line
639 " - a [beginning-blanck] } followed by anything but a { $
640 let previous_line = last_line
641 let last_line_num = lnum
642 let LastLineClosed = 1
643 " The idea here is to check if the current line is after a non '{}'
644 " structure so we can indent it like the top of that structure.
645 " The top of that structure is caracterized by a if (ff)$ style line
646 " preceded by a stated line. If there is no such structure then we
647 " just have to find two 'normal' lines following each other with the
648 " same indentation and with the first of these two lines terminated by
649 " a ; or by a }...
650
651 while 1
652 " let's skip '{}' blocks
653 if previous_line =~ '^\s*}'
654 " find the openning '{'
655 let last_line_num = FindOpenBracket(last_line_num)
656
657 " if the '{' is alone on the line get the line before
658 if getline(last_line_num) =~ '^\s*{'
659 let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
660 endif
661
662 let previous_line = getline(last_line_num)
663
664 continue
665 else
666 " At this point we know that the previous_line isn't a closing
667 " '}' so we can check if we really are in such a structure.
668
669 " it's not a '}' but it could be an else alone...
670 if getline(last_line_num) =~# '^\s*else\%(if\)\=\>'
671 let last_line_num = FindTheIfOfAnElse(last_line_num, 0)
672 continue " re-run the loop (we could find a '}' again)
673 endif
674
675 " So now it's ok we can check :-)
676 " A good quality is to have confidence in oneself so to know
677 " if yes or no we are in that struct lets test the indent of
678 " last_line_num and of last_line_num - 1!
679 " If those are == then we are almost done.
680 "
681 " That isn't sufficient, we need to test how the first of the
682 " 2 lines is ended...
683
684 " Note the indenting of the line we are checking
685
686 let last_match = last_line_num " remember the 'topest' line we found so far
687
688 let one_ahead_indent = indent(last_line_num)
689 let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
690 let two_ahead_indent = indent(last_line_num)
691 let after_previous_line = previous_line
692 let previous_line = getline(last_line_num)
693
694
695 " If we find a '{' or a case/default then we are inside that block so lets
696 " indent properly... Like the line following that block starter
697 if previous_line =~# '^\s*\%(case\|default\).*:\|{'.endline
698 break
699 endif
700
701 " The 3 lines below are not necessary for the script to work
702 " but it makes it work a little more faster in some (rare) cases.
703 " We verify if we are at the top of a non '{}' struct.
704 if after_previous_line=~# '^\s*'.s:blockstart.'.*)'.endline && previous_line =~# '[;}]'.endline
705 break
706 endif
707
708 if one_ahead_indent == two_ahead_indent || last_line_num < 1
709 " So the previous line and the line before are at the same
710 " col. Now we just have to check if the line before is a ;$ or [}]$ ended line
711 " we always check the most ahead line of the 2 lines so
712 " it's useless to match ')$' since the lines couldn't have
713 " the same indent...
714 if previous_line =~# '[;}]'.endline || last_line_num < 1
715 break
716 endif
717 endif
718 endif
719 endwhile
720
721 if indent(last_match) != ind " if nothing was done lets the old script continue
722 let ind = indent(last_match) " let's use the indent of the last line matched by the alhorithm above
723 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting "line added in version 1.02 to prevent optimized mode
724 " from acting in some special cases
725 return ind
726 endif
727 endif
728
729
730 let plinnum = GetLastRealCodeLNum(lnum - 1)
731 let pline = getline(plinnum) " previous to last line
732
733 " REMOVE comments at end of line before treatment
1d607244 734 " the first part of the regex removes // from the end of line when they are
8fffc476
AM
735 " followed by a number of '"' which is a multiple of 2. The second part
736 " removes // that are not followed by any '"'
737 " Sorry for this unreadable thing...
738 let last_line = substitute(last_line,"\\(//\\|#\\)\\(\\(\\([^\"']*\\([\"']\\)[^\"']*\\5\\)\\+[^\"']*$\\)\\|\\([^\"']*$\\)\\)",'','')
739
740 " Indent blocks enclosed by {} or () (default indenting)
741 if !LastLineClosed " the last line isn't a .*; or a }$ line
742 " if the last line is a [{(]$ or a multiline function call (or array
743 " declaration) with already one parameter on the opening ( line
744 if last_line =~# '[{(]'.endline || last_line =~? '\h\w*\s*(.*,$' && pline !~ '[,(]'.endline
745 let ind = ind + &sw
746 if cline !~# '^\s*\%(default\|case\).*:' " case and default are not indented inside blocks
747 let b:PHP_CurrentIndentLevel = ind
748 return ind
749 endif
750 endif
751 endif
752
753 " If the current line closes a multiline function call or array def
754 if cline =~ '^\s*);\='
755 let ind = ind - &sw
756 elseif cline =~# '^\s*\%(default\|case\).*:'
757 let ind = ind - &sw
758 endif
759
760 if last_line =~# '^\s*\%(default\|case\).*:'
761 let ind = ind + &sw
762 endif
763
764 let b:PHP_CurrentIndentLevel = ind
765 return ind
766endfunction
767
768" vim: set ts=4 sw=4:
a4c85cb5 769" vim: set ff=unix:
This page took 0.188106 seconds and 4 git commands to generate.