Emacs for Xcode+ios Development

|

Setup Emacs for XCode+iOS development

The current document has been written after being tested on Emacs 24 with XCode 4.4 and iOS SDK 5.1 with Mac OS X Mountain Lion. All github repositories have been forked for modifications and also so that this document remains valid even after they have changed, but the credits go to the respective authors.

For building from command line you have to use xcodebuild. You can get info about that and other tools from the Apple developer documentation. So it has not been discussed here. Also for any command line implementations run the Emacs shell by pressing Ctrl-x m or run a shell using M-x shell.

Emacs as a development tool is excellent. The abstract and global approach of Emacs towards programming languages, has helped me to finally setup up Objective-C for iOS inside it, in such a way, that I am free to ditch XCode. Except perhaps some mundane tasks like file additions, etc. which Apple is so clumsy to provide to developers from the command line.

Moving on, Emacs already provides an objc-mode. But its very limited in its functionality. You will need much more than just objc-mode to get near the XCode functionalities. I tried implementing some of them and here’s the things which I have suceeded to implement so far:

Automatic iOS Framework method implementations using YASnippet and auto-complete in Emacs

YASnippet

YASnippet is a template system for Emacs. It allows you to type an abbreviation and automatically expand it into function templates. Now for iOS/Obj-C we have functions like

1
- (void) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

Memorizing such functions is a pain, and almost never really works out. With YASnippet you can just start typing and a choice of possible function templates are presented to you.

To do this you need to have yasobjc.rb. Get this from https://github.com/roupam/yasobjc

Then run the yasobjc.rb script as:

1
$ find /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks -name "*.h" | xargs ./yasobjc.rb -o ~/.emacs.d/elpa/yasnippet-0.6.1/snippets/text-mode/cc-mode/objc-mode/

A really long command, let me abbreviate that:

1
$ find IPHONE_SDK_FRAMEWORKS_DIR -name "*.h" | xargs ./yasobjc.rb -o YASNIPPETS_SNIPPETS_DIR/text-mode/cc-mode/objc-mode/
Basically this reads the iOS Framework header files, makes the function templates and puts them into your YASnippets directory.

Here’s a sample yasnippet config for the Emacs init file Change the parameters according to your emacs installation of YASnippets.

