Wikia

Vim Tips Wiki

Different syntax highlighting within regions of a file

Talk0
1,610pages on
this wiki
Tip 857 Printable Monobook Previous Next

created 2005 · complexity advanced · author Ivan Tishchenko · version 6.0


In many cases, you may want to apply different syntax highlighting from the rest of the file on specific sections of the file. Examples where this would be useful would be including C code snippets in a text file, or including Vim script inside <pre> sections on a web page or wiki entry. Vim allows you to do this!

SketchEdit

Try the following, in a new text file:

:syntax on
:syntax include @CPP syntax/cpp.vim
:syntax region cppSnip matchgroup=Snip start="@begin=cpp@" end="@end=cpp@" contains=@CPP
:hi link Snip SpecialComment

Now type in the following text:

This is simple text, and following is C++:
@begin=cpp@
  int q;
  struct w { double e };
@end=cpp@

Now you have text between @begin=cpp@ and @end=cpp@ highlighted as C++, though filetype is not 'cpp'.

Extended versionEdit

Here is a more useful version, which should work on any file, even those with a pre-existing syntax (i.e. not just text files):

function! TextEnableCodeSnip(filetype,start,end,textSnipHl) abort
  let ft=toupper(a:filetype)
  let group='textGroup'.ft
  if exists('b:current_syntax')
    let s:current_syntax=b:current_syntax
    " Remove current syntax definition, as some syntax files (e.g. cpp.vim)
    " do nothing if b:current_syntax is defined.
    unlet b:current_syntax
  endif
  execute 'syntax include @'.group.' syntax/'.a:filetype.'.vim'
  try
    execute 'syntax include @'.group.' after/syntax/'.a:filetype.'.vim'
  catch
  endtry
  if exists('s:current_syntax')
    let b:current_syntax=s:current_syntax
  else
    unlet b:current_syntax
  endif
  execute 'syntax region textSnip'.ft.'
  \ matchgroup='.a:textSnipHl.'
  \ start="'.a:start.'" end="'.a:end.'"
  \ contains=@'.group
endfunction

Now we can write something like:

call TextEnableCodeSnip(  'c',   '@begin=c@',   '@end=c@', 'SpecialComment')
call TextEnableCodeSnip('cpp', '@begin=cpp@', '@end=cpp@', 'SpecialComment')
call TextEnableCodeSnip('sql', '@begin=sql@', '@end=sql@', 'SpecialComment')

to enable highlighting of code pieces for c, cpp and sql. The begin and end markers are arbitrary; you can use whatever you want. For example, it might be useful is to use fold markers in the begin and end patterns, like this:

call TextEnableCodeSnip('html' ,'#{{{html' ,'#html}}}', 'SpecialComment')

This will allow you to fold snippet sections if you :set foldmethod=marker.

Setting up these function calls in your after/syntax directory will allow you to automatically allow such snippet sections in every file of a given type.

NotesEdit

  • If highlighting gets out of sync, try executing :syn sync fromstart to fix it.
  • If you want this highlighting within other syntax items (like strings), you may need to tweak the syntax rules here or in the syntax file using contains and/or containedin. :help :syn-contains :help :syn-containedin

ReferencesEdit

Related pluginsEdit

  • SyntaxRange uses the mechanism from this page to define :SyntaxIgnore and :SyntaxInclude {filetype} commands, which allow for quick, interactive application, as well as functions for finer control and use in custom mappings or syntax tweaks.

CommentsEdit

Hi, nice tip, I was trying this, and once I do the C formatting between my "BEGIN" and "END" sections, I want the BEGIN and END keywords to be highlighted and running

syn keyword Macro BEGIN END

will remove the previous C highlight! is there a way to change this?

Why do you feel the need to add a separate keyword syntax group? The "matchgroup" code already does this for you! Just pass "Macro" into the function as the final argument and it should work as you desire. Unless I misunderstand your desire. --Fritzophrenic 15:05, April 15, 2010 (UTC)

Is this also possible for indentation? Lets say C inside of an XML file?

It is not as direct as it is for syntax rules, but it can be done. Basically, it involves overriding the filetype indent rules with your own function that returns the usual filetype's indentexpr except within the markers you choose. See the comments of the notes on restoring indentation of tips in Ipkiss's user subpage for an example, using Vim script indent rules within a wikipedia file type. We don't currently have a tip proper on this subject; perhaps we should. --Fritzophrenic 14:28, April 13, 2010 (UTC)
Thanks. I'll give it a try. If I can manage to do it, I will try to post a tip on it. I have however not the slightest bit of experience with this. :-)

containedin example requestedEdit

An example on how to use containedin would be most useful. I am attempting to use this tip in a reStructuredText file (vim syntax file: rst.vim). I have identified the parent syntax item is rstLiteralBlock, what do I modify in the tip to make it work when containedin this block?

Doesn't work on a file that already has highlighting?Edit

All of the above code, including the TextEnableCodeSnip function, works perfectly on a brand new, plain text document. That is, I can embed highlighted C++ and friends within surrounding plain text. However, if I edit a TeX file, none of this code works. It seems to be unable to override the normal TeX highlighting. I want to embed highlighted C++ within highlighted TeX, but all I get is TeX -- @begin=cpp@ does not seem to trigger any C++ highlighting.

Note that a user on StackOverflow has the exact same problem, but with trying to embed html in yaml. So I don't think it's just a problem with TeX/C++: http://stackoverflow.com/questions/4829666/vim-syntax-highlighting-of-html-nested-in-yaml

I know little about this topic, but I do know that the method explained here works for me. Fritzophrenic will probably notice this discussion in a couple of days and might comment further. The place to ask would be the vim_use mailing list, which is confusingly called vim@vim.org here. JohnBeckett 06:54, March 3, 2011 (UTC)
"Out of the box", this tip will often not work on a file which already has highlighting. You will need to tweak the "contains" rules in the syntax file or "containedin" rules in the setup given in this tip, to enable placing the begin/end markers inside the appropriate syntax group of whichever language you are editing. I do note that the yaml post on stackoverflow which you mention has a possible solution posted, of simply placing the begin group on a line by itself. --Fritzophrenic 15:45, March 3, 2011 (UTC)

Bug?Edit

As far as I can tell, this does not work in Vim 7. I.e., the initial minimal example with @begin=cpp@ does not work. Does anybody know how to do this in Vim 7?

We don't use talk pages here (not enough meta discussion to warrant it). Sorry that the tip is a bit congested, but you have commented there and that's all we can offer. JohnBeckett 06:56, March 3, 2011 (UTC)
It "works" for me but has an issue that we need to sort out. It would certainly help if you told us what the problem is, not that it "does not work".
I DO get syntax highligting in a plaintext file using the exact example code given, with the following text:
@begin=c@

if (true)
{
  funccall();
}
else
{
  otherfunc();
  printf("hello world!");
}

@end=c@

hello world!
if hahaha
however, the c highlight does not end where it ought to, it continues on to the end of the buffer. Hopefully I will find some time to look into this soon. --Fritzophrenic 15:45, March 3, 2011 (UTC)

Around Wikia's network

Random Wiki