blob: c38712745d4821266024e3d1b623cd183ed4f6b8 [file] [log] [blame]
Bram Moolenaar34feacb2012-12-05 19:01:43 +01001" Vim indent file
Bram Moolenaaracc22402020-06-07 21:07:18 +02002" Language: YAML
3" Maintainer: Nikolai Pavlov <zyx.vim@gmail.com>
Bram Moolenaar0daafaa2022-09-04 17:45:43 +01004" Last Updates: Lukas Reineke, "lacygoill"
Bram Moolenaard799daa2022-06-20 11:17:32 +01005" Last Change: 2022 Jun 17
Christian Brabandtc6ed8162024-08-15 22:29:47 +02006" 2024 Feb 29 by Vim project: disable mulitline indent by default
7" 2024 Aug 14 by Vim project: fix re-indenting when commenting out lines
Bram Moolenaar34feacb2012-12-05 19:01:43 +01008
9" Only load this indent file when no other was loaded.
10if exists('b:did_indent')
11 finish
12endif
13
Bram Moolenaar34feacb2012-12-05 19:01:43 +010014let b:did_indent = 1
15
16setlocal indentexpr=GetYAMLIndent(v:lnum)
Christian Brabandtc6ed8162024-08-15 22:29:47 +020017setlocal indentkeys=!^F,o,O,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
Bram Moolenaare0e39172021-01-25 21:14:57 +010027let s:save_cpo = &cpo
28set cpo&vim
29
Bram Moolenaar34feacb2012-12-05 19:01:43 +010030function s:FindPrevLessIndentedLine(lnum, ...)
31 let prevlnum = prevnonblank(a:lnum-1)
32 let curindent = a:0 ? a:1 : indent(a:lnum)
33 while prevlnum
Bram Moolenaar0daafaa2022-09-04 17:45:43 +010034 \ && indent(prevlnum) >= curindent
35 \ && getline(prevlnum) !~# '^\s*#'
Bram Moolenaar34feacb2012-12-05 19:01:43 +010036 let prevlnum = prevnonblank(prevlnum-1)
37 endwhile
38 return prevlnum
39endfunction
40
41function s:FindPrevLEIndentedLineMatchingRegex(lnum, regex)
42 let plilnum = s:FindPrevLessIndentedLine(a:lnum, indent(a:lnum)+1)
43 while plilnum && getline(plilnum) !~# a:regex
44 let plilnum = s:FindPrevLessIndentedLine(plilnum)
45 endwhile
46 return plilnum
47endfunction
48
Bram Moolenaard799daa2022-06-20 11:17:32 +010049let s:mapkeyregex = '\v^\s*\#@!\S@=%(\''%([^'']|\''\'')*\''' ..
50 \ '|\"%([^"\\]|\\.)*\"' ..
Bram Moolenaardc1f1642016-08-16 18:33:43 +020051 \ '|%(%(\:\ )@!.)*)\:%(\ |$)'
Bram Moolenaard799daa2022-06-20 11:17:32 +010052let s:liststartregex = '\v^\s*%(\-%(\ |$))'
Bram Moolenaar34feacb2012-12-05 19:01:43 +010053
Bram Moolenaardc1f1642016-08-16 18:33:43 +020054let s:c_ns_anchor_char = '\v%([\n\r\uFEFF \t,[\]{}]@!\p)'
Bram Moolenaard799daa2022-06-20 11:17:32 +010055let s:c_ns_anchor_name = s:c_ns_anchor_char .. '+'
56let s:c_ns_anchor_property = '\v\&' .. s:c_ns_anchor_name
Bram Moolenaardc1f1642016-08-16 18:33:43 +020057
58let s:ns_word_char = '\v[[:alnum:]_\-]'
Bram Moolenaar0daafaa2022-09-04 17:45:43 +010059let s:ns_tag_char = '\v%(\x\x|' .. s:ns_word_char .. '|[#/;?:@&=+$.~*''()])'
Bram Moolenaard799daa2022-06-20 11:17:32 +010060let s:c_named_tag_handle = '\v\!' .. s:ns_word_char .. '+\!'
Bram Moolenaardc1f1642016-08-16 18:33:43 +020061let s:c_secondary_tag_handle = '\v\!\!'
62let s:c_primary_tag_handle = '\v\!'
Bram Moolenaard799daa2022-06-20 11:17:32 +010063let s:c_tag_handle = '\v%(' .. s:c_named_tag_handle.
64 \ '|' .. s:c_secondary_tag_handle.
65 \ '|' .. s:c_primary_tag_handle .. ')'
66let s:c_ns_shorthand_tag = '\v' .. s:c_tag_handle .. s:ns_tag_char .. '+'
Bram Moolenaardc1f1642016-08-16 18:33:43 +020067let s:c_non_specific_tag = '\v\!'
Bram Moolenaar0daafaa2022-09-04 17:45:43 +010068let s:ns_uri_char = '\v%(\x\x|' .. s:ns_word_char .. '\v|[#/;?:@&=+$,.!~*''()[\]])'
Bram Moolenaard799daa2022-06-20 11:17:32 +010069let s:c_verbatim_tag = '\v\!\<' .. s:ns_uri_char.. '+\>'
70let s:c_ns_tag_property = '\v' .. s:c_verbatim_tag.
71 \ '\v|' .. s:c_ns_shorthand_tag.
72 \ '\v|' .. s:c_non_specific_tag
Bram Moolenaardc1f1642016-08-16 18:33:43 +020073
74let s:block_scalar_header = '\v[|>]%([+-]?[1-9]|[1-9]?[+-])?'
75
Bram Moolenaar34feacb2012-12-05 19:01:43 +010076function GetYAMLIndent(lnum)
77 if a:lnum == 1 || !prevnonblank(a:lnum-1)
78 return 0
79 endif
80
81 let prevlnum = prevnonblank(a:lnum-1)
82 let previndent = indent(prevlnum)
83
84 let line = getline(a:lnum)
85 if line =~# '^\s*#' && getline(a:lnum-1) =~# '^\s*#'
86 " Comment blocks should have identical indent
87 return previndent
88 elseif line =~# '^\s*[\]}]'
89 " Lines containing only closing braces should have previous indent
90 return indent(s:FindPrevLessIndentedLine(a:lnum))
91 endif
92
93 " Ignore comment lines when calculating indent
94 while getline(prevlnum) =~# '^\s*#'
95 let prevlnum = prevnonblank(prevlnum-1)
96 if !prevlnum
97 return previndent
98 endif
99 endwhile
100
101 let prevline = getline(prevlnum)
102 let previndent = indent(prevlnum)
103
104 " Any examples below assume that shiftwidth=2
105 if prevline =~# '\v[{[:]$|[:-]\ [|>][+\-]?%(\s+\#.*|\s*)$'
106 " Mapping key:
107 " nested mapping: ...
108 "
109 " - {
110 " key: [
111 " list value
112 " ]
113 " }
114 "
115 " - |-
116 " Block scalar without indentation indicator
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200117 return previndent+shiftwidth()
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100118 elseif prevline =~# '\v[:-]\ [|>]%(\d+[+\-]?|[+\-]?\d+)%(\#.*|\s*)$'
119 " - |+2
120 " block scalar with indentation indicator
121 "#^^ indent+2, not indent+shiftwidth
122 return previndent + str2nr(matchstr(prevline,
123 \'\v([:-]\ [|>])@<=[+\-]?\d+%([+\-]?%(\s+\#.*|\s*)$)@='))
124 elseif prevline =~# '\v\"%([^"\\]|\\.)*\\$'
125 " "Multiline string \
126 " with escaped end"
127 let qidx = match(prevline, '\v\"%([^"\\]|\\.)*\\')
128 return virtcol([prevlnum, qidx+1])
129 elseif line =~# s:liststartregex
130 " List line should have indent equal to previous list line unless it was
131 " caught by one of the previous rules
132 return indent(s:FindPrevLEIndentedLineMatchingRegex(a:lnum,
133 \ s:liststartregex))
134 elseif line =~# s:mapkeyregex
135 " Same for line containing mapping key
Bram Moolenaarca635012015-09-25 20:34:21 +0200136 let prevmapline = s:FindPrevLEIndentedLineMatchingRegex(a:lnum,
137 \ s:mapkeyregex)
138 if getline(prevmapline) =~# '^\s*- '
139 return indent(prevmapline) + 2
140 else
141 return indent(prevmapline)
142 endif
Christian Brabandtb4eb3f12024-02-29 17:23:51 +0100143 elseif get(g:, 'yaml_indent_multiline_scalar', 0) &&
144 \ prevline =~# '^\s*- '
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100145 " - List with
146 " multiline scalar
147 return previndent+2
Christian Brabandtb4eb3f12024-02-29 17:23:51 +0100148 elseif get(g:, 'yaml_indent_multiline_scalar', 0) &&
149 \ prevline =~# s:mapkeyregex .. '\v\s*%(%(' .. s:c_ns_tag_property ..
Bram Moolenaard799daa2022-06-20 11:17:32 +0100150 \ '\v|' .. s:c_ns_anchor_property ..
151 \ '\v|' .. s:block_scalar_header ..
Bram Moolenaardc1f1642016-08-16 18:33:43 +0200152 \ '\v)%(\s+|\s*%(\#.*)?$))*'
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100153 " Mapping with: value
154 " that is multiline scalar
Bram Moolenaar3ec574f2017-06-13 18:12:01 +0200155 return previndent+shiftwidth()
Bram Moolenaar34feacb2012-12-05 19:01:43 +0100156 endif
157 return previndent
158endfunction
159
160let &cpo = s:save_cpo