iTerm+blur: updated; thanks git

Update: The patch has been merged into upstream CVS. Yay!

I’ve merged the current CVS HEAD (sub-minor version 0821 apparently) of iTerm with my +blur branch. You can download the new binary.

In doing so, I found that there’s a new maintainer, James Bunton, responsible for most of the changes. He’s got a mercurial tree, but it’s not up to date with sourceforge CVS. Welcome to distributed VC hell, where CVS is being used as a central repository between patchset-based DVCs. There are some importers, but if the canonical repository is CVS, importing from the mercurial tree is strictly more work (since I’d still need to import the CVS updates, and merge again).

cvsps and git-cvsimport do a good job of making working with cvs repositories from git reasonably painless. But I had some issues.

Perhaps it was just me failing, but I couldn’t coax git-cvsimport to import into my remotes (yes, using -r). Also it would be nice if git pull could figure out a remote was CVS and run git-cvsimport for me, using cached parameters. As it is, I have one repository for running git-cvsimport, and my working repository that pulls from that.

Git seems remarkably unhelpful when it comes time to do manual merging. An “ours”-type strategy for hunks consisting of just CVS $Id$ keywords would be nice. Why isn’t there a simple comand to run a 3-way merge with an arbitrary merge(1)-compatible invocation? I discovered smartmerge too late, but surely manual merges are common enough that getting 3 temporary files together could be done in one base command?

There’s a persistent feeling when using git that I’m doing it wrong, or at least there’s an easier way if only I could remember the command. I ran git status |grep unmerged because I couldn’t remember that I wanted git ls-files -u. I have to re-read git-rebase’s documentation every time I use it.

Update: the ident attribute deals neatly with CVS $Id$ keywords.
Update: the git mergetool command can be used instead of smartmerge.

blur for iTerm

iTerm+blur screenshot
iTerm+blur screenshot

I’ve been a fan of terminal transparency since there have been terminal-emulators that supported it (although in the old days, it was just showing the X11 root window with some tinting). I’m not alone, and similar terminal-emulator users have been ahead of their time with respect to the transparency-fetish that is now popular.

Back on Windows 2k and xp there were various hacks that could turn a window transparent (I used one that came with my nVidia drivers). They weren’t perfect, as the transparency included the window borders and chrome, but they granted real transparency: where the background is a composition of alpha-blended windows. This added a little bit of depth to the desktop, rather than just having pretty terminal backgrounds.

When I moved to OS X, iTerm did it properly (i.e. without making the UI parts transparent). However, at the end of a long night hacking, with several accumulated editor and terminal windows full of text merged on top of each other, there is a serious readability problem with low opacities.

I use transparency because:

  1. It’s easier on the eyes than high-contrast text-on-black.
  2. It’s multiplexing content from multiple windows without consuming screen resolution. This is a fidelity trade-off: as the visibility of lower layers of text increases, the accuity of the frontmost (focused) layer decreases.
  3. It impresses others.

When I saw Vista’s glass effect, the first thing I thought was “finally the answer to stacking translucent terminals!”. Combining blurring with transparency preserves the accuity of the focused window while transmitting enough information to be useful. So you won’t be able to transcribe text from below, but you can see if there’s, say, a burst of activity in IRC.

I suspect Microsoft got some IP rights on it, because Leopard has the most subtle application of transparency+blurring ever (in sheets and the menu bar), compared to Aero’s egregious UI-glassing. However, the imporant thing is that the new Core Image filters can be applied to windows, with a compositing mode that is perfect for terminals (and text editors for that matter).

One stumbling block is that the API to apply window filters is undocumented. Fortunately, thanks to the CGSInternal headers some of this API has been exposed.

It’s already been exploited for Apple’s Terminal.app, but that requires Input Manager patching hacks. I gave reasons why I prefer iTerm in my last post, but here’s another one: it’s open source and so I can add blurring in myself.

Update: check out the source at github, or the built binary.

Update: The patch has been merged into upstream CVS. Yay!

monadic parser combinators with parsec

I decided to pull out Haskell for my Linguistics 1101 Phrase Structure Rules Assignment. It seemed like a good opportunity to play with these monadic parser combinator things, which sound impressive if nothing else. The result was pleasing, although I’m not sure if my tutor will appreciate it.

It was fun revisiting Haskell, and writing parsers directly using Parsec is certainly a novel alternative to using a Bison-style compiler-compiler. Spirit was similar, but C++ can become so syntactically clunky some of the joy is lost.

I’m not sure whether it was something specific to the Parsec paradigm, my abuse of Parsec, or my ignorance of Haskell and monadic programming in general, but I kept finding myself on the wrong side of Monads and do-expressions. It seems you have to use liftM a lot.

In looking for a generalisation of the liftMn functions I came up with:

foldMLr :: (Monad m) => (t -> a -> a) -> a -> [m t] -> m a
-- foldMLr f u xs binds the monads in xs headfirst, and folds their results
-- from the right using f and u as the rightmost.
foldMLr _ u [] = return u
foldMLr f u (x:xs) = do { a <- x ; b <- foldMLr f u xs ; return (f a b) }
-- equivalently:
-- foldMLr f u (x:xs) = liftM2 f x (foldMLr f u xs)

which is not the same as foldM but is a generalisation of sequence, which can be defined as foldMLr (:) []. I didn’t end up using it in the final parser.

Another issue was that constructing a parse tree (using Data.Tree types) was actually somewhat tedious. I guess Parsec assumes that you want to fold up the result within the parsers.

Also watch out for the change in showErrorMessages, in ghc it takes some extra initial string arguments that weren’t there in the standalone release.