luxicks Emacs Configuration
- Set up UI
- Set up package repositories
- Set Backup Location
- Define useful functions
- Theming
- Ivy
- Counsel
- Magit
- Org Mode
- Treemacs
- Elfeed
- Additional Package Imports
- Set Variables
- General Emacs Options
- Read environment variables from the shell
- Show the current filename in titlebar
- Default encoding
- Shorten "yes or no" questions
- Always highlight the current line
- Always highlight matching braces
- Allow selection override
- Behave like a normal text editor
- Set cursor and indet mode
- Set default column width
- Hooks
- Global Key Bindings
- Load
personal.el - Load
custom.el
This is my configuration for the emacs editor.
Points of intrest:
- Personal information (name, email) are stored in a separate
personal.elfile. - Machine specific settings are stored in a separate
custom.elfile. - Both files are loaded automatically.
- When Exporting HTML from
org-modethe style from theorg-theme.cssfile is inlined automatically.
Set up UI
Remove all those UI elements. They do not look good and waste space.
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(tooltip-mode -1)
(fringe-mode -1)
Set up package repositories
Require package support
State that we will need package support and define a macro for adding package repos to the archives
(require 'package)
(defmacro append-to-list (target suffix)
"Append SUFFIX to TARGET in place."
`(setq ,target (append ,target ,suffix)))
Add package repos
(append-to-list package-archives
'(("melpa" . "http://melpa.org/packages/")
("org-elpa" . "https://orgmode.org/elpa/")))
Ensure use-package command is present
(package-initialize)
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(require 'use-package)
(setq
use-package-always-ensure t
use-package-verbose t)
(use-package gnu-elpa-keyring-update)
Set Backup Location
Emacs, by default clutters the file system with backup files. We do not want them to be right next to the actual file, so we tell emacs to use dedicated directory to store them. While we are at it, we also set rule for how many version emacs should keep as backups.
(setq backup-directory-alist `(("." . "~/.emacs-backup")))
(setq backup-by-copying t)
(setq delete-old-versions t
kept-new-versions 6
kept-old-versions 2
version-control t)
Define useful functions
Edit the config file
A simple funtion to open this file for quick editing.
(defun edit-config ()
(interactive)
(find-file "~/.emacs.d/README.org"))
Reformat a whole buffer
Reindet the whole buffer with F12
(defun indent-buffer ()
(interactive)
(save-excursion
(indent-region (point-min) (point-max) nil)))
(global-set-key [f12] 'indent-buffer)
Split windows and immediately switch to it
(defun split-right-and-enter ()
"Split the window to the right and enter it."
(interactive)
(split-window-right)
(other-window 1))
(defun split-below-and-enter ()
"Split the window down and enter it."
(interactive)
(split-window-below)
(other-window 1))
Quick buffer switching
(defun switch-to-previous-buffer ()
"Switch to previously open buffer. Repeated invocations toggle between the two most recently open buffers."
(interactive)
(switch-to-buffer (other-buffer (current-buffer) 1)))
Fold all except the current heading
With this all other subtrees in the buffer van be collapsed, leaving only the subtree at the point expanded
(defun org-show-current-heading-tidily ()
(interactive) ;Inteactive
"Show next entry, keeping other entries closed."
(if (save-excursion (end-of-line) (outline-invisible-p))
(progn (org-show-entry) (show-children))
(outline-back-to-heading)
(unless (and (bolp) (org-on-heading-p))
(org-up-heading-safe)
(hide-subtree)
(error "Boundary reached"))
(org-overview)
(org-reveal t)
(org-show-entry)
(show-children)))
And it should be accessible with a quick keystroke:
(global-set-key "\M-s" 'org-show-current-heading-tidily)
Load file content as string
(defun get-string-from-file (filePath)
"Return filePath's file content."
(with-temp-buffer
(insert-file-contents filePath)
(buffer-string)))
Load all files in a directory
(defun load-directory (dir)
(let ((load-it (lambda (f)
(load-file (concat (file-name-as-directory dir) f)))
))
(mapc load-it (directory-files dir nil "\\.el$"))))
Theming
Apply a nice looking theme.
;; Light Theme
(use-package modus-operandi-theme)
(load-theme 'modus-operandi t)
;; Syntax highlighing
(setq modus-operandi-theme-faint-syntax t)
(setq modus-operandi-theme-org-blocks "greyscale")
(setq default-frame-alist
(append (list '(width . 90) '(height . 50)
'(vertical-scroll-bars . nil)
'(internal-border-width . 10)
'(font . "Roboto Mono Light 10"))))
Use a nice looking modeline package
(use-package telephone-line)
(telephone-line-mode 1)
Ivy
Use Ivy to make minibuf promts better. Adds the ability to sort and filter.
Use Ivy
(use-package ivy
:diminish
:init
(ivy-mode 1)
(unbind-key "S-SPC" ivy-minibuffer-map)
(setq ivy-height 30
ivy-use-virtual-buffers t
ivy-use-selectable-prompt t)
:bind (("C-x b" . ivy-switch-buffer)
("C-c C-r" . ivy-resume)
("C-s" . swiper)))
;; ivy-rich makes Ivy look a little bit more like Helm.
(use-package ivy-rich
:after counsel
:custom
(ivy-virtual-abbreviate 'full
ivy-rich-switch-buffer-align-virtual-buffer t
ivy-rich-path-style 'abbrev)
:init
(ivy-rich-mode))
(use-package ivy-hydra)
Smex
Sort commands by recency in ivy windows
(use-package smex)
Counsel
(use-package counsel
:after ivy
:init (counsel-mode 1)
:bind (("C-c ;" . counsel-M-x)
("C-c U" . counsel-unicode-char)
("C-c i" . counsel-imenu)
("C-x f" . counsel-find-file)
("C-c y" . counsel-yank-pop)
("C-c r" . counsel-recentf)
:map ivy-minibuffer-map
("C-r" . counsel-minibuffer-history))
:diminish)
Magit
Magit is THE go to package for using git in emacs.
(use-package magit
:bind (("C-c g" . magit-status))
:diminish magit-auto-revert-mode
:diminish auto-revert-mode
:custom
(magit-remote-set-if-missing t)
(magit-diff-refine-hunk t)
:config
(magit-auto-revert-mode t)
(advice-add 'magit-refresh :before #'maybe-unset-buffer-modified)
(advice-add 'magit-commit :before #'maybe-unset-buffer-modified)
(setq magit-completing-read-function 'ivy-completing-read)
(add-to-list 'magit-no-confirm 'stage-all-changes))
(use-package libgit
:disabled
:after magit)
The advice-add entries are thereto stop magit from bugging us to save buffers when commiting and refreshing.
Helper Functions
(autoload 'diff-no-select "diff")
(defun current-buffer-matches-file-p ()
"Return t if the current buffer is identical to its associated file."
(when (and buffer-file-name (buffer-modified-p))
(diff-no-select buffer-file-name (current-buffer) nil 'noasync)
(with-current-buffer "*Diff*"
(and (search-forward-regexp "^Diff finished \(no differences\)\." (point-max) 'noerror) t))))
Clear modified bit on all unmodified buffers
(defun maybe-unset-buffer-modified (&optional _)
(interactive)
(dolist (buf (buffer-list))
(with-current-buffer buf
(when (and buffer-file-name (buffer-modified-p) (current-buffer-matches-file-p))
(set-buffer-modified-p nil)))))
Don't prompt to save unmodified buffers on exit.
(advice-add 'save-buffers-kill-emacs :before #'maybe-unset-buffer-modified)
(defun kill-buffer-with-prejudice (&optional _)
"Kill a buffer, eliding the save dialogue if there are no diffs."
(interactive)
(when (current-buffer-matches-file-p) (set-buffer-modified-p nil))
(kill-buffer))
Org Mode
Define important files
The Link Dump
I use a single file to dump all links I plan on viewing later.
(defvar link-dump "")
(defun open-link-dump ()
(interactive)
(find-file link-dump))
Configure org-mode
This is the main configuration for the infamous org-mode. The most important parts are configuring key bindings to quickly access the files we have defined above.
(use-package org
;; Always get this from the GNU archive.
:pin gnu
:bind (("C-c o c" . org-capture)
("C-c o l" . open-link-dump)
("C-c o s" . org-store-link)
("C-c o a" . org-agenda)
:map org-mode-map
("M-s-<return>" . org-insert-todo-heading)
("M-<return>" . org-insert-heading-respect-content)
("C-c c" . org-mode-insert-code)
("C-c a s" . org-emphasize)
("C-c a r" . org-ref)
("C-c a e" . outline-show-all)
("C-c a t" . unindent-by-four))
:hook ((org-mode . visual-line-mode)
(org-mode . variable-pitch-mode)
(org-mode . org-indent-mode))
:config
(let ((todo-path (expand-file-name "~/Notes/todo.org")))
(when (file-exists-p todo-path)
(setq org-agenda-files (list todo-path)
org-default-notes-file todo-path)))
(setq org-footnote-section ""
org-startup-with-inline-images t
org-pretty-entities t
org-indent-mode t
org-footnote-section nil
org-hide-leading-stars nil
org-link-file-path-type 'relative
org-image-actual-width nil ; with this image sizes can be set per image, with an attribute
org-display-inline-images t
)
(setcar (nthcdr 4 org-emphasis-regexp-components) 4)
(defun org-mode-insert-code ()
(interactive)
(org-emphasize ?~)))
Set default archive location
When archiving items in org files, the default ist to crate a separate file named <filename>.org_archive.
This clutters up my notes folder quite a bit, as I use a lot of separate files with thier respective archives.
All archives should be stored in a single .archive file per directory.
(setq org-archive-location "./.archive::* From %s")
Beautify org-mode
Icons
(use-package org-bullets
:init (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
(setq org-bullets-bullet-list '("◉" "○" "◆" "✿" "✚" "▶"))
Ellipsis icon:
(setq org-ellipsis "▾")
Nice Icons for lists:
(add-hook 'org-mode-hook
(lambda ()
"Beautify Org Checkbox Symbol"
(push '("[ ]" . "☐") prettify-symbols-alist)
(push '("[X]" . "☑" ) prettify-symbols-alist)
(push '("[-]" . "❍" ) prettify-symbols-alist)
(prettify-symbols-mode)))
We also want them in exported HTML files
(setq org-html-checkbox-type 'html)
Strike out done ckeckbox items
(defface org-checkbox-done-text
'((t (:foreground "#71696A" :strike-through t)))
"Face for the text part of a checked org-mode checkbox.")
(font-lock-add-keywords
'org-mode
`(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)"
1 'org-checkbox-done-text prepend))
'append)
Replace dash in bullet lists with unicode symbol
(font-lock-add-keywords 'org-mode
'(("^ *\\([-]\\) "
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))
Prettier Timestamps in Exports
(setq-default org-display-custom-times t)
(setq org-time-stamp-custom-formats
'("<%a %d.%m.%Y>" . "<%d.%m.%y %H:%M>"))
Templates
Babel
Here we set custom templates to be used for structure expansion.
These are used when we type "<" folowed by the shortcut for a template and hit "TAB".
e.g. "<s TAB" expands to #+BEGIN_SRC ?\n\n#+END_SRC
Use org-tempo to quickly insert the structures
(require 'org-tempo)
emacs-lisp
Shortcut for creating emacs-lisp code blocks. This is used extensively in this very file.
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
Capture Support Functions
First we define a function to look the subheading under which we want to file captures:
(defun org-get-target-headline (&optional targets prompt)
"Prompt for a location in an org file and jump to it.
This is for promping for refile targets when doing captures.
Targets are selected from `org-refile-targets'. If TARGETS is
given it temporarily overrides `org-refile-targets'. PROMPT will
replace the default prompt message.
If CAPTURE-LOC is is given, capture to that location instead of
prompting."
(let ((org-refile-targets (or targets org-refile-targets))
(prompt (or prompt "Capture Location")))
(org-refile t nil nil prompt))
)
Org Capture
Here we define templates we want to use to quickly capture stuff and automatically file them away.
(setq org-capture-templates
'(("l" "Link" entry (file link-dump)
"* NEW %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i\n")
))
CSS inlining
Auto inline a CSS theme for org HTML exports. This will make sure a self contained single HTML file is created.
(defun my-org-inline-css-hook (exporter)
"Insert custom inline css"
(when (eq exporter 'html)
(let* ((dir (ignore-errors (file-name-directory (buffer-file-name))))
(path (concat dir "style.css"))
(homestyle (or (null dir) (null (file-exists-p path))))
(final (if homestyle "~/.emacs.d/org-theme.css" path))) ;; <- set your own style file path
(setq org-html-head-include-default-style nil)
(setq org-html-head (concat
"<style type=\"text/css\">\n"
"<!--/*--><![CDATA[/*><!--*/\n"
(with-temp-buffer
(insert-file-contents final)
(buffer-string))
"/*]]>*/-->\n"
"</style>\n")))))
(add-hook 'org-export-before-processing-hook 'my-org-inline-css-hook)
Export to a subdirectory
This snippet will create a sub dir for exports from org-mode. See the Stackoverflow question
(defun org-export-output-file-name-modified (orig-fun extension &optional subtreep pub-dir)
(unless pub-dir
(setq pub-dir "Exports")
(unless (file-directory-p pub-dir)
(make-directory pub-dir)))
(apply orig-fun extension subtreep pub-dir nil))
(advice-add 'org-export-output-file-name :around #'org-export-output-file-name-modified)
Treemacs
Treemacs makes navigating folders and files much easier. This is the default config from the offical repository as a base, with slight modifications to suite my config.
(use-package treemacs
:defer t
:init
(with-eval-after-load 'winum
(define-key winum-keymap (kbd "M-0") #'treemacs-select-window))
:config
(progn
(setq treemacs-collapse-dirs (if treemacs-python-executable 3 0)
treemacs-deferred-git-apply-delay 0.5
treemacs-display-in-side-window t
treemacs-eldoc-display t
treemacs-file-event-delay 5000
treemacs-file-follow-delay 0.2
treemacs-follow-after-init t
treemacs-git-command-pipe ""
treemacs-goto-tag-strategy 'refetch-index
treemacs-indentation 2
treemacs-indentation-string " "
treemacs-is-never-other-window nil
treemacs-max-git-entries 5000
treemacs-missing-project-action 'ask
treemacs-no-png-images nil
treemacs-no-delete-other-windows t
treemacs-project-follow-cleanup nil
treemacs-persist-file (expand-file-name ".cache/treemacs-persist" user-emacs-directory)
treemacs-position 'left
treemacs-recenter-distance 0.1
treemacs-recenter-after-file-follow nil
treemacs-recenter-after-tag-follow nil
treemacs-recenter-after-project-jump 'always
treemacs-recenter-after-project-expand 'on-distance
treemacs-show-cursor nil
treemacs-show-hidden-files t
treemacs-silent-filewatch nil
treemacs-silent-refresh nil
treemacs-sorting 'alphabetic-desc
treemacs-space-between-root-nodes t
treemacs-tag-follow-cleanup t
treemacs-tag-follow-delay 1.5
treemacs-width 35)
;; The default width and height of the icons is 22 pixels. If you are
;; using a Hi-DPI display, uncomment this to double the icon size.
;;(treemacs-resize-icons 44)
(treemacs-follow-mode t)
(treemacs-filewatch-mode t)
(treemacs-fringe-indicator-mode t)
(treemacs-toggle-show-dotfiles)
(pcase (cons (not (null (executable-find "git")))
(not (null treemacs-python-executable)))
(`(t . t)
(treemacs-git-mode 'deferred))
(`(t . _)
(treemacs-git-mode 'simple))))
:bind
(:map global-map
("M-0" . treemacs)
("C-x t 1" . treemacs-delete-other-windows)
("C-x t B" . treemacs-bookmark)
("C-x t C-t" . treemacs-find-file)
("C-x t M-t" . treemacs-find-tag)))
(use-package treemacs-magit
:after treemacs magit
:ensure t)
Elfeed
Elfeed is an RSS reader for emacs.
(use-package elfeed
:bind ("C-x w" . 'elfeed))
Hooks
elfeed can be extended with various hooks for ease of used
Auto tag youtube feeds
(add-hook 'elfeed-new-entry-hook
(elfeed-make-tagger :feed-url "youtube\\.com"
:add '(video youtube)))
Do not spam unread tag
(add-hook 'elfeed-new-entry-hook
(elfeed-make-tagger :before "2 weeks ago"
:remove 'unread))
Additional Package Imports
All The Icons
We want to have some nice looking icons
(use-package all-the-icons)
Recentf
Show recent files in the buffer selection
(use-package recentf
:init (recentf-mode t)
:config
(add-to-list 'recentf-exclude "\\.emacs.d")
(add-to-list 'recentf-exclude ".+tmp......\\.org"))
Rainbow Delimiters
We want to have some nicely colored delimiters when reading and writing lisp code
(use-package rainbow-delimiters
:hook (prog-mode . rainbow-delimiters-mode))
Markdown Mode
(use-package markdown-mode
:mode ("\\.md$" . gfm-mode)
:config
(when (executable-find "pandoc")
(setq markdown-command "pandoc -f markdown -t html")))
Duplicate Thing
Quick bind to ~C-c u ~ to duplicate the current line
(use-package duplicate-thing
:bind (("C-c u" . duplicate-thing)))
ACE Window
Small package to quickly switch tiled windows.
Use M-p to quickly switch.
(use-package ace-window
:bind (("M-o" . 'ace-window))
:config
(custom-set-faces
'(aw-leading-char-face
((t (:inherit ace-jump-face-foreground :height 3.0))))
))
htmlize
HTML Exporter for org-mode
(use-package htmlize)
Autocompletion
(use-package company
:config
(global-company-mode))
vterm
vterm is a superiour alternative to the integrated eshell, shell or term modes.
The packages only works on linux and reuqires that emacs is compiled with module support (the module-file-suffix variable will be filled).
(if (and (string-equal system-type "gnu/linux")
(bound-and-true-p module-file-suffix))
(use-package vterm
:ensure t
:config
(setq vterm-kill-buffer-on-exit t)
(setq vterm-copy-exclude-prompt t)))
Olivetti
A simple Emacs minor mode for a nice writing environment. Gihub Link
(use-package olivetti
:config
(setq-default
olivetti-hide-mode-line t
olivetti-body-width 90))
Auto enable it in text modes
(add-hook 'text-mode-hook 'olivetti-mode)
Ag
Ag.el allows you to search using ag from inside Emacs. You can filter by file type, edit results inline, or find files.
(use-package ag)
Set Variables
General Emacs Options
(setq
compilation-always-kill t ; Never prompt to kill a compilation session.
compilation-scroll-output 'first-error ; Always scroll to the bottom.
make-backup-files nil ; No backups, thanks.
auto-save-default nil ; Or autosaves. What's the difference between autosaves and backups?
create-lockfiles nil ; Emacs sure loves to put lockfiles everywhere.
default-directory "~/" ; Home sweet home.
inhibit-startup-screen t ; No need to see GNU agitprop.
kill-whole-line t ; Lets C-k delete the whole line
require-final-newline t ; Auto-insert trailing newlines.
ring-bell-function 'ignore ; Do not ding. Ever.
use-dialog-box nil ; Dialogues always go in the modeline.
initial-scratch-message nil ; SHUT UP SHUT UP SHUT UP
save-interprogram-paste-before-kill t ; preserve paste to system ring
enable-recursive-minibuffers t ; don't fucking freak out if I use the minibuffer twice
sentence-end-double-space nil ; are you fucking kidding me with this shit
confirm-kill-processes nil ; don't whine at me when I'm quitting.
mark-even-if-inactive nil ; prevent really unintuitive undo behavior
load-prefer-newer t ; load newest file version available
)
Read environment variables from the shell
When not running on a windows system, we can use the env variables in emacs
(use-package exec-path-from-shell
:if (not (eq system-type 'windows-nt))
:config
(exec-path-from-shell-initialize))
Show the current filename in titlebar
(setq frame-title-format
'((:eval user-login-name) "@" (:eval (system-name)) ": " (:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name))
"%b")) " [%*]"))
Default encoding
(prefer-coding-system 'utf-8)
Shorten "yes or no" questions
(defalias 'yes-or-no-p 'y-or-n-p)
Always highlight the current line
(global-hl-line-mode t)
Always highlight matching braces
(show-paren-mode t)
Allow selection override
(delete-selection-mode t)
Behave like a normal text editor
Changed: No more CUA, C-c is used in to many places that are broken by cua-mode
(cua-mode t)
Set cursor and indet mode
(setq-default
cursor-type 'bar
indent-tabs-mode nil
cursor-in-non-selected-windows nil)
Set default column width
(set-fill-column 95)
Hooks
Remove trailing whitespace on file close
(add-hook 'before-save-hook 'delete-trailing-whitespace)
Elisp
Some customization for writing elisp
(defun my-elisp-mode-hook ()
"My elisp customizations."
(electric-pair-mode 1)
(add-hook 'before-save-hook 'check-parens nil t)
(auto-composition-mode nil))
(add-hook 'emacs-lisp-mode-hook 'my-elisp-mode-hook)
Global Key Bindings
(bind-key "C-x k" 'kill-buffer-with-prejudice)
(bind-key "C-x C-k" 'kill-buffer-and-window)
(bind-key "C-c 5" 'query-replace-regexp) ;; stupid vestigial binding
(bind-key "M-/" 'hippie-expand)
(bind-key "C-c \\" 'align-regexp)
(bind-key "C-c m" 'compile)
(bind-key "C-c 3" 'split-right-and-enter)
(bind-key "C-c 2" 'split-below-and-enter)
(bind-key "M-p" 'switch-to-previous-buffer)
(bind-key "C-c /" 'comment-or-uncomment-region)
(bind-key "C-c x" 'ESC-prefix)
(bind-key "M-i" 'delete-indentation)
(bind-key "C-+" 'text-scale-increase)
(bind-key "C--" 'text-scale-decrease)
(bind-key "C-<" 'beginning-of-buffer)
(bind-key "C->" 'end-of-buffer)
(bind-key "C-x C-b" 'ibuffer) ;; buffer-list is not a good default
(bind-key "C-c n" 'line-number-mode)
Unbind some default key bindings
(unbind-key "C-<tab>") ;; prevent switching to tab mode randomly
(unbind-key "C-h n") ;; I have never wanted to see emacs news ever
(unbind-key "C-h C-n") ;; why on earth is it bound to two keybindings??
(unbind-key "C-x C-d") ;; list-directory is utterly useless given the existence of dired
(unbind-key "C-x C-r") ;; as is find-file-read-only
Load personal.el
All information about the current user should reside in the personal.el file.
This file contains personal information like name, email or other identifying information.
This file should contain definitions, that are the same on every device, but sould not be commited to a repository.
(setq personal-file "~/.emacs.d/personal.el")
(load personal-file 'noerror)
Load custom.el
Load a custom file from the emacs home dir. This file is specific to the machine emacs runs on. It conatins customizations and file locations that are machine dependend.
(setq custom-file "~/.emacs.d/custom.el")
(load custom-file 'noerror)