1
2
3
4
5
6
7
8
9
;; yasnippet
(add-to-list 'load-path "~/.emacs.d/elpa/yasnippet-0.6.1")
(require 'yasnippet)
(setq yas/trigger-key (kbd "C-c <kp-multiply>"))
(yas/initialize)

;; This is where your snippets will lie.
(setq yas/root-directory '("~/.emacs.d/elpa/yasnippet-0.6.1/snippets"))
(mapc 'yas/load-directory yas/root-directory)

Auto-complete

Auto-complete is a very very useful functionality in Emacs and there’s a ton of discussion of it on the web, so I won’t discuss how to set it up right here. I’ll just post my config here. Note the yasnippet mentioned in the auto-complete config.

1
2
3
4
5
6
7
8
9
10
11
12
13
;; auto-complete
(add-to-list 'load-path "~/.emacs.d/elpa/auto-complete-1.4.20110207")
(require 'auto-complete-config)
(add-to-list 'ac-dictionary-directories "~/.emacs.d/elpa/auto-complete-1.4.20110207/dict")

(setq-default ac-sources '(ac-source-yasnippet ac-source-abbrev ac-source-dictionary ac-source-words-in-same-mode-buffers))
(add-hook 'emacs-lisp-mode-hook 'ac-emacs-lisp-mode-setup)
(add-hook 'c-mode-common-hook 'ac-cc-mode-setup)
(add-hook 'ruby-mode-hook 'ac-ruby-mode-setup)
(add-hook 'css-mode-hook 'ac-css-mode-setup)
(add-hook 'auto-complete-mode-hook 'ac-common-setup)
(global-auto-complete-mode t)
(add-to-list 'ac-modes 'objc-mode)

Here’s a sample screenshot showing webView methods using YASnippet and auto-complete

XCode pragma marks in Emacs

Pragma marks are XCode’s way of browsing through large Objective-C source code files, showing the functionality of a set of methods.

For example check this screenshot:

It shows a set of methods associated with TextView, another set with TableView and so on, and the methods themselves. This is very convenient, if you are trying to read and understand the code.

Here’s my Emacs config for setting up pragma-marks:

1
2
3
4
5
6
7
8
9
10
11
12
13
(require 'anything)
(require 'anything-config)

(defvar anything-c-source-objc-headline
  '((name . "Objective-C Headline")
    (headline  "^[-+@]\\|^#pragma mark")))

(defun objc-headline ()
  (interactive)
  ;; Set to 500 so it is displayed even if all methods are not narrowed down.
  (let ((anything-candidate-number-limit 500))
    (anything-other-buffer '(anything-c-source-objc-headline)
                           "*ObjC Headline*")))

And I have bound the function to the key Ctrl-x p

1
(global-set-key "\C-xp" 'objc-headline)

So whenever I am editing a source code file and I press Ctrl-x p here’s what I see in a separate buffer:

Selecting a method and pressing enter takes you to that particular method.

Source code browsing and viewing Framework definitions using etags

ETAGS or Emacs Tags is a facility for recording names and their definitions and later looking up the definitions. Here’s how to record the names and definitions of any project that your are using. You should have a binary called etags in your Mac OS X installation. Go to the root of your project directory and do.

1
2
$ find . -name '*.[hm]' | xargs etags
$ find IPHONE_SDK_FRAMEWORKS_DIR -name '*.[h]' | xargs etags -a

This will generate a TAGS file in that directory. Visit that file using M-x visit-tags-table and it’s done.

Now you can browse through class definitions and your source code functions. Just go to a class name in your source code like say NSUserDefaults, and press M-. and you will be presented with the complete class definition, methods, etc. that can be found in the Framework headers.

Press M-* to go back to where you were before.

Check out more about Emacs TAGS here http://emacswiki.org/emacs/EmacsTags

XCode documentation search and viewing inside Emacs

If you have w3m installed for use from within your Emacs, then you can view and search XCode docsets. There’s nifty little tool that you can get from here https://github.com/roupam/emacs-xcode-document-viewer

1
2
3
(require 'xcode-document-viewer)
(setq xcdoc:document-path "/Users/rpg/Library/Developer/Shared/Documentation/DocSets/com.apple.adc.documentation.AppleiOS5_1.iOSLibrary.docset")
(setq xcdoc:open-w3m-other-buffer t)

You will also need to modify the xcode-document-viewer.el and point to the right docsetutil command

1
2
3
4
(defun xcdoc:docsetutil-command ()
  (or (executable-find "docsetutil")
      (and (file-executable-p "/Applications/Xcode.app/Contents/Developer/usr/bin/docsetutil") "/Applications/Xcode.app/Contents/Developer/usr/bin/docsetutil")
      (error "docsetutil command is not found. Perhaps you dont have Xcode man.")))

To search you can just do M-x xcdoc:search. For example a search on NSString leads to this.

Debugging on Simulator and on Devices

Get fruitstrap from here https://github.com/roupam/fruitstrap

Clone this git://github.com/roupam/fruitstrap.git Get into the cloned directory and do

1
make fruitstrap
Put the generated fruitstrap binary in any suitable path

Get the Mac OS X 10.8 version with XCode 4.4 support from here https://github.com/phonegap/ios-sim After building just make the executable aviablable in your path

Open an Emacs shell. Press Ctrl-x m To run on device go to your project root and do

1
2
$ xcodebuild -sdk iphoneos build
$ fruitstrap -d -b QNote/build/Release-iphoneos/YOUR_APP.app
To run on simulator likewise do
1
2
$ xcodebuild -sdk iphonesimulator5.1 build
$ ios-sim launch build/Release-iphonesimulator/YOUR_APP.app --sdk 5.1

Xcode project management from the command line

There’s a tool called xcs, but somewhat limited in its functionality, but still gets the job done. But still I think its an awesome piece of code, considering the fact that Apple is clumsy when it comes to developer support outside of Xcode.

You can get xcs from here https://github.com/gonzoua/xcs

Switching between header (.h) and source (.m) files

Add this to you emacs init file if you would like to jump quickly between .h and .m files. Use Ctrl-C t

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
;; --- Obj-C switch between header and source ---

(defun objc-in-header-file ()
  (let* ((filename (buffer-file-name))
         (extension (car (last (split-string filename "\\.")))))
    (string= "h" extension)))

(defun objc-jump-to-extension (extension)
  (let* ((filename (buffer-file-name))
         (file-components (append (butlast (split-string filename
                                                         "\\."))
                                  (list extension))))
    (find-file (mapconcat 'identity file-components "."))))

;;; Assumes that Header and Source file are in same directory
(defun objc-jump-between-header-source ()
  (interactive)
  (if (objc-in-header-file)
      (objc-jump-to-extension "m")
    (objc-jump-to-extension "h")))

(defun objc-mode-customizations ()
  (define-key objc-mode-map (kbd "C-c t") 'objc-jump-between-header-source))

(add-hook 'objc-mode-hook 'objc-mode-customizations)

Thanks to Kiran Kulkarni for this switching code.

Hope you enjoyed this post, and believe me Emacs is more than you could expect, much much more.

Please feel free to email me at roupam dot ghosh at gmail dot com.

That’s all folks.