1" Vim indent file 2" Language: YAML 3" Maintainer: Nikolai Pavlov <[email protected]> 4" Last Change: 2017 Jun 13 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 27function s:FindPrevLessIndentedLine(lnum, ...) 28 let prevlnum = prevnonblank(a:lnum-1) 29 let curindent = a:0 ? a:1 : indent(a:lnum) 30 while prevlnum 31 \&& indent(prevlnum) >= curindent 32 \&& getline(prevlnum) =~# '^\s*#' 33 let prevlnum = prevnonblank(prevlnum-1) 34 endwhile 35 return prevlnum 36endfunction 37 38function s:FindPrevLEIndentedLineMatchingRegex(lnum, regex) 39 let plilnum = s:FindPrevLessIndentedLine(a:lnum, indent(a:lnum)+1) 40 while plilnum && getline(plilnum) !~# a:regex 41 let plilnum = s:FindPrevLessIndentedLine(plilnum) 42 endwhile 43 return plilnum 44endfunction 45 46let s:mapkeyregex='\v^\s*\#@!\S@=%(\''%([^'']|\''\'')*\'''. 47 \ '|\"%([^"\\]|\\.)*\"'. 48 \ '|%(%(\:\ )@!.)*)\:%(\ |$)' 49let s:liststartregex='\v^\s*%(\-%(\ |$))' 50 51let s:c_ns_anchor_char = '\v%([\n\r\uFEFF \t,[\]{}]@!\p)' 52let s:c_ns_anchor_name = s:c_ns_anchor_char.'+' 53let s:c_ns_anchor_property = '\v\&'.s:c_ns_anchor_name 54 55let s:ns_word_char = '\v[[:alnum:]_\-]' 56let s:ns_tag_char = '\v%(%\x\x|'.s:ns_word_char.'|[#/;?:@&=+$.~*''()])' 57let s:c_named_tag_handle = '\v\!'.s:ns_word_char.'+\!' 58let s:c_secondary_tag_handle = '\v\!\!' 59let s:c_primary_tag_handle = '\v\!' 60let s:c_tag_handle = '\v%('.s:c_named_tag_handle. 61 \ '|'.s:c_secondary_tag_handle. 62 \ '|'.s:c_primary_tag_handle.')' 63let s:c_ns_shorthand_tag = '\v'.s:c_tag_handle . s:ns_tag_char.'+' 64let s:c_non_specific_tag = '\v\!' 65let s:ns_uri_char = '\v%(%\x\x|'.s:ns_word_char.'\v|[#/;?:@&=+$,.!~*''()[\]])' 66let s:c_verbatim_tag = '\v\!\<'.s:ns_uri_char.'+\>' 67let s:c_ns_tag_property = '\v'.s:c_verbatim_tag. 68 \ '\v|'.s:c_ns_shorthand_tag. 69 \ '\v|'.s:c_non_specific_tag 70 71let s:block_scalar_header = '\v[|>]%([+-]?[1-9]|[1-9]?[+-])?' 72 73function GetYAMLIndent(lnum) 74 if a:lnum == 1 || !prevnonblank(a:lnum-1) 75 return 0 76 endif 77 78 let prevlnum = prevnonblank(a:lnum-1) 79 let previndent = indent(prevlnum) 80 81 let line = getline(a:lnum) 82 if line =~# '^\s*#' && getline(a:lnum-1) =~# '^\s*#' 83 " Comment blocks should have identical indent 84 return previndent 85 elseif line =~# '^\s*[\]}]' 86 " Lines containing only closing braces should have previous indent 87 return indent(s:FindPrevLessIndentedLine(a:lnum)) 88 endif 89 90 " Ignore comment lines when calculating indent 91 while getline(prevlnum) =~# '^\s*#' 92 let prevlnum = prevnonblank(prevlnum-1) 93 if !prevlnum 94 return previndent 95 endif 96 endwhile 97 98 let prevline = getline(prevlnum) 99 let previndent = indent(prevlnum) 100 101 " Any examples below assume that shiftwidth=2 102 if prevline =~# '\v[{[:]$|[:-]\ [|>][+\-]?%(\s+\#.*|\s*)$' 103 " Mapping key: 104 " nested mapping: ... 105 " 106 " - { 107 " key: [ 108 " list value 109 " ] 110 " } 111 " 112 " - |- 113 " Block scalar without indentation indicator 114 return previndent+shiftwidth() 115 elseif prevline =~# '\v[:-]\ [|>]%(\d+[+\-]?|[+\-]?\d+)%(\#.*|\s*)$' 116 " - |+2 117 " block scalar with indentation indicator 118 "#^^ indent+2, not indent+shiftwidth 119 return previndent + str2nr(matchstr(prevline, 120 \'\v([:-]\ [|>])@<=[+\-]?\d+%([+\-]?%(\s+\#.*|\s*)$)@=')) 121 elseif prevline =~# '\v\"%([^"\\]|\\.)*\\$' 122 " "Multiline string \ 123 " with escaped end" 124 let qidx = match(prevline, '\v\"%([^"\\]|\\.)*\\') 125 return virtcol([prevlnum, qidx+1]) 126 elseif line =~# s:liststartregex 127 " List line should have indent equal to previous list line unless it was 128 " caught by one of the previous rules 129 return indent(s:FindPrevLEIndentedLineMatchingRegex(a:lnum, 130 \ s:liststartregex)) 131 elseif line =~# s:mapkeyregex 132 " Same for line containing mapping key 133 let prevmapline = s:FindPrevLEIndentedLineMatchingRegex(a:lnum, 134 \ s:mapkeyregex) 135 if getline(prevmapline) =~# '^\s*- ' 136 return indent(prevmapline) + 2 137 else 138 return indent(prevmapline) 139 endif 140 elseif prevline =~# '^\s*- ' 141 " - List with 142 " multiline scalar 143 return previndent+2 144 elseif prevline =~# s:mapkeyregex . '\v\s*%(%('.s:c_ns_tag_property. 145 \ '\v|'.s:c_ns_anchor_property. 146 \ '\v|'.s:block_scalar_header. 147 \ '\v)%(\s+|\s*%(\#.*)?$))*' 148 " Mapping with: value 149 " that is multiline scalar 150 return previndent+shiftwidth() 151 endif 152 return previndent 153endfunction 154 155let &cpo = s:save_cpo 156