Editing CoffeeScript with Sublime Text 2

I’ve been playing with CoffeeScript and IcedCoffeeScript lately, and I’ve been looking for a decent editor for them. Not as easy as you might think.

I wanted an editor that Just Worked. And by “Just Worked”, I mean the basics, of course, like syntax highlighting, multiple editor tabs, and all that other stuff you take for granted. But I also mean that the editor should have these two features:

  • Code folding. If I’m writing Mocha tests (and man, CoffeeScript is awesome for writing Mocha tests!), I want to be able to collapse describes that I’m not actively working on at the moment.
  • Smart indentation. If I type -> and press Enter, I want the editor to indent the next line for me. (This isn’t just laziness — it’s also a hint to me when I forget to type ->, which I still do fairly often.)

It’s kind of depressing how much those two features narrow the field. Here’s all I wound up with:

  • SciTE. It doesn’t actually support smart indentation or CoffeeScript syntax highlighting, but I’ve been using it for years, it’s comfortable, and if you lie and tell it it’s editing Python, then you get all the code folding you want. Plus, it’s free. Far from great, but it’s at least adequate.
  • Cloud9 IDE. Its smart indentation is great, but when I looked at it last, it didn’t support code folding. (They claim that it does now, though they give no details on whether/how it works with CoffeeScript, and I haven’t bothered to sign up for an account to try it out.) Freemium, and also Web-based, which is intriguing; I may give this another look at some point.
  • JetBrains IDEA-based IDEs (IntelliJ IDEA, PyCharm, WebStorm, etc.) Commercial, $49 and up. I had already bought a license for PyCharm, and then they released 2.0 and added support for CoffeeScript, and I was eligible for a free upgrade. Code folding and smart indentation are there, all right, but so are a boatload of bugs — I could never use it without finding four or five bugs at a sitting. I wrote them all up, they fixed some of them in the next update but introduced more. Repeat. And again. I finally got frustrated and gave up.
  • Sublime Text 2 (the subject of the rest of this post). Commercial, $59.

I was a little bit amused to find that, even though I’m only interested in Windows, everything on this short list is cross-platform: Windows, Linux, and Mac OSX.

ST2

I’ve been using the free trial of Sublime Text 2 for the past couple of months (it’s fully functional, it just shows the occasional nag screen when you save). And I’ve been loving it, and finally sprung for a license today. (Note: not a paid advertisement. Just a happy customer.)

ST2 (as the Sublime Text 2 users like to call it) seems to be in perpetual beta. New versions come out every now and then, but the documentation is far from complete and there are the occasional rough edges. But that’s easily made up for by the fact that it rocks. It’s fast, it’s beautiful, it’s crazy powerful.

Package Control

How powerful? ST2 has a built-in Python console for scripting the editor. Scripts and customizations can be bundled into add-on packages (it’s even mostly-compatible with TextMate bundles, i.e. packages designed for the Mac TextMate editor). Packages can add everything from syntax-highlighting rules for new languages, to entirely new editor commands, to who knows what else (Python scripting, remember?)

Here’s the really awesome thing: somebody wrote a free add-on package, called Package Control, that is a GUI package manager for ST2, that runs inside ST2. You install it by pasting a single line (okay, a long line) of code into the Python console, which downloads and installs Package Control for you. And forever after, installing a new package is a matter of opening Package Control via ST2’s menu, selecting “Install”, typing a keyword search into the incremental-search box, and selecting the package you want — which it then downloads and installs in a second or two, and the new package is instantly live and working. Crazy fantastic.

Fast, powerful

The editor is always snappy and responsive — it scrolls like the scrollbar is glued to the mouse. There’s a sidebar that shows a miniature version of your whole file; it updates fast and scrolls fast, and you can recognize the shape of your code even though it’s approximately a 1.5-point font. There are a few animations in the editor, but they never slow you down; they just make the editor feel even more responsive.

