diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..4510efb
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,15 @@
+name: test
+
+on:
+ push:
+ pull_request:
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install Vim and Neovim
+ run: sudo apt-get update && sudo apt-get install -y vim neovim
+ - name: Run tests
+ run: ./test/run.sh
diff --git a/.gitignore b/.gitignore
index 6e9b2ec..4d4d57c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
README.html
test.vue
.DS_STORE
+test/deps/
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index e8679a7..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-dist: focal
-
-language: minimal
-
-before_install:
- - sudo add-apt-repository ppa:neovim-ppa/stable -y
- - sudo apt-get update
- - sudo apt-get -y install neovim
-
-install:
- - git clone https://github.com/leafOfTree/test ../test --depth=1
-
- - git clone https://github.com/digitaltoad/vim-pug ../vim-pug --depth=1
- - git clone https://github.com/kchmck/vim-coffee-script ../vim-coffee-script --depth=1
- - git clone https://github.com/leafgarland/typescript-vim ../typescript-vim --depth=1
- - git clone https://github.com/iloginow/vim-stylus.git ../vim-stylus --depth=1
-
-script:
- - bash ../test/start.sh vue vim-vue-plugin
diff --git a/README.md b/README.md
index 6996da7..f8b9ced 100644
--- a/README.md
+++ b/README.md
@@ -208,6 +208,17 @@ For example, the built-in syntax `sass.vim` and `less.vim` in vim8.1 runtime and
+ endif
```
+## Tests
+
+Run tests with Vim and Neovim, whichever is installed
+
+```sh
+./test/run.sh
+./test/run.sh basic template # Only these cases
+```
+
+Each case is a `.vue` file in [test/cases](test/cases), with an optional `.vim` file for the config and syntax checks. A case fails if indenting the whole file changes it, a check fails, or there is an error message. Tests also run on GitHub Actions for each push and pull request.
+
## Acknowledgments & Refs
- [mxw/vim-jsx][1]
diff --git a/test/cases/basic.vim b/test/cases/basic.vim
new file mode 100644
index 0000000..eb117a9
--- /dev/null
+++ b/test/cases/basic.vim
@@ -0,0 +1,7 @@
+let g:vim_vue_plugin_config = {
+ \'syntax': {
+ \ 'script': ['javascript'],
+ \ 'template': ['html'],
+ \ 'style': ['css'],
+ \},
+ \}
diff --git a/test/cases/basic.vue b/test/cases/basic.vue
new file mode 100644
index 0000000..1f7d4bc
--- /dev/null
+++ b/test/cases/basic.vue
@@ -0,0 +1,20 @@
+
+ {{ greeting }}
+
+
+
+
+
diff --git a/test/cases/example.vim b/test/cases/example.vim
new file mode 100644
index 0000000..530800c
--- /dev/null
+++ b/test/cases/example.vim
@@ -0,0 +1,15 @@
+" Uses syntax plugins in test/deps
+let g:vim_vue_plugin_config = {
+ \'syntax': {
+ \ 'template': ['html', 'pug'],
+ \ 'script': ['javascript', 'typescript', 'coffee'],
+ \ 'style': ['css', 'scss', 'sass', 'less', 'stylus'],
+ \ 'docs': 'markdown',
+ \ 'i18n': ['json', 'yaml'],
+ \ 'route': 'json',
+ \},
+ \'attribute': 1,
+ \'keyword': 1,
+ \'foldexpr': 1,
+ \'full_syntax': ['scss', 'less'],
+ \}
diff --git a/test/cases/example.vue b/test/cases/example.vue
new file mode 100644
index 0000000..fce9e3e
--- /dev/null
+++ b/test/cases/example.vue
@@ -0,0 +1,160 @@
+
+ div.set
+ span(id="123")
+
+
+
+
+
+
+
+
+ {{ greeting }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{
+ "name": "home",
+ "meta": {
+ "requiresAuth": true
+ }
+}
+
+
+
+# This is the documentation for component.
+
+
+
+en:
+ hello: "Hello World!"
+ja:
+ hello: "こんにちは、世界!"
+
+
+
+{
+ "en": {
+ "language": "Language",
+ "hello": "hello, world!"
+ },
+ "ja": {
+ "language": "言語",
+ "hello": "こんにちは、世界!"
+ }
+}
+
diff --git a/test/cases/fold.vim b/test/cases/fold.vim
new file mode 100644
index 0000000..2ba1f62
--- /dev/null
+++ b/test/cases/fold.vim
@@ -0,0 +1,15 @@
+let g:vim_vue_plugin_config = {
+ \'syntax': {
+ \ 'script': ['javascript'],
+ \ 'template': ['html'],
+ \ 'style': ['css'],
+ \},
+ \'foldexpr': 1,
+ \}
+
+function! Check()
+ let levels = [1, 2, 1, 1, 1, 2, 3, 4, 4, 3, 3, 1, 1, 1, 1, 1, 2, 2, 1, 1]
+ for lnum in range(1, len(levels))
+ call ExpectFoldlevel(lnum, levels[lnum - 1])
+ endfor
+endfunction
diff --git a/test/cases/fold.vue b/test/cases/fold.vue
new file mode 100644
index 0000000..1f7d4bc
--- /dev/null
+++ b/test/cases/fold.vue
@@ -0,0 +1,20 @@
+
+ {{ greeting }}
+
+
+
+
+
diff --git a/test/cases/indent.vim b/test/cases/indent.vim
new file mode 100644
index 0000000..a23b534
--- /dev/null
+++ b/test/cases/indent.vim
@@ -0,0 +1,9 @@
+let g:vim_vue_plugin_config = {
+ \'syntax': {
+ \ 'template': ['html'],
+ \ 'script': ['javascript'],
+ \ 'style': ['css', 'sass', 'scss'],
+ \ 'codepen-additional': ['javascript', 'json'],
+ \},
+ \'initial_indent': ['script', 'style', 'codepen-additional'],
+ \}
diff --git a/test/cases/indent.vue b/test/cases/indent.vue
new file mode 100644
index 0000000..52a4b8e
--- /dev/null
+++ b/test/cases/indent.vue
@@ -0,0 +1,27 @@
+
+ {{ greeting }}
+
+
+
+
+
+
+
+ const easings = {
+ linear: '',
+ easeInQuad: '',
+ }
+
diff --git a/test/cases/keyword.vim b/test/cases/keyword.vim
new file mode 100644
index 0000000..1300e7a
--- /dev/null
+++ b/test/cases/keyword.vim
@@ -0,0 +1,16 @@
+let g:vim_vue_plugin_config = {
+ \'syntax': {
+ \ 'template': ['html'],
+ \ 'script': ['javascript', 'typescript'],
+ \},
+ \'keyword': 1,
+ \'initial_indent': ['script', 'style', 'codepen-additional'],
+ \}
+
+function! Check()
+ call ExpectSyntax('name', 'vueObjectKey')
+ call ExpectSyntax('data', 'vueObjectFuncKey')
+ call ExpectSyntax('data', 'vueObjectFuncName')
+ call ExpectSyntax('computed', 'vueObjectKey')
+ call ExpectSyntax('mounted', 'vueObjectFuncName')
+endfunction
diff --git a/test/cases/keyword.vue b/test/cases/keyword.vue
new file mode 100644
index 0000000..992725b
--- /dev/null
+++ b/test/cases/keyword.vue
@@ -0,0 +1,45 @@
+
+
+
diff --git a/test/cases/oneline.vim b/test/cases/oneline.vim
new file mode 100644
index 0000000..7ac3f54
--- /dev/null
+++ b/test/cases/oneline.vim
@@ -0,0 +1,22 @@
+" One-line blocks like
+
+function! Check()
+ call ExpectSyntax('script', 'javascriptScriptBlock')
+ call ExpectSyntax('p {', 'cssStyleBlock')
+ call ExpectSyntax('color', 'cssTextProp')
+ call ExpectSyntax('p {', 'cssStyleBlock')
+ call ExpectSyntax('color', 'cssTextProp')
+ call ExpectSyntax('Hello', 'htmlTemplateBlock')
+ call CheckSync()
+endfunction
+
+" Syntax from a sync point, as after jumping to a line not displayed yet
+function! CheckSync()
+ silent edit!
+ call cursor(line('$'), 1)
+ call search('Hello', 'cW')
+ if index(SyntaxList(), 'htmlTemplateBlock') == -1
+ call Fail('after syncing, Hello should be htmlTemplateBlock, but got '
+ \.string(SyntaxList()))
+ endif
+endfunction
diff --git a/test/cases/oneline.vue b/test/cases/oneline.vue
new file mode 100644
index 0000000..d8db5f4
--- /dev/null
+++ b/test/cases/oneline.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+Hello
diff --git a/test/cases/random.vim b/test/cases/random.vim
new file mode 100644
index 0000000..3df54f4
--- /dev/null
+++ b/test/cases/random.vim
@@ -0,0 +1,10 @@
+let g:vim_vue_plugin_config = {
+ \'syntax': {
+ \ 'template': ['html'],
+ \ 'script': ['javascript'],
+ \ 'style': [],
+ \},
+ \'attribute': 1,
+ \'keyword': 1,
+ \'foldexpr': 1,
+ \}
diff --git a/test/cases/random.vue b/test/cases/random.vue
new file mode 100644
index 0000000..45b12b2
--- /dev/null
+++ b/test/cases/random.vue
@@ -0,0 +1,151 @@
+
+
+
+
+
+
diff --git a/test/cases/script-setup.vim b/test/cases/script-setup.vim
new file mode 100644
index 0000000..cb8c7d9
--- /dev/null
+++ b/test/cases/script-setup.vim
@@ -0,0 +1,18 @@
+let g:vim_vue_plugin_config = {
+ \'syntax': {
+ \ 'template': ['html'],
+ \ 'script': ['javascript', 'typescript'],
+ \},
+ \'keyword': 1,
+ \}
+
+function! Check()
+ call ExpectSyntax('withDefaults', 'vue3Keyword')
+ call ExpectSyntax('defineProps<', 'vue3Keyword')
+ call ExpectSyntax('defineEmits<', 'vue3Keyword')
+ call ExpectSyntax('defineModel<', 'vue3Keyword')
+ call ExpectSyntax('useTemplateRef', 'vue3Keyword')
+ call ExpectSyntax('ref', 'vue3Keyword')
+ call ExpectNoSyntax('value < 3', 'vue3Keyword')
+ call ExpectSyntax('defineExpose', 'vue3Keyword')
+endfunction
diff --git a/test/cases/script-setup.vue b/test/cases/script-setup.vue
new file mode 100644
index 0000000..d64cd51
--- /dev/null
+++ b/test/cases/script-setup.vue
@@ -0,0 +1,15 @@
+
+ {{ props.foo }}
+
+
+
diff --git a/test/cases/template.vim b/test/cases/template.vim
new file mode 100644
index 0000000..bcaceb8
--- /dev/null
+++ b/test/cases/template.vim
@@ -0,0 +1,18 @@
+" Nested and in
+let g:vim_vue_plugin_config = {
+ \'syntax': {
+ \ 'script': ['javascript'],
+ \ 'template': ['html'],
+ \ 'style': ['css'],
+ \ 'docs': 'markdown',
+ \},
+ \}
+
+function! Check()
+ while search('/template', 'W')
+ call ExpectTag(line('.'), 'template')
+ endwhile
+ normal! gg
+ call ExpectNoSyntax('/docs', 'markdownDocsBlock')
+ call ExpectSyntax('/docs', 'markdownDocsBlock')
+endfunction
diff --git a/test/cases/template.vue b/test/cases/template.vue
new file mode 100644
index 0000000..3eeb8e5
--- /dev/null
+++ b/test/cases/template.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Hello
+
diff --git a/test/cases/vue3.vim b/test/cases/vue3.vim
new file mode 100644
index 0000000..533d2d4
--- /dev/null
+++ b/test/cases/vue3.vim
@@ -0,0 +1,15 @@
+let g:vim_vue_plugin_config = {
+ \'syntax': {
+ \ 'template': ['html'],
+ \ 'script': ['javascript', 'typescript'],
+ \ 'style': ['css'],
+ \},
+ \'keyword': 1,
+ \}
+
+function! Check()
+ call ExpectSyntax('v-bind', 'cssFunctionName')
+ call ExpectSyntax('slotted', 'cssPseudoClassId')
+ call ExpectSyntax('global', 'cssPseudoClassId')
+ call ExpectSyntax('deep', 'cssPseudoClassId')
+endfunction
diff --git a/test/cases/vue3.vue b/test/cases/vue3.vue
new file mode 100644
index 0000000..c323eb2
--- /dev/null
+++ b/test/cases/vue3.vue
@@ -0,0 +1,8 @@
+
diff --git a/test/run.sh b/test/run.sh
new file mode 100755
index 0000000..7c13272
--- /dev/null
+++ b/test/run.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Run all test cases, or the ones given as arguments, with vim and nvim if
+# they are installed. Vim runs in a pseudo terminal by `script`, as syntax
+# in Ex mode (-es) isn't the same as in a terminal.
+# ./test/run.sh
+# ./test/run.sh basic template
+cd "$(dirname "$0")/.." || exit 1
+
+# Syntax plugins used by test/cases/example.vue
+mkdir -p test/deps
+for repo in digitaltoad/vim-pug kchmck/vim-coffee-script \
+ leafgarland/typescript-vim iloginow/vim-stylus; do
+ dir=test/deps/${repo#*/}
+ [ -d "$dir" ] || git clone -q --depth 1 "https://github.com/$repo" "$dir"
+done
+
+if [ $# -gt 0 ]; then
+ cases=$*
+else
+ cases=$(ls test/cases/*.vue | sed 's#.*/##; s#\.vue$##')
+fi
+
+out=$(mktemp)
+status=0
+expected=0
+for name in $cases; do
+ if command -v vim >/dev/null; then
+ expected=$((expected + 1))
+ VUE_TEST_CASE=$name VUE_TEST_OUT=$out timeout 60 script -qec \
+ 'stty rows 40 cols 120; vim -N -u NONE -i NONE -S test/run.vim' \
+ /dev/null >/dev/null || status=1
+ fi
+ if command -v nvim >/dev/null; then
+ expected=$((expected + 1))
+ VUE_TEST_CASE=$name VUE_TEST_OUT=$out timeout 60 \
+ nvim --headless -u NONE -i NONE -S test/run.vim || status=1
+ fi
+done
+
+cat "$out"
+passed=$(grep -c '^ok' "$out")
+failed=$(grep -c '^FAIL' "$out")
+missing=$((expected - passed - failed))
+echo "$passed passed, $failed failed, $missing without result"
+[ $failed -eq 0 ] && [ $missing -eq 0 ] || status=1
+rm -f "$out"
+exit $status
diff --git a/test/run.vim b/test/run.vim
new file mode 100644
index 0000000..01ab223
--- /dev/null
+++ b/test/run.vim
@@ -0,0 +1,117 @@
+" Run one test case, see test/run.sh
+" VUE_TEST_CASE=basic vim -N -u NONE -i NONE -S test/run.vim
+"
+" A case is test/cases/.vue, with optional test/cases/.vim to set
+" g:vim_vue_plugin_config and define Check() for more assertions. It fails if
+" - indenting the whole file changes it
+" - Check() calls Fail() or an Expect*() function fails
+" - there are error messages
+"
+" Results are appended to $VUE_TEST_OUT. Exit code is 1 if the case fails.
+
+set nocompatible
+let s:root = expand(':p:h:h')
+let s:name = $VUE_TEST_CASE
+let s:case = s:root.'/test/cases/'.s:name
+let s:errors = []
+
+" Plugin first, before Vim's placeholder vue syntax and indent files
+let &runtimepath = join([s:root, s:root.'/test/runtime']
+ \ + glob(s:root.'/test/deps/*', 0, 1)
+ \ + [&runtimepath], ',')
+set expandtab shiftwidth=2
+" Plugin scripts aren't loaded with -u NONE, e.g. vim-stylus sets g:css_units
+runtime! plugin/**/*.vim
+
+" Helpers for Check()
+function! Fail(msg)
+ call add(s:errors, a:msg)
+endfunction
+
+function! SyntaxList()
+ return map(synstack(line('.'), col('.')), { _, id -> synIDattr(id, 'name') })
+endfunction
+
+" Search pattern forward from cursor and check syntax at the match
+function! ExpectSyntax(pattern, syntax)
+ if !search('\V'.a:pattern, 'W')
+ return Fail('not found: '.a:pattern)
+ endif
+ if index(SyntaxList(), a:syntax) == -1
+ call Fail(printf('%s at line %d should be %s, but got %s',
+ \ a:pattern, line('.'), a:syntax, string(SyntaxList())))
+ endif
+endfunction
+
+function! ExpectNoSyntax(pattern, syntax)
+ if !search('\V'.a:pattern, 'W')
+ return Fail('not found: '.a:pattern)
+ endif
+ if index(SyntaxList(), a:syntax) != -1
+ call Fail(printf('%s at line %d should not be %s, but got %s',
+ \ a:pattern, line('.'), a:syntax, string(SyntaxList())))
+ endif
+endfunction
+
+function! ExpectFoldlevel(lnum, level)
+ if foldlevel(a:lnum) != a:level
+ call Fail(printf('foldlevel at line %d should be %d, but got %d',
+ \ a:lnum, a:level, foldlevel(a:lnum)))
+ endif
+endfunction
+
+function! ExpectTag(lnum, tag)
+ if GetVueTag(a:lnum) !=# a:tag
+ call Fail(printf('tag at line %d should be %s, but got %s',
+ \ a:lnum, string(a:tag), string(GetVueTag(a:lnum))))
+ endif
+endfunction
+
+if filereadable(s:case.'.vim')
+ execute 'source '.fnameescape(s:case.'.vim')
+endif
+filetype plugin indent on
+syntax on
+
+messages clear
+execute 'silent edit '.fnameescape(s:case.'.vue')
+redraw
+
+" Indent
+let s:lines = getline(1, '$')
+silent normal! gg=G
+let s:indented = getline(1, '$')
+if s:indented != s:lines
+ let s:lnum = 0
+ while s:lnum < len(s:lines) && get(s:indented, s:lnum) ==# s:lines[s:lnum]
+ let s:lnum += 1
+ endwhile
+ call Fail(printf('indent changed at line %d: expected %s, but got %s',
+ \ s:lnum + 1, string(get(s:lines, s:lnum, '')),
+ \ string(get(s:indented, s:lnum, ''))))
+ silent undo
+endif
+
+" Assertions
+normal! gg
+if exists('*Check')
+ call Check()
+endif
+
+" Errors
+for s:msg in split(execute('messages'), "\n")
+ if s:msg =~# '^E\d\+:\|^Error detected'
+ call Fail('message: '.s:msg)
+ endif
+endfor
+
+let s:editor = has('nvim') ? 'nvim' : 'vim'
+call writefile(empty(s:errors)
+ \ ? [printf('ok %s %s', s:editor, s:name)]
+ \ : [printf('FAIL %s %s', s:editor, s:name)]
+ \ + map(copy(s:errors), '" ".v:val'),
+ \ $VUE_TEST_OUT, 'a')
+if !empty(s:errors)
+ cquit
+endif
+qall!
diff --git a/test/runtime/indent/yaml.vim b/test/runtime/indent/yaml.vim
new file mode 100644
index 0000000..143bd5a
--- /dev/null
+++ b/test/runtime/indent/yaml.vim
@@ -0,0 +1,157 @@
+" Vim indent file
+" Language: YAML
+" Maintainer: Nikolai Pavlov
+" Last Update: Lukas Reineke
+" Last Change: 2020 Jun 07
+
+" Only load this indent file when no other was loaded.
+if exists('b:did_indent')
+ finish
+endif
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+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
+
+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%('.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%('.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
+