Archive

Terminator 0.90 progress

Further to my previous post I thought I'd post a quick update about how things are progressing. I mentioned in my previous post that I knew of several things that were not yet working in the Epic Refactor branch:

  • -e and -x command line options
  • all forms of drag & drop
  • directional navigation
  • some keyboard shortcuts

I'm pleased to say that the first two of these are now taken care of, but the latter two are still to be done. I'm less pleased to say that I haven't had much external feedback about this branch yet, but I suspect that most people who might be interested probably don't read my blog ;) So if you know people who like Terminator and enjoy testing things out, all they need to do is: bzr branch lp:~cmsj/terminator/epic-refactor cd epic-refactor ./terminator

and give some feedback!


Testing Terminator 0.90

You might have seen my recent posts about the epic refactoring that has been going on in the Terminator codebase for the last few months. I think it's finally time that we get some more eyeballs on it, mainly so I can check that I haven't massively screwed something up. I know there is lots of missing functionality right now, and probably a bunch of subtle bugs, but I could use your help quantifying exactly what these are! If you're inclined to help, please branch lp:~cmsj/terminator/epic-refactor, cd into it and run ./terminator, then use it like you always would and file bugs, preferably indicating clearly in the bug that you're using this branch and not trunk (maybe tag the bug 'epicrefactor'). Things I know are broken right now:

  • -e and -x command line options
  • all forms of drag & drop
  • directional navigation
  • some keyboard shortcuts

