enzu.ru
3 min readApr 21, 2020

--

Setting up Emacs as a modern Objective-C editor

Source: https://seeklogo.com/vector-logo/340070/objective-c

Your .emacs.d/ only requires a few software packages and custom Lisp functions to function as a modern Objective-C editor. These instructions are primarily aimed at people developing on GNUstep but could probably be adapted easily for an Apple macOS environment.

First and foremost, emacs-ccls provides IDE features such as code completion, code outlining, and integration into your text completion framework of choice such as company, ivy, or helm.

This technology is powered by the Language Server Protocol which provides these IDE features to text editors through a separate server process.

The setup is quick and easy:

(require 'lsp-mode)
(require 'ccls)
(setq ccls-executable "/var/lib/snapd/snap/bin/ccls")
(add-hook 'objc-mode-hook #'lsp)
  • Add a .ccls file to the root directory of your Objective-C project with your compiler settings such as the locations of header files. For clang on NEXTSPACE this looks like:
clang
-I/Developer/Headers
-I/usr/NextSpace/include
-fobjc-nonfragile-abi
-F/usr/NextSpace/Frameworks

Now the next time you open a file within that project, ccls will be activated.

To get started, I find the three most helpful functions are finding references, finding definitions, and finding documentation, so I bind those in Objective-C mode to three easy keystrokes: C-x C-d(ocumentation) , C-x C-r(eferences) , and C-x C-w(here is function defined) .

Unfortunately, these packages do not provide rich documentation for Cocoa, so I had to write a function called cocoa-open-documentation to open Apple’s documentation in a web browser when over a specific symbol.

(defun buffer-contains-substring (string)
(save-excursion
(save-match-data
(goto-char (point-min))
(search-forward string nil t))))
(defun cocoa-open-documentation ()
(interactive)
(let ((foundation-url (concat "https://developer.apple.com/documentation/foundation/" (downcase (thing-at-point 'word))))
(appkit-url (concat "https://developer.apple.com/documentation/appkit/" (downcase (thing-at-point 'word)))))
(let ((previous-buffer (current-buffer))
(web-result (url-retrieve-synchronously foundation-url)))
(switch-to-buffer web-result)
(if (buffer-contains-substring "404 Not Found")
(browse-url appkit-url)
(browse-url foundation-url))
(switch-to-buffer previous-buffer))))
(add-hook 'objc-mode-hook
(lambda ()
(local-set-key (kbd "C-x C-d") 'cocoa-open-documentation)
(local-set-key (kbd "C-x C-r") 'lsp-ui-peek-find-references)
(local-set-key (kbd "C-x C-w") 'lsp-ui-peek-find-definitions)))

One keybinding that is helpful and already exists is C-x c(ompile) for compiling and running a project. If you’re on macOS, you’ll have to write a shell script to do this for you, but for GNUstep the compile command just looks like make && openapp ./App.app .

With all that setup, you now have a pleasantly modern environment for writing Objective-C in.

Note: I am noticing Emacs.app on GNUstep is having trouble opening a web browser. I’ll hopefully submit a patch shortly.

My .emacs.d/ may be of further help and can be viewed here: https://github.com/enzuru/.emacs.d

--

--

enzu.ru

Learning content for the GNU operating system and Lisp user space, developed through my eponymous charity (https://enzu.ru)