Showing posts with label vim. Show all posts
Showing posts with label vim. Show all posts

Saturday, March 24, 2012

Syntax highlighting stax scripts in vim

What is Staf/Stax?

STAF is a Software Testing Automation Framework. It provides all basic infrastructure for creating robust distributed test environments. It's structured as a collection of services which can be called from the command line or from a ui, or from your favourite programming language. These services implement things like: "start a process on pc xxx and get the return code", "copy files from pc xxx to pc yyy", synchronization primitives, sharing of variables between pcs, sending mails, etc etc etc.

STAF is a very impressive piece of software. Don't let the outdated JAVA ui look and feel of some of the tools that come with it fool you. Everything can be activated from the command line. Making use of the JAVA uis is optional, but the ui offers lots of out-of-the-box functionality that I wouldn't want to program myself if I can avoid it. Probably the quickest way to get started writing a test harness is to use the STAX service. Lots of excellent documentation and tutorials on STAF/STAX are available from the official STAF/STAX website, but I found it beneficial to first read this introduction from Grig Gheorghiu. STAX offers an XML based language with embedded Jython fragments (Jython is a version of Python that compiles to the java virtual machine).

To be honest, STAX being based on XML doesn't make it the most programmer friendly programming language in existence (the value of what it provides to a certain extent compensates for the discomfort of using it). To make it somewhat user friendlier, good syntax highlighting is indispensable. The syntax highlighting is somewhat complicated because STAX really consists of a combination of two rather different languages in one: on one hand there's the XML that is used to define the high-level control flow of the test harnass. On the other hand there's embedded jython code.

If you understand why creating a syntax highlighting definition for a language like STAX could be a challenge, you might appreciate the elegance with which the problem can be solved in the world's most powerful programmer's editor: vim. Vim offers ways to define syntax highlighting in different modes (if you know vim, this concept of modes should not come as a surprise ;) ). The easiest way to syntax highlight STAX programs in vim is to reuse the existing syntax highlighting for XML and Python. Vim can switch between different syntax highlighting modes based on encountering certain regular expressions.

Syntax highlighting code

Put the following code in a file called stax.vim:

runtime! syntax/xml.vim
unlet! b:current_syntax
syntax include @Python syntax/python.vim
syntax region pythoncode matchgroup=pythongroup start=+<script>+ keepend end=+</script>+ contains=@Python
hi link pythongroup xmlTag

On my linux system, in the .vimrc file, I added

au BufNewFile,BufRead *.stax set filetype=stax

to activate the syntax highlighting for all files that have a .stax file extension. On a windows system, i had to add the above line to "Program Files"\Vim\vim73\filetype.vim instead.

With the syntax highlighting definition provided here, STAX becomes more programmer friendly. (Note: I posted this same code some time ago on the staf/stax mailing list)

Monday, September 19, 2011

Generate side-by-side diffs in html using vim

Problem

Given two text files, generate a visually appealing diff between them. Do so in html, so it can be visualized in a web browser.

Some approaches

Searching the web

The internet has a suprisingly little amount of flexible standalone tools to generate html diffs that fullfill all my requirements. My requirements include
  • generate side-by-side diff
  • allow to save to html without user intervention
  • work fast on large files with lots of differences
