Merge branch 'vim-with-runtime' into feat/quickfix-title
[vim_extended.git] / runtime / indent / sh.vim
blob49146c7e377d8a1b0e2fb6be0c152fcce0623f6b
1 " Vim indent file
2 " Language:         Shell Script
3 " Maintainer:       Nikolai Weibull <now@bitwi.se>
4 " Latest Revision:  2010-01-06
6 if exists("b:did_indent")
7   finish
8 endif
9 let b:did_indent = 1
11 setlocal indentexpr=GetShIndent()
12 setlocal indentkeys+=0=then,0=do,0=else,0=elif,0=fi,0=esac,0=done,),0=;;,0=;&
13 setlocal indentkeys+=0=fin,0=fil,0=fip,0=fir,0=fix
14 setlocal indentkeys-=:,0#
15 setlocal nosmartindent
17 if exists("*GetShIndent")
18   finish
19 endif
21 let s:cpo_save = &cpo
22 set cpo&vim
24 function s:buffer_shiftwidth()
25   return &shiftwidth
26 endfunction
28 let s:sh_indent_defaults = {
29       \ 'default': function('s:buffer_shiftwidth'),
30       \ 'continuation-line': function('s:buffer_shiftwidth'),
31       \ 'case-labels': function('s:buffer_shiftwidth'),
32       \ 'case-statements': function('s:buffer_shiftwidth'),
33       \ 'case-breaks': 0 }
35 function! s:indent_value(option)
36   let Value = exists('b:sh_indent_options')
37             \ && has_key(b:sh_indent_options, a:option) ?
38             \ b:sh_indent_options[a:option] :
39             \ s:sh_indent_defaults[a:option]
40   if type(Value) == type(function('type'))
41     return Value()
42   endif
43   return Value
44 endfunction
46 function! GetShIndent()
47   let lnum = prevnonblank(v:lnum - 1)
48   if lnum == 0
49     return 0
50   endif
52   let pnum = prevnonblank(lnum - 1)
54   let ind = indent(lnum)
55   let line = getline(lnum)
56   if line =~ '^\s*\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\)\>'
57     if line !~ '\<\%(fi\|esac\|done\)\>\s*\%(#.*\)\=$'
58       let ind += s:indent_value('default')
59     endif
60   elseif s:is_case_label(line, pnum)
61     if !s:is_case_ended(line)
62       let ind += s:indent_value('case-statements')
63     endif
64   elseif line =~ '^\s*\<\k\+\>\s*()\s*{' || line =~ '^\s*{'
65     if line !~ '}\s*\%(#.*\)\=$'
66       let ind += s:indent_value('default')
67     endif
68   elseif s:is_continuation_line(line)
69     if pnum == 0 || !s:is_continuation_line(getline(pnum))
70       let ind += s:indent_value('continuation-line')
71     endif
72   elseif pnum != 0 && s:is_continuation_line(getline(pnum))
73     let ind = indent(s:find_continued_lnum(pnum))
74   endif
76   let pine = line
77   let line = getline(v:lnum)
78   if line =~ '^\s*\%(then\|do\|else\|elif\|fi\|done\)\>' || line =~ '^\s*}'
79     let ind -= s:indent_value('default')
80   elseif line =~ '^\s*esac\>'
81     let ind -= (s:is_case_label(pine, lnum) && s:is_case_ended(pine) ?
82              \ 0 : s:indent_value('case-statements')) +
83              \ s:indent_value('case-labels')
84     if s:is_case_break(pine)
85       let ind += s:indent_value('case-breaks')
86     endif
87   elseif s:is_case_label(line, lnum)
88     if s:is_case(pine)
89       let ind = indent(lnum) + s:indent_value('case-labels')
90     else
91       let ind -= s:indent_value('case-statements') - s:indent_value('case-breaks')
92     endif
93   elseif s:is_case_break(line)
94     let ind -= s:indent_value('case-breaks')
95   endif
97   return ind
98 endfunction
100 function! s:is_continuation_line(line)
101   return a:line =~ '\%(\%(^\|[^\\]\)\\\|&&\|||\)$'
102 endfunction
104 function! s:find_continued_lnum(lnum)
105   let i = a:lnum
106   while i > 1 && s:is_continuation_line(getline(i - 1))
107     let i -= 1
108   endwhile
109   return i
110 endfunction
112 function! s:is_case_label(line, pnum)
113   if a:line !~ '^\s*(\=.*)'
114     return 0
115   endif
117   if a:pnum > 0
118     let pine = getline(a:pnum)
119     if !(s:is_case(pine) || s:is_case_ended(pine))
120       return 0
121     endif
122   endif
124   let suffix = substitute(a:line, '^\s*(\=', "", "")
125   let nesting = 0
126   let i = 0
127   let n = strlen(suffix)
128   while i < n
129     let c = suffix[i]
130     let i += 1
131     if c == '\\'
132       let i += 1
133     elseif c == '('
134       let nesting += 1
135     elseif c == ')'
136       if nesting == 0
137         return 1
138       endif
139       let nesting -= 1
140     endif
141   endwhile
142   return 0
143 endfunction
145 function! s:is_case(line)
146   return a:line =~ '^\s*case\>'
147 endfunction
149 function! s:is_case_break(line)
150   return a:line =~ '^\s*;[;&]'
151 endfunction
153 function! s:is_case_ended(line)
154   return s:is_case_break(a:line) || a:line =~ ';[;&]\s*\%(#.*\)\=$'
155 endfunction
157 let &cpo = s:cpo_save
158 unlet s:cpo_save