Custom syntax highlighting in vim for links - vim

I have a custom file format for graphs which looks like this:
node1.link1 : node2
node1.attribute1 : an_attribute_for_node1
node2.my_attribute1 : an_attribute_for_node2
(there is nothing special about the attributes names, an attribute is a link iff one can find its value at the left of a dot. So node2 is a link, because there is a line somewhere in the file that begins with node2.<something>).
I would like to highlight the attribute values if they are links (so I would like to highlight node2, but not attribute_for_node1).
Obviously, this kind of syntax highlighting cannot be based only on line wide regexp, because one needs to read the entire file to do the correct highlighting.
I already have a python parser for this kind of files (which gives a dict of dict string -> (string -> string)), but I don't know if python can interact with syntax highlighting in vim 7.
EDIT
As a clarification, the dictionary produced for this example is:
d = {
'node1': {'link1' : 'node2', 'attribute1' : 'an_attribute_for_node1'},
'node2': {'attribute2': 'an_attribute_for_node2'}
}
By definition, l is a link for node n if and only if:
d[n][l] in d
Names are meaningless, the format is only structure dependant, and there is no language keywords.
I would like to highlight node2 in the first line, because it is the name for a node.
I hope it is clearer now.
Someone has an idea ?

This should be very straightforward, but it's a little difficult to work out exactly what your dict looks like (what is 'string'? node1? attribute1? something else?). I have a plugin that I wrote called the ctags highlighter which does a fairly similar thing: it uses ctags to generate a list of keywords and then uses python to turn this into a simple vim script that highlights those keywords appropriately.
Basically, what you need to do is make your parser (or another python module that uses your parser) to generate a list of keywords (node1, node2 etc) and output them in this form (use as many per line as you like, but don't make the lines too long):
syn keyword GraphNode node1 node2
syn keyword GraphNode node3
Write this to a file and create an autocommand that does something like:
autocmd BufRead,BufNewFile *.myextension if filereadable('nodelist.vim') | source nodelist.vim | endif
Then do:
hi GraphNode guifg=blue
or whatever. If you want more details, post a little more information about your parser or have a look at the code in my plugin.
For more information, see
:help :autocmd
:help syn-keyword
:help BufEnter
:help BufNewFile
:help filereadable()
:help :source
:help :highlight
Edit
I'm still not completely sure I know what you want, but if I am understanding correctly, something like this should work:
Let's assume that your python parser is called mypyparser.py, it takes one argument (the current filename) and the dictionary it creates is called MyPyDict. You'll obviously have to modify the script to match the actual use of your parser. Add this script somewhere in your runtimepath (e.g. in .vimrc or in ~/.vim/ftplugin/myfiletype.vim) and then open your file and type :HighlightNodes.
" Create a command for ease of use
command! HighlightNodes call HighlightNodes()
function! HighlightNodes()
" Run the parser to create MyPyDict
exe 'pyfile mypyparser.py ' . expand('%:p')
" Next block is python code (indent gone to keep python happy)
py <<EOF
# Import the Vim interface
import vim
# Iterate through the keys in the dictionary and highlight them in Vim
for key in MyPyDict.keys():
vim.command('syn keyword GraphNode ' + key)
endfor
EOF
" Make sure that the GraphNode is highlighted in some colour or other
hi link GraphNode Keyword
endfunction

Related

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.

How to make a parameterized command map in vim editor

I m trying to make a custom command for block commenting, to avoid writing the whole search and replace sequence each time in vim for commenting lines.
What I m trying to do is make a key combination map to which I can pass line numbers as parameter and those should be passed to the .vimrc file and processed there. Is it possible?
For example, I have this in my .vimrc
map :pc :17,21s/^/#<CR>
Now whenver I will do :pc in vim, it will add a # infront of lines 17-21 (commenting them in python)
Now 17,18 is hard coded in command here but can I make this command parameterized so that I can pass line numbers specifically like :17,21pc and it will take them in map command?
If it is possible then I would love to make the '#' symbol parameterized too so that I can pass in language specific comment symbol, like // in JS.
Mappings can't have parameters, but it's typically a command's job (see :h :command).
command! -range -nargs=? Comment call CommentThis(<line1>, <line2>, <q-args>)
function! CommentThis(l1, l2, lead)
let l:lead = a:lead == '' ? '#' : a:lead
exe printf('%i,%is+^+%s', a:l1, a:l2, l:lead)
endf
You can use it like this: select some lines with V and arrows, then:
:'<,'>Comment //
Of course you can specify the line numbers by yourself : don't select anything, then type:
:17,21Comment //
:12,45Comment " '#' is the default
Note: the above code is far from perfect, it's just an example.
But there is really better if your goal is to comment some lines: use NERD Commenter; it automatically chooses the right comment leader depending of the filetype, it allows several kinds of comment styles, it can comment and uncomment...
Here is an example of its use: select some lines with V and arrows, then type <leader>cc, with <leader> as \ by default.

How can I get vim find to ignore whitespace?

I have XML entries that span two or more lines sometimes, and so I can look for something like this:
something on one line
But if I try the vim command /something on one line and the line is like this:
something on one
line
then it doesn't find it, because the second text block is actually seen as
something on one^J line
Which might have something to do with the fact that I'm using a DOS formatted file.
How can I get vim search to ignore whitespace and newlines?
In vim search, _s means a new line, a space or a tab. So you can try something such as:
/something on one\_s*line
to match the example string you used as example.
Replacing the spaces with \_s\+ manually is cumbersome. The Search for visually selected text topic on the Vim Tips Wiki has a mapping that does this for you for the current visual selection. You can use it like the built-in * mapping, to search (ignoring spaces) for the current selection. Very handy!
While I like the existing answers, I was looking for a way to do the substitution of spaces to \_s* "automagically" for every search that I type.
Luckily, such a solution is possible, as explained in this reddit post. I ended up using the following command:
cnoremap <expr><space> '/?' =~ getcmdtype() ? '\_s*' : ' '
This makes it so that whenever you type a space in a search command (either / or ?), all spaces that you type are automatically replaced by \_s*.
In fact, I only wanted this behavior for LaTeX files, so I added the following to my .vimrc:
autocmd FileType tex cnoremap <expr><space> '/?' =~ getcmdtype() ? '\_s*' : ' '

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.

Convert Notepad++ syntax highlighting file to vim (or does anyone have a q/kdb+ vim syntax highlight file?)

I have a syntax highlighting file for the q/kdb+ language and I'd like to convert it to a vim compatible file so my q code won't look any more ugly than usual.
Are there utilities available to automatically convert notepad++ xml syntax highlighting files to vi versions? I had a look around but I couldn't find anything.
Alternatively does anyone have a vim q syntax highlighting file?
a q/kdb+ vim syntax highlight files:
https://github.com/simongarland/vim
The answer to both questions is no (I don't know of any converters and I don't have a q syntax highlighting file), but the Notepad++ syntax highlighting XML format looks extremely simple. I don't have the 'Q' one to hand, but I had a look at one of the ones from the website and the translation looks pretty trivial. In that case, you could do most of the work with:
" Remove all the lines that aren't lists of keywords
" (there doesn't seem to be anything much more complicated
" than that in the definition file)
:g!/<Keywords name=/d
" Convert the lines (fairly poor XML parsing here!)
:%s/\s*<Keywords name="\([^"]\+\)">\([[:alpha:]_ ]\{-}\)<\/Keywords>/syn keyword \1 \2/
This generates lots of lines that look like:
syn keyword Words1 case then do while
You'll have to tweak the syntax class (Words1 in this case) to be something that will be highlighted in Vim (or syn-link it to something that will be highlighted in Vim).
You could probably then deal with the symbols with a regexp, but it might be easier to just do them by hand, so convert:
<Keywords name="Operators">- ! " # $ & * , . ; ? # \ ^ { | } ~ + < = ></Keywords>
into:
syn match Operators /\<[-!"#$&*,.;?#\\^{|}~+<=>]/
(this is \< to mark a word boundary, followed by a character class [..] with all the symbols in it).
You would then just need to add:
if exists("b:current_syntax")
finish
endif
at the start and:
let b:current_syntax = "q"
at the end.
Of course, this doesn't get you all the way, but hopefully it will give you a lot of what you need to get the syntax file that you want. There is plenty of help available in:
:help syntax
and by looking at the examples in the syntax directory of the runtime folder.
Good luck!

Resources