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