26 KiB
luxicks Emacs Configuration
- Set Up use-package
- Fix Defaults
- Useful Functions
- Fonts
- Theming
- Completion
- Magit
- Org Mode
- Treemacs
- Elfeed
- Misc Packages
- Programming
- Load additional files
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 use-package
Throughout this configuration I will use use-package to configure packages from melpa and other sources.
Link to GitHub page
(require 'package)
;; Add melpa to the package repos
(add-to-list 'package-archives
'("melpa" . "http://melpa.org/packages/"))
(package-initialize)
;; Install use-package
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(setq use-package-always-ensure t)
Packages that are manually installed should be saved under .emacs.d/packages
(add-to-list 'load-path "~/.emacs.d/packages/")
Fix Defaults
Hide UI elements
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)
Disable file backups
Emacs sure loves to clutter directories with backup files.
(setq make-backup-files nil)
(setq auto-save-default nil)
(setq create-lockfiles nil)
Other Settings
;; The default encoding should be utf-8 everywhere
(prefer-coding-system 'utf-8)
;; All "Yes or No" questions can be shortend to "y or n".
(defalias 'yes-or-no-p 'y-or-n-p)
;; No more startup messages and screens
(setq inhibit-startup-screen t)
(setq initial-scratch-message nil)
(defun display-startup-echo-area-message ()
(message "Welcome Back!"))
;; Highlight matching braces
(show-paren-mode t)
;; cua-mode. Like any other editor
(cua-mode t)
;; Configure the cursor
(setq-default
cursor-type 'bar
indent-tabs-mode nil
cursor-in-non-selected-windows nil)
(blink-cursor-mode 0)
;; Default column with
(set-fill-column 95)
;; Start up in the home directory
(setq default-directory "~/")
;; Make C-k always kill the whole line
(setq kill-whole-line t)
;; Do not ding. Ever.
(setq ring-bell-function 'ignore)
;; Dialogues always go in the modeline.
(setq use-dialog-box nil)
;; Show tooltips on hover and not in the echo area.
;; Those are often cut of.
(tooltip-mode)
;; Better line wraping
(global-visual-line-mode 1)
Keybindings
(bind-key "C-x k" 'kill-buffer-with-prejudice)
(bind-key "C-x C-k" 'kill-buffer-and-window)
(bind-key "M-p" 'switch-to-previous-buffer)
(bind-key "M-i" 'delete-indentation)
(bind-key "C-+" 'text-scale-increase)
(bind-key "C--" 'text-scale-decrease)
;; buffer-list is not a good default
(bind-key "C-x C-b" 'ibuffer)
(bind-key "C-c n" 'display-line-numbers-mode)
Unbind useless keys.
(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
Useful Functions
Edit This File
A simple funtion to open this file for quick editing.
(defun edit-config ()
(interactive)
(find-file "~/.emacs.d/README.org"))
Reformating
Reindet the whole buffer with F12
(defun lux/indent-buffer ()
"Reindents the whole buffer"
(interactive)
(save-excursion
(indent-region (point-min) (point-max) nil)))
(global-set-key [f12] 'lux/indent-buffer)
Window Splitting
These are functions for splitting windows and move the cursor over immediately.
(defun lux/split-right-and-enter ()
"Split the window to the right and enter it."
(interactive)
(split-window-right)
(other-window 1))
(bind-key "M-3" 'lux/split-right-and-enter)
(defun lux/split-below-and-enter ()
"Split the window down and enter it."
(interactive)
(split-window-below)
(other-window 1))
(bind-key "M-2" 'lux/split-below-and-enter)
Rebind the default window controls to use "M-*" keys for ease-of-use
(bind-key "M-1" 'delete-other-windows)
(bind-key "M-0" 'delete-window)
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)))
The Links File
The link dump is the file to throw all links for later reading in.Where the file is located should be set in either personal.el or custom.el.
(defvar lux/link-dump "")
(defun lux/open-link-dump ()
"Open the file with the links"
(interactive)
(find-file lux/link-dump))
Variable Pitch Mode
This custom version of variable-pitch-mode allows to mix variable and fixed fonts in the same buffer. This is very useful for org buffers with code blocks in them. This is a slight variation of Protesilaos Stavrous version.
(use-package face-remap
:diminish buffer-face-mode ; the actual mode
:commands lux/variable-pitch-mode
:hook (text-mode . lux/variable-pitch-mode)
:config
(define-minor-mode lux/variable-pitch-mode
"Toggle `variable-pitch-mode', except for `prog-mode'."
:init-value nil
:global nil
(if lux/variable-pitch-mode
(unless (derived-mode-p 'prog-mode)
(variable-pitch-mode 1))
(variable-pitch-mode -1))))
Focused Mode
This is a special minor mode that allows focus reading of longer texts. It is a combination of other useful modes to create a distraction free reading environment.
This is a minor mode for keeping the cursor at the center of the screen while scrolling
(setq-default scroll-preserve-screen-position t)
(setq-default scroll-conservatively 1)
(setq-default scroll-margin 0)
(define-minor-mode lux/center-scroll-mode
"Toggle centred cursor scrolling behaviour."
:init-value nil
:lighter " S="
:global nil
(if lux/center-scroll-mode
(setq-local scroll-margin (* (frame-height) 2)
scroll-conservatively 0
maximum-scroll-margin 0.5)
(dolist (local '(scroll-preserve-screen-position
scroll-conservatively
maximum-scroll-margin
scroll-margin))
(kill-local-variable `,local))))
(bind-key "C-c l" 'lux/center-scroll-mode)
(define-minor-mode lux/focus-mode
"Creates a distraction free reading environment in the current buffer"
:init-value nil
:global nil
(if lux/focus-mode
(progn
(olivetti-mode 1)
(lux/center-scroll-mode 1))
(progn
(olivetti-mode -1)
(lux/center-scroll-mode -1))))
(bind-key "C-c f" 'lux/focus-mode)
Org show only current subtree
Fold all other subtrees in an org file and show just the current one
(defun lux/org-show-just-me (&rest _)
"Fold all other trees, then show entire current subtree."
(interactive)
(org-overview)
(org-reveal)
(org-show-subtree))
(bind-key "C-c m" 'lux/org-show-just-me)
Fonts
Set up the fonts to use. I like the Iosevka font family.
(set-face-attribute 'default nil :font "Iosevka Light-12")
(set-face-attribute 'fixed-pitch nil :font "Iosevka Light-12")
(set-face-attribute 'variable-pitch nil :font "Iosevka Aile Light-12")
Theming
Apply a nice looking theme. Source for the themes
;; Light Theme
(use-package modus-operandi-theme)
(use-package modus-vivendi-theme)
;; Configuration for both themes
(defmacro modus-themes-format-sexp (sexp &rest objects)
`(eval (read (format ,(format "%S" sexp) ,@objects))))
(dolist (theme '("operandi" "vivendi"))
(modus-themes-format-sexp
(defun modus-%1$s-theme-load ()
(setq modus-%1$s-theme-slanted-constructs t
modus-%1$s-theme-bold-constructs t
modus-%1$s-theme-no-link-underline nil
modus-%1$s-theme-faint-syntax t
modus-%1$s-theme-prompts 'intense
modus-%1$s-theme-completions 'moderate
modus-%1$s-theme-diffs 'fg-only
modus-%1$s-theme-org-blocks 'rainbow
modus-%1$s-theme-scale-headings t
modus-%1$s-theme-scale-1 1.1
modus-%1$s-theme-scale-2 1.15
modus-%1$s-theme-scale-3 1.21
modus-%1$s-theme-scale-4 1.27
modus-%1$s-theme-scale-5 1.33)
(load-theme 'modus-%1$s t))
theme))
Allow switching between light and dark mode
(defun modus-themes-toggle ()
"Toggle between `modus-operandi' and `modus-vivendi' themes."
(interactive)
(if (eq (car custom-enabled-themes) 'modus-operandi)
(progn
(disable-theme 'modus-operandi)
(modus-vivendi-theme-load))
(disable-theme 'modus-vivendi)
(modus-operandi-theme-load)))
Call the swich function once to load the light theme
(modus-themes-toggle)
Use a nice looking modeline package
(use-package telephone-line)
(telephone-line-mode 1)
Set up the default frame look
(setq default-frame-alist
(append (list '(width . 90) '(height . 50)
'(vertical-scroll-bars . nil)
'(internal-border-width . 5))))
Completion
Ivy
Use Ivy to make minibuf promts better. Adds the ability to sort and filter.
(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-c y" . counsel-yank-pop)
("C-c r" . counsel-recentf)
:map ivy-minibuffer-map
("C-r" . counsel-minibuffer-history))
:diminish)
Ido
(use-package ido
:config (ido-mode 1)
:bind (("C-x f" . ido-find-file)))
Autocompletion
(use-package auto-complete
:config
(ac-config-default))
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
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.
:bind (("C-c o c" . org-capture)
("C-c o l" . lux/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 a s" . org-emphasize)
("C-c -" . org-edit-special))
:hook ((org-mode . visual-line-mode)
(org-mode . org-indent-mode))
:config
(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
org-hide-emphasis-markers t
)
(setcar (nthcdr 4 org-emphasis-regexp-components) 4))
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")
Export Location
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)
Export HTML
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)
Include images in org files as base64 directly into the HTML
(defun replace-in-string (what with in)
(replace-regexp-in-string (regexp-quote what) with in nil 'literal))
(defun org-html--format-image (source attributes info)
(progn
(setq source (replace-in-string "%20" " " source))
(format "<img src=\"data:image/%s;base64,%s\"%s />"
(or (file-name-extension source) "")
(base64-encode-string
(with-temp-buffer
(insert-file-contents-literally source)
(buffer-string)))
(file-name-nondirectory source))
))
Org Mode Bling
(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)
;; Replace dash in bullet lists with unicode symbol
(font-lock-add-keywords 'org-mode
'(("^ *\\([-]\\) "
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))
;; 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)
;; 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)
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
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))
)
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 lux/link-dump)
"* NEW %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i\n")
))
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-show-hidden-files t
treemacs-sorting 'alphabetic-asc
treemacs-width 35)
(treemacs-filewatch-mode t)
(treemacs-toggle-show-dotfiles))
:bind
(:map global-map
("C-x t t" . treemacs)
("M-9" . treemacs-select-window)))
(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)
:config
(add-hook 'elfeed-show-mode-hook #'lux/focus-mode))
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))
Misc Packages
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-o 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)
Olivetti
A simple Emacs minor mode for a nice writing environment. Gihub Link
(use-package olivetti
:diminish
:config
(setq olivetti-minimum-body-width 72)
(setq olivetti-body-width 0.65)
(setq olivetti-recall-visual-line-mode-entry-state t))
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)
Yasnippet
(use-package yasnippet
:config
(progn
(setq yas-snippet-dirs '("~/.emacs.d/snippets"))
(yas-global-mode 1)))
Programming
Elisp
Some customization for writing elisp
(defun my-elisp-mode-hook ()
"My elisp customizations."
(electric-pair-local-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)
Load additional files
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 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)