The keys that bind: KeyBinding Madness part 2

[Tweet : ADN : nvALT]

If you’ve poked around this blog at all, you know I dig System Services and TextExpander snippets more than is probably healthy. I have a new obsession, though, and it’s been taking up a lot of my playtime. Welcome to part two of (what is now) an ongoing series about Mac OS X Key Bindings. Originally inspired by Lauri Ranta, I’ve come to believe that system-wide keybindings for the Cocoa Text System are one of the most powerful tools available to any text nerd.

I’ve actually signed on to write the big picture up for Macworld, so I’m going just going to be sharing some of my favorites here and save the details for that post. For now, there’s an overview in my previous KeyBindings post. My fully-updated DefaultKeyBindings.dict file will be available at its GitHub page as soon as I finish commenting and documenting. In the meantime, here’s the first of my favorites…

Command-Option-Return

In some editors (nvALT, MultiMarkdown Composer, TextMate, Byword, et al), starting a Markdown list, entering a line and pressing return will give you another list item character and maintain indentation. It’s really nice when you’re outlining. This keybinding brings that joy to every other Cocoa text editor. It will find the list item delimiter (1., *, -, +) and duplicate it on the next line, with indentation intact. You can trigger it from anywhere on the line; it won’t break the line, just start a new item below. You can make one that does break the line and start a new list item with the part after the cursor, but this one is intended to work as is.

If you already have a ~/Library/KeyBindings/DefaultKeyBinding.dict file, just drop the code below into it. If not, create that file in a text editor and add a pair of curly brackets ({}), then paste this code between them.

// Command-Option-Return (Markdown list continuation)
"~@\U000D" = (  
    breakUndoCoalescing,
    moveToEndOfParagraph:,
    insertText:, "x",
    moveToBeginningOfParagraph:,
    selectWord:,
    moveRightAndModifySelection:,
    moveWordForwardAndModifySelection:,
    moveWordBackwardAndModifySelection:,
    moveLeftAndModifySelection:,
    setMark:,
    deleteToMark:,
    yank:,
    moveToEndOfParagraph:,
    deleteBackward:,
    insertNewlineIgnoringFieldEditor:,
    deleteToBeginningOfParagraph:,
    yank:,
    insertText:, " ",
    selectWord:,
    insertText:, " "
);

It’s spread out for readability, but you can remove the linebreaks and insert it all as one line if your DefaultKeyBindings.dict file is getting a little long.

Yes, there’s a reason for all of that jumping around. It looks like nonsense, but it takes advantage of the way that “move by word” (Option-left/right) works in OS X to kill double whitespace and find delimiters of varying lengths. It works pretty darn well. It’s not perfect, but it’s very, very handy. Imagine having solid Markdown editing tools in a text field in Safari. Yep, it works there.

Some of the extra movement in the keybinding is actually to allow my new bindings to work in the aforementioned editors that already have pairing, list continuation, etc. built in. By inserting and deleting extra spaces, I’m able (in most cases) to prevent triggering the default actions in the editor. I just wanted to be able to train my muscle memory for hotkeys as universally as possible. Note that Byword already has a shortcut on Command-Option-Enter, so if you want to use this there, you’ll need to add a new Application Shortcut for “Enable Paragraph Focus” in the Keyboard pane of System Preferences. I added the same shortcut again for “Disable Paragraph Focus” because the menu title changes, but I’m not sure that was necessary.

You’ll notice that for ordered lists it keeps repeating the same number. Markdown doesn’t care… a number is a number. If the first item at that level of indentation is a number, so are its following siblings. It turns it into an ol (ordered list) tag, and HTML handles the rest. Therefore, you don’t have to worry about numbers when you’re typing, sorting and editing your list1. However, for the sake of readability, it’s nice to have it come together in the end. I packaged up Fletcher Penney’s script from the TextMate Markdown bundle as a System Service you can run on a selected list to clean it up and fix the numbering. It turns this:

1. But they're all '1.'!
	1. Markdown reads any digit and orders everything after when it renders
		* To be fair, it just makes an `<ol>` and HTML handles the rest
	1. it does make readability harder
		* at the same time, it makes editing easier
			* you don't have to keep renumbering everything if:
				1. you change the order
				1. add new items out of sequence
1. this Service fixes it in post
	* Just select your list and run it.
	* you'll love it

into this:

1. But they're all '1.'!
	1. Markdown reads any digit and orders everything after when it renders
		* To be fair, it just makes an `<ol>` and HTML handles the rest
	2. it does make readability harder
		* at the same time, it makes editing easier
			* you don't have to keep renumbering everything if:
				1. you change the order
				2. add new items out of sequence
2. this Service fixes it in post
	* Just select your list and run it.
	* you'll love it

Download below and install.

Clean up Markdown Lists v1.0

A script by Fletcher Penney, originally for the TextMate MultiMarkdown bundle, packaged as a System Service. Cleans up and re-numbers Markdown lists.

Updated Wed Nov 09 2011.

DonateMore info…

  1. By the way, Byword does an amazing job with automatically ordering and re-ordering lists for you as you type. Try it.