There’s also an optional sidebar on the left, that shows a list of open files (which duplicates the tab bar, but I like it). If you create a “project” (basically just a list of directories you want to work with, which can be as simple as “.” or can include filtering and multiple locations), then the sidebar also shows a directory tree, which is a feature I’ve always liked and seldom found.

(These sidebars are optional, of course. You can turn them off, along with the tab bar and the status bar and even the menu bar. You can run ST2 fullscreen with no window chrome at all, if you like — they even have a shortcut to get you there called “distraction-free mode”.)

Autocomplete is interesting. ST2 is not an IDE; it doesn’t parse your code and understand which classes have which methods. Instead, it keeps track of all the different words in the current source file, and when you start typing a word, it will try to complete from that list. It’s surprising how well this simple, non-context-sensitive completion can work, especially since it’s lightning-quick.

Keystrokes

ST2 has a way of making mundane features awesome. For example, if you press Ctrl+D (select word), it also highlights all the other usages of that same word in the file. And then if you press Ctrl+D again, it will add the next one to your selection (that’s right, ST2 supports disjoint selection). Keep pressing Ctrl+D until you’ve highlighted all the usages inside a method, and then start typing a replacement — and hello, Sync Edit.

(I keep trying to use Ctrl+W to select word, because that’s what it is in ReSharper at my day job. But of course Ctrl+W is Close File, just like in Web browsers and SciTE and most everything else except Visual Studio. At least, if I close a tab by mistake, I can use Ctrl+Shift+T to reopen it — hooray for features stolen from Web browsers!)

Then again, there are the keystrokes that are just different for the sake of being different. You can do rectangular selections, but you can’t use the usual Alt+Shift+arrow keys; you have to use Ctrl+Alt+Up/Down followed by Shift+Left/Right. And for some reason, Ctrl+Shift+S defaults to Save As, instead of the more familiar (and far more useful) Save All.

You can customize all the keystrokes (and a lot of other things, for that matter) by editing JSON config files. There are convenient menu items to open these config files for editing right there inside ST2.

CoffeeScript and beyond

ST2 doesn’t support CoffeeScript out of the box, but there are free CoffeeScript and IcedCoffeeScript packages. (The IcedCoffeeScript package is a simple superset of the CoffeeScript one, so if you want both languages, it’s enough to just install the Iced package.) The easiest way to install them, of course, is via Package Control. Code folding works beautifully, though ST2 hides the folding arrows by default (to reduce screen clutter) — if you just move the mouse over the gutter, the folding arrows will appear. The smart indentation works great too. With the Iced package, ST2 is a perfect fit what I set out to find.

I’ve also installed the Task package (via Package Control, naturally), which gives you syntax highlighting for a minimalist “task” pseudo-language that lets you use ST2 as a to-do list (but without all the stupid limitations that most task-list apps want to give you, like “must be a single flat list” — here you can easily create hierarchies, multiple lists, whatever). Task highlights lines starting with a hyphen (“-“) as “undone tasks” and lines starting with a check mark (““) as “done tasks”, and it adds an editor command to toggle a line between – and ✓. This add-on isn’t very polished, but it’s still pretty nice to have. Unfortunately it’s tightly coupled to the color scheme you’ve selected in ST2; by default, with the Monokai scheme I prefer, everything shows up as plain white. You have to edit the package to make it work with your theme (instructions included in the readme). (For reference: with Monokai, it works well to set Task Title to markup.inserted, Completed Tasks to comment, Action Items to support.function, and the rest to keyword.)

If you use the Task package on Windows, you’ll run into the problem that the Consolas font (which ST2 uses by default on Windows) doesn’t support the “CHECK MARK” Unicode character. This is easily fixed: download and install the “DejaVu Sans Mono” font (yes, it distinguishes between O and 0, 1 and I and l; and it’s also useful for seeing Mocha’s output properly on Windows) and then add "font_face": "DejaVu Sans Mono" to your user settings file (Preferences > Settings – User; the file is in JSON format).

Where IDEA could win

The IDEA-based editors (PyCharm, WebStorm, etc.) have a couple of things going for them compared to ST2: IDEA is much more aggressive about highlighting syntax errors and warnings as you type, and it has a feature that auto-formats your code (prettyprinting), either on demand, or as you type. Both would be awesome features if they worked reliably.

