This repo was adapted/modified from Uncle Dave’s Emacs, found here: https://github.com/daedreth/UncleDavesEmacs
The majority of the configuration and especially the functions were written by him, so a huge thank you for making my Emacs experience a lot more pleasant.
git clone https://github.com/Keyhenge/emacs-config.git ~/.emacs.d
Running the above command will clone this repository into your Emacs settings, overwriting anything you have there already. I highly recommend backing up your current settings by copying them into another repository (e.g. cp ~/.emacs.d ~/.emacs.d.bak
). You should also read the dependencies section before installing.
I bind control
to caps_lock
and caps_lock
to both shift keys. This frees up left control to be used as Hyper whenever we need Emacs-wide bindings that we know won’t interfere with other modes. To use my setup, copy the following into ~/.Xmodmap and add the command setxkbmap -option ‘shift:both_capslock’ to your ~/.xsession.
clear lock clear control clear mod1 clear mod2 clear mod3 clear mod4 clear mod5 keycode 37 = Hyper_L keycode 66 = Control_L add control = Control_L Control_R add mod1 = Alt_L Alt_R Meta_L add mod2 = Num_Lock add mod3 = Hyper_L add mod4 = Super_L Super_R add mod5 = Mode_switch ISO_Level3_Shift
If you use OSX, the following binds fn to Hyper in Emacs. Consider using Karabiner Elements for further key changes, especially changing caps_lock
to control
.
(setq ns-function-modifier 'hyper)
Alternatively if you like your current setup, find a place to bind hyper as it’s used for many personalized functions in this config.
fira-code
, a very nice, readable font. If you want to use something else, make sure to edit the init.el file.qutebrowser
, a keyboard driven browser.
NOTE: Much of the EXWM section is currently disabled until a later date. You can re-enable it if you wish.
EXWM is a window manager with Emacs as its base. Everything is treated as a buffer, allowing us to use Emacs bindings across the entire system and keep “mode-switching” to a minimum.
xorg-server
, the windowing system ubiquitous among Linux distros, though slowly being replaced by Wayland. Unfortunately, Emacs doesn’t support Wayland as of yet, and there is no EXWM equivalent.pulsemixer
, a CLI/curses mixer for PulseAudio. Used for audio control functions.imagemagick
, a simple image suite we’ll be using to take screenshots with.
- A compositor (recommended, I use
compton
) noto-cjk
, to display foreign languages correctlyslock
, if you want to lock the screen
TRAMP (Transparent Remote Access, Multiple Protocols), is used to ssh into other users and machines. We’ll primarily use it to make edits as root, but it’s also incredibly useful for remote editing.
sudo
, properly configured for your user.
mpd
, to play music
You’ll also need various programs for code completion, REPLs, and style guide enforcement.
clang
, for C/C++ completion.sbcl
, for clisp completion and its REPL.virtualenv
, for python completion.lua
, to run lua code, completion, and REPL.guile
, to run a scheme REPL.
pip install jedi flake8 autopep8
, for code completion and style enforcement.
gopls
, downloaded here.
Helm is an easy way to search your filesystem and pretty much anything in Emacs, while Dired is a more simplistic but still useful view of your directories.
all-the-icons-fonts
, for icons that match file types. This also affects the dashboard.ag
, for grepping/finding strings inside filesavfs
, for looking inside archivespass
, for its helm integration
These are the programs I use to open various file types, feel free to change them in Openwith.
mpv
for video/sound filesimv
for imageslibreoffice
for various documents
mu4e (mu-for-emacs) is a mailing suite inside of Emacs, allowing us to use Emacs’s text editing/movement when composing/reading email.
mu
, which indexes your mail and actually contains mu4egetmail
, which syncs a designated folder with your mailing server via POP or IMAPmsmtp
, for sending mail
mu4e is a bit special in that it requires its dependencies to have already been installed, configured, and run. Check here and here on how to setup getmail, check here for the documentation on both mu and mu4e, and check here for a basic msmtp setup.
This configuration changes the default exit chord of C-x C-c
to C-x C-q
, see Change exit chord.
use-package
automatically downloads and configures all of the packages with minimal effort. Meanwhile, init.el
automatically checks for whether use-package
is installed, and downloads/installs it if it is not.
This config file is saved as a .org file, which is a markup language and one of the best packages in Emacs. At launch, this file is stripped of all of its text save for sections labeled as emacs-lisp, which is then parsed into config.el and used. You can find some more info on Org-mode here, and my custom configuration in the Org section. As such, most sections have some sort of rambling attached explaining what the keybindings are, what packages I’ve added, why things are the way they are, etc. You should read through them to get the full benefit of the configuration. Also, if you do decide to download, try deleting these ramblings and filling them in with your own. Doing so helped me understand each part of the config, customize it further to my liking, and got me more familiar with the programs I was using.
This configuration is intended to be a full configuration for Emacs in terms of text editing/programming/themes/media/etc. However, because all of the configuration is divided into sections that rarely depend on each other, it’s relatively trivial to remove a portion you don’t want without harming the rest of the configuration.
TODO: There are several things that don’t really work in EXWM that’d I’d consider essential, those being:
- A working mpd player (EMMS processes tags incorrectly, Mingus causes blinking on non-emacs buffers while up on any workspace, Bongo doesn’t use mpv correctly, non Emacs-native players not integrating well, etc.)
- Dynamic window management (EXWM defaults to standard Emacs behavior, which is manual tiling)
- A working IME (Fcitx refuses to work in Emacs. Apparently Ubuntu has a package that allows mozc to work inside Emacs but it isn’t currently available on NixOS)
- A bug where the first buffer you open in the first workspace will always be lost when switching to another workspace. This is pretty minor, but it’s annoying to have to do the sacrificial ritual every time I restart.
There are several packages that might fix these issues in the coming years, namely edwina
and EAF
, but they currently aren’t compatible with EXWM or are too buggy. Until then, much of this section will be disabled and I’ll continue with i3.
Everything surrounding EXWM is contained here, as well as a few extra controls which will only be accessible while Emacs is in focus.
EXWM makes Emacs into your window manager, making the entire system far more consistent. Everything is Emacs, so your color scheme applies everywhere. EXWM can fake keypresses to other applications, so you can use the same keybindings everywhere. Everything is a buffer, so you can use your kill ring anywhere.
+BEGIN_SRC emacs-lisp (use-package exwm :ensure t :config ;; necessary to configure exwm manually (require ‘exwm-config)
;; Number of workspaces created when EXWM starts. Even though EXWM creates them dynamically, window loss can occur so I just make them all immediately (setq exwm-workspace-number 10)
;; Set name of new program buffers (add-hook ‘exwm-update-class-hook (lambda () (unless (or (string-prefix-p “sun-awt-X11-” exwm-instance-name) (string= “gimp” exwm-instance-name)) (exwm-workspace-rename-buffer exwm-class-name)))) (add-hook ‘exwm-update-title-hook (lambda () (when (or (not exwm-instance-name) (string-prefix-p “sun-awt-X11-” exwm-instance-name) (string= “gimp” exwm-instance-name)) (exwm-workspace-rename-buffer exwm-title))))
;; Global keybindings. EXWM has the concept of line-mode (which intercepts keys) and char-mode (which doesn’t), but these keys override that and always work. (setq exwm-input-global-keys `( ;; Bind “s-r” to exit char-mode and fullscreen mode. ([?\s-r] . exwm-reset) ;; Bind “s-w” to switch workspace interactively. ([?\s-w] . exwm-workspace-switch) ;; Bind “s-0” to “s-9” to switch to a workspace by its index. ,@(mapcar (lambda (i) `(,(kbd (format “s-%d” i)) . (lambda () (interactive) (exwm-workspace-switch-create ,i)))) (number-sequence 0 9)) ;; Bind “s-&” to launch applications (‘M-&’ also works if the output ;; buffer does not bother you). ([?\s-&] . (lambda (command) (interactive (list (read-shell-command “$ “))) (start-process-shell-command command nil command))) ;; Bind “s-<f2>” to “slock”, a simple X display locker. ([s-f2] . (lambda () (interactive) (start-process “” nil “/usr/bin/slock”)))))
;; an easy way to make keybindings work only in line mode (define-key exwm-mode-map [?\C-q] #’exwm-input-send-next-key)
;; simulation keys are keys that exwm will send to the exwm buffer upon inputting a key combination (exwm-input-set-simulation-keys ‘( ;; movement ([?\C-b] . left) ([?\M-b] . C-left) ([?\C-f] . right) ([?\M-f] . C-right) ([?\C-p] . up) ([?\C-n] . down) ([?\C-a] . home) ([?\C-e] . end) ([?\M-v] . prior) ([?\C-v] . next) ([?\C-d] . delete) ([?\C-k] . (S-end delete)) ;; cut/paste ([?\C-w] . ?\C-x) ([?\M-w] . ?\C-c) ([?\C-y] . ?\C-v) ;; cancel ([?\C-g] . escape) ;; search ([?\C-s] . ?\C-f)))
(add-hook ‘exwm-manage-finish-hook (lambda () (when (and exwm-class-name (string= exwm-class-name “Blender”)) (exwm-input-set-local-simulation-keys nil))))
;; this little bit will make sure that XF86 keys work in exwm buffers as well (dolist (k ‘(XF86AudioLowerVolume XF86AudioRaiseVolume XF86PowerOff XF86AudioMute XF86AudioPlay XF86AudioStop XF86AudioPrev XF86AudioNext XF86ScreenSaver XF68Back XF86Forward Scroll_Lock print)) (cl-pushnew k exwm-input-prefix-keys))
;; this just enables exwm, it started automatically once everything is ready ;(exwm-enable) ) +END_SRC
Gives some useful keybinds while using GNU Icecat in EXWM. This is actually meant for Firefox, but I’ve modified it to work on Icecat instead. To use the original, download it here, and the core here. +BEGIN_SRC emacs-lisp (load “~/.emacs.d/custom/exwm-icecat.el”) (require ‘exwm-icecat) +END_SRC
A great little application launcher that works with helm. +BEGIN_SRC emacs-lisp (use-package dmenu :ensure t :bind (”s-SPC” . ‘dmenu)) +END_SRC
A few useful processes linked to keybinds. The shutdown bind is every modifier key + p, so that you never accidently press it. +BEGIN_SRC emacs-lisp (defun exwm-async-run (name) (interactive) (start-process name nil name))
(defun daedreth/launch-browser () (interactive) (exwm-async-run “”))
(defun daedreth/lock-screen () (interactive) (exwm-async-run “slock”))
(defun daedreth/shutdown () (interactive) (start-process “halt” nil “sudo” “halt”))
(global-set-key (kbd “<H-tab>”) ‘daedreth/launch-browser) (global-set-key (kbd “<H-s-l>”) ‘daedreth/lock-screen) (global-set-key (kbd “<H-s-C-M-p>”) ‘daedreth/shutdown) +END_SRC
A set of controls/settings to manipulate audio from inside Emacs.
Some functions we’ll be using in a second to mute/raise/lower volume. The volume modifier describes how much the volume will be raised or lowered by. +BEGIN_SRC emacs-lisp (defconst volumeModifier “2”) (defun audio/mute () (interactive) (start-process “audio-mute” nil “pulsemixer” “–toggle-mute”))
(defun audio/raise-volume () (interactive) (start-process “raise-volume” nil “pulsemixer” “–change-volume” (concat “+” volumeModifier)))
(defun audio/lower-volume () (interactive) (start-process “lower-volume” nil “pulsemixer” “–change-volume” (concat “-” volumeModifier))) +END_SRC
I have a couple dedicated audio keys on my keyboard, which I bind the above functions to here. That being said, these are the only dedicated audio keys I have, so other audio keybinds (like those defined in Media) are bound to function keys. +BEGIN_SRC emacs-lisp (global-set-key (kbd “<XF86AudioMute>”) ‘audio/mute) (global-set-key (kbd “<XF86AudioRaiseVolume>”) ‘audio/raise-volume) (global-set-key (kbd “<XF86AudioLowerVolume>”) ‘audio/lower-volume) +END_SRC
Gives us basic screenshot capabilities.
Bound to <Print Screen>. +BEGIN_SRC emacs-lisp (defun daedreth/take-screenshot () “Takes a fullscreen screenshot of the current workspace” (interactive) (when window-system (loop for i downfrom 3 to 1 do (progn (message (concat (number-to-string i) “…”)) (sit-for 1))) (message “Cheese!”) (sit-for 1) (start-process “screenshot” nil “import” “-window” “root” (concat (getenv “HOME”) “/” (subseq (number-to-string (float-time)) 0 10) “.png”)) (message “Screenshot taken!”))) (global-set-key (kbd “<print>”) ‘daedreth/take-screenshot) +END_SRC
Bound to <Scroll Lock>, which I can practically guarantee you don’t use. +BEGIN_SRC emacs-lisp (defun daedreth/take-screenshot-region () “Takes a screenshot of a region selected by the user.” (interactive) (when window-system (call-process “import” nil nil nil “.newScreen.png”) (call-process “convert” nil nil nil “.newScreen.png” “-shave” “1x1” (concat (getenv “HOME”) “/” (subseq (number-to-string (float-time)) 0 10) “.png”)) (call-process “rm” nil nil nil “.newScreen.png”))) (global-set-key (kbd “<Scroll_Lock>”) ‘daedreth/take-screenshot-region) +END_SRC
I use Qutebrowser. Qutebrowser now has basic adblocking/uMatrix(jMatrix) support, making it viable for everyday browsing. However it’s still fairly rocky and doesn’t block everything, so if I need more privacy/blocking I fall back to a hardened Firefox.
(setq browse-url-browser-function 'browse-url-generic
browse-url-generic-program "qutebrowser")
;; Emacs as a daemon, use "emacsclient <filename>" to seamlessly edit files from the terminal directly in the exwm instance
(server-start)
Emacs is a great text editor that can be even better if you actually use it properly. That means remembering the keybindings for whatever task you’re doing and using them as often as possible. These configs aim to make those even more useful and waste as little of your time as possible.
(use-package ivy
:ensure t)
This setting should make Emacs never re-center the cursor while scrolling down, instead scrolling line-by-line as you would expect.
(setq scroll-conservatively 100)
(global-set-key (kbd "M-l") 'goto-line)
No matter what you’re doing in Emacs, you WILL frequently forget what key does what. Fortunately, Emacs is self documenting and allows you to search for specific functions/describe key combinations. Even more fortunately, the which-key
package will automatically open a small buffer at the bottom of the screen showing all possible completions of a command.
(use-package which-key
:ensure t
:config
(which-key-mode))
Many people, myself included, have multiple screens, work with more than 2 files at once, etc. that makes the default windowing behavior of buffers annoying and cumbersome. These small enhancements make those annoyances disappear.
Cycling through all of your buffers with C-x o
is tiresome. How about we press it once, have all available buffers display a letter, then press that letter to get to that specific buffer? We’ll also make the letters they display easily accessible, starting with the home-row keys.
(use-package switch-window
:ensure t
:config
(setq switch-window-input-style 'minibuffer)
(setq switch-window-increase 4)
(setq switch-window-threshold 2)
(setq switch-window-shortcut-style 'qwerty)
(setq switch-window-qwerty-shortcuts
'("a" "s" "d" "f" "g" "h" "j" "k" "l" ";" "w" "e" "r" "u" "i" "o"))
:bind
([remap other-window] . switch-window))
Whenever you split your window, your focus will now be on the newly created window. After all, if you’re making a new buffer, surely you want to do something with it right?
(defun split-and-follow-horizontally ()
(interactive)
(split-window-below)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 2") 'split-and-follow-horizontally)
(defun split-and-follow-vertically ()
(interactive)
(split-window-right)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 3") 'split-and-follow-vertically)
A much better searching package than the default. Shows a preview of instances of the search text, as well as their line numbers.
(use-package swiper
:ensure t
:bind ("C-s" . 'swiper))
Buffers contain just about everything in Emacs, so we should make them better.
C-x k
should always kill the buffer that currently has focus.
(defun kill-current-buffer ()
"Kills the current buffer."
(interactive)
(kill-buffer (current-buffer)))
(global-set-key (kbd "C-x k") 'kill-current-buffer)
(global-set-key (kbd "C-x b") 'ibuffer)
Sets Ctrl+Mod+Super+k
to kill all buffers. The key combination should ensure that you never accidently do this.
(defun close-all-buffers ()
"Kill all buffers without regard for their origin."
(interactive)
(mapc 'kill-buffer (buffer-list)))
(global-set-key (kbd "C-M-s-k") 'close-all-buffers)
Many commands in Emacs are more useful when you specify how many times you want to do them. Making line numbers relative relieves you of the stress of calculating how many lines you want to affect when doing such a command.
(use-package linum-relative
:ensure t
:config
(setq linum-relative-current-symbol "")
(add-hook 'prog-mode-hook 'linum-relative-mode))
Helm is another extremely useful package that is used almost everywhere. Efficient fuzzy-finding, directory navigating, command searching, file system editing, it has it all. It’s no joke when I say this can almost replace your file manager.
(use-package helm
:ensure t
:bind
("C-x C-f" . 'helm-find-files)
("C-x C-b" . 'helm-buffers-list)
("M-x" . 'helm-M-x)
:config
(defun daedreth/helm-hide-minibuffer ()
(when (with-helm-buffer helm-echo-input-in-header-line)
(let ((ov (make-overlay (point-min) (point-max) nil nil t)))
(overlay-put ov 'window (selected-window))
(overlay-put ov 'face
(let ((bg-color (face-background 'default nil)))
`(:background ,bg-color :foreground ,bg-color)))
(setq-local cursor-type nil))))
(add-hook 'helm-minibuffer-set-up-hook 'daedreth/helm-hide-minibuffer)
(setq helm-autoresize-max-height 0
helm-autoresize-min-height 40
helm-M-x-fuzzy-match t
helm-buffers-fuzzy-matching t
helm-recentf-fuzzy-match t
helm-semantic-fuzzy-match t
helm-imenu-fuzzy-match t
helm-split-window-in-side-p nil
helm-move-to-line-cycle-in-source nil
helm-ff-search-library-in-sexp t
helm-scroll-amount 8
helm-echo-input-in-header-line t)
(add-to-list 'helm-completing-read-handlers-alist
'(dired . nil))
:init
(helm-mode 1))
(use-package helm-projectile
:ensure t
:bind
("C-x C-z" . 'helm-projectile)
:config
(helm-projectile-on))
; Helm interface to pass, a password manager
(use-package helm-pass
:ensure t)
(require 'helm-config)
(helm-autoresize-mode 1)
(define-key helm-find-files-map (kbd "C-b") 'helm-find-files-up-one-level)
(define-key helm-find-files-map (kbd "C-f") 'helm-execute-persistent-action)
Let’s say you’re writing an essay and you spot a typo a few paragraphs up. You could go up by paragraph, then navigate to the line, and then the word, then the letter OR you could just press M-s
, type the character you want to jump to, type the 2-3 character string which pops up that differentiates it from the other occurences of the character, and now you’re there. 10s of key presses reduced to 3-4.
(use-package avy
:ensure t
:bind
("M-s" . avy-goto-char))
As Emacs is a text editor, we should make some improvements to how you edit text.
Replace All is an incredibly common use case, so let’s have 2 ways of doing it. If you want to specify some number of occurrences to replace after the current one, simply do C-<number> C-c q
. If you want to edit all occurrences in the file, either place the cursor on a word or highlight a region and then do C-;
, edit, then press C-;
again to finish.
(use-package mark-multiple
:ensure t
:bind ("C-c q" . 'mark-next-like-this))
(use-package iedit
:ensure t)
I have never understood why “kill-word” doesn’t kill the entire word. Therefore, here’s a function that does kill the entire word, and replaces the default keybinding.
(defun daedreth/kill-inner-word ()
"Kills the entire word your cursor is in. Equivalent to 'ciw' in vim."
(interactive)
(forward-char 1)
(backward-word)
(kill-word 1))
(global-set-key (kbd "M-d") 'daedreth/kill-inner-word)
Copies the word your cursor is currently on.
(defun daedreth/copy-whole-word ()
(interactive)
(save-excursion
(forward-char 1)
(backward-word)
(kill-word 1)
(yank)))
(global-set-key (kbd "C-c c") 'daedreth/copy-whole-word)
Copies the whole line the cursor is on.
(defun daedreth/copy-whole-line ()
"Copies a line without regard for cursor position."
(interactive)
(save-excursion
(kill-new
(buffer-substring
(point-at-bol)
(point-at-eol)))))
(global-set-key (kbd "C-c l") 'daedreth/copy-whole-line)
Kills the whole like the cursor is on.
(global-set-key (kbd "C-c k") 'kill-whole-line)
Just some minor things that help you out once in a while.
Something I find myself doing too often is moving to press C-x
and accidently pressing C-x C-c
, closing Emacs, which is quite annoying. This changes it to C-x C-q
, overwriting a command I never use (read-only mode) and making it harder to make that mistake.
(global-set-key (kbd "C-x C-q") 'save-buffers-kill-terminal)
(global-unset-key (kbd "C-x C-c"))
It’s often cumbersome to go looking for this file, so binding it to H-c e
means you can instantly access it.
(defun config-visit ()
(interactive)
(find-file "~/.emacs.d/config.org"))
(global-set-key (kbd "H-c e") 'config-visit)
Rather than typing out config-reload
into M-x
, we’ll just bind it to H-c r
(defun config-reload ()
"Reloads ~/.emacs.d/config.org at runtime"
(interactive)
(org-babel-load-file (expand-file-name "~/.emacs.d/config.org")))
(global-set-key (kbd "H-c r") 'config-reload)
Makes Emacs treat camelCasedWords as separate words.
(global-subword-mode 1)
Whenever you enter one of these characters, the corresponding character is also added. Very convenient for programming.
(setq electric-pair-pairs '(
(?\{ . ?\})
(?\( . ?\))
(?\[ . ?\])
(?\" . ?\")
))
(electric-pair-mode t)
Changing buffers, windows, moving up/down with M-v
and C-v
etc. dramatically alters the cursor’s position. This will briefly highlight the line it moved to.
(use-package beacon
:ensure t
:config
(beacon-mode 1))
Any time you enter a hexadecimal that resembles a color code, it will automatically highlight the code with that color. See Dired Rainbow (while running this config in your Emacs) for an example.
(use-package rainbow-mode
:ensure t
:init
(add-hook 'prog-mode-hook 'rainbow-mode))
Highlights matching parens and brackets according to their depth.
(show-paren-mode 1)
Expands the region you’re highlighting to the next logical step.
(use-package expand-region
:ensure t
:bind ("C-q" . er/expand-region))
Gets rid of all whitespace until the next non-whitespace character is encountered. This may not be to your taste, in which case I recommend you bind it to some combination of a modifying key and backspace.
(use-package hungry-delete
:ensure t
:config
(global-hungry-delete-mode))
Deletes everything up to a character you choose. Similar to avy’s ace-jump, except it deletes everything inbetween you and the character while doing it.
(use-package zzz-to-char
:ensure t
:bind ("M-z" . zzz-up-to-char))
Allows you to export your buffer to HTML while respecting your tabs, theming, fonts, etc.
(use-package htmlize
:ensure t)
Whenever you’re editing system files, it’s nice to have a shortcut so you don’t have to go through tramp for privileges.
(use-package sudo-edit
:ensure t
:bind
("H-e" . sudo-edit))
The kill ring is your clipboard in Emacs. Whenever you kill or copy a word, it’s added to the kill ring, which can be accessed with M-y
.
Doubles the size of the default kill ring.
(setq kill-ring-max 120)
Default Emacs behavior is to cycle through the kill ring with M-y
. This changes it so that M-y
brings up a popup, where you can preview and select what you want to paste.
(use-package popup-kill-ring
:ensure t
:bind ("M-y" . popup-kill-ring))
Part of the reason to move to Emacs over other text editors is all of the great replacements for standard terminal programs. Sometimes you still need access to a shell for various commands though, and eshell is a great replacement for bash/zsh/fish that integrates directly with helm.
Command completion isn’t that great in eshell, so let’s leech from the great completion fish provides.
(use-package fish-completion
:ensure t)
(when (and (executable-find "fish")
(require 'fish-completion nil t))
(global-fish-completion-mode))
(add-hook 'eshell-mode-hook
(lambda ()
(eshell-cmpl-initialize)
(define-key eshell-mode-map [remap eshell-pcomplete] 'helm-esh-pcomplete)
(define-key eshell-mode-map (kbd "M-p") 'helm-eshell-history)))
(setq helm-show-completion-display-function #'helm-show-completion-default-display-function)
(global-set-key (kbd "<H-return>") 'eshell)
Generally I want to use eshell for its Emacs integration, and use a terminal emulator for curses programs. However, there are still a few times where I want a shell, Emacs integration, and POSIX compliance.
For the rare times I need to use a terminal in Emacs that isn’t eshell, it should at least be using zsh. This used to be fish, but eshell replacing most of my shell use means it’s better to have a POSIX compliant shell.
(defvar my-term-shell "/bin/zsh")
(defadvice ansi-term (before force-zsh)
(interactive (list my-term-shell)))
(ad-activate 'ansi-term)
Dired is the default Emacs file manager. Below are some customizations for it.
(use-package dired
:ensure nil
:delight "Dired "
:custom
(dired-auto-revert-buffer t) ;; Refreshes the dired buffer upon revisiting
(dired-dwim-target t) ;; If two dired buffers are open, save in the other when trying to copy
(dired-hide-details-hide-symlink-targets nil) ;; Don't hide symlink targets
(dired-listing-switches "-alh") ;; Have dired view all folders, in lengty format, with data amounts in human readable format
(dired-ls-F-marks-symlinks nil) ;; Informs dired about how 'ls -lF' marks symbolic links, see help page for more details
(dired-recursive-copies 'always)) ;; Always copy recursively without asking
Makes it easier to differentiate files in dired, making it a lot more pleasant.
(use-package all-the-icons
:ensure t)
(use-package all-the-icons-dired
:after all-the-icons
:hook dired)
(with-eval-after-load 'all-the-icons-dired
(defun ess/dired-subtree-icons ()
(dired-subtree-down)
(dired-subtree-narrow)
(when (fboundp 'dired-insert-set-properties)
(let ((inhibit-read-only t)
(ov (dired-subtree--get-ov)))
(dired-insert-set-properties (overlay-start ov) (overlay-end ov))))
(all-the-icons-dired--reset)
(all-the-icons-dired--display)
(widen))
(remove-hook 'dired-subtree-after-insert-hook 'dired-subtree--after-insert)
(add-hook 'dired-subtree-after-insert-hook 'ess/dired-subtree-icons))
(use-package dired-hacks-utils
:ensure t)
Dired hacks is a collection of utilities and improvements to dired. The ones I use are:
Filters allow you to group files/directories in dired in a number of different ways, including regular expressions and predefined groups. Simply activating grouping is bound to C-f
while marking files with a filter is done with C-j
.
(use-package dired-filter
:ensure t
:config
(define-key dired-mode-map (kbd "C-f") dired-filter-map)
(define-key dired-mode-map (kbd "C-j") dired-filter-mark-map))
avfs allows dired to browse archives.
(use-package dired-avfs
:ensure t)
Lets you open subdirectories in a dired buffer. <Tab>
and <Backtab>
cycle depth while the C-,
prefix gives you access to subdirectory functions.
(use-package dired-subtree
:ensure t
:bind (:map dired-mode-map
("<backtab>" . dired-subtree-cycle)
("<tab>" . dired-subtree-toggle)
("C-, i" . dired-subtree-insert)
("C-, r" . dired-subtree-remove)
("C-, v" . dired-subtree-revert)
("C-, t" . dired-subtree-narrow)
("C-, p" . dired-subtree-up)
("C-, n" . dired-subtree-down)
("C-, f" . dired-subtree-next-sibling)
("C-, b" . dired-subtree-previous-sibling)
("C-, a" . dired-subtree-beginning)
("C-, e" . dired-subtree-end)
("C-, m" . dired-subtree-mark-subtree)
("C-, u" . dired-subtree-unmark-subtree)))
Not actually ranger, but brings some useful features like multi-stage copy-pasting and bookmarks. As a quick note, the bookmarks aren’t persistent across Emacs sessions.
(use-package dired-ranger
:ensure t
:bind (:map dired-mode-map
("C-w" . dired-ranger-copy)
("C-y" . dired-ranger-paste)
("M-y" . dired-ranger-move)
("`" . dired-ranger-bookmark-visit)
("M-b" . dired-ranger-bookmark)))
Collapses nested directories with only one file in them to just point to that file. For example, where the path /foo/bar/file.org took 3 clicks before, it now takes one.
(use-package dired-collapse
:ensure t
:config
(add-hook 'dired-mode-hook 'dired-collapse-mode))
Controls the colors of various files found in dired.
(use-package dired-rainbow
:ensure t
:config
(progn
(dired-rainbow-define-chmod directory "#61afef" "d.*")
(dired-rainbow-define shell "#fcf4c3" ("awk" "bash" "bat" "sed" "sh" "zsh" "vim" "ini" "conf"))
(dired-rainbow-define html "#ff8070" ("css" "less" "sass" "scss" "htm" "html" "jhtm" "mht" "eml" "mustache" "xhtml"))
(dired-rainbow-define xml "#ddbd78" ("xml" "xsd" "xsl" "xslt" "wsdl" "bib" "json" "msg" "pgn" "rss" "yaml" "yml" "rdata"))
(dired-rainbow-define document "#c678dd" ("docm" "doc" "docx" "odb" "odt" "pdb" "pdf" "ps" "rtf" "djvu" "epub" "odp" "ppt" "pptx"))
(dired-rainbow-define markdown "#da8548" ("org" "etx" "info" "markdown" "md" "mkd" "nfo" "pod" "rst" "tex" "textfile" "txt"))
(dired-rainbow-define database "#005f87" ("xlsx" "xls" "csv" "accdb" "db" "mdb" "sqlite" "nc"))
(dired-rainbow-define media "#98be65" ("mp3" "mp4" "MP3" "MP4" "avi" "mpeg" "mpg" "flv" "ogg" "mov" "mid" "midi" "wav" "aiff" "flac"))
(dired-rainbow-define image "#9eac8c" ("tiff" "tif" "cdr" "gif" "ico" "jpeg" "jpg" "png" "psd" "eps" "svg"))
(dired-rainbow-define log "#687080" ("log"))
(dired-rainbow-define interpreted "#ff6464" ("py" "ipynb" "rb" "pl" "t" "msql" "mysql" "pgsql" "sql" "r" "clj" "cljs" "scala" "js"))
(dired-rainbow-define compiled "#ff6464" ("asm" "cl" "lisp" "el" "c" "h" "c++" "h++" "hpp" "hxx" "m" "cc" "cs" "cp" "cpp" "go" "f" "for" "ftn" "f90" "f95" "f03" "f08" "s" "rs" "hi" "hs" "pyc" ".java"))
(dired-rainbow-define executable "PeachPuff3" ("exe" "msi"))
(dired-rainbow-define compressed "#b33c49" ("7z" "zip" "bz2" "tgz" "txz" "gz" "xz" "z" "Z" "jar" "war" "ear" "rar" "sar" "xpi" "apk" "xz" "tar"))
(dired-rainbow-define packaged "#afaf87" ("deb" "rpm" "apk" "jad" "jar" "cab" "pak" "pk3" "vdf" "vpk" "bsp"))
(dired-rainbow-define encrypted "#87af5f" ("gpg" "pgp" "asc" "bfe" "enc" "signature" "sig" "p12" "pem"))
(dired-rainbow-define fonts "#5fafff" ("afm" "fon" "fnt" "pfb" "pfm" "ttf" "otf"))
(dired-rainbow-define partition "#ff2727" ("dmg" "iso" "bin" "nrg" "qcow" "toast" "vcd" "vmdk" "bak"))
(dired-rainbow-define vc "Orange" ("git" "gitignore" "gitattributes" "gitmodules"))
(dired-rainbow-define-chmod executable-unix "#38c172" "-.*x.*")))
PDF tools allows us to view/edit pdfs.
(use-package pdf-tools
:ensure t)
Configures Emacs to always open certain file extensions with certain programs. While dired hacks gives us dired-open, I prefer to use this since it applies to everything Emacs tries to open, whether it’s through dired or not.
(use-package openwith
:ensure t
:config
(setq openwith-associations
(list
(list (openwith-make-extension-regexp
'("mpg" "mpeg" "mp3" "mp4" "opus"
"avi" "wmv" "wav" "mov" "flv"
"ogm" "ogg" "mkv" "webm" "opus"))
"mpv"
'(file))
(list (openwith-make-extension-regexp
'("xbm" "pbm" "pgm" "ppm" "pnm"
"png" "gif" "bmp" "tif" "jpeg" "jpg"))
"imv"
'(file))
(list (openwith-make-extension-regexp
'("doc" "xls" "ppt" "odt" "ods" "odg" "odp"))
"libreoffice"
'(file))
))
(openwith-mode 1)
)
Lets you view the disk usage of various files and folders from Emacs, in a similar view to Dired.
(use-package disk-usage
:ensure t)
I use NixOS, which is a distro that utilizes transactional package management and makes an effort to give reproducible builds. The package manager behind it, Nix (as well as Guix!), can be installed on any Linux distro.
(use-package nix-mode
:ensure t)
(use-package nixos-options
:ensure t)
(use-package helm-nixos-options
:ensure t
:bind
("C-c C-n" . 'helm-nixos-options))
(use-package company-nixos-options
:ensure t
:config
(add-to-list 'company-backends 'company-nixos-options))
(use-package nix-sandbox
:ensure t)
(defun nixos-config-visit ()
(interactive)
(find-file "/etc/nixos/configuration.nix"))
(global-set-key (kbd "H-c n") 'nixos-config-visit)
While Emacs is great for general text editing among many other features, let’s be real: if you’re reading this, you’re a programmer. Therefore, we need some accessories to greatly improve the general programming workflow.
Projectile is a flexible project manager that allows you to perform a lot of arbitrary actions, anything from running tests to replacing text project-wide. It automatically recognizes anything being tracked by a VCS as a project.
Allows any folder to be considered a project. Also maps all projectile commands to C-c p
. Also, don’t forget C-x C-z
to use helm to search over a projectile project!
(use-package projectile
:ensure t
:init
(projectile-mode 1)
:bind
("C-c p" . 'projectile-command-map))
Binds F5 to compile your project via a Makefile in the root directory.
(global-set-key (kbd "<f5>") 'projectile-compile-project)
Yasnippet gives you access to a bunch of different templates that you can use to quickly define parts of a project. You put in the first few letters of what you want, hit tab
, and suddenly a template you can fill out appears. Press tab
while editing the template to jump to the next “part” of the form (like the function name -> parameters -> returned types). C-M-y
brings up a table of the available snippets for your current major mode. C-c &
is the prefix for various snippet editing commands, like defining new ones or inserting an arbitrary snippet.
(use-package yasnippet
:ensure t
:hook (go-mode . yas-minor-mode)
:config
(use-package yasnippet-snippets
:ensure t)
(yas-reload-all))
(global-set-key (kbd "C-M-y") 'yas-describe-tables)
A programmer’s best friend, checks for syntax and styling errors.
(use-package flycheck
:ensure t)
Text completion, another great tool. Use M-n
and M-p
to cycle through suggestions and Return
to choose one (or M-<num>
to choose one of the first 10). You may want to set the delay to be lower if you use completion a lot.
(use-package company
:ensure t
:config
(setq company-idle-delay 1)
(setq company-minimum-prefix-length 3))
(with-eval-after-load 'company
(define-key company-active-map (kbd "SPC") #'company-abort))
;; company-lsp integrates company mode completion with lsp-mode.
;; completion-at-point also works out of the box but doesn't support snippets.
(use-package company-lsp
:ensure t
:commands company-lsp)
(defun tab-indent-or-complete ()
(interactive)
(if (minibufferp)
(minibuffer-complete)
(if (or (not yas-minor-mode)
(null (do-yas-expand)))
(if (check-expansion)
(company-complete-common)
(indent-for-tab-command)))))
(global-set-key [backtab] 'tab-indent-or-complete)
Git is used just about everywhere, and magit makes it easy to use from inside Emacs. M-g
to pull it up, I recommend reading the manual or the M-h m
page, there’s a lot to learn.
(use-package magit
:ensure t
:config
(setq magit-push-always-verify nil)
(setq git-commit-summary-max-length 50)
:bind
("M-g" . magit-status))
The language server protocol is where you connect to an external program that provides all of the syntax checking and suggestions for a language, developed because people keep making new editors and developers have given up writing new implementations for each. Should have just stuck with Emacs/vi…
While this doesn’t matter for older languages like Python and C that already have rich ecosystems in Emacs, Go requires it.
(use-package lsp-mode
:ensure t
:commands (lsp lsp-deferred)
:hook (go-mode . lsp-deferred))
;; Set up before-save hooks to format buffer and add/delete imports.
;; Make sure you don't have other gofmt/goimports hooks enabled.
(defun lsp-go-install-save-hooks ()
(add-hook 'before-save-hook #'lsp-format-buffer t t)
(add-hook 'before-save-hook #'lsp-organize-imports t t))
(add-hook 'go-mode-hook #'lsp-go-install-save-hooks)
;; Optional - provides fancier overlays.
(use-package lsp-ui
:ensure t
:commands lsp-ui-mode)
Packages and settings that make working in specific languages easier.
(add-hook 'c++-mode-hook 'yas-minor-mode)
(add-hook 'c-mode-hook 'yas-minor-mode)
;; (use-package flycheck-clang-analyzer
;; :ensure t
;; :config
;; (with-eval-after-load 'flycheck
;; (require 'flycheck-clang-analyzer)
;; (flycheck-clang-analyzer-setup)))
(with-eval-after-load 'company
(add-hook 'c++-mode-hook 'company-mode)
(add-hook 'c-mode-hook 'company-mode))
(use-package company-c-headers
:ensure t)
(use-package company-irony
:ensure t
:config
(setq company-backends '((company-c-headers
company-dabbrev-code
company-irony))))
(use-package irony
:ensure t
:config
(add-hook 'c++-mode-hook 'irony-mode)
(add-hook 'c-mode-hook 'irony-mode)
(add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options))
(add-hook 'python-mode-hook 'yas-minor-mode)
(add-hook 'python-mode-hook 'flycheck-mode)
(with-eval-after-load 'company
(add-hook 'python-mode-hook 'company-mode))
(use-package company-jedi
:ensure t
:config
(require 'company)
(add-to-list 'company-backends 'company-jedi))
(defun python-mode-company-init ()
(setq-local company-backends '((company-jedi
company-etags
company-dabbrev-code))))
(use-package company-jedi
:ensure t
:config
(require 'company)
(add-hook 'python-mode-hook 'python-mode-company-init))
(use-package paredit
:ensure t)
(add-hook 'emacs-lisp-mode-hook 'yas-minor-mode)
(add-hook 'emacs-lisp-mode-hook 'company-mode)
(add-hook 'emacs-lisp-mode-hook 'paredit-mode)
(use-package geiser
:ensure t)
;;(add-hook 'scheme-mode-hook 'run-guile)
(add-hook 'scheme-mode-hook 'paredit-mode)
(add-hook 'scheme-mode-hook 'yas-minor-mode)
(add-hook 'scheme-mode-hook 'company-mode)
(add-hook 'shell-mode-hook 'yas-minor-mode)
(add-hook 'shell-mode-hook 'flycheck-mode)
(add-hook 'shell-mode-hook 'company-mode)
(defun shell-mode-company-init ()
(setq-local company-backends '((company-shell
company-shell-env
company-etags
company-dabbrev-code))))
(use-package company-shell
:ensure t
:config
(require 'company)
(add-hook 'shell-mode-hook 'shell-mode-company-init))
(add-hook 'lua-mode-hook 'yas-minor-mode)
(add-hook 'lua-mode-hook 'flycheck-mode)
;;; this will download the necessary modules from git
(let (value)
(dolist (element '("love" "lua") value)
(unless (file-directory-p (concatenate 'string (getenv "HOME") "/.emacs.d/auto-complete-" element))
(shell-command (format "git clone %s %s" (concatenate 'string
"https://github.com/rolpereira/auto-complete-" element ".el")
(concatenate 'string (getenv "HOME") "/.emacs.d/auto-complete-" element) nil)))
(add-to-list 'load-path (expand-file-name (concatenate 'string "~/.emacs.d/auto-complete-" element)))))
(require 'auto-complete-love)
(require 'auto-complete-lua)
;;; repl!
(add-hook 'lua-mode-hook '(lambda ()
(local-set-key (kbd "C-c C-s") 'lua-show-process-buffer)
(local-set-key (kbd "C-c C-h") 'lua-hide-process-buffer)))
;;; ac > company
(use-package auto-complete
:ensure t
:config
(setq ac-use-menu-map t)
(setq ac-ignore-case nil)
(define-key ac-menu-map "\C-n" 'ac-next)
(define-key ac-menu-map "\C-p" 'ac-previous))
;;; this will be changed, it's good enough for now
(add-hook 'lua-mode-hook '(lambda ()
(setq ac-sources '(ac-source-love
ac-source-lua
ac-source-abbrev
ac-source-words-in-same-mode-buffers))
(auto-complete-mode)))
(add-hook 'lua-mode-hook 'auto-complete-mode)
;;; I don't even know all the functionality
(use-package love-minor-mode
:ensure t
:config
(add-hook 'lua-mode-hook 'love-minor-mode))
;;; behold, perfection :°
(global-set-key (kbd "<f9>") '(lambda () (interactive) (start-process "love-play-game" nil "love" default-directory)))
;; Set environment variables. Needed for the major mode/LSP to see go commands
(setenv "PATH"
(concat
"/usr/local/bin" ":"
"usr/local/go/bin" ":"
(getenv "PATH")
":" (getenv "HOME") "/go/bin"))
(setenv "GOPATH" (concat (getenv "HOME") "/go"))
(setenv "GO111MODULE" "on")
(use-package go-mode
:ensure t)
As much as I like org mode, it can’t replace things like JSON, XML, or YAML, so we need some syntax checking for them.
(use-package yaml-mode
:ensure t
:config
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
(add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode))
(add-hook 'yaml-mode-hook
'(lambda ()
(define-key yaml-mode-map "\C-m" 'newline-and-indent))))
The most useful mode in Emacs, bar none. This entire document is written in it, my schedule is written it, my contact book is written in it, my papers are written in it, etc.
(setq org-ellipsis "…") ;; Sets the character that comes after headings if they are collapsed
(setq org-src-fontify-natively t) ;; Gives code blocks in org files proper highlighting
(setq org-src-tab-acts-natively t) ;; When in a code block, makes tab operate as if it were in that language's major mode
(setq org-confirm-babel-evaluate nil) ;; Disables y/n check when evaluating code in Org buffers
(setq org-export-with-smart-quotes t) ;; Treats double quotes as primary quotes, single quotes as secondary quotes, and single quote marks as apostrophes when exporting
(setq org-src-window-setup 'current-window) ;; When editing code blocks with =C-c '=, open editing in current buffer
(add-hook 'org-mode-hook 'org-indent-mode) ;; Always have indent mode active in org mode
Always wrap lines in org mode.
(add-hook 'org-mode-hook
'(lambda ()
(visual-line-mode 1)))
Pressing C-c '
while in a code block will pull up that code in its own buffer with the appropriate major mode activated.
(global-set-key (kbd "C-c '") 'org-edit-src-code)
Replaces the asterisks you usually get in Org mode with more visually interesting bullets.
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode))))
Great for editing this document in particular. If you ever need to add a new block of code just type “<el” and then hit Tab
.
(add-to-list 'org-structure-template-alist
'("el" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC"))
Adds the ability to export your org documents to LaTeX.
(when (file-directory-p "/usr/share/emacs/site-lisp/tex-utils")
(add-to-list 'load-path "/usr/share/emacs/site-lisp/tex-utils")
(require 'xdvi-search))
If you really want to stay organized, I highly recommend starting an agenda.org file and adding tasks and deadlines, then adding it to the org agenda list. Once you do both, you can pull up a 17 day summary (3 days before and two weeks ahead) of your schedule with H-a
. This config assumes you’re setting it up in ~/.local/org-files/agenda.org.
(global-set-key (kbd "H-a") 'org-agenda-list)
(setq org-agenda-start-day "-3d")
(setq org-agenda-span 17)
(defun agenda-visit ()
(interactive)
(find-file "~/.local/org-files/agenda.org"))
(global-set-key (kbd "H-c a") 'agenda-visit)
Interfaces for several messaging clients. Remember, we want to be using Emacs any time we’re editing text. Still need to add a matrix client.
mu4e is a search based mail client that can be used inside Emacs.
(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e")
(require 'mu4e)
(setq mu4e-maildir (expand-file-name "~/maildir") ;; top-level Maildir
mu4e-sent-folder "/sent" ;; folder for sent messages
mu4e-drafts-folder "/drafts" ;; unfinished messages
mu4e-trash-folder "/trash" ;; trashed messages
mu4e-refile-folder "/archive" ;; saved messages
user-mail-address "key@keyhenge.xyz"
mu4e-attachment-dir (expand-file-name "~/maildir/attachments")
mu4e-get-mail-command "getmail --getmaildir ~/.config/getmail --rcfile main --rcfile alt --rcfile job"
mu4e-update-interval 900
mu4e-change-filenames-when-moving t ;;
smtpmail-queue-mail nil ;; start in normal mode
smtpmail-queue-dir (expand-file-name "~/maildir/queue/cur"))
(setq mail-user-agent 'mu4e-user-agent)
(add-hook 'message-mode-hook 'auto-fill-mode)
(setq mu4e-compose-format-flowed t)
(setq visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow))
(add-hook 'mu4e-view-mode-hook 'visual-line-mode)
(use-package visual-fill-column
:ensure t
:config
(add-hook 'mu4e-view-mode-hook 'visual-fill-column-mode))
;; Get alerts when important mail comes in
(use-package mu4e-alert
:ensure t
:after mu4e
:init
(setq mu4e-alert-interesting-mail-query
(concat
"flag:unread maildir:/accounts"
"OR "
"flag:unread maildir:/key"))
(add-hook 'after-init-hook #'mu4e-alert-enable-notifications)
(add-hook 'after-init-hook #'mu4e-alert-enable-mode-line-display)
(mu4e-alert-enable-mode-line-display)
(defun gjstein/refresh-mu4e-alert-mode-line ()
(interactive)
(mu4e~proc-kill)
(mu4e-alert-enable-mode-line-display))
(run-with-timer 0 60 'gjstein/refresh-mu4e-alert-mode-line))
(setq sendmail-program "/run/current-system/sw/bin/msmtp"
send-mail-function 'smtpmail-send-it
message-sendmail-f-is-evil t
message-sendmail-extra-arguments '("--read-envelope-from")
message-send-mail-function 'message-send-mail-with-sendmail)
;; don't save messages to Sent Messages, Gmail/IMAP takes care of this
;;(setq mu4e-sent-messages-behavior 'delete)
(global-set-key (kbd "H-m") 'mu4e)
Elfeed is an RSS news feed with tagging, searching, auto-downloads, the works. You can open it via H-f
and additionally play links with media in them (like youtube) with r
. I also use elfeed-org to manage what feeds I’m subscribed to with an org file.
(use-package elfeed
:ensure t
:config
(global-set-key (kbd "H-f") 'elfeed)
(defun ga/play-with-mpv (start end)
"Play the link in the region with mpv"
(interactive "r")
(shell-command (concat "mpv " (buffer-substring start end) " \&")))
(define-key elfeed-show-mode-map (kbd "C-c o") 'ga/play-with-mpv))
(use-package elfeed-org
:ensure t
:config
(setq rmh-elfeed-org-files (list "~/.local/org-files/elfeed.org"))
:init
(elfeed-org))
(defun feed-visit ()
(interactive)
(find-file "~/.local/org-files/elfeed.org"))
(global-set-key (kbd "H-c f") 'feed-visit)
Mingus allows us to control MPD from within Emacs. Use H-p
to reach its various functions.
(use-package mingus
:ensure t
:bind
("H-p p" . mingus)
("H-<f5>" . mingus-previous)
("H-<f8>" . mingus-next)
("H-<f6>" . mingus-pause)
("H-<f7>" . mingus-stop))
Since EMMS will be using MPD to play music, it’s also nice to have some controls we can easily use.
(setq mpc-host "localhost:6600")
(defun mpd/start-music-daemon ()
"Start MPD, connects to it and syncs the metadata cache."
(interactive)
(shell-command "mpd")
(mpd/update-database)
(emms-player-mpd-connect)
(emms-cache-set-from-mpd-all)
(message "MPD Started!"))
(global-set-key (kbd "H-p c") 'mpd/start-music-daemon)
(defun mpd/kill-music-daemon ()
"Stops playback and kill the music daemon."
(interactive)
(emms-stop)
(call-process "killall" nil nil nil "mpd")
(message "MPD Killed!"))
(global-set-key (kbd "H-p k") 'mpd/kill-music-daemon)
(defun mpd/update-database ()
"Updates the MPD database synchronously."
(interactive)
(call-process "mpc" nil nil nil "update")
(message "MPD Database Updated!"))
(global-set-key (kbd "H-p u") 'mpd/update-database)
Theming is done last as some of the hooks (namely delimiters) won’t work when placed earlier in the config.
Some improvements to the look and feel of Emacs.
By default, Emacs has its own startup screen. We’ll be replacing it in Dashboard.
(setq inhibit-startup-message t)
Gets rid of the GUI buttons and scrollbars of Emacs. You’ll be using your keyboard anyway, so all these do is take up valuable screen space.
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
Gets rid of the audible/visible notifications of things happening, which usually show up on the minibuffer anyway.
(setq ring-bell-function 'ignore)
Sets all text to UTF-8.
(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(when window-system (global-hl-line-mode))
Changes various symbol names (e.g. lambda
) to their actual symbol.
(when window-system
(use-package pretty-mode
:ensure t
:config
(global-pretty-mode t)))
Rather than polluting your directory with obnoxious #file.etx#
files, this saves your backups to a designated folder.
(setq make-backup-files t)
(setq auto-save-default t)
(setq backup-directory-alist
`(("." . ,(concat user-emacs-directory "backups"))))
Whenever Emacs asks a yes or no question, you have to type `yes` or `no`, or Emacs refuses to do anything. This shortens that process.
(defalias 'yes-or-no-p 'y-or-n-p)
Uses asynchronous processes when possible.
(use-package async
:ensure t
:init (dired-async-mode 1))
Replaces the standard Emacs splash screen with a more streamlined one relevant to whatever you’re working on. Change it at your leisure, documentation details can be found here.
(use-package dashboard
:ensure t
:init
(dashboard-setup-startup-hook)
3 :config
(setq dashboard-startup-banner "~/.emacs.d/img/Emacs-logo_green.svg")
(setq dashboard-banner-logo-title "今日も一日頑張ってくれ!")
(setq dashboard-set-navigator t)
(setq dashboard-set-footer nil)
(setq dashboard-set-heading-icons t)
(setq dashboard-set-file-icons t)
(setq dashboard-items '((recents . 10)
(projects . 10)
(bookmarks . 10))))
Every good config needs a good theme. I’ve customized mine to be as easily readible as possible. Zeronight/Zerolight are really just Zerodark (by Nicolas Petton) with minor tweaks. Still, putting the customized versions into their own files allows us to switch between dark and light themes quickly.
(load "~/.emacs.d/custom/zeronight-theme.el")
(load "~/.emacs.d/custom/zerolight-theme.el")
(defvar *theme-dark* 'zeronight)
(defvar *theme-light* 'zerolight)
(defvar *current-theme* *theme-dark*)
(load-theme *current-theme* t)
;; disable other themes before loading new one
(defadvice load-theme (before theme-dont-propagate activate)
"Disable theme before loading new one."
(mapc #'disable-theme custom-enabled-themes))
(defun haba/next-theme (theme)
(load-theme theme t)
(setq *current-theme* theme))
(defun haba/toggle-theme ()
(interactive)
(cond ((eq *current-theme* *theme-dark*) (haba/next-theme *theme-light*))
((eq *current-theme* *theme-light*) (haba/next-theme *theme-dark*)))
;; Reset powerline for proper colors
(powerline-reset)
;; Reset org bullets to get rid of misplaced asterisks
(org-bullets-mode)
(org-bullets-mode))
(global-set-key (kbd "H-t") 'haba/toggle-theme)
Color parens and brackets according to their depth. Especially useful in lisp.
(use-package rainbow-delimiters
:ensure t
:config
(add-hook 'prog-mode-hook 'rainbow-delimiters-mode))
The modeline is at the bottom of every single buffer in Emacs and contains all of the information you would ever need.
A modified powerline used in spacemacs. Easy configuration and looks good with the theme.
(use-package spaceline
:ensure t
:config
(require 'spaceline-config)
(setq spaceline-buffer-encoding-abbrev-p nil)
(setq spaceline-line-column-p nil)
(setq spaceline-line-p nil)
(setq powerline-default-separator (quote arrow))
(spaceline-spacemacs-theme)
(powerline-reset))
Shows a clock and the date to the bottom right.
If you don’t want a 24-hour clock, set the first line to `nil`.
(setq display-time-24hr-format t)
(setq display-time-format "%H:%M - %d %B %Y")
(display-time-mode 1)
Shows battery percentage left on laptops.
(use-package fancy-battery
:ensure t
:config
(setq fancy-battery-show-percentage t)
(setq battery-update-interval 15)
(if window-system
(fancy-battery-mode)
(display-battery-mode)))
Hides the following modes from your modeline in order to save room.
(use-package diminish
:ensure t
:init
(diminish 'which-key-mode "")
(diminish 'linum-relative-mode "")
(diminish 'hungry-delete-mode "")
(diminish 'visual-line-mode "")
(diminish 'subword-mode "")
(diminish 'beacon-mode "")
(diminish 'irony-mode "")
(diminish 'page-break-lines-mode "")
(diminish 'auto-revert-mode "")
(diminish 'rainbow-delimiters-mode "")
(diminish 'rainbow-mode "")
(diminish 'yas-minor-mode "")
(diminish 'flycheck-mode "")
(diminish 'helm-mode "")
(diminish 'org-indent-mode)
(diminish 'org-src-mode)
(diminish 'eldoc-mode)
(diminish 'lispy-mode)
(diminish 'company-mode))