diff options
Diffstat (limited to 'runtime/indent/yaml.vim')
-rw-r--r-- | runtime/indent/yaml.vim | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/runtime/indent/yaml.vim b/runtime/indent/yaml.vim new file mode 100644 index 0000000..93fd8ea --- /dev/null +++ b/runtime/indent/yaml.vim @@ -0,0 +1,156 @@ +" Vim indent file +" Language: YAML +" Maintainer: Nikolai Pavlov <zyx.vim@gmail.com> +" Last Updates: Lukas Reineke, "lacygoill" +" Last Change: 2022 Jun 17 + +" Only load this indent file when no other was loaded. +if exists('b:did_indent') + finish +endif + +let b:did_indent = 1 + +setlocal indentexpr=GetYAMLIndent(v:lnum) +setlocal indentkeys=!^F,o,O,0#,0},0],<:>,0- +setlocal nosmartindent + +let b:undo_indent = 'setlocal indentexpr< indentkeys< smartindent<' + +" Only define the function once. +if exists('*GetYAMLIndent') + finish +endif + +let s:save_cpo = &cpo +set cpo&vim + +function s:FindPrevLessIndentedLine(lnum, ...) + let prevlnum = prevnonblank(a:lnum-1) + let curindent = a:0 ? a:1 : indent(a:lnum) + while prevlnum + \ && indent(prevlnum) >= curindent + \ && getline(prevlnum) !~# '^\s*#' + let prevlnum = prevnonblank(prevlnum-1) + endwhile + return prevlnum +endfunction + +function s:FindPrevLEIndentedLineMatchingRegex(lnum, regex) + let plilnum = s:FindPrevLessIndentedLine(a:lnum, indent(a:lnum)+1) + while plilnum && getline(plilnum) !~# a:regex + let plilnum = s:FindPrevLessIndentedLine(plilnum) + endwhile + return plilnum +endfunction + +let s:mapkeyregex = '\v^\s*\#@!\S@=%(\''%([^'']|\''\'')*\''' .. + \ '|\"%([^"\\]|\\.)*\"' .. + \ '|%(%(\:\ )@!.)*)\:%(\ |$)' +let s:liststartregex = '\v^\s*%(\-%(\ |$))' + +let s:c_ns_anchor_char = '\v%([\n\r\uFEFF \t,[\]{}]@!\p)' +let s:c_ns_anchor_name = s:c_ns_anchor_char .. '+' +let s:c_ns_anchor_property = '\v\&' .. s:c_ns_anchor_name + +let s:ns_word_char = '\v[[:alnum:]_\-]' +let s:ns_tag_char = '\v%(\x\x|' .. s:ns_word_char .. '|[#/;?:@&=+$.~*''()])' +let s:c_named_tag_handle = '\v\!' .. s:ns_word_char .. '+\!' +let s:c_secondary_tag_handle = '\v\!\!' +let s:c_primary_tag_handle = '\v\!' +let s:c_tag_handle = '\v%(' .. s:c_named_tag_handle. + \ '|' .. s:c_secondary_tag_handle. + \ '|' .. s:c_primary_tag_handle .. ')' +let s:c_ns_shorthand_tag = '\v' .. s:c_tag_handle .. s:ns_tag_char .. '+' +let s:c_non_specific_tag = '\v\!' +let s:ns_uri_char = '\v%(\x\x|' .. s:ns_word_char .. '\v|[#/;?:@&=+$,.!~*''()[\]])' +let s:c_verbatim_tag = '\v\!\<' .. s:ns_uri_char.. '+\>' +let s:c_ns_tag_property = '\v' .. s:c_verbatim_tag. + \ '\v|' .. s:c_ns_shorthand_tag. + \ '\v|' .. s:c_non_specific_tag + +let s:block_scalar_header = '\v[|>]%([+-]?[1-9]|[1-9]?[+-])?' + +function GetYAMLIndent(lnum) + if a:lnum == 1 || !prevnonblank(a:lnum-1) + return 0 + endif + + let prevlnum = prevnonblank(a:lnum-1) + let previndent = indent(prevlnum) + + let line = getline(a:lnum) + if line =~# '^\s*#' && getline(a:lnum-1) =~# '^\s*#' + " Comment blocks should have identical indent + return previndent + elseif line =~# '^\s*[\]}]' + " Lines containing only closing braces should have previous indent + return indent(s:FindPrevLessIndentedLine(a:lnum)) + endif + + " Ignore comment lines when calculating indent + while getline(prevlnum) =~# '^\s*#' + let prevlnum = prevnonblank(prevlnum-1) + if !prevlnum + return previndent + endif + endwhile + + let prevline = getline(prevlnum) + let previndent = indent(prevlnum) + + " Any examples below assume that shiftwidth=2 + if prevline =~# '\v[{[:]$|[:-]\ [|>][+\-]?%(\s+\#.*|\s*)$' + " Mapping key: + " nested mapping: ... + " + " - { + " key: [ + " list value + " ] + " } + " + " - |- + " Block scalar without indentation indicator + return previndent+shiftwidth() + elseif prevline =~# '\v[:-]\ [|>]%(\d+[+\-]?|[+\-]?\d+)%(\#.*|\s*)$' + " - |+2 + " block scalar with indentation indicator + "#^^ indent+2, not indent+shiftwidth + return previndent + str2nr(matchstr(prevline, + \'\v([:-]\ [|>])@<=[+\-]?\d+%([+\-]?%(\s+\#.*|\s*)$)@=')) + elseif prevline =~# '\v\"%([^"\\]|\\.)*\\$' + " "Multiline string \ + " with escaped end" + let qidx = match(prevline, '\v\"%([^"\\]|\\.)*\\') + return virtcol([prevlnum, qidx+1]) + elseif line =~# s:liststartregex + " List line should have indent equal to previous list line unless it was + " caught by one of the previous rules + return indent(s:FindPrevLEIndentedLineMatchingRegex(a:lnum, + \ s:liststartregex)) + elseif line =~# s:mapkeyregex + " Same for line containing mapping key + let prevmapline = s:FindPrevLEIndentedLineMatchingRegex(a:lnum, + \ s:mapkeyregex) + if getline(prevmapline) =~# '^\s*- ' + return indent(prevmapline) + 2 + else + return indent(prevmapline) + endif + elseif prevline =~# '^\s*- ' + " - List with + " multiline scalar + return previndent+2 + elseif prevline =~# s:mapkeyregex .. '\v\s*%(%(' .. s:c_ns_tag_property .. + \ '\v|' .. s:c_ns_anchor_property .. + \ '\v|' .. s:block_scalar_header .. + \ '\v)%(\s+|\s*%(\#.*)?$))*' + " Mapping with: value + " that is multiline scalar + return previndent+shiftwidth() + endif + return previndent +endfunction + +let &cpo = s:save_cpo |