Flaky Goodness

Making Xcode more like Emacs

October 13, 2016

You might already know that macOS has great system-wide support for Emacs text editing shortcuts. And you might also know that you can customize that support to add your own custom shortcuts. In fact, there is a nice pre-built file of additional Emacs bindings compiled by Jacob Rus that I recommend.

Xcode ignores these customizations.

Luckily you can add your own similar customizations if you're willing to dig into the Xcode application bundle. Here's the file to edit:

/Applications/Xcode.app/Contents/Frameworks/IDEKit.framework/Resources/IDETextKeyBindingSet.plist

It gets replaced when you swap out your Xcode binary so be prepared to copy your modified version back in from time to time. Here's a snippet from mine, appearing directly under the </dict> closing the <key>Writing Direction</key> section.

<key>Custom</key> <dict> <key>Move to non-whitespace beginning of line</key> <string>moveToBeginningOfLine:, moveSubWordForward:, moveSubWordBackward:</string> <key>Delete current line in one hit</key> <string>moveToEndOfLine:, deleteToBeginningOfLine:, deleteToEndOfParagraph:</string> <key>Insert line above</key> <string>moveToBeginningOfLine:, insertNewline:, moveUp:</string> <key>Insert line after end of current line</key> <string>moveToEndOfLine:, insertNewline:</string> </dict>

When you restart Xcode you will find your custom commands available in Xcode > Preferences > Key Bindings > All. You can bind keyboard shortcuts here.

Bind keyboard shortcuts

Happily the keyboard bindings seem to persist through Xcode updates, so just copy your IDETextKeyBindingSet.plist file back in after updates and you should be good to go.

Limitations

It seems that the methods available to us for the definition of custom text editing shortcuts (like deleteToBeginningOfLine:) are all instance methods on NSResponder. So many of the more useful Emacs features (like Moving by Defuns) might be impossible to implement. If you can think of a way to do this, I'd appreciate hearing from you.