January 26, 2010

The P4 command line client in colour

Integration

As they say on the old maps: Here be dragons.

Looking at the typical Linux command line tools like ls, I noticed that the output of these commands is normally in colour; this makes the output much easier to scan. So I wondered: could this be done to the output of the Perforce client P4 as well? The search for an answer took me on an interesting journey I'd like to share with you.

Client or Server?

The first question I had to ask myself was: where do I add the colour (excuse my British English spelling), client or server? I already knew that I wanted to simply add ANSI control sequences to the output, but creating a special client for it seemed tedious. Then I analysed what the server actually sends to the client (try "p4 -vrpc=5 info" for a laugh) and realized that I had all the building blocks already in my hand:

What the server returns are format strings in the following form:

RpcRecvBuffer fmt0 = Server date: %serverDate% %serverTimeZone%
RpcRecvBuffer serverDate = 2010/01/08 13:12:12
RpcRecvBuffer serverTimeZone = +0000 GMT Standard Time

What I wanted to colour in were those place holders surrounded by % characters. If only there was a way to change the format string in the server and I'd be done. Turns out, there is a simple way that does not require any server changes.

P4Language

Very few of you will have come across the environment variable P4LANGUAGE (or "p4 -L <language>" as a command line switch). This switch is useful if you want to localize the responses of the server into your language (such as Japanese). All responses from a server, be it messages or errors, are number-coded. The default, English, is compiled into the server code, but additional languages can be added. These will be stored in the Perforce server in the table db.message, which is normally empty. Now, if you ask Perforce support nicely (or check my public depot //guest/sven_erik_knop/colour), you can get a file normally called "english.txt". This is a journal file that contains all Perforce Server messages. Modify this file, restore it to your server and you can change the server messages.

The file contains entries that look like this:

@pv@ 0 @db.message@ @en@ 1092816903 @Bad opcode '%operation%' journal record!@

The initiated should recognize this as a standard Perforce journal file for the table "db.message". The language here is "en". If you restore this journal to your server and set "P4LANGUAGE = en" in your environment, you can modify your server output. Unsetting P4LANGUAGE or simply pointing it to a non-existent language (like None) will get back your original server messages.

Aha, you sayz, I know just what to do! I simply surround all place-holders in the text messages with my ANSI escape sequences, replace all instances of "@en@" with "@en-color@", install the so modified journal file on my server, set "P4LANGUAGE=en-color" and - presto - I have colour output. Alas, it is not quite as easy.

ANSI Escape Sequences

ANSI escape sequences for colour encoding have the following form:

Esc[Value;...;Valuem

Values are typically a triplet separated by semicolons. Here is a table from the ACII escape table website

Text attributes
0 All attributes off
1 Bold on
4 Underscore (on monochrome display adapter only)
5 Blink on
7 Reverse video on
8 Concealed on
 
Foreground colors
30 Black
31 Red
32 Green
33 Yellow
34 Blue
35 Magenta
36 Cyan
37 White
 
Background colors
40 Black
41 Red
42 Green
43 Yellow
44 Blue
45 Magenta
46 Cyan
47 White

To reset the colour, you would simply use the sequence

ESC[0m

The problem with surrounding those place holders in the journal file with the escape sequence is that this sequence contains a square bracket "[", and the Perforce client looks out for this character to detect optional entries, for example in this entry:

@%job%[ on %date%][ by %user%][ *%status%*][%description%]@

The fields date, user and so on are only printed if the values for the place holder inside the square brackets are returned by the server. Unfortunately this breaks the colour escape sequence, and the client returns garbage.

The solution

The surprisingly simple solution (thanks Paul) is to surround the whole colour escape sequence with an additional square brackets.

There we have it then. An example for a modified server message that displays a change number in colour looks like this:

@Invalid changelist number '[ESC[1;32;40m%change%ESC[0m]'.@

(replace ESC with the ASCII character 27). According to the above table, this will present the changelist itself in green on black background. Here is an example from my test server:

p4-colour

Unfortunately this does not work in the Windows Command Prompt, since the console does not honour ANSI escape sequence. You need to either wrap the P4 output to translate the escape sequences, use Cygwin or, as I did, modify the P4 client code to do the translation for me. Maybe a future version of the Perforce client for Windows will do that for us automatically?

Happy hacking

Sven Erik