21

When I edit a PHP file and I define a string in a heredoc, syntax highlighting will be enabled inside the heredoc if it is JavaScript syntax or HTML syntax or SQL syntax. However it will not work for CSS syntax.

Example (if we create a new PHP file called hello.php with the following code):

<?php
$foo = <<<"JAVASCRIPT"
var hello = "hello";
JAVASCRIPT;

$bar = <<<"CSS"
/* This code below should be syntax-highlighted. */
.hello {
  font-weight: bold;
}
CSS;

The JAVASCRIPT block is highlighted correctly, but the CSS block is not. Also, if I run SynStack on the var keyword on the JavaScript code block, I get ['phpRegion', 'phpHereDoc', 'javaScriptIdentifier'], but if I do the same to any place in the CSS block, I only get ['phpRegion', 'phpHereDoc'], so I need to add some CSS syntax highlighting rules. Where are these syntax rules getting defined, and how do I add to them?

3
  • 1
    Note: // This should be syntax-highlighted is not a valid CSS comment, and so should be syntax highlighted as something other than a comment. CSS only supports /* */ multi-line comments. // single-line comments are only supported if you use preprocessor languages such as Sass or Stylus. Mar 10, 2017 at 20:01
  • You are correct. I have updated the code to reflect that change.
    – MrSnrub
    Apr 10, 2017 at 13:41
  • I too am looking to get a solution for CSS heredoc syntax highlighting. I tried many scenarios but could not get it to work. Anyone have a solution?
    – Ken
    Apr 26, 2017 at 14:06

1 Answer 1

6

TL;DR:

It's defined in Vim's PHP and HTML syntax files. To see how to add rules for CSS, jump to the section And how do I add to them? below, or read on for an explanation of how it works.

Where are these syntax rules getting defined?

The JavaScript heredoc is highlighted using Vim's syntax contains1 feature, which allows syntax groups to contain other syntax groups.

To find where this is defined, first open up the syntax highlighting file for PHP:

:e $VIMRUNTIME/syntax/php.vim

Now, presumably the syntax file is finding the JavaScript heredoc based on a match of the string "javascript", so lets try searching for that:

/javascript

The third match is this comment:

" including HTML,JavaScript,SQL even if not enabled via options

Looks promising! Let's take a look at the relevant syntax line:

syn region  phpHereDoc  matchgroup=Delimiter
\ start="\(<<<\)\@<=\(\"\=\)\z(\(\I\i*\)\=\(javascript\)\c\(\i*\)\)\2$"
\ end="^\z1\(;\=$\)\@="
\ contained
\ contains=@htmlJavascript,phpIdentifierSimply,phpIdentifier,phpIdentifierComplex,phpBackslashSequences,phpMethodsVar,@Spell
\ keepend extend

(line continuations added for easier reading)

Okay, so this syntax region finds the JavaScript heredoc with a convoluted regular expression, and allows JavaScript highlighting within the region by including the @htmlJavascript syntax cluster2 within the contains argument.

But there is no corresponding definition for CSS heredocs! Lets add one. So the first thing to change is the start regular expression. Simply change the javascript into css:

start="\(<<<\)\@<=\(\"\=\)\z(\(\I\i*\)\=\(css\)\c\(\i*\)\)\2$"

This is easy!

But we don't want JavaScript highlighting in our CSS heredoc. So we also need to change the @htmlJavascript to the CSS equivalent. But what is the CSS equivalent? (You might be able to guess, but let's go through the motions to be sure.)

Lets search for htmljavascript3 to see where that is defined:

/htmljavascript

Hmmm. No other results. It must be defined elsewhere! Let's have a quick look at the top of the file to see if we can find any includes:

runtime! syntax/html.vim

This looks like it could be it4.

:e $VIMRUNTIME/syntax/html.vim

Run the search again in this file, and we find this line5:

syn cluster htmlJavaScript      add=@htmlPreproc

So htmlJavaScript is a cluster, defined in html.vim. Is there a similar cluster for CSS we can use?

/htmlcss

Yup!

syn include @htmlCss syntax/css.vim

So we just need to replace @htmlJavascript with @htmlCss in the contains argument:

contains=@htmlCss,phpIdentifierSimply,phpIdentifier,[...]

And how do I add to them?

Save the entire syntax command below in the file ~/after/syntax/php.vim so that it is run after the rest of the PHP syntax processing has been carried out, and you're done!

syn region  phpHereDoc  matchgroup=Delimiter
\ start="\(<<<\)\@<=\(\"\=\)\z(\(\I\i*\)\=\(css\)\c\(\i*\)\)\2$"
\ end="^\z1\(;\=$\)\@="
\ contained
\ contains=@htmlCss,phpIdentifierSimply,phpIdentifier,phpIdentifierComplex,phpBackslashSequences,phpMethodsVar,@Spell
\ keepend extend

1: See :help :syn-contains for details.
2: See :help :syn-cluster.
3: I've got 'ignorecase' switched on. Without it, you'll need to search for htmlJavascript or \chtmljavascript
4: In fact, based on the naming scheme used in Vim syntax files, we probably could have figured this out based on the htmlJavascript name alone.
5: With "JavaScript" capitalised differently, this time. Lucky we've got 'ignorecase' switched on, eh?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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