Good with Computers

The Sixty North Blog

Writing the Simplest Emacs company-mode Backend

In Emacs, company-mode (short for “complete anything”) is a framework for performing completion in buffers.1 It’s an alternative to the popular auto-complete-mode. company-mode supports extension via backends which provide the framework with lists of possible completions in various contexts. So, for example, there’s a backend that provides completion support for Emacs lisp and one that does the same for Python. Backends can use very different technologies as long as they conform to the backend interface specified by the mode.

I recently decided to write a company-mode backend for ycmd, a completion server for languages including C/C++/Objective-C and Python.2 All in all it was a relatively pain-free experience, but the process isn’t as well documented as I would have liked. So I want to use this series to describe how it’s done with the hope of making it easier for others and of helping me remember how to do it in the future.

I won’t be covering all of the details of company-mode backends (partially because I don’t know them all), but this series should tell you what you need to know to create your own fully-armed and operational backend.3 In this article we’ll define the simplest possible backend in order to familiarize you with the concepts and infrastructure involved. In the next article we’ll add some sophistication to that backend to improve the user experience.

The simplest possible backend

For our example we need to define a source of completion candidates. Ultimately, any completion source is just a sequence of strings that meet some criteria. Examples might include:

  • A list of English words starting with some prefix
  • Methods for a particular object in Java
  • Modules available for import in Python program

company-mode doesn’t care about the nature of these strings. It just takes them and makes it easy for the user to select from the available options.

In this case, we’ll just define a fixed list of strings:

(defconst sample-completions
    '("alan" "john" "ada" "don"))

That’s it.4 Completion sources don’t need to (though they generally will) be more complex than that.

Defining the backend

Backends take the form of a function which takes a command as its first argument. This command can take any of a number of values, and backends are required to respond to a handful of them. Before we get into those details, let’s look at our very basic backend implementation:

 1 (require 'cl-lib)
 2 (require 'company)
 3 
 4 (defun company-sample-backend (command &optional arg &rest ignored)
 5   (interactive (list 'interactive))
 6 
 7   (cl-case command
 8     (interactive (company-begin-backend 'company-sample-backend))
 9     (prefix (and (eq major-mode 'fundamental-mode)
10                  (company-grab-symbol)))
11     (candidates
12      (cl-remove-if-not
13       (lambda (c) (string-prefix-p arg c))
14       sample-completions))))

The signature of this function is mandated by company-mode. Line 5 makes the function interactive so that you can easily drive your backend without invoking company-mode, something we’ll do in a bit. The cl-case statement on line 7 is where we decide what to do based on command. In this case, we respond to interactive, prefix, and candidates.

The interactive command is passed once, before the other commands are used, and it is used to initialize the company-mode infrastructure. All you need to do as a backend developer is pass your backend to company-begin-backend as in this example.

The prefix command

The prefix command is probably the most complex command to handle. This command should return the text that is to be completed. Determining this text can be complex depending on what you’re trying to complete, but company-grab-symbol often does “the right thing” if your completion context is space-delimited.

If the prefix command returns nil, this tells company-mode that the backend is not suitable for doing completion on this context. On line 9 of our example we check to see if we’re in fundamental-mode and, if not, return nil. In other words, we’re saying here that our backend only applies to fundamental-mode. Programming language-oriented backends can make a similar check for their specific modes. When a backend responds to prefix with nil, other backends are given a chance to do the completion.

On the other hand, if a backend is appropriate for the current completion but it can’t provide any completions for some reason, the backend should return 'stop. This tells company-mode that no other backends should be used for this completion.

So our backend is effectively saying that it can do completion for anything in fundamental mode. There are more details to prefix, but that’s covers the important parts.

The candidates commands

The response to the candidates command is where you actually generate a list of possible completions at a point in a buffer. When this command is passed in, the arg argument holds the value returned by prefix. In other words, you construct your candidates based on the text that you previously indicated was to be completed.

In our case, the prefix we indicated was whatever came before point in the buffer. To calculate our possible completions, we filter the sample-completions values with that prefix using remove-if-not, returning only those candidates which begin with the prefix.

As with prefix calculations, real candidate calculations can be much more complex. But if you understand how the data is piped around, then constructing these complex candidate lists should be fairly straightforward.

Test-driving the backend

To test out our backend, first enter all of the code into a buffer and evaluate it (e.g. with M-x eval-buffer.) Then create a new buffer and run M-x fundamental-mode and M-x company-mode.5

In this new buffer enter the single character “a” and then, with the cursor immediately after the “a”, run M-x company-sample-backend. This should give you completion options something like this:
Screen Shot 2014-08-28 at 7.17.11 PM

If that works correctly, then you’ve done almost everything you need to for a fully working backend.

Plugging the backend into company-mode

The final thing you need to do to make your backend available to company-mode is to add it the list company-backends. One simple way to do that is with add-to-list list this:

(add-to-list 'company-backends 'company-sample-backend)

Once you’ve done this, you can use the command company-complete to do completions, and your new backend will be used in concert with all of the other backends in that list. Generally speaking, company-complete is the command you’ll use for completion with company-mode, and it’ll often be bound to a simple keystroke.

A complete company-mode backend

That’s all there is to writing a basic company-mode backend. In the next article in this series we’ll look at adding a few more details to what we have already.

Here’s a complete listing of the code used in this article:

(require 'company)

(defconst sample-completions
  '("alan" "john" "ada" "don"))

(defun company-sample-backend (command &optional arg &rest ignored)
  (interactive (list 'interactive))

  (case command
    (interactive (company-begin-backend 'company-sample-backend))
    (prefix (and (eq major-mode 'fundamental-mode)
                 (company-grab-symbol)))
    (candidates
     (remove-if-not
      (lambda (c) (string-prefix-p arg c))
      sample-completions))))

(add-to-list 'company-backends 'company-sample-backend)


  1. company-mode project site 

  2. The ycmd github repository and my Emacs client

  3. Sorry, I couldn’t resist the Star Wars reference

  4. We’ll filter the strings later based on context. 

  5. This puts your buffer in major mode “fundamental” and minor mode “company”. 

Stay in Touch

Our business hours are 08:00 to 16:00 CET/CEST.