I edited my original question and title to broaden its scope to any syntax - with SQL used as just an example. You can adapt the examples and the answer to other languages.
By adding suitable highlighting rules, one can make vim highlight multiple languages within the same file. This comes particularly handy for shell scripts, in which each new language block is embedded inside a heredoc. For instance, the above picture shows SQL within four shell heredocs. SQL is displayed mono-color inside EOF delimited heredocs, in which default highlighting rules apply, By contrast, SQL is displayed multi-color inside SQLDOC delimited heredocs, in which new highlighting rules were added specific to SQL syntax elements. We can see an issue, however: the last SQLDOC heredoc is incorrectly highlighted mono-color. How can I fix this and make that block display multi-color SQL highlights?
To reproduce this issue:
Close vim and copy the highlighting file to ~/.vim/after/syntax/sh/heredoc-embed.vim (file contents below).
Start
vim ./vim-heredoc-syntax-issue.sh(file contents below).
We are often instructed to start vim with -u NONE to make sure that plugins don't get in the way of reproducing an issue. In this case I can't tell you so. If I use -u NONE syntax highlighting will not load at all. And I'm unable to find a sequence of vim commands that enables syntax highlighting from -u NONE to my issue. I tried! but failed. So please start your vim as I explained above and hopefully you'll reproduce this issue. To make sure that it occurs in a reasonably pristine vim configuration, I took the above screenshot in a virtual machine, in which I booted a fresh copy of my Linux distribution, installed vim from the package manager, copied the "heredoc-embed.vim" file, and ran vim.
heredoc-embed.vim
" This VIML code sets SQL syntax highlighting for heredoc content blocks
" marked by word <LANGUAGE>DOWN, i.e. SQLDOC.
" source https://subvisual.co/blog/posts/87-smarter-heredoc-syntax-in-vim/ {{{1
let s:bcs = b:current_syntax
" this unlet instruction is needed before we load each new syntax
unlet b:current_syntax
syntax include @SQL syntax/sql.vim
let b:current_syntax = s:bcs
syntax region hereDocDashSQL matchgroup=Statement start=+<<\s*[-'\\]\?\z(SQLDOC\)+ end=+^\s*\z1+ contains=@SQL
if exists("b:current_syntax")
unlet b:current_syntax
endif
vim-heredoc-syntax-issue.sh
# colorscheme evening
: << EOF
SELECT * FROM table;
EOF
: << SQLDOC
SELECT * FROM table;
SQLDOC
foo() {
: << EOF
SELECT * FROM table;
EOF
: << SQLDOC
SELECT * FROM table;
SQLDOC
}
Similar questions I found on SE:
I'd rather fix mine because the regular expressions are simpler.
Maybe Dr Chip can tell me?
My formula but for Perl heredoc.


shtosql. Look at lineSELECT * FROM table;. Here I see that highlighting changes as the file type changes. It shouldn't. The line should be highlighted as SQL regardless of the file type. With plugin hilinks it's easy to see thatSELECTis recognized asshStringinstead ofsqlStatement... – stepse Apr 03 '19 at 20:36SELECT=sqlStatement,FROM&TABLE=sqlKeyword. But*&;=shHereDoc, which is expected as in a normal SQL file they have no highlight at all. If I switch from filetypeshtosql, only the color for*and;change. Did you remove your customsyntax/sh.vimbefore testing? (BTW: Vim 8.1.1099, but I don't think that makes a difference.) – Ralf Apr 04 '19 at 04:38SELECT=sqlStatementbut*and;=shHereDoc->ShString. Your explanation of why*and;are highlighted that way makes sense but I didn't expect to see any shell syntax creep in and colorize parts of SQL. It doesn't happen with the other method. I also noticed that with this methodSELECT 'a'||'b'matches'a' || 'b'asShStrings, while with the other method the matches aresqlString,sqlFold,sqlString(plus quote tokens). I think that both methods have their merits, and they just aren't exactly equivalent. – stepse Apr 04 '19 at 19:51startendpattern pair. I prefer mine because it can match seldom-used but valid heredoc syntax such as<<- \EOF. I'm usingstart=+<<-\=\s*['"\\]\=\z(SQLDOC\)+ end="^\s*\z1"– stepse Apr 20 '19 at 19:34