Emacs and Unity Every Day
Originally published here.
As I may have mentioned before, I like using Emacs. When working on Fable we were of course entirely based around the glorious Visual Studio, since the XBox and the 360 required it, and I started out using Emacs largely for editing Python and Lua code; we used those languages for various tools and scripting duties and Visual Studio at the time didn't have very good support for 'other' languages. Gradually I drifted into using org-mode, then into eshell, and eventually I got to the point where I started missing certain features in other editors. Yes, even the glorious Visual Studio.
These days I'm working on a Mac, using Unity. I tried to use MonoDevelop but found it to be slow and clunky, and not being able to view two files at the same time was very frustrating. Eventually I switched entirely over to using Emacs. It wasn't easy at first, and I still lament the lack of a decent autocompletion system, but in general I'm very happy with the workflow.
You don't spend numerous years using Emacs without picking up a few customisations and I thought it would be worth documenting a few of the ones I use most often. If anyone finds it useful, I might dip further into the recesses of my dotemacs file.
So, here we go; Emacs things that I use every day.
Evil mode evil-mode is a fabulous vi emulation layer in Emacs. I'm pretty new to it, and I originally turned to it in a last ditch attempt to cope with some RSI issues I'd been developing (at this point I have probably bought pretty much every ergonomic keyboard in existence). I'm not sure if it helps the RSI, but it has certainly helped my coding speed. A side benefit is that, while Emacs is incredibly flexible, it's very easy to run out of keybindings for all your custom functionality. Evil-mode and it's modal system largely makes that problem go away.
Ace jump Inspired, I believe, by a vim plugin called from Easy Motion, ace-jump allows you to jump to any character on screen in (usually) 3 keypresses. It's a little difficult to explain how, so I'll skip straight to a demo of it in action. I hit space (my personal activation key in evil-mode), select a character to jump to (in this case 'p'). Ace-jump highlights every 'p' there is and gives it a unique letter. I choose the one I want (in this case 'n') the character jumps to the correct location.
In that particular example, I'm jumping to any character on the screen which can create alot of hits, but there are other ways to call it which only highlight characters at the beginning of words.
It's looks a bit mental at first, but once you've used it there's no going back.
Mark Multiple Another toughie to describe in text, mark-multiple allows you to select a section of text and then select further matching sections and edit them all simultaneously. If you've ever used Sublime Text you'll be familiar with it. Here's an example:
Here I hit v to select the terminating semi-colon, M-j to select further semicolons below, c to change the selection, and then type in the new code. There are other ways to achieve the same thing, of course, but mark-multiple is nice and tactile.
Helm
This used to be called 'Anything', and it's essentially a generic quick jump system for Emacs, and it's easily extended. For example, I have a simple custom project management system to allow me to easily compile projects, select which files go into a tags file, etc, and I use Helm to select files anywhere in my project, regardless of whether or not they are already open. Again, a simple example should suffice:
In this I hit C-x f to trigger the helm file finder, and type in part of the file I'm looking for. It shows files in my project, recently accessed files, open buffers; once I've narrowed down the selection enough I can then select using the cursor keys and hit enter to select the file.
Yasnippet Alot of coding is repetitive stuff, and TextMate's 'snippets' innovation was a great way of tackling some of the more tedious bits. The canonical Emacs implementation yasnippet expands on that, allowing you to create some very sophisticated code templates. Previously I've struggled to get it in my workflow - remembering the exact trigger phrase for an expansion never worked for me, and autocompletion often got in the way. I've recently discovered that you can trigger a snippet manually, however, and then use fuzzy-matching via ido to choose the right snippet. Example below:
In this example I'm hitting C-c s to trigger yasnippet, typing 'fore' to find the foreach expansion and hitting enter - it creates the skeleton and then I tab through the editable sections, filling them in as I go, with the last tab placing me in the braces. When you're spending all day writing classes with conditions and loops and methods, this can be a big time saver.
Flymake Something you may have noticed in one or two of the examples above is that I get syntax errors highlighted on the fly. This is the magic of flymake, which continually compiles the project in the background. I've got it hooked up with and a script to compile the Unity project, and it makes for a very smooth Unity coding experience. Errors underline in red as you type, the error message shows up in the minibuffer when you move the cursor into position, and it disappears when you fix it. Hardly revolutionary, but a nice productivity boost. It also seems to catch more genuine issues than the 'on-the-fly' error checker built into MonoDevelop, which is nice.
Shaderlab mode Shaderlab-mode is a custom mode for editing shaders for Unity. It's relatively basic, but it handles syntax colouring and indentation, which is all I really care about.
Wrapping it up The upshot of this is that I spend 90% of my day in Emacs - from the start of the day when I check my todo.org list of tasks, to the edit-compile cycle for csharp, to editing shaders; I rarely leave Emacs, and when I do it's usually just to tab on over to Unity to test out my changes.
I believe all of these extensions are available via ELPA, in marmalade or milkbox. Regardless, pulling it all together can take a little time, so I thought it might be worth sharing the details of how that's done in my config. I've cobbled alot of this from various places on the intermawebs, notably here and here.
(require 'evil)
;;This gives you all the normal Emacs editing commands when in insert-mode
;;This eases the transition somewhat.
(setcdr evil-insert-state-map nil)
(define-key evil-insert-state-map (read-kbd-macro evil-toggle-key) 'evil-emacs-state)
(define-key evil-insert-state-map \[escape\] 'evil-normal-state)
;;Not sure why, but semicolon started misbehaving for me when in insert mode.
(define-key evil-insert-state-map (kbd ";") 'self-insert-command)
;;Make evil-mode up/down operate in screen lines instead of logical lines
(define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line)
(define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line)
;;Exit insert mode by pressing j and then k quickly
(setq key-chord-two-keys-delay 0.2)
(key-chord-define evil-insert-state-map "jk" 'evil-normal-state)
(key-chord-mode 1)
;;If you work in camelCase or use underscored\_names, this is very helpful
(evil-define-motion evil-little-word (count)
:type exclusive
(let ((case-fold-search nil))
(forward-char)
(search-forward-regexp "\[\_A-Z\]\\\\|\\\\W" nil t)
(backward-char)))
(evil-define-motion evil-little-word-backward (count)
:type exclusive
(let ((case-fold-search nil))
(backward-char) (search-backward-regexp "\[\_A-Z\]\\\\|\\\\W" nil t)))
(define-key evil-normal-state-map (kbd ", b") 'evil-little-word-backward)
(define-key evil-normal-state-map (kbd ", w") 'evil-little-word)
(define-key evil-operator-state-map (kbd ", w") 'evil-little-word)
(define-key evil-operator-state-map (kbd ", b") 'evil-little-word-backward)
;;Not sure why this isn't the default - it is in vim - but this makes C-u to go up half a page (define-key evil-normal-state-map (kbd "C-u") 'evil-scroll-up)
;;Allow quick manual triggering of snippets
(define-key evil-normal-state-map (kbd "C-c s") 'yas-insert-snippet)
(define-key evil-insert-state-map (kbd "C-c s") 'yas-insert-snippet)
;;Toggle comments
(define-key evil-visual-state-map (kbd ", c") 'whole-line-or-region-comment-dwim)
(define-key evil-normal-state-map (kbd ", c") 'whole-line-or-region-comment-dwim)
;;Easy access to the mark multiple library when in visual-mode
(define-key evil-visual-state-map (kbd "M-j") 'mark-next-like-this)
(define-key evil-visual-state-map (kbd "M-k") 'mark-previous-like-this)
;;Ace jump stuff. Honestly, I just use Space 99% of the time
(define-key evil-normal-state-map (kbd "SPC") 'ace-jump-char-mode)
(define-key evil-normal-state-map (kbd ", , w") 'ace-jump-word-mode)
(define-key evil-normal-state-map (kbd ", , c") 'ace-jump-char-mode)
(define-key evil-normal-state-map (kbd ", , l") 'ace-jump-line-mode)
(define-key evil-operator-state-map (kbd ", , c") 'ace-jump-char-mode)
(define-key evil-operator-state-map (kbd ", , l") 'ace-jump-line-mode)
;;Personally I like ace-jump to be limited to the window I'm working in
(setq ace-jump-mode-scope 'window)
;; Remap org-mode meta keys for convenience
(mapcar
(lambda (state) (evil-declare-key state org-mode-map
(kbd "M-l") 'org-metaright
(kbd "M-h") 'org-metaleft
(kbd "M-k") 'org-metaup
(kbd "M-j") 'org-metadown
(kbd "M-L") 'org-shiftmetaright
(kbd "M-H") 'org-shiftmetaleft
(kbd "M-K") 'org-shiftmetaup
(kbd "M-J") 'org-shiftmetadown))
'(normal insert))
(evil-mode)
Most of that should be self explanatory with the comments. One thing to mention is that this makes use of the excellent keychord.el and comment-dwim both also available via ELPA repository. Keychord allows you to combine arbitrary keypresses into triggers, and it's what allows the 'jk' trick above. There's lots of other stuff I use too - org, nav, bm, window-number, winner - and lots of personal customisations, but I'll leave those for another day.
The main thing I really miss is proper 'correct' autocompletion for C#, which Visual Studio spoiled me with for years. Someone has created a plugin for Sublime, called CompleteSharp, which uses a standalone commandline program to load up your assemblies and provide completion information, and I'm sorely tempted to write some Emacs hooks for it. If only I had the time...