Skip to content

Commit 711f4a0

Browse files
committed
runtime(sh): update sh indent script
fixes: #16930 Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent e08f10a commit 711f4a0

1 file changed

Lines changed: 41 additions & 17 deletions

File tree

runtime/indent/sh.vim

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
" License: Vim (see :h license)
88
" Repository: https://github.com/chrisbra/vim-sh-indent
99
" Changelog:
10+
" 20250318 - Detect local arrays in functions
1011
" 20241411 - Detect dash character in function keyword for
1112
" bash mode (issue #16049)
1213
" 20190726 - Correctly skip if keywords in syntax comments
@@ -73,6 +74,8 @@ function! s:indent_value(option)
7374
endfunction
7475

7576
function! GetShIndent()
77+
let mode = mode()
78+
7679
let curline = getline(v:lnum)
7780
let lnum = prevnonblank(v:lnum - 1)
7881
if lnum == 0
@@ -86,8 +89,11 @@ function! GetShIndent()
8689

8790
" Check contents of previous lines
8891
" should not apply to e.g. commented lines
89-
if line =~ '^\s*\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>' ||
90-
\ (&ft is# 'zsh' && line =~ '^\s*\<\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>')
92+
93+
if s:start_block(line)
94+
let ind += s:indent_value('default')
95+
elseif line =~ '^\s*\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>\($\|\s\)' ||
96+
\ (&ft is# 'zsh' && line =~ '^\s*\<\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>\($\|\s\)')
9197
if !s:is_end_expression(line)
9298
let ind += s:indent_value('default')
9399
endif
@@ -111,7 +117,7 @@ function! GetShIndent()
111117
let ind += s:indent_value('continuation-line')
112118
endif
113119
elseif s:end_block(line) && !s:start_block(line)
114-
let ind = indent(lnum)
120+
let ind -= s:indent_value('default')
115121
elseif pnum != 0 &&
116122
\ s:is_continuation_line(pline) &&
117123
\ !s:end_block(curline) &&
@@ -122,7 +128,7 @@ function! GetShIndent()
122128
while !s:is_empty(getline(i)) && i > pnum
123129
let i -= 1
124130
endw
125-
if i == pnum
131+
if i == pnum && (s:is_continuation_line(line) || pline =~ '{\s*\(#.*\)\=$')
126132
let ind += ind2
127133
else
128134
let ind = ind2
@@ -136,7 +142,11 @@ function! GetShIndent()
136142
" TODO: should we do the same for other "end" lines?
137143
if curline =~ '^\s*\%(fi\);\?\s*\%(#.*\)\=$'
138144
let ind = indent(v:lnum)
139-
let previous_line = searchpair('\<if\>', '', '\<fi\>\zs', 'bnW', 'synIDattr(synID(line("."),col("."), 1),"name") =~? "comment\\|quote"')
145+
" in insert mode, try to place the cursor after the fi statement
146+
let endp = '\<fi\>' .. (mode ==? 'i' ? '\zs' : '')
147+
let startp = '^\s*\<if\>'
148+
let previous_line = searchpair(startp, '', endp , 'bnW',
149+
\ 'synIDattr(synID(line("."),col("."), 1),"name") =~? "comment\\|quote\\|option"')
140150
if previous_line > 0
141151
let ind = indent(previous_line)
142152
endif
@@ -167,7 +177,13 @@ function! GetShIndent()
167177
elseif match(map(synstack(v:lnum, 1), 'synIDattr(v:val, "name")'), '\c\mheredoc') > -1
168178
return indent(v:lnum)
169179
elseif s:is_comment(line) && s:is_empty(getline(v:lnum-1))
170-
return indent(v:lnum)
180+
if s:is_in_block(v:lnum)
181+
" return indent of line in same block
182+
return indent(lnum)
183+
else
184+
" use indent of current line
185+
return indent(v:lnum)
186+
endif
171187
endif
172188

173189
return ind > 0 ? ind : 0
@@ -203,7 +219,18 @@ function! s:is_function_definition(line)
203219
endfunction
204220

205221
function! s:is_array(line)
206-
return a:line =~ '^\s*\<\k\+\>=('
222+
return a:line =~ '^\s*\(\(declare\|typeset\|local\)\s\+\(-[Aalrtu]\+\s\+\)\?\)\?\<\k\+\>=('
223+
endfunction
224+
225+
function! s:is_in_block(line)
226+
" checks whether a:line is whithin a
227+
" block e.g. a shell function
228+
" foo() {
229+
" ..
230+
" }
231+
let prevline = searchpair('{', '', '}', 'bnW', 'synIDattr(synID(line("."),col("."), 1),"name") =~? "comment\\|quote"')
232+
let nextline = searchpair('{', '', '}', 'nW', 'synIDattr(synID(line("."),col("."), 1),"name") =~? "comment\\|quote"')
233+
return a:line > prevline && a:line < nextline
207234
endfunction
208235

209236
function! s:is_case_label(line, pnum)
@@ -280,15 +307,8 @@ function! s:end_block(line)
280307
endfunction
281308

282309
function! s:start_block(line)
283-
return a:line =~ '{\s*\(#.*\)\?$'
284-
endfunction
285-
286-
function! s:find_start_block(lnum)
287-
let i = a:lnum
288-
while i > 1 && !s:start_block(getline(i))
289-
let i -= 1
290-
endwhile
291-
return i
310+
# return a:line =~ '{\s*\(#.*\)\?$'
311+
return a:line =~ '^[^#]*[{(]\s*\(#.*\)\?$'
292312
endfunction
293313

294314
function! s:is_comment(line)
@@ -300,7 +320,11 @@ function! s:is_end_expression(line)
300320
endfunction
301321

302322
function! s:is_bash()
303-
return get(g:, 'is_bash', 0) || get(b:, 'is_bash', 0)
323+
if &ft is# 'bash' || getline(1) is# '#!/bin/bash'
324+
return v:true
325+
else
326+
return get(g:, 'is_bash', 0) || get(b:, 'is_bash', 0)
327+
endif
304328
endfunction
305329

306330
let &cpo = s:cpo_save

0 commit comments

Comments
 (0)