This overview is by no means meant to be exhaustive:
  • lots of diff tools exist, but to the best of my knowledge none of them can generate html.
  • match-patch doesn't seem to generate the layout i'd like to see.
  • diff2html.py and derived tools won't generate intraline differences.
  • csdiff only works on windows systems (but in all honesty, it's faster to generate diffs than using the VIM approach described in this article, and the generated html is more user friendly because it includes navigation between differences)

Rolling your own

In the past i have rolled my own solution in python, using two different approaches:
  • Using python's difflib. This is by far the easiest solution, but it can be very slow for long files with a lot of differences between the two files under comparison.
  • Using a combination of GNU diff and python's difflib. I used GNU diff to generate a rough diff, then used python difflib to generate the intraline differences. This was a lot faster than using only python's difflib already, but still too slow on very large files with many differences. This approach does have the advantage of being very flexible: this tool can generate both side-by-side and line-by-line differences with or without intra-line differences indicated.

Using vim

The text editor vim has an option to visualize the diff of two files by calling it with the command line option "-d":
gvim -d file1.txt file2.txt
Vim highlights as the intraline difference everything between the common prefix and common suffix of a line. Depending on your needs, this may be too much of an approximation. In recent enough versions of vim, the complete diff can be rendered to html using the command
:TOhtml
This command will create a third buffer containing the html representation. Colors are determined by the active colorscheme. Colorscheme can be changed using the command
:colorscheme <name>
Colorscheme only seems to have the expected effect if you use gvim instead of vim. You can experiment with using "vim" instead of "gvim". The names of possible colorschemes can be found underneath the colors folder in the vim installation folder. By default the following colorschemes were installed on my system:
  • blue
  • darkblue
  • default
  • delek
  • desert
  • elflord
  • evening
  • koehler
  • morning
  • murphy
  • pablo
  • peachpuff
  • ron
  • shine
  • slate
  • torte
  • zellner

Automating the html generation using vim

All of the above consists of steps to perform manually, which is ok if you have to compare two files, but far from ok if you have to diff hundreds of files. So how can it be automated? Luckily vim has a few interesting command line options, one of which is the option "-c". Option "-c" allows you to pass a command that will be executed on startup, after the file(s) are loaded. You can pass more than one "-c" command. The following one-liner will load the files, select a colorscheme, generate the diff, save it as html to a file called diff.html, and close vim:
gvim -d orig.txt modified.txt -c "colorscheme zellner"\
-c TOhtml -c "w! test.html" -c q! -c q! -c q!
Note that if you intend to send a lot of commands to vim, you will want to use the command line option "-s" , which allows you to specify a file with vim commands to be executed after the first file is loaded. so the previous command line then becomes
gvim -d orig.txt modified.txt -s commands.vim
and the contents of commands.vim are:
:colorscheme zellner
:TOhtml
:w! test.html
:q!
:q!
:q!

Generating html fragments to embed in a bigger page

Here's one approach to strip the <html> and <head> tags, and replace the <body> tag with a table. In short, replace the previous commands.vim file with this one:
:colorscheme zellner
:let g:html_use_css=0
:TOhtml
:%g/<body/normal k$dgg
:%s/<body\s*\(bgcolor="[^"]*"\)\s*text=\("[^"]*"\)\s*>/<table \1 cellPadding=0><tr><td><font color=\2>/
:%s#</body>\(.\|\n\)*</html>#\='</font></td></tr></table>'#i
:w! PATH/TO/diff.html
:q!
:q!
:q!
Vim's TOhtml command takes a few options that allow you to influence the html generation. Some examples are listed below. Be sure to check out the vim documentation to find out about other useful options.
  • add
    -c "let g:html_use_css=0"
    to avoid generating css (for using with very old browsers, or to embed in emails);
  • add
    -c "let g:html_dynamic_folds=1"
    to generate html with css that allows dynamic folding of sections in the files (useful for source code)
  • add
    -c "let g:html_number_lines=1"
    to show line numbers
  • add
    -c "let g:html_no_pre=1"
    to wrap long lines instead of having scrollable columns
  • add
    -c "let g:html_use_xhtml=1"
    to generate XHTML instead of HTML
Needless to say, if you (ab)use vim in this way in a multi-user environment you will have to take care of choosing a suitable .html filename (unique name for each user/process) to avoid multithreading problems.

Using vim in server mode

Here's another neat trick in case you want to avoid starting up vim over and over again... You can start vim in server mode, meaning that it can listen to remote commands, as follows
gvim --servername DIFFSERVER
DIFFSERVER is just a name I chose. It's an id that is used to identify the correct vim instance that should receive your commands. After you've started vim in server mode you can start a different console (or keep using the same one...) and send commands to the vim server:
vim --servername DIFFSERVER --remote-send ":e PATH/TO/file1.txt"
vim --servername DIFFSERVER --remote-send ":vert diffsplit PATH/TO/file2.txt"
vim --servername DIFFSERVER --remote-send ":colorscheme zellner"
vim --servername DIFFSERVER --remote-send ":let g:html_use_css=1"
vim --servername DIFFSERVER --remote-send ":TOhtml"
vim --servername DIFFSERVER --remote-send ":w! PATH/TO/diff.html" 
vim --servername DIFFSERVER --remote-send ":q!"
vim --servername DIFFSERVER --remote-send ":q"
For now it seems to work reasonably fast even on large files with many differences (except when you use dynamic folding). Diff to html? Piece of cake! ;)