Taymacs
aknowledgements
this config was based off of uncle daves emacs who i am forever grateful to for allowing me a user friendly entry point to emacs check out uncle daves repo at https://github.com/daedreth/UncleDavesEmacs
Dependencies for:
EXWM
Since we are going to use emacs as our window manager, it would be nice to have some external software to make our life easier.
From the package manager:
xorg-server
, for obvious reasons. (there is no wayland support as of now)pulsemixer
, available fromhttps://github.com/GeorgeFilipkin/pulsemixer
.imagemagick
, if you are going to be using emacs to take screenshots.ibus-daemon
, if you need multiple keyboard input options (emacs handles them well on its own but ibus is nice).terminus-font
, for it to work out of the box, if you don’t want terminus you need to edit yourinit.el
.
Optional
- A browser (sadly, the built in xwidgets-webkit thingie is unreliable).
- A composite manager (highly recommended, I personally use
compton
, the built in one does not work as intended.). noto-cjk
, for all the fonts imaginable.slock
, if you would like to lock the screen.
EMMS
From the package manager:
mpd
, since we are going to be using EMMS for music playback, I recommend setting up a working mpd server.mpv
, for video playback.
Programming
Package manager
clang
, for c/c++ completion.sbcl
, for clisp completion and repl.virtualenv
, for python completion.lua
, for obvious reasons.
import manually installed packages
(let ((default-directory (concat user-emacs-directory
(convert-standard-filename "lisp/"))))
(normal-top-level-add-to-load-path '("."))
(normal-top-level-add-subdirs-to-load-path))
evil
(use-package evil
:ensure t
:init
(setq evil-want-integration t)
(setq evil-want-keybinding nil)
:config
(evil-mode 1)
(define-key evil-insert-state-map (kbd "C-g") 'evil-normal-state))
(use-package evil-collection
:ensure t)
(use-package evil-surround
:ensure t)
undo tree
(use-package undo-tree
:ensure t
:config
(global-undo-tree-mode))
Theme
high contrast
(use-package modus-vivendi-theme
:ensure t
:init
(setq modus-vivendi-theme-slanted-constructs t
modus-vivendi-theme-bold-constructs t
modus-vivendi-theme-visible-fringes t
modus-vivendi-theme-3d-modeline t
modus-vivendi-theme-subtle-diffs t
modus-vivendi-theme-intense-standard-completions t
modus-vivendi-theme-distinct-org-blocks t
modus-vivendi-theme-rainbow-org-src-blocks t
modus-vivendi-theme-proportional-fonts t
modus-vivendi-theme-rainbow-headings t
modus-vivendi-theme-section-headings t)
:config
(load-theme 'modus-vivendi t))
Font
;; Set default font
(set-face-attribute 'default nil
:family "Hack"
:height 150
;; :weight 'normal
:width 'normal)
;; set fallback font for emoji
(set-fontset-font t nil (font-spec :size 20 :name "Unifont"))
Basic Interface Settings
These are setting that do not depend on packages and are built-in enhancements to the UI.
Looks
remove original dashboard
(setq inhibit-startup-message t)
Disable menus and scrollbars
If you like using any of those, change -1
to 1
.
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
Set UTF-8 encoding
(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
hl-line
is awesome! It’s not very awesome in the terminal version of emacs though, so we don’t use that.
Besides, it’s only used for programming.
(when window-system (add-hook 'prog-mode-hook 'hl-line-mode))
visual bell
(setq visible-bell t)
Functionality
backups and auto-saves
I don’t use either, you might want to turn those from nil
to t
if you do.
(setq make-backup-files nil)
(setq auto-save-default nil)
Change yes-or-no questions into y-or-n questions
(defalias 'yes-or-no-p 'y-or-n-p)
Async
use asynchronous processes wherever possible
(use-package async
:ensure t
:init (dired-async-mode 1))
Window Manager
Everything regarding the WM or DE-like functionality is bundled here, remove the entire section if you do not wish to use exwm
.
exwm
The only time I actually had to use comments, this is for ease of removal if you happen to not like exwm.
Installation
(use-package exwm
:ensure t
:config
;; necessary to configure exwm manually
(require 'exwm-config)
;; fringe size, most people prefer 1
(fringe-mode 3)
;; emacs as a daemon, use "emacsclient <filename>" to seamlessly edit files from the terminal directly in the exwm instance
(server-start)
;; this fixes issues with ido mode, if you use helm, get rid of it
;; (exwm-config-ido)
;; a number between 1 and 9, exwm creates workspaces dynamically so I like starting out with 1
(setq exwm-workspace-number 1)
;; this is a way to declare truly global/always working keybindings
;; this is a nifty way to go back from char mode to line mode without using the mouse
(exwm-input-set-key (kbd "s-r") #'exwm-reset)
(exwm-input-set-key (kbd "s-k") #'exwm-workspace-delete)
(exwm-input-set-key (kbd "s-w") #'exwm-workspace-swap)
(exwm-input-set-key (kbd "s-n") 'ibuffer)
(exwm-input-set-key (kbd "s-m") 'next-buffer)
(exwm-input-set-key (kbd "s-,") 'previous-buffer)
(exwm-input-set-key (kbd "s-/") 'kill-current-buffer)
(exwm-input-set-key (kbd "s-j") 'windmove-left)
(exwm-input-set-key (kbd "s-k") 'windmove-down)
(exwm-input-set-key (kbd "s-i") 'windmove-up)
(exwm-input-set-key (kbd "s-l") 'windmove-right)
(exwm-input-set-key (kbd "s-;") 'delete-window)
(exwm-input-set-key (kbd "s-s h") 'split-window-right)
(exwm-input-set-key (kbd "s-s j") 'split-window-below)
(exwm-input-set-key (kbd "s-s k") 'split-and-follow-horizontally)
(exwm-input-set-key (kbd "s-s l") 'split-and-follow-vertically)
;; the next loop will bind s-<number> to switch to the corresponding workspace
(dotimes (i 10)
(exwm-input-set-key (kbd (format "s-%d" i))
`(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
;; the simplest launcher, I keep it in only if dmenu eventually stopped working or something
(exwm-input-set-key (kbd "s-&")
(lambda (command)
(interactive (list (read-shell-command "$ ")))
(start-process-shell-command command nil command)))
;; an easy way to make keybindings work *only* in line mode
(push ?\C-q exwm-input-prefix-keys)
(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)
;; search
([?\C-f] . ?\C-f)
;; movement
([?\M-h] . return)
([?\M-m] . return)
([?\M-l] . right)
([?\M-k] . down)
([?\M-j] . left)
([?\M-\\] . prior)
([?\M-'] . next)))
;; 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))
Multi monitor
(require 'exwm-randr)
(setq exwm-randr-workspace-output-plist '(0 "DP-4"))
(add-hook 'exwm-randr-screen-change-hook
(lambda ()
(start-process-shell-command
"xrandr" nil "xrandr --output DP-4 --auto")))
(exwm-randr-enable)
autoname the buffers
;; autoname buffers
(add-hook 'exwm-update-class-hook
(lambda ()
(exwm-workspace-rename-buffer exwm-class-name)))
System tray
(require 'exwm-systemtray)
(exwm-systemtray-enable)
Launchers
Since I do not use a GUI launcher and do not have an external one like dmenu or rofi, I figured the best way to launch my most used applications would be direct emacsy keybindings.
dmenu for emacs
Who would’ve thought this was available, together with ido-vertical it’s a nice large menu with its own cache for most launched applications.
(use-package dmenu
:ensure t
:bind
("s-SPC" . 'dmenu))
Audio controls
This is a set of bindings to my XF86 keys that invokes pulsemixer with the correct parameters
Volume modifier
It goes without saying that you are free to modify the modifier as you see fit, 4 is good enough for me though.
(defconst volumeModifier "4")
Functions to start processes
(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)))
Keybindings to start processes
You can also change those if you’d like, but I highly recommend keeping ‘em the same, chances are, they will just work.
(global-set-key (kbd "<XF86AudioMute>") 'audio/mute)
(global-set-key (kbd "<XF86AudioRaiseVolume>") 'audio/raise-volume)
(global-set-key (kbd "<XF86AudioLowerVolume>") 'audio/lower-volume)
Screenshots
I don’t need scrot to take screenshots, or shutter or whatever tools you might have. This is enough. These won’t work in the terminal version or the virtual console, obvious reasons.
Screenshotting the entire screen
(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)
Screenshotting a region
(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)
eaf
gui applications from inside emacs using python repl connected to the lisp
(use-package eaf
:load-path "~/.emacs.d/site-lisp/emacs-application-framework" ; Set to "/usr/share/emacs/site-lisp/eaf" if installed from AUR
:custom
(eaf-find-alternate-file-in-dired t)
:config
(eaf-bind-key scroll_up "C-n" eaf-pdf-viewer-keybinding)
(eaf-bind-key scroll_down "C-p" eaf-pdf-viewer-keybinding)
(eaf-bind-key take_photo "p" eaf-camera-keybinding)
(define-key dired-mode-map (kbd "e") 'eaf-open-this-from-dired))
Default browser
I use eww for most browsing, and I use icecat when I need to open something in an external browser.
(setq browse-url-browser-function 'eww-browse-url
browse-url-generic-program "icecat")
shrface for eww that is more like org mode
;; (use-package shrface
;; :defer t
;; :ensure t
;; :config
;; (shrface-basic)
;; (shrface-trial)
;; (setq shrface-href-versatile t))
;; (use-package eww
;; :init
;; (add-hook 'eww-after-render-hook #'shrface-mode)
;; :config
;; (require 'shrface))
sometimes i load a page and it has a lot of animated images and it makes eww crawl, or it has big images that make the page hard to read, so I dont open images by default, but this neat script i found lets you turn on and off images.
(defun my/eww-toggle-images ()
"Toggle whether images are loaded and reload the current page from cache."
(interactive)
(setq-local shr-inhibit-images (not shr-inhibit-images))
(eww-reload t)
(message "Images are now %s"
(if shr-inhibit-images "off" "on")))
;; (define-key eww-mode-map (kbd "I") #'my/eww-toggle-images)
;; (define-key eww-link-keymap (kbd "I") #'my/eww-toggle-images)
;; minimal rendering by default
(setq-default shr-inhibit-images t) ; toggle with `I`
(setq-default shr-use-fonts nil) ; toggle with `F`
this highlights syntax in eww, good for elisp snippets on the wiki.
;; syntax highlighting
(use-package language-detection
:ensure t
:config
(require 'cl-lib)
(defun eww-tag-pre (dom)
(let ((shr-folding-mode 'none)
(shr-current-font 'default))
(shr-ensure-newline)
(insert (eww-fontify-pre dom))
(shr-ensure-newline)))
(defun eww-fontify-pre (dom)
(with-temp-buffer
(shr-generic dom)
(let ((mode (eww-buffer-auto-detect-mode)))
(when mode
(eww-fontify-buffer mode)))
(buffer-string)))
(defun eww-fontify-buffer (mode)
(delay-mode-hooks (funcall mode))
(font-lock-default-function mode)
(font-lock-default-fontify-region (point-min)
(point-max)
nil))
(defun eww-buffer-auto-detect-mode ()
(let* ((map '((ada ada-mode)
(awk awk-mode)
(c c-mode)
(cpp c++-mode)
(clojure clojure-mode lisp-mode)
(csharp csharp-mode java-mode)
(css css-mode)
(dart dart-mode)
(delphi delphi-mode)
(emacslisp emacs-lisp-mode)
(erlang erlang-mode)
(fortran fortran-mode)
(fsharp fsharp-mode)
(go go-mode)
(groovy groovy-mode)
(haskell haskell-mode)
(html html-mode)
(java java-mode)
(javascript javascript-mode)
(json json-mode javascript-mode)
(latex latex-mode)
(lisp lisp-mode)
(lua lua-mode)
(matlab matlab-mode octave-mode)
(objc objc-mode c-mode)
(perl perl-mode)
(php php-mode)
(prolog prolog-mode)
(python python-mode)
(r r-mode)
(ruby ruby-mode)
(rust rust-mode)
(scala scala-mode)
(shell shell-script-mode)
(smalltalk smalltalk-mode)
(sql sql-mode)
(swift swift-mode)
(visualbasic visual-basic-mode)
(xml sgml-mode)))
(language (language-detection-string
(buffer-substring-no-properties (point-min) (point-max))))
(modes (cdr (assoc language map)))
(mode (cl-loop for mode in modes
when (fboundp mode)
return mode)))
(message (format "%s" language))
(when (fboundp mode)
mode)))
(setq shr-external-rendering-functions
'((pre . eww-tag-pre))))
File Manager
Dired
(setq-default dired-listing-switches "-alh")
(use-package all-the-icons-dired
:ensure t
:hook (dired-mode . all-the-icons-dired-mode)
)
Projectile
Enable projectile globally
This makes sure that everything can be a project.
(use-package projectile
:ensure t
:init (projectile-mode 1)
:custom
(projectile-completion-system)
:bind ("C-c p" . 'projectile-command-map))
(use-package counsel-projectile
:ensure t
:config (counsel-projectile-mode))
Let projectile call make
(global-set-key (kbd "<f5>") 'projectile-compile-project)
Dashboard
Dashboard with recent files and projects
(use-package dashboard
:ensure t
:config
(dashboard-setup-startup-hook)
(setq dashboard-startup-banner "~/.emacs.d/img/dashLogo.png")
(setq dashboard-items '((recents . 5)
(projects . 5)))
(setq dashboard-banner-logo-title "TAYMACS"))
Modeline
Clock
Time format
(setq display-time-24hr-format nil)
(setq display-time-format "%H:%M - %d %B %Y")
Enabling the mode
This turns on the clock globally.
(display-time-mode 1)
The terminal
Default shell
(defvar my-term-shell "/bin/bash")
(defadvice ansi-term (before force-bash)
(interactive (list my-term-shell)))
(ad-activate 'ansi-term)
discoverablility and completion
Ivy
;; (use-package counsel
;; :ensure t
;; :after ivy
;; :config (counsel-mode))
;; (use-package ivy
;; :ensure t
;; :config
;; (ivy-mode 1)
;; :bind
;; ("C-x C-b" . 'ivy-switch-buffer))
;; (use-package ivy-rich
;; :ensure t
;; :after counsel
;; :init
;; (ivy-rich-mode 1))
potential:
https://github.com/masasam/emacs-counsel-tramp
helm
(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)
:init
(helm-mode 1))
(require 'helm-config)
(helm-autoresize-mode 0)
;; (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)
silver searcher helm
(use-package helm-ag
:ensure t)
look into icicles
look into anything.el
which-key
automatic cheat sheet once you press part of a key series
(use-package which-key
:ensure t
:config
(which-key-mode))
prescient
better auto completion - sorts by length and prioritizes more commonly used selections
(use-package ivy-prescient
:ensure t
:after counsel
:config (ivy-prescient-mode 1))
Moving around emacs
windows,panes and why I hate other-window
Some of us have large displays, others have tiny netbook screens, but regardless of your hardware
you probably use more than 2 panes/windows at times, cycling through all of them with
C-c o
is annoying to say the least, it’s a lot of keystrokes and takes time, time you could spend doing something more productive.
switch-window
switch window uses an ace type jump if more than 2 windows are open
(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" "j" "k" "l" "i" "o"))
:bind
([remap other-window] . switch-window))
Following window splits
After you split a window, your focus remains in the previous one. This annoyed me so much I wrote these two, they take care of it.
(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)
buffers
Another big thing is, buffers. If you use emacs, you use buffers, everyone loves them. Having many buffers is useful, but can be tedious to work with, let us see how we can improve it.
Always murder current buffer
Doing C-x k
should kill the current buffer at all times, we have ibuffer
for more sophisticated thing.
(defun kill-current-buffer ()
"Kills the current buffer."
(interactive)
(kill-buffer (current-buffer)))
(global-set-key (kbd "C-x k") 'kill-current-buffer)
Kill buffers without asking for confirmation
Unless you have the muscle memory, I recommend omitting this bit, as you may lose progress for no reason when working.
(setq kill-buffer-query-functions (delq 'process-kill-buffer-query-function kill-buffer-query-functions))
Turn switch-to-buffer into ibuffer
I don’t understand how ibuffer isn’t the default option by now. It’s vastly superior in terms of ergonomics and functionality, you can delete buffers, rename buffer, move buffers, organize buffers etc.
(global-set-key (kbd "C-x b") 'ibuffer)
expert-mode
If you feel like you know how ibuffer works and need not to be asked for confirmation after every serious command, enable this as follows.
;;(setq ibuffer-expert t)
line numbers
Relative line numbers
(use-package linum-relative
:ensure t
:config
(setq linum-relative-current-symbol "")
(add-hook 'prog-mode-hook 'linum-relative-mode))
isearch/avy/ace jump
personally i have tried using avy but plain isearch seems to do the job the best for me so far, i may revisit avy at some point in the far future if i feel the need
revisit avy mode
ace-link for eww
(use-package ace-link
:ensure t
:config
(ace-link-setup-default)
)
non-sinful custom bindings (C-c lowercase)
Mark Multiple
(use-package mark-multiple
:ensure t
:bind ("C-c q" . 'mark-next-like-this))
vim-like (v)
everything is inner-object because the rest is easy enough in emacs way
list of actions
kill - k copy - w mark - m yank into occur multicursor
word
kill (k)
(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 "C-c v w k") 'daedreth/kill-inner-word)
copy (w)
And again, the same as above but we make sure to not delete the source word.
(defun daedreth/copy-whole-word ()
(interactive)
(save-excursion
(forward-char 1)
(backward-word)
(kill-word 1)
(yank)))
(global-set-key (kbd "C-c v w w") 'daedreth/copy-whole-word)
line (l)
copy (w)
Regardless of where your cursor is, this quickly copies a line.
(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 v l w") 'daedreth/copy-whole-line)
kill (k)
And this quickly deletes a line.
(global-set-key (kbd "C-c v l k") 'kill-whole-line)
media (d)
management (m)
(global-set-key (kbd "C-c d m") 'emms)
add (a)
from dired (d)
(global-set-key (kbd "C-c a d") 'emms-add-dired)
from search (s)
from find-file (f)
(global-set-key (kbd "C-c a f") 'emms-add-find)
streams (s)
(global-set-key (kbd "C-c d s") 'emms-streams)
next (n)
(global-set-key (kbd "C-c d n") 'emms-next)
previous (p)
(global-set-key (kbd "C-c d p") 'emms-previous)
pause (SPC)
(global-set-key (kbd "C-c d SPC") 'emms-pause)
framing (f)
maybe something like persp mode?
web (w)
wowser (w)
(global-set-key (kbd "C-c w w") 'eww)
mark (m)
line (l)
word (w)
insert (i)
insert unicode (u)
snippet (s)
compile (c)
capture/journal (j)
(global-set-key (kbd "C-c j") 'org-capture)
Minor conveniences
Emacs is at it’s best when it just does things for you, shows you the way, guides you so to speak. This can be best achieved using a number of small extensions. While on their own they might not be particularly impressive. Together they create a nice environment for you to work in.
Visiting the configuration
Quickly edit ~/.emacs.d/config.org
(defun config-visit ()
(interactive)
(find-file "~/.emacs.d/config.org"))
(global-set-key (kbd "C-c e") 'config-visit)
Reloading the configuration
Simply pressing Control-c r
will reload this file, very handy.
You can also manually invoke config-reload
.
(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 "C-c r") 'config-reload)
Subwords
Emacs treats camelCase strings as a single word by default, this changes said behaviour.
(global-subword-mode 1)
Electric
autocomplete pairs
(setq electric-pair-pairs '(
(?\{ . ?\})
(?\( . ?\))
(?\[ . ?\])
(?\" . ?\")))
And now to enable it
(electric-pair-mode t)
Rainbow
shows color of hex color
(use-package rainbow-mode
:ensure t
:init
(add-hook 'prog-mode-hook 'rainbow-mode))
Show parens
highlight matching paren
(show-paren-mode 1)
Rainbow delimiters
Colors parentheses and other delimiters depending on their depth
(use-package rainbow-delimiters
:ensure t
:init
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode))
Expand region
grow region over levels of semantic objects.
(use-package expand-region
:ensure t
:bind ("C-M-q" . er/expand-region))
Hungry deletion
Backspace or Delete will get rid of all whitespace until the next non-whitespace character is encountered.
(use-package hungry-delete
:ensure t
:config
(global-hungry-delete-mode))
Programming
Minor, non-completion related settings and plugins for writing code.
paredit
(use-package paredit
:ensure t
:config
(autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t)
(add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
(add-hook 'ielm-mode-hook #'enable-paredit-mode)
(add-hook 'lisp-mode-hook #'enable-paredit-mode)
(add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)
(add-hook 'scheme-mode-hook #'enable-paredit-mode))
yasnippet
(use-package yasnippet
:ensure t
:config
(use-package yasnippet-snippets
:ensure t)
(yas-reload-all))
flycheck
(use-package flycheck
:ensure t
:config
(add-hook 'after-init-hook #'global-flycheck-mode)
(flycheck-add-mode 'javascript-eslint 'web-mode 'scala-mode))
company mode
I set the delay for company mode to kick in to half a second, I also make sure that it starts doing its magic after typing in only 2 characters.
I prefer C-n
and C-p
to move around the items, so I remap those accordingly.
(use-package company
:ensure t
:bind (:map company-active-map
("<tab>" . company-complete-selection))
:config
(setq company-idle-delay 0)
(setq company-minimum-prefix-length 1))
emacs
specific languages
Be it for code or prose, completion is a must.
After messing around with auto-completion
for a while I decided to drop it
in favor of company
, and it turns out to have been a great decision.
Each category also has additional settings.
c/c++
yasnippet
(add-hook 'c++-mode-hook 'yas-minor-mode)
(add-hook 'c-mode-hook 'yas-minor-mode)
flycheck
(use-package flycheck-clang-analyzer
:ensure t
:config
(with-eval-after-load 'flycheck
(require 'flycheck-clang-analyzer)
(flycheck-clang-analyzer-setup)))
company
Requires libclang to be installed.
(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
yasnippet
(add-hook 'python-mode-hook 'yas-minor-mode)
flycheck
(add-hook 'python-mode-hook 'flycheck-mode)
company
(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))
emacs-lisp
eldoc
(add-hook 'emacs-lisp-mode-hook 'eldoc-mode)
yasnippet
(add-hook 'emacs-lisp-mode-hook 'yas-minor-mode)
company
(add-hook 'emacs-lisp-mode-hook 'company-mode)
(use-package slime
:ensure t
:config
(setq inferior-lisp-program "/usr/bin/sbcl")
(setq slime-contribs '(slime-fancy)))
(use-package slime-company
:ensure t
:init
(require 'company)
(slime-setup '(slime-fancy slime-company)))
lua
yasnippet
(add-hook 'lua-mode-hook 'yas-minor-mode)
flycheck
(add-hook 'lua-mode-hook 'flycheck-mode)
company
(add-hook 'lua-mode-hook 'company-mode)
(defun custom-lua-repl-bindings ()
(local-set-key (kbd "C-c C-s") 'lua-show-process-buffer)
(local-set-key (kbd "C-c C-h") 'lua-hide-process-buffer))
(defun lua-mode-company-init ()
(setq-local company-backends '((company-lua
company-etags
company-dabbrev-code))))
(use-package company-lua
:ensure t
:config
(require 'company)
(setq lua-indent-level 4)
(setq lua-indent-string-contents t)
(add-hook 'lua-mode-hook 'custom-lua-repl-bindings)
(add-hook 'lua-mode-hook 'lua-mode-company-init))
bash
yasnippet
(add-hook 'shell-mode-hook 'yas-minor-mode)
flycheck
(add-hook 'shell-mode-hook 'flycheck-mode)
company
(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))
haskell
(use-package haskell-mode
:ensure t)
JS
(add-hook 'emacs-lisp-mode-hook 'company-mode)
(add-hook 'emacs-lisp-mode-hook 'yas-minor-mode)
(use-package js2-mode
:ensure t
:init
(setq js-basic-indent 2)
(setq js2-strict-missing-semi-warning nil)
(setq js2-missing-semi-one-line-override t)
(setq-default js2-basic-indent 2
js2-basic-offset 2
js2-auto-indent-p t
js2-cleanup-whitespace t
js2-enter-indents-newline t
js2-indent-on-enter-key t
js2-global-externs (list "window" "module" "require" "buster" "sinon" "assert" "refute" "setTimeout" "clearTimeout" "setInterval" "clearInterval" "location" "__dirname" "console" "JSON" "jQuery" "$"))
(add-hook 'js2-mode-hook
(lambda ()
(push '("function" . ?ƒ) prettify-symbols-alist)))
(add-hook 'js2-mode-hook 'company-mode)
(add-hook 'js2-mode-hook 'yas-minor-mode)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode)))
;; jump to definition
;;(use-package tern
;; :ensure t
;; :init (add-hook 'js2-mode-hook (lambda () (tern-mode t)))
;; :config
;; (use-package company-tern
;; :ensure t
;; :init (add-to-list 'company-backends 'company-tern)))
;; refactoring (C-c)
(use-package js2-refactor
:ensure t
:init (add-hook 'js2-mode-hook 'js2-refactor-mode)
:config (js2r-add-keybindings-with-prefix "C-c ."))
(use-package prettier
:ensure t
:config
(add-hook 'after-init-hook #'global-prettier-mode)
;; (add-hook 'js2-mode-hook 'prettier-mode)
;; (add-hook 'web-mode-hook 'prettier-mode)
)
drools
(autoload 'drools-mode "drools-mode")
(defun set-extension-mode (extension mode)
(setq auto-mode-alist
(cons (cons (concat "\\" extension "\\'") mode)
auto-mode-alist) ) )
(set-extension-mode ".drl" 'drools-mode)
(set-extension-mode ".dslr" 'drools-mode)
(add-hook 'drools-mode-hook 'my-drools-hook)
(defun drools-return-and-indent()
(interactive)
(newline) (indent-for-tab-command) )
(defun my-drools-hook ()
(setq indent-tabs-mode nil)
(local-set-key [?\C-m] 'drools-return-and-indent) )
scala
(use-package scala-mode
:ensure t
:interpreter
("scala" . scala-mode))
(use-package sbt-mode
:commands sbt-start sbt-command
:ensure t
:config
;; WORKAROUND: https://github.com/ensime/emacs-sbt-mode/issues/31
;; allows using SPACE when in the minibuffer
(substitute-key-definition
'minibuffer-complete-word
'self-insert-command
minibuffer-local-completion-map)
;; sbt-supershell kills sbt-mode: https://github.com/hvesalai/emacs-sbt-mode/issues/152
(setq sbt:program-options '("-Dsbt.supershell=false"))
)
(use-package lsp-mode
;; Optional - enable lsp-mode automatically in scala files
:ensure t
:hook (scala-mode . lsp)
(lsp-mode . lsp-lens-mode)
:config (setq lsp-prefer-flymake nil))
;; Add metals backend for lsp-mode
(use-package lsp-metals
:ensure t
:config (setq lsp-metals-treeview-show-when-views-received nil))
;; Enable nice rendering of documentation on hover
(use-package lsp-ui
:ensure t)
;; Add company-lsp backend for metals
(use-package company-lsp
:ensure t)
;; Use the Debug Adapter Protocol for running tests and debugging
(use-package posframe
:ensure t
;; Posframe is a pop-up tool that must be manually installed for dap-mode
)
(use-package dap-mode
:ensure t
:hook
(lsp-mode . dap-mode)
(lsp-mode . dap-ui-mode)
)
TS
(use-package tide
:ensure t
:config
(defun setup-tide-mode ()
(interactive)
(tide-setup)
(flycheck-mode +1)
(setq flycheck-check-syntax-automatically '(save mode-enabled))
(eldoc-mode +1)
(tide-hl-identifier-mode +1)
;; company is an optional dependency. You have to
;; install it separately via package-install
;; `M-x package-install [ret] company`
(company-mode +1))
;; aligns annotation to the right hand side
(setq company-tooltip-align-annotations t)
;; formats the buffer before saving
(add-hook 'before-save-hook 'tide-format-before-save)
(add-hook 'typescript-mode-hook #'setup-tide-mode))
(add-hook 'web-mode-hook
(lambda ()
(when (string-equal "tsx" (file-name-extension buffer-file-name))
(setup-tide-mode))))
web programming
vue
vue-mode
(use-package vue-mode
:ensure t
:init (add-hook 'vue-mode-hook 'company-mode)
(add-hook 'vue-mode-hook 'yas-minor-mode)
:config
(setq mmm-submode-decoration-level 0))
vue-html-mode
(use-package vue-html-mode
:ensure t)
vue lsp?
(use-package vue-mode
:ensure t)
emmet
(use-package emmet-mode
:ensure t)
coffee?
web-mode
(use-package web-mode
:ensure t
:init
(add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.vue\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode))
(add-hook 'editorconfig-custom-hooks
(lambda (hash) (setq web-mode-block-padding 0)))
(add-hook 'web-mode-hook 'company-mode)
(add-hook 'web-mode-hook 'yas-minor-mode)
:config
(setq web-mode-enable-auto-indentation nil)
(setq web-mode-content-types-alist '(("jsx" . "\\.js[x]?\\'"))))
LaTeX
(use-package tex
:defer t
:ensure auctex
:config
(setq TeX-auto-save t))
;; (use-package auctex
;; :ensure t)
Git integration
Countless are the times where I opened ansi-term to use git
on something.
These times are also something that I’d prefer stay in the past, since magit
is
great. It’s easy and intuitive to use, shows its options at a keypress and much more.
magit
(use-package magit
:ensure t
:config
(setq magit-push-always-verify nil)
(setq git-commit-summary-max-length 80)
:bind
("C-c g" . sudo-edit))
git gutter
(use-package diff-hl
:ensure t
:config
(global-diff-hl-mode))
magit forge
(use-package forge
:ensure t
:after magit)
Remote editing
Editing with sudo
Pretty self-explanatory, useful as hell if you use exwm.
(use-package sudo-edit
:ensure t
:bind
("s-e" . sudo-edit))
Org
One of the absolute greatest features of emacs is called “org-mode”. This very file has been written in org-mode, a lot of other configurations are written in org-mode, same goes for academic papers, presentations, schedules, blogposts and guides. Org-mode is one of the most complex things ever, lets make it a bit more usable with some basic configuration.
Those are all rather self-explanatory.
Common settings
(setq org-ellipsis " ")
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
(setq org-confirm-babel-evaluate nil)
(setq org-export-with-smart-quotes t)
(setq org-src-window-setup 'current-window)
(add-hook 'org-mode-hook 'org-indent-mode)
org journal
(use-package org-journal
:ensure t
:defer t
:custom
(org-journal-dir "~/notes/journal/")
(org-journal-date-format "%A, %d %B %Y"))
Syntax highlighting for documents exported to HTML
(use-package htmlize
:ensure t)
Line wrapping
(add-hook 'org-mode-hook
'(lambda ()
(visual-line-mode 1)))
spell checking
(add-hook 'org-mode-hook
'(lambda ()
(flyspell-mode 1)))
Keybindings
edit the stuff in a src block with proper modes
(global-set-key (kbd "C-c '") 'org-edit-src-code)
Org Bullets
change astrisks to bullets
(use-package org-bullets
:ensure t
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode))))
Easy-to-add emacs-lisp template
Hitting tab after an “<el” in an org-mode file will create a template for elisp insertion.
(add-to-list 'org-structure-template-alist
'("el" "emacs-lisp"))
Exporting options
One of the best things about org is the ability to export your file to many formats. Here is how we add more of them!
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))
web browser
elpher for gopher and gem
(use-package elpher
:ensure t)
irc
circe
erc, also known as “a way to ask for help on #emacs”
You might want to edit the default nick, it’s password protected anyway so don’t bother.
find a way to ignore some channels and only show notifications in modeline
Some common settings
This also hides some of the channel messages to avoid cluttering the buffer. The other line changes the prompt for each channel buffer to match the channel name, this way you always know who you are typing to.
(setq erc-nick "nobodynogroup")
(setq erc-prompt (lambda () (concat "[" (buffer-name) "]")))
(setq erc-hide-list '("JOIN" "PART" "QUIT"))
selectable server list
What it says on the tin, this changes the erc
history to include the server I connect to often.
(setq erc-server-history-list '("irc.libera.chat"
"localhost"))
Nick highlighting
You can even highlight nicks to make the buffers a bit more visually pleasing and easier to look at.
(use-package erc-hl-nicks
:ensure t
:config
(erc-update-modules))
ELIM
(add-to-list 'load-path "~/elim/elisp")
(load-library "garak")
EMMS
There is many backends, many players and codecs for EMMS, we use mpd now.
Basic setup for mpd
The non XF86 keys are made to be somewhat logical to follow and easy to remember. At the bottom part of the configuration, you will notice how XF86 keys are used by default, so unless you keyboard is broken it should work out of the box. Obviously you might have to adjust server-name and server-port to fit your configuration.
(use-package emms
:ensure t
:config
(require 'emms-setup)
(require 'emms-player-mpd)
(emms-all) ; don't change this to values you see on stackoverflow questions if you expect emms to work
(setq emms-seek-seconds 5)
(emms-default-players)
;; (setq emms-player-list '(emms-player-mpd))
;; (setq emms-info-functions '(emms-info-mpd))
(setq emms-player-mpd-server-name "localhost")
(setq emms-player-mpd-server-port "6600")
(setq emms-source-file-default-directory "~/Media/")
:bind
;; ("s-m p" . emms)
;; ("s-m b" . emms-smart-browse)
;; ("s-m r" . emms-player-mpd-update-all-reset-cache)
("<XF86AudioPrev>" . emms-previous)
("<XF86AudioNext>" . emms-next)
("<XF86AudioPlay>" . emms-pause)
("<XF86AudioPause>" . emms-pause)
("<XF86AudioStop>" . emms-stop))
MPC Setup
Setting the default port
We use non-default settings for the socket, to use the built in mpc
functionality we need to set up a variable.
Adjust according to your setup.
(setq mpc-host "localhost:6601")
mpv
(use-package emms-player-mpv
:ensure t
:config
(add-to-list 'emms-player-list 'emms-player-mpv))
Some more fun stuff
Starting the daemon from within emacs
If you have an absolutely massive music library, it might be a good idea to get rid of mpc-update
and only invoke it manually when needed.
(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 "s-m 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 "s-m 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 "s-m u") 'mpd/update-database)
youtube-dl
(defun play-youtube (url)
"plays youtube."
(interactive "sUrl of video: ")
(shell-command (concat "youtube-dl " url " --add-metadata --write-info-json &" ))
(emms-add-file (substring (shell-command-to-string (concat "youtube-dl " url " --get-filename ")) 0 -1)))
UI modernization
Icons to make things pretty
M-x all-the-icons-install-fonts
(use-package all-the-icons
:ensure t)
Atomic actions
Duplicate Line atomically
;; https://stackoverflow.com/questions/88399/how-do-i-duplicate-a-whole-line-in-emacs
(defun duplicate-line (arg)
"Duplicate current line, leaving point in lower line."
(interactive "*p")
;; save the point for undo
(setq buffer-undo-list (cons (point) buffer-undo-list))
;; local variables for start and end of line
(let ((bol (save-excursion (beginning-of-line) (point)))
eol)
(save-excursion
;; don't use forward-line for this, because you would have
;; to check whether you are at the end of the buffer
(end-of-line)
(setq eol (point))
;; store the line and disable the recording of undo information
(let ((line (buffer-substring bol eol))
(buffer-undo-list t)
(count arg))
;; insert the line arg times
(while (> count 0)
(newline) ;; because there is no newline in 'line'
(insert line)
(setq count (1- count))))
;; create the undo information
(setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list)))) ; end-of-let
;; put the point in the lowest line and return
(next-line arg))
making new lines
(defun newline-below-go ()
"1. move to end of the line.
2. insert newline with index"
(interactive)
(let ((oldpos (point)))
(end-of-line)
(newline-and-indent)))
(defun newline-above-go ()
"1. move to end of the line.
2. insert newline with index"
(interactive)
(let ((oldpos (point)))
(beginning-of-line)
(newline-and-indent) ;;fixme indent the new line
(previous-line)
(end-of-line)))
deleting lines
(defun kill-previous-line ()
"1. move to end of the line.
2. insert newline with index"
(interactive)
(let ((oldpos (point)))
(previous-line)
(kill-whole-line)))
(defun kill-next-line ()
"1. move to end of the line.
2. insert newline with index"
(interactive)
(let ((oldpos (point)))
(next-line)
(kill-whole-line)))
(defun backward-kill-line (arg)
"Kill ARG lines backward."
(interactive "p")
(kill-line (- 1 arg)))
WM startup
Tabs
;; abolish tabs
(setq-default indent-tabs-mode nil)
(setq tab-stop-list (number-sequence 2 120 2))
editorconfig
(use-package editorconfig
:ensure t
:config
(editorconfig-mode 1))
:lighter
Diminishing modes
Your modeline is sacred, and if you have a lot of modes enabled, as you will if you use this config,
you might end up with a lot of clutter there, the package diminish
disables modes on the mode line but keeps
them running, it just prevents them from showing up and taking up space.
THIS WILL BE REMOVED SOON AS USE-PACKAGE HAS THE FUNCTIONALITY BUILT IN
Edit this list as you see fit!
(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 'editorconfig-mode)
(diminish 'subl-mode)
(diminish 'emo-mode)
(diminish 'org-indent-mode)
(diminish 'projectile-mode)
(diminish 'helm-mode)
(diminish 'company-mode)
(diminish 'undo-tree-mode)
(diminish 'ivy-mode)
(diminish 'flycheck-mode)
;; (diminish 'projectile-mode "➶")
;; (diminish 'helm-mode "⛫")
;; (diminish 'company-mode "✓")
(diminish 'rainbow-mode))
elfeed
replacing gnus with elfeed
elfeed itself
(use-package elfeed
:ensure t)
elfeed goodies
org mode feed list
(use-package elfeed-org
:ensure t
:config
(elfeed-org)
(setq rmh-elfeed-org-files (list "~/Dropbox/newsfeeds.org" )))
gnus
hackernews in gnus
i may turn this back on once i have a better grasp of gnus
(use-package nnhackernews
:ensure t
:config
(add-to-list 'gnus-secondary-select-methods '(nnhackernews "")))
reddit in gnus
i may turn this back on once i have a better grasp of gnus
;; (use-package nnreddit
;; :ensure t
;; :config
;; (add-to-list 'gnus-secondary-select-methods '(nnreddit "")))
convert atom feeds to rss
;; (require 'mm-url)
;; (defadvice mm-url-insert (after DE-convert-atom-to-rss () )
;; "Converts atom to RSS by calling xsltproc."
;; (when (re-search-forward "xmlns=\"http://www.w3.org/.*/Atom\""
;; nil t)
;; (goto-char (point-min))
;; (message "Converting Atom to RSS... ")
;; (call-process-region (point-min) (point-max)
;; "xsltproc"
;; t t nil
;; (expand-file-name "~/atom2rss.xsl") "-")
;; (goto-char (point-min))
;; (message "Converting Atom to RSS... done")))
;; (ad-activate 'mm-url-insert)
config management
something that sets the indentation of org mode src blocks
screenreader
eloud
(use-package eloud
:ensure t
:config
(setq eloud-espeak-path "/usr/bin/espeak"))
org
todo states
(setq org-todo-keywords
'((sequence "TODO(t)" "PLAN(p)" "WAIT(w@)" "|" "DONE(d!)" "CANCELED(c@)" "MISSED(m@)")))