So you’ve betrayed us?
I’m not a traitor
I just wanted to see what we can learn and borrow from Emacs. It’s extremely mature text editor, and LISP environment, featuring many packages with interesting ideas.
I’m not pretending to know everything in Emacs, but I’m using it on daily basis for half of a year pretty much every day to do notes, various exercises, and configure it just for fun, because it features one of the most interesting configuration approaches, which I’ll discuss little bit later in this post.
Since Emacs is complex in some points, I’m going to try to briefly explain some Emacs local names of things in case someone here didn’t used it and doesn’t understand the terms, which actually very different from other editors from time to time. If you’re Emacs veteran fell free to correct me
in direct messages, so you don’t elisp-shame me in public here, I’ll update the post text accordingly, or start a long long rant with you in the comments because why not? Anyway, this going to be quite big a post, so welcome if you’re interested in what 43 year old LISP machine could teach 8 year old code editor.
Let’s start from the visuals. Both Emacs and Kakoune features color schemes, and syntax highlighting. Here’s how Emacs looks on my PC while I write this post:
I’ve put a lot of time to make it look like this, because by default it looks like 43 year old editor. Oh wait… Anyway, I’m liking how it looks , and this was only possible because of the great community of Emacs. I wish such community will built over time for Kakoune as well. I’ts amazing.
But back to the post.
I love when syntax highlighting has many consistent colors, so I could distinguish code structure just by glancing at the colors of the code block. Emacs has somewhat minimalist approach when it comes to highlighting, and I believe it is closely related to the underlying system that is being used for highlighting.
Emacs has regex based syntax highlighting, that can be extended or manipulated via regex syntax table. Various major modes provide syntax highlighting on it’s own, so there’s no general place where we could adjust syntax highlighting. If you don’t know what major mode is, here’s a quick explanation below.
About major modes...
A major mode in Emacs is a set of behaviors for specific task, of which you can think as of a filetype plugin in Vim, or filetype script, like those located in
rc/filetype/. Usually it provides indentation rules, syntax highlighting, completion, checker, all that kind of stuff that meaningful to the language we’re working with. But it doesn’t have to be a language mode. It can be a whole new environment for Emacs, like git wrapper or PDF reader, so it is more complex then just a filetype plugin. We’re going to talk about it in terms of supporting languages, so doesn’t think much about it - just know that major mode provides set of behaviors for Emacs for certain task, like editing the code of specific type.
So major mode provides highlighting, but I’ve said that Emacs uses minimalist approach, due the underlying implementation of a font locking. Font locking is simply a mechanism to change font attributes, like color, height, font, weight, e.t.c. The name is kinda weird but I believe it’s going back to lisp machines having various lock keys, here’s nice post about that. And font locking in Emacs is kinda slow and somewhat memory expensive (not quite). Kakoune shared similar memory problems, but it’s highlighting system is faster, compared to Emacs one. So usually Emacs highlights text only when the highlighting will make something important stand out, like function definition of variable declaration, but not function call, or variable usage:
Here the essential elements are highlighted, and everything that has less interest (as Emacs thinks) is not. Of course we can change this a bit by modifying font lock keywords to make it look more like modern editors highlight code, but that’s another story. Here’s how Kakoune handles highlighting for this code:
Kakoune (Note: I’ve changed some comments, treat them as part of the text of the post.)
Luckily for us, Kakoune, as well as Emacs features regex highlighting that we can easily modify to make it more distinguishable. Here’s how it looks in my setup:
But I believe that this doesn’t count, because users who just installed Kakoune to write some Rust code won’t get that rich highlighting without investing their time into defining regexps for everything there, and even if such highlighting will get merged, still there’s lot of work to do for other languages, to provide semantic highlighting.
Currently Kakoune features highlighting scripts for many languages, with 70 scripts in total. I’m going to admit that it is good amount of languages already, but the highlighting may be broken sometimes. So this area really needs improvements. I have plans to rework some bits of highlighting for
rust.kak since these are my two primary languages that I use every day, and I want them to be highlighted meaningfully. Perhaps I’ll go with the Emacs way of highlighting, to mark important places in the code, leaving less important parts up to users.
There’s one more thing I want to cover in syntax highlighting that is done little bit better in Emacs -highlighting overriding.
You see that I’ve added highlighting of function calls and methods to Emacs and Kakoune, but in Emacs it was easier, because we can choose where this highlighting will be put in the table. The syntax for highlighting is:
(font-lock-add-keywords MODE KEYWORDS &optional HOW)
MODE is a mode to which we want restrict the highlighting,
KEYWORDS are regular expressions paired with
face and optional
HOW argument that can help us choose if we want to override existing highlighting, or highlight only unhighlighted text.
In Kakoune, we only have option to add one highlighter before another, so the latter will just override the former. So for example if I want to highlight function call in Kakoune but don’t really highlight control flow operator as functions I have two options:
add-highlighter shared/rust/code/functions regex ([a-z_]\w*)\b\h*(?=\() 1:function add-highlighter shared/rust/code/keywords regex \b(?:for|in|while|break)\b 0:keyword
This everything that was highlighted as functions but matches highlighting of a keyword would be re-highlighted. Or I could:
add-highlighter shared/rust/code/functions regex ([a-z_]*?\w*?)\b(for|in|while|break)?\h*(?=\() 1:function
This carefully avoids everything that in the second group, and such highlighting is independent from it’s position in the list of highlighters, but it involves extra calculations, and rich highlighting can get slow because of it.
I would like to propose an
-override switch for
add-highlighter function, so it will ignore if highlighting was already applied to this match. This way users will be able to extend highlighting easier without worrying to override builtin keywords, and override things if they need.
Another note on syntax highlighting in Emacs, is that it is more smart. It detects types in C where syntax really expects type to be:
Look at the casts and user defined types. It is just regular expression highlighting, it doesn’t actually knows that this type is defined somewhere, it just understands the syntax. Now look at Kakoune:
As I’ve already mentioned, this issue is on my list of TODOs for Kakoune, so I’m going to work on this to bring such semantic highlighting to the languages that I use. I don’t write in other languages that often but I know that there’s also minor problems with Perl highlighting:
Kakoune (Doesn’t know arrays in Perl?)
Another topic that I would like to discuss is indentation rules. Emacs has some mechanisms to make indentation rules for different languages, and it is actually awesome. Emacs sets correct indentation for current line based on syntax around this line, typically by searching upwards from the cursor in order to find which syntax constructions are there and which indentation rules they provide. This is really nice, compared to really basic indentation handling in Kakoune. Vim is no exception here, but it had something similar to Emacs called
cindent. It does some sort of parsing of a code to provide automatic indentation. Kakoune typically checks some conditions which can be failed if syntax isn’t that what is expected by these conditions but still valid in the language, like comments after curly braces in C:
Emacs handles this better, providing correct indentation, based on syntax around the cursor on each line while typing.
The issue with syntax highlighting and indentation can be solved by external tools like tree sitter, but this means a dependency on external tool, or including parses generated by tree sitter into the core of Kakoune, like it was done with Atom, which can also provide nice syntax aware features, like folding, selections (Kakoune actually can have huge benefit from that), and even error highlighting, since tree sitter can indicate syntax errors.
But I think that it should be implemented in that way so users could extend syntax indentation rules based easier, that writing a grammar for tree sitter. Not sure how to implement it, I’ve tried to write a generic parser for C-like languages in Perl to provide semantic indentation but it’s kinda hard task with many quirks here and there.
Since Kakoune focuses on code editing task I believe that this particular problem should be one of the top priorities, because incorrect indentation always gets in your way when you write or edit code.
There was a poll somewhere about favorite editor documentation, with three votes and all for Vim documentation system, including my own. But it doesn’t mean that we shouldn’t discuss Emacs way of documenting things. And it’s pretty good too.
Because Emacs is written and configured in Emacs LISP (which is nice) a full featured programming language, which allows to add documentations to the code, we also are able to browse these documentations. In Emacs, you can call
describe-SOMETHING and pass the name of
SOMETHING to it. If that something has documentation (it has 99% of the time) you’ll be prompted with it. The buffer will show up, containing documentation text, as well as information about that something, e.g. is it a function or variable, and location of where it was declared:
Emacs help buffer on the right, function definition on the left.
You can see that there are highlighted references available in the help buffer. Since this function calls two other functions I would like to read documentation of those too. I can do that because I’ve specified these references in the docstring by using this syntax: `function_name’, and Emacs automatically references it in help buffer by adding clickable link.
Kakoune follows similar approach, but in a different way. We all know
-docstring switch for
define-function which can be browsed while we’re in the
prompt writing command. But there’s no way to look to the definition of that variable or function, unless we go and dig in
rc directory where this thing is.
Another problem is that we can’t include documentation with the scripts that will be accessible with the
:doc command. Usually there’s no documentation in Emacs packages, but being able to quickly locate their source and read documentation there isn’t big problem.
Modes, Packages, Plugins, Extensions
This is where Emacs really shines. Possibilities are endless. You can play tetris, you can order salads, you can even play nes games in pure Elisp:
Emacs features Super Mario Bros. in emacs-nes.el
– Heeey, that’s not fair! Kakoune is a code editor!
– Yeah, but have you heard about Sokoban?
Kakoune features sokoban.kak
Just kidding, I’m not going to game-shame Kakoune, since who needs games in text editor? If you need, I recommend you to open Emacs and visit a doctor via
M-x doctor RET. Damn it! Emacs actually has a builtin psychotherapist! (Try it, it’s awesome)
But games are not the main point here. The point is that in Emacs it is possible to do any kind of thing, because Emacs isn’t a text editor really. You can think of it as an editor with side features, but in fact it is a LISP machine with editor as a side feature.
Well, Kakoune also capable of manipulating text in a buffer, hence that’s what editor is all about usually, so we could implement many things like in Emacs too. Also, since we’re able to use any language from shell expansion, plugins for Kakoune can be as complex as in Emacs, as long as Kakoune provides some features. As some quick examples of simple text manipulations to provide UI like plugins are file browsing plugins, or tag browsing:
Kakoune plugin edit-or-dir
Well, that’s not really a side panel file explorer, but I mean that nothing prevent us from implementing one. We don’t even need folding for that really. Folds will make things easier, for sure, but instead we can request list of files in the directory and rebuild whole buffer.
Here’s how filetree plugin looks in Emacs:
Emacs package Treemacs
Sure, it looks just like in GUI application, and Emacs in GUI mode is capable of displaying graphics, but these are custom font icons, so this buffer technically contains text only.
And there’s far more useful packages that can help you with any kind of task in Emacs. Sure, that’s because Emacs is a full featured LISP environment and highly extensible on its own. But I think that Kakoune is mostly as extensible, as it exposes it’s state via shell, and we can control it from external tools pretty much just as we would do it by hands, so for such plugins to show up we only need to wait or implement them ourselves.
I’ve mentioned that when we configure Emacs we’re loading a program into LISP machine. That’s quite interesting topic, so let’s discuss it too:
Emacs understands any
.el file when it knows where to get it. We need to manage paths to our scripts in order to
(require 'feature) in Emacs, in the very same way as
source command works in Kakoune. We can write tools to automatically load our scripts like use-package for Emacs, and plug.kak for Kakoune, but essentially it all comes down to sourcing script from particular place at particular time. This can be done on loading, or when certain event happens, it doesn’t really matter here, since in these places Emacs and Kakoune share the pretty much the same mechanics. But what Emacs can offer is non Emacs LISP configuration files.
You see, Emacs is extremely powerful tool and it has its exclusive features like Org Mode. Org mode is a markup language for Emacs, that is far more than just a markup language. It features spreadsheets with calculations, rendering to various formats, linking, and most importantly for us now, it can execute code blocks. What does this mean? Well, it means that we can write our configuration in Org Mode, and have nice formatting, and commentary on every piece of our configuration file. And then load this configuration file as if it was generic
.el file into our Emacs with org mode command
org-babel-load-file. This command strips away all the text from the org file, and puts all source blocks into separate
.el file, or to different files if you want it to.
I’m using this approach myself, and find it really useful and unique way to configure my editor:
Fragment of my configuration file for Emacs.
This file is actual configuration file for Emacs. When I change configuration of the editor I edit this file, and not the Emacs Lisp files. And you can render it to PDF and print it if you want! Question - how cool is that? Answer - very.
A bit about Org mode
Org mode is capable to do a lot of things. You can write books in Org mode, calculate in tables, do you presentations, generate websites, run your agenda, and more. Here’s for example some math lab from the university I helped my friend to plot in Emacs:
Org mode buffer with some LaTeX formulas and gnu plot code
Now we can press
C-u C-u C-c x l to render LaTeX, and
C-c C-c to execute code block where our cursor is:
Same Org mode buffer, but with Inline LaTeX previewed, and gnu plot code executed within Emacs providing a picture as a result.
And here’s PDF that you can get from this buffer with
C-c C-e o l:
Emacs viewing PDF generated from the Org file.
If you’re got interested in Org mode, I can recommend you this talk that briefly explains basics of using Org mode.
So how can this apply to Kakoune. Well, certainly we can’t just start using Org mode for configuring Kakoune (which is a bit of a shame), but I think that it won’t be too hard to implement such a thing. Basically we just need to strip away every text that is not in source code blocks, and then parse source code blocks parameters to generate
.kak files, or even just source them without it. The benefits of such method is that one can have beautiful document with everything commented and set up in single place. I’m currently trying to have up to date README.md for Kakoune, but I change configuration quite often so it’s hard to update it every time. The downside is that it isn’t really the script, so it’s harder to debug. I see this as an interesting idea though.
Lastly I want to talk about plugins once more. We already know about Major modes, but what about minor modes? What’s the difference?
You see, in Emacs, there can be only one Major mode that is active at a time. But you can have any amount of Minor modes simultaneously active when you’re using Major mode. Minor modes usually provide extra features. For example multiple-cursors in Emacs is a minor mode. Or for example, when you’re working with C you may want to use aggressive indent. So this is essentially just a plugins that provide additional functions to the editor.
What makes Emacs stand out is not that you can load minor modules, but the fact that you can unload them.
For example, I’m using Racer when I’m writing quick examples of Rust code in Emacs. But sometimes I actually want to switch to language server for Rust. So I can unload
racer-mode and load eglot minor mode, effectively replacing one functionality with another.
Kakoune, and Vim shares the problem of being unable to unload functionality. Recently, Kakoune added support of loading code with
require-module, that was written in
provide-module block. But we can’t really unload a module. So if I require some plugin in, it will stay there as long as Kakoune is active. That can cause problems when you have some things that you want to use from time to time but that conflict, and if you load one, you’ll get the error if you’re load another. Sure there’s no such situations currently, but I’m not sure what will happen if, I load
kak-lsp together and try to edit Rust code. Who will win? One who was loaded latest?
Vim actually has a plugin, that allows to unload other plugins: vim-scriptease. That’s another level of sorcery, but I think that it shows the state of the art with Vim plugins and how Emacs minor modes are little bit better in this particular aspect.
Kakoune also can benefit form unloading modes to provide long working sessions that do not grow in size when working for several days with different files, which can also help to narrow down amount of conflicts in various plugins that may appear. And at some point I’m sure they’ll appear.
In Emacs context is a huge part of the editor. Indentation is context based, interactive features are context based too. Kakoune lacks this a bit and here’s how it can make things interesting.
Take for example Org Mode. In org mode when your cursor is on the heading, you can arrange headings of the same depths, but you can’t go past the bottom. You use alt and arrow keys for that. Tab key opens and closes nodes. When you’re in table, alt and arrow keys now arrange columns and rows. Tab key now is used to jump between cells. If you press
C-c C-c on the heading options Org mode will reload them. If you press the same shortcut while your cursor is inside source block, it will execute it. So the thing is that Emacs is always aware of the context of where your cursor is. It’s not default functionality, and Org mode is implementing all of this by itself, but it is common practice in Emacs to be context aware.
We can achieve something similar in Kakoune. I’ve already mentioned some plugins that transform buffers into interactive buffers instead of plain text buffers, like
edit-or-dir.kak, but in order to do that we need to redefine keys in these buffers. And there may be some problems with these approach. Not sure what could be done here, but currently most obvious way is to remap keys only in normal mode, but usually user can enter insert mode and break such buffer.
Another great feature from Emacs which also relates to context, is narrowing. One can narrow the scope of the buffer to current function/tree-node/s expressions/e.t.c. if mode provides such contexts.
So for example my config file is 1700 lines long. I want to edit part of it and don’t mess with other parts, and since I’m using Org mode I have different setting placed in separate subtrees:
Emacs showing full file contents with a lot of subtrees
Let’s imagine I want to work with
Geiser configuration only, do some global replaces, and run spell checking on that part of the file. I can narrow to this subtree with
C-x n s (Ctrl x narrow subtree):
Emacs showing narrowed part of the file, which now only 14 lines long.
Now I can do any kind of global actions, and it won’t affect the rest of my file. Kakoune solves this problem by allowing to select some area and then select things inside it, or run commands for current selection, but what if you need to do a lot of things with this area? You’ll have to select it every time after every action. Instead you could narrow the buffer to current selection, and widen it back when you’re done.
Another example is editing code. As you can see on the screenshot above, there’s a
#+BEGIN+SRC emacs-lisp block, that ends with
#+END_SRC. It is a source block that has highlighting inside it. What if I told you, that you can edit this part of the buffer, as a file of the type of this language? Meaning that all fancy features like auto completion, paren matching, and other stuff that specific to LISP will work for that code, while you’re working with Org mode? Remember when you’re writing markdown, you always need to switch to different buffer with appropriate filetype loaded in order to have correct indentation and completions? Well, in Org mode you can narrow to this part in a separate window like so:
You can see in the modeline that left window is
Organd right is
Now you can edit code in the right window and when you finish it will appear in the left window. But what if I edit it in the left window while I’m editing it in the right? Well, you can’t. Emacs understands that in this context you’re effectively editing this part of a file in another place so this part must not change. You can change text around this source code block, but not inside. Once you press
C-c ' in the right window it will apply those changes in the left:
Changes appeared in the Org buffer
But the most great thing about context is completions. Yes, completions in Emacs are context aware too. When you type something in a buffer that can provide contextual information to completion fronted your completions will display functions where you need to insert functions, variables where you need variable, and so on:
Help message at the bottom line of the screen.
advice-add: (SYMBOL WHERE FUNCTION &optional PROPS) at the bottom? It’s context help for you that actually understood by completion system, so when I start typing, I’ll get contextual completions:
Completion window with functions for FUNCTION parameter of
Kakoune also features semantic completions in various places, like when we write things in
prompt mode, usually it suggests switches for commands just right. Now imagine if the same worked when you write kakscript? I’m going to
prompt mode quite often just to check correct switches when writing plugins, so I’d like this feature very much in Kakoune. It really helps you not to make mistakes.
Kakoune also has contextual completions with LSP, but that’s different story, and Emacs also can do that.
While Kakoune is a great editing tool, I think it can be improved, and here are my thoughts. If you disagree with me, feel free to throw you thoughts in, since that’s why we’re here. In case you’ve missed something in this post, here’s brief summary of things that I’ve touched:
- Syntax highlighting
- Highlighting Overriding
- Smarter Highlighting
- Syntax indentation
- Syntax highlighting
- Packages, Plugins, Modes, Configurations
- Minor modes
- Automatic Completion
Sure that doesn’t cover whole Emacs world, but I hope that I’ve brought to the light some design points that can be rethought, borrowed, or improved by looking at a extremely well made editor that stood the test of time for 43 years and still continues to improve.