EECS 280 Tutorials
Emacs
Emacs is an extensible, customizable, free, text editor. It has an IDE mode that works with gdb
and lldb
. It is awdeorio’s favorite way to code. When you are good at Emacs, you can edit code very quickly.
This tutorial is intended for Emacs beginners who want to learn a powerful editor and some of its features for working with C++ projects.
Reasons to learn Emacs:
- Endlessly customizable
- Blazing fast code editing. Once you learn the key bindings, they become second nature.
- IDE-like features with zero project setup
- Optional text-only mode good for remote servers
- Emacs keyboard shortcuts work in many places: command line, GDB prompt, LLDB prompt, Xcode (optional), Visual Studio (optional)
Quick start
Install.
$ brew install --cask emacs # macOS
$ sudo apt install emacs # Windows/WSL, Linux
Learn keyboard shortcuts with this Emacs Cheat Sheet for beginners.
Start editing files.
$ emacs main.cpp
Prerequisites
We’re going to use external command line tools. If you haven’t installed CLI tools on your machine yet, follow one of these tutorials first.
macOS | Windows | Linux |
Make sure you have a compiler and a debugger installed. Your version might be different. Instructions for installation on macOS, Windows/WSL/Linux.
$ g++ --version # macOS
Apple clang version 13.1.6 (clang-1316.0.21.2.5)
$ lldb --version # macOS
Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12)
$ g++ --version # WSL/Linux
g++ (GCC) 8.5.0 20210514
$ gdb --version # WSL/Linux
GNU gdb (GDB)
Next, follow our Command line interface (CLI) tutorial.
Install
Choose your platform below.
When you’re done, you should have Emacs version 24.4 or higher.
$ emacs --version
GNU Emacs 27.1
Linux
This works for Ubuntu and other Debian-based distros.
$ sudo apt install emacs
CAEN Linux
Emacs is already installed on CAEN Linux.
macOS
Use the Homebrew package manager.
$ brew install --cask emacs
Windows/WSL
Start an Ubuntu Bash shell.
$ sudo apt install emacs
It will be easier to get GUI Emacs windows to work from inside WSL if you have Windows 11 and WSL 2.
Start and quit
Start Emacs, and you should see something like this screenshot.
$ emacs
Pro-tip: Start Emacs in the background so you can continue to use your Terminal.
$ emacs &
Quit. The Emacs notation for this keyboard shortcut is C-x C-c
.
- Press and hold Control.
- Press x and release it. Continue holding Control.
- Press c and release it.
- Release Control.
Key bindings
Emacs key bindings may seem byzantine at first, but once you learn them you can edit files very quickly. When Emacs was created, keyboards looked different and today’s conventions like cut-copy-paste hadn’t been invented yet.
Without keyboard shortcuts, you can run commands by name, for example “save and quit” with M-x save-buffers-kill-terminal
.
- Press and hold Meta (AKA Alt on Windows/Linux, AKA Option on macOS).
- Continue pressing Meta and press x.
- Release both keys.
- You’re now in the mini-buffer, where you can type the command
save-buffer
. Tab completion works in the mini-buffer. - Press Return (Enter).
In Emacs documentation, M
means Meta (AKA Alt on Windows/Linux, AKA Option on macOS) and C
means Control.
C-x C-s
: Save
- Press and hold Control.
- Press x and release it. Continue holding Control.
- Press s and release it.
- Release Control.
C-x C-c
: Quit
Learn a few more keyboard shortcuts with this Emacs Cheat Sheet for beginners and keep around an Emacs Reference Card.
Pro-tip: Keep your hands on the keyboard’s home row. Avoid the mouse and arrow keys.
Warning: You might be tempted to remap Emacs keyboard shortcuts to be more familiar, M-c
for copy, etc. Don’t do this! There are thousands of keybindings, and changing them can cause a chain reaction. For example, C-c
is already used a prefix for many other commands.
Caps lock as control
You’ll use the control key a lot in Emacs. Some users find it more ergonomic to map the Caps Lock key to Control. Here’s the setting in MacOS.
macOS
On Apple laptops, it’s more ergonomic to map Command to Meta and Option to Super. Add this to your ~/.emacs.d/init.el
.
;; macOS modifier keys
(setq mac-command-modifier 'meta) ; Command == Meta
(setq mac-option-modifier 'super) ; Option == Super
Customize
The out-of-the-box Emacs configuration is terrible. Some users start with Spacemacs or Doom Emacs, which are just Emacs shipped with a bunch of customizations. Many of these users later graduate to vanilla Emacs with their own customizations. Here’s awdeorio’s init.el.
Basic
Edit ~/.emacs.d/init.el
with Emacs. Yours will probably be blank.
$ emacs ~/.emacs.d/init.el
Here are a few basic customizations that you might like. Paste with C-y
.
;; Don't show a startup message
(setq inhibit-startup-message t)
;; Show line and column numbers
(setq line-number-mode t)
(setq column-number-mode t)
;; Show syntax highlighting
(global-font-lock-mode t)
;; Highlight marked regions
(setq-default transient-mark-mode t)
;; Parentheses
(electric-pair-mode 1) ; automatically close parentheses, etc.
(show-paren-mode t) ; show matching parentheses
;; Smooth scrolling (one line at a time)
(setq scroll-step 1)
;; Tab settings: 2 spaces. See also: language-specific customizations below.
(setq-default indent-tabs-mode nil)
(setq tab-width 2)
;; Easier buffer switching
(global-set-key "\C-x\C-b" 'electric-buffer-list)
Package manager
Set up use-package
, which automates package installation and configuration.
;; Configure built in package manager
(require 'package)
(package-initialize)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/"))
;; Install use-package
;; https://github.com/jwiegley/use-package
(when (not (package-installed-p 'use-package))
(package-refresh-contents)
(package-install 'use-package))
(eval-when-compile
(require 'use-package))
Undo/redo
Emacs default undo is confusing. Undo Tree provides more intuitive undo and redo.
;; More intuitive undo/redo. M-_ undo, C-M-_ redo
(use-package undo-tree
:config
(global-undo-tree-mode)
(global-set-key "\C-\M-_" 'redo)
:ensure t
:defer t
)
C/C++
Here are some optional packages that you might like for C/C++ programming.
;; Intellisense syntax checking
;; http://www.flycheck.org/en/latest/
(use-package flycheck
:config
;; enable in all modes
(global-flycheck-mode)
;; C++17
(add-hook 'c++-mode-hook (lambda () (setq flycheck-clang-language-standard "c++17")))
:ensure t
:defer t
)
;; C and C++ programming. Build with C-c m. Rebuild with C-c c. Put
;; this in c-mode-base-map because c-mode-map, c++-mode-map, and so
;; on, inherit from it.
(add-hook 'c-initialization-hook
(lambda () (define-key c-mode-base-map (kbd "C-c m") 'compile)))
(add-hook 'c-initialization-hook
(lambda () (define-key c-mode-base-map (kbd "C-c c") 'recompile)))
(setq-default c-basic-offset tab-width) ; indentation
(add-to-list 'auto-mode-alist '("\\.h$" . c++-mode)) ; assume C++ for .h files
Dark mode
Of course Emacs has a dark mode. Add the following to your init.el
.
(use-package spacemacs-common
:ensure spacemacs-theme
:config (load-theme 'spacemacs-dark t)
)
Hide menu bars
After you learn the keyboard shortcuts really well, you might not need the menu bars any more. You can remove tool bars and scroll bars like this.
;; Remove scrollbars, menu bars, and toolbars
(when (fboundp 'menu-bar-mode) (menu-bar-mode -1))
(when (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(when (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
Create a project
Emacs doesn’t require any special setup for a project.
Create a new directory, then move into the new directory. Your folder location might be different.
$ mkdir ~/eecs280/p1-stats
$ cd ~/eecs280/p1-stats
Add new files
To create a new file, start Emacs with a new file name.
$ emacs main.cpp
Alternatively, create your main.cpp
file from the command line using touch
.
$ touch main.cpp
Copy-paste this Hello World program into your main.cpp
. Remember, paste is C-y
.
#include <iostream>
using namespace std;
int main() {
cout << "Hello World!\n";
}
Add existing files
Emacs doesn’t require any special steps for adding existing files.
If you have starter files, add them to your project directory. This example is from EECS 280 Project 1, but this tutorial doesn’t require understanding the files. Your URL or files might be different.
Download, unpack, and move the starter files into the directory that already contains main.cpp
. Your URL or folder might be different.
$ wget https://eecs280staff.github.io/p1-stats/starter-files.tar.gz
$ tar -xvzf starter-files.tar.gz
$ mv starter-files/* .
$ rm -rf starter-files starter-files.tar.gz
You should see your new files in your project directory.
$ tree
.
├── Makefile
├── cats.csv
├── cats.out.correct
├── main.cpp
├── p1_library.cpp
├── p1_library.hpp
├── stats.hpp
├── stats_public_tests.cpp
├── stats_tests.cpp.starter
└── two_sample.cpp.starter
Rename files
Emacs doesn’t require any special steps for renaming files.
Rename a file at the command line.
$ mv stats_tests.cpp.starter stats_tests.cpp
Compile and Run
Some Emacs users compile and run at the command line. Others compile and run inside Emacs. We’ll use the command line in this tutorial.
$ make main.exe
$ ./main.exe
Hello World!
If you don’t have a Makefile
, you can compile manually.
$ g++ -g main.cpp -o main.exe
Navigate to a specific line number with M-g M-g
. This is useful for jumping to a line of code reported as a compiler error.
Debug
Some Emacs users run GDB or LLDB at the command line. Others use Emacs’ GDB or LLDB integration. We’ll start at the command line.
Linux and Windows/WSL: Run GDB from the command line with the GDB Tutorial
macOS: Run LLDB from the command line with the LLDB Tutorial.
Integrated debugging
Emacs provides a user interface for GDB or LLDB. Make sure you already know how to use one.
macOS: Install and configure the realgud-lldb
package by adding this to your init.el
.
(use-package realgud
:ensure t
)
(use-package realgud-lldb
:ensure t
)
Compile the executable you wish to debug.
$ make main.exe
Start Emacs.
$ emacs main.cpp
Start debug mode. Emacs runs GDB or LLDB behind the scenes.
GDB (Linux/WSL) | LLDB (macOS) |
---|---|
M-x gud-gdb |
M-x realgud--lldb |
Pro-tip: try M-x gdb M-x gdb-many-windows
on Linux/WSL.
Set a breakpoint and run. GDB and LLDB use very similar commands. The Emacs window should split.
(lldb) b main
(lldb) r
Step into a function with s
.
Move to the next line of code with n
. Do this a few times until you reach this line of code.
Print a variable with p
.
Quit the debugger with q
. Then, close the current window pane (the debugger) with C-x 0
.
Pro-tips
Tips and tricks for becoming an Emacs wizard.
Autocomplete
Use built-in Emacs autocomplete with M-/
. Cycle through the completion options by holding M
and continuing to hit /
.
Use Company Mode to provide more complex C++ code completion by simply typing the first 3 characters of a symbol and waiting for a second. Hit TAB
to cycle the completion options. M-n
and M-p
for next or previous completion. You’ll see the company-mode
configuration in init.el
.
Configure Company Mode by adding this to your init.el
.
;; Autocomplete for code
;; Company docs: https://company-mode.github.io/
;; Company TNG: https://github.com/company-mode/company-mode/issues/526
(use-package company
:config
(company-tng-configure-default) ; use default configuration
(global-company-mode)
:ensure t
:defer t ; lazy loading
)
Emacs launch shortcut
Add this to your ~/.bash_profile
or ~/.zshrc
to start Emacs in the background with e
. Close your terminal and open it again.
e ()
{
emacs "$@" &
}
Then you can simply type:
$ e stats.cpp
Editing remotely with TRAMP
Emacs TRAMP mode lets you edit a file on a remote server using a local GUI window.
Configure Emacs TRAMP mode to use SSH multiplexing. Add this to your ~/.emacs.d/init.el
.
(use-package tramp
:config
(setq tramp-default-method "ssh")
(setq tramp-ssh-controlmaster-options
(concat
"-o ControlMaster auto "
"-o ControlPath ~/.ssh/socket-%%C "
))
(setq tramp-use-ssh-controlmaster-options nil)
:defer 1 ; lazy loading
)
Open an Emacs GUI window on your local machine. It doesn’t matter what directory you’re in.
$ emacs
SSH into your remote server, CAEN Linux in this example. This will set up an SSH multiplexing connection.
$ ssh login.engin.umich.edu
...
In Emacs, open the file /ssh:login.engin.umich.edu:main.cpp
. Recall C-x C-f
is find-file
. Tab completion works in the minibuffer. You’re now editing a file main.cpp
on a remote server.
Pair programming with tmux
Pair program on a remote machine with two people inside the same Emacs instance. We’ll use tmux, which is a terminal multiplexer.
Alice connects to a remote server containing her code. She starts a tmux session named shared
. Then, she starts Emacs inside that tmux session.
$ ssh login.engin.umich.edu
$ hostname
caen-vnc-vm05.engin.umich.edu
$ cd p1-stats
$ tmux new -s shared
$ emacs -nw main.cpp
Bob connects to the same remote server that Alice did. He connects to Alice’s tmux session named shared
. She’s already running Emacs, so he sees her Emacs session.
$ ssh caen-vnc-vm05.engin.umich.edu
$ tmux attach -t shared
Text-only Emacs
If you’re on a remote server without a GUI, you can use Emacs in text-only mode. The -nw
option stands for “no window”.
$ emacs -nw
Fast text-only Emacs install
For a light weight text-only Emacs install on a Linux server, use the emacs-nox
package. This is great for small tasks on remote servers.
$ sudo apt-get install emacs-nox
Nano as a fallback
Many servers have two text editors installed by default: vi
and nano
. Because Nano navigation keyboard shortcuts are similar to Emacs, it’s a nice alternative for environments where you need to edit some configuration files, but don’t want to install anything.
$ nano main.cpp
Troubleshooting
To reset all Emacs configuration, plugins, and settings:
$ rm -rf ~/.emacs ~/.emacs.d/
Acknowledgments
Original document written by Andrew DeOrio awdeorio@umich.edu.
This document is licensed under a Creative Commons Attribution-NonCommercial 4.0 License. You’re free to copy and share this document, but not to sell it. You may not share source code provided with this document.