New text navigation KeyBindings

[Tweet]

I haven’t had much time to write here this week thanks to some day job stress, major additions to Marked, writing for other venues, updating iTextEditors and various other fun. I had a brainstorm that resulted in new KeyBindings this morning, though, and thought it would be a good chance to get a post up before anyone thinks I’ve been kidnapped.

In case you’ve missed my past keybinding craziness, you can catch up on the evolution in the tag archive. Basically, OS X has a text system that lets you add custom commands and shortcuts that trigger sequences of the text commands you use every day (e.g. option-arrow word navigation, command-arrow to end of line, etc.).

My shorcut collection is pretty extensive (and beyond even my capability to memorize), but you can pick and choose what’s handy for you and create your own KeyBindings.dict file from it. The latest versions are always up on Github.

Paragraph navigation

The new bindings are primarily for paragraph navigation. One of the features I’ve come to love in several code editing applications is the ability to jump to the first character in the line (after any whitespace). So I added Command-Option-Left/Right Arrow navigation to do just that (and handle last character before trailing whitespace as well). I also added one that jumps to the first alphanumeric character in the line, which is great when working with Markdown lists. The unordered ones, at least, because numbers will stop the movement and it has the same result as jump to first character. This is bound to Control-Command-Option-Left Arrow. You can use them from anywhere in the paragraph, even if you’re at the beginning of a line and intuitively think that left arrow will move backward… with these commands it will always jump to the first character even if it’s in front of the cursor.

Jumping to the last character is cool, but in most of my work any whitespace after that shouldn’t be there. Even when I’m just writing Markdown, I don’t want any extra space triggering a hard line break accidentally. I added one more command to the set for this purpose: Control-Option-Right Arrow jumps to the last character and deletes any space following it. In a similar vein, I updated the Full Outdent command (Control-Shift-Command-Left Arrow) to use the same technique, no longer deleting the first character if the line was already fully outdented.

~/Library/KeyBindings/DefaultKeyBinding.dict code for all of the above:

// Move to first Alphanumeric character of line (new)
  "@~^\UF702" = (moveToBeginningOfParagraph:,moveWordRight:, moveWordLeft:);
// Move to first non-whitespace character of line (new)
"@~\UF702" = (moveToBeginningOfParagraph:, insertText:, " ", moveLeft:, selectWord:, moveRight:, setMark:, moveToBeginningOfParagraph:, deleteForward:, swapWithMark:, moveLeft:);
// Select to first character of line with leading space (new)
"@~$\UF702" = (setMark:,moveToBeginningOfParagraph:,selectWord:, moveRight:, selectToMark:);
// Move to last non-whitespace character of paragraph (new)
"~@\UF703" = (moveToEndOfParagraph:, insertText:, " ", selectWord:, moveLeft:, setMark:, moveToEndOfParagraph:, deleteBackward:, swapWithMark:);
// Move to end of paragraph and delete trailing whitespace (new)
"^~\UF703" = (moveToEndOfParagraph:, insertText:, " ", selectWord:, deleteBackward:);

Markdown line breaks

Lastly, this somehow inspired me to add a couple of linebreak commands. In Markdown, adding two spaces at the end of a line causes it to be interpreted as a hard break instead of just concatenating the next line to it in a paragraph. I bound Control-Option-Return to add these spaces to the end of the current line–regardless of cursor position–and begin a new line.

The other line break command (Control-Command-Return) is Markdown again, this time adding two spaces and starting a new paragraph from the cursor position; basically just a way to add a quick hard line break in the middle of a paragraph. This binding conflicts with the Line Focus shortcut in Byword1, by the way, so if I get used to using it I’ll either change the binding in Byword (I never use line focus) or update my own bindings. Feel free to change it to whatever is intuitive to you, keeping in mind that control-enter and shift-enter may already be bound to behaviors in the Cocoa application you’re working in.

Here’s the code for these:

// Add hard break for current line and insert newline below (new)
"^~\U000D" = (moveToEndOfParagraph:, insertText:, " ", selectWord:, deleteBackward:, insertText:, "  ", insertNewline:);
// Break line at cursor and add Markdown hard line break (new)
"^@\U000D" = (insertText:, "  ", insertNewline:);

Cheatsheet

In addition to the readme.md file in the repo, I’ve updated the Cheaters cheat sheet for the KeyBindings (because I regularly lose track of the shortcuts for lesser-used bindings). The new sheet is available as a gist or you can just right-click and download the raw file. If you have a default install of Cheaters, you can just overwrite the old keybindings.html file with this one. The new keybindings are marked with “(new)” in green, which is mostly for my own good in locating them quickly2.

Grab the whole thing from the KeyBindings repo on Github.

I know, I’m a little crazy.

  1. Command-Enter–my TextMate-style binding for starting a new paragraph from anywhere within a line without breaking it–also conflicts with the full-screen keyboard shortcut. I overrode that one in Byword using System Preferences->Keyboard->Applications, but I also include Option-O and Option-Shift-O (Vim-like) in the default file for this reason.

  2. I really want to add an in-page search to Cheaters. It would greatly improve its usefulness for me if I could just quickly type any part of what I’m looking for and jump to the info. I’ll work on that soon, I think.