Switching to mercurial: taming zsh

A quick one, so you’ll know not all my posts must have so many words. PEP 385 is materializing, and its time to learn Mercurial. I can’t say I’m a Mercurial expert, but I thought migrating all my git-oriented-zsh-gizmos would help me along the way. The conversion is almost done and had just one somewhat noteworthy tidbit.

A while back I copied from a friend a rather elaborate zsh prompt (not as elaborate as some people’s…), which includes my current git branch (if any) in it. The code to make it looked like this:
[sourcecode lang=”bash”]
parse_git_branch() {
git branch –no-color 2> /dev/null | sed -e ‘/^[^*]/d’ -e ‘s/* \(.*\)/(\1)/’
}

function _rprompt_git {
local git_branch="$(parse_git_branch)"
if [ -n "$git_branch" ]; then
result=":%{$fg[blue]%}$git_branch$rst"
fi
echo -n $result
}
[/sourcecode]
I’ve naïvely added a Mercurial equivalent to parse_git_branch using hg bookmarks or hg branch, and retrofitted/redubbed _rprompt_git into _rprompt_dvcs. It worked well, but was slow. I’m not the kind of person to give hg grief over reasonable speed differences with the speed monster, but you can’t wait 0.15 seconds for your friggin’ prompt, now can you (this is not an invitation for a git/hg/bzr performance holy war in the comments, people). Removing a call to hg by using $ hg root just once, storing that value and using cat to get the actual branch/bookmark didn’t speed things up enough. #mercurial on freenode was kind but didn’t know how to help, other than suggest I buy a really fast computer… Blah, I’ll have to jot something out in C.

One bitbucket account later and a bit of tinkering led to fast_hg_root, which is a dumb C program which acts as a (fast) replacement to hg root. So now my dvcs-prompt-related code includes:
[sourcecode lang=”bash”]
parse_git_branch() {
git branch –no-color 2> /dev/null | sed -e ‘/^[^*]/d’ -e ‘s/* \(.*\)/(\1)/’
}

parse_hg_branch() {
if ! HG_ROOT=$(fast_hg_root) 2> /dev/null; then
# not an HG repository, quit
return
fi
BOOKMARK=$(cat "$HG_ROOT"/.hg/bookmarks.current 2> /dev/null)
if [ -n "$BOOKMARK" ]; then
# have a current bookmark, display that
echo $BOOKMARK
return
fi
# display the current branch or ‘default’
cat "$HG_ROOT"/.hg/branch 2> /dev/null || echo ‘default’
}

function _rprompt_dvcs {
local git_branch="$(parse_git_branch)"
if [ -n "$git_branch" ]; then
result=":%{$fg[blue]%}$git_branch$rst"
else
local hg_branch="$(parse_hg_branch)"
if [ -n "$hg_branch" ]; then
result=":%{$fg[green]%}$hg_branch$rst"
fi
fi
echo -n $result
}
[/sourcecode]

Which leads to my terminal sessions on my netbook monica looking like so:
DVCS aware zsh prompts

C’est tout. If someone is interested, I’ll open a repository with more of my .zsh.d stuff. By the way, anyone knows of a good way to capture a terminal into HTML, preserving ANSI color? I know of ttyrec and found HTML::FromANSI, but was hoping for a finished program or at least, uhm, a library less in Perl. :p


Comments

12 responses to “Switching to mercurial: taming zsh”

  1. dubek Avatar
    dubek

    I don’t know about mercurial, but git comes with a bash script to give you the branch name (if you’re inside a “working copy”), and even the dirty-state and whether you have stashed files.

    I have this in my bash_profile (sorry, haven’t moved to zsh yet):

    export GIT_PS1_SHOWDIRTYSTATE=1
    . /usr/local/git/contrib/completion/git-completion.bash
    export PS1=’\u@\h \w$(__git_ps1) \$ ‘

    The __git_ps1 function uses some plumbing utils like git-rev-parse which are probably faster than git-branch.

    1. Sweet, cheers (good to see you among the readers)!

  2. ap3rson Avatar
    ap3rson

    I’ve noticed that you have a broken Wikipedia reference going out to Monica_Sex (a rock band) instead of what I assume is meant to be a reference to Monica Font Family.

    -D

    1. Nope, my hostname is monica, named after the rock band Monica Sex. 🙂

      1. ap3rson Avatar
        ap3rson

        Touche sir, my apologies. That’ll teach me how to read and look at the terminal window more carefully :).

        Thanks for great posts.

        -D

  3. Nice post. Regarding script-to-HTML formatting, I started a Python program to do exactly that. Click on my name for the link. It does not yet support color, but if you express interest, that might give me enough motivation to finish it. Or, I’d gladly accept patches… 🙂

    1. Man, it’s been a while since I’ve looked at it. It *does* support color – I just don’t have test cases for them yet. So, it probably works. It does not yet support 256 color output – just normal 8-bit (+ bold) colors.

      1. I wish I could edit or delete my posts. I meant 8-color, not 8-bit color. I’ll stop now.

        1. Thanks for your interest/support. I’d be happy to take a look at your program as soon as I can (I’m a bit on a schedule these days, but due to good reasons…), will see if I can provide feedback or even patches at a later time. By the way, I can edit your comments, I just wasn’t sure if you’d want me to… 🙂

  4. Brec Carson Avatar
    Brec Carson

    why not just use sed to parse hg branch like is done for git? too slow?

    that’s the approach I’m taking but don’t know sed very well so was hoping to see a shortcut here.

    1. Brec Carson Avatar
      Brec Carson

      what I’ve gotten to work that has turned out to be quite easy and fast is this:

      parse_hg_branch() {
      hg branch 1> /dev/null 2> /dev/null | sed
      }

      I’m very naive wrt shell scripting experience so any advice is welcome.

      1. As I wrote in the article, hg branch does exactly what you need already, but being a Python process and wanting it to appear in the prompt causes it to be too slow. Also, piping through sed without any arguments has no text manipulation effect, it’s much like not piping it through anything at all. If it’s fast enough for your need, which it most likely is, vanilla hg branch is good enough.