Things I know are missing because they're not coming back: - Extreme tabs mode (sorry, it's just too insane to support) - GNOME Terminal profile reading (I'm trying to simplify our crazy config system and dropping GConf is a good way to achieve that) - Config file reading. At some point I'll write something that migrates old Terminator configs to the new format, but for now you'll have to live without your old config file. The new one isn't documented yet either, but it is a whole bunch better!

Now would also be a great time to start writing plugins for Terminator and telling me about them. I'm happy to ship good plugins, but more importantly I want feedback about the weaknesses/strengths of our plugin system. Right now you can only hook into URL mangling and the terminal context menu, but the latter of those gives you pretty serious flexibility I think. Obviously one massive weakness is a lack of documentation about the plugin API, but I'll get to that, I promise! So there we have it, another step along the way to me being able to merge this branch into trunk and put out a real release of 0.90 and then eventually 1.0!


Python wanderings, part two

2. Plugging it all in

Sometimes we get feature requests and merge proposals for features that are clearly useful for someone, but not appropriate for the general use cases. It's always unfortunate to have to say no to these folks, but we have a slim menu UI and I'm wary of cluttering it with niche features. Still, turning away legitimate users is something I don't like doing, so for a while we've been considering how to fix this. The obvious answer is that we should support plugins, and I've been working on such a system for my epic refactoring. This is a quick wander through some thoughts I've had. I started out by googling for python plugin systems; One if the top hits was this page by Armin Ronacher . In it he demonstrates a plugin system in under 40 lines of Python. It's simple and flexible, but there are some issues, like it makes doctest very sad. I asked about this in #python and was politely informed that I was Doing It Wrong. I chatted for a while with the helpful residents and came away with a list of plugin frameworks to look at, namely twisted.plugin and zope.interface. Pulling in external dependencies is a big deal for us - many of our users are on Ubuntu or similar desktops with lots of python packages already installed, but some are not using GNOME or a Linux desktop at all, so we have to be sure that we need a library before we depend on it. After playing a little with both of the options I came to the conclusion that while they are both really well made and capable, they are far more formal than we need, and the added dependency issues continued to concern me. I revisited Armin's plugin system and removed the use of .__subclasses__() that was breaking doctest and offending #python instead having a list in each .py file which the plugin system extracts and treats any classes mentioned in that list as plugins. I also extended it to always instantiate the plugins and look for the plugin files in both the system directories and the user's home directory. This plugin system is currently hooked into two places in the branch, URL mangling and the context menu. This allows plugins to add support for new URL types (e.g. we just added support for Launchpad code URLs like lp:~cmsj/+junk/terminator-epic-refactor), and insert new options into the context menu. I'm not sure if we need to go further, but if you would like to hook into other parts let me know - it's pretty easy to arrange now :)


Python wanderings, part one

As mentioned in my earlier post about refactoring Terminator, I want to talk about some of the things I've learned about Python and programming in the last few months. If I were you I wouldn't place any great significance in anything I'm about to say - after all I'm a rank amateur in the field of programming. This is going to be a multi-part post so I at least get something out there, rather than leaving it to rot forever in my drafts folder.

1. Solving global warming^W variables

I have objects that represent terminal widgets, objects that represent widgets that contain terminals, objects that contain configuration, and one master object that functions as the brains of the operation. Inevitably these objects need to know about each other, but how to achieve that? The brain object is simply called 'Terminator' and almost every other part of the system needs to know about it, same with the config object, and Terminator needs to know about all of the terminal objects, etc. The dependencies are all over the place and one aim of the re-factor was to separate all these parts out and decouple them, but ultimately I was never going to get away from different objects needing to know about each other. So how to go about it? As far as I know the options are: - pass around object references (every time you create something, pass it your references to all the bits it needs) - Pros: no hacks or tricks involved - Cons: makes every __init__() more complicated, means passing references that an object doesn't need other than to pass to its children.

  • use global variables

    • Pros: they're global
    • Cons: everyone seems to hate global variables, perhaps because it's an implicit dependency not an explicit one, or because of potential namespace collisions, or maybe other reasons.
  • use singletons

    • Pros: explicit dependency
    • Cons: often seems to involve hackery to get the singleton object reference

In my searching around I came across a fourth option that somewhat relates to singletons... the Borg pattern. This is a very simple idea - it's a class that always instantiates to the same thing. You don't need a factory or function or something that gives you a reference to the singleton, you just instantiate a class and it's the same as all of the others you've instantiated of the same class. Best of all, the Borg pattern is incredibly simple in Python. Like, really simple. Don't believe me? Click here. Yep, four lines of code. Technically it's probably a bit ugly, but the resulting code feels very clean. So now I have the Borg pattern in use for the main class, a class that provides all the configuration, a class that discovers plugins and lets them be referenced, and a fairly new class I'm experimenting with that acts as a factory for all of my classes, as a way to break any possibility of circular module dependencies. Reality has to bite though, the Borg isn't a panacea; One has to be very careful about how one creates Borg objects. I chose to create a base class called Borg which Terminator, Config, Factory and PluginRegistry all derive from, but this turns out to have been a very short sighted decision to abstract out the common 4 lines. It wasn't until I started building Config to have functions that allow it to be accessed as a dict that I realised all of my Terminator, Config, Factory and PluginRegistry instances were the same thing as opposed to each type being distinct. It's also terrifyingly important that the subclasses of Borg not use class attributes. Any attributes defined by these classes *must* be instantiated as None so they are instance variables, and *after* you've called Borg.__init__(self) in your own __init__() you can then set up your attributes however you want because they are then part of the shared state. On the whole I am happy with the Borg pattern. I've written test code to ensure that all of the assumptions I explicitly made are guaranteed, and all of the implicit assumptions I've discovered I made are also safe. Nonetheless, it's not a completely clean solution and I find myself wishing it was somehow a primitive of the language.


Random musical linkage

I listen to a lot of electronic music and one of the nice things about that is the intermingling of other music by way of samples. Case in point, I'm currently watching The Ballet Boyz's production of The Rite Of Spring with Rike, and I suddenly realised that the string motif playing at the entrance of The Elders is sampled and looped to great effect by the hypnotic Physical World on Freeland's album Now & Them. This kind of thing makes me smile :)


Epic Terminator refactoring afoot

The current bzr repository for Terminator began its life in November 2006 with the simplest possible implementation of the concept of packing multiple terminals into one window. In the 3 years since then we have expanded and extended the code in a variety of directions to produce a moderately compelling feature set, but one that is really obviously incomplete. In the same time period we've also seen a really gratifying amount of adoption - I believe our active userbase numbers in the thousands if not tens of thousands. I am forced to largely estimate these numbers for all the usual FOSS reasons, but it's all based on one real metric - Ubuntu has about a million users reporting popcon data and over 10,000 of those have Terminator installed. I don't actually think that they all use it, but nonetheless it's the kind of number that makes you think "hey maybe I need to be doing more for these folks". And I do think that, and I am trying to do more. Back in August I took a serious look at where we are and came to the same old conclusions - we lack one or two headline features that people keep asking for (barely a week goes by when I don't get asked how someone can save a particular layout of terminals). These features are very subtle and deeply problematic with the existing code architecture - we've just been hacking in features as we can without any regard for architecture or future maintainability. I decided that I'd had enough of being confused and frustrated by the status quo and so I started a side branch in my Launchpad /+junk/ folder called "epic-refactor" with the aim of refactoring all of Terminator from scratch. I'd read through every line of existing code and figure out what we were actually doing and how it could fit together more sensibly, then sketch that out in the barest form possible while I experimented with various Python techniques to arrive at an architecture that makes sense for our project, then port over the existing code feature-by-feature to the new architecture. It's now a little over four months since I started the epic refactor and looking at where I stand today I am really happy. It's not ready to be merged into trunk yet, but the amount of work to get it there is less than the amount of work I've done on it so far. I don't want to put a timescale on it, but I hope to be calling for some wider testing in 2-3 months or less. Once we are acceptably close to feature parity with the current releases I'll merge the epic-refactor branch over  and we can start to push forward with implementing the features that everyone wants, and finally get to the point of being able to comfortably release a 1.0 version. I'd always thought that I'd hand over maintainership after a 1.0 version, but the last 4 months have been a whirlwind of programming discovery, so I might very well just stick around and see what people want on the road to a 2.0 release. Alternatively, the work I've been doing in the last few days on a plugin system might mean that I can kick back and watch everyone else implement crazy, awesome and sublime features I'd never thought of! I'll be back with more when I have written a configuration subsystem for epic-refactor, because by then I'll be wanting your help to test! I'm also going to write a separate post shortly about some of the interesting Python paradigms and ideas I've hit upon along the way. I'm sure none of it will be a revelation to anyone with serious programming chops, but for a rank amateur like me it would have been useful to have read four months ago ;)


Terminator 0.14 released!

This has been another long gap release unfortunately, but we do have some goodies for you. Stephen Boddy is back with some excellent re-working of the UI relating to grouping terminals, Kees Cook brings us some clever work relating to window geometry and myself and others have been fixing bugs for you. We hope you enjoy this release, especially those of you who hated the "I'll be back" notifications from 0.13!

Home Page: http://www.tenshu.net/terminator Launchpad Page: http://launchpad.net/terminator Ubuntu PPAs: https://launchpad.net/~gnome-terminator/+archive/ppa


Rise of the Floating Fonters

For about two years now I've been using a 127dpi laptop screen as my primary computer display. It's a comfortable thing to be looking at, and after much playing around I've settled on 6.5pt as my ideal application font size. No problems with that, right? Fontconfig says font sizes are a double (a high precision floating point number), but not all libraries/applications follow this. In my testing of Karmic I've found two such things that particularly stick out:

  • notify-osd

    • Assumes font sizes are whole numbers, so ends up using a tiny font
  • Gwibber

    • Assumes font sizes are integers and completely fails to run if they are not

Obviously this won't do, so I've checked that we have filed bugs (and in the case of Gwibber, a patch), but I seem to be meeting some resistance, or this just isn't considered to be a high priority. Thus a new Launchpad team is born, The Floating Fonters, for exiles such as myself who won't kowtow to the integers. We even have a PPA with fixed versions of notify-osd and Gwibber, but no guarantees are included!


Thinkpad USB keyboard

Yesterday I took delivery of a new Thinkpad USB keyboard because I've started putting my laptop up on a stand to be next to it's external monitor. In so doing I needed a keyboard and the ten quid Logitech was making me very sad, hence the Thinkpad one. If you've ever typed on a thinkpad you immediately know why this keyboard is awesome :)

keyboard keyboard


I'm waving I'm waving

Do you wave? If so, apply some superposition to cmsjtenshu@googlewave.com