xref: /vim-8.2.3635/runtime/indent/yaml.vim (revision 2bf24176)
1" Vim indent file
2" Language:         YAML
3" Maintainer:       Nikolai Pavlov <[email protected]>
4" Last Change:	    2015 Nov 01
5
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)
17setlocal indentkeys=!^F,o,O,0#,0},0],<:>,0-
18setlocal 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
40                \&& getline(prevlnum) !~# '^\s*#'
41        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
54let s:mapkeyregex='\v^\s*%(\''%([^'']|'''')*\'''.
55                \        '|\"%([^"\\]|\\.)*\"'.
56                \        '|%(%(\:\ )@!.)*)\:%(\ |$)'
57let s:liststartregex='\v^\s*%(\-%(\ |$))'
58
59function GetYAMLIndent(lnum)
60    if a:lnum == 1 || !prevnonblank(a:lnum-1)
61        return 0
62    endif
63
64    let prevlnum = prevnonblank(a:lnum-1)
65    let previndent = indent(prevlnum)
66
67    let line = getline(a:lnum)
68    if line =~# '^\s*#' && getline(a:lnum-1) =~# '^\s*#'
69        " Comment blocks should have identical indent
70        return previndent
71    elseif line =~# '^\s*[\]}]'
72        " Lines containing only closing braces should have previous indent
73        return indent(s:FindPrevLessIndentedLine(a:lnum))
74    endif
75
76    " Ignore comment lines when calculating indent
77    while getline(prevlnum) =~# '^\s*#'
78        let prevlnum = prevnonblank(prevlnum-1)
79        if !prevlnum
80            return previndent
81        endif
82    endwhile
83
84    let prevline = getline(prevlnum)
85    let previndent = indent(prevlnum)
86
87    " Any examples below assume that shiftwidth=2
88    if prevline =~# '\v[{[:]$|[:-]\ [|>][+\-]?%(\s+\#.*|\s*)$'
89        " Mapping key:
90        "     nested mapping: ...
91        "
92        " - {
93        "     key: [
94        "         list value
95        "     ]
96        " }
97        "
98        " - |-
99        "     Block scalar without indentation indicator
100        return previndent+s:shiftwidth()
101    elseif prevline =~# '\v[:-]\ [|>]%(\d+[+\-]?|[+\-]?\d+)%(\#.*|\s*)$'
102        " - |+2
103        "   block scalar with indentation indicator
104        "#^^ indent+2, not indent+shiftwidth
105        return previndent + str2nr(matchstr(prevline,
106                    \'\v([:-]\ [|>])@<=[+\-]?\d+%([+\-]?%(\s+\#.*|\s*)$)@='))
107    elseif prevline =~# '\v\"%([^"\\]|\\.)*\\$'
108        "    "Multiline string \
109        "     with escaped end"
110        let qidx = match(prevline, '\v\"%([^"\\]|\\.)*\\')
111        return virtcol([prevlnum, qidx+1])
112    elseif line =~# s:liststartregex
113        " List line should have indent equal to previous list line unless it was
114        " caught by one of the previous rules
115        return indent(s:FindPrevLEIndentedLineMatchingRegex(a:lnum,
116                    \                                       s:liststartregex))
117    elseif line =~# s:mapkeyregex
118        " Same for line containing mapping key
119        let prevmapline = s:FindPrevLEIndentedLineMatchingRegex(a:lnum,
120                    \                                           s:mapkeyregex)
121        if getline(prevmapline) =~# '^\s*- '
122            return indent(prevmapline) + 2
123        else
124            return indent(prevmapline)
125        endif
126    elseif prevline =~# '^\s*- '
127        " - List with
128        "   multiline scalar
129        return previndent+2
130    elseif prevline =~# s:mapkeyregex
131        " Mapping with: value
132        "     that is multiline scalar
133        return previndent+s:shiftwidth()
134    endif
135    return previndent
136endfunction
137
138let &cpo = s:save_cpo
139