Development Environment with Emacs

2017. 11. 13.

Development Environment with Emacs

Entering the Forbidden Realm

I used to be the type of person who felt compelled to try every new tool related to work, whether it was an editor or an IDE. However, at some point, I realized that they were all pretty much the same, and even with new features, the functionalities I actually used for development were very limited. I used IntelliJ for over a year, but since I primarily develop for the front-end, I didn't really need an IDE. Using it felt like overkill, as I barely touched its vast array of features.

As this feeling grew, a passage from Park Woong-hyun's book Eight Words unexpectedly sparked a decision. The essence of an editor remains constant; classics transcend time, retaining their enduring value. That's right. I decided to learn the classic editors: Vim and Emacs.

My reasoning was that getting used to the key bindings of classic editors would likely be beneficial in various situations, as many modern editors offer support for them. Plus, I had heard about the power of Vim and Emacs and was confident that if I could just adapt, one of them would surely become my main editor. I started with Vim and used it for a little less than a year. I became quite proficient, so I didn't initially plan on learning Emacs. However, Vim alone wasn't enough to cover everything. It required using Tmux, a terminal multiplexer. Korean language support was inconvenient for documentation work. And since Vim lacked a way to run external processes asynchronously (until Vim 8), static analysis plugins would cause the editor to freeze whenever they ran. Furthermore, while I wanted to create simple plugins, Vimscript, Vim's plugin language, held no appeal for me to learn separately.

Then, after watching this YouTube video and exploring various articles and other Emacs-related YouTube videos, I embarked on another challenging journey. It has now been a year and a month since I started using Emacs. I've established a reasonably stable environment and feel I can handle it adeptly without any inconvenience. Emacs has become my companion for almost all work tasks, not just development, but also project management, scheduling, and documentation. This very post is being written in Emacs. Emacs calls plugins "modes," and I'm even studying Lisp (specifically Emacs Lisp) to develop the modes I need. Lisp seemed preferable to Vimscript in many ways. This experience even sparked an interest in the Lisp language itself, leading me to dabble in Clojure, a Lisp descendant. In short, I'm completely hooked on Emacs. Even Uncle Bob, who famously mentioned in the latter part of Clean Code that he had settled on IntelliJ after leaving Emacs, eventually returned to Emacs (related tweet).

Learning and using a classic editor is, in itself, both a game and a study. It's genuinely fun. I'm writing this post in the hope that you, too, might give it a try.

Now, all I need to do is get better at development.

Not Just the Terminal: Use OS-Specific Builds

Emacs can fundamentally be used in the terminal. While it was designed for that purpose, using it in a terminal environment comes with various limitations and inconveniences. It's better to use a separate build for your specific operating system. Using an OS-specific build means running Emacs as a standalone application rather than within the terminal. These builds are optimized and ported using native frameworks, resulting in excellent integration with the OS. For example, on a Mac, you can scroll pixel by pixel with the mouse, use dictionary lookups, integrate with window layout management tools (like Magnet), and generally experience better performance than in the terminal. Crucially, on a Mac, it's much more convenient to bind the Command key to Meta, which is not possible in the terminal version of Emacs. As a Mac user, I personally recommend one of the builds by Mitsuharu Yamamoto, a brilliant Japanese developer. The main repository is here, but it's better to download from the Homebrew repository. While you can install via Homebrew, it takes a very long time and sometimes results in build errors, so I just download the release build. Once you start using an OS-specific build instead of the terminal version, you'll immediately notice the difference in comfort.

What is a Mode?

Emacs is less a program with specific functions and more a Lisp-based programming platform, often referred to as an OS in its own right. It has a development environment onto which additional functionalities are extended through plugins. In Emacs, these plugin layers are called "modes." Modes are divided into major modes and minor modes. A major mode can only have one loaded per buffer (akin to a tab in modern editors). Typically, a major mode provides support for syntax highlighting, auto-completion, indentation, etc., for the programming language within the buffer, or it corresponds to a single internal application. For JavaScript, there's js2-mode; most other languages like Swift, Go, Python, etc., have one or more major modes available and under development. Then there are minor modes. Multiple minor modes can be loaded in a single buffer and usually extend cross-language functionalities. Examples include bulk editing features, static analysis modes, or modes that display Git changes in the gutter. Typically, you choose one major mode for a language (if options exist) and extend its functionality with useful minor modes. There can also be extensions that aren't strictly modes, and sometimes major and minor modes are used together to form an application. The main focus of this post is to introduce various modes that perform specific functions. It doesn't cover basic usage at all. The first step is to pique your interest…