Unfortunately, both of those features have been major bug farms in the IDEA IDEs. They highlight “errors” in code that’s perfectly valid, they “reformat” code in ways that cause it to become non-compilable or that subtly change its meaning, etc. And of course, if CoffeeScript adds a new feature (I’ll bet do (x = 1, y = 2) ->, just added in CoffeeScript 1.3.1, is going to give them problems), then you have to submit an enhancement request and wait for them to add the feature and ship a new point release — which means you’re stuck with false-positive error highlighting for a good long while. ST2 packages are typically open-source, so can be a lot more agile.

I’m sure IDEA will be pretty awesome for CoffeeScript if JetBrains ever use it to dogfood some real CoffeeScript development of their own, and actually shake out some of the bugs before they ship (and add some actual regression tests, and everything else it would take to make it stable). But until that happens, if you’re easily frustrated, then don’t use IDEA for CoffeeScript.

So how about that extensibility?

I haven’t actually done much yet to extend ST2 on my own. The big hurdle here is that, by and large, you extend ST2 by writing TextMate packages, and I haven’t been able to find any documentation on how to write a TextMate package, beyond “open TextMate, tell it to create a new package, and use the GUI to specify all the options”. Since I don’t have a Mac, and since TextMate is Mac-only, that doesn’t help me much.

But hey. Even just using extensions other people have written, ST2 is just plain fun to use. I think it’s well worth the modest price.

AutoHotKey for quick Git access

I really like Git’s GUI tools: Git Gui for reviewing diffs and committing, and Gitk for dealing with branches. They’re powerful tools — powerful enough that I’m skeptical of any IDE that claims to include all that functionality in a little tool window.

So that means I do a lot of task switching between my IDE, Git Gui, and Gitk. And since I hate repetitive Alt+Tabbing, I’ve written an AutoHotKey script to make it easier.

AutoHotKey is an open-source tool that lets you bind scripts to various keys or key combinations on your keyboard. I’ve chosen these keybindings:

  • Numpad Minus: bring up the Git Gui window (or start it if it’s not already running), send F5 to refresh it, and put focus in the “description” box.
  • Numpad Plus: bring up the Gitk window (or start it if it’s not already running) and send F5 to refresh it. (Mnemonic: Gitk shows a tree, hence my choice of “+”)

I wrote a little AutoHotKey script and put it in version control at work, and several of the other devs started using it too. It’s almost disorienting when I’m at someone else’s computer and they don’t have it running.

Here’s the script. I suggest saving it as a GitHotKeys.ahk file somewhere inside your Git working copy; that way, if it needs to launch Git Gui or Gitk, they’ll automatically come up in the right repository.

; Copyright (c) 2011 Joe White
;
; Permission is hereby granted, free of charge, to any person obtaining
; a copy of this software and associated documentation files (the
; "Software"), to deal in the Software without restriction, including
; without limitation the rights to use, copy, modify, merge, publish,
; distribute, sublicense, and/or sell copies of the Software, and to
; permit persons to whom the Software is furnished to do so, subject to
; the following conditions:
;
; The above copyright notice and this permission notice shall be
; included in all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
; OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
; SOFTWARE.

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
SetTitleMatchMode, 1

NumpadSub::
IfWinNotExist, Git Gui
  Run, git gui,, Hide
WinActivate, Git Gui
IfWinActive, Git Gui
{
  ControlGetPos, control_x, control_y,,, TkChild18, Git Gui
  CoordMode, Mouse, Screen
  MouseGetPos, mouse_x, mouse_y
  click_x := control_x + 5
  click_y := control_y + 5
  CoordMode, Mouse, Relative
  Click %click_x%, %click_y%
  CoordMode, Mouse, Screen
  MouseMove, %mouse_x%, %mouse_y%, 0

  Send, {F5}
}
return

NumpadAdd::
IfWinNotExist, gitk
  Run, gitk
