Skip to content

Keyhenge/emacs-config

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Keyhenge’s Emacs

./img/dark-capture.png ./img/light-capture.png

Credit

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.

Installation

Quick Installation

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.

Dependencies for

Keybindings

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.

General

  • 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.

EXWM

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.

Optional

  • A compositor (recommended, I use compton)
  • noto-cjk, to display foreign languages correctly
  • slock, if you want to lock the screen

TRAMP

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.

Mingus

  • mpd, to play music

Programming

You’ll also need various programs for code completion, REPLs, and style guide enforcement.

Package manager

  • 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 (python package manager)

  • pip install jedi flake8 autopep8, for code completion and style enforcement.

Go

  • gopls, downloaded here.

Helm/Dired

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 files
  • avfs, for looking inside archives
  • pass, for its helm integration

Open With

These are the programs I use to open various file types, feel free to change them in Openwith.

  • mpv for video/sound files
  • imv for images
  • libreoffice for various documents

mu4e

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 mu4e
  • getmail, which syncs a designated folder with your mailing server via POP or IMAP
  • msmtp, 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.

Some notes

On some of the keybindings

This configuration changes the default exit chord of C-x C-c to C-x C-q, see Change exit chord.

On use-package

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.

On the format of the configuration

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.

On the use case of this configuration

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.

Interface

Window Manager

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

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.

Installation

+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

Icecat

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

Launchers

dmenu for Emacs

A great little application launcher that works with helm. +BEGIN_SRC emacs-lisp (use-package dmenu :ensure t :bind (”s-SPC” . ‘dmenu)) +END_SRC

Various processes

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

Audio controls

A set of controls/settings to manipulate audio from inside Emacs.

Volume

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

Audio Keybindings

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

Screenshots

Gives us basic screenshot capabilities.

Screenshotting the entire screen

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

Screenshotting a region

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

Default browser

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)

Moving around Emacs

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.

Prerequisites for other packages

(use-package ivy
  :ensure t)

Scrolling

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)

Goto line

(global-set-key (kbd "M-l") 'goto-line)

Which-key

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))

Windows/Panes

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.

switch-window

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))

Following window splits

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)

Swiper

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

Buffers contain just about everything in Emacs, so we should make them better.

Always murder current buffer

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)

Turn switch-to-buffer into ibuffer

(global-set-key (kbd "C-x b") 'ibuffer)

close-all-buffers

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)

Line Numbers

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

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)

avy

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))

Text manipulation

As Emacs is a text editor, we should make some improvements to how you edit text.

Mark-Multiple/IEdit

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)

Improved kill-word

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)

Improved copy-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)

Copy a line

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)

Kill a line

Kills the whole like the cursor is on.

(global-set-key (kbd "C-c k") 'kill-whole-line)

Minor conveniences

Just some minor things that help you out once in a while.

Change exit chord

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"))

Visiting the configuration

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)

Reloading the configuration

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)

Subwords

Makes Emacs treat camelCasedWords as separate words.

(global-subword-mode 1)

Electric

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)

Beacon

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))

Rainbow

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))

Show parens

Highlights matching parens and brackets according to their depth.

(show-paren-mode 1)

Expand region

Expands the region you’re highlighting to the next logical step.

(use-package expand-region
  :ensure t
  :bind ("C-q" . er/expand-region))

Hungry deletion

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))

Zapping to char

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))

Syntax highlighting for documents exported to HTML

Allows you to export your buffer to HTML while respecting your tabs, theming, fonts, etc.

(use-package htmlize
  :ensure t)

Remote editing

Editing with sudo

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))

Kill ring

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.

Maximum entries on the ring

Doubles the size of the default kill ring.

(setq kill-ring-max 120)

popup-kill-ring

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))

Eshell

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.

Completion

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)

Shortcut

(global-set-key (kbd "<H-return>") 'eshell)

Regular shell

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.

Default shell should be zsh

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)

File manager

Dired

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

All the icons

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))

Dired hacks

(use-package dired-hacks-utils
  :ensure t)

Dired hacks is a collection of utilities and improvements to dired. The ones I use are:

Filter

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

avfs allows dired to browse archives.

(use-package dired-avfs
  :ensure t)

Subtree

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)))

ranger

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)))

Collapse

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))

Dired Rainbow

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

PDF tools allows us to view/edit pdfs.

(use-package pdf-tools
  :ensure t)

Openwith

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)
  )

Disk-Usage

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)

Package manager

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)

Programming

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

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.

Enable projectile globally

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))

Let projectile call make

Binds F5 to compile your project via a Makefile in the root directory.

(global-set-key (kbd "<f5>") 'projectile-compile-project)

Yasnippet

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)

Flycheck

A programmer’s best friend, checks for syntax and styling errors.

(use-package flycheck
  :ensure t)

Company mode

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 integration

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))

Language Server Protocol

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)

Specific languages

Packages and settings that make working in specific languages easier.

C/C++

(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))

Python

(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))

ELisp

(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)

Scheme

(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)

Bash

(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))

Lua/löve

(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)))

Golang

;; 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)

Markup languages

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.

YAML

(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))))

Misc

Org

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.

Common settings

(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

Line wrapping

Always wrap lines in org mode.

(add-hook 'org-mode-hook
	     '(lambda ()
	        (visual-line-mode 1)))

Edit code blocks

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)

Org Bullets

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))))

Easy-to-add Elisp template

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"))

Exporting options

latex

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))

Agenda

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)

Messaging

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

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

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

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))

MPD

Since EMMS will be using MPD to play music, it’s also nice to have some controls we can easily use.

MPC Setup

(setq mpc-host "localhost:6600")

Starting the daemon from within Emacs

(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)

Killing the daemon from within Emacs

(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)

Updating the database easily

(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

Theming is done last as some of the hooks (namely delimiters) won’t work when placed earlier in the config.

Basic Interface Settings

Some improvements to the look and feel of Emacs.

Looks

Remove startup screen

By default, Emacs has its own startup screen. We’ll be replacing it in Dashboard.

(setq inhibit-startup-message t)

Disable menus and scrollbars

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)

Disable bell

Gets rid of the audible/visible notifications of things happening, which usually show up on the minibuffer anyway.

(setq ring-bell-function 'ignore)

Set UTF-8 encoding

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)

Highlight current line

(when window-system (global-hl-line-mode))

Pretty symbols

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)))

Functionality

Backups and auto-saves

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"))))

Change yes-or-no questions into y-or-n questions

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)

Async

Uses asynchronous processes when possible.

(use-package async
  :ensure t
  :init (dired-async-mode 1))

Dashboard

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))))

Theme

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)

Rainbow delimiters

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))

Modeline

The modeline is at the bottom of every single buffer in Emacs and contains all of the information you would ever need.

Spaceline

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))

Clock

Shows a clock and the date to the bottom right.

Time format

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")

Enabling the mode

(display-time-mode 1)

Battery indicator

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)))

Diminishing modes

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))

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •