summaryrefslogtreecommitdiffstats
path: root/runtime/indent/vim.vim
blob: 4b0867d88a86fb5df198452941ae286c8922f013 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
" Vim indent file
" Language:	Vim script
" Maintainer:	Bram Moolenaar <Bram@vim.org>
" Last Change:	2020 Sep 27

" Only load this indent file when no other was loaded.
if exists("b:did_indent")
  finish
endif
let b:did_indent = 1

setlocal indentexpr=GetVimIndent()
setlocal indentkeys+==end,=},=else,=cat,=finall,=END,0\\,0=\"\\\ 
setlocal indentkeys-=0#

let b:undo_indent = "setl indentkeys< indentexpr<"

" Only define the function once.
if exists("*GetVimIndent")
  finish
endif
let s:keepcpo= &cpo
set cpo&vim

function GetVimIndent()
  let ignorecase_save = &ignorecase
  try
    let &ignorecase = 0
    return GetVimIndentIntern()
  finally
    let &ignorecase = ignorecase_save
  endtry
endfunc

let s:lineContPat = '^\s*\(\\\|"\\ \)'

function GetVimIndentIntern()
  " Find a non-blank line above the current line.
  let lnum = prevnonblank(v:lnum - 1)

  " If the current line doesn't start with '\' or '"\ ' and below a line that
  " starts with '\' or '"\ ', use the indent of the line above it.
  let cur_text = getline(v:lnum)
  if cur_text !~ s:lineContPat
    while lnum > 0 && getline(lnum) =~ s:lineContPat
      let lnum = lnum - 1
    endwhile
  endif

  " At the start of the file use zero indent.
  if lnum == 0
    return 0
  endif
  let prev_text = getline(lnum)

  " Add a 'shiftwidth' after :if, :while, :try, :catch, :finally, :function
  " and :else.  Add it three times for a line that starts with '\' or '"\ '
  " after a line that doesn't (or g:vim_indent_cont if it exists).
  let ind = indent(lnum)

  " In heredoc indenting works completely differently.
  if has('syntax_items') 
    let syn_here = synIDattr(synID(v:lnum, 1, 1), "name")
    if syn_here =~ 'vimLetHereDocStop'
      " End of heredoc: use indent of matching start line
      let lnum = v:lnum - 1
      while lnum > 0
	if synIDattr(synID(lnum, 1, 1), "name") !~ 'vimLetHereDoc'
	  return indent(lnum)
	endif
	let lnum -= 1
      endwhile
      return 0
    endif
    if syn_here =~ 'vimLetHereDoc'
      if synIDattr(synID(lnum, 1, 1), "name") !~ 'vimLetHereDoc'
	" First line in heredoc: increase indent
	return ind + shiftwidth()
      endif
      " Heredoc continues: no change in indent
      return ind
    endif
  endif

  if cur_text =~ s:lineContPat && v:lnum > 1 && prev_text !~ s:lineContPat
    if exists("g:vim_indent_cont")
      let ind = ind + g:vim_indent_cont
    else
      let ind = ind + shiftwidth() * 3
    endif
  elseif prev_text =~ '^\s*aug\%[roup]\s\+' && prev_text !~ '^\s*aug\%[roup]\s\+[eE][nN][dD]\>'
    let ind = ind + shiftwidth()
  else
    " A line starting with :au does not increment/decrement indent.
    if prev_text !~ '^\s*au\%[tocmd]'
      let i = match(prev_text, '\(^\||\)\s*\(export\s\+\)\?\({\|\(if\|wh\%[ile]\|for\|try\|cat\%[ch]\|fina\|finall\%[y]\|fu\%[nction]\|def\|el\%[seif]\)\>\)')
      if i >= 0
	let ind += shiftwidth()
	if strpart(prev_text, i, 1) == '|' && has('syntax_items')
	      \ && synIDattr(synID(lnum, i, 1), "name") =~ '\(Comment\|String\)$'
	  let ind -= shiftwidth()
	endif
      endif
    endif
  endif

  " If the previous line contains an "end" after a pipe, but not in an ":au"
  " command.  And not when there is a backslash before the pipe.
  " And when syntax HL is enabled avoid a match inside a string.
  let i = match(prev_text, '[^\\]|\s*\(ene\@!\)')
  if i > 0 && prev_text !~ '^\s*au\%[tocmd]'
    if !has('syntax_items') || synIDattr(synID(lnum, i + 2, 1), "name") !~ '\(Comment\|String\)$'
      let ind = ind - shiftwidth()
    endif
  endif


  " Subtract a 'shiftwidth' on a :endif, :endwhile, :catch, :finally, :endtry,
  " :endfun, :enddef, :else and :augroup END.
  if cur_text =~ '^\s*\(ene\@!\|}\|cat\|finall\|el\|aug\%[roup]\s\+[eE][nN][dD]\)'
    let ind = ind - shiftwidth()
  endif

  return ind
endfunction

let &cpo = s:keepcpo
unlet s:keepcpo

" vim:sw=2