WinActivate, gitk
IfWinActive, gitk
  Send, {F5}
return

CoffeeScript’s for loops don’t work on strings (despite appearances to the contrary)

I’ve been playing around with CoffeeScript, and found myself needing to loop over the characters (and indexes) in a string. So I tried a simple CoffeeScript for loop:

for char, index in line
    # ...

I ran it, and it worked, even in IE, so I assumed that CoffeeScript was doing whatever magical syntax was required to make it work everywhere.

Later I found out I was wrong. CoffeeScript was generating the syntax that works with arrays — list[index] — and that syntax only happens to sometimes work with strings. It works consistently in Chrome, and FireFox, and Opera. It even works in IE… but only if you have an HTML5 doctype.

<!DOCTYPE html>
<script>
document.write('abc'[1]);
</script>

The above HTML page works fine in IE9, outputting b as expected. But if you remove the <!DOCTYPE html> line, IE outputs undefined instead. That’s right, it loads a completely different version of JavaScript depending on what version of HTML you’re using! And if you load the above page into a WPF Frame, even the doctype won’t save you — it always outputs undefined.

When I went back and looked through the CoffeeScript documentation, sure enough, nowhere do they actually say that for loops can be used to iterate through the characters in a string. The fact that it ever works is apparently an accident, so don’t rely on it.

If you need to loop over the characters in a string, the right thing is to loop over the indexes and use charAt: See update below

for index in [0...line.length]
    char = line.charAt index
    # ...

Edit: Here’s a better way, suggested by the kind CoffeeScript folks:

for char, index in str.split ''

Contributing to open source: uhttpsharp

I’ve been using open-source since at least my senior honors project in college, 15 years ago. I’m well overdue to give something back.*

Last night I made my very first commit to an open-source project: uhttpsharp, “a very lightweight & simple embedded http server for c#”. And I’ve added quite a bit of stuff in the day since that first commit — file serving, customizable index and error pages, keep-alive support. I’m thinking about adding NuGet support at some point.

If you need a simple HTTP server for .NET, and you don’t want to use HttpListener (e.g. because you don’t want to require admin permissions to register the URI prefix), go check it out.

* Actually, I’ve done plenty of open-source work before, if you count stuff that I wrote myself. And some of that stuff does count; I think a few people have found DGrok helpful. But I have a strong tendency toward not-invented-here syndrome… and this time I offered to contribute to an existing open-source project, that I heard about through posts on StackOverflow. So it’s not just me writing something by myself, which is cool.

Well, okay, I’m contributing to this project so I can use it in another project that I am writing by myself…

.NET and CoffeeScript: comparing Jurassic, Jint, and IronJS

Recently I went looking for ways to write a .NET desktop app that could compile CoffeeScript to JavaScript. There are already several NuGet packages for exactly this, but most of them look like they’re tightly bound to ASP.NET. So I struck out on my own, following the general steps in “CoffeeDemo – A Simple Demo of IronJS, using CoffeeScript”. The main CoffeeScript compiler is written in CoffeeScript, but they also provide one written in JavaScript, so my basic outline was:

  1. Instantiate a JavaScript engine.
  2. Tell the JavaScript engine to run coffee-script.js. This creates the CoffeeScript object and its compile method.
  3. Tell the JavaScript engine to call CoffeeScript.compile, and pass a string containing the CoffeeScript code to compile.

But my first attempt ran slower than I’d hoped for. (Well, coffee-script.js is 163 KB, and that’s the minified version! So I guess it does have a lot to do.)

I decided to find out whether I could do better: I tried several different JavaScript-in-.NET implementations, to see which one would perform the best. I tested Jurassic, Jint, and IronJS. My results are below, along with the C# code in case anyone is interested in seeing the minor differences between the APIs.

In all three cases, the coffeeCompiler parameter contains the 1.1.2 version of coffee-script.js, as downloaded from GitHub; and the input parameter contains a one-line CoffeeScript script:

alert "Hello world!"

Jurassic

