I am trying to improve Vim's syntax highlighting for YAML files. YAML supports long string literals that begin with either a ">" or "|", like this:

keyA: >
  A string literal
  that spans

  multiple lines
  keyC: |
    Another string literal
    That spans multiple lines
keyD: somevalue

The scope of the string is indentation-dependent -- everything is included in it until a line with a smaller indent begins.

I have defined a syntax region like this:

syn region yamlLongStringLiteral start="\v\>|\|" end=/^\ze\S/ contains=NONE

(Note: I've excluded contained from the definition above because it 's irrelevant to this question). This works for string literals stored in top-level keys (e.g. keyA above) but fails for literals stored in nested keys (e.g. keyC above). What I need to do is detect the indentation of the first line of the long literal and terminate the region on the first line with a lesser indent level. This would seem to require accessing captured groups from the start pattern in the end pattern. Is this possible, or is there some other way to accomplish my goal?

  • 1
    you can use the special item \z( to mark groups that are available at end section of the pattern. Check $VIMRUNTIME/syntax for the pattern \\z( Read also the help at :h /\z/, it includes an example – Christian Brabandt Mar 1 '18 at 7:02

Thanks to Christian's comment above, I came up with the following:

syn region yamlLongStringLiteral
      \ start="\(>\||\) *\n^\z( \+\)"
      \ end="^\(\z1\|$\)\@!"
      \ contains=NONE

The \z in the start pattern stores a group holding the leading indent, which is then referenced in the end pattern with \z1. \@! does negative lookahead, so ^\(\z1|$\)\@! means: "any non-empty line that does not start with the saved indent group".

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.