blob: 350accaa111df51117ec5c69e7f84790c3df924d [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001" Vim indent file
2" Language: PHP
Bram Moolenaar54775062019-07-31 21:07:14 +02003" Author: John Wellesz <John.wellesz (AT) gmail (DOT) com>
4" URL: https://www.2072productions.com/vim/indent/php.vim
Bram Moolenaare6ae6222013-05-21 21:01:10 +02005" Home: https://github.com/2072/PHP-Indenting-for-VIm
Bram Moolenaarb17893a2020-03-14 08:19:51 +01006" Last Change: 2020 Mar 05
dkearns0382f052023-08-29 05:32:59 +10007" 2023 Aug 28 by Vim Project (undo_indent)
Bram Moolenaar54775062019-07-31 21:07:14 +02008" Version: 1.70
Bram Moolenaar071d4272004-06-13 20:20:40 +00009"
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000010"
Bram Moolenaare6ae6222013-05-21 21:01:10 +020011" Type :help php-indent for available options
12"
13" A fully commented version of this file is available on github
Bram Moolenaara5792f52005-11-23 21:25:05 +000014"
15"
Bram Moolenaar259f26a2018-05-15 22:25:40 +020016" If you find a bug, please open a ticket on github.com
Bram Moolenaare6ae6222013-05-21 21:01:10 +020017" ( https://github.com/2072/PHP-Indenting-for-VIm/issues ) with an example of
18" code that breaks the algorithm.
Bram Moolenaar9ff70112005-07-11 22:29:03 +000019"
Bram Moolenaare6ae6222013-05-21 21:01:10 +020020
Bram Moolenaar9ff70112005-07-11 22:29:03 +000021" NOTE: This script must be used with PHP syntax ON and with the php syntax
Bram Moolenaare6ae6222013-05-21 21:01:10 +020022" script by Lutz Eymers (http://www.isp.de/data/php.vim ) or with the
Bram Moolenaar54775062019-07-31 21:07:14 +020023" script by Peter Hodge (https://www.vim.org/scripts/script.php?script_id=1571 )
Bram Moolenaar5c736222010-01-06 20:54:52 +010024" the later is bunbdled by default with Vim 7.
Bram Moolenaar9ff70112005-07-11 22:29:03 +000025"
26"
Bram Moolenaarc236c162008-07-13 17:41:49 +000027" In the case you have syntax errors in your script such as HereDoc end
28" identifiers not at col 1 you'll have to indent your file 2 times (This
29" script will automatically put HereDoc end identifiers at col 1 if
30" they are followed by a ';').
Bram Moolenaarc9b4b052006-04-30 18:54:39 +000031"
Bram Moolenaare6ae6222013-05-21 21:01:10 +020032
Bram Moolenaar5c736222010-01-06 20:54:52 +010033" NOTE: If you are editing files in Unix file format and that (by accident)
34" there are '\r' before new lines, this script won't be able to proceed
35" correctly and will make many mistakes because it won't be able to match
36" '\s*$' correctly.
37" So you have to remove those useless characters first with a command like:
Bram Moolenaar9ff70112005-07-11 22:29:03 +000038"
Bram Moolenaar5c736222010-01-06 20:54:52 +010039" :%s /\r$//g
Bram Moolenaar9ff70112005-07-11 22:29:03 +000040"
Bram Moolenaar5c736222010-01-06 20:54:52 +010041" or simply 'let' the option PHP_removeCRwhenUnix to 1 and the script will
42" silently remove them when VIM load this script (at each bufread).
Bram Moolenaarbcb98982014-05-01 14:08:19 +020043
44
Bram Moolenaar071d4272004-06-13 20:20:40 +000045if exists("b:did_indent")
Bram Moolenaar1e015462005-09-25 22:16:38 +000046 finish
Bram Moolenaar071d4272004-06-13 20:20:40 +000047endif
48let b:did_indent = 1
49
Bram Moolenaar9ff70112005-07-11 22:29:03 +000050
Bram Moolenaared32d942014-12-06 23:33:00 +010051let g:php_sync_method = 0
Bram Moolenaar9ff70112005-07-11 22:29:03 +000052
Bram Moolenaare6ae6222013-05-21 21:01:10 +020053
Bram Moolenaar9ff70112005-07-11 22:29:03 +000054if exists("PHP_default_indenting")
Bram Moolenaar3ec574f2017-06-13 18:12:01 +020055 let b:PHP_default_indenting = PHP_default_indenting * shiftwidth()
Bram Moolenaar9ff70112005-07-11 22:29:03 +000056else
Bram Moolenaar1e015462005-09-25 22:16:38 +000057 let b:PHP_default_indenting = 0
Bram Moolenaar9ff70112005-07-11 22:29:03 +000058endif
59
Bram Moolenaare6ae6222013-05-21 21:01:10 +020060if exists("PHP_outdentSLComments")
Bram Moolenaar3ec574f2017-06-13 18:12:01 +020061 let b:PHP_outdentSLComments = PHP_outdentSLComments * shiftwidth()
Bram Moolenaare6ae6222013-05-21 21:01:10 +020062else
63 let b:PHP_outdentSLComments = 0
64endif
65
Bram Moolenaar9ff70112005-07-11 22:29:03 +000066if exists("PHP_BracesAtCodeLevel")
Bram Moolenaar1e015462005-09-25 22:16:38 +000067 let b:PHP_BracesAtCodeLevel = PHP_BracesAtCodeLevel
Bram Moolenaar9ff70112005-07-11 22:29:03 +000068else
Bram Moolenaar1e015462005-09-25 22:16:38 +000069 let b:PHP_BracesAtCodeLevel = 0
Bram Moolenaar9ff70112005-07-11 22:29:03 +000070endif
71
Bram Moolenaarc236c162008-07-13 17:41:49 +000072
Bram Moolenaara5792f52005-11-23 21:25:05 +000073if exists("PHP_autoformatcomment")
74 let b:PHP_autoformatcomment = PHP_autoformatcomment
75else
76 let b:PHP_autoformatcomment = 1
77endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +000078
Bram Moolenaar8408a9a2010-07-30 22:41:22 +020079if exists("PHP_outdentphpescape")
80 let b:PHP_outdentphpescape = PHP_outdentphpescape
81else
82 let b:PHP_outdentphpescape = 1
83endif
84
Bram Moolenaar0b0f0992018-05-22 21:41:30 +020085if exists("PHP_noArrowMatching")
86 let b:PHP_noArrowMatching = PHP_noArrowMatching
87else
88 let b:PHP_noArrowMatching = 0
89endif
90
Bram Moolenaar8408a9a2010-07-30 22:41:22 +020091
92if exists("PHP_vintage_case_default_indent") && PHP_vintage_case_default_indent
93 let b:PHP_vintage_case_default_indent = 1
Bram Moolenaarc236c162008-07-13 17:41:49 +000094else
95 let b:PHP_vintage_case_default_indent = 0
96endif
97
Bram Moolenaar54775062019-07-31 21:07:14 +020098if exists("PHP_IndentFunctionCallParameters")
99 let b:PHP_IndentFunctionCallParameters = PHP_IndentFunctionCallParameters
100else
101 let b:PHP_IndentFunctionCallParameters = 0
102endif
Bram Moolenaarc236c162008-07-13 17:41:49 +0000103
Bram Moolenaar54775062019-07-31 21:07:14 +0200104if exists("PHP_IndentFunctionDeclarationParameters")
105 let b:PHP_IndentFunctionDeclarationParameters = PHP_IndentFunctionDeclarationParameters
106else
107 let b:PHP_IndentFunctionDeclarationParameters = 0
108endif
Bram Moolenaarc236c162008-07-13 17:41:49 +0000109
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000110let b:PHP_lastindented = 0
111let b:PHP_indentbeforelast = 0
112let b:PHP_indentinghuge = 0
113let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
114let b:PHP_LastIndentedWasComment = 0
115let b:PHP_InsideMultilineComment = 0
116let b:InPHPcode = 0
117let b:InPHPcode_checked = 0
118let b:InPHPcode_and_script = 0
119let b:InPHPcode_tofind = ""
120let b:PHP_oldchangetick = b:changedtick
121let b:UserIsTypingComment = 0
122let b:optionsset = 0
123
124setlocal nosmartindent
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000125setlocal noautoindent
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000126setlocal nocindent
Bram Moolenaar1e015462005-09-25 22:16:38 +0000127setlocal nolisp
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000128
Bram Moolenaar071d4272004-06-13 20:20:40 +0000129setlocal indentexpr=GetPhpIndent()
Bram Moolenaared32d942014-12-06 23:33:00 +0100130setlocal indentkeys=0{,0},0),0],:,!^F,o,O,e,*<Return>,=?>,=<?,=*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000131
dkearns0382f052023-08-29 05:32:59 +1000132let b:undo_indent = "setl ai< cin< inde< indk< lisp< si<"
Bram Moolenaar1e015462005-09-25 22:16:38 +0000133
134let s:searchpairflags = 'bWr'
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000135
136if &fileformat == "unix" && exists("PHP_removeCRwhenUnix") && PHP_removeCRwhenUnix
Bram Moolenaar1e015462005-09-25 22:16:38 +0000137 silent! %s/\r$//g
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000138endif
139
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140if exists("*GetPhpIndent")
Bram Moolenaar5c736222010-01-06 20:54:52 +0100141 call ResetPhpOptions()
Bram Moolenaar54775062019-07-31 21:07:14 +0200142 finish " XXX -- comment this line for easy dev
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143endif
144
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200145
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200146let s:endline = '\s*\%(//.*\|#.*\|/\*.*\*/\s*\)\=$'
Bram Moolenaar54775062019-07-31 21:07:14 +0200147let s:PHP_validVariable = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
148let s:notPhpHereDoc = '\%(break\|return\|continue\|exit\|die\|else\|end\%(if\|while\|for\|foreach\|switch\)\)'
149let 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\>\)'
150let s:functionDeclPrefix = '\<function\>\%(\s\+&\='.s:PHP_validVariable.'\)\=\s*('
151let s:functionDecl = s:functionDeclPrefix.'.*'
152let s:multilineFunctionDecl = s:functionDeclPrefix.s:endline
153let s:arrayDecl = '\<array\>\s*(.*'
154let s:multilineFunctionCall = s:PHP_validVariable.'\s*('.s:endline
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200155let s:unstated = '\%(^\s*'.s:blockstart.'.*)\|\%(//.*\)\@<!\<e'.'lse\>\)'.s:endline
Bram Moolenaared32d942014-12-06 23:33:00 +0100156
157
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200158let s:terminated = '\%(\%(;\%(\s*\%(?>\|}\)\)\=\|<<<\s*[''"]\=\a\w*[''"]\=$\|^\s*}\|^\s*'.s:PHP_validVariable.':\)'.s:endline.'\)'
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000159let s:PHP_startindenttag = '<?\%(.*?>\)\@!\|<script[^>]*>\%(.*<\/script>\)\@!'
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200160let s:structureHead = '^\s*\%(' . s:blockstart . '\)\|'. s:functionDecl . s:endline . '\|\<new\s\+class\>'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000162
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200163let s:escapeDebugStops = 0
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200164function! DebugPrintReturn(scriptLine)
165
Bram Moolenaared32d942014-12-06 23:33:00 +0100166 if ! s:escapeDebugStops
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200167 echo "debug:" . a:scriptLine
168 let c = getchar()
169 if c == "\<Del>"
170 let s:escapeDebugStops = 1
171 end
172 endif
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200173
174endfunction
175
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000176function! GetLastRealCodeLNum(startline) " {{{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000177
Bram Moolenaar1e015462005-09-25 22:16:38 +0000178 let lnum = a:startline
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000179
Bram Moolenaar05a7bb32006-01-19 22:09:32 +0000180 if b:GetLastRealCodeLNum_ADD && b:GetLastRealCodeLNum_ADD == lnum + 1
181 let lnum = b:GetLastRealCodeLNum_ADD
182 endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000183
Bram Moolenaar1e015462005-09-25 22:16:38 +0000184 while lnum > 1
185 let lnum = prevnonblank(lnum)
186 let lastline = getline(lnum)
187
188 if b:InPHPcode_and_script && lastline =~ '?>\s*$'
189 let lnum = lnum - 1
190 elseif lastline =~ '^\s*?>.*<?\%(php\)\=\s*$'
191 let lnum = lnum - 1
192 elseif lastline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)'
193 let lnum = lnum - 1
194 elseif lastline =~ '\*/\s*$'
195 call cursor(lnum, 1)
196 if lastline !~ '^\*/'
197 call search('\*/', 'W')
198 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000199 let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
Bram Moolenaar1e015462005-09-25 22:16:38 +0000200
201 let lastline = getline(lnum)
202 if lastline =~ '^\s*/\*'
203 let lnum = lnum - 1
204 else
205 break
206 endif
207
208
209 elseif lastline =~? '\%(//\s*\|?>.*\)\@<!<?\%(php\)\=\s*$\|^\s*<script\>'
210
211 while lastline !~ '\(<?.*\)\@<!?>' && lnum > 1
212 let lnum = lnum - 1
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000213 let lastline = getline(lnum)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000214 endwhile
215 if lastline =~ '^\s*?>'
216 let lnum = lnum - 1
217 else
218 break
219 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000220
221
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200222 elseif lastline =~? '^\a\w*;\=$' && lastline !~? s:notPhpHereDoc
Bram Moolenaarcbebd482016-02-07 23:02:56 +0100223 let tofind=substitute( lastline, '\(\a\w*\);\=', '<<<\\s*[''"]\\=\1[''"]\\=$', '')
Bram Moolenaar1e015462005-09-25 22:16:38 +0000224 while getline(lnum) !~? tofind && lnum > 1
225 let lnum = lnum - 1
226 endwhile
Bram Moolenaar54775062019-07-31 21:07:14 +0200227 elseif lastline =~ '^\s*[''"`][;,]' || (lastline =~ '^[^''"`]*[''"`][;,]'.s:endline && IslinePHP(lnum, "") == "SpecStringEntrails")
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200228
229 let tofind=substitute( lastline, '^.*\([''"`]\)[;,].*$', '^[^\1]\\+[\1]$\\|^[^\1]\\+[=([]\\s*[\1]', '')
230 let trylnum = lnum
231 while getline(trylnum) !~? tofind && trylnum > 1
232 let trylnum = trylnum - 1
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200233 endwhile
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200234
235 if trylnum == 1
236 break
237 else
238 if lastline =~ ';'.s:endline
239 while getline(trylnum) !~? s:terminated && getline(trylnum) !~? '{'.s:endline && trylnum > 1
240 let trylnum = prevnonblank(trylnum - 1)
241 endwhile
242
243
244 if trylnum == 1
245 break
246 end
247 end
248 let lnum = trylnum
249 end
Bram Moolenaar1e015462005-09-25 22:16:38 +0000250 else
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000251 break
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000252 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000253 endwhile
254
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200255 if lnum==1 && getline(lnum) !~ '<?'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000256 let lnum=0
257 endif
258
Bram Moolenaared32d942014-12-06 23:33:00 +0100259 if b:InPHPcode_and_script && 1 > b:InPHPcode
Bram Moolenaar1e015462005-09-25 22:16:38 +0000260 let b:InPHPcode_and_script = 0
261 endif
Bram Moolenaard5ab34b2007-05-05 17:15:44 +0000262
Bram Moolenaar1e015462005-09-25 22:16:38 +0000263 return lnum
264endfunction " }}}
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000265
Bram Moolenaara5792f52005-11-23 21:25:05 +0000266function! Skippmatch2()
267
268 let line = getline(".")
269
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200270 if line =~ "\\([\"']\\).*/\\*.*\\1" || line =~ '\%(//\|#\).*/\*'
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200271 return 1
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200272 else
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200273 return 0
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200274 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000275endfun
276
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200277function! Skippmatch() " {{{
Bram Moolenaar1e015462005-09-25 22:16:38 +0000278 let synname = synIDattr(synID(line("."), col("."), 0), "name")
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200279 if synname ==? "Delimiter" || synname ==? "phpRegionDelimiter" || synname =~? "^phpParent" || synname ==? "phpArrayParens" || synname =~? '^php\%(Block\|Brace\)' || synname ==? "javaScriptBraces" || synname =~? '^php\%(Doc\)\?Comment' && b:UserIsTypingComment
Bram Moolenaar1e015462005-09-25 22:16:38 +0000280 return 0
281 else
282 return 1
283 endif
284endfun " }}}
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000285
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200286function! FindOpenBracket(lnum, blockStarter) " {{{
Bram Moolenaar1e015462005-09-25 22:16:38 +0000287 call cursor(a:lnum, 1)
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200288 let line = searchpair('{', '', '}', 'bW', 'Skippmatch()')
289
290 if a:blockStarter == 1
Bram Moolenaared32d942014-12-06 23:33:00 +0100291 while line > 1
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200292 let linec = getline(line)
293
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200294 if linec =~ s:terminated || linec =~ s:structureHead
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200295 break
296 endif
297
298 let line = GetLastRealCodeLNum(line - 1)
299 endwhile
300 endif
301
302 return line
Bram Moolenaar1e015462005-09-25 22:16:38 +0000303endfun " }}}
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000304
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200305let s:blockChars = {'{':1, '[': 1, '(': 1, ')':-1, ']':-1, '}':-1}
Bram Moolenaar54775062019-07-31 21:07:14 +0200306let s:blockCharsLUT = {'{':'{', '}':'{', '[':'[', ']':'[', '(':'(', ')':'('}
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200307function! BalanceDirection (str)
308
Bram Moolenaar54775062019-07-31 21:07:14 +0200309 let balance = {'{':0, '[': 0, '(': 0, 'none':0}
310 let director = 'none'
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200311
312 for c in split(a:str, '\zs')
313 if has_key(s:blockChars, c)
Bram Moolenaar54775062019-07-31 21:07:14 +0200314 let balance[s:blockCharsLUT[c]] += s:blockChars[c]
315
316 if balance[s:blockCharsLUT[c]]
317 let director = s:blockCharsLUT[c]
318 endif
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200319 endif
320 endfor
321
Bram Moolenaar54775062019-07-31 21:07:14 +0200322 return balance[director]
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200323endfun
324
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200325function! StripEndlineComments (line)
326 return substitute(a:line,"\\(//\\|#\\)\\(\\(\\([^\"']*\\([\"']\\)[^\"']*\\5\\)\\+[^\"']*$\\)\\|\\([^\"']*$\\)\\)",'','')
327endfun
328
329function! FindArrowIndent (lnum) " {{{
330
Viktor Szépe3fc7a7e2023-08-23 21:20:00 +0200331 let parentArrowPos = -1
Bram Moolenaar54775062019-07-31 21:07:14 +0200332 let cursorPos = -1
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200333 let lnum = a:lnum
334 while lnum > 1
335 let last_line = getline(lnum)
336 if last_line =~ '^\s*->'
Viktor Szépe3fc7a7e2023-08-23 21:20:00 +0200337 let parentArrowPos = indent(a:lnum)
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200338 break
339 else
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200340
Bram Moolenaar54775062019-07-31 21:07:14 +0200341 if b:PHP_noArrowMatching
342 break
343 endif
344
345 let cleanedLnum = StripEndlineComments(last_line)
346
347 if cleanedLnum =~ ')'.s:endline
348 if BalanceDirection(cleanedLnum) <= 0
349 call cursor(lnum, 1)
350 call searchpos(')'.s:endline, 'cW', lnum)
351 let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()')
352 let cursorPos = col(".")
353 if openedparent != lnum
354 let lnum = openedparent
355 continue
356 else
357 endif
358 else
Viktor Szépe3fc7a7e2023-08-23 21:20:00 +0200359 let parentArrowPos = -1
Bram Moolenaar54775062019-07-31 21:07:14 +0200360 break
361 end
362 endif
363
364 if cleanedLnum =~ '->'
365 call cursor(lnum, cursorPos == -1 ? strwidth(cleanedLnum) : cursorPos)
Viktor Szépe3fc7a7e2023-08-23 21:20:00 +0200366 let parentArrowPos = searchpos('->', 'cWb', lnum)[1] - 1
Bram Moolenaar54775062019-07-31 21:07:14 +0200367
368 break
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200369 else
Viktor Szépe3fc7a7e2023-08-23 21:20:00 +0200370 let parentArrowPos = -1
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200371 break
372 endif
373 endif
374 endwhile
375
Viktor Szépe3fc7a7e2023-08-23 21:20:00 +0200376 if parentArrowPos == -1
377 let parentArrowPos = indent(lnum) + shiftwidth()
Bram Moolenaar54775062019-07-31 21:07:14 +0200378 end
379
Viktor Szépe3fc7a7e2023-08-23 21:20:00 +0200380 return parentArrowPos
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200381endfun "}}}
382
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000383function! FindTheIfOfAnElse (lnum, StopAfterFirstPrevElse) " {{{
Bram Moolenaar1e015462005-09-25 22:16:38 +0000384
385 if getline(a:lnum) =~# '^\s*}\s*else\%(if\)\=\>'
386 let beforeelse = a:lnum
387 else
388 let beforeelse = GetLastRealCodeLNum(a:lnum - 1)
389 endif
390
391 if !s:level
392 let s:iftoskip = 0
393 endif
394
395 if getline(beforeelse) =~# '^\s*\%(}\s*\)\=else\%(\s*if\)\@!\>'
396 let s:iftoskip = s:iftoskip + 1
397 endif
398
399 if getline(beforeelse) =~ '^\s*}'
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200400 let beforeelse = FindOpenBracket(beforeelse, 0)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000401
402 if getline(beforeelse) =~ '^\s*{'
403 let beforeelse = GetLastRealCodeLNum(beforeelse - 1)
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000404 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000405 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000406
407
Bram Moolenaar1e015462005-09-25 22:16:38 +0000408 if !s:iftoskip && a:StopAfterFirstPrevElse && getline(beforeelse) =~# '^\s*\%([}]\s*\)\=else\%(if\)\=\>'
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000409 return beforeelse
Bram Moolenaar1e015462005-09-25 22:16:38 +0000410 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000411
Bram Moolenaar1e015462005-09-25 22:16:38 +0000412 if getline(beforeelse) !~# '^\s*if\>' && beforeelse>1 || s:iftoskip && beforeelse>1
413
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200414 if s:iftoskip && getline(beforeelse) =~# '^\s*if\>'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000415 let s:iftoskip = s:iftoskip - 1
416 endif
417
418 let s:level = s:level + 1
419 let beforeelse = FindTheIfOfAnElse(beforeelse, a:StopAfterFirstPrevElse)
420 endif
421
422 return beforeelse
423
424endfunction " }}}
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000425
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200426let s:defaultORcase = '^\s*\%(default\|case\).*:'
427
428function! FindTheSwitchIndent (lnum) " {{{
429
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200430 let test = GetLastRealCodeLNum(a:lnum - 1)
431
432 if test <= 1
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200433 return indent(1) - shiftwidth() * b:PHP_vintage_case_default_indent
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200434 end
435
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200436 while getline(test) =~ '^\s*}' && test > 1
437 let test = GetLastRealCodeLNum(FindOpenBracket(test, 0) - 1)
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200438
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200439 if getline(test) =~ '^\s*switch\>'
440 let test = GetLastRealCodeLNum(test - 1)
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200441 endif
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200442 endwhile
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200443
444 if getline(test) =~# '^\s*switch\>'
445 return indent(test)
446 elseif getline(test) =~# s:defaultORcase
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200447 return indent(test) - shiftwidth() * b:PHP_vintage_case_default_indent
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200448 else
449 return FindTheSwitchIndent(test)
450 endif
451
452endfunction "}}}
453
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200454let s:SynPHPMatchGroups = {'phpparent':1, 'delimiter':1, 'define':1, 'storageclass':1, 'structure':1, 'exception':1}
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000455function! IslinePHP (lnum, tofind) " {{{
Bram Moolenaar1e015462005-09-25 22:16:38 +0000456 let cline = getline(a:lnum)
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000457
Bram Moolenaar1e015462005-09-25 22:16:38 +0000458 if a:tofind==""
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200459 let tofind = "^\\s*[\"'`]*\\s*\\zs\\S"
Bram Moolenaar1e015462005-09-25 22:16:38 +0000460 else
461 let tofind = a:tofind
462 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000463
Bram Moolenaar1e015462005-09-25 22:16:38 +0000464 let tofind = tofind . '\c'
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000465
Bram Moolenaar1e015462005-09-25 22:16:38 +0000466 let coltotest = match (cline, tofind) + 1
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000467
Bram Moolenaar1e015462005-09-25 22:16:38 +0000468 let synname = synIDattr(synID(a:lnum, coltotest, 0), "name")
469
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200470 if synname ==? 'phpStringSingle' || synname ==? 'phpStringDouble' || synname ==? 'phpBacktick'
Bram Moolenaar54775062019-07-31 21:07:14 +0200471 if cline !~ '^\s*[''"`]' " ??? XXX
Bram Moolenaared32d942014-12-06 23:33:00 +0100472 return "SpecStringEntrails"
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200473 else
474 return synname
475 end
476 end
477
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200478 if get(s:SynPHPMatchGroups, tolower(synname)) || synname =~ '^php' || synname =~? '^javaScript'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000479 return synname
480 else
481 return ""
482 endif
483endfunction " }}}
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000484
Bram Moolenaar5c736222010-01-06 20:54:52 +0100485let s:autoresetoptions = 0
486if ! s:autoresetoptions
487 let s:autoresetoptions = 1
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000488endif
489
Bram Moolenaar5c736222010-01-06 20:54:52 +0100490function! ResetPhpOptions()
Bram Moolenaared32d942014-12-06 23:33:00 +0100491 if ! b:optionsset && &filetype =~ "php"
Bram Moolenaara5792f52005-11-23 21:25:05 +0000492 if b:PHP_autoformatcomment
493
494 setlocal comments=s1:/*,mb:*,ex:*/,://,:#
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000495
Bram Moolenaarc236c162008-07-13 17:41:49 +0000496 setlocal formatoptions-=t
Bram Moolenaara5792f52005-11-23 21:25:05 +0000497 setlocal formatoptions+=q
498 setlocal formatoptions+=r
499 setlocal formatoptions+=o
Bram Moolenaara5792f52005-11-23 21:25:05 +0000500 setlocal formatoptions+=c
501 setlocal formatoptions+=b
502 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000503 let b:optionsset = 1
504 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000505endfunc
506
Bram Moolenaar5c736222010-01-06 20:54:52 +0100507call ResetPhpOptions()
508
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200509function! GetPhpIndentVersion()
Bram Moolenaar54775062019-07-31 21:07:14 +0200510 return "1.70-bundle"
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200511endfun
512
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000513function! GetPhpIndent()
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000514
Bram Moolenaar05a7bb32006-01-19 22:09:32 +0000515 let b:GetLastRealCodeLNum_ADD = 0
516
Bram Moolenaar1e015462005-09-25 22:16:38 +0000517 let UserIsEditing=0
518 if b:PHP_oldchangetick != b:changedtick
519 let b:PHP_oldchangetick = b:changedtick
520 let UserIsEditing=1
521 endif
522
523 if b:PHP_default_indenting
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200524 let b:PHP_default_indenting = g:PHP_default_indenting * shiftwidth()
Bram Moolenaar1e015462005-09-25 22:16:38 +0000525 endif
526
527 let cline = getline(v:lnum)
528
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000529 if !b:PHP_indentinghuge && b:PHP_lastindented > b:PHP_indentbeforelast
Bram Moolenaar1e015462005-09-25 22:16:38 +0000530 if b:PHP_indentbeforelast
531 let b:PHP_indentinghuge = 1
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000532 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000533 let b:PHP_indentbeforelast = b:PHP_lastindented
534 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000535
Bram Moolenaar1e015462005-09-25 22:16:38 +0000536 if b:InPHPcode_checked && prevnonblank(v:lnum - 1) != b:PHP_lastindented
537 if b:PHP_indentinghuge
Bram Moolenaar1e015462005-09-25 22:16:38 +0000538 let b:PHP_indentinghuge = 0
539 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000540 endif
Bram Moolenaared32d942014-12-06 23:33:00 +0100541 let real_PHP_lastindented = v:lnum
Bram Moolenaar1e015462005-09-25 22:16:38 +0000542 let b:PHP_LastIndentedWasComment=0
543 let b:PHP_InsideMultilineComment=0
544 let b:PHP_indentbeforelast = 0
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000545
Bram Moolenaar1e015462005-09-25 22:16:38 +0000546 let b:InPHPcode = 0
547 let b:InPHPcode_checked = 0
548 let b:InPHPcode_and_script = 0
549 let b:InPHPcode_tofind = ""
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000550
Bram Moolenaar1e015462005-09-25 22:16:38 +0000551 elseif v:lnum > b:PHP_lastindented
552 let real_PHP_lastindented = b:PHP_lastindented
Bram Moolenaared32d942014-12-06 23:33:00 +0100553 else
554 let real_PHP_lastindented = v:lnum
Bram Moolenaar1e015462005-09-25 22:16:38 +0000555 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000556
Bram Moolenaared32d942014-12-06 23:33:00 +0100557 let b:PHP_lastindented = v:lnum
558
Bram Moolenaar1e015462005-09-25 22:16:38 +0000559
560 if !b:InPHPcode_checked " {{{ One time check
561 let b:InPHPcode_checked = 1
Bram Moolenaarcbebd482016-02-07 23:02:56 +0100562 let b:UserIsTypingComment = 0
Bram Moolenaar1e015462005-09-25 22:16:38 +0000563
Bram Moolenaar05a7bb32006-01-19 22:09:32 +0000564 let synname = ""
565 if cline !~ '<?.*?>'
566 let synname = IslinePHP (prevnonblank(v:lnum), "")
567 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000568
569 if synname!=""
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200570 if synname ==? "SpecStringEntrails"
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200571 let b:InPHPcode = -1 " thumb down
Bram Moolenaared32d942014-12-06 23:33:00 +0100572 let b:InPHPcode_tofind = ""
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200573 elseif synname !=? "phpHereDoc" && synname !=? "phpHereDocDelimiter"
Bram Moolenaar1e015462005-09-25 22:16:38 +0000574 let b:InPHPcode = 1
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000575 let b:InPHPcode_tofind = ""
576
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200577 if synname =~? '^php\%(Doc\)\?Comment'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000578 let b:UserIsTypingComment = 1
Bram Moolenaarcbebd482016-02-07 23:02:56 +0100579 let b:InPHPcode_checked = 0
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000580 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000581
Bram Moolenaar1e015462005-09-25 22:16:38 +0000582 if synname =~? '^javaScript'
583 let b:InPHPcode_and_script = 1
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000584 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000585
Bram Moolenaar1e015462005-09-25 22:16:38 +0000586 else
587 let b:InPHPcode = 0
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000588
Bram Moolenaar1e015462005-09-25 22:16:38 +0000589 let lnum = v:lnum - 1
Bram Moolenaarcbebd482016-02-07 23:02:56 +0100590 while getline(lnum) !~? '<<<\s*[''"]\=\a\w*[''"]\=$' && lnum > 1
Bram Moolenaar1e015462005-09-25 22:16:38 +0000591 let lnum = lnum - 1
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000592 endwhile
593
Bram Moolenaarcbebd482016-02-07 23:02:56 +0100594 let b:InPHPcode_tofind = substitute( getline(lnum), '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '')
Bram Moolenaar1e015462005-09-25 22:16:38 +0000595 endif
596 else
597 let b:InPHPcode = 0
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200598 let b:InPHPcode_tofind = s:PHP_startindenttag
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000599 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000600 endif "!b:InPHPcode_checked }}}
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000601
602
Bram Moolenaar1e015462005-09-25 22:16:38 +0000603 " Test if we are indenting PHP code {{{
604 let lnum = prevnonblank(v:lnum - 1)
605 let last_line = getline(lnum)
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200606 let endline= s:endline
Bram Moolenaar1e015462005-09-25 22:16:38 +0000607
608 if b:InPHPcode_tofind!=""
609 if cline =~? b:InPHPcode_tofind
Bram Moolenaar1e015462005-09-25 22:16:38 +0000610 let b:InPHPcode_tofind = ""
611 let b:UserIsTypingComment = 0
Bram Moolenaared32d942014-12-06 23:33:00 +0100612
613 if b:InPHPcode == -1
614 let b:InPHPcode = 1
615 return -1
616 end
617
618 let b:InPHPcode = 1
619
Bram Moolenaar1e015462005-09-25 22:16:38 +0000620 if cline =~ '\*/'
621 call cursor(v:lnum, 1)
622 if cline !~ '^\*/'
623 call search('\*/', 'W')
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000624 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000625 let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000626
Bram Moolenaar1e015462005-09-25 22:16:38 +0000627 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000628
Bram Moolenaar1e015462005-09-25 22:16:38 +0000629 let b:PHP_LastIndentedWasComment = 0
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000630
Bram Moolenaar1e015462005-09-25 22:16:38 +0000631 if cline =~ '^\s*\*/'
632 return indent(lnum) + 1
633 else
634 return indent(lnum)
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000635 endif
636
Bram Moolenaar1e015462005-09-25 22:16:38 +0000637 elseif cline =~? '<script\>'
638 let b:InPHPcode_and_script = 1
Bram Moolenaar05a7bb32006-01-19 22:09:32 +0000639 let b:GetLastRealCodeLNum_ADD = v:lnum
Bram Moolenaar1e015462005-09-25 22:16:38 +0000640 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000641 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000642 endif
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000643
Bram Moolenaared32d942014-12-06 23:33:00 +0100644 if 1 == b:InPHPcode
Bram Moolenaar1e015462005-09-25 22:16:38 +0000645
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200646 if !b:InPHPcode_and_script && last_line =~ '\%(<?.*\)\@<!?>\%(.*<?\)\@!' && IslinePHP(lnum, '?>')=~?"Delimiter"
Bram Moolenaar1e015462005-09-25 22:16:38 +0000647 if cline !~? s:PHP_startindenttag
648 let b:InPHPcode = 0
649 let b:InPHPcode_tofind = s:PHP_startindenttag
650 elseif cline =~? '<script\>'
651 let b:InPHPcode_and_script = 1
652 endif
653
Bram Moolenaar54775062019-07-31 21:07:14 +0200654 elseif last_line =~ '^[^''"`]\+[''"`]$' && last_line !~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)' " a string identifier with nothing after it and no other string identifier before
Bram Moolenaared32d942014-12-06 23:33:00 +0100655 let b:InPHPcode = -1
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200656 let b:InPHPcode_tofind = substitute( last_line, '^.*\([''"`]\).*$', '^[^\1]*\1[;,]$', '')
Bram Moolenaarcbebd482016-02-07 23:02:56 +0100657 elseif last_line =~? '<<<\s*[''"]\=\a\w*[''"]\=$'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000658 let b:InPHPcode = 0
Bram Moolenaarcbebd482016-02-07 23:02:56 +0100659 let b:InPHPcode_tofind = substitute( last_line, '^.*<<<\s*[''"]\=\(\a\w*\)[''"]\=$', '^\\s*\1;\\=$', '')
Bram Moolenaar1e015462005-09-25 22:16:38 +0000660
661 elseif !UserIsEditing && cline =~ '^\s*/\*\%(.*\*/\)\@!' && getline(v:lnum + 1) !~ '^\s*\*'
662 let b:InPHPcode = 0
663 let b:InPHPcode_tofind = '\*/'
664
665 elseif cline =~? '^\s*</script>'
666 let b:InPHPcode = 0
667 let b:InPHPcode_tofind = s:PHP_startindenttag
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000668 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000669 endif " }}}
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000670
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000671
Bram Moolenaared32d942014-12-06 23:33:00 +0100672 if 1 > b:InPHPcode && !b:InPHPcode_and_script
Bram Moolenaar1e015462005-09-25 22:16:38 +0000673 return -1
674 endif
675
Bram Moolenaar1e015462005-09-25 22:16:38 +0000676 " Indent successive // or # comment the same way the first is {{{
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200677 let addSpecial = 0
Bram Moolenaar1e015462005-09-25 22:16:38 +0000678 if cline =~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)'
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200679 let addSpecial = b:PHP_outdentSLComments
Bram Moolenaar1e015462005-09-25 22:16:38 +0000680 if b:PHP_LastIndentedWasComment == 1
681 return indent(real_PHP_lastindented)
682 endif
683 let b:PHP_LastIndentedWasComment = 1
684 else
685 let b:PHP_LastIndentedWasComment = 0
686 endif " }}}
687
688 " Indent multiline /* comments correctly {{{
689
690 if b:PHP_InsideMultilineComment || b:UserIsTypingComment
691 if cline =~ '^\s*\*\%(\/\)\@!'
692 if last_line =~ '^\s*/\*'
693 return indent(lnum) + 1
694 else
695 return indent(lnum)
696 endif
697 else
698 let b:PHP_InsideMultilineComment = 0
699 endif
700 endif
701
Bram Moolenaared32d942014-12-06 23:33:00 +0100702 if !b:PHP_InsideMultilineComment && cline =~ '^\s*/\*\%(.*\*/\)\@!'
Bram Moolenaar05a7bb32006-01-19 22:09:32 +0000703 if getline(v:lnum + 1) !~ '^\s*\*'
704 return -1
705 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000706 let b:PHP_InsideMultilineComment = 1
Bram Moolenaar1e015462005-09-25 22:16:38 +0000707 endif " }}}
708
709
710 " Things always indented at col 1 (PHP delimiter: <?, ?>, Heredoc end) {{{
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200711 if cline =~# '^\s*<?' && cline !~ '?>' && b:PHP_outdentphpescape
Bram Moolenaar1e015462005-09-25 22:16:38 +0000712 return 0
713 endif
714
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200715 if cline =~ '^\s*?>' && cline !~# '<?' && b:PHP_outdentphpescape
Bram Moolenaar1e015462005-09-25 22:16:38 +0000716 return 0
717 endif
718
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200719 if cline =~? '^\s*\a\w*;$\|^\a\w*$\|^\s*[''"`][;,]' && cline !~? s:notPhpHereDoc
Bram Moolenaar1e015462005-09-25 22:16:38 +0000720 return 0
721 endif " }}}
722
723 let s:level = 0
724
725 let lnum = GetLastRealCodeLNum(v:lnum - 1)
Bram Moolenaar05a7bb32006-01-19 22:09:32 +0000726
Bram Moolenaar1e015462005-09-25 22:16:38 +0000727 let last_line = getline(lnum)
728 let ind = indent(lnum)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000729
730 if ind==0 && b:PHP_default_indenting
731 let ind = b:PHP_default_indenting
732 endif
733
734 if lnum == 0
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200735 return b:PHP_default_indenting + addSpecial
Bram Moolenaar1e015462005-09-25 22:16:38 +0000736 endif
737
738
739 if cline =~ '^\s*}\%(}}\)\@!'
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200740 let ind = indent(FindOpenBracket(v:lnum, 1))
Bram Moolenaar1e015462005-09-25 22:16:38 +0000741 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000742 return ind
Bram Moolenaar1e015462005-09-25 22:16:38 +0000743 endif
744
745 if cline =~ '^\s*\*/'
746 call cursor(v:lnum, 1)
747 if cline !~ '^\*/'
748 call search('\*/', 'W')
749 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000750 let lnum = searchpair('/\*', '', '\*/', s:searchpairflags, 'Skippmatch2()')
Bram Moolenaar1e015462005-09-25 22:16:38 +0000751
752 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
753
754 if cline =~ '^\s*\*/'
755 return indent(lnum) + 1
756 else
757 return indent(lnum)
758 endif
759 endif
760
Bram Moolenaar1e015462005-09-25 22:16:38 +0000761
Bram Moolenaar54775062019-07-31 21:07:14 +0200762 if last_line =~ '[;}]'.endline && last_line !~ '^[)\]]' && last_line !~# s:defaultORcase && last_line !~ '^\s*[''"`][;,]'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000763 if ind==b:PHP_default_indenting
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200764 return b:PHP_default_indenting + addSpecial
Bram Moolenaar1e015462005-09-25 22:16:38 +0000765 elseif b:PHP_indentinghuge && ind==b:PHP_CurrentIndentLevel && cline !~# '^\s*\%(else\|\%(case\|default\).*:\|[})];\=\)' && last_line !~# '^\s*\%(\%(}\s*\)\=else\)' && getline(GetLastRealCodeLNum(lnum - 1))=~';'.endline
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200766 return b:PHP_CurrentIndentLevel + addSpecial
Bram Moolenaar1e015462005-09-25 22:16:38 +0000767 endif
768 endif
769
770 let LastLineClosed = 0
771
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200772 let terminated = s:terminated
Bram Moolenaar1e015462005-09-25 22:16:38 +0000773
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200774 let unstated = s:unstated
775
Bram Moolenaar1e015462005-09-25 22:16:38 +0000776
777 if ind != b:PHP_default_indenting && cline =~# '^\s*else\%(if\)\=\>'
778 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
779 return indent(FindTheIfOfAnElse(v:lnum, 1))
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200780 elseif cline =~# s:defaultORcase
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200781 return FindTheSwitchIndent(v:lnum) + shiftwidth() * b:PHP_vintage_case_default_indent
Bram Moolenaarc236c162008-07-13 17:41:49 +0000782 elseif cline =~ '^\s*)\=\s*{'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000783 let previous_line = last_line
784 let last_line_num = lnum
785
786 while last_line_num > 1
787
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200788 if previous_line =~ terminated || previous_line =~ s:structureHead
Bram Moolenaar1e015462005-09-25 22:16:38 +0000789
790 let ind = indent(last_line_num)
791
792 if b:PHP_BracesAtCodeLevel
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200793 let ind = ind + shiftwidth()
Bram Moolenaar1e015462005-09-25 22:16:38 +0000794 endif
795
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000796 return ind
Bram Moolenaar1e015462005-09-25 22:16:38 +0000797 endif
798
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200799 let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000800 let previous_line = getline(last_line_num)
801 endwhile
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200802 elseif cline =~ '^\s*->'
803 return FindArrowIndent(lnum)
Bram Moolenaarc236c162008-07-13 17:41:49 +0000804 elseif last_line =~# unstated && cline !~ '^\s*);\='.endline
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200805 let ind = ind + shiftwidth() " we indent one level further when the preceding line is not stated
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200806 return ind + addSpecial
Bram Moolenaar1e015462005-09-25 22:16:38 +0000807
Bram Moolenaared32d942014-12-06 23:33:00 +0100808 elseif (ind != b:PHP_default_indenting || last_line =~ '^[)\]]' ) && last_line =~ terminated
Bram Moolenaar1e015462005-09-25 22:16:38 +0000809 let previous_line = last_line
810 let last_line_num = lnum
811 let LastLineClosed = 1
812
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200813 let isSingleLineBlock = 0
Bram Moolenaar1e015462005-09-25 22:16:38 +0000814 while 1
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200815 if ! isSingleLineBlock && previous_line =~ '^\s*}\|;\s*}'.endline
Bram Moolenaar1e015462005-09-25 22:16:38 +0000816
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200817 call cursor(last_line_num, 1)
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200818 if previous_line !~ '^}'
819 call search('}\|;\s*}'.endline, 'W')
820 end
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200821 let oldLastLine = last_line_num
822 let last_line_num = searchpair('{', '', '}', 'bW', 'Skippmatch()')
823
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200824 if getline(last_line_num) =~ '^\s*{'
Bram Moolenaar1e015462005-09-25 22:16:38 +0000825 let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200826 elseif oldLastLine == last_line_num
827 let isSingleLineBlock = 1
828 continue
Bram Moolenaar1e015462005-09-25 22:16:38 +0000829 endif
830
831 let previous_line = getline(last_line_num)
832
833 continue
834 else
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200835 let isSingleLineBlock = 0
Bram Moolenaar1e015462005-09-25 22:16:38 +0000836
837 if getline(last_line_num) =~# '^\s*else\%(if\)\=\>'
838 let last_line_num = FindTheIfOfAnElse(last_line_num, 0)
839 continue
840 endif
841
842
843 let last_match = last_line_num
844
845 let one_ahead_indent = indent(last_line_num)
846 let last_line_num = GetLastRealCodeLNum(last_line_num - 1)
847 let two_ahead_indent = indent(last_line_num)
848 let after_previous_line = previous_line
849 let previous_line = getline(last_line_num)
850
851
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200852 if previous_line =~# s:defaultORcase.'\|{'.endline
Bram Moolenaar1e015462005-09-25 22:16:38 +0000853 break
854 endif
855
856 if after_previous_line=~# '^\s*'.s:blockstart.'.*)'.endline && previous_line =~# '[;}]'.endline
857 break
858 endif
859
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000860 if one_ahead_indent == two_ahead_indent || last_line_num < 1
Bram Moolenaarc236c162008-07-13 17:41:49 +0000861 if previous_line =~# '\%(;\|^\s*}\)'.endline || last_line_num < 1
Bram Moolenaar1e015462005-09-25 22:16:38 +0000862 break
863 endif
864 endif
865 endif
866 endwhile
867
868 if indent(last_match) != ind
869 let ind = indent(last_match)
870 let b:PHP_CurrentIndentLevel = b:PHP_default_indenting
871
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200872 return ind + addSpecial
Bram Moolenaar1e015462005-09-25 22:16:38 +0000873 endif
874 endif
875
Bram Moolenaared32d942014-12-06 23:33:00 +0100876 if (last_line !~ '^\s*}\%(}}\)\@!')
877 let plinnum = GetLastRealCodeLNum(lnum - 1)
878 else
879 let plinnum = GetLastRealCodeLNum(FindOpenBracket(lnum, 1) - 1)
880 endif
881
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200882 let AntepenultimateLine = getline(plinnum)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000883
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200884 let last_line = StripEndlineComments(last_line)
Bram Moolenaar1e015462005-09-25 22:16:38 +0000885
886 if ind == b:PHP_default_indenting
Bram Moolenaared32d942014-12-06 23:33:00 +0100887 if last_line =~ terminated && last_line !~# s:defaultORcase
Bram Moolenaar1e015462005-09-25 22:16:38 +0000888 let LastLineClosed = 1
889 endif
890 endif
891
892 if !LastLineClosed
893
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200894 let openedparent = -1
895
Bram Moolenaar5c736222010-01-06 20:54:52 +0100896
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200897 if last_line =~# '[{(\[]'.endline || last_line =~? '\h\w*\s*(.*,$' && AntepenultimateLine !~ '[,(\[]'.endline && BalanceDirection(last_line) > 0
Bram Moolenaar1e015462005-09-25 22:16:38 +0000898
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200899 let dontIndent = 0
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200900 if last_line =~ '\S\+\s*{'.endline && last_line !~ '^\s*[)\]]\+\(\s*:\s*'.s:PHP_validVariable.'\)\=\s*{'.endline && last_line !~ s:structureHead
Bram Moolenaarbcb98982014-05-01 14:08:19 +0200901 let dontIndent = 1
902 endif
903
904 if !dontIndent && (!b:PHP_BracesAtCodeLevel || last_line !~# '^\s*{')
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200905 let ind = ind + shiftwidth()
Bram Moolenaar1e015462005-09-25 22:16:38 +0000906 endif
907
Bram Moolenaar54775062019-07-31 21:07:14 +0200908 if b:PHP_IndentFunctionCallParameters && last_line =~ s:multilineFunctionCall && last_line !~ s:structureHead && last_line !~ s:arrayDecl
909 let ind = ind + b:PHP_IndentFunctionCallParameters * shiftwidth()
910 endif
911
912 if b:PHP_IndentFunctionDeclarationParameters && last_line =~ s:multilineFunctionDecl
913 let ind = ind + b:PHP_IndentFunctionDeclarationParameters * shiftwidth()
914 endif
915
Bram Moolenaar8408a9a2010-07-30 22:41:22 +0200916 if b:PHP_BracesAtCodeLevel || b:PHP_vintage_case_default_indent == 1
Bram Moolenaar1e015462005-09-25 22:16:38 +0000917 let b:PHP_CurrentIndentLevel = ind
Bram Moolenaarc236c162008-07-13 17:41:49 +0000918
Bram Moolenaar1e015462005-09-25 22:16:38 +0000919 endif
920
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200921 elseif last_line =~ '),'.endline && BalanceDirection(last_line) < 0
Bram Moolenaar1e015462005-09-25 22:16:38 +0000922 call cursor(lnum, 1)
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200923 call searchpos('),'.endline, 'cW')
Bram Moolenaar1e015462005-09-25 22:16:38 +0000924 let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()')
925 if openedparent != lnum
926 let ind = indent(openedparent)
927 endif
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200928
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200929 elseif last_line =~ s:structureHead
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200930 let ind = ind + shiftwidth()
Bram Moolenaar1e015462005-09-25 22:16:38 +0000931
Bram Moolenaarc236c162008-07-13 17:41:49 +0000932
Bram Moolenaare0720cb2017-03-29 13:48:40 +0200933 elseif AntepenultimateLine =~ '{'.endline && AntepenultimateLine !~? '^\s*use\>' || AntepenultimateLine =~ terminated || AntepenultimateLine =~# s:defaultORcase
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200934 let ind = ind + shiftwidth()
Bram Moolenaar1e015462005-09-25 22:16:38 +0000935 endif
936
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200937
938 if openedparent >= 0
939 let last_line = StripEndlineComments(getline(openedparent))
940 endif
Bram Moolenaar1e015462005-09-25 22:16:38 +0000941 endif
942
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200943 if cline =~ '^\s*[)\]];\='
Bram Moolenaar54775062019-07-31 21:07:14 +0200944 call cursor(v:lnum, 1)
945 call searchpos('[)\]]', 'cW')
946 let matchedBlockChar = cline[col('.')-1]
947 let openedparent = searchpair('\M'.s:blockCharsLUT[matchedBlockChar], '', '\M'.matchedBlockChar, 'bW', 'Skippmatch()')
948 if openedparent != v:lnum
949 let ind = indent(openedparent)
950 endif
Bram Moolenaar0b0f0992018-05-22 21:41:30 +0200951
Bram Moolenaar54775062019-07-31 21:07:14 +0200952 elseif last_line =~ '^\s*->' && last_line !~? s:structureHead && BalanceDirection(last_line) <= 0
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200953 let ind = ind - shiftwidth()
Bram Moolenaar1e015462005-09-25 22:16:38 +0000954 endif
955
956 let b:PHP_CurrentIndentLevel = ind
Bram Moolenaare6ae6222013-05-21 21:01:10 +0200957 return ind + addSpecial
Bram Moolenaar9ff70112005-07-11 22:29:03 +0000958endfunction