Emacs as an IDE: Setup
I found myself in emacsland through somewhat unconventional means. It wasn't a parent, mentor, or king of the geeks that turned me on to it, it was grad school. And it was one class in particular, Analysis of Algorithms. To complete the homework assignments for the class, I had to create lots and lots of mathematical equations, graphs, and diagrams. Drawing them by hand was acceptable but no one wants to draw a five or six level diagram by hand.
The one sensible way to do that was LaTeX, a typesetting language created in the 1980s but still in use for print technical books. Emacs org-mode, a likely subject for a subsequent post, has extensive LaTeX support and my time to complete homework was cut by a third.
From there I branched out into the other capabilities of emacs, taking advantage of its high level of customization, rich set of plugins, and existence on almost every modern computing platform.
I'll answer the burning question in advance, "why not VS CODE?" I started using emacs before VS Code was a thing. I also like having everything under one roof. Org-mode is an emacs-exclusive feature that I use for document creation and personal productivity. So I'd be spending time here anyways.
Emacs users often share their configurations online in
dotfiles repos and there's a culture of learning by example vs formal education. Packages for almost every purpose imaginable are available in various repositories so the joke about users endlessly tweaking their configuration can ring true. This series of posts will not go to far down that path. Mind you, I have been that user but have trimmed down the hand rolled stuff. There will be opportunities to tweak things but we'll be starting from an opinionated base "distro" (a collection of plugins, platforms and processes) called doom-emacs.
Why doom ?
First it's to combat bad ergonomics of a default Emacs config. Long story short, Emacs uses the CTRL and ALT keys a lot for UI navigation. These keys are often at the extreme left and right of the keyboard and a reduced size key as well. There are a lot of other examples where the application shows its age, pre-dating many of the conventions of the last 40 years.
For example, in normal Emacs, you save a file with CTRL+x CTRL+s. In doom-emacs, saving a file is completed with
SPC f s. Space is the system wide leader key that brings up a popup window.
f is the context for file operations and
s saves the file. This organization system makes it easier to discover commands quickly.
Doom provides a couple different ways to install packages: through normal repositories like MELPA or using its managed module system. Each module will specify packages to install if that module is enabled, associated functions and commands that should be available to the user and binds them to context menus. For example, when you enable the Java module, it knows that most Java builds use Gradle/Groovy so those are installed along side the Java packages.
Doom is also really fast. With a spartan build, it is ready to use in a couple seconds, my full build loads in just under 10s. Much much much faster than I could do with IntelliJ.
Install Emacs and doom-emacs
Doom has a pretty good guide to install Emacs and doom.
It covers the quirks of getting Emacs installed on different platforms and the two lines of code to get doom installed:
git clone https://github.com/hlissner/doom-emacs ~/.emacs.d ~/.emacs.d/bin/doom install
doom command is your main way to
sync your installed packages as well as troubleshoot problems with your install(
doctor). After this first instance, you can update, sync, and reload your configuration from inside Emacs.
Understanding the module system
Your doom configuration lives in three files:
packages.el. Most of the time, you'll be editing init.el as it controls which modules are installed. Modules are grouped by general function areas. Here is a subset of the module groups, listing only the ones we care about.
input, alternate keyboard layouts and Japanese/Chinese input
completion, code completion and file/command search manipulation
ui, modules that modify the general app user interface
editor, modules that make Emacs more IDE like (snippets, text manipulation, cursor niceties, etc)
emacs, core emacs functionality
term, options to run a terminal in Emacs
checkers, syntax and grammar checkers
tools, general small to medium scale apps and integrations (git, docker, password managers, etc )
lang, programming language support
app, large scale apps that tailor emacs to that purpose like social media clients, RSS readers and media players
You can peruse the list by running
SPC f P. The capital P is important.
Navigation and working with files
Here are a couple of basic doom emacs commands.
- Open file
SPC f f
- Save file
SPC f s
- Open configuration files
SPC f P
- Change to insert mode
- Exit insert mode
- Run a command
M-x(read as Meta, it's usually the Alt key)
Emacs needs to differentiate between when you want to edit the contents of a file and when you want to enter commands. You can tell if you are in insert mode or not based on the cursor shape. | is insert mode, █ is command mode. Press
i to start editing files.
Setting up basic IDE features
By default, Doom enables a number of defaults. To make it more like a traditional IDE, we can add a project drawer for easy navigation, tabs to switch between files in a project more easily, github style emoji and terminal support. We can also enable a side minimap to navigate inside a file quickly.
:ui section of
init.el, uncomment/add [remove the ;;]:
minimap tabs treemacs (emoji +github)
:term section, uncomment:
Exit insert mode (
SPC f s to save the file and then
SPC h r r or alternatively run
M-x doom/reload to reload the config.
An project will look like this:
Pretty cool but we add some language support.
Tweaking fonts and themes
Emacs can use an installed system font as the editor font. The default is perfectly serviceable but I like to use Fira Code.
The font is set in the
config.el file, usually commented out at first. The following sets 16pt Fira Code Retina as the default UI font.
(setq doom-font (font-spec :family "Fira Code Retina" :size 16))
Doom has over 70 included themes, you can apply a different one using
M-x load-theme or
SPC h t.
doom-one is the default, check this repo for descriptions of the included themes.
You may get the prompts
Loading a theme can run Lisp code. Really load? and
Treat this theme as safe in future sessions?. Answer yes to both.
This will activate the theme for only the current session, after which it will revert back to
doom-one. To make it permanent, update the theme in the
config.el file. The following assigns
(setq doom-theme 'doom-dark+)
Language Server Protocol and Debugging
Some of the key features that separates the text based editors like emacs and vim from more heavy IDEs like Android Studio or XCode are things like refactoring, linting and code completion. In the past, you had to forgo all that if you wanted a lightweight portable solution. That's no longer the case.
The Language Server Protocol allows a server to be notified when changes in a document happen. These changes are analyzed and the client is sent a message noting any errors or warnings that have come with the change. The language server can also include possible linting optimizations the user can perform as well as navigating to signatures/defintions of classes and functions.
LSP started as a Microsoft Visual Studio Code feature but developed as its own specification and can be used in almost any text editor that's capable of sending and consuming JSON-RPC messages.
LangServer.org maintains a list of well supported LSPs. I'll be covering the specifics for setting up support for the languages individually but for now, we need to set up global support. In tools section of
:tools ;; ... lsp (debugger +lsp)
Company-mode, short for complete anything is a text completion framework that you get for free with enabling doom's LSP support.
The Debug Adapter Protocol, modeled somewhat like LSP, is a means to provide language and tooling debugging to users. Tooling only needs the common interface of debug adapters. Each debug adapter then handles the specifics of interacting with the underlying debugging tool. Emacs dap-mode hasn't hit 1.0 so it doesn't have as much language coverage as LSP.
The following blog posts will cover the various programming languages and writing environments I use. First up is Flutter.