Jurassic dynamically compiles JavaScript to CLR code at runtime, so you take a performance hit the first time you run some JS, but it should be pretty fast after that. Jurassic is available via NuGet.

private void CompileCoffeeScriptUsingJurassic(
    string coffeeCompiler, string input)
{
    Console.WriteLine("Jurassic");
    var stopwatch = Stopwatch.StartNew();
    Console.WriteLine(stopwatch.Elapsed + ": Creating engine");
    var engine = new ScriptEngine();
    Console.WriteLine(stopwatch.Elapsed + ": Parsing coffee-script.js");
    engine.Execute(coffeeCompiler);
    Console.WriteLine(stopwatch.Elapsed + ": Adding compile wrapper");
    engine.Execute("var compile = function (src) " +
        "{ return CoffeeScript.compile(src, { bare: true }); };");
    Console.WriteLine(stopwatch.Elapsed + ": Compiling CoffeeScript input");
    var output = engine.CallGlobalFunction("compile", input);
    Console.WriteLine(stopwatch.Elapsed + ": Done");
    Console.WriteLine("Output:");
    Console.WriteLine(output);
    Console.WriteLine();
}

Jint

Jint is a JavaScript interpreter. It’s not available through NuGet yet, but it’s a single DLL.

private void CompileCoffeeScriptUsingJint(
    string coffeeCompiler, string input)
{
    Console.WriteLine("Jint");
    var stopwatch = Stopwatch.StartNew();
    Console.WriteLine(stopwatch.Elapsed + ": Creating engine");
    var engine = new JintEngine();
    Console.WriteLine(stopwatch.Elapsed + ": Parsing coffee-script.js");
    engine.Run(coffeeCompiler);
    Console.WriteLine(stopwatch.Elapsed + ": Adding compile wrapper");
    engine.Run("var compile = function (src) " +
        "{ return CoffeeScript.compile(src, { bare: true }); };");
    Console.WriteLine(stopwatch.Elapsed + ": Compiling CoffeeScript input");
    object output = null;
    try
    {
        output = engine.CallFunction("compile", input);
    }
    catch (JsException ex)
    {
        Console.WriteLine("ERROR: " + ex.Value);
    }
    Console.WriteLine(stopwatch.Elapsed + ": Done");
    Console.WriteLine("Output:");
    Console.WriteLine(output);
    Console.WriteLine();
}

IronJS

IronJS is based on the DLR, so it seemed like it might strike a great balance between upfront compile time and runtime — after all, that’s what the DLR is all about.

IronJS is available through NuGet — there’s both an IronJS.Core (standalone) and an IronJS (depends on IronJS.Core), with nothing to explain the difference between the two; but at least for this code, you only need IronJS.Core.

private void CompileCoffeeScriptUsingIronJs(
    string coffeeCompiler, string input)
{
    Console.WriteLine("IronJS");
    var stopwatch = Stopwatch.StartNew();
    Console.WriteLine(stopwatch.Elapsed + ": Creating engine");
    var engine = new CSharp.Context();
    Console.WriteLine(stopwatch.Elapsed + ": Parsing coffee-script.js");
    engine.Execute(coffeeCompiler);
    Console.WriteLine(stopwatch.Elapsed + ": Adding compile wrapper");
    engine.Execute("var compile = function (src) " +
        "{ return CoffeeScript.compile(src, { bare: true }); };");
    Console.WriteLine(stopwatch.Elapsed + ": Fetching compile wrapper");
    var compile = engine.GetGlobalAs<FunctionObject>("compile");
    Console.WriteLine(stopwatch.Elapsed + ": Compiling CoffeeScript input");
    var result = compile.Call(engine.Globals, input);
    var output = IronJS.TypeConverter.ToString(result);
    Console.WriteLine(stopwatch.Elapsed + ": Done");
    Console.WriteLine("Output:");
    Console.WriteLine(output);
    Console.WriteLine();
}

The results

Jurassic
00:00:00.0000063: Creating engine
00:00:00.1540545: Parsing coffee-script.js
00:00:03.4346969: Adding compile wrapper
00:00:03.4408860: Compiling CoffeeScript input
00:00:05.3466983: Done
Output:
alert("Hello world!");

