11 KiB
Editor
Configuration and imrpovements to the editor experience within Emacs. Vim1 user? This module extends the keybindings by implementing Evil2. Doom3, Spacemacs4? The all powerful leader key is also implemented right here!
Keybindings
Offer ESC
as an alternative to quit (most) prompts, instead of the default C-g
.
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
Completions
Emacs has a lot of keybindings, sometimes it's useful to just start mashing keys and see what happens. This behaviour exists in a third-party package called which-key5. It displays the current incomplete keybinding input in a mini-buffer, showing available completion options with their corresponding keybindings.
(use-package which-key :diminish which-key-mode :custom (which-key-idle-delay dotfiles/idle) :config (which-key-mode))
Turn Emacs into Vim
Emacs has some strange default keybindings, they're not like any other editor you've likely ever used. To overcome this nearly show-stopping hurdle, we turn Emacs into Vim1 with Evil Mode - The Extensible VI Layer for Emacs2.
(use-package evil :custom (evil-want-integration t) ;; Required for `evil-collection'. (evil-want-keybinding nil) ;; Same as above :config (evil-mode +1))
While covering substantial ground towards our goal, the default keybindings implemented in Evil2 alone are lacking compared to what you would expect from Vim1. There's, of course, a communicated curated package evil-collection6 that does a much better job implementing the proper keybindings.
(use-package evil-collection :after evil :config (evil-collection-init))
Surround text
Whether it's on purpose, or more likely, you forgot an opening brace; evil-surround7 surrounds highlighted blocks of text with functions, quotations, and any symbol you can input.
(use-package evil-surround :after evil :config (global-evil-surround-mode 1))
Toggle comments
When you're in deep with errors, or just trying some new code, it's useful to be able to toggle large comment sections in a language agnostic manner. In comes evil-nerd-commentor8, with a custom binding to M-;
. What is M-
? Typically that refers to the Alt
key, called the Meta
key in Emacs.
(use-package evil-nerd-commenter :after evil :bind ("M-;" . evilnc-comment-or-uncomment-lines))
Implementing the leader key
If you're like me and started with Emacs using a framework like Doom3 or Spacemacs4, you probably have a lot of muscle memory for using SPC
as a leader key. This behaviour is actually not difficult to implement, especially when using general.el9.
-
SPC
in most situations as a prefix key -
C-SPC
when using the Desktop module within anX
buffer
(use-package general :after evil :config (general-create-definer dotfiles/leader :states '(normal motion) :keymaps 'override :prefix dotfiles/leader-key :global-prefix dotfiles/leader-key-global))
Transient bindings
Create transient keybindings with a shared prefix through Hydra10. This is also used by a number of third-party packages as a completion system. An implementation example is available in the Font section of the Interface module.
-
Defer loading for performance
(use-package hydra :defer t)
Place runtime tweaks behind SPC t
(dotfiles/leader "t" '(:ignore t :which-key "Tweaks"))
Cherry picked shortcuts
Implement shortcut bindings, cherry picked from Doom3.
-
Close buffers with
SPC c
-
Find files with
SPC , (comma)
(dotfiles/leader "." '(find-file :which-key "Files") "c" '(kill-buffer-and-window :which-key "Close"))
Managing windows
Window management with SPC w
-
Swap with
w
-
Close with
c
-
Move with
h,j,k,l
-
Split with
s - <motion>
(dotfiles/leader "w" '(:ignore t :which-key "Window") "ww" '(window-swap-states :which-key "Swap") "wc" '(delete-window :which-key "Close") "wh" '(windmove-left :which-key "Left") "wj" '(windmove-down :which-key "Down") "wk" '(windmove-up :which-key "Up") "wl" '(windmove-right :which-key "Right") "ws" '(:ignore t :which-key "Split") "wsj" '(split-window-below :which-key "Down") "wsl" '(split-window-right :which-key "Right"))
Quitting Emacs
Quit Emacs with SPC q
-
Save and quit
q
-
Quit without saving
w
-
Exit the Frame (daemon)
f
(dotfiles/leader "q" '(:ignore t :which-key "Quit") "qq" '(save-buffers-kill-emacs :which-key "Save") "qw" '(kill-emacs :which-key "Now") "qf" '(delete-frame :which-key "Frame"))
Helper functions
Use the built-in describe-*
functionality of Emacs to quickly access documentation for packages, variables, and functions.
-
Run helper functions with
SPC h
-
Packages
p
-
Variables
v
-
Functions
f
-
(dotfiles/leader "h" '(:ignore t :which-key "Help") "hp" '(describe-package :which-key "Package") "hv" '(describe-variable :which-key "Variable") "hf" '(describe-function :which-key "Function"))
File navigation
Emacs has some really cool built-in packages, Dired11 is one of them. It's not perfect out of the box though, there's work to do.
Navigating to the current directory
I don't want to have to press RET
twice to navigate to the current directory. Avoid this behaviour with jump
, included in the dired-x
package that ships with Dired11.
-
Open a new dired buffer with
SPC d
.
(require 'dired-x) (dotfiles/leader "d" '(dired-jump :which-key "Dired"))
Reusing the same buffer
By default Dired11 will create a new buffer every time you press RET
over a directory. This leads to unwanted buffers all over the place. Avoid this behaviour with Dired Single12, reusing the same dired buffer.
-
Move up a directory with
h
-
Open a single buffer with
l
(use-package dired-single :config (evil-collection-define-key 'normal 'dired-mode-map "h" 'dired-single-up-directory "l" 'dired-single-buffer))
Version control
Yet another hallmark feature of Emacs: Magit13 with the darling name, the developer stresses it's supposed to be Magic but with Git14. It's a complete Git14 porcelain within Emacs.
(use-package magit :commands magit-status :custom (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1))
Place keybindings for magit13 behind SPC g
.
-
Clone with
c
-
Status with
g
(dotfiles/leader "g" '(:ignore t :which-key "Magit") "gc" '(magit-clone :which-key "Clone") "gg" '(magit-status :which-key "Status"))
GitHub integration
Deploying the global config
Git14 reads its global config from $HOME/.gitconfig
, create a link to the custom configuration.
(dotfiles/symlink "~/.emacs.d/config/git" "~/.gitconfig")
Terminal emulation
Performing terminal interaction within an editor is a must have, the choices are Eshell17 and Vterm18.
Emacs lisp shell
Another really incredible piece of kit, shipped with Emacs. Eshell17 is a fully POSIX compliant shell written entirely in Emacs Lisp. While not a traditional terminal emulator, it provides me with all of the functionality I expect and require from one. The infamous lambda prompt implemented with the Eshell Prompt Extras19 package.
(use-package eshell-prompt-extras :custom (eshell-highlight-prompt nil) (eshell-prefer-lisp-functions nil) (eshell-prompt-function 'epe-theme-lambda))
-
Open an
eshell
buffer withSPC e
(dotfiles/leader "e" '(eshell :which-key "Shell"))
Interactive terminal
Sometimes Eshell17 just isn't enough. Going through Thinking in C++ for one of my courses requires lots of terminal input which Eshell17 just doesn't handle. Prior to this I was dropping to another TTY interface, but that was cumbersome. Vterm's18 based on an external C library which is blazing fast.
-
Always compile the module
(use-package vterm :commands (vterm-other-window) :custom (vterm-always-compile-module t))
-
Open
vterm
buffer withSPC v
(dotfiles/leader "v" '(vterm-other-window :which-key "Terminal"))
Installing dependencies
Install dependencies on Debian/Ubuntu:
sudo apt install -y cmake \ libtool \ libtool-bin