Using Emacs in a Terminal
2024-08-23 #emacs

Fun fact: a coworker thought I was using a GUI application when they saw my terminal Emacs.
Introduction
At my workplace, most coding tasks must be performed on a remote workstation (or a browser-based IDE) due to policies prohibiting local storage of source code and the limited development tools available on company laptops.
Coding with Emacs on a remote workstation requires access via SSH or a remote desktop connection. I have experimented with various solutions, including Tramp, Chrome Remote Desktop, GTK Broadway, xpra, and wprs. However, these proved buggy, resource-intensive, or slow. Consequently, I settled on the reliable terminal-based approach using SSH and Tmux.
Issues
Initially, I encountered several issues using Emacs in the terminal, as things were not working out-of-the-box:
- Emacs was no longer colorful.
- Some keybindings did not work.
- I could not copy text to the native clipboard.
- Version control diff highlighting was not visible.
- Opening links in a local browser was not easy.
Over time, I discovered solutions and workarounds for these issues and began to enjoy some extra benefits I had not expected:
- Using the same Emacs instance across multiple computers.
- Eliminating Crostini on my Chromebook.
- Reducing the need to synchronize files and resolve conflicts.
- Remote file editing is faster than Tramp.
- Providing a more native terminal experience via Tmux multiplexing (compared to
vterm
,shell
, etc.). - No font size scaling issue.
Solutions
Here's how I configured Emacs for comfortable terminal use.
Pick a Good Terminal Emulator
First, pick a terminal emulator that supports at least:
- true color, and
- OSC 52 (for system clipboard integration).
Ideally, it should have fewer default keybindings or allow customization to avoid conflicts with Emacs.
The default Chrome OS terminal (hterm) is what I currently use, as it meets all three requirements. I do not use Linux, macOS, or Windows frequently enough nowadays to offer recommendations for those platforms.
Some terminals can even display images! E.g., the terminal graphics protocol by Kitty, the inline image protocol by iTerm2, and the Sixel protocol. It would be nice if there were Emacs integration with them!
Use Emacs in a Tmux Session
I use Emacs inside Tmux because it provides a persistent session that can be reattached from any computer or after losing an SSH connection. I also automatically reattach to the Tmux session upon SSH connection with this SSH config:
Host myhost RemoteCommand tmux -u new -A -D -s main RequestTTY yes
Alternative ssh command:
ssh -t myhost tmux -u new -A -D -s main
Alternative shell script approach:
# .bashrc # Attach to the main Tmux session if it is # - in SSH session # - not inside Tmux # - not inside Emacs if [[ -n "$SSH_CLIENT" && -z "$TMUX" && -z "$INSIDE_EMACS" ]]; then # "-A" : reattach if session-name already exists # "-D" : detach other clients (ensure $SSH_TTY is always correct) tmux new -A -D -s main fi
Tmux also allows me to have multiple workspaces using Tmux windows (or sessions).
If I need extra terminals, I split new panes or new windows. I find the Tmux terminal better than Emacs's term
, shell
, vterm
, or eat
, because it is more native, faster, and easily distinguishable from an Emacs buffer.
Also, I can add information like the system status (CPU, RAM, Disk, etc.) and the current time to the Tmux status bar.
Optionally, change the default Tmux leader to reserve C-b
for moving the cursor.
set-option -g prefix M-\
Make Emacs Colorful
The screenshots below show the difference with and without true color (24-bit color) enabled.
Without true color, low contrast | With true color, high contrast |
---|---|
![]() |
![]() |
There are a few ways to get true color in a terminal Emacs session:
- Use a
TERM
that supports true color, e.g.,xterm-direct
. (This won't work inside Tmux, which changes the term totmux-256color
.) - Set the
COLORTERM
environment variable totruecolor
. (preferred)
# .bashrc export COLORTERM=truecolor
There are a few ways to get true color support in Tmux:
- Use a
TERM
that supports true color, e.g.,xterm-direct
, or - Start tmux with the RGB feature, e.g.,
tmux -T RGB
, or - Override the features of your terminal in
.tmux.conf
, e.g.:
# .tmux.conf # See https://github.com/tmux/tmux/wiki/FAQ#how-do-i-use-rgb-colour. set -as terminal-overrides ",xterm-256color:RGB"
Tip: Use this script to test for true color support.
Copy Text to Native Clipboard (OSC 52)
OSC 52 works by printing an unreadable sequence, \033]52;c;[base64 data]\a
, which instructs the terminal to alter the system clipboard with the base64-encoded data. To verify that OSC 52 is working for your terminal setup, run printf "\033]52;c;$(printf \"Hello, world\" | base64)\a"
from the terminal. It should put "Hello, world" into the system clipboard.
In the Emacs config, install the Clipetty package, which sends text that you kill in Emacs to the native clipboard.
;; init.el (use-package clipetty :hook (after-init . global-clipetty-mode))
To enable clipboard support in Tmux, add these lines to .tmux.conf
:
# .tmux.conf set -g set-clipboard on # Required to make Clipetty work better on re-attach by appending # "SSH_TTY" to "update-environment". See # https://github.com/spudlyo/clipetty?tab=readme-ov-file#dealing-with-a-stale-ssh_tty-environment-variable set -ag update-environment "SSH_TTY"
If it still does not work, try running the printf
verification command above and check the Tmux clipboard wiki.
Open Link in Local Browser
I have two workarounds for opening a web link from a remote Emacs session in a local browser:
- Use a mouse click if the terminal emulator can recognize links and open them locally.
- Copy the link to the local clipboard and paste it into the browser.
For (2), I added an advice to browse-url
to place the URL into the native clipboard via OSC 52. I then paste it into a local browser. I also added key and mouse bindings for the function to make copying more seamless.
(define-advice browse-url (:around (orig-fun &rest args) copy-url-if-terminal) (if (display-graphic-p) (apply orig-fun args) (let ((url (nth 0 args))) (message "Clipetty link: %s" url) (clipetty--emit (clipetty--osc url t)))))
See my Emacs configuration for the full and updated version.
Tweak for xterm-paste
When pasting from the native clipboard, I would like to delete the region if one is active.
This is like (delete-selection-mode)
for xterm-paste
.
(define-advice xterm-paste (:before (&args) delete-active-region) "Delete the selected text first before pasting from xterm." (when (use-region-p) (delete-active-region)))
Update Key Maps that Works in Terminal
The idea is to have a set of keybindings that the terminal can respond to.
This part varies from person to person. For example, I have remapped:
C-;
toM-;
forflyspell-correct-wrapper
(C-;
is unsupported).C-c C-,
toC-c ,
fororg-insert-structure-template
(C-,
is unsupported).
Show Diff Highlighting with Margin
diff-hl
does not work in the terminal by default, and this issue had annoyed me for a while until I searched for a solution. It turns out that diff-hl
already has a solution: using the "margin" to show the diff.
I added this Elisp config to turn on diff-hl-margin-mode
whenever I am inside a terminal.
;; init.el (add-hook 'diff-hl-mode-on-hook (lambda () (unless (display-graphic-p) (diff-hl-margin-local-mode))))

Enable Mouse Support
Don't forget to enable mouse support.
Note that there was a conflict where any mouse movement over Emacs would deactivate the Tmux prefix key (this is fixed in Tmux 3.5!). See https://github.com/tmux/tmux/issues/4111.
;; init.el (xterm-mouse-mode +1)
# .tmux.conf # Enables mouse support in Tmux (switching windows and panes, # resizing panes, etc.). Setting mouse on or off does not disable # Emacs's xterm-mouse-mode. set -g mouse on
Conclusion
For most Emacsers, GUI Emacs is still a better choice because it:
- Has no network latency.
- Has better multimedia support (images, PDFs, etc.).
- Can handle all keybindings.
- Can interact with the clipboard natively.
- Can open links in a local browser easily.
- Is more customizable (font size per buffer, tooltips, etc.).
However, if you, like me, need to work remotely or want to use the same Emacs instance across multiple computers via SSH and Tmux, I hope the tricks above can improve your setup, even at the expense of the aforementioned GUI features.
Update on 2025-09: also check out this YouTube video nobody knows that using Emacs in the terminal is so great by Jake B!