1" Vim indent file 2" Language: Shell Script 3" Maintainer: Christian Brabandt <[email protected]> 4" Previous Maintainer: Peter Aronoff <[email protected]> 5" Original Author: Nikolai Weibull <[email protected]> 6" Latest Revision: 2015-12-15 7" License: Vim (see :h license) 8" Repository: https://github.com/chrisbra/vim-sh-indent 9 10if exists("b:did_indent") 11 finish 12endif 13let b:did_indent = 1 14 15let b:undo_indent = 'setlocal indentexpr< indentkeys< smartindent<' 16 17setlocal indentexpr=GetShIndent() 18setlocal indentkeys+=0=then,0=do,0=else,0=elif,0=fi,0=esac,0=done,0=end,),0=;;,0=;& 19setlocal indentkeys+=0=fin,0=fil,0=fip,0=fir,0=fix 20setlocal indentkeys-=:,0# 21setlocal nosmartindent 22 23if exists("*GetShIndent") 24 finish 25endif 26 27let s:cpo_save = &cpo 28set cpo&vim 29 30function s:buffer_shiftwidth() 31 return &shiftwidth 32endfunction 33 34let s:sh_indent_defaults = { 35 \ 'default': function('s:buffer_shiftwidth'), 36 \ 'continuation-line': function('s:buffer_shiftwidth'), 37 \ 'case-labels': function('s:buffer_shiftwidth'), 38 \ 'case-statements': function('s:buffer_shiftwidth'), 39 \ 'case-breaks': 0 } 40 41function! s:indent_value(option) 42 let Value = exists('b:sh_indent_options') 43 \ && has_key(b:sh_indent_options, a:option) ? 44 \ b:sh_indent_options[a:option] : 45 \ s:sh_indent_defaults[a:option] 46 if type(Value) == type(function('type')) 47 return Value() 48 endif 49 return Value 50endfunction 51 52function! GetShIndent() 53 let lnum = prevnonblank(v:lnum - 1) 54 if lnum == 0 55 return 0 56 endif 57 58 let pnum = prevnonblank(lnum - 1) 59 60 let ind = indent(lnum) 61 let line = getline(lnum) 62 if line =~ '^\s*\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>' 63 if line !~ '\<\%(fi\|esac\|done\|end\)\>\s*\%(#.*\)\=$' 64 let ind += s:indent_value('default') 65 endif 66 elseif s:is_case_label(line, pnum) 67 if !s:is_case_ended(line) 68 let ind += s:indent_value('case-statements') 69 endif 70 elseif line =~ '^\s*\<\k\+\>\s*()\s*{' || line =~ '^\s*{' 71 if line !~ '}\s*\%(#.*\)\=$' 72 let ind += s:indent_value('default') 73 endif 74 elseif s:is_continuation_line(line) 75 if pnum == 0 || !s:is_continuation_line(getline(pnum)) 76 let ind += s:indent_value('continuation-line') 77 endif 78 elseif pnum != 0 && s:is_continuation_line(getline(pnum)) 79 let ind = indent(s:find_continued_lnum(pnum)) 80 endif 81 82 let pine = line 83 let line = getline(v:lnum) 84 if line =~ '^\s*\%(then\|do\|else\|elif\|fi\|done\|end\)\>' || line =~ '^\s*}' 85 let ind -= s:indent_value('default') 86 elseif line =~ '^\s*esac\>' && s:is_case_empty(getline(v:lnum - 1)) 87 let ind -= s:indent_value('default') 88 elseif line =~ '^\s*esac\>' 89 let ind -= (s:is_case_label(pine, lnum) && s:is_case_ended(pine) ? 90 \ 0 : s:indent_value('case-statements')) + 91 \ s:indent_value('case-labels') 92 if s:is_case_break(pine) 93 let ind += s:indent_value('case-breaks') 94 endif 95 elseif s:is_case_label(line, lnum) 96 if s:is_case(pine) 97 let ind = indent(lnum) + s:indent_value('case-labels') 98 else 99 let ind -= (s:is_case_label(pine, lnum) && s:is_case_ended(pine) ? 100 \ 0 : s:indent_value('case-statements')) - 101 \ s:indent_value('case-breaks') 102 endif 103 elseif s:is_case_break(line) 104 let ind -= s:indent_value('case-breaks') 105 endif 106 107 return ind 108endfunction 109 110function! s:is_continuation_line(line) 111 return a:line =~ '\%(\%(^\|[^\\]\)\\\|&&\|||\)$' 112endfunction 113 114function! s:find_continued_lnum(lnum) 115 let i = a:lnum 116 while i > 1 && s:is_continuation_line(getline(i - 1)) 117 let i -= 1 118 endwhile 119 return i 120endfunction 121 122function! s:is_case_label(line, pnum) 123 if a:line !~ '^\s*(\=.*)' 124 return 0 125 endif 126 127 if a:pnum > 0 128 let pine = getline(a:pnum) 129 if !(s:is_case(pine) || s:is_case_ended(pine)) 130 return 0 131 endif 132 endif 133 134 let suffix = substitute(a:line, '^\s*(\=', "", "") 135 let nesting = 0 136 let i = 0 137 let n = strlen(suffix) 138 while i < n 139 let c = suffix[i] 140 let i += 1 141 if c == '\\' 142 let i += 1 143 elseif c == '(' 144 let nesting += 1 145 elseif c == ')' 146 if nesting == 0 147 return 1 148 endif 149 let nesting -= 1 150 endif 151 endwhile 152 return 0 153endfunction 154 155function! s:is_case(line) 156 return a:line =~ '^\s*case\>' 157endfunction 158 159function! s:is_case_break(line) 160 return a:line =~ '^\s*;[;&]' 161endfunction 162 163function! s:is_case_ended(line) 164 return s:is_case_break(a:line) || a:line =~ ';[;&]\s*\%(#.*\)\=$' 165endfunction 166 167function! s:is_case_empty(line) 168 if a:line =~ '^\s*$' || a:line =~ '^\s*#' 169 return s:is_case_empty(getline(v:lnum - 1)) 170 else 171 return a:line =~ '^\s*case\>' 172 endif 173endfunction 174 175let &cpo = s:cpo_save 176unlet s:cpo_save 177