blob: 3201462fbc8067f7b0d9621e8f8baeeb1fbc028a [file] [log] [blame]
Bram Moolenaar34feacb2012-12-05 19:01:43 +01001" Vim indent file
2" Language: YAML
3" Maintainer: Nikolai Pavlov <zyx.vim@gmail.com>
Bram Moolenaarb4ff5182015-11-10 21:15:48 +01004" Last Change: 2015 Nov 01
Bram Moolenaar34feacb2012-12-05 19:01:43 +01005
6" Only load this indent file when no other was loaded.
7if exists('b:did_indent')
8 finish
9endif
10
11let s:save_cpo = &cpo
12set cpo&vim
13
14let b:did_indent = 1
15
16setlocal indentexpr=GetYAMLIndent(v:lnum)
Bram Moolenaarb4ff5182015-11-10 21:15:48 +010017setlocal indentkeys=!^F,o,O,0#,0},0],<:>,0-
Bram Moolenaar34feacb2012-12-05 19:01:43 +010018setlocal nosmartindent
19
20let b:undo_indent = 'setlocal indentexpr< indentkeys< smartindent<'
21
22" Only define the function once.
23if exists('*GetYAMLIndent')
24 finish
25endif
26
27if exists('*shiftwidth')
28 let s:shiftwidth = function('shiftwidth')
29else
30 function s:shiftwidth()
31 return &shiftwidth
32 endfunction
33endif
34
35function s:FindPrevLessIndentedLine(lnum, ...)
36 let prevlnum = prevnonblank(a:lnum-1)
37 let curindent = a:0 ? a:1 : indent(a:lnum)
38 while prevlnum
39 \&& indent(prevlnum) >= curindent
Bram Moolenaardc1f1642016-08-16 18:33:43 +020040 \&& getline(prevlnum) =~# '^\s*#'
Bram Moolenaar34feacb2012-12-05 19:01:43 +010041 let prevlnum = prevnonblank(prevlnum-1)
42 endwhile
43 return prevlnum
44endfunction
45
46function s:FindPrevLEIndentedLineMatchingRegex(lnum, regex)
47 let plilnum = s:FindPrevLessIndentedLine(a:lnum, indent(a:lnum)+1)
48 while plilnum && getline(plilnum) !~# a:regex
49 let plilnum = s:FindPrevLessIndentedLine(plilnum)
50 endwhile
51 return plilnum
52endfunction
53
Bram Moolenaardc1f1642016-08-16 18:33:43 +020054let s:mapkeyregex='\v^\s*\#@!\S@=%(\''%([^'']|\''\'')*\'''.
55 \ '|\"%([^"\\]|\\.)*\"'.
56 \ '|%(%(\:\ )@!.)*)\:%(\ |$)'
Bram Moolenaar34feacb2012-12-05 19:01:43 +010057let s:liststartregex='\v^\s*%(\-%(\ |$))'
58
Bram Moolenaardc1f1642016-08-16 18:33:43 +020059let s:c_ns_anchor_char = '\v%([\n\r\uFEFF \t,[\]{}]@!\p)'
60let s:c_ns_anchor_name = s:c_ns_anchor_char.'+'
61let s:c_ns_anchor_property = '\v\&'.s:c_ns_anchor_name
62
63let s:ns_word_char = '\v[[:alnum:]_\-]'
64let s:ns_tag_char = '\v%(%\x\x|'.s:ns_word_char.'|[#/;?:@&=+$.~*''()])'
65let s:c_named_tag_handle = '\v\!'.s:ns_word_char.'+\!'
66let s:c_secondary_tag_handle = '\v\!\!'
67let s:c_primary_tag_handle = '\v\!'
68let s:c_tag_handle = '\v%('.s:c_named_tag_handle.
69 \ '|'.s:c_secondary_tag_handle.
70 \ '|'.s:c_primary_tag_handle.')'
71let s:c_ns_shorthand_tag = '\v'.s:c_tag_handle . s:ns_tag_char.'+'
72let s:c_non_specific_tag = '\v\!'
73let s:ns_uri_char = '\v%(%\x\x|'.s:ns_word_char.'\v|[#/;?:@&=+$,.!~*''()[\]])'
74let s:c_verbatim_tag = '\v\!\<'.s:ns_uri_char.'+\>'
75let s:c_ns_tag_property = '\v'.s:c_verbatim_tag.
76 \ '\v|'.s:c_ns_shorthand_tag.
77 \ '\v|'.s:c_non_specific_tag
78
79let s:block_scalar_header = '\v[|>]%([+-]?[1-9]|[1-9]?[+-])?'
80
Bram Moolenaar34feacb2012-12-05 19:01:43 +010081function GetYAMLIndent(lnum)
82 if a:lnum == 1 || !prevnonblank(a:lnum-1)
83 return 0
84 endif
85
86 let prevlnum = prevnonblank(a:lnum-1)
87 let previndent = indent(prevlnum)
88
89 let line = getline(a:lnum)
90 if line =~# '^\s*#' && getline(a:lnum-1) =~# '^\s*#'
91 " Comment blocks should have identical indent
92 return previndent
93 elseif line =~# '^\s*[\]}]'
94 " Lines containing only closing braces should have previous indent
95 return indent(s:FindPrevLessIndentedLine(a:lnum))
96 endif
97
98 " Ignore comment lines when calculating indent
99 while getline(prevlnum) =~# '^\s*#'
100 let prevlnum = prevnonblank(prevlnum-1)
101 if !prevlnum
102 return previndent
103 endif
104 endwhile
105
106 let prevline = getline(prevlnum)
107 let previndent = indent(prevlnum)
108
109 " Any examples below assume that shiftwidth=2
110 if prevline =~# '\v[{[:]$|[:-]\ [|>][+\-]?%(\s+\#.*|\s*)$'
111 " Mapping key:
112 " nested mapping: ...
113 "
114 " - {
115 " key: [
116 " list value
117 " ]
118 " }
119 "
120 " - |-
121 " Block scalar without indentation indicator
122 return previndent+s:shiftwidth()
123 elseif prevline =~# '\v[:-]\ [|>]%(\d+[+\-]?|[+\-]?\d+)%(\#.*|\s*)$'
124 " - |+2
125 " block scalar with indentation indicator
126 "#^^ indent+2, not indent+shiftwidth
127 return previndent + str2nr(matchstr(prevline,
128 \'\v([:-]\ [|>])@<=[+\-]?\d+%([+\-]?%(\s+\#.*|\s*)$)@='))
129 elseif prevline =~# '\v\"%([^"\\]|\\.)*\\$'
130 " "Multiline string \
131 " with escaped end"
132 let qidx = match(prevline, '\v\"%([^"\\]|\\.)*\\')
133 return virtcol([prevlnum, qidx+1])
134 elseif line =~# s:liststartregex
135 " List line should have indent equal to previous list line unless it was
136 " caught by one of the previous rules
137 return indent(s:FindPrevLEIndentedLineMatchingRegex(a:lnum,
138 \ s:liststartregex))
139 elseif line =~# s:mapkeyregex
140 " Same for line containing mapping key
Bram Moolenaarca635012015-09-25 20:34:21 +0200141 let prevmapline = s:FindPrevLEIndentedLineMatchingRegex(a:lnum,
142 \ s:mapkeyregex)
143 if getline(prevmapline) =~# '^\s*- '
144 return indent(prevmapline) + 2
145 else
146 return indent(prevmapline)
147 endif
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100148 elseif prevline =~# '^\s*- '
149 " - List with
150 " multiline scalar
151 return previndent+2
Bram Moolenaardc1f1642016-08-16 18:33:43 +0200152 elseif prevline =~# s:mapkeyregex . '\v\s*%(%('.s:c_ns_tag_property.
153 \ '\v|'.s:c_ns_anchor_property.
154 \ '\v|'.s:block_scalar_header.
155 \ '\v)%(\s+|\s*%(\#.*)?$))*'
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100156 " Mapping with: value
157 " that is multiline scalar
158 return previndent+s:shiftwidth()
159 endif
160 return previndent
161endfunction
162
163let &cpo = s:save_cpo