Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 1 | " Vim indent file |
Bram Moolenaar | acc2240 | 2020-06-07 21:07:18 +0200 | [diff] [blame] | 2 | " Language: YAML |
| 3 | " Maintainer: Nikolai Pavlov <zyx.vim@gmail.com> |
Bram Moolenaar | 0daafaa | 2022-09-04 17:45:43 +0100 | [diff] [blame] | 4 | " Last Updates: Lukas Reineke, "lacygoill" |
Bram Moolenaar | d799daa | 2022-06-20 11:17:32 +0100 | [diff] [blame] | 5 | " Last Change: 2022 Jun 17 |
Christian Brabandt | c6ed816 | 2024-08-15 22:29:47 +0200 | [diff] [blame] | 6 | " 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 Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 8 | |
| 9 | " Only load this indent file when no other was loaded. |
| 10 | if exists('b:did_indent') |
| 11 | finish |
| 12 | endif |
| 13 | |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 14 | let b:did_indent = 1 |
| 15 | |
| 16 | setlocal indentexpr=GetYAMLIndent(v:lnum) |
Christian Brabandt | c6ed816 | 2024-08-15 22:29:47 +0200 | [diff] [blame] | 17 | setlocal indentkeys=!^F,o,O,0},0],<:>,0- |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 18 | setlocal nosmartindent |
| 19 | |
| 20 | let b:undo_indent = 'setlocal indentexpr< indentkeys< smartindent<' |
| 21 | |
| 22 | " Only define the function once. |
| 23 | if exists('*GetYAMLIndent') |
| 24 | finish |
| 25 | endif |
| 26 | |
Bram Moolenaar | e0e3917 | 2021-01-25 21:14:57 +0100 | [diff] [blame] | 27 | let s:save_cpo = &cpo |
| 28 | set cpo&vim |
| 29 | |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 30 | function s:FindPrevLessIndentedLine(lnum, ...) |
| 31 | let prevlnum = prevnonblank(a:lnum-1) |
| 32 | let curindent = a:0 ? a:1 : indent(a:lnum) |
| 33 | while prevlnum |
Bram Moolenaar | 0daafaa | 2022-09-04 17:45:43 +0100 | [diff] [blame] | 34 | \ && indent(prevlnum) >= curindent |
| 35 | \ && getline(prevlnum) !~# '^\s*#' |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 36 | let prevlnum = prevnonblank(prevlnum-1) |
| 37 | endwhile |
| 38 | return prevlnum |
| 39 | endfunction |
| 40 | |
| 41 | function 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 |
| 47 | endfunction |
| 48 | |
Bram Moolenaar | d799daa | 2022-06-20 11:17:32 +0100 | [diff] [blame] | 49 | let s:mapkeyregex = '\v^\s*\#@!\S@=%(\''%([^'']|\''\'')*\''' .. |
| 50 | \ '|\"%([^"\\]|\\.)*\"' .. |
Bram Moolenaar | dc1f164 | 2016-08-16 18:33:43 +0200 | [diff] [blame] | 51 | \ '|%(%(\:\ )@!.)*)\:%(\ |$)' |
Bram Moolenaar | d799daa | 2022-06-20 11:17:32 +0100 | [diff] [blame] | 52 | let s:liststartregex = '\v^\s*%(\-%(\ |$))' |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 53 | |
Bram Moolenaar | dc1f164 | 2016-08-16 18:33:43 +0200 | [diff] [blame] | 54 | let s:c_ns_anchor_char = '\v%([\n\r\uFEFF \t,[\]{}]@!\p)' |
Bram Moolenaar | d799daa | 2022-06-20 11:17:32 +0100 | [diff] [blame] | 55 | let s:c_ns_anchor_name = s:c_ns_anchor_char .. '+' |
| 56 | let s:c_ns_anchor_property = '\v\&' .. s:c_ns_anchor_name |
Bram Moolenaar | dc1f164 | 2016-08-16 18:33:43 +0200 | [diff] [blame] | 57 | |
| 58 | let s:ns_word_char = '\v[[:alnum:]_\-]' |
Bram Moolenaar | 0daafaa | 2022-09-04 17:45:43 +0100 | [diff] [blame] | 59 | let s:ns_tag_char = '\v%(\x\x|' .. s:ns_word_char .. '|[#/;?:@&=+$.~*''()])' |
Bram Moolenaar | d799daa | 2022-06-20 11:17:32 +0100 | [diff] [blame] | 60 | let s:c_named_tag_handle = '\v\!' .. s:ns_word_char .. '+\!' |
Bram Moolenaar | dc1f164 | 2016-08-16 18:33:43 +0200 | [diff] [blame] | 61 | let s:c_secondary_tag_handle = '\v\!\!' |
| 62 | let s:c_primary_tag_handle = '\v\!' |
Bram Moolenaar | d799daa | 2022-06-20 11:17:32 +0100 | [diff] [blame] | 63 | let s:c_tag_handle = '\v%(' .. s:c_named_tag_handle. |
| 64 | \ '|' .. s:c_secondary_tag_handle. |
| 65 | \ '|' .. s:c_primary_tag_handle .. ')' |
| 66 | let s:c_ns_shorthand_tag = '\v' .. s:c_tag_handle .. s:ns_tag_char .. '+' |
Bram Moolenaar | dc1f164 | 2016-08-16 18:33:43 +0200 | [diff] [blame] | 67 | let s:c_non_specific_tag = '\v\!' |
Bram Moolenaar | 0daafaa | 2022-09-04 17:45:43 +0100 | [diff] [blame] | 68 | let s:ns_uri_char = '\v%(\x\x|' .. s:ns_word_char .. '\v|[#/;?:@&=+$,.!~*''()[\]])' |
Bram Moolenaar | d799daa | 2022-06-20 11:17:32 +0100 | [diff] [blame] | 69 | let s:c_verbatim_tag = '\v\!\<' .. s:ns_uri_char.. '+\>' |
| 70 | let 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 Moolenaar | dc1f164 | 2016-08-16 18:33:43 +0200 | [diff] [blame] | 73 | |
| 74 | let s:block_scalar_header = '\v[|>]%([+-]?[1-9]|[1-9]?[+-])?' |
| 75 | |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 76 | function 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 Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 117 | return previndent+shiftwidth() |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 118 | 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 Moolenaar | ca63501 | 2015-09-25 20:34:21 +0200 | [diff] [blame] | 136 | 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 Brabandt | b4eb3f1 | 2024-02-29 17:23:51 +0100 | [diff] [blame] | 143 | elseif get(g:, 'yaml_indent_multiline_scalar', 0) && |
| 144 | \ prevline =~# '^\s*- ' |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 145 | " - List with |
| 146 | " multiline scalar |
| 147 | return previndent+2 |
Christian Brabandt | b4eb3f1 | 2024-02-29 17:23:51 +0100 | [diff] [blame] | 148 | elseif get(g:, 'yaml_indent_multiline_scalar', 0) && |
| 149 | \ prevline =~# s:mapkeyregex .. '\v\s*%(%(' .. s:c_ns_tag_property .. |
Bram Moolenaar | d799daa | 2022-06-20 11:17:32 +0100 | [diff] [blame] | 150 | \ '\v|' .. s:c_ns_anchor_property .. |
| 151 | \ '\v|' .. s:block_scalar_header .. |
Bram Moolenaar | dc1f164 | 2016-08-16 18:33:43 +0200 | [diff] [blame] | 152 | \ '\v)%(\s+|\s*%(\#.*)?$))*' |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 153 | " Mapping with: value |
| 154 | " that is multiline scalar |
Bram Moolenaar | 3ec574f | 2017-06-13 18:12:01 +0200 | [diff] [blame] | 155 | return previndent+shiftwidth() |
Bram Moolenaar | 34feacb | 2012-12-05 19:01:43 +0100 | [diff] [blame] | 156 | endif |
| 157 | return previndent |
| 158 | endfunction |
| 159 | |
| 160 | let &cpo = s:save_cpo |