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