Appearance

!(https://user-images.githubusercontent.com/389021/32757999-981a7334-c925-11e7-9d58-b549ba87e3a6.png) The large area is the buffer, though it's more accurate to say the buffer exists within a window. You edit files through the buffer. Window splitting is, of course, freely possible. Various messages or UI elements for specific functions appear in the space at the very bottom, called the mini-buffer. For instance, during a search, it prompts for the search term.

!(https://user-images.githubusercontent.com/389021/32758037-ca55c7ea-c925-11e7-8be3-0cc038ddfb7c.png)

The screenshot above shows a case where the mini-buffer size is temporarily increased. Usually, it's just one line. This mini-buffer interface can also be extended with plugins, notably ivy and helm.

Useful Modes

Project Management: Projectile

When Emacs opens a file, it goes into a "buffer." This is similar to the concept of a tab in modern editors and will be familiar to those who have used Vim. By default, Emacs buffers are just independent entities with no inherent connection or grouping. Projectile creates distinctions between these buffers, allowing them to be managed as independent projects. Modern editors often use separate editor instances for each project. With Projectile in Emacs, you can manage and work on multiple projects within a single Emacs instance. A project in Projectile is typically recognized based on the Git root directory. So, when you open a specific file via Emacs, it searches for the Git root containing that file. If found, it automatically registers it as a project. This means Projectile can automatically recognize and use projects without requiring special configuration files. Projectile has numerous features, but I'll introduce just a few commonly used ones. I don't even know all of its many functions myself.

Find File in a Specific Project

!(https://user-images.githubusercontent.com/389021/32718992-2ae450ce-c8a2-11e7-9cee-6a2bd0e69175.png)

Select the desired project, and

!(https://user-images.githubusercontent.com/389021/32718991-2aba0620-c8a2-11e7-8cab-5370e909427b.png)

you can search for and open files within that project. File searching has basic support, but external extension modules can also be used. Not just for this feature, but file searching in Emacs generally uses a fuzzy algorithm with minimal configuration.

Find File in Current Project

Strictly speaking, this means searching for files within the project to which the currently open and focused buffer belongs. It's equivalent to Sublime Text's "Jump to File" or Vim's CtrlP. It's very fast and convenient.

!(https://user-images.githubusercontent.com/389021/32718989-2a56a198-c8a2-11e7-84eb-bb52a5d0854f.png)

Search File Contents Within Project (grep)

Projectile supports searching file contents within a project using external programs. It can utilize grep, ag (The Silver Searcher), or rg (ripgrep). I personally recommend rg – it's incredibly fast.

!(https://user-images.githubusercontent.com/389021/32718987-2a275c9e-c8a2-11e7-8975-4f24fc10c8aa.png)

Entering a search term like this displays the live search results below. Selecting a result jumps to that location. If you use ivy for mini-buffer selection, a simple shortcut here can open the search results in a new buffer within a window adjacent to your current editing buffer.

!(https://user-images.githubusercontent.com/389021/32718983-29ba973a-c8a2-11e7-82ef-b50caf966478.png)

While projectile-replace allows replacing content across all files at once, I personally prefer, especially for refactoring names, to open the results like this and review each change individually rather than using the bulk editing features found in modern editors. Furthermore, this provides a clear overview of how and where a function or class is used, which is very useful.

!(https://user-images.githubusercontent.com/389021/32718960-26ad8840-c8a2-11e7-8cd0-30afabfdf560.gif)

Workspace Management: Eyebrowse

The space containing buffers is called a window. Even with Emacs' basic functionality, you can split this window as desired to work with multiple buffers on one screen. Eyebrowse allows you to create multiple workspaces, much like Spaces on macOS. This means you can have workspace 1 with a side-by-side split window showing files A and B, and workspace 2 with a top-bottom split window showing files C and D, switching between them as needed.

!(https://user-images.githubusercontent.com/389021/32718968-2752b914-c8a2-11e7-8b1b-01b646906ab7.gif)

Look at the mode line at the bottom of the right buffer; you can see information about the spaces, like ``.

Process Management: Prodigy

Prodigy is a helper program (more of an Emacs application than a mode) for conveniently running external processes like starting servers or executing Gulp/npm scripts from within Emacs.

!(https://user-images.githubusercontent.com/389021/32718962-26d6357e-c8a2-11e7-9d55-1cab97dfd2be.png)

You can pre-configure the processes to run in your Emacs configuration file. Then, in the Prodigy buffer, you can view these processes. It handles build automation tools, running tests, or starting servers. "Running" indicates the process is currently active. Instead of repeatedly starting servers in the terminal, you set it up once and can easily start, stop, or restart processes from within Emacs. You can automate anything you could do in the terminal, like compilation. A shortcut allows viewing the terminal output of the respective process.

Fast Navigation Within Buffers: swiper, avy

For quick navigation within or between buffers during editing, I use swiper or avy. Think of it as teleportation within your code. Swiper prompts for a search term, displays matching lines in the mini-buffer, and lets you select one to jump quickly. Avy, when invoked, prompts for one or two characters. It then overlays temporary shortcuts on lines or words starting with those characters; typing the shortcut instantly moves the cursor there.

Moving within the current buffer using swiper:

!(https://user-images.githubusercontent.com/389021/32718972-27fead14-c8a2-11e7-80ba-4970b024d4fd.gif)

Using swiper-all to navigate across all open buffers:

!(https://user-images.githubusercontent.com/389021/32718974-28551f6e-c8a2-11e7-8a0b-527f6e479d13.gif)

Navigation using avy:

!(https://user-images.githubusercontent.com/389021/32718976-28b8b722-c8a2-11e7-95c1-dd81224a1df4.gif)

After invoking avy and typing a character, potential jump locations starting with that character are marked with shortcuts on the screen. Typing the corresponding shortcut moves the cursor there.

Bulk Editing: iedit Video

iedit provides a bulk editing feature where changes are reflected in real-time. When invoked on a word or text selection, all identical occurrences in the buffer are highlighted, allowing simultaneous editing. You can narrow or widen the scope of modification, and if the buffer is very large, it can condense the view to show only the lines being modified.

Selecting a word and narrowing the scope to modify content:

!(https://user-images.githubusercontent.com/389021/32718977-28e4f396-c8a2-11e7-974e-deba6927ebe1.gif)

Selecting the modification scope (easily widened or narrowed with shortcuts):

!(https://user-images.githubusercontent.com/389021/32718986-29fc6214-c8a2-11e7-9d34-9167765a2c13.gif)

While other development tools offer similar functionality, the intuitive feel of iedit is unmatched.

Modifying All Files After Grep in a Single Buffer: wgrep

As seen with Projectile, you can search file contents within a project using grep-like tools. When the search results from such a tool are put into a buffer, they are displayed in the structure of grep-mode text. At this point, you can use wgrep. wgrep allows you to perform bulk edits across multiple files from within that single buffer. In other words, modifying the content in the search results buffer can apply those changes to the actual files (!).

First, perform a search and create a grep buffer:

!(https://user-images.githubusercontent.com/389021/32759173-604c75d2-c92b-11e7-8149-a3fff4e7cf6b.gif)

Activate wgrep in the grep buffer (C-c C-p), modify the content, and save (C-x C-s). For convenience, the individual files were opened beforehand.

!(https://user-images.githubusercontent.com/389021/32759174-60c1763e-c92b-11e7-93d1-67620eb1dd45.gif)

And since the grep buffer is also a text buffer, you can naturally use iedit for bulk changes as well.

!(https://user-images.githubusercontent.com/389021/32759175-60fab39a-c92b-11e7-9900-f1e1ee636fb6.gif)

I couldn't help but be impressed by this.

Auto-completion: Company-mode

Emacs has its own built-in auto-completion tool called Autocomplete, which works fine. However, Company-mode is often used because it tends to be easier to configure. Auto-completion primarily relies on its own backends, but for providing useful information specific to languages, the auto-completion backend is often configured using major modes or additional tools (it's easy). For dynamically typed languages like JavaScript, using ternjs enables accurate auto-completion through type inference.

!(https://user-images.githubusercontent.com/389021/32718981-298f13bc-c8a2-11e7-98f0-97ab8791bfa2.gif)

Static Analysis: flycheck

For integration with static analysis tools, flycheck is used. It's generally well-configured out of the box, so if the external tool is installed correctly, it integrates without special effort. For JavaScript, ESLint is commonly used. It needs to be installed globally to work by default, but with a little tweaking, it can also use locally installed modules.

!(https://user-images.githubusercontent.com/389021/32718979-293aca96-c8a2-11e7-8ce3-841f4eb30890.gif)

Terminal: multi-term

Having a terminal within the editor is possible in Vim too, but frankly, it feels forced and isn't commonly used. However, the terminal in Emacs is quite usable. Emacs has a built-in shell mode, but multi-term is recommended for conveniently managing multiple terminals. multi-term is essential if you need to keep multiple terminals open.

!(https://user-images.githubusercontent.com/389021/32718957-262ca81a-c8a2-11e7-8872-304dda20d2cd.gif)

Shortcut Cheat Sheet: which-key

While Emacs supports mouse usage, it's fundamentally a keyboard-driven editor, allowing control over everything via the keyboard. Reducing reliance on the mouse is an advantage, but it also means there are many shortcuts. Since the Emacs environment is extended based on functions, you can always invoke the function search (Meta-x) and search for the desired operation. However, shortcuts are typically used. Emacs shortcuts can be single combinations like C-c, but these aren't sufficient to cover all of Emacs' functionality. Therefore, Emacs uses sequences of key combinations. For example, pressing C-c, then p, then f executes a command. This is called a key sequence. which-key provides a cheat sheet for these key sequences. When you press C-c, it shows the possible next keys along with their descriptions. Pressing p then shows the next possible keys. This allows you to easily find the functions you need without memorizing everything. No special configuration is required; which-key figures it out automatically.

!(https://user-images.githubusercontent.com/389021/32718958-26550864-c8a2-11e7-8e28-48d663e924a3.gif)

Emacs Applications

It's a cliché, but Emacs is itself a platform and an OS, allowing users to create and use applications within it. Many excellent programs exist, and here are introductions to two prominent examples.

The Best Git Client: Magit

Magit is a Git client. Once you use it and get accustomed to it, you won't think about other clients anymore—it's that captivating. Personally, for critical tools like Git, I prefer using only the basic tools without additional layers. Magit, however, feels like a convenient extension of the basic tools.

Magit's main screen:

!(https://user-images.githubusercontent.com/389021/32718959-26801ad6-c8a2-11e7-89ec-5cd271f08b7e.png)

If you understand Git, the only shortcut you need to remember in Magit is "?". Pressing the question mark opens a popup at the bottom, similar to which-key, displaying a list of available actions and their shortcuts.

!(https://user-images.githubusercontent.com/389021/32718969-277b9c12-c8a2-11e7-86dc-f775dd1815be.png)

This first shows categories of actions. Pressing a shortcut here displays a list of specific tasks. For example, to commit, press "c" for Committing:

!(https://user-images.githubusercontent.com/389021/32718971-27cf3822-c8a2-11e7-8411-50a2e89b2ea2.png)

This brings up the detailed menu for committing. Pressing "c" for Commit here:

!(https://user-images.githubusercontent.com/389021/32718973-2829fafa-c8a2-11e7-99ca-a5ce92b4b0c6.png)

Opens a window showing the changes to be committed and another window for entering the commit message. It looks familiar to command-line users, making it intuitive. You can easily learn Magit through this process without needing to read the manual beforehand. Magit covers all Git functionalities, so I'll just provide this brief introduction and attach a short video demonstrating its overall features.

Emacs Rocks! Episode 17: Magit (2m 39s)

Scheduling and Document Writing: Org-mode

Org-mode is a program so outstanding in its extensibility and features, coupled with stability honed over many years of development, that some people learn Emacs just to use it. It's a program for writing documents and managing schedules. This document was written in Org-mode. Org-mode's document format is fundamentally text-based, similar to Markdown, making it easily editable in any standard text editor. Many Org-mode users highly value the fact that it uses plain text files rather than a proprietary format.

!(https://user-images.githubusercontent.com/389021/32718975-28808d0c-c8a2-11e7-9478-7bfd46bc9c50.png)

By default, an Org-mode document doesn't look like this, but installing simple extensions can add various visual effects like these. It uses an outline-based structure for writing, making content easy to manage.

!(https://user-images.githubusercontent.com/389021/32718978-290eec1e-c8a2-11e7-9588-00336ebb361b.gif)

Using a feature called Babel, you can execute specific code blocks within the document and see the results, making it an unparalleled tool for studying languages. Babel extensions already exist for most common languages.

!(https://user-images.githubusercontent.com/389021/32718980-29649ec0-c8a2-11e7-9414-ad88c071ce2f.gif)

Additionally, there's Reveal.js integration to instantly turn an Org document into a presentation slide deck. Exporting Org documents to other formats like HTML, doc, or Markdown is also easy. I know many people use Org-mode to write books. Org-mode excels at table management too, allowing it to be used as a text-based spreadsheet with Excel-like usability. While I don't use this feature much personally, I know many use Org-mode for corporate expense tracking or personal finance management. But above all, Org-mode serves not only as a document tool but also as a scheduling tool. I use Org-mode to manage everything from project tasks to personal appointments and am highly satisfied with it.

Let's create a schedule item.

!(https://user-images.githubusercontent.com/389021/32718954-25dabd70-c8a2-11e7-9918-9880180ad4cd.gif)

Typically, I create one Org document per project to manage its schedule. Below is the Org document for a personal side project developing an Emacs mode. To-dos, ideas, and notes are managed within this single document. As an aside, when working on side projects, always creating the next to-do item before finishing the current task significantly increases the completion rate (though completion itself might not always be the goal of a side project).

!(https://user-images.githubusercontent.com/389021/32718955-26031680-c8a2-11e7-85ad-357217c25510.png)

You can even create links to the source code you were working on and attach them to Org-mode tasks. Links can be created to anywhere within text files.

!(https://user-images.githubusercontent.com/389021/32718963-2701b42e-c8a2-11e7-94ec-a023c5f5e4ce.gif)

As something of a GTD enthusiast, I've used various scheduling tools (Omnifocus, Things, Wunderlist, Todoist, etc.). In terms of functionality and extensibility, Org-mode is undoubtedly the best. However, while mobile apps exist, they aren't particularly great, making mobile syncing inconvenient. But I figured I'm rarely away from my computer when managing work tasks. So, I use Omnifocus as a supplementary tool. To-dos or ideas that come to mind while on the move are saved in Omnifocus and later transferred to Org-mode when I'm back at the computer. Omnifocus was the GTD tool I used right before switching to Org-mode; I had purchased both v1 and v2 Mac and iPhone apps. Expensive :(

I sync Org documents between home and work using a private Git repository on GitLab (which is free). Both GitLab and GitHub support rendering Org-mode documents, so uploading them displays them nicely formatted, not just as plain text. Programming code blocks even get syntax highlighting. You can use README.org instead of README.md.

Org-mode has been developed for over a decade, so its manual is extensive enough to fill a book, reflecting its vast functionality.

Closing Remarks

This post was written to provide a general introduction to Emacs. Learning Emacs is certainly not easy. I intentionally omitted parts that might seem difficult. While this isn't an exhaustive introduction to everything Emacs offers, I tried to include content that might capture attention. My simple hope is that the number of Emacs users in Korea increases, even by just one. For those familiar with Vim, spacemacs, which cleverly combines the strengths of Vim and Emacs, is also worth considering. Like many other Emacs users, I manage my Emacs configuration files via GitHub. If you're a Clojure, Emacs, Swift, C#, or front-end developer, referencing my setup might not be a bad starting point. (My config on GitHub) When you first start with Emacs, you tend to learn features familiar from other editors. As you do, you discover Emacs-specific functionalities, eventually finding that things possible in Emacs aren't available elsewhere, making it hard to use other editors. Emacs is free. Let's get started!

♥ Support writer ♥
with kakaopay

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

shiren • © 2025Sungho Kim