In VIM, how can I mix syntax/ident rules of both jinja and javascript in the same file? - vim

I'm using jinja template language to generate html and javascript for a website. How can I make vim understand that everything between '{{'/'}}' and '{%'/'%}' is Jinja code and the rest it javascript code? Is there a simple way of doing that?

There is a relatively easy way to have different regions in your code that use different syntax files, by using the "syntax include" command and a "syntax region" command to define each region. Below is some code I have to syntax highlight different regions of Perl, R, and Python in a single document. The 'unlet' statments are necessary because the syntax files often depend on b:current_syntax not existing when they are first run. Yours would be similar, but define the 'start' and 'end' for the jinja and javascript regions using the delimiters you listed in your question. Check help for "syn-region" and "syn-include" to get more info:
let b:current_syntax = ''
unlet b:current_syntax
syntax include #Perlcode $VIMRUNTIME\syntax\perl.vim
syntax region rgnPerl start='^src-Perl' end='^end-Perl' contains=#Perlcode
let b:current_syntax = ''
unlet b:current_syntax
syntax include #rinvim $VIMRUNTIME\syntax\r.vim
syntax region rgnR matchgroup=Snip start="^src-R" end="^end-R" keepend contains=#rinvim
let b:current_syntax = ''
unlet b:current_syntax
syntax include #python $VIMRUNTIME\syntax\python.vim
syntax region rgnPython matchgroup=Snip start="^src-Python" end="^end-Python" keepend contains=#python
let b:current_syntax='combined'
I'm not sure about how to get different auto-indenting in the regions, that's a question I was going to look into myself. I think one solution would be to consolidate all of the languages indent files into one and have an if structure that processes according to which region it finds itself in. Maybe there's a simpler way than that, though.

For the syntax, my SyntaxRange plugin makes the setup as simple as a single function call.
For different filetype settings like indentation options, you have to install an :autocmd CursorMoved,CursorMovedI that checks into which region the current line falls (maybe using the syntax for hints, e.g. with synID()), and then swaps the option values depending on the result.
Edit: For your particular use case, that would be something like:
:call SyntaxRange#Include('{{', '}}', 'jinja')
:call SyntaxRange#Include('{%', '%}', 'jinja')
which you could put into ~/.vim/after/syntax/javascript.vim to apply it automatically to all JavaScript files.

Related

How do I stop vim reading in the default syntax?

I have defined my own javascript syntax file, which is in ~/.vim/syntax/after/
The problem is that the default syntax file that exists in /usr/share/vim/vim82/syntax is loaded along side my custom syntax file (it seems to be loaded before my custom syntax).
The result is that it conflicts with my custom syntax.
How do I ONLY load my custom syntax file? Not the default one.
Of course I could just delete the default one (which works), but that seems like a not very robust fix to the problem considering it will just be put back there when vim is updated.
I have "syntax clear" at the top of my custom file but it doesn't help.
I also note that the default syntax file has the following at the top:
if !exists("main_syntax")
" quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
let main_syntax = 'javascript'
elseif exists("b:current_syntax") && b:current_syntax == "javascript"
finish
endif
But that doesn't do anything either.
I have also tried putting the syntax folder in .vim/syntax, as suggested on the official vim page, but that doesn't seem to do anything at all (as in, it's not read at all).
Thankyou.
In principle, the order in which syntax scripts are sourced is the following:
~/.vim/syntax/foo.vim
$VIMRUNTIME/syntax/foo.vim
~/.vim/after/syntax/foo.vim
~/.vim/after/syntax/ comes last. It is not a good place if you are writing a complete replacement of a built-in syntax script because you have at least one syntax script sourced before yours. On the other hand, it is a good place if what you want to do is either add your own stuff or selectively override stuff that has been set earlier.
$VIMRUNTIME/syntax/ is not a good place either, because it is a systemwide location. Your customisation is supposed to happen in your $HOME, right?.
~/.vim/syntax/ comes first so it is the ideal place for custom syntax scripts, if you add the following line:
let b:current_syntax = "javascript"
This is because $VIMRUNTIME/syntax/javascript.vim begins with the following boilerplate:
if !exists("main_syntax")
" quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
let main_syntax = 'javascript'
elseif exists("b:current_syntax") && b:current_syntax == "javascript"
finish
endif
which, essentially, throws the towel if b:current_syntax is set, and ends with:
let b:current_syntax = "javascript"
to "mark its territory", if you will.
You don't have to check for anything because you come first, but you still have to tell other syntax scripts to mind their own business.
Note that bad mannered syntax scripts may not check for that buffer-local variable so it is entirely possible to still have conflicts even if you are doing the right thing. But that's the nature of Vim.