Jint
00:00:00.0000019: Creating engine
00:00:00.2617049: Parsing coffee-script.js
00:00:02.5270733: Adding compile wrapper
00:00:02.5295317: Compiling CoffeeScript input
ERROR: Parse error on line 2: Unexpected 'STRING'
00:00:02.5832895: Done
Output:


IronJS
00:00:00.0000019: Creating engine
00:00:00.2282421: Parsing coffee-script.js
00:00:55.5590620: Adding compile wrapper
00:00:55.5629230: Fetching compile wrapper
00:00:55.5642908: Compiling CoffeeScript input
00:01:17.8580574: Done
Output:
alert("Hello world!");

Jint wasn’t up to the task — it got a weird error when trying to call CoffeeScript.compile. I played with this a bit, and found that it would work if I passed an empty string, but give errors with non-blank CoffeeScript to compile; sometimes a string error like above, sometimes a weird error about multiline comments. It’s too bad, because Jint shows a lot of promise, speed-wise. I don’t know what the problem is; the error didn’t give me much to go on, and I’m not terribly motivated to pursue the problem when the other libraries work. (I did write this up in their bugtracker, though — it’s issue #6928.)

I was surprised that IronJS was so much slower than the others — about 20x slower than Jint at running coffee-script.js, and about 10x slower than Jurassic. This is especially puzzling since the article I based my code on mentions a “compilation lag”. To me, 55 seconds is hardly “lag”!

The winner here (and coincidentally the first one I tried) is Jurassic — so the performance that disappointed me is also the best I’m likely to get. On my laptop, you take about a 3.5-second penalty to compile coffee-script.js, and then another two seconds to run CoffeeScript.compile on a one-line script.

I did find that subsequent calls to CoffeeScript.compile were nearly instantaneous with all three libraries. So Jurassic’s 2 seconds is probably due to the JIT compiler running for the first time on that runtime-generated code. Not sure what to make of the 20 seconds for IronJS; is the DLR just that big?

Aptana, GPL, and the definition of “intact”

I’m looking at Python IDEs and decided to try Aptana, but their installer isn’t giving the best first impressions. First it did nothing but peg my CPU for half a minute or so, without so much as a splash screen. Then, when it finally showed some GUI, the very first screenful of text was downright incomprehensible:

Aptana License Agreement

No, there’s no horizontal scrollbar to explain why the beginnings of words are cut off.

What I love most is how that last line insists that this victim of random hack-and-slash copy/paste must be kept… “intact”.

If Reflector needed money so badly, why didn’t they ask?

Your copy of Reflector will self-destruct at the end of February… unless you pay the ransom.

This is depressing, not because of the money — I could easily pay $35 for a kick-ass tool like Reflector — but because of the betrayal of trust.

It’s not unlike the way Borland repeatedly betrayed their users’ trust with crap like “Inprise” and “Application Lifecycle Management”. (What’s left of Borland just got bought out. Good riddance.) Or the way Embarcadero priced me out of the Delphi market a couple of years ago. (They’ve since decided that was a bad move and started selling a starter edition. Some people learn from their mistakes, though sometimes too late.)

When RedGate bought Reflector, they said that they would continue to offer a free version. Now they admit that they lied. Well, actually, they don’t admit anything; they just repeatedly say that they never “promised” a free version. I guess that interview, and the “Red Gate will continue to offer the tool for free to the community” soundbite, were imaginary.

But wait! You can buy a version that will continue to work forever! Honest! They promise! Well, no, actually. If you search their open letter for the word “promise”, you’ll find it conspicuously absent.

I’ve been reading the reactions on StackOverflow, and even finally got a Twitter account so I could follow the news there. Some people say “suck it up, it’s worth it”. More people say “that’s not the point, RedGate has proven they can’t be trusted”. I lean toward the latter camp.

Then, across the Twitter feed comes a link to a YouTube interview with Simon Galbraith, one of the co-founders of RedGate, about the decision to charge for Reflector. Apart from again going on about the word “promise”, he explains something that should have been forefront of their announcement: keeping up with new frameworks and new platforms is a big deal. They want to make Reflector an even more awesome tool, and people haven’t been paying for Reflector Pro (our department actually did buy it, BTW) so they can’t bankroll what they want to do.

But instead of actually talking to the community about this, they kept it quiet. They “agonized” over it for about six months, and then decided that the right move was to break their word, antagonize the community, and try to extort the money, at the cost of their professional reputation.

They forgot two things that should have made this easy.

One, they forgot to ask. Wikipedia isn’t afraid to ask for donations, and they get them. NaNoWriMo isn’t afraid to ask for donations, and they get them. Granted, there are plenty of open-source projects with “Donate” buttons that probably never see a dime. But for a tool like Reflector, if they had said, “Hey, we want to do X and Y and Z to make this great tool even better, but we can’t do it without your help. We need to raise this many dollars to make it happen. Who’s with us?” I think people would have responded.

And two, empathy matters. Putting up a cold, faceless, impersonal warning icon that says “Screw you, we know we said we wouldn’t do this but we’re sticking it to you anyway” is not going to earn you many friends.

Compare that to: “We need your help. We want to keep up with new platforms and features, and we want to do more than keep up: we want to make an awesome tool even more awesome. But we can’t do it without you. We know you’ve always had Reflector for free — and we promise that won’t change — but if this tool is going to survive the changes Microsoft has in store and still get even better than it’s ever been, if this tool that’s satisfied your curiosity, and taught you loads, and, yes, saved your butt time and time again, is going to stay relevant, we need you. Think back over the questions you’ve answered with Reflector, the number of people you’ve recommended Reflector to, the times you’ve sworn you couldn’t do your job without Reflector, and then just tell us this: Can we count on your help?”

Sigh.

Okay, that’s enough of that. Off to check out Monoflector.

“Retail” comic gets its own site, full archive

For a while, my hometown’s local newspaper, the Cedar Rapids Gazette, carried a comic strip called “Retail”. I enjoyed the strip’s wry humor, even though I’ve never worked in retail. (I spent a few months as a checker in a grocery store, but that doesn’t compare to what happens in the strip.)

Earlier this year, the Gazette dropped “Retail”, which was very sad. (I only read the Gazette when I went back to visit family, but still, “Retail” was one of the high points of the comics page.) And here in Omaha, the World-Herald has never carried the strip. So I was psyched at the beginning of this year when Norm Feuti, the author, started posting daily “Retail” re-runs from 2006 on his personal site. It’s been in my Google Reader all year.

Now he’s announced that the “Retail” comic now has its own Web site, with unlimited archives. And yes, it has an RSS feed, so I can still get “Retail” in Google Reader — but now it’s today’s strip. Sweet!

From what I can tell, “Retail” is still syndicated in newspapers — it hasn’t made the jump to 100% webcomics. And I don’t see any way to buy dead-tree collections of the comics. (Not that I’ve ever bought a paper compilation of a webcomic… thought about it, never done it.) So for now, the strip is in an interesting state. But it’s an interesting state with full archives, so I’m happy.

If you haven’t read the comic, and enjoy dry humor, go check it out.

Interesting times

I keep thinking I should blog about events in my life, so I can look back later and say, “When did that happen?” Maybe nobody but me will care, but the past couple of weeks were interesting enough that I’m going to blog about them anyway.

First, there was the hailstorm a week ago Thursday. Jennie and I were watching TV when we heard a weird thump overhead. It sounded like somebody had thrown a baseball at our roof. Then another, and another. I looked outside and it looked like someone had been throwing snowballs at our driveway. I later heard that it had been “softball-sized” or “three-inch” hail. It only lasted about two minutes, but it was crazy.

My car had been parked in the driveway, and the next morning, I found that its back window was basically gone. Maybe a third of its area was still intact; the rest was just not there anymore. There were tiny shards of glass everywhere, including the front seat of the car. This is the old car; we didn’t have comprehensive insurance on it, so I had to pay to repair it. It also hasn’t been able to start since last November, so we had to get it towed to the shop (it was either that, or have it get rained in). On the plus side, they got it running again, and they fixed the air conditioner too.

Then we found out our house’s roof took a beating in the storm, and we may have to get the whole roof replaced.The adjuster hasn’t been out to look at it yet, so we don’t know for sure, but we’re saving up to pay the deductible if they do decide it needs replacing.

Tycho has barely been eating for a while now, even if we offer him wet food, so Jennie took him to the vet. He’s lost a full pound, which doesn’t seem like a good sign, and the vet took X-rays (these are our cats — we’ve learned to take X-rays and do bloodwork if anything seems even a little out of the ordinary) and she found that he had several teeth whose roots were splitting. Doesn’t that sound like fun? She said he didn’t need them extracted right away, and gave him some pain medication. When he got home, he snarfed as much food as we could put in front of him. Since then, he’s been back to eating a few mouthfuls at each meal, even though the pain medication was supposed to last three days and we’ve given him even more pain meds since then. We’ll probably need to do something more about this soon.

And yesterday, I got scratched in the face by another cat — one with all four sets of claws, and one who was in a stressful situation and obviously far, far more freaked out than I realized. Also in a position to use all four sets of claws on my face at once, because I was stupid. Pulled my glasses right off. Didn’t get my eyes, thank goodness, but my eyebrows, both cheekbones, a couple of deep gashes in my chin, even clipped one ear and the back of my head. I went to urgent care and got five stitches in my chin. I looked like Frankenstein’s monster for most of the weekend, with all the dried blood from all the scratches. The blue thread of the stitches makes the red cut look like this huge scary purple gash, but when you look closer it’s not as frightening as it looks from a distance. The doc gave me a tetanus shot and some antibiotics, just in case, so now I’ve got a sore arm and chills (aftereffects of the tetanus shot) and a sore face (Advil helps). But I’ll be fine. I’m not one of those lawyer-happy freaks who would sue or something stupid like that — sometimes shit just happens! The cat has been removed from the stressful situation and should also be fine; this was hugely out of character and there’s no reason to think it’ll happen again — just one of those freak things. And on the plus side, with this cut on my chin, I may well end up with a Harrison Ford scar.

Oh, and between the vet bill, the car-repair bill, and one or two other things, Jennie and I had to sit down and redo the budget last Friday. We were afraid we would have to empty our emergency fund. It turns out we didn’t have to touch it. We reallocated a bunch of stuff, put other things off for another month or two, and found over a thousand dollars in this month’s budget. We had to make a few tough calls, but man. This is why we budget.

So there’s definitely some good stuff to go with all the excitement. But still, I think I’ll go do something very uninteresting now.

Refactoring with MVVM is easy!

I’ve built up a kind of intellectual appreciation for some of the things MVVM gives you, but today I had a real “wow!” moment.

I’ve been working on a WPF UserControl, and it was getting kind of big and cumbersome. I wanted to extract some pieces from it into smaller UserControls to make it more manageable (and to make it easier to make some changes to the high-level layout).

So I created a new UserControl, moved my XAML into it, and referenced it from the original spot.

And that was it. I ran it, and it worked. That simple. No worries about moving dozens of code-behind methods onto the new control. No messing with method and field visibilities, and figuring out which objects the new control needed to have references to so it could do its work. No re-hooking event handlers.

Okay, it wasn’t quite cut-and-paste — there was some fixup to be done. The new UserControl needed some xmlns: attributes added. And I wanted the attached layout properties (Grid.Row, Grid.Column) to stay in the original file, not move into the new one (they’re part of the parent layout, not intrinsic to the child UI). So it took maybe a minute or so.

But it was nothing like the splitting headache that is extracting a UserControl in WinForms.

And then I extracted another UserControl. And I ran. And it just worked.

Wow.

Just, wow.

But the downside is, now I’ve got this overwhelming temptation to rewrite our million-line codebase in WPF…