Writing custom ACE Editor Mode

Jakub Mikuláš
4 min readJan 16, 2018

--

Creating your own ACE Editor mode could look as a daunting task. And it kind of is to be honest. Hopefully, this guide will make it a bit easier. Why would you need a custom highlighter in a first place? Well, you might've created your own language, like we did few years ago with the API Blueprint.

ACE Editor is using so-called Modes for highlighting. Mode is a set of regex rules run on each line. There is a documentation on how to create these Modes and ACE also has a handy online utility for creating and debuging those. You can also run that utility locally.

How does it work tl;dr

  1. The $rules object holds arrays of rules
  2. Lines are matched 1-by-1
  3. Rules in start are executed first
  4. If there is a next key, continue with the specified block

In short, you can get something like this:

Setting things up

I will be using the Brace version of ACE, just to take advantage of the Webpack bundling. There are few minor `differences`, for example changing ace.require to acequire. But code-wise of the actual Mode itself, there shouldn't be any changes. But feel free to use the Mode Creator. Modes are quite easy to transfer between ACE and Brace.

Don't start from scratch

Writing rules from scratch is a quite tedious, because you need to also define some default behaviours like newline indent/outdent etc. If you want to see how it looks like, check out the ACE's Text Mode. Much more approachable and recommended solution is to use some other Mode as a base and extend on it.

Extending other languages

Let's start by creating our Custom Mode, which is extending the Text Mode, inheriting just a very basic set of rules and some useful behaviours:

Do you see the object this.$rules on line 18? Just start filling it with your own highlighting rules.

First, anything that might occur in the top scope of the document should be in the start array. From there, you can branch out into different parts of your language. Also, always remember that you can go back to the start scope with the next key.

Tips for writing rules

Take a look at the official docs on highlighter rules. There are few things that could help you:

Reusable highlighting rules

This is actually a big one. You can define a block and then reuse it in other blocks. Think bold/emphasis tags in Markdown. They might occur in the top scope (start). But you can also use bold/emphasis in other scopes, like headers, lists, blockquotes etc. Luckily, there is a built-in way how to achieve it with an include property and a this.normalizeRules() function.

You can use regex instead of string

Escaping regex in a string is no fun. There is also a chance, that your editor is actually pretty good at highlighting regular expressions. Luckily, you can pass them directly to the regex key in rule object.

Use only valid keywords

If you keep to only using predefined keywords your Mode will be compatible with all ACE themes out of the box, because they rely on CSS class naming.

Do validations with a regex

Because regex rules are evaluated in the order they are in the array, you can use a fall-through logic to catch invalid expressions with a different regex and an invalid token.

In this example, I'm formatting a Headers part of the API Blueprint. Header name can't contain space, so we just check for the validity with a regex and then mark the header invalid if we found any space in it.

Embedding other languages

You can also embed other Modes into yours. Think CSS snippets in HTML or SQL highlighting in query strings. To do it, you just need to find the starting point and then send the highlighter to the different Mode:

This code would add a highlighting for GitHub flavoured Markdown code blocks.

Importing tmlanguage files

There is a way to reuse tmlanguage files within ACE, used by other editors like Sublime Text. Sadly, I had no luck with them and had much better results with creating the mode from scratch.

--

--