Remove #Spell from a syntax cluster

I'm using the vim-polyglot plugin. In the JavaScript filetype plugin file, it configures Vim to run spell checking on strings. After glancing through the plugin's implementation, I can see that does this for the following syntax clusters:
jsString
jsTemplateString
jsObjectKeyString
jsObjectStringKey
Here's an example of how the cluster is defined:
syntax region jsString start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1+ end=+$+ contains=jsSpecial,#Spell extend
I've tried adding the lines below to ~/.config/nvim/init.vim as well as ~/.config.nvim/ftplugins/javascript.vim, but neither seems to remove the spelling:
syntax cluster jsString remove=#Spell
syntax cluster jsTemplateString remove=#Spell
syntax cluster jsObjectKeyString remove=#Spell
syntax cluster jsObjectStringKey remove=#Spell
How can I remove spelling from select syntax highlighting groups provided by vim-polyglot?
These are not really syntax clusters, but simply syntax items.
While #Spell and #NoSpell are syntax clusters, what matters with those is where they are contained and not really items they contain, so we can't really use syntax cluster to modify those and enable or spelling for existing syntax items...
So your best bet here is really to redefine the syntax items, removing the #Spell part of them.
You can redefine only those 4 items, but there aren't really good ways to just modify part of the command (simply removing the #Spell part), you end up having to set them from scratch again, which means you have to copy their definition from the original file and then make the modifications.
To add to an existing syntax file, see :help mysyntaxfile-add.
In short, you should create a ~/.vim/after/syntax/javascript.vim with contents:
syntax clear jsString
syntax clear jsTemplateString
syntax clear jsObjectKeyString
syntax clear jsObjectStringKey
syntax region jsString start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1+ end=+$+ contains=jsSpecial extend
syntax region jsTemplateString start=+`+ skip=+\\`+ end=+`+ contains=jsTemplateExpression,jsSpecial extend
syntax region jsObjectKeyString contained start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1\|$+ contains=jsSpecial skipwhite skipempty nextgroup=jsObjectValue
syntax region jsObjectStringKey contained start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1\|$+ contains=jsSpecial extend skipwhite skipempty nextgroup=jsFuncArgs,jsObjectValue
These commands will first clear the syntax items and then define them again, but this time without including the contains=#Spell part, so they'll not enable spell checking for those rules.

vim automatic hard wrap for fortran with line-continuation

I'm a Fortran programmer who uses both free-form and fixed form. Since I have to mix them, usually I write code in a common form between free and fixed format, so in this way I can tell to vim that all my files are in the free format.
Vim is great in doing things like autoindentation, but I would like to type and let vim automatically wrap my code, and placing the Fortran continuation character & at column 73 (or greater), and at column 6 in the new line. Is it possible, or does it exist a plugin for this?
Currently I'm using textwidth=72 in fortran files to hard wrap the lines.
Thanks in advance.
One way to make vim insert text when going to a new line is to use formatexpr. Set it so to capture the line and replace it with itself with & and new line appended, when at/beyond a given column. In this case you are handling line breaks and textwidth does not apply. I didn't yet get to test some simple code for it, but here is a related example.
Another way would be to write general code so that when in a given column it inserts & and <CR>.
However, making any such approach respect Fortran-specific exclusions (comments, for one thing) will make it more complicated. The best solution would be to find suitable existing option(s) for Fortran, but I haven't so far.
This is a comment on indentation in general. It should allow you to directly set up a desired rule for a new line. Here is one standard set of files that set up a lot of indentation rules and features.
The usual entry point is this vim script, which requires another standard set of files. The link given on that page for the other files is broken though, so here is where to find them: unpack this zip file (found on this page), right into your ~/.vim/ directory. It will create subdirectories indent/, syntax/, and ftpplugin/, or put files into them if they exist, so be careful if you have stuff there already.
Then you can put the first script linked above into .vim/after/indent/. In this file, there are specific calculations of where to put the cursor when a new line is entered. Find the right place(s) and change to your desired indent, or preferably set up a snippet from it in another file (so not to change this file). In this case you also need to set things up so that it overrides settings from the first file.
A useful resource is indentexpr (or :help indentexpr).
Here is also a tutorial on that.
These are comments on syntax in general, posted initially. They contain items of help related to what you want and should be generally useful, but probably have not much to say about adding &.
There are plugins for fortran. Here is the syntax file, with many things to tweak.
This may already be on your system. (It was on mine.) Thus I would go through and pick and choose things to add to your .vimrc. Here are a few options that are directly related
syn match fortranContinueMark display "&"
syn sync linecont "&" minlines=20
Here are paragraphs that seem to me relevant in their entirety
if (b:fortran_fixed_source == 1)
if !exists("fortran_have_tabs")
"Flag items beyond column 72
syn match fortranSerialNumber excludenl "^.\{73,}$"lc=72
"Flag left margin errors
syn match fortranLabelError "^.\{-,4}[^0-9 ]" contains=fortranTab
syn match fortranLabelError "^.\{4}\d\S"
endif
syn match fortranComment excludenl "^[!c*].*$" contains=#fortranCommentGroup
syn match fortranLeftMargin transparent "^ \{5}"
syn match fortranContinueMark display "^.\{5}\S"lc=5
else
syn match fortranContinueMark display "&"
endif
if b:fortran_dialect != "f77"
syn match fortranComment excludenl "!.*$" contains=#fortranCommentGroup,#spell
endif
Then a block of syn match statements follow for common cpp-like settings, and then
"Synchronising limits assume that comment and continuation lines are not mixed
if exists("fortran_fold") || exists("fortran_more_precise")
syn sync fromstart
elseif (b:fortran_fixed_source == 0)
syn sync linecont "&" minlines=20
else
syn sync minlines=20
endif
By your question it appears that you know how to set up .vimrc but here are a few comments.
Syntax support need be enabled with appropriate enable and autogroup statements, for example
syntax enable
" au BufRead,BufNewFile *.f90 FileType=fortran
au FileType fortran setlocal ...
Here are some common formatting options that I have for fortran
autocmd FileType fortran setlocal formatoptions=croql comments=:/!/
There can also be a t among options, for textwidth
Here are some specific settings I have, which I see in this syntax file with far more sophistication
let fortran_free_source=1
" Said to need fortran.vim and/or fortran support packages (they work)
let fortran_do_enddo=1
let fortran_more_precise=1
Standard vim help is of course extensive, but try :help fortran -- it has a number of useful settings right up front and is not overwhelming at all. Also see ft-fortran-syntax from help.
See this post with some troubleshooting if things aren't working right. Here is another useful post, even as it appears unrelated by its title.

highlight sub-match in vim

I'm trying to figure out how to highlight a specific portion of a match in vim.
Given the following example rule (taken from the coffeescript syntax file source):
syn match coffeeExtendedOp /\%(\S\s*\)\#<=[+\-*/%&|\^=!<>?.]\+\|[-=]>\|--\|++\|:/ display
This regular expression matches various coffeescript operators. The operators are highlighted (in my vimrc) like this:
hi Operator guifg=#ff0000
For example, since coffeeExtendedOp is linked to coffeeOperator which is linked to Operator, in the above source file. This all works, but I'm wondering how to specifically highlight the ++ operator matched in the above syn match with a different color, say blue, within my vimrc (that is, without altering the original source file above). I'm simply wondering if this is possible.
EDIT: I think the rules are placed under a cluster, so perhaps that's why it's not affecting anything. Is there a way to access the rule within the cluster?
EDIT: Question was clarified.
Solution:
syn match plusplus /++/ contained containedin=coffeeExtendedOp display
hi plusplus guifg=#0000ff
The problem now is that this only works when I run them as commands in vim, but not when I put it in my vimrc file. Any ideas? Could it be that the stuff is hidden behind the cluster? But then why is it visible in vim through a command? I tried including the syntax file but it didn't seem to have any effect.
Looking at the coffee.vim you linked to it seems like the dot belongs to the coffeeDotAccess syntax item. So you can highlight it just by doing this:
:hi coffeeDotAccess ctermfg=blue
I'm going to guess a bit at what you need. (I don't speak Coffeescript and your sample regex is way too complicated for me to start reading at the moment).
Transparent syntax items
You could have a look at transparent syntax rules: (http://vimdoc.sourceforge.net/htmldoc/usr_44.html)
In a C language file you would like to highlight the () text after a "while"
differently from the () text after a "for". In both of these there can be
nested () items, which should be highlighted in the same way. You must make
sure the () highlighting stops at the matching ). This is one way to do this:
:syntax region cWhile matchgroup=cWhile start=/while\s*(/ end=/)/
\ contains=cCondNest
:syntax region cFor matchgroup=cFor start=/for\s*(/ end=/)/
\ contains=cCondNest
:syntax region cCondNest start=/(/ end=/)/ contained transparent
Partial matches in regex
If you really just meant highlighting submatches, have a look at the the
\zs start match
\ze end match
In short,
:match Error /foo\zsbar\zered/
would highlight only 'bar' in 'foobarred'

extend/modify vim highlighting for all filetypes at once?

How do I extend/modify vim highlighting for all filetypes at once?
I have certain relatively simple patterns which I'd like highlight differently, that can occur in any filetype. So rather than adding something like the below to every conceivable filetype I might use (~/.vim/syntax/python.vim, .../css.vim, .../html.vim, ...) is there some way I can define it once for all filetypes?
syn match SpecialComment "#[#\-+].*" containedin=Comment
syn match Comment "\* .*$"hs=s+1 containedin=SpecialComment
update:
As suggested I saved my changes to ~/.vim/after/filetype.vim, with the result that it works in Cream but not stock Gvim or Vim. The actual code I'm using here, a sample python file to test against here, and the desired result:
You could try putting those two lines in ~/.vim/after/filetype.vim. That should get sourced after any of the top level syntax files. It's possibly not the 'correct' place to put it, but it should work.
filetype.vim seems to be sourced BEFORE the syntax files, so it gets overwritten by the default syntax file. Therefore, I'd recommend you create a new file called something like:
~/.vim/after/common_syntax.vim
with the highlight lines that you're interested in. Then, add this to ~/.vim/after/filetype.vim:
if !exists("after_autocmds_loaded")
let after_autocmds_loaded = 1
au BufNewFile,BufRead * source ~/.vim/after/common_syntax.vim
endif
This will cause the file to be sourced once the file has been read.
P.S. Responding to the comment in your sample code: "why can't we use plain ol 'comment' group instead of 'pythoncomment' etc. ?", it's because the syntax highlight group is pythonComment, which is merely coloured in the same way as Comment. If your syntax is unique enough for it not to be a problem, you could just do containedin=ALL. If it is close, but not quite unique, you could do containedin=ALLBUT,conflictgroup where conflictgroup is the highlight group you want to steer clear of.

Resources