xref: /vim-8.2.3635/runtime/indent/php.vim (revision b17893aa)
1071d4279SBram Moolenaar" Vim indent file
2071d4279SBram Moolenaar" Language:	PHP
35477506aSBram Moolenaar" Author:	John Wellesz <John.wellesz (AT) gmail (DOT) com>
45477506aSBram Moolenaar" URL:		https://www.2072productions.com/vim/indent/php.vim
5e6ae6225SBram Moolenaar" Home:		https://github.com/2072/PHP-Indenting-for-VIm
6*b17893aaSBram Moolenaar" Last Change:	2020 Mar 05
75477506aSBram Moolenaar" Version:	1.70
8071d4279SBram Moolenaar"
9071d4279SBram Moolenaar"
10e6ae6225SBram Moolenaar"	Type :help php-indent for available options
11e6ae6225SBram Moolenaar"
12e6ae6225SBram Moolenaar"	A fully commented version of this file is available on github
13a5792f58SBram Moolenaar"
14a5792f58SBram Moolenaar"
15259f26acSBram Moolenaar"  If you find a bug, please open a ticket on github.com
16e6ae6225SBram Moolenaar"  ( https://github.com/2072/PHP-Indenting-for-VIm/issues ) with an example of
17e6ae6225SBram Moolenaar"  code that breaks the algorithm.
189ff7011bSBram Moolenaar"
19e6ae6225SBram Moolenaar
209ff7011bSBram Moolenaar" NOTE: This script must be used with PHP syntax ON and with the php syntax
21e6ae6225SBram Moolenaar"	script by Lutz Eymers (http://www.isp.de/data/php.vim ) or with the
225477506aSBram Moolenaar"	script by Peter Hodge (https://www.vim.org/scripts/script.php?script_id=1571 )
235c73622aSBram Moolenaar"	the later is bunbdled by default with Vim 7.
249ff7011bSBram Moolenaar"
259ff7011bSBram Moolenaar"
26c236c16dSBram Moolenaar"	In the case you have syntax errors in your script such as HereDoc end
27c236c16dSBram Moolenaar"	identifiers not at col 1 you'll have to indent your file 2 times (This
28c236c16dSBram Moolenaar"	script will automatically put HereDoc end identifiers at col 1 if
29c236c16dSBram Moolenaar"	they are followed by a ';').
309ff7011bSBram Moolenaar"
31e6ae6225SBram Moolenaar
325c73622aSBram Moolenaar" NOTE: If you are editing files in Unix file format and that (by accident)
339ff7011bSBram Moolenaar"	there are '\r' before new lines, this script won't be able to proceed
349ff7011bSBram Moolenaar"	correctly and will make many mistakes because it won't be able to match
359ff7011bSBram Moolenaar"	'\s*$' correctly.
369ff7011bSBram Moolenaar"	So you have to remove those useless characters first with a command like:
379ff7011bSBram Moolenaar"
389ff7011bSBram Moolenaar"	:%s /\r$//g
399ff7011bSBram Moolenaar"
409ff7011bSBram Moolenaar"	or simply 'let' the option PHP_removeCRwhenUnix to 1 and the script will
419ff7011bSBram Moolenaar"	silently remove them when VIM load this script (at each bufread).
42bcb9898eSBram Moolenaar
43bcb9898eSBram Moolenaar
44071d4279SBram Moolenaarif exists("b:did_indent")
45071d4279SBram Moolenaar    finish
46071d4279SBram Moolenaarendif
47071d4279SBram Moolenaarlet b:did_indent = 1
48071d4279SBram Moolenaar
49071d4279SBram Moolenaar
50ed32d942SBram Moolenaarlet g:php_sync_method = 0
51071d4279SBram Moolenaar
52e6ae6225SBram Moolenaar
539ff7011bSBram Moolenaarif exists("PHP_default_indenting")
543ec574f2SBram Moolenaar    let b:PHP_default_indenting = PHP_default_indenting * shiftwidth()
556bb68366SBram Moolenaarelse
569ff7011bSBram Moolenaar    let b:PHP_default_indenting = 0
57071d4279SBram Moolenaarendif
58071d4279SBram Moolenaar
59e6ae6225SBram Moolenaarif exists("PHP_outdentSLComments")
603ec574f2SBram Moolenaar    let b:PHP_outdentSLComments = PHP_outdentSLComments * shiftwidth()
61e6ae6225SBram Moolenaarelse
62e6ae6225SBram Moolenaar    let b:PHP_outdentSLComments = 0
63e6ae6225SBram Moolenaarendif
64e6ae6225SBram Moolenaar
659ff7011bSBram Moolenaarif exists("PHP_BracesAtCodeLevel")
669ff7011bSBram Moolenaar    let b:PHP_BracesAtCodeLevel = PHP_BracesAtCodeLevel
679ff7011bSBram Moolenaarelse
689ff7011bSBram Moolenaar    let b:PHP_BracesAtCodeLevel = 0
69071d4279SBram Moolenaarendif
709ff7011bSBram Moolenaar
71c236c16dSBram Moolenaar
72a5792f58SBram Moolenaarif exists("PHP_autoformatcomment")
73a5792f58SBram Moolenaar    let b:PHP_autoformatcomment = PHP_autoformatcomment
74a5792f58SBram Moolenaarelse
75a5792f58SBram Moolenaar    let b:PHP_autoformatcomment = 1
76a5792f58SBram Moolenaarendif
779ff7011bSBram Moolenaar
788408a9adSBram Moolenaarif exists("PHP_outdentphpescape")
798408a9adSBram Moolenaar    let b:PHP_outdentphpescape = PHP_outdentphpescape
808408a9adSBram Moolenaarelse
818408a9adSBram Moolenaar    let b:PHP_outdentphpescape = 1
828408a9adSBram Moolenaarendif
838408a9adSBram Moolenaar
840b0f0992SBram Moolenaarif exists("PHP_noArrowMatching")
850b0f0992SBram Moolenaar    let b:PHP_noArrowMatching = PHP_noArrowMatching
860b0f0992SBram Moolenaarelse
870b0f0992SBram Moolenaar    let b:PHP_noArrowMatching = 0
880b0f0992SBram Moolenaarendif
890b0f0992SBram Moolenaar
908408a9adSBram Moolenaar
918408a9adSBram Moolenaarif exists("PHP_vintage_case_default_indent") && PHP_vintage_case_default_indent
928408a9adSBram Moolenaar    let b:PHP_vintage_case_default_indent = 1
93c236c16dSBram Moolenaarelse
94c236c16dSBram Moolenaar    let b:PHP_vintage_case_default_indent = 0
95c236c16dSBram Moolenaarendif
96c236c16dSBram Moolenaar
975477506aSBram Moolenaarif exists("PHP_IndentFunctionCallParameters")
985477506aSBram Moolenaar    let b:PHP_IndentFunctionCallParameters = PHP_IndentFunctionCallParameters
995477506aSBram Moolenaarelse
1005477506aSBram Moolenaar    let b:PHP_IndentFunctionCallParameters = 0
1015477506aSBram Moolenaarendif
102c236c16dSBram Moolenaar
1035477506aSBram Moolenaarif exists("PHP_IndentFunctionDeclarationParameters")
1045477506aSBram Moolenaar    let b:PHP_IndentFunctionDeclarationParameters = PHP_IndentFunctionDeclarationParameters
1055477506aSBram Moolenaarelse
1065477506aSBram Moolenaar    let b:PHP_IndentFunctionDeclarationParameters = 0
1075477506aSBram Moolenaarendif
108c236c16dSBram Moolenaar
1099ff7011bSBram Moolenaarlet b:PHP_lastindented = 0
1109ff7011bSBram Moolenaarlet b:PHP_indentbeforelast = 0
1119ff7011bSBram Moolenaarlet b:PHP_indentinghuge = 0
1129ff7011bSBram Moolenaarlet b:PHP_CurrentIndentLevel = b:PHP_default_indenting
1139ff7011bSBram Moolenaarlet b:PHP_LastIndentedWasComment = 0
1149ff7011bSBram Moolenaarlet b:PHP_InsideMultilineComment = 0
1159ff7011bSBram Moolenaarlet b:InPHPcode = 0
1169ff7011bSBram Moolenaarlet b:InPHPcode_checked = 0
1179ff7011bSBram Moolenaarlet b:InPHPcode_and_script = 0
1189ff7011bSBram Moolenaarlet b:InPHPcode_tofind = ""
1199ff7011bSBram Moolenaarlet b:PHP_oldchangetick = b:changedtick
1209ff7011bSBram Moolenaarlet b:UserIsTypingComment = 0
1219ff7011bSBram Moolenaarlet b:optionsset = 0
1229ff7011bSBram Moolenaar
1239ff7011bSBram Moolenaarsetlocal nosmartindent
1249ff7011bSBram Moolenaarsetlocal noautoindent
1259ff7011bSBram Moolenaarsetlocal nocindent
1261e015460SBram Moolenaarsetlocal nolisp
1279ff7011bSBram Moolenaar
1289ff7011bSBram Moolenaarsetlocal indentexpr=GetPhpIndent()
129ed32d942SBram Moolenaarsetlocal indentkeys=0{,0},0),0],:,!^F,o,O,e,*<Return>,=?>,=<?,=*/
1309ff7011bSBram Moolenaar
1319ff7011bSBram Moolenaar
1321e015460SBram Moolenaar
1339ff7011bSBram Moolenaarlet s:searchpairflags = 'bWr'
1349ff7011bSBram Moolenaar
1359ff7011bSBram Moolenaarif &fileformat == "unix" && exists("PHP_removeCRwhenUnix") && PHP_removeCRwhenUnix
1369ff7011bSBram Moolenaar    silent! %s/\r$//g
1379ff7011bSBram Moolenaarendif
1389ff7011bSBram Moolenaar
1399ff7011bSBram Moolenaarif exists("*GetPhpIndent")
1405c73622aSBram Moolenaar    call ResetPhpOptions()
1415477506aSBram Moolenaar    finish " XXX -- comment this line for easy dev
1429ff7011bSBram Moolenaarendif
1439ff7011bSBram Moolenaar
144bcb9898eSBram Moolenaar
1459ff7011bSBram Moolenaarlet s:endline = '\s*\%(//.*\|#.*\|/\*.*\*/\s*\)\=$'
1465477506aSBram Moolenaarlet s:PHP_validVariable = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
1475477506aSBram Moolenaarlet s:notPhpHereDoc = '\%(break\|return\|continue\|exit\|die\|else\|end\%(if\|while\|for\|foreach\|switch\)\)'
1485477506aSBram Moolenaarlet s:blockstart = '\%(\%(\%(}\s*\)\=else\%(\s\+\)\=\)\=if\>\|\%(}\s*\)\?else\>\|do\>\|while\>\|switch\>\|case\>\|default\>\|for\%(each\)\=\>\|declare\>\|class\>\|trait\>\|\%()\s*\)\=use\>\|interface\>\|abstract\>\|final\>\|try\>\|\%(}\s*\)\=catch\>\|\%(}\s*\)\=finally\>\)'
1495477506aSBram Moolenaarlet s:functionDeclPrefix = '\<function\>\%(\s\+&\='.s:PHP_validVariable.'\)\=\s*('
1505477506aSBram Moolenaarlet s:functionDecl = s:functionDeclPrefix.'.*'
1515477506aSBram Moolenaarlet s:multilineFunctionDecl = s:functionDeclPrefix.s:endline
1525477506aSBram Moolenaarlet s:arrayDecl = '\<array\>\s*(.*'
1535477506aSBram Moolenaarlet s:multilineFunctionCall = s:PHP_validVariable.'\s*('.s:endline
154e0720cbfSBram Moolenaarlet s:unstated = '\%(^\s*'.s:blockstart.'.*)\|\%(//.*\)\@<!\<e'.'lse\>\)'.s:endline
155ed32d942SBram Moolenaar
156ed32d942SBram Moolenaar
157e0720cbfSBram Moolenaarlet s:terminated = '\%(\%(;\%(\s*\%(?>\|}\)\)\=\|<<<\s*[''"]\=\a\w*[''"]\=$\|^\s*}\|^\s*'.s:PHP_validVariable.':\)'.s:endline.'\)'
1589ff7011bSBram Moolenaarlet s:PHP_startindenttag = '<?\%(.*?>\)\@!\|<script[^>]*>\%(.*<\/script>\)\@!'
159e0720cbfSBram Moolenaarlet s:structureHead = '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . s:endline . '\|\<new\s\+class\>'
1609ff7011bSBram Moolenaar
1619ff7011bSBram Moolenaar
162bcb9898eSBram Moolenaarlet s:escapeDebugStops = 0
163e6ae6225SBram Moolenaarfunction! DebugPrintReturn(scriptLine)
164e6ae6225SBram Moolenaar
165bcb9898eSBram Moolenaar    if ! s:escapeDebugStops
166e6ae6225SBram Moolenaar	echo "debug:" . a:scriptLine
167bcb9898eSBram Moolenaar	let c = getchar()
168bcb9898eSBram Moolenaar	if c == "\<Del>"
169bcb9898eSBram Moolenaar	    let s:escapeDebugStops = 1
170bcb9898eSBram Moolenaar	end
171bcb9898eSBram Moolenaar    endif
172e6ae6225SBram Moolenaar
173e6ae6225SBram Moolenaarendfunction
174e6ae6225SBram Moolenaar
1759ff7011bSBram Moolenaarfunction! GetLastRealCodeLNum(startline) " {{{
17605a7bb36SBram Moolenaar
1779ff7011bSBram Moolenaar    let lnum = a:startline
17805a7bb36SBram Moolenaar
17905a7bb36SBram Moolenaar    if b:GetLastRealCodeLNum_ADD && b:GetLastRealCodeLNum_ADD == lnum + 1
18005a7bb36SBram Moolenaar	let lnum = b:GetLastRealCodeLNum_ADD
18105a7bb36SBram Moolenaar    endif
18205a7bb36SBram Moolenaar
1839ff7011bSBram Moolenaar    while lnum > 1
1849ff7011bSBram Moolenaar	let lnum = prevnonblank(lnum)
1859ff7011bSBram Moolenaar	let lastline = getline(lnum)
1869ff7011bSBram Moolenaar
1879ff7011bSBram Moolenaar	if b:InPHPcode_and_script && lastline =~ '?>\s*$'
1889ff7011bSBram Moolenaar	    let lnum = lnum - 1
1899ff7011bSBram Moolenaar	elseif lastline =~ '^\s*?>.*<?\%(php\)\=\s*$'
1909ff7011bSBram Moolenaar	    let lnum = lnum - 1
1911e015460SBram Moolenaar	elseif lastline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)'
1929ff7011bSBram Moolenaar	    let lnum = lnum - 1
1931e015460SBram Moolenaar	elseif lastline =~ '\*/\s*$'
1949ff7011bSBram Moolenaar	    call cursor(lnum, 1)
1951e015460SBram Moolenaar	    if lastline !~ '^\*/'
1961e015460SBram Moolenaar		call search('\*/', 'W')
1971e015460SBram Moolenaar	    endif
198a5792f58SBram Moolenaar	    let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
1999ff7011bSBram Moolenaar
2009ff7011bSBram Moolenaar	    let lastline = getline(lnum)
2011e015460SBram Moolenaar	    if lastline =~ '^\s*/\*'
2021e015460SBram Moolenaar		let lnum = lnum - 1
2039ff7011bSBram Moolenaar	    else
2049ff7011bSBram Moolenaar		break
2059ff7011bSBram Moolenaar	    endif
2069ff7011bSBram Moolenaar
2079ff7011bSBram Moolenaar
2081e015460SBram Moolenaar	elseif lastline =~? '\%(//\s*\|?>.*\)\@<!<?\%(php\)\=\s*$\|^\s*<script\>'
2099ff7011bSBram Moolenaar
2109ff7011bSBram Moolenaar	    while lastline !~ '\(<?.*\)\@<!?>' && lnum > 1
2119ff7011bSBram Moolenaar		let lnum = lnum - 1
2129ff7011bSBram Moolenaar		let lastline = getline(lnum)
2139ff7011bSBram Moolenaar	    endwhile
2141e015460SBram Moolenaar	    if lastline =~ '^\s*?>'
2159ff7011bSBram Moolenaar		let lnum = lnum - 1
2169ff7011bSBram Moolenaar	    else
2171e015460SBram Moolenaar		break
2189ff7011bSBram Moolenaar	    endif
2199ff7011bSBram Moolenaar
2209ff7011bSBram Moolenaar
2218408a9adSBram Moolenaar	elseif lastline =~? '^\a\w*;\=$' && lastline !~? s:notPhpHereDoc
222cbebd487SBram Moolenaar	    let tofind=substitute( lastline, '\(\a\w*\);\=', '<<<\\s*[''"]\\=\1[''"]\\=$', '')
2239ff7011bSBram Moolenaar	    while getline(lnum) !~? tofind && lnum > 1
2249ff7011bSBram Moolenaar		let lnum = lnum - 1
2259ff7011bSBram Moolenaar	    endwhile
2265477506aSBram Moolenaar	elseif lastline =~ '^\s*[''"`][;,]' || (lastline =~ '^[^''"`]*[''"`][;,]'.s:endline && IslinePHP(lnum, "") == "SpecStringEntrails")
227e0720cbfSBram Moolenaar
228e0720cbfSBram Moolenaar	    let tofind=substitute( lastline, '^.*\([''"`]\)[;,].*$', '^[^\1]\\+[\1]$\\|^[^\1]\\+[=([]\\s*[\1]', '')
229e0720cbfSBram Moolenaar	    let trylnum = lnum
230e0720cbfSBram Moolenaar	    while getline(trylnum) !~? tofind && trylnum > 1
231e0720cbfSBram Moolenaar		let trylnum = trylnum - 1
232bcb9898eSBram Moolenaar	    endwhile
233e0720cbfSBram Moolenaar
234e0720cbfSBram Moolenaar	    if trylnum == 1
235e0720cbfSBram Moolenaar		break
236e0720cbfSBram Moolenaar	    else
237e0720cbfSBram Moolenaar		if lastline =~ ';'.s:endline
238e0720cbfSBram Moolenaar		    while getline(trylnum) !~? s:terminated && getline(trylnum) !~? '{'.s:endline && trylnum > 1
239e0720cbfSBram Moolenaar			let trylnum = prevnonblank(trylnum - 1)
240e0720cbfSBram Moolenaar		    endwhile
241e0720cbfSBram Moolenaar
242e0720cbfSBram Moolenaar
243e0720cbfSBram Moolenaar		    if trylnum == 1
244e0720cbfSBram Moolenaar			break
245e0720cbfSBram Moolenaar		    end
246e0720cbfSBram Moolenaar		end
247e0720cbfSBram Moolenaar		let lnum = trylnum
248e0720cbfSBram Moolenaar	    end
2499ff7011bSBram Moolenaar	else
2501e015460SBram Moolenaar	    break
2519ff7011bSBram Moolenaar	endif
2529ff7011bSBram Moolenaar    endwhile
2539ff7011bSBram Moolenaar
2549ff7011bSBram Moolenaar    if lnum==1 && getline(lnum) !~ '<?'
2559ff7011bSBram Moolenaar	let lnum=0
2569ff7011bSBram Moolenaar    endif
2579ff7011bSBram Moolenaar
258ed32d942SBram Moolenaar    if b:InPHPcode_and_script && 1 > b:InPHPcode
2599ff7011bSBram Moolenaar	let b:InPHPcode_and_script = 0
2609ff7011bSBram Moolenaar    endif
261d5ab34bdSBram Moolenaar
2629ff7011bSBram Moolenaar    return lnum
2631e015460SBram Moolenaarendfunction " }}}
2649ff7011bSBram Moolenaar
265a5792f58SBram Moolenaarfunction! Skippmatch2()
266a5792f58SBram Moolenaar
267a5792f58SBram Moolenaar    let line = getline(".")
268a5792f58SBram Moolenaar
269e6ae6225SBram Moolenaar    if line =~ "\\([\"']\\).*/\\*.*\\1" || line =~ '\%(//\|#\).*/\*'
270a5792f58SBram Moolenaar	return 1
271a5792f58SBram Moolenaar    else
272a5792f58SBram Moolenaar	return 0
273a5792f58SBram Moolenaar    endif
274a5792f58SBram Moolenaarendfun
275a5792f58SBram Moolenaar
2769ff7011bSBram Moolenaarfunction! Skippmatch()	" {{{
2779ff7011bSBram Moolenaar    let synname = synIDattr(synID(line("."), col("."), 0), "name")
2780b0f0992SBram Moolenaar    if synname ==? "Delimiter" || synname ==? "phpRegionDelimiter" || synname =~? "^phpParent" || synname ==? "phpArrayParens" || synname =~? '^php\%(Block\|Brace\)' || synname ==? "javaScriptBraces" || synname =~? '^php\%(Doc\)\?Comment' && b:UserIsTypingComment
2799ff7011bSBram Moolenaar	return 0
2809ff7011bSBram Moolenaar    else
2819ff7011bSBram Moolenaar	return 1
2829ff7011bSBram Moolenaar    endif
2831e015460SBram Moolenaarendfun " }}}
2849ff7011bSBram Moolenaar
285bcb9898eSBram Moolenaarfunction! FindOpenBracket(lnum, blockStarter) " {{{
2861e015460SBram Moolenaar    call cursor(a:lnum, 1)
287bcb9898eSBram Moolenaar    let line = searchpair('{', '', '}', 'bW', 'Skippmatch()')
288bcb9898eSBram Moolenaar
289bcb9898eSBram Moolenaar    if a:blockStarter == 1
290bcb9898eSBram Moolenaar	while line > 1
291bcb9898eSBram Moolenaar	    let linec = getline(line)
292bcb9898eSBram Moolenaar
293e0720cbfSBram Moolenaar	    if linec =~ s:terminated || linec =~ s:structureHead
294bcb9898eSBram Moolenaar		break
295bcb9898eSBram Moolenaar	    endif
296bcb9898eSBram Moolenaar
297bcb9898eSBram Moolenaar	    let line = GetLastRealCodeLNum(line - 1)
298bcb9898eSBram Moolenaar	endwhile
299bcb9898eSBram Moolenaar    endif
300bcb9898eSBram Moolenaar
301bcb9898eSBram Moolenaar    return line
3021e015460SBram Moolenaarendfun " }}}
3039ff7011bSBram Moolenaar
304e0720cbfSBram Moolenaarlet s:blockChars = {'{':1, '[': 1, '(': 1, ')':-1, ']':-1, '}':-1}
3055477506aSBram Moolenaarlet s:blockCharsLUT = {'{':'{', '}':'{',   '[':'[', ']':'[',   '(':'(', ')':'('}
306e0720cbfSBram Moolenaarfunction! BalanceDirection (str)
307e0720cbfSBram Moolenaar
3085477506aSBram Moolenaar    let balance = {'{':0, '[': 0, '(': 0, 'none':0}
3095477506aSBram Moolenaar    let director = 'none'
310e0720cbfSBram Moolenaar
311e0720cbfSBram Moolenaar    for c in split(a:str, '\zs')
312e0720cbfSBram Moolenaar	if has_key(s:blockChars, c)
3135477506aSBram Moolenaar	    let balance[s:blockCharsLUT[c]] += s:blockChars[c]
3145477506aSBram Moolenaar
3155477506aSBram Moolenaar	    if balance[s:blockCharsLUT[c]]
3165477506aSBram Moolenaar		let director = s:blockCharsLUT[c]
3175477506aSBram Moolenaar	    endif
318e0720cbfSBram Moolenaar	endif
319e0720cbfSBram Moolenaar    endfor
320e0720cbfSBram Moolenaar
3215477506aSBram Moolenaar    return balance[director]
322e0720cbfSBram Moolenaarendfun
323e0720cbfSBram Moolenaar
3240b0f0992SBram Moolenaarfunction! StripEndlineComments (line)
3250b0f0992SBram Moolenaar    return substitute(a:line,"\\(//\\|#\\)\\(\\(\\([^\"']*\\([\"']\\)[^\"']*\\5\\)\\+[^\"']*$\\)\\|\\([^\"']*$\\)\\)",'','')
3260b0f0992SBram Moolenaarendfun
3270b0f0992SBram Moolenaar
3280b0f0992SBram Moolenaarfunction! FindArrowIndent (lnum)  " {{{
3290b0f0992SBram Moolenaar
3305477506aSBram Moolenaar    let parrentArrowPos = -1
3315477506aSBram Moolenaar    let cursorPos = -1
3320b0f0992SBram Moolenaar    let lnum = a:lnum
3330b0f0992SBram Moolenaar    while lnum > 1
3340b0f0992SBram Moolenaar	let last_line = getline(lnum)
3350b0f0992SBram Moolenaar	if last_line =~ '^\s*->'
3360b0f0992SBram Moolenaar	    let parrentArrowPos = indent(a:lnum)
3370b0f0992SBram Moolenaar	    break
3380b0f0992SBram Moolenaar	else
3395477506aSBram Moolenaar
3405477506aSBram Moolenaar	    if b:PHP_noArrowMatching
3410b0f0992SBram Moolenaar		break
3420b0f0992SBram Moolenaar	    endif
3430b0f0992SBram Moolenaar
3445477506aSBram Moolenaar	    let cleanedLnum = StripEndlineComments(last_line)
3455477506aSBram Moolenaar
3465477506aSBram Moolenaar	    if cleanedLnum =~ ')'.s:endline
3475477506aSBram Moolenaar		if BalanceDirection(cleanedLnum) <= 0
3485477506aSBram Moolenaar		    call cursor(lnum, 1)
3495477506aSBram Moolenaar		    call searchpos(')'.s:endline, 'cW', lnum)
3505477506aSBram Moolenaar		    let openedparent =  searchpair('(', '', ')', 'bW', 'Skippmatch()')
3515477506aSBram Moolenaar		    let cursorPos = col(".")
3525477506aSBram Moolenaar		    if openedparent != lnum
3535477506aSBram Moolenaar			let lnum = openedparent
3545477506aSBram Moolenaar			continue
3550b0f0992SBram Moolenaar		    else
3565477506aSBram Moolenaar		    endif
3575477506aSBram Moolenaar		else
3585477506aSBram Moolenaar		    let parrentArrowPos = -1
3595477506aSBram Moolenaar		    break
3605477506aSBram Moolenaar		end
3615477506aSBram Moolenaar	    endif
3625477506aSBram Moolenaar
3635477506aSBram Moolenaar	    if cleanedLnum =~ '->'
3645477506aSBram Moolenaar		call cursor(lnum, cursorPos == -1 ? strwidth(cleanedLnum) : cursorPos)
3655477506aSBram Moolenaar		let parrentArrowPos = searchpos('->', 'cWb', lnum)[1] - 1
3665477506aSBram Moolenaar
3675477506aSBram Moolenaar		break
3685477506aSBram Moolenaar	    else
3695477506aSBram Moolenaar		let parrentArrowPos = -1
3700b0f0992SBram Moolenaar		break
3710b0f0992SBram Moolenaar	    endif
3720b0f0992SBram Moolenaar	endif
3730b0f0992SBram Moolenaar    endwhile
3740b0f0992SBram Moolenaar
3755477506aSBram Moolenaar    if parrentArrowPos == -1
3765477506aSBram Moolenaar	let parrentArrowPos = indent(lnum) + shiftwidth()
3775477506aSBram Moolenaar    end
3785477506aSBram Moolenaar
3790b0f0992SBram Moolenaar    return parrentArrowPos
3800b0f0992SBram Moolenaarendfun "}}}
3810b0f0992SBram Moolenaar
3829ff7011bSBram Moolenaarfunction! FindTheIfOfAnElse (lnum, StopAfterFirstPrevElse) " {{{
3839ff7011bSBram Moolenaar
3849ff7011bSBram Moolenaar    if getline(a:lnum) =~# '^\s*}\s*else\%(if\)\=\>'
3851e015460SBram Moolenaar	let beforeelse = a:lnum
3869ff7011bSBram Moolenaar    else
3879ff7011bSBram Moolenaar	let beforeelse = GetLastRealCodeLNum(a:lnum - 1)
3889ff7011bSBram Moolenaar    endif
3899ff7011bSBram Moolenaar
3909ff7011bSBram Moolenaar    if !s:level
3919ff7011bSBram Moolenaar	let s:iftoskip = 0
3929ff7011bSBram Moolenaar    endif
3939ff7011bSBram Moolenaar
3949ff7011bSBram Moolenaar    if getline(beforeelse) =~# '^\s*\%(}\s*\)\=else\%(\s*if\)\@!\>'
3959ff7011bSBram Moolenaar	let s:iftoskip = s:iftoskip + 1
3969ff7011bSBram Moolenaar    endif
3979ff7011bSBram Moolenaar
3989ff7011bSBram Moolenaar    if getline(beforeelse) =~ '^\s*}'
399bcb9898eSBram Moolenaar	let beforeelse = FindOpenBracket(beforeelse, 0)
4009ff7011bSBram Moolenaar
4019ff7011bSBram Moolenaar	if getline(beforeelse) =~ '^\s*{'
4029ff7011bSBram Moolenaar	    let beforeelse = GetLastRealCodeLNum(beforeelse - 1)
4039ff7011bSBram Moolenaar	endif
4049ff7011bSBram Moolenaar    endif
4059ff7011bSBram Moolenaar
4069ff7011bSBram Moolenaar
4079ff7011bSBram Moolenaar    if !s:iftoskip && a:StopAfterFirstPrevElse && getline(beforeelse) =~# '^\s*\%([}]\s*\)\=else\%(if\)\=\>'
4089ff7011bSBram Moolenaar	return beforeelse
4099ff7011bSBram Moolenaar    endif
4109ff7011bSBram Moolenaar
4119ff7011bSBram Moolenaar    if getline(beforeelse) !~# '^\s*if\>' && beforeelse>1 || s:iftoskip && beforeelse>1
4129ff7011bSBram Moolenaar
4139ff7011bSBram Moolenaar	if s:iftoskip && getline(beforeelse) =~# '^\s*if\>'
4149ff7011bSBram Moolenaar	    let s:iftoskip = s:iftoskip - 1
4159ff7011bSBram Moolenaar	endif
4169ff7011bSBram Moolenaar
4179ff7011bSBram Moolenaar	let s:level =  s:level + 1
4189ff7011bSBram Moolenaar	let beforeelse = FindTheIfOfAnElse(beforeelse, a:StopAfterFirstPrevElse)
4199ff7011bSBram Moolenaar    endif
4209ff7011bSBram Moolenaar
4219ff7011bSBram Moolenaar    return beforeelse
4229ff7011bSBram Moolenaar
4231e015460SBram Moolenaarendfunction " }}}
4249ff7011bSBram Moolenaar
4258408a9adSBram Moolenaarlet s:defaultORcase = '^\s*\%(default\|case\).*:'
4268408a9adSBram Moolenaar
4278408a9adSBram Moolenaarfunction! FindTheSwitchIndent (lnum) " {{{
4288408a9adSBram Moolenaar
4298408a9adSBram Moolenaar    let test = GetLastRealCodeLNum(a:lnum - 1)
4308408a9adSBram Moolenaar
4318408a9adSBram Moolenaar    if test <= 1
4323ec574f2SBram Moolenaar	return indent(1) - shiftwidth() * b:PHP_vintage_case_default_indent
4338408a9adSBram Moolenaar    end
4348408a9adSBram Moolenaar
435bcb9898eSBram Moolenaar    while getline(test) =~ '^\s*}' && test > 1
436bcb9898eSBram Moolenaar	let test = GetLastRealCodeLNum(FindOpenBracket(test, 0) - 1)
4378408a9adSBram Moolenaar
438bcb9898eSBram Moolenaar	if getline(test) =~ '^\s*switch\>'
439bcb9898eSBram Moolenaar	    let test = GetLastRealCodeLNum(test - 1)
4408408a9adSBram Moolenaar	endif
441bcb9898eSBram Moolenaar    endwhile
4428408a9adSBram Moolenaar
4438408a9adSBram Moolenaar    if getline(test) =~# '^\s*switch\>'
4448408a9adSBram Moolenaar	return indent(test)
4458408a9adSBram Moolenaar    elseif getline(test) =~# s:defaultORcase
4463ec574f2SBram Moolenaar	return indent(test) - shiftwidth() * b:PHP_vintage_case_default_indent
4478408a9adSBram Moolenaar    else
4488408a9adSBram Moolenaar	return FindTheSwitchIndent(test)
4498408a9adSBram Moolenaar    endif
4508408a9adSBram Moolenaar
4518408a9adSBram Moolenaarendfunction "}}}
4528408a9adSBram Moolenaar
4530b0f0992SBram Moolenaarlet s:SynPHPMatchGroups = {'phpparent':1, 'delimiter':1, 'define':1, 'storageclass':1, 'structure':1, 'exception':1}
4549ff7011bSBram Moolenaarfunction! IslinePHP (lnum, tofind) " {{{
4559ff7011bSBram Moolenaar    let cline = getline(a:lnum)
4569ff7011bSBram Moolenaar
4579ff7011bSBram Moolenaar    if a:tofind==""
458bcb9898eSBram Moolenaar	let tofind = "^\\s*[\"'`]*\\s*\\zs\\S"
4599ff7011bSBram Moolenaar    else
4609ff7011bSBram Moolenaar	let tofind = a:tofind
4619ff7011bSBram Moolenaar    endif
4629ff7011bSBram Moolenaar
4631e015460SBram Moolenaar    let tofind = tofind . '\c'
4649ff7011bSBram Moolenaar
4651e015460SBram Moolenaar    let coltotest = match (cline, tofind) + 1
4669ff7011bSBram Moolenaar
4671e015460SBram Moolenaar    let synname = synIDattr(synID(a:lnum, coltotest, 0), "name")
4689ff7011bSBram Moolenaar
4690b0f0992SBram Moolenaar    if synname ==? 'phpStringSingle' || synname ==? 'phpStringDouble' || synname ==? 'phpBacktick'
4705477506aSBram Moolenaar	if cline !~ '^\s*[''"`]' " ??? XXX
471ed32d942SBram Moolenaar	    return "SpecStringEntrails"
472bcb9898eSBram Moolenaar	else
473bcb9898eSBram Moolenaar	    return synname
474bcb9898eSBram Moolenaar	end
475bcb9898eSBram Moolenaar    end
476bcb9898eSBram Moolenaar
4770b0f0992SBram Moolenaar    if get(s:SynPHPMatchGroups, tolower(synname)) || synname =~ '^php' ||  synname =~? '^javaScript'
4789ff7011bSBram Moolenaar	return synname
4799ff7011bSBram Moolenaar    else
4809ff7011bSBram Moolenaar	return ""
481071d4279SBram Moolenaar    endif
4821e015460SBram Moolenaarendfunction " }}}
4839ff7011bSBram Moolenaar
4845c73622aSBram Moolenaarlet s:autoresetoptions = 0
4855c73622aSBram Moolenaarif ! s:autoresetoptions
4865c73622aSBram Moolenaar    let s:autoresetoptions = 1
4879ff7011bSBram Moolenaarendif
4889ff7011bSBram Moolenaar
4895c73622aSBram Moolenaarfunction! ResetPhpOptions()
490ed32d942SBram Moolenaar    if ! b:optionsset && &filetype =~ "php"
491a5792f58SBram Moolenaar	if b:PHP_autoformatcomment
492a5792f58SBram Moolenaar
493a5792f58SBram Moolenaar	    setlocal comments=s1:/*,mb:*,ex:*/,://,:#
494a5792f58SBram Moolenaar
495c236c16dSBram Moolenaar	    setlocal formatoptions-=t
496a5792f58SBram Moolenaar	    setlocal formatoptions+=q
497a5792f58SBram Moolenaar	    setlocal formatoptions+=r
498a5792f58SBram Moolenaar	    setlocal formatoptions+=o
499a5792f58SBram Moolenaar	    setlocal formatoptions+=c
500a5792f58SBram Moolenaar	    setlocal formatoptions+=b
501a5792f58SBram Moolenaar	endif
5029ff7011bSBram Moolenaar	let b:optionsset = 1
5039ff7011bSBram Moolenaar    endif
5049ff7011bSBram Moolenaarendfunc
5059ff7011bSBram Moolenaar
5065c73622aSBram Moolenaarcall ResetPhpOptions()
5075c73622aSBram Moolenaar
5080b0f0992SBram Moolenaarfunction! GetPhpIndentVersion()
5095477506aSBram Moolenaar    return "1.70-bundle"
5100b0f0992SBram Moolenaarendfun
5110b0f0992SBram Moolenaar
5129ff7011bSBram Moolenaarfunction! GetPhpIndent()
5139ff7011bSBram Moolenaar
51405a7bb36SBram Moolenaar    let b:GetLastRealCodeLNum_ADD = 0
51505a7bb36SBram Moolenaar
5169ff7011bSBram Moolenaar    let UserIsEditing=0
5179ff7011bSBram Moolenaar    if	b:PHP_oldchangetick != b:changedtick
5189ff7011bSBram Moolenaar	let b:PHP_oldchangetick = b:changedtick
5199ff7011bSBram Moolenaar	let UserIsEditing=1
5209ff7011bSBram Moolenaar    endif
5219ff7011bSBram Moolenaar
5229ff7011bSBram Moolenaar    if b:PHP_default_indenting
5233ec574f2SBram Moolenaar	let b:PHP_default_indenting = g:PHP_default_indenting * shiftwidth()
5249ff7011bSBram Moolenaar    endif
5259ff7011bSBram Moolenaar
5261e015460SBram Moolenaar    let cline = getline(v:lnum)
5279ff7011bSBram Moolenaar
5289ff7011bSBram Moolenaar    if !b:PHP_indentinghuge && b:PHP_lastindented > b:PHP_indentbeforelast
5299ff7011bSBram Moolenaar	if b:PHP_indentbeforelast
5309ff7011bSBram Moolenaar	    let b:PHP_indentinghuge = 1
5319ff7011bSBram Moolenaar	endif
5329ff7011bSBram Moolenaar	let b:PHP_indentbeforelast = b:PHP_lastindented
5339ff7011bSBram Moolenaar    endif
5349ff7011bSBram Moolenaar
5359ff7011bSBram Moolenaar    if b:InPHPcode_checked && prevnonblank(v:lnum - 1) != b:PHP_lastindented
5369ff7011bSBram Moolenaar	if b:PHP_indentinghuge
5379ff7011bSBram Moolenaar	    let b:PHP_indentinghuge = 0
5389ff7011bSBram Moolenaar	    let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
5399ff7011bSBram Moolenaar	endif
540ed32d942SBram Moolenaar	let real_PHP_lastindented = v:lnum
5419ff7011bSBram Moolenaar	let b:PHP_LastIndentedWasComment=0
5429ff7011bSBram Moolenaar	let b:PHP_InsideMultilineComment=0
5439ff7011bSBram Moolenaar	let b:PHP_indentbeforelast = 0
5449ff7011bSBram Moolenaar
5459ff7011bSBram Moolenaar	let b:InPHPcode = 0
5469ff7011bSBram Moolenaar	let b:InPHPcode_checked = 0
5479ff7011bSBram Moolenaar	let b:InPHPcode_and_script = 0
5489ff7011bSBram Moolenaar	let b:InPHPcode_tofind = ""
5499ff7011bSBram Moolenaar
5501e015460SBram Moolenaar    elseif v:lnum > b:PHP_lastindented
5519ff7011bSBram Moolenaar	let real_PHP_lastindented = b:PHP_lastindented
552ed32d942SBram Moolenaar    else
553ed32d942SBram Moolenaar	let real_PHP_lastindented = v:lnum
5549ff7011bSBram Moolenaar    endif
5559ff7011bSBram Moolenaar
556ed32d942SBram Moolenaar    let b:PHP_lastindented = v:lnum
557ed32d942SBram Moolenaar
5589ff7011bSBram Moolenaar
5599ff7011bSBram Moolenaar    if !b:InPHPcode_checked " {{{ One time check
5609ff7011bSBram Moolenaar	let b:InPHPcode_checked = 1
561cbebd487SBram Moolenaar	let b:UserIsTypingComment = 0
5629ff7011bSBram Moolenaar
56305a7bb36SBram Moolenaar	let synname = ""
56405a7bb36SBram Moolenaar	if cline !~ '<?.*?>'
5651e015460SBram Moolenaar	    let synname = IslinePHP (prevnonblank(v:lnum), "")
56605a7bb36SBram Moolenaar	endif
5679ff7011bSBram Moolenaar
5689ff7011bSBram Moolenaar	if synname!=""
5690b0f0992SBram Moolenaar	    if synname ==? "SpecStringEntrails"
570e0720cbfSBram Moolenaar		let b:InPHPcode = -1 " thumb down
571ed32d942SBram Moolenaar		let b:InPHPcode_tofind = ""
5720b0f0992SBram Moolenaar	    elseif synname !=? "phpHereDoc" && synname !=? "phpHereDocDelimiter"
5739ff7011bSBram Moolenaar		let b:InPHPcode = 1
5749ff7011bSBram Moolenaar		let b:InPHPcode_tofind = ""
5759ff7011bSBram Moolenaar
5760b0f0992SBram Moolenaar		if synname =~? '^php\%(Doc\)\?Comment'
5779ff7011bSBram Moolenaar		    let b:UserIsTypingComment = 1
578cbebd487SBram Moolenaar		    let b:InPHPcode_checked = 0
5799ff7011bSBram Moolenaar		endif
5809ff7011bSBram Moolenaar
5819ff7011bSBram Moolenaar		if synname =~? '^javaScript'
5829ff7011bSBram Moolenaar		    let b:InPHPcode_and_script = 1
5839ff7011bSBram Moolenaar		endif
5849ff7011bSBram Moolenaar
5859ff7011bSBram Moolenaar	    else
5869ff7011bSBram Moolenaar		let b:InPHPcode = 0
5879ff7011bSBram Moolenaar
5889ff7011bSBram Moolenaar		let lnum = v:lnum - 1
589cbebd487SBram Moolenaar		while getline(lnum) !~? '<<<\s*[''"]\=\a\w*[''"]\=$' && lnum > 1
5909ff7011bSBram Moolenaar		    let lnum = lnum - 1
5919ff7011bSBram Moolenaar		endwhile
5929ff7011bSBram Moolenaar
593cbebd487SBram Moolenaar		let b:InPHPcode_tofind = substitute( getline(lnum), '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '')
5949ff7011bSBram Moolenaar	    endif
5951e015460SBram Moolenaar	else
5969ff7011bSBram Moolenaar	    let b:InPHPcode = 0
597e6ae6225SBram Moolenaar	    let b:InPHPcode_tofind = s:PHP_startindenttag
5989ff7011bSBram Moolenaar	endif
5999ff7011bSBram Moolenaar    endif "!b:InPHPcode_checked }}}
6009ff7011bSBram Moolenaar
6019ff7011bSBram Moolenaar
6021e015460SBram Moolenaar    " Test if we are indenting PHP code {{{
6039ff7011bSBram Moolenaar    let lnum = prevnonblank(v:lnum - 1)
6049ff7011bSBram Moolenaar    let last_line = getline(lnum)
605bcb9898eSBram Moolenaar    let endline= s:endline
6069ff7011bSBram Moolenaar
6079ff7011bSBram Moolenaar    if b:InPHPcode_tofind!=""
6089ff7011bSBram Moolenaar	if cline =~? b:InPHPcode_tofind
6099ff7011bSBram Moolenaar	    let b:InPHPcode_tofind = ""
6109ff7011bSBram Moolenaar	    let b:UserIsTypingComment = 0
611ed32d942SBram Moolenaar
612ed32d942SBram Moolenaar	    if b:InPHPcode == -1
613ed32d942SBram Moolenaar		let b:InPHPcode = 1
614ed32d942SBram Moolenaar		return -1
615ed32d942SBram Moolenaar	    end
616ed32d942SBram Moolenaar
617ed32d942SBram Moolenaar	    let b:InPHPcode = 1
618ed32d942SBram Moolenaar
6191e015460SBram Moolenaar	    if cline =~ '\*/'
6209ff7011bSBram Moolenaar		call cursor(v:lnum, 1)
6211e015460SBram Moolenaar		if cline !~ '^\*/'
6221e015460SBram Moolenaar		    call search('\*/', 'W')
6231e015460SBram Moolenaar		endif
624a5792f58SBram Moolenaar		let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
6259ff7011bSBram Moolenaar
6269ff7011bSBram Moolenaar		let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
6271e015460SBram Moolenaar
6281e015460SBram Moolenaar		let b:PHP_LastIndentedWasComment = 0
6299ff7011bSBram Moolenaar
6309ff7011bSBram Moolenaar		if cline =~ '^\s*\*/'
6319ff7011bSBram Moolenaar		    return indent(lnum) + 1
6329ff7011bSBram Moolenaar		else
6339ff7011bSBram Moolenaar		    return indent(lnum)
6349ff7011bSBram Moolenaar		endif
6359ff7011bSBram Moolenaar
6361e015460SBram Moolenaar	    elseif cline =~? '<script\>'
6379ff7011bSBram Moolenaar		let b:InPHPcode_and_script = 1
63805a7bb36SBram Moolenaar		let b:GetLastRealCodeLNum_ADD = v:lnum
6399ff7011bSBram Moolenaar	    endif
6409ff7011bSBram Moolenaar	endif
6419ff7011bSBram Moolenaar    endif
6429ff7011bSBram Moolenaar
643ed32d942SBram Moolenaar    if 1 == b:InPHPcode
6449ff7011bSBram Moolenaar
6450b0f0992SBram Moolenaar	if !b:InPHPcode_and_script && last_line =~ '\%(<?.*\)\@<!?>\%(.*<?\)\@!' && IslinePHP(lnum, '?>')=~?"Delimiter"
6469ff7011bSBram Moolenaar	    if cline !~? s:PHP_startindenttag
6479ff7011bSBram Moolenaar		let b:InPHPcode = 0
6489ff7011bSBram Moolenaar		let b:InPHPcode_tofind = s:PHP_startindenttag
6499ff7011bSBram Moolenaar	    elseif cline =~? '<script\>'
6509ff7011bSBram Moolenaar		let b:InPHPcode_and_script = 1
6519ff7011bSBram Moolenaar	    endif
6529ff7011bSBram Moolenaar
6535477506aSBram Moolenaar	elseif last_line =~ '^[^''"`]\+[''"`]$' && last_line !~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)' " a string identifier with nothing after it and no other string identifier before
654ed32d942SBram Moolenaar	    let b:InPHPcode = -1
655bcb9898eSBram Moolenaar	    let b:InPHPcode_tofind = substitute( last_line, '^.*\([''"`]\).*$', '^[^\1]*\1[;,]$', '')
656cbebd487SBram Moolenaar	elseif last_line =~? '<<<\s*[''"]\=\a\w*[''"]\=$'
6579ff7011bSBram Moolenaar	    let b:InPHPcode = 0
658cbebd487SBram Moolenaar	    let b:InPHPcode_tofind = substitute( last_line, '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '')
6599ff7011bSBram Moolenaar
6601e015460SBram Moolenaar	elseif !UserIsEditing && cline =~ '^\s*/\*\%(.*\*/\)\@!' && getline(v:lnum + 1) !~ '^\s*\*'
6619ff7011bSBram Moolenaar	    let b:InPHPcode = 0
6629ff7011bSBram Moolenaar	    let b:InPHPcode_tofind = '\*/'
6639ff7011bSBram Moolenaar
6649ff7011bSBram Moolenaar	elseif cline =~? '^\s*</script>'
6659ff7011bSBram Moolenaar	    let b:InPHPcode = 0
6669ff7011bSBram Moolenaar	    let b:InPHPcode_tofind = s:PHP_startindenttag
6679ff7011bSBram Moolenaar	endif
6689ff7011bSBram Moolenaar    endif " }}}
6699ff7011bSBram Moolenaar
67005a7bb36SBram Moolenaar
671ed32d942SBram Moolenaar    if 1 > b:InPHPcode && !b:InPHPcode_and_script
6729ff7011bSBram Moolenaar	return -1
6739ff7011bSBram Moolenaar    endif
6749ff7011bSBram Moolenaar
6759ff7011bSBram Moolenaar    " Indent successive // or # comment the same way the first is {{{
676e6ae6225SBram Moolenaar    let addSpecial = 0
6779ff7011bSBram Moolenaar    if cline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)'
678e6ae6225SBram Moolenaar	let addSpecial = b:PHP_outdentSLComments
6799ff7011bSBram Moolenaar	if b:PHP_LastIndentedWasComment == 1
6801e015460SBram Moolenaar	    return indent(real_PHP_lastindented)
6819ff7011bSBram Moolenaar	endif
6829ff7011bSBram Moolenaar	let b:PHP_LastIndentedWasComment = 1
6839ff7011bSBram Moolenaar    else
6849ff7011bSBram Moolenaar	let b:PHP_LastIndentedWasComment = 0
6851e015460SBram Moolenaar    endif " }}}
6869ff7011bSBram Moolenaar
6879ff7011bSBram Moolenaar    " Indent multiline /* comments correctly {{{
6889ff7011bSBram Moolenaar
6899ff7011bSBram Moolenaar    if b:PHP_InsideMultilineComment || b:UserIsTypingComment
6901e015460SBram Moolenaar	if cline =~ '^\s*\*\%(\/\)\@!'
6911e015460SBram Moolenaar	    if last_line =~ '^\s*/\*'
6929ff7011bSBram Moolenaar		return indent(lnum) + 1
6939ff7011bSBram Moolenaar	    else
6949ff7011bSBram Moolenaar		return indent(lnum)
6959ff7011bSBram Moolenaar	    endif
6969ff7011bSBram Moolenaar	else
6979ff7011bSBram Moolenaar	    let b:PHP_InsideMultilineComment = 0
6989ff7011bSBram Moolenaar	endif
6999ff7011bSBram Moolenaar    endif
7009ff7011bSBram Moolenaar
701ed32d942SBram Moolenaar    if !b:PHP_InsideMultilineComment && cline =~ '^\s*/\*\%(.*\*/\)\@!'
70205a7bb36SBram Moolenaar	if getline(v:lnum + 1) !~ '^\s*\*'
7039ff7011bSBram Moolenaar	    return -1
70405a7bb36SBram Moolenaar	endif
70505a7bb36SBram Moolenaar	let b:PHP_InsideMultilineComment = 1
7061e015460SBram Moolenaar    endif " }}}
7079ff7011bSBram Moolenaar
7081e015460SBram Moolenaar
7091e015460SBram Moolenaar    " Things always indented at col 1 (PHP delimiter: <?, ?>, Heredoc end) {{{
7108408a9adSBram Moolenaar    if cline =~# '^\s*<?' && cline !~ '?>' && b:PHP_outdentphpescape
7119ff7011bSBram Moolenaar	return 0
7129ff7011bSBram Moolenaar    endif
7139ff7011bSBram Moolenaar
7148408a9adSBram Moolenaar    if	cline =~ '^\s*?>' && cline !~# '<?' && b:PHP_outdentphpescape
7159ff7011bSBram Moolenaar	return 0
7169ff7011bSBram Moolenaar    endif
7179ff7011bSBram Moolenaar
718bcb9898eSBram Moolenaar    if cline =~? '^\s*\a\w*;$\|^\a\w*$\|^\s*[''"`][;,]' && cline !~? s:notPhpHereDoc
7199ff7011bSBram Moolenaar	return 0
7201e015460SBram Moolenaar    endif " }}}
7219ff7011bSBram Moolenaar
7229ff7011bSBram Moolenaar    let s:level = 0
7239ff7011bSBram Moolenaar
7249ff7011bSBram Moolenaar    let lnum = GetLastRealCodeLNum(v:lnum - 1)
72505a7bb36SBram Moolenaar
7261e015460SBram Moolenaar    let last_line = getline(lnum)
7271e015460SBram Moolenaar    let ind = indent(lnum)
7289ff7011bSBram Moolenaar
7299ff7011bSBram Moolenaar    if ind==0 && b:PHP_default_indenting
7309ff7011bSBram Moolenaar	let ind = b:PHP_default_indenting
7319ff7011bSBram Moolenaar    endif
7329ff7011bSBram Moolenaar
7339ff7011bSBram Moolenaar    if lnum == 0
734e6ae6225SBram Moolenaar	return b:PHP_default_indenting + addSpecial
7359ff7011bSBram Moolenaar    endif
7369ff7011bSBram Moolenaar
7379ff7011bSBram Moolenaar
7389ff7011bSBram Moolenaar    if cline =~ '^\s*}\%(}}\)\@!'
739bcb9898eSBram Moolenaar	let ind = indent(FindOpenBracket(v:lnum, 1))
7409ff7011bSBram Moolenaar	let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
7419ff7011bSBram Moolenaar	return ind
7429ff7011bSBram Moolenaar    endif
7439ff7011bSBram Moolenaar
7441e015460SBram Moolenaar    if cline =~ '^\s*\*/'
7459ff7011bSBram Moolenaar	call cursor(v:lnum, 1)
7461e015460SBram Moolenaar	if cline !~ '^\*/'
7471e015460SBram Moolenaar	    call search('\*/', 'W')
7481e015460SBram Moolenaar	endif
749a5792f58SBram Moolenaar	let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
7509ff7011bSBram Moolenaar
7519ff7011bSBram Moolenaar	let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
7529ff7011bSBram Moolenaar
7539ff7011bSBram Moolenaar	if cline =~ '^\s*\*/'
7549ff7011bSBram Moolenaar	    return indent(lnum) + 1
7559ff7011bSBram Moolenaar	else
7569ff7011bSBram Moolenaar	    return indent(lnum)
7579ff7011bSBram Moolenaar	endif
7589ff7011bSBram Moolenaar    endif
7599ff7011bSBram Moolenaar
7609ff7011bSBram Moolenaar
7615477506aSBram Moolenaar    if last_line =~ '[;}]'.endline && last_line !~ '^[)\]]' && last_line !~# s:defaultORcase && last_line !~ '^\s*[''"`][;,]'
7621e015460SBram Moolenaar	if ind==b:PHP_default_indenting
763e6ae6225SBram Moolenaar	    return b:PHP_default_indenting + addSpecial
7649ff7011bSBram Moolenaar	elseif b:PHP_indentinghuge && ind==b:PHP_CurrentIndentLevel && cline !~# '^\s*\%(else\|\%(case\|default\).*:\|[})];\=\)' && last_line !~# '^\s*\%(\%(}\s*\)\=else\)' && getline(GetLastRealCodeLNum(lnum - 1))=~';'.endline
765e6ae6225SBram Moolenaar	    return b:PHP_CurrentIndentLevel + addSpecial
7669ff7011bSBram Moolenaar	endif
7679ff7011bSBram Moolenaar    endif
7689ff7011bSBram Moolenaar
7691e015460SBram Moolenaar    let LastLineClosed = 0
7709ff7011bSBram Moolenaar
771bcb9898eSBram Moolenaar    let terminated = s:terminated
7729ff7011bSBram Moolenaar
773e0720cbfSBram Moolenaar    let unstated  = s:unstated
774e0720cbfSBram Moolenaar
7759ff7011bSBram Moolenaar
7769ff7011bSBram Moolenaar    if ind != b:PHP_default_indenting && cline =~# '^\s*else\%(if\)\=\>'
7771e015460SBram Moolenaar	let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
7789ff7011bSBram Moolenaar	return indent(FindTheIfOfAnElse(v:lnum, 1))
7798408a9adSBram Moolenaar    elseif cline =~# s:defaultORcase
7803ec574f2SBram Moolenaar	return FindTheSwitchIndent(v:lnum) + shiftwidth() * b:PHP_vintage_case_default_indent
781c236c16dSBram Moolenaar    elseif cline =~ '^\s*)\=\s*{'
7821e015460SBram Moolenaar	let previous_line = last_line
7831e015460SBram Moolenaar	let last_line_num = lnum
7841e015460SBram Moolenaar
7851e015460SBram Moolenaar	while last_line_num > 1
7861e015460SBram Moolenaar
787e0720cbfSBram Moolenaar	    if previous_line =~ terminated || previous_line =~ s:structureHead
7881e015460SBram Moolenaar
7891e015460SBram Moolenaar		let ind = indent(last_line_num)
7901e015460SBram Moolenaar
7911e015460SBram Moolenaar		if  b:PHP_BracesAtCodeLevel
7923ec574f2SBram Moolenaar		    let ind = ind + shiftwidth()
7931e015460SBram Moolenaar		endif
7941e015460SBram Moolenaar
7951e015460SBram Moolenaar		return ind
7961e015460SBram Moolenaar	    endif
7971e015460SBram Moolenaar
798bcb9898eSBram Moolenaar	    let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
7991e015460SBram Moolenaar	    let previous_line = getline(last_line_num)
8001e015460SBram Moolenaar	endwhile
8010b0f0992SBram Moolenaar    elseif cline =~ '^\s*->'
8020b0f0992SBram Moolenaar	return FindArrowIndent(lnum)
803c236c16dSBram Moolenaar    elseif last_line =~# unstated && cline !~ '^\s*);\='.endline
8043ec574f2SBram Moolenaar	let ind = ind + shiftwidth() " we indent one level further when the preceding line is not stated
805e6ae6225SBram Moolenaar	return ind + addSpecial
8069ff7011bSBram Moolenaar
807ed32d942SBram Moolenaar    elseif (ind != b:PHP_default_indenting || last_line =~ '^[)\]]' ) && last_line =~ terminated
8089ff7011bSBram Moolenaar	let previous_line = last_line
8099ff7011bSBram Moolenaar	let last_line_num = lnum
8109ff7011bSBram Moolenaar	let LastLineClosed = 1
8119ff7011bSBram Moolenaar
812bcb9898eSBram Moolenaar	let isSingleLineBlock = 0
8139ff7011bSBram Moolenaar	while 1
8140b0f0992SBram Moolenaar	    if ! isSingleLineBlock && previous_line =~ '^\s*}\|;\s*}'.endline
8159ff7011bSBram Moolenaar
816e6ae6225SBram Moolenaar		call cursor(last_line_num, 1)
817bcb9898eSBram Moolenaar		if previous_line !~ '^}'
818bcb9898eSBram Moolenaar		    call search('}\|;\s*}'.endline, 'W')
819bcb9898eSBram Moolenaar		end
820e6ae6225SBram Moolenaar		let oldLastLine = last_line_num
821e6ae6225SBram Moolenaar		let last_line_num = searchpair('{', '', '}', 'bW', 'Skippmatch()')
822e6ae6225SBram Moolenaar
823bcb9898eSBram Moolenaar		if getline(last_line_num) =~ '^\s*{'
8249ff7011bSBram Moolenaar		    let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
825bcb9898eSBram Moolenaar		elseif oldLastLine == last_line_num
826bcb9898eSBram Moolenaar		    let isSingleLineBlock = 1
827bcb9898eSBram Moolenaar		    continue
8289ff7011bSBram Moolenaar		endif
8299ff7011bSBram Moolenaar
8309ff7011bSBram Moolenaar		let previous_line = getline(last_line_num)
8319ff7011bSBram Moolenaar
8329ff7011bSBram Moolenaar		continue
8339ff7011bSBram Moolenaar	    else
834bcb9898eSBram Moolenaar		let isSingleLineBlock = 0
8351e015460SBram Moolenaar
8369ff7011bSBram Moolenaar		if getline(last_line_num) =~# '^\s*else\%(if\)\=\>'
8379ff7011bSBram Moolenaar		    let last_line_num = FindTheIfOfAnElse(last_line_num, 0)
8381e015460SBram Moolenaar		    continue
8399ff7011bSBram Moolenaar		endif
8409ff7011bSBram Moolenaar
8419ff7011bSBram Moolenaar
8421e015460SBram Moolenaar		let last_match = last_line_num
8439ff7011bSBram Moolenaar
8449ff7011bSBram Moolenaar		let one_ahead_indent = indent(last_line_num)
8459ff7011bSBram Moolenaar		let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
8469ff7011bSBram Moolenaar		let two_ahead_indent = indent(last_line_num)
8479ff7011bSBram Moolenaar		let after_previous_line = previous_line
8489ff7011bSBram Moolenaar		let previous_line = getline(last_line_num)
8499ff7011bSBram Moolenaar
8509ff7011bSBram Moolenaar
8518408a9adSBram Moolenaar		if previous_line =~# s:defaultORcase.'\|{'.endline
8529ff7011bSBram Moolenaar		    break
8539ff7011bSBram Moolenaar		endif
8549ff7011bSBram Moolenaar
8559ff7011bSBram Moolenaar		if after_previous_line=~# '^\s*'.s:blockstart.'.*)'.endline && previous_line =~# '[;}]'.endline
8569ff7011bSBram Moolenaar		    break
8579ff7011bSBram Moolenaar		endif
8589ff7011bSBram Moolenaar
8599ff7011bSBram Moolenaar		if one_ahead_indent == two_ahead_indent || last_line_num < 1
860c236c16dSBram Moolenaar		    if previous_line =~# '\%(;\|^\s*}\)'.endline || last_line_num < 1
8619ff7011bSBram Moolenaar			break
8629ff7011bSBram Moolenaar		    endif
8639ff7011bSBram Moolenaar		endif
8649ff7011bSBram Moolenaar	    endif
8659ff7011bSBram Moolenaar	endwhile
8669ff7011bSBram Moolenaar
8671e015460SBram Moolenaar	if indent(last_match) != ind
8681e015460SBram Moolenaar	    let ind = indent(last_match)
8691e015460SBram Moolenaar	    let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
8709ff7011bSBram Moolenaar
871e6ae6225SBram Moolenaar	    return ind + addSpecial
8729ff7011bSBram Moolenaar	endif
8739ff7011bSBram Moolenaar    endif
8749ff7011bSBram Moolenaar
875ed32d942SBram Moolenaar    if (last_line !~ '^\s*}\%(}}\)\@!')
8769ff7011bSBram Moolenaar	let plinnum = GetLastRealCodeLNum(lnum - 1)
877ed32d942SBram Moolenaar    else
878ed32d942SBram Moolenaar	let plinnum = GetLastRealCodeLNum(FindOpenBracket(lnum, 1) - 1)
879ed32d942SBram Moolenaar    endif
880ed32d942SBram Moolenaar
8818408a9adSBram Moolenaar    let AntepenultimateLine = getline(plinnum)
8829ff7011bSBram Moolenaar
8830b0f0992SBram Moolenaar    let last_line = StripEndlineComments(last_line)
8849ff7011bSBram Moolenaar
8859ff7011bSBram Moolenaar    if ind == b:PHP_default_indenting
886ed32d942SBram Moolenaar	if last_line =~ terminated && last_line !~# s:defaultORcase
8879ff7011bSBram Moolenaar	    let LastLineClosed = 1
8889ff7011bSBram Moolenaar	endif
8899ff7011bSBram Moolenaar    endif
8909ff7011bSBram Moolenaar
8911e015460SBram Moolenaar    if !LastLineClosed
8921e015460SBram Moolenaar
8930b0f0992SBram Moolenaar	let openedparent = -1
8940b0f0992SBram Moolenaar
8955c73622aSBram Moolenaar
896e0720cbfSBram Moolenaar	if last_line =~# '[{(\[]'.endline || last_line =~? '\h\w*\s*(.*,$' && AntepenultimateLine !~ '[,(\[]'.endline && BalanceDirection(last_line) > 0
8979ff7011bSBram Moolenaar
898bcb9898eSBram Moolenaar	    let dontIndent = 0
8990b0f0992SBram Moolenaar	    if last_line =~ '\S\+\s*{'.endline && last_line !~ '^\s*[)\]]\+\(\s*:\s*'.s:PHP_validVariable.'\)\=\s*{'.endline && last_line !~ s:structureHead
900bcb9898eSBram Moolenaar		let dontIndent = 1
901bcb9898eSBram Moolenaar	    endif
902bcb9898eSBram Moolenaar
903bcb9898eSBram Moolenaar	    if !dontIndent && (!b:PHP_BracesAtCodeLevel || last_line !~# '^\s*{')
9043ec574f2SBram Moolenaar		let ind = ind + shiftwidth()
9059ff7011bSBram Moolenaar	    endif
9069ff7011bSBram Moolenaar
9075477506aSBram Moolenaar	    if b:PHP_IndentFunctionCallParameters && last_line =~ s:multilineFunctionCall && last_line !~ s:structureHead && last_line !~ s:arrayDecl
9085477506aSBram Moolenaar		let ind = ind + b:PHP_IndentFunctionCallParameters * shiftwidth()
9095477506aSBram Moolenaar	    endif
9105477506aSBram Moolenaar
9115477506aSBram Moolenaar	    if b:PHP_IndentFunctionDeclarationParameters && last_line =~ s:multilineFunctionDecl
9125477506aSBram Moolenaar		let ind = ind + b:PHP_IndentFunctionDeclarationParameters * shiftwidth()
9135477506aSBram Moolenaar	    endif
9145477506aSBram Moolenaar
9158408a9adSBram Moolenaar	    if b:PHP_BracesAtCodeLevel || b:PHP_vintage_case_default_indent == 1
9169ff7011bSBram Moolenaar		let b:PHP_CurrentIndentLevel = ind
917c236c16dSBram Moolenaar
9189ff7011bSBram Moolenaar	    endif
9199ff7011bSBram Moolenaar
9200b0f0992SBram Moolenaar	elseif last_line =~ '),'.endline && BalanceDirection(last_line) < 0
9219ff7011bSBram Moolenaar	    call cursor(lnum, 1)
9220b0f0992SBram Moolenaar	    call searchpos('),'.endline, 'cW')
9239ff7011bSBram Moolenaar	    let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()')
9249ff7011bSBram Moolenaar	    if openedparent != lnum
9259ff7011bSBram Moolenaar		let ind = indent(openedparent)
9269ff7011bSBram Moolenaar	    endif
9278408a9adSBram Moolenaar
9280b0f0992SBram Moolenaar	elseif last_line =~ s:structureHead
9293ec574f2SBram Moolenaar	    let ind = ind + shiftwidth()
9309ff7011bSBram Moolenaar
931c236c16dSBram Moolenaar
932e0720cbfSBram Moolenaar	elseif AntepenultimateLine =~ '{'.endline && AntepenultimateLine !~? '^\s*use\>' || AntepenultimateLine =~ terminated || AntepenultimateLine =~# s:defaultORcase
9333ec574f2SBram Moolenaar	    let ind = ind + shiftwidth()
934c236c16dSBram Moolenaar	endif
935c236c16dSBram Moolenaar
9360b0f0992SBram Moolenaar
9370b0f0992SBram Moolenaar	if openedparent >= 0
9380b0f0992SBram Moolenaar	    let last_line = StripEndlineComments(getline(openedparent))
9390b0f0992SBram Moolenaar	endif
9409ff7011bSBram Moolenaar    endif
9419ff7011bSBram Moolenaar
942e6ae6225SBram Moolenaar    if cline =~ '^\s*[)\]];\='
9435477506aSBram Moolenaar	call cursor(v:lnum, 1)
9445477506aSBram Moolenaar	call searchpos('[)\]]', 'cW')
9455477506aSBram Moolenaar	let matchedBlockChar = cline[col('.')-1]
9465477506aSBram Moolenaar	let openedparent = searchpair('\M'.s:blockCharsLUT[matchedBlockChar], '', '\M'.matchedBlockChar, 'bW', 'Skippmatch()')
9475477506aSBram Moolenaar	if openedparent != v:lnum
9485477506aSBram Moolenaar	    let ind = indent(openedparent)
9499ff7011bSBram Moolenaar	endif
9509ff7011bSBram Moolenaar
9515477506aSBram Moolenaar    elseif last_line =~ '^\s*->' && last_line !~? s:structureHead && BalanceDirection(last_line) <= 0
9520b0f0992SBram Moolenaar	let ind = ind - shiftwidth()
9530b0f0992SBram Moolenaar    endif
9540b0f0992SBram Moolenaar
9559ff7011bSBram Moolenaar    let b:PHP_CurrentIndentLevel = ind
956e6ae6225SBram Moolenaar    return ind + addSpecial
9579ff7011bSBram Moolenaarendfunction
958