Monday, 23 January 2012

Hiding a regex with vim (aka making C comments disappear)

I use the mighty vim editor for most of my coding. I have a heavily customized setup which has evolved over quite a few years. However, it is by no means a static setup as I keep finding new scripts and tricks (and of course Bram keeps on adding extra goodness with each release).

    Recently, I was hacking through a lot of C code containing lots of debug cruft (log function calls, commented out bits and pieces, etc). The problem was I couldn't get a feel for the code as all the debug was too distracting. The question popped into my head, "can I hide all this stuff?" A number of folk have come up with ways to "hide" the data you don't want to see in Vim using folds (":help fold" in Vim). However, that wasn't what I wanted as folds also introduce their own "visual noise". I just wanted this stuff gone.

    What I came up with is a complete hack, but it suited my purpose rather well: I changed the colour of the regex's matching the data I wanted to hide to match the colour of my terminals background.

    So rather than seeing this:




    ...with a few keystrokes, I could change it to this:


    Neat huh? Note that I've removed:

    • C-style comments
    • C++-style comments
    • "#if 0" blocks
    If we cancel "hidden mode", you can see the highlighted text:


    To achieve this, we need to make a few tweaks to your ~/.vimrc. First, we need a function that enables highlight search mode and then toggles the highlight mode for the "Search" highlighting group. We also need a variable to keep track whether we're in "hidden mode" or not:

    let g:Hide_Search = 0
    
    function! JHHideSearch()
      :set hlsearch
    if g:Hide_Search == 1
        let g:Hide_Search = 0
    " XXX: you might want to tweak the colours in the line below 
    :hi search term=reverse ctermfg=0 ctermbg=3 guibg=Yellow
      else
        let g:Hide_Search = 1
        " XXX: the colours to use to make the search terms invisible
        :hi search ctermbg=black ctermfg=black guifg=black guibg=black
      endif
    endfunction
    

    This is the "hack" since as you can see, I've hard-coded the normal colours used for highlighting the "Search" highlight group and I've also hard-coded the colour to make the search terms invisible. For the latter, I've used black as that is the colour I use for my terminal background. You might want to tweak those ":hi" lines with colours of your choice.

    Now, we need a key combo that will invoke this function. I chose "\h" (where "h" is a mnemonic for "hide":

    noremap \h :call JHHideSearch()<cr>
    

    Now, try searching for a string. Let's search for "hello" using the familiar vi(m) command:

    /hello
    

    Assuming that text is found in your file, if you now type "\h", all occurrences of that string will disappear! Type "\h" to undo "hidden mode" and display the search highlight again. This works for regular expressions of course.

    Since I spent most of my time working with C code, I also added a key combination that will select the 3 types of "comment" listed above:

    noremap \c /\/\*\_.\{-}\*\/\n\{,1}\\|^\s*\/\/.*\n\|\s*\/\/.*\\|\/\/.*$\\|^\#if 0\_.\{-}\_.\{-}#endif<cr>
    

    So, to hide all comments in the code I'm reading, I simply type "\c \h". And to revert to normal Vim behaviour, I type "\h".

    For further reading, fire up Vim: and look at:


    • :help highlight
    • :help hlsearch

    Thursday, 19 January 2012

    making uzbl-tabbed open a link in a new tab (not a new window)

    If like me you gravitate towards minimal applications, check out the uzbl web browser. It's based on webkit, supports Java, Flash, CSS, Javascript, etc and has full keyboard control. Added to this, it is fully configurable - it has a standard ASCII config file. This page shows the default keybindings.

    uzbl is a godsend to those of us who are too lazy (or busy) to take their hands away from the keyboard to reach for the pesky mouse.

    To install:

    sudo apt-get install uzbl
    

    I'm running uzbl-tabbed (which comes as part of the uzbl package). As the name suggests, this supports tabs. However, I was scratching my head trying to work out how to open a new link in a new tab, rather than a new window.

    The answer is simplicity itself (once you know of course :-). Fire up your favourite editor and point it at ~/.config/uzbl/config. Then, make sure you have an entry like this:

    @on_event   NEW_WINDOW     event NEW_TAB %s
    

    Now, any request to open a new window actually gets remapped to opening a new tab.
    So, I can type "fL" (which would normally open a link in a new window), type the number of the link I want and have the link opened in a new tab!

    Tip: Make sure your uzbl config files doesn't contain any other "@on_event NEW_WINDOW ..." entries are they are all honoured!

    Thursday, 5 January 2012

    Converting troff tables to ASCII

    One particularly useful piece of information I've been wanting to add to the Upstart Cookbook for a while now is the upstart-events(7) manual page. This page shows a summary of the "well-known" Upstart events that are provided on an Ubuntu system.  However, as show in the link, formatting this data is tricky due to the number and complexity of the tables.

    I wondered about converting the troff source to some other format (maybe DocBook) and using that source to generate both the man page and the same data in a format suitable for inclusion in the Upstart Cookbook. However, DocBook seemed a bit heavy weight and I'm not convinced it could handle it (tell me if I'm wrong!)

    My preference actually is to keep the source as troff since:

    • troff+tbl is a very rich language which provides a lot of control.
    • I want full control over the width of the tables

      The man page may look a little "cramped". I could have padded it out and made it a little easier on the eye, but I set myself a width constraint of 80 columns specifically for all the server folk out there who may want to view the page over an SSH connection.
    Recently, I've found a workflow that I'm happy with and it all hinges on the legendary Eric S. Raymond's awesome tool called doclifter. Here's the process:


    $ cd /tmp
    $ doclifter upstart-events.7
    $ xsltproc -o upstart-events.7.html \
          /usr/share/xml/docbook/stylesheet/nwalsh/xhtml/docbook.xsl \
          upstart-events.7.xml
    $ tidy -indent -utf8 -o upstart-events.7.xhtml \
          -asxhtml upstart-events.7.html
    $ elinks -dump-width 100 -dump upstart-events.7.xhtml > tmp.txt
    $ sed -e '1i ::\n' -e 's/^/  /g' tmp.txt > upstart-events.7.txt
    

    The workflow above converts the troff+tbl to XML (using doclifter), then to reformatted XHTML (using xsltproc), then to ASCII (using elinks), and finally it adds a reStructuredText "header" to show the ASCII is to be treated verbatim (using echo and sed).

    Once I've generated upstart-events.7.txt, I can include it into the cookbook like this:

    .. include:: upstart-events.7.txt
    

    Note that I could have left the data in XHTML for inclusion into the Cookbook, but that would have meant the PDF version of the Cookbook wouldn't have contained this data.

    Of course all the commands above can be wrapped up into a Makefile so we don't have to worry about typing them in again. Having done all that, let's look at the result: