xref: /vim-8.2.3635/runtime/indent/php.vim (revision ca63501f)
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 November 26th
7" Version:	1.57
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
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),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:PHP_validVariable = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
132let s:notPhpHereDoc = '\%(break\|return\|continue\|exit\|die\|else\)'
133let 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\>\)'
134let s:functionDecl = '\<function\>\%(\s\+'.s:PHP_validVariable.'\)\=\s*(.*'
135let s:endline= '\s*\%(//.*\|#.*\|/\*.*\*/\s*\)\=$'
136
137
138let s:terminated = '\%(\%(;\%(\s*\%(?>\|}\)\)\=\|<<<''\=\a\w*''\=$\|^\s*}\|^\s*'.s:PHP_validVariable.':\)'.s:endline.'\)\|^[^''"`]*[''"`]$'
139let s:PHP_startindenttag = '<?\%(.*?>\)\@!\|<script[^>]*>\%(.*<\/script>\)\@!'
140
141
142
143let s:escapeDebugStops = 0
144function! DebugPrintReturn(scriptLine)
145
146    if ! s:escapeDebugStops
147	echo "debug:" . a:scriptLine
148	let c = getchar()
149	if c == "\<Del>"
150	    let s:escapeDebugStops = 1
151	end
152    endif
153
154endfunction
155
156function! GetLastRealCodeLNum(startline) " {{{
157
158    let lnum = a:startline
159
160    if b:GetLastRealCodeLNum_ADD && b:GetLastRealCodeLNum_ADD == lnum + 1
161	let lnum = b:GetLastRealCodeLNum_ADD
162    endif
163
164    while lnum > 1
165	let lnum = prevnonblank(lnum)
166	let lastline = getline(lnum)
167
168	if b:InPHPcode_and_script && lastline =~ '?>\s*$'
169	    let lnum = lnum - 1
170	elseif lastline =~ '^\s*?>.*<?\%(php\)\=\s*$'
171	    let lnum = lnum - 1
172	elseif lastline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)'
173	    let lnum = lnum - 1
174	elseif lastline =~ '\*/\s*$'
175	    call cursor(lnum, 1)
176	    if lastline !~ '^\*/'
177		call search('\*/', 'W')
178	    endif
179	    let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
180
181	    let lastline = getline(lnum)
182	    if lastline =~ '^\s*/\*'
183		let lnum = lnum - 1
184	    else
185		break
186	    endif
187
188
189	elseif lastline =~? '\%(//\s*\|?>.*\)\@<!<?\%(php\)\=\s*$\|^\s*<script\>'
190
191	    while lastline !~ '\(<?.*\)\@<!?>' && lnum > 1
192		let lnum = lnum - 1
193		let lastline = getline(lnum)
194	    endwhile
195	    if lastline =~ '^\s*?>'
196		let lnum = lnum - 1
197	    else
198		break
199	    endif
200
201
202	elseif lastline =~? '^\a\w*;\=$' && lastline !~? s:notPhpHereDoc
203	    let tofind=substitute( lastline, '\(\a\w*\);\=', '<<<''\\=\1''\\=$', '')
204	    while getline(lnum) !~? tofind && lnum > 1
205		let lnum = lnum - 1
206	    endwhile
207	elseif lastline =~ '^[^''"`]*[''"`][;,]'.s:endline
208	    let tofind=substitute( lastline, '^.*\([''"`]\)[;,].*$', '^[^\1]\\+[\1]$', '')
209	    while getline(lnum) !~? tofind && lnum > 1
210		let lnum = lnum - 1
211	    endwhile
212	else
213	    break
214	endif
215    endwhile
216
217    if lnum==1 && getline(lnum) !~ '<?'
218	let lnum=0
219    endif
220
221    if b:InPHPcode_and_script && 1 > b:InPHPcode
222	let b:InPHPcode_and_script = 0
223    endif
224
225    return lnum
226endfunction " }}}
227
228function! Skippmatch2()
229
230    let line = getline(".")
231
232    if line =~ "\\([\"']\\).*/\\*.*\\1" || line =~ '\%(//\|#\).*/\*'
233	return 1
234    else
235	return 0
236    endif
237endfun
238
239function! Skippmatch()	" {{{
240    let synname = synIDattr(synID(line("."), col("."), 0), "name")
241    if synname == "Delimiter" || synname == "phpRegionDelimiter" || synname =~# "^phpParent" || synname == "phpArrayParens" || synname =~# '^php\%(Block\|Brace\)' || synname == "javaScriptBraces" || synname =~# '^php\%(Doc\)\?Comment' && b:UserIsTypingComment
242	return 0
243    else
244	return 1
245    endif
246endfun " }}}
247
248function! FindOpenBracket(lnum, blockStarter) " {{{
249    call cursor(a:lnum, 1)
250    let line = searchpair('{', '', '}', 'bW', 'Skippmatch()')
251
252    if a:blockStarter == 1
253	while line > 1
254	    let linec = getline(line)
255
256	    if linec =~ s:terminated || linec =~ '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . s:endline
257		break
258	    endif
259
260	    let line = GetLastRealCodeLNum(line - 1)
261	endwhile
262    endif
263
264    return line
265endfun " }}}
266
267function! FindTheIfOfAnElse (lnum, StopAfterFirstPrevElse) " {{{
268
269    if getline(a:lnum) =~# '^\s*}\s*else\%(if\)\=\>'
270	let beforeelse = a:lnum
271    else
272	let beforeelse = GetLastRealCodeLNum(a:lnum - 1)
273    endif
274
275    if !s:level
276	let s:iftoskip = 0
277    endif
278
279    if getline(beforeelse) =~# '^\s*\%(}\s*\)\=else\%(\s*if\)\@!\>'
280	let s:iftoskip = s:iftoskip + 1
281    endif
282
283    if getline(beforeelse) =~ '^\s*}'
284	let beforeelse = FindOpenBracket(beforeelse, 0)
285
286	if getline(beforeelse) =~ '^\s*{'
287	    let beforeelse = GetLastRealCodeLNum(beforeelse - 1)
288	endif
289    endif
290
291
292    if !s:iftoskip && a:StopAfterFirstPrevElse && getline(beforeelse) =~# '^\s*\%([}]\s*\)\=else\%(if\)\=\>'
293	return beforeelse
294    endif
295
296    if getline(beforeelse) !~# '^\s*if\>' && beforeelse>1 || s:iftoskip && beforeelse>1
297
298	if s:iftoskip && getline(beforeelse) =~# '^\s*if\>'
299	    let s:iftoskip = s:iftoskip - 1
300	endif
301
302	let s:level =  s:level + 1
303	let beforeelse = FindTheIfOfAnElse(beforeelse, a:StopAfterFirstPrevElse)
304    endif
305
306    return beforeelse
307
308endfunction " }}}
309
310let s:defaultORcase = '^\s*\%(default\|case\).*:'
311
312function! FindTheSwitchIndent (lnum) " {{{
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 "SpecStringEntrails"
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 real_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    else
434	let real_PHP_lastindented = v:lnum
435    endif
436
437    let b:PHP_lastindented = v:lnum
438
439
440    if !b:InPHPcode_checked " {{{ One time check
441	let b:InPHPcode_checked = 1
442
443	let synname = ""
444	if cline !~ '<?.*?>'
445	    let synname = IslinePHP (prevnonblank(v:lnum), "")
446	endif
447
448	if synname!=""
449	    if synname == "SpecStringEntrails"
450		let b:InPHPcode = -1 " thumb down
451		let b:UserIsTypingComment = 0
452		let b:InPHPcode_tofind = ""
453	    elseif synname != "phpHereDoc" && synname != "phpHereDocDelimiter"
454		let b:InPHPcode = 1
455		let b:InPHPcode_tofind = ""
456
457		if synname =~# '^php\%(Doc\)\?Comment'
458		    let b:UserIsTypingComment = 1
459		else
460		    let b:UserIsTypingComment = 0
461		endif
462
463		if synname =~? '^javaScript'
464		    let b:InPHPcode_and_script = 1
465		endif
466
467	    else
468		let b:InPHPcode = 0
469		let b:UserIsTypingComment = 0
470
471		let lnum = v:lnum - 1
472		while getline(lnum) !~? '<<<''\=\a\w*''\=$' && lnum > 1
473		    let lnum = lnum - 1
474		endwhile
475
476		let b:InPHPcode_tofind = substitute( getline(lnum), '^.*<<<''\=\(\a\w*\)''\=$', '^\\s*\1;\\=$', '')
477	    endif
478	else
479	    let b:InPHPcode = 0
480	    let b:UserIsTypingComment = 0
481	    let b:InPHPcode_tofind = s:PHP_startindenttag
482	endif
483    endif "!b:InPHPcode_checked }}}
484
485
486    " Test if we are indenting PHP code {{{
487    let lnum = prevnonblank(v:lnum - 1)
488    let last_line = getline(lnum)
489    let endline= s:endline
490
491    if b:InPHPcode_tofind!=""
492	if cline =~? b:InPHPcode_tofind
493	    let b:InPHPcode_tofind = ""
494	    let b:UserIsTypingComment = 0
495
496	    if b:InPHPcode == -1
497		let b:InPHPcode = 1
498		return -1
499	    end
500
501	    let b:InPHPcode = 1
502
503	    if cline =~ '\*/'
504		call cursor(v:lnum, 1)
505		if cline !~ '^\*/'
506		    call search('\*/', 'W')
507		endif
508		let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
509
510		let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
511
512		let b:PHP_LastIndentedWasComment = 0
513
514		if cline =~ '^\s*\*/'
515		    return indent(lnum) + 1
516		else
517		    return indent(lnum)
518		endif
519
520	    elseif cline =~? '<script\>'
521		let b:InPHPcode_and_script = 1
522		let b:GetLastRealCodeLNum_ADD = v:lnum
523	    endif
524	endif
525    endif
526
527    if 1 == b:InPHPcode
528
529	if !b:InPHPcode_and_script && last_line =~ '\%(<?.*\)\@<!?>\%(.*<?\)\@!' && IslinePHP(lnum, '?>')=~"Delimiter"
530	    if cline !~? s:PHP_startindenttag
531		let b:InPHPcode = 0
532		let b:InPHPcode_tofind = s:PHP_startindenttag
533	    elseif cline =~? '<script\>'
534		let b:InPHPcode_and_script = 1
535	    endif
536
537	elseif last_line =~ '^[^''"`]\+[''"`]$'
538	    let b:InPHPcode = -1
539	    let b:InPHPcode_tofind = substitute( last_line, '^.*\([''"`]\).*$', '^[^\1]*\1[;,]$', '')
540	elseif last_line =~? '<<<''\=\a\w*''\=$'
541	    let b:InPHPcode = 0
542	    let b:InPHPcode_tofind = substitute( last_line, '^.*<<<''\=\(\a\w*\)''\=$', '^\\s*\1;\\=$', '')
543
544	elseif !UserIsEditing && cline =~ '^\s*/\*\%(.*\*/\)\@!' && getline(v:lnum + 1) !~ '^\s*\*'
545	    let b:InPHPcode = 0
546	    let b:InPHPcode_tofind = '\*/'
547
548	elseif cline =~? '^\s*</script>'
549	    let b:InPHPcode = 0
550	    let b:InPHPcode_tofind = s:PHP_startindenttag
551	endif
552    endif " }}}
553
554
555    if 1 > b:InPHPcode && !b:InPHPcode_and_script
556	return -1
557    endif
558
559    " Indent successive // or # comment the same way the first is {{{
560    let addSpecial = 0
561    if cline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)'
562	let addSpecial = b:PHP_outdentSLComments
563	if b:PHP_LastIndentedWasComment == 1
564	    return indent(real_PHP_lastindented)
565	endif
566	let b:PHP_LastIndentedWasComment = 1
567    else
568	let b:PHP_LastIndentedWasComment = 0
569    endif " }}}
570
571    " Indent multiline /* comments correctly {{{
572
573    if b:PHP_InsideMultilineComment || b:UserIsTypingComment
574	if cline =~ '^\s*\*\%(\/\)\@!'
575	    if last_line =~ '^\s*/\*'
576		return indent(lnum) + 1
577	    else
578		return indent(lnum)
579	    endif
580	else
581	    let b:PHP_InsideMultilineComment = 0
582	endif
583    endif
584
585    if !b:PHP_InsideMultilineComment && cline =~ '^\s*/\*\%(.*\*/\)\@!'
586	if getline(v:lnum + 1) !~ '^\s*\*'
587	    return -1
588	endif
589	let b:PHP_InsideMultilineComment = 1
590    endif " }}}
591
592
593    " Things always indented at col 1 (PHP delimiter: <?, ?>, Heredoc end) {{{
594    if cline =~# '^\s*<?' && cline !~ '?>' && b:PHP_outdentphpescape
595	return 0
596    endif
597
598    if	cline =~ '^\s*?>' && cline !~# '<?' && b:PHP_outdentphpescape
599	return 0
600    endif
601
602    if cline =~? '^\s*\a\w*;$\|^\a\w*$\|^\s*[''"`][;,]' && cline !~? s:notPhpHereDoc
603	return 0
604    endif " }}}
605
606    let s:level = 0
607
608    let lnum = GetLastRealCodeLNum(v:lnum - 1)
609
610    let last_line = getline(lnum)
611    let ind = indent(lnum)
612
613    if ind==0 && b:PHP_default_indenting
614	let ind = b:PHP_default_indenting
615    endif
616
617    if lnum == 0
618	return b:PHP_default_indenting + addSpecial
619    endif
620
621
622    if cline =~ '^\s*}\%(}}\)\@!'
623	let ind = indent(FindOpenBracket(v:lnum, 1))
624	let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
625	return ind
626    endif
627
628    if cline =~ '^\s*\*/'
629	call cursor(v:lnum, 1)
630	if cline !~ '^\*/'
631	    call search('\*/', 'W')
632	endif
633	let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
634
635	let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
636
637	if cline =~ '^\s*\*/'
638	    return indent(lnum) + 1
639	else
640	    return indent(lnum)
641	endif
642    endif
643
644
645    if last_line =~ '[;}]'.endline && last_line !~ '^[)\]]' && last_line !~# s:defaultORcase
646	if ind==b:PHP_default_indenting
647	    return b:PHP_default_indenting + addSpecial
648	elseif b:PHP_indentinghuge && ind==b:PHP_CurrentIndentLevel && cline !~# '^\s*\%(else\|\%(case\|default\).*:\|[})];\=\)' && last_line !~# '^\s*\%(\%(}\s*\)\=else\)' && getline(GetLastRealCodeLNum(lnum - 1))=~';'.endline
649	    return b:PHP_CurrentIndentLevel + addSpecial
650	endif
651    endif
652
653    let LastLineClosed = 0
654
655    let terminated = s:terminated
656
657    let unstated   = '\%(^\s*'.s:blockstart.'.*)\|\%(//.*\)\@<!\<e'.'lse\>\)'.endline
658
659    if ind != b:PHP_default_indenting && cline =~# '^\s*else\%(if\)\=\>'
660	let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
661	return indent(FindTheIfOfAnElse(v:lnum, 1))
662    elseif cline =~# s:defaultORcase
663	return FindTheSwitchIndent(v:lnum) + &sw * b:PHP_vintage_case_default_indent
664    elseif cline =~ '^\s*)\=\s*{'
665	let previous_line = last_line
666	let last_line_num = lnum
667
668	while last_line_num > 1
669
670	    if previous_line =~ terminated || previous_line =~ '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . endline
671
672		let ind = indent(last_line_num)
673
674		if  b:PHP_BracesAtCodeLevel
675		    let ind = ind + &sw
676		endif
677
678		return ind
679	    endif
680
681	    let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
682	    let previous_line = getline(last_line_num)
683	endwhile
684
685    elseif last_line =~# unstated && cline !~ '^\s*);\='.endline
686	let ind = ind + &sw
687	return ind + addSpecial
688
689    elseif (ind != b:PHP_default_indenting || last_line =~ '^[)\]]' ) && last_line =~ terminated
690	let previous_line = last_line
691	let last_line_num = lnum
692	let LastLineClosed = 1
693
694	let isSingleLineBlock = 0
695	while 1
696	    if ! isSingleLineBlock && previous_line =~ '^\s*}\|;\s*}'.endline
697
698		call cursor(last_line_num, 1)
699		if previous_line !~ '^}'
700		    call search('}\|;\s*}'.endline, 'W')
701		end
702		let oldLastLine = last_line_num
703		let last_line_num = searchpair('{', '', '}', 'bW', 'Skippmatch()')
704
705		if getline(last_line_num) =~ '^\s*{'
706		    let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
707		elseif oldLastLine == last_line_num
708		    let isSingleLineBlock = 1
709		    continue
710		endif
711
712		let previous_line = getline(last_line_num)
713
714		continue
715	    else
716		let isSingleLineBlock = 0
717
718		if getline(last_line_num) =~# '^\s*else\%(if\)\=\>'
719		    let last_line_num = FindTheIfOfAnElse(last_line_num, 0)
720		    continue
721		endif
722
723
724		let last_match = last_line_num
725
726		let one_ahead_indent = indent(last_line_num)
727		let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
728		let two_ahead_indent = indent(last_line_num)
729		let after_previous_line = previous_line
730		let previous_line = getline(last_line_num)
731
732
733		if previous_line =~# s:defaultORcase.'\|{'.endline
734		    break
735		endif
736
737		if after_previous_line=~# '^\s*'.s:blockstart.'.*)'.endline && previous_line =~# '[;}]'.endline
738		    break
739		endif
740
741		if one_ahead_indent == two_ahead_indent || last_line_num < 1
742		    if previous_line =~# '\%(;\|^\s*}\)'.endline || last_line_num < 1
743			break
744		    endif
745		endif
746	    endif
747	endwhile
748
749	if indent(last_match) != ind
750	    let ind = indent(last_match)
751	    let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
752
753	    return ind + addSpecial
754	endif
755    endif
756
757    if (last_line !~ '^\s*}\%(}}\)\@!')
758	let plinnum = GetLastRealCodeLNum(lnum - 1)
759    else
760	let plinnum = GetLastRealCodeLNum(FindOpenBracket(lnum, 1) - 1)
761    endif
762
763    let AntepenultimateLine = getline(plinnum)
764
765    let last_line = substitute(last_line,"\\(//\\|#\\)\\(\\(\\([^\"']*\\([\"']\\)[^\"']*\\5\\)\\+[^\"']*$\\)\\|\\([^\"']*$\\)\\)",'','')
766
767
768    if ind == b:PHP_default_indenting
769	if last_line =~ terminated && last_line !~# s:defaultORcase
770	    let LastLineClosed = 1
771	endif
772    endif
773
774    if !LastLineClosed
775
776
777	if last_line =~# '[{(\[]'.endline || last_line =~? '\h\w*\s*(.*,$' && AntepenultimateLine !~ '[,(\[]'.endline
778
779	    let dontIndent = 0
780	    if last_line =~ '\S\+\s*{'.endline && last_line !~ '^\s*)\s*{'.endline && last_line !~ '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . s:endline
781		let dontIndent = 1
782	    endif
783
784	    if !dontIndent && (!b:PHP_BracesAtCodeLevel || last_line !~# '^\s*{')
785		let ind = ind + &sw
786	    endif
787
788	    if b:PHP_BracesAtCodeLevel || b:PHP_vintage_case_default_indent == 1
789		let b:PHP_CurrentIndentLevel = ind
790
791		return ind + addSpecial
792	    endif
793
794	elseif last_line =~ '\S\+\s*),'.endline
795	    call cursor(lnum, 1)
796	    call search('),'.endline, 'W')
797	    let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()')
798	    if openedparent != lnum
799		let ind = indent(openedparent)
800	    endif
801
802	elseif last_line =~ '^\s*'.s:blockstart
803	    let ind = ind + &sw
804
805
806    elseif AntepenultimateLine =~ '{'.endline || AntepenultimateLine =~ terminated || AntepenultimateLine =~# s:defaultORcase
807	    let ind = ind + &sw
808	endif
809
810    endif
811
812    if cline =~  '^\s*[)\]];\='
813	let ind = ind - &sw
814    endif
815
816    let b:PHP_CurrentIndentLevel = ind
817    return ind + addSpecial
818endfunction
819