views:

475

answers:

1

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 ?

+2  A: 

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
Al
I am sorry for not having been clear.the syntax of the format, in pseudo(-pseudo) BNF, isline := node '.' attribute ':' link | propertynode := [a-Z]+link := nodeattribute := [a-Z]+property := [a-Z]+The only thing that discriminates a node from a property is that it can be the name of a nodeMy python dict like this is {'node1' : {'link1':'node1', 'attribute1': 'an_attribute_for_node_1'}, 'node2': {'my_attribute1' : 'an_attribute_for_node2'}}l is a link for a node n iff d[n][l] in dSo node1 has no signification at all. In fact, the syntax is NOT keyword based. Hope this is clearer.
LeMiz
I wasn't suggesting that you use keywords based on a language file, but based on parsing of the current file. For example, in my C code, if I have a function called GetCurrentValue(), I would expect GetCurrentValue to be highlighted throughout that code, despite it not being a C keyword. If I open a different project, I would not expect GetCurrentValue to be highlighted. I guess what I'm asking is: "in this file specifically, should 'node2' be highlighted at the end of line 1 and the start of line 3, or just on the first line?".
Al
I've added a more explicit example of what I mean, but if I'm still wrong, perhaps you could give a more detailed example with a sample file and the specific parts and locations you want highlighted for that file?
Al
That will do the trick, thanks. I only want to highlight just the link, ie the node2 that is at the right of the :, but I think that with your second example I will be able to do it. Thanks !
LeMiz