123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- " 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
|