Single keystroke commenting/uncommenting in vim

November 6, 2010

A substantial amount of debugging time is spent commenting and uncommenting lines of code. The following vim code has greatly increased my efficiency in debugging by allowing me to comment or uncomment a line of code with a single keystroke – f2 to comment and f3 to uncomment. Note that it does rely on code indenting being switched on (I just use the ’set autoindent’ command in my .vimrc).

It automatically uses the appropriate comment syntax depending on what type of file you’re editing (or more accurately, depending on the file extension). Currently it supports the following single line comment styles and file types:

  • ‘//’ for Javascript (.js), PHP (.php), C (.c and .h), and Java (.java) files
  • ‘/*’ … ‘*/’ for CSS (.css) files
  • ‘#’ for ini (.ini) and perl (.pl) files
  • ‘<!––’ … ‘––>’ for HTML (.html), XML (.xml) and ASP (.aspx) files
  • ‘”‘ for .vimrc files

The f2 key comments the current line and f3 uncomments the current line. It places the beginning comment symbol (‘//’ or ‘/*’ for example) right at the beginning of the line, and the ending comment symbol if there is one (‘*/’ for example), right at the end of the line.

Download: awc_vim_config_commenting-1.0.tgz

To use, just add the contents of the file ‘commenting.vimrc’ to your .vimrc file. The code is reproduced below, but it’s safer to use the download link above, rather than cutting and pasting from this page, as mistakes can creep into the markup in a web page. As modifications are made, I’ll put the old versions at the bottom of this post.

" {{{ START Commenting functionality for different file types

" Comment a line
autocmd BufNewFile,BufRead,TabEnter     *.js,*.php,*.c,*.h,*.java       nnoremap <f2> <home>i//<Esc>
autocmd BufNewFile,BufRead,TabEnter     *.css                           nnoremap <f2> <home>i/*<end>*/<Esc>
autocmd BufNewFile,BufRead,TabEnter     *.ini,*.pl                      nnoremap <f2> <home>i#<Esc>
autocmd BufNewFile,BufRead,TabEnter     *.html,*.xml,*.aspx             nnoremap <f2> <home>i<!--<end>--><Esc>
autocmd BufNewFile,BufRead,TabEnter     *.vimrc                         nnoremap <f2> <home>i"<Esc>

" Uncomment a line
autocmd BufNewFile,BufRead,TabEnter     *.js,*.php,*.c,*.cpp,*.h        nnoremap <f3> :.s/^\(\s*\)\/\//\1/<cr>:let @/=''<Esc>
autocmd BufNewFile,BufRead,TabEnter     *.css                           nnoremap <f3> :.s/^\(\s*\)\/\*\(.*\)\(\s*\*\/\)/\2/<cr>:.s/\s*$//<cr>:let @/=''<Esc>
autocmd BufNewFile,BufRead,TabEnter     *.ini,*.pl                      nnoremap <f3> :.s/^\(\s*\)#/\1/<cr>:let @/=''<Esc>
autocmd BufNewFile,BufRead,TabEnter     *.html,*.xml,*.aspx             nnoremap <f3> :.s/^\(\s*\)<!--\(.*\)-->/\1\2/<cr>:let @/=''<Esc>
autocmd BufNewFile,BufRead,TabEnter     *.vimrc                         nnoremap <f3> :.s/^\(\s*\)"/\1/<cr>:let @/=''<Esc>
" }}} END Commenting functionality for different file types
0

vim tabs

October 28, 2010
Tags: ,

I recently discovered that vim has tabs built in as of version 7. Although there are already a couple of ways to edit several files at one, tabs save me quite a few keystrokes over moving between split windows or ‘Ctrl-z/fg’-ing in the shell. They also allow me to see at a glance all of the files I currently have open, and they only take up a single line of valuable vertical space.

I found the default key mappings for cycling through the tabs to be a bit awkward though (gt – go to next tab; gT – go to previous tab), and the command to open a new tab (‘tabnew’) a bit verbose (compared to ’sp’ to open a new file in a split window).

To make cycling through tabs more comfortable, intuitive and efficient, I’ve mapped <tab> and <s-tab> (that’s shift-tab in vimland) to cycle forward/backward through the tabs. To cut down on keystrokes when opening a new tab, I added an abbreviation ‘nt’ (new tab) for the ‘tabnew’ command.

Here’s the vim code (add to your .vimrc file):

nnoremap <tab> gt
nnoremap <s-tab> gT
cabbr nt tabnew

To open multiple files in tabs from the command line, use the ‘-p’ option. If you don’t want to remember that, then you could alias ‘vim -p’ to something memorable like ‘vimtabs’ in your .bashrc file, eg:

alias vimtabs='vim -p'

This is all you need to know to start using tabs effectively, but you can learn more by typing ‘:help tab-page-intro’ in vim.

0

Detecting Keystrokes On The Console With Java

July 20, 2010

I was well into writing a console application in Java, when I discovered one of its limitations – it’s not possible to detect keypresses directly in Java if you’re not using a GUI in your program. You can read from stdin alright, but you get a whole line of input, as Java won’t give you the input until the user presses enter.

The workaround I came up with is not a complete solution, but it fulfilled my needs at the time. The basic technique is to filter stdin before it reaches Java, adding a newline after every character typed.
This is done with the bash read command.

So, to run my java program (TestClient1.jar) I create a bash file called runTestClient1.bash which looks like this:


while [ 1 ]
do
    read -n1 KEY
    echo "$KEY"
done | java -jar TestClient1.jar

Now I run my java program by executing this bash file.

In your Java program, you can read the keypresses like in this example code for a ‘user input’ thread. When it receives a keypress it calls a method of my main TestClient1 class:


import java.io.*;
import java.util.*;

class UserInputThread extends Thread
{

    public BufferedReader in;

    public void run()
    {
        in = new BufferedReader( new InputStreamReader(System.in) );

        while ( true )
        {
            String line = "";

            try
            {
                line = in.readLine();
            }
            catch ( IOException e )
            {
                System.out.println("IOException: " + e);
            }

            TestClient1.keyPressed( line );

            try
            {
                Thread.sleep(50);
            }
            catch ( InterruptedException e )
            {
                 System.out.println("InterruptedException: " + e );
            }
        }
    }
}

As it stands, this solution doesn’t let you detect cursor keys, function keys, shift/alt keys etc. In my Java program I test for an empty string and assume that’s the return key. I’ll post updates if I make any improvements to this solution.

0

HTTP Streaming With PHP

January 10, 2010

Introduction

This article outlines the technique of HTTP Streaming with PHP, which I first used in AWC Blackjack (version 0.9 at time of writing). The game was partly proof-of-concept work at the time, back in 2005 – to see if a real-time multi-player game could be implemented with only open technologies found in any modern web browser (ie without proprietary browser technologies like Flash or Java).

A major hurdle was Javascript’s lack of socket support. I expected to implement server polling, and to accept a certain sluggishness on the front end as a result. Thankfully, I discovered HTTP Streaming which enabled the game to deliver a constant stream of data on a dedicated connection to each game client. This made the game more responsive, and brought the game’s performance and efficiency closer to that of a socket connection based game than I had dared hope.

The technique has one major limitation – it is scuppered by proxy servers, which renders the technique unsuitable for mobiles as they tend to access the web via a proxy. I anticipate solving this problem by using long-polling instead of streaming for such clients (whilst abstracting away these implementation details in my Javascript classes).

The Problem

The HTTP protocol doesn’t provide a constant dedicated connection between server and client. In a traditional client/server app, socket connections are usually used to achieve this. The connection is created once, and then both server and client can use it to send messages to each other as a constant stream without having to break off and re-establish the connection every time they want to communicate.

Unfortunately, Javascript doesn’t support sockets. In the web model, if the client wants to send a message to the server, it must open a HTTP connection, send the message and then close the connection. It must repeat this process every time it wants to send a message. The server has an even bigger problem: if it has data to send to a client, it has no way to contact the client – it must wait for the client to contact it, and then give it the data. Often, polling is used to solve this problem – contacting the server periodically (say, every second or so) to check for messages.

This is not an efficient client/server model, as HTTP connections are very expensive, both in terms of how long it takes to open the connection, and the amount of bandwidth required. Establishing a HTTP connection usually takes a non-negligible fraction of a second – on the order of a tenth of a second or so for a desktop PC with a broadband connection. Also, a message might only be a byte long, so wrapping it up in a hundred or more bytes of HTTP headers is a waste of bandwidth.

Fortunately, we can get a dedicated connection between server and client by using HTTP Streaming. Basically, this means keeping a HTTP connection open indefinitely and outputting data to the client as and when it becomes available.

It doesn’t work the other way round though – client to server communication must still use regular HTTP connections to send one message at a time. For an app like AWC Blackjack, which only needs to send data from client to server infrequently – typically in response to a user action, clicking on something say – that’s hardly a problem at all.

The PHP Solution

The key to implementing the HTTP Stream is to keep the connection open indefinitely with an infinite loop in a PHP page. On each iteration of the loop, we check if there are any new messages to output to the client, output them if there are, and then pause for a while before starting the next iteration.

In PHP, the basic loop would look something like this:


while ( 1 )
{
    $aMessages = checkForMessages();

    if ( !empty($aMessages) )
    {
        foreach ( $aMessages as $msg )
        {
            echo $msg . MESSAGE_DELIMITER;
            ob_flush();
            flush();
        }
    }

    usleep( MESSAGES_CHECK_INTERVAL );
}

Note the calls to ob_flush() and flush() – these are both required to ensure that PHP and the webserver (I’m assuming Apache here) output straight to the client without buffering.

Depending on your app, you may need to detect when the user has disconnected. There are several ways the connection could be interrupted or stopped. If PHP detects a deliberate disconnect (the user pressing ’stop’ or closing the browser) it will shut the script down. It will also stop the script if its execution time exceeds PHP’s max_execution_time setting, or if a fatal error occurs somewhere in the script’s execution.

For these cases, we can use PHP’s register_shutdown_function() function to tell PHP to execute a handler function when the script dies, for whatever reason. In the handler, we can determine what caused the script shutdown, and take any necessary action. A deliberate user abort can be ascertained using PHP’s conection handling features.


register_shutdown_function('handleShutdown');

function handleShutdown()
{
    $connectionStatus = connection_status();

    if ( $connectionStatus == 1)
    {
        // User aborted - take appropriate action
    }
    elseif ( $connectionStatus == 2 )
    {
        // Script execution timed out - take appropriate action
    }
    else
    {
        // Connection appears to be normal - maybe fatal PHP error?
    }
}

The case not handled here is where a network error occurred somewhere between the client and server. In this case, PHP doesn’t know the connection has been lost, script execution won’t be halted and so handleShutdown() won’t be called. If your app needs to handle this eventuality you could, as AWC Blackjack does, have the server decide the client has ‘gone away’ if it doesn’t receive any messages from it for a specified length of time, and feed a ’shutdown’ instruction to the still-running script to have it shut itself down.

Note also that PHP won’t detect a deliberate user abort until it tries to output some data to the browser. So if there happens to be no new messages to send to the client for 10 seconds, you may only be notified of a user abort up to 10 seconds after the actual event. This is easily worked around by periodically sending a ‘pulse’ message, which the client would ignore and whose sole purpose is to help PHP decide if the client is still there or not.

If, for example, you need to know about a user abort within two seconds, then you could send the client the pulse message whenever there have been no other messages for two seconds. Or if you need to know immediately about a user abort, send the pulse at the end of every iteration of your main loop.

There is one final thing to add, due to a cross-browser issue that affects our PHP. I’ll detail the issue further in a future post describing how to use Javascript to use the HTTP stream. In short though, some browsers require a ‘kickstart’ to the stream – they must receive a certain number of bytes before they’ll start allowing the data in the stream to be accessed via Javascript. So at the start of the script we output 500 bytes before going into the main loop.

With the kickstart added, and assuming we’re sending a pulse message on every iteration of the main loop, the whole PHP script would look something like:


<?php

define( 'MESSAGES_CHECK_INTERVAL', 250000 );
define( 'MESSAGE_DELIMITER', '#' );
define( 'KICKSTART_LENGTH', 500 );

define( 'PULSE_MESSAGE', '.' );

register_shutdown_function('handleShutdown');

// Kickstart
outputToBrowser( str_repeat( '.', KICKSTART_LENGTH ) );

while ( 1 )
{
    $aMessages = checkForMessages();

    if ( !empty($aMessages) )
    {
        foreach ( $aMessages as $msg )
        {
            outputMessage( $msg );
        }
    }

    // Pulse
    outputMessage( PULSE_MESSAGE );

    // Pause before next iteration
    usleep( MESSAGES_CHECK_INTERVAL );
}

#
# END OF SCRIPT - functions follow
#

function outputToBrowser($out)
{
    echo $out;
    ob_flush();
    flush();
}

function outputMessage($msg)
{
    outputToBrowser( $msg . MESSAGE_DELIMITER );
}

function handleShutdown()
{
    $connectionStatus = connection_status();

    if ( $connectionStatus == 1)
    {
        // User aborted - take appropriate action
    }
    elseif ( $connectionStatus == 2 )
    {
        // Script execution timed out - take appropriate action
    }
    else
    {
        // Connection appears to be normal - maybe fatal PHP error?
    }
}
?>
0

Bash ini File Parser

January 5, 2010
Tags: ,

Download: awc_bash_ini_parser-0.3.tgz

I often have a need to store config information which various parts of my web apps can access, usually PHP on the front end and a mixture of bash, PHP, perl, python etc on the back end. While building my AWC Search Site package (the basis of http://billiardsearch.net and http://drums.tinternet.info), I decided that ini files would be a good solution, as they have a simple format and are easy to read and edit with a regular text editor.

Unfortunately I couldn’t find a decent ready-made solution to enable my bash scripts to read ini files at the time, so I thought I’d roll my own. It was an opportunity to improve my bash scripting knowledge, particularly manipulating strings.

It was a nice exercise in bash coding, as I encountered many whitespace preservation and quoting issues, learnt about some surprisingly sophisticated in-built string manipulation features of bash, as well as being gotcha’d by a variable scoping issue, which took alot of head scratching before I got to the ‘doh!’ moment, and implemented a solution (non-POSIX compliant unfortunately) I found here.

Partly because of these issues, the code is not very optimised as I may have done some things differently to work around issues I solved only recently (and not undone the workarounds yet). But as of this version (0.3 at time of writing), I’m mainly concerned with making it stable, easy to use, and with clearly documented behaviour.

There is no real standard for the ini file format – many different implementations allow different features. See the README file contained in the distribution for a brief description of what this implementation allows, and browse the test ini files (in the distribution’s test/ directory) for some comprehensive examples.

If you use it be aware of the fact that eval is used in the script – it’s the only way I could initialise variables with names built up from other variables. This could potentially cause malicious code inserted into a data value to be executed. There are two obvious ways this could be done – by using the backtick operator, or the $() notation (both exactly equivalent notation, though the latter is preferred these days for a number of reasons) – so I’ve dealt with those cases. These two ini file entries, for example, will not delete IMPORTANT_FILE:

var1 = blah blah blah `rm -rf IMPORTANT_FILE` blah blah
var2 = blah blah blah $(rm -rf IMPORTANT_FILE) blah blah

Any other vulnerabilities will be dealt with as they come to light – please let me know if you think of any!

2

Rotating Images: Fun with the canvas

August 29, 2009


rotater_thumb_mantis

A script to rotate images on web pages (AWC Image Rotater) using the HTML canvas element and Javascript (so it won’t work in non-standard browsers like Internet Explorer). Uses prototype javascript framework.

Move your mouse over any image on this page to see it spin.

rotater_thumb_human_femaleImage rotation will soon be possible via CSS3, and it’s already possible on WebKit-based browsers (like Safari and Chrome). When web designers cotton on to the fact that they can now tilt or rotate images, they’re going to use it, and maybe the web page authors will want a fallback method for browsers that don’t support CSS3 or the webkit transforms. Hopefully this script will be useful to them.

rotater_thumb_camelThe script also provides some additional useful functionality in the form of a set of custom mouse events which give the mouse co-ordinates relative to the top left of the image, no matter what its current rotation angle. This would make it easy, for example, to detect when a certain portion of your image is clicked.

rotater_thumb_orangutanIf I ever get time, I will add IE support. Unfortunately, excanvas isn’t suitable at the moment. When it supports the toDataURL() method I should be able to code AWC Image Rotater to work with excanvas. I did attempt IE support using Microsoft’s filters, but they turned out not to be viable because it simply didn’t work as expected. Possibly I could use a VML-based solution, but I’ll probably just wait a while first to see if excanvas gets the toDataURL() method in future releases.

Images from morguefile. (more…)

0