contents
introduction
Iāve been using GNU Emacs for most of my adult life. Iām nowhere near being any sort of guru, and Iāll never be a saint in the Church of Emacs, but I manage well enough. I use Emacs mainly for the following purposes:
- writing fiction
- writing blog posts and rants
- tinkering with my personal website
- writing shell scripts and makefiles
- managing files with
dired
I use Emacs on GNU/Linux, BSD, and macOS.
This is my configuration. Its source
is an Org Mode file from
which I
extract my config using org-babel
. I use the
same file to generate this web page.
initialization
This section handles low-level settings and dependencies needed in other sections.
package mangler
I want to be able to pull packages from the main Emacs
repositories, and have the latest Org Mode when I decide to use
Org (like for this config file). I also want to use
use-package
to install and configure packages.
(require 'package)
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
("org" . "https://orgmode.org/elpa/")
("elpa" . "https://elpa.gnu.org/packages/")))
(package-initialize)
(unless package-archive-contents
(package-refresh-contents))
use-package
If we donāt have the use-package macro installed, grab it, load it, and tweak some of its settings.
(unless (package-installed-p 'use-package)
(package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t)
I want use-package
to always
use the ensure
function to
guarantee that a package is installed and loaded, lest I forget
to specify it for a given package.
diminish
I also want the diminish
package because my
modeline is intolerably cluttered.
(unless (package-installed-p 'diminish)
(package-install 'diminish))
(require 'diminish)
custom variables
These are some variables I use elsewhere in my configuration.
They can also be modified through the āCustomizeā interface
because I defined them with defcustom
instead of defvar
.
(defcustom mg-local-config
"~/.emacs.d/local.el"
"location of a local config with custom settings")
(defcustom mg-name
"Matthew Graybosch"
"redundant custom variable for setting user name")
(defcustom mg-email
"contact@starbreaker.org"
"redundant custom variable for setting mail address")
(defcustom mg-default-font
""
"custom variable for default/fixed-width font name")
(defcustom mg-default-variable-font
""
"custom variable for variable-width font name")
(defcustom mg-default-font-size
200
"custom variable for default/fixed-width font size")
(defcustom mg-default-variable-font-size
200
"custom variable for variable-width font size")
(defcustom mg-dired-path
"/tmp"
"custom variable for default dired path")
(defcustom mg-shell
"sh"
"custom variable for vterm shell")
local settings
I may want to customize certain settings for a particular machine, like font size.
(when (file-exists-p mg-local-config)
(load-file mg-local-config))
putting customizations in a separate file
Apparently the Emacs package mangler concatenates customizations into the main init file. That doesnāt strike me as desirable behavior, but we can change it.
(setq custom-file (concat user-emacs-directory "custom.el"))
(load custom-file t)
personal information
I want Emacs to know my name and email address. Among other things, this is useful with the magit package. Iām using variables Iāve set earlier on.
(setq user-full-name mg-name
user-mail-address mg-email)
custom functions
Defining functions here for use elsewhere.
mg-text-scale-reset
A little function to reset text scaling after adjusting it
(defun mg-text-scale-reset ()
"reset text size after adjusting scaling"
(interactive)
(text-scale-set 0))
mg-emms-track-description
I cribbed this function from EmacsWiki. It was originally written by Filipp Gunbin. I decided I donāt need the year display.
(defun mg-emms-track-description (track)
"Return a somewhat nice track description."
(let ((artist (emms-track-get track 'info-artist))
(year (emms-track-get track 'info-year))
(album (emms-track-get track 'info-album))
(tracknumber (emms-track-get track 'info-tracknumber))
(title (emms-track-get track 'info-title)))
(cond
((or artist title)
(concat (if (> (length artist) 0) artist "Unknown artist") " - "
(if (> (length album) 0) album "Unknown album") " - "
(if (> (length tracknumber) 0)
(format "%02d" (string-to-number tracknumber))
"XX") " - "
(if (> (length title) 0) title "Unknown title")))
(t
(emms-track-simple-description track)))))
mg-recent-file-open
I cribbed this from Mastering
Emacs, but I donāt really need it when I could just use
counsel-recentf
instead.
(defun mg-recent-file-open ()
"Use `ido-completing-read' to \\[find-file] a recent file"
(interactive)
(if (find-file (ido-completing-read "Find recent file: " recentf-list))
(message "Opening file...")
(message "Aborting")))
key bindings
Some custom key bindings here. Not necessarily Stallman-approved, but thatās how Free Software works. š©
wait; this isnāt vi
C-g
is the cancel key in Emacs,
but if Iām drunk I might forget and hit ESC
instead. This binding makes that key
cancel as well. Donāt use this if youāre used to using ESC
as your meta key because you use
Emacs in a terminal.
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
get a word count for the current buffer/region
When Iām writing text, it helps to be able to easily get a word count. So letās bind a key that will give me a count for the current buffer/region.
(bind-key "C-c w" 'count-words)
joining lines
I might want to join āfilledā paragraphs into a single line for ease of editing.
(bind-key "C-c j" 'join-line)
text scaling
Depending on how Iām feeling, and whether or not my wife has her glasses on when looking over my shoulder, I may need to enlarge the text on my screen.
(bind-key "M-+" 'text-scale-increase)
(bind-key "M-=" 'text-scale-increase)
(bind-key "M--" 'text-scale-decrease)
(bind-key "M-0" 'mg-text-scale-reset)
replace find-file-read-only with a recentf function
I canāt remember the last time I bothered opening a file in
read-only mode, but thereās always
M-x find-file-read-only
if I really need it.
(global-set-key (kbd "C-x C-r") 'counsel-recentf)
custom windmove bindings
The default windmove
bindings
use C-<up>
, C-<down>
, etc.
and donāt necessarily play nicely with general movement or Org
mode. So Iām remapping that functionality to the
C-c
prefix, which is traditionally used for custom
keybindings.
(global-set-key (kbd "C-c <up>") 'windmove-up)
(global-set-key (kbd "C-c <down>") 'windmove-down)
(global-set-key (kbd "C-c <left>") 'windmove-left)
(global-set-key (kbd "C-c <right>") 'windmove-right)
package installation
Iām installing a bunch of additional packages, so letās try to keep them in one section.
projectile
Not sure why I didnāt get around to installing this before,
but whatever. This should help me deal with files in
repositories more easily. Weāre also going to install packages
for fd
and ripgrep
and make sure Emacs
knows about them.
(use-package projectile
:ensure t
:init
(setq projectile-project-search-path '("~/texts/" ("~/git" . 1)))
(projectile-mode +1)
:bind (:map projectile-mode-map
("s-p" . projectile-command-map)
("C-c p" . projectile-command-map)))
(use-package ripgrep
:ensure t)
(use-package projectile-ripgrep
:ensure t)
Youāll also want to install fd-find
and
ripgrep
via your operating systemās package mangler
to avoid dependency errors.
circadian
This will let me use a light theme during the day and a dark theme at night, regardless of OS. I would just to give it my ICBM address.
(use-package circadian
:diminish
:config
(setq calendar-latitude 40.28)
(setq calendar-longitude -76.85)
(setq circadian-themes '((:sunrise . modus-operandi)
(:sunset . modus-vivendi)))
(circadian-setup))
editor config
I havenāt had much use for this in personal projects, but I want it available if I ever work on somebody elseās stuff and they care enough about a common coding style to create a standard configuration.
(use-package editorconfig
:diminish
:init
(editorconfig-mode 1))
org mode
Org Mode fans find it useful for all sorts of work; maybe I should take a hint and dig deeper to see what more I can do with it in my own work.
In the meantime, letās get the current org from the
repository and make sure the Lisp modules included with it are
part of Emacsā load-path
.
(use-package org
:load-path ("lisp/org-mode/lisp" "lisp/org-mode/lisp/contrib/lisp"))
(require 'ox-md)
I donāt remember why I explicitly required the module for Org-to-Markdown export, but I suspect I wanted it for something. Doesnāt seem to be doing any harm so Iāll leave it for now.
Even though I have all text modes set to use variable-pitch-mode
, I still want Org to
use fixed-pitch text when displaying code and other
pre-formatted text. I cargo-culted the following from zzamboni.org.
(custom-theme-set-faces
'user
'(org-block ((t (:inherit fixed-pitch))))
'(org-code ((t (:inherit (shadow fixed-pitch)))))
'(org-document-info ((t (:foreground "dark orange"))))
'(org-document-info-keyword ((t (:inherit (shadow fixed-pitch)))))
'(org-indent ((t (:inherit (org-hide fixed-pitch)))))
'(org-link ((t (:foreground "royal blue" :underline t))))
'(org-meta-line ((t (:inherit (font-lock-comment-face fixed-pitch)))))
'(org-property-value ((t (:inherit fixed-pitch))) t)
'(org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))))
'(org-table ((t (:inherit fixed-pitch :foreground "#83a598"))))
'(org-tag ((t (:inherit (shadow fixed-pitch) :weight bold :height 0.8))))
'(org-verbatim ((t (:inherit (shadow fixed-pitch))))))
markdown mode
I think it might be nice to get away from Markdown and just
use Org Mode for everything. Itās built into Emacs and pandoc
can work as easily with Org
markup as it does with Markdown. But Iām familiar with Markdown,
so not yetā¦
(use-package markdown-mode
:init
(setq markdown-command "/usr/bin/pandoc")
(autoload 'markdown-mode "markdown-mode" "Major mode for editing Markdown files" t)
(add-to-list 'auto-mode-alist
'("\\.\\(?:md\\|markdown\\|mkd\\|mdown\\|mkdn\\|mdwn\\)\\'" . markdown-mode))
(autoload 'gfm-mode "markdown-mode" "Major mode for editing GitHub Flavored Markdown files" t)
(add-to-list 'auto-mode-alist
'("README\\.md\\'" . gfm-mode)))
Just like with Org mode, I want pre-formatted text and code to use fixed-pitch when everything else is variable-pitch.
(custom-theme-set-faces
'user
'(markdown-pre-face ((t (:inherit fixed-pitch))))
'(markdown-code-face ((t (:inherit fixed-pitch)))))
async
I mainly use this for the dired-async
module; the others arenāt
relevant to my use case, but I donāt want dired
freezing Emacs during a
long-running operation.
(use-package async
:diminish
:init
(dired-async-mode 1))
web mode
This is a major mode for writing HTML and CSS. It can be set to work in PHP, Handlebars, ERB, and other templating languages, but I donāt need those at the moment.
(use-package web-mode
:bind (
("C-c s p p" . sgml-pretty-print))
:init
(add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.htm\\'" . web-mode))
(setq web-mode-ac-sources-alist
'(("css" . (ac-source-css-property))
("html" . (ac-source-words-in-buffer ac-source-abbrev)))))
Letās include Emmet mode, too. For shits und giggles.
(use-package emmet-mode
:init
(add-hook 'sgml-mode-hook 'emmet-mode) ;; Auto-start on any markup modes
(add-hook 'html-mode-hook 'emmet-mode)
(add-hook 'web-mode-hook 'emmet-mode)
(add-hook 'css-mode-hook 'emmet-mode))
el-fly-indent-mode
I donāt work with Emacs Lisp often, and mainly to adjust my Emacs configuration, but when I do I want to be able to automatically indent my code.
(use-package el-fly-indent-mode
:diminish
:init
(add-hook 'emacs-lisp-mode-hook #'el-fly-indent-mode))
smartparens
Itās embarrassing to find that your code doesnāt work because a cat stole your closing parenthesis, bracket, curly brace, etc. Fortunately, thereās a package for that.
(use-package smartparens
:diminish
:init
(setq show-paren-delay 0)
(show-paren-mode t)
(add-hook 'prog-mode-hook #'smartparens-mode))
During setup I enable show-paren-mode
to highlight which set
of parentheses Iām interacting with. Itās handy when dealing
with nested parentheses. I also have a hook to activate smartparens-mode
whenever Iām working on
code instead of prose.
rainbow-delimiters
Nest parentheses deeply enough (easily done when youāre working with Emacs Lisp) and itās hard to tell which parentheses are paired. Again, thereās a package for that.
(use-package rainbow-delimiters
:diminish
:init
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode))
Thereās a hook to activate these whenever Iām editing code.
vterm
Iāve been getting into eshell
lately, but there are situations where it isnāt suitable and
ansi-term
is kinda slow and janky.
So I use vterm
.
(use-package vterm
:commands vterm
:bind (
("C-c t v" . vterm)
("C-c t a" . ansi-term))
:config
(setq term-prompt-regexp "^[^#$%>\n]*[#$%>] *")
(setq vterm-kill-buffer-on-exit 't)
(setq vterm-shell mg-shell)
(setq vterm-max-scrollback 10000))
Iāv got a custom keybinding to launch vterm
and a few other settings. Details
are in the manual. Shell depends on operating system; macOS uses
zsh
and GNU/Linux uses bash
. Iāve also taken the opportunity to
create bindings to launch ansi-term
and eshell
.
If you think thatās insane, get this. If I was using
Emacs on my corporate-issue machine I might look into making
vterm
work on Windows and use
PowerShell
.
Incidentally, when you first install vterm
it tries to compile a little C
library to integrate into Emacs. If thatās a problem for you,
then you might want to use ansi-term
or a separate terminal
emulator.
magit
This is supposed to be a nice way to do git in Emacs.
(use-package magit
:commands magit
:bind (
("C-c g g" . magit-status)
("C-c g c" . magit-commit)
("C-c g f" . magit-pull)
("C-c g p" . magit-push)
("C-c g s" . magit-stage)))
ivy mode
By default, Emacs will list possible completions
horizontally. This probably made sense to RMS but I prefer to
scroll up and down through the list. This is especially the case
when Iām searching for a string in a file with C-s
.
(use-package ivy
:diminish
:bind (("C-s" . swiper)
("C-r" . swiper-backward)
:map ivy-minibuffer-map
("TAB" . ivy-alt-done)
("C-l" . ivy-alt-done)
("C-j" . ivy-next-line)
("C-k" . ivy-previous-line)
:map ivy-switch-buffer-map
("C-k" . ivy-previous-line)
("C-l" . ivy-done)
("C-d" . ivy-switch-buffer-kill)
:map ivy-reverse-i-search-map
("C-k" . ivy-previous-line)
("C-d" . ivy-reverse-i-search-kill))
:config
(ivy-mode 1))
ivy
gives me an improved
incremental search: swiper
, which
I bind to C-s
to replace the
built-in isearch
function. Iāve
also got some navigation functions to bind within minibuffers,
and I make sure that ivy-mode
is
always available.
However, I might eventually consider setting up helm instead, if
it will let me do on its own what I currently need additional
packages to do with ivy
.
ivy-rich
This package is supposed to pretty up the ivy
interface.
(use-package ivy-rich
:diminish
:init
(ivy-rich-mode 1)
:config
(setcdr (assq t ivy-format-functions-alist)
#'ivy-format-function-line)
(setq ivy-rich-path-style 'abbrev))
counsel
In addition to ivy
, Iāve also
got counsel
set up to provide
various completion functions using the ivy-modified
minibuffer.
(use-package counsel
:diminish
:bind (("M-x" . counsel-M-x)
("C-x b" . counsel-ibuffer)
("C-x C-f" . counsel-find-file)
("s-SPC" . counsel-linux-app)
:map minibuffer-local-map
("C-r" . 'counsel-minibuffer-history))
:config
(setq counsel-linux-app-format-function
#'counsel-linux-app-format-function-name-pretty))
EMMS
EMMS seems to be the most current and feature-rich package for music playback in Emacs. Some people have theirs configured to work somewhat like iTunes did back in the day, but I havenāt taken things that far.
Iāve got cmus-style keybindings for various functions
beginning with C-c e
. Rather than create a huge
main playlist, Iām content to generate ad-hoc playlists from
directory trees or by picking files with dired.
(use-package emms
:init
(add-hook 'emms-player-started-hook 'emms-show)
:config
(require 'emms-setup)
(require 'emms-mode-line)
(require 'emms-playing-time)
(require 'emms-info)
(emms-all)
(emms-mode-line 0)
(emms-playing-time 0)
(setq emms-source-file-default-directory "~/Music/")
(setq emms-player-list '(emms-player-mpv))
(setq emms-player-mpv-update-metadata t)
(setq emms-player-mpv-environment '("PULSE_PROP_media.role=music"))
(setq emms-player-mpv-parameters '("--quiet" "--really-quiet" "--no-audio-display" "--force-window=no" "--vo=null"))
(setq emms-track-description-function 'mg-emms-track-description)
(setq emms-info-asynchronously t)
(add-to-list 'emms-info-functions
'emms-info-native
'emms-info-exiftool)
(setq emms-show-format "[EMMS] now playing: %s")
:bind (
("C-c e e" . emms)
("C-c e v" . emms-stop)
("C-c e c" . emms-pause)
("C-c e z" . emms-previous)
("C-c e b" . emms-next)
("C-c e x" . emms-start)
("C-c e i" . emms-show)
("C-c e r" . emms-toggle-repeat-playlist)
("C-c e s" . emms-toggle-random-playlist)
("C-c e R" . emms-toggle-repeat-track)
("C-c e S" . emms-toggle-single-track)
("C-c e d" . emms-add-directory-tree)
("C-c e D" . emms-add-dired)
("C-c e p d" . emms-play-directory-tree)
("C-c e p D" . emms-play-dired)))
If you use my configuration, youāll want to make sure youāve
got mpv
and exiftool
installed for playback and tag
extraction.
Ogg Vorbis fans should be advised that the
emms-info-native
function does not like
embedded cover art, and will balk at reading metadata from files
where embedded cover art is present.
If you have a large collection of Ogg Vorbis files, manually
removing embedded cover art will not be fun.
Fortunately, itās also unnecessary. You can use the following
command if youāve got the vorbis-tools
package
installed and vorbiscomment
is in
$PATH
:
find ~/Music/ -type f -name '*.ogg' -print0 \
| xargs -0 -n1 -P8 vorbiscomment -d 'metadata_block_picture'
If you have eyeD3
installed and want to remove
embedded cover art from MP3s, too, use this:
find ~/Music/ -type f -name '*.mp3' -print0 \
| xargs -0 -n1 -P8 eyeD3 --remove-all-images
The commands above use find
and
xargs
to find all files of a given type within your
~/Music/
directory and run them
through vorbiscomment
or eyeD3
concurrently to take advantage of multicore processors. I got
this from āCommand-line
Tools can be 235x Faster than your Hadoop Clusterā by Adam
Drake.
Incidentally, if you have MPEG4 (*.m4a) files, the
emms-info-native
function wonāt retrieve metadata.
Youāll need an additional function.
emms-info-exiftool
seems to work, but as I
mentioned earlier youāll need to install exiftool
separately from Emacs.
uniquify
When Iām editing different pages in my website, it would be easy to end up with a shitload of buffers named āindex.mdā. Fortunately, Emacs has a package for this.
(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)
csv mode
Hereās a handy package for editing CSV (comma-separated
values) and TSV (tab-separated values) files in Emacs. I use the
latter when working on my website. Running TSV through
awk
beats the shit out of dicking around with JSON
and JavaScript.
(use-package csv-mode)
wc-mode
I might be able to do a little better than this, though. Maybe I can get a word count in my mode line. Though I should set a delay so that Emacs isnāt constantly trying to update the count while Iām typing.
;; (use-package wc-mode
;; :config
;; (setq wc-idle-wait 30
;; wc-modeline-format "(Wc: %tw)")
;; (add-hook 'text-mode-hook #'wc-mode))
Unfortunately, even with wc-idle-wait
set,
wc-mode slows down Emacs when the active buffer contains more
than 10,000 words. This makes it unsuitable for use when writing
longform prose like novellas or full-on novels.
Maybe thereās something Iām missing. Perhaps wc-mode
doesnāt play nicely with olivetti-mode
? Regardless, letās not use
this. Donāt forget to manually remove the package with
M-x package-delete
.
olivetti
When writing text, letās center it and soft-wrap it at 72 characters. The olivetti package (named for the typewriter) makes this easy.
(use-package olivetti
:diminish
:config
(add-hook 'text-mode-hook #'olivetti-mode)
(setq-default olivetti-body-width 72))
eshell
Hereās some configuration for eshell
. Gonna use a Lisp command
line.
(use-package eshell
:commands eshell
:bind (
("C-c t e" . eshell))
:init
(setq eshell-directory-name "~/.emacs.d/eshell/"
eshell-history-file-name "~/.emacs.d/eshell/history"
eshell-aliases-file "~/.emacs.d/eshell/aliases"
eshell-last-dir-ring-file-name "~/.emacs.d/eshell/lastdir"
eshell-banner-message "Welcome to GNU Emacs. This is eshell.\n\n")
;; Visual commands
(setq eshell-visual-commands '("htop" "neofetch" "vim" "lynx"))
(setq eshell-visual-subcommands '("git" "log" "diff" "show")))
;; aliases
(defalias 'ff 'find-file)
esxml
This seems to be a dependency for nov.el
.
(use-package esxml
:diminish)
nov.el
This is a package for reading ebooks (in EPUB format) in Emacs
(use-package nov
:config
(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
(add-hook 'nov-mode-hook 'olivetti-mode))
BBCode
Iāve been frequenting more forums that allow BBCode formatting, and Friendica also seems to do BBCode internally, but who wants to type in a browser? Letās make Emacs speak BBCode.
(use-package bbcode-mode)
Org Mode ā BBCode
If I do more writing on my website with Org Mode, but want to syndicate to a forum or Friendica, why not extend Orgās publisher to output BBCode?
(use-package ox-bb)
Unfortunately, quite a few Org features arenāt implemented. I
guess begin_html
is considered a āspecial-blockā in
ox-bb.el
, and
begin_verse
isnāt implemented either.
I might have to start using straight.el
instead of the built-in
package.el
so I can fork the ox-bb repository and
implement some of this shit myself. Dammit.
Apple Dictionary integration
Thereās a package I can use with Appleās Dictionary on macOS.
Iāll implement dictd
integration separately, since
thatās mainly relevant to GNU/Linux.
(cond ((eq system-type 'darwin)
(use-package osx-dictionary
:bind (("C-c d l" . osx-dictionary-search-word-at-point)
("C-c d i" . osx-dictionary-search-input)))))
dictd integration on GNU/Linux
(cond ((eq system-type 'gnu/linux)
(use-package dictionary
:bind (("C-c d l" . dictionary-lookup-definition))
:config
(dictionary-server "localhost"))))
unfill
This is a package for hard-breaking paragraphs at an arbitrary column or unbreaking them.
(use-package unfill
:diminish
:bind (("C-c u r" . unfill-region)
("C-c u p" . unfill-paragraph)
("C-c u t" . unfill-toggle)))
UI settings
This section contains UI settings that donāt require external packages.
tweaks based on OS type
Some settings are only relevant for macOS. For example, I
have to install GNU coreutils via homebrew
and I want Emacs to use the
tools from that package instead of the BSD-based macOS userland.
I also want to use the Command key as a Meta key in Emacs
(though this requires adjusting the key for one of macOSā
screenshot tools in system settings).
GNU/Linux might have different fonts or a different default shell. I account for these differences here using the custom variables I defined earlier.
(cond ((eq system-type 'darwin)
(setq insert-directory-program "/opt/homebrew/bin/gls"
dired-use-ls-dired t
mg-default-font "Menlo"
mg-default-variable-font "Georgia"
mg-dired-path "/Users/starbreaker/"
mg-shell "zsh"
ns-alternate-modifier 'alt
ns-command-modifier 'meta
ns-right-alternate-modifier 'super
exec-path (append exec-path '("/opt/homebrew/bin"))
explicit-shell-file-name "/bin/zsh")
(setenv "PATH" (concat (getenv "PATH") ":/opt/homebrew/bin")))
((eq system-type 'gnu/linux)
(setq mg-default-font "Noto Mono"
mg-default-variable-font "Noto Serif"
mg-dired-path "/home/starbreaker"
mg-shell "bash"
explicit-shell-file-name "/bin/bash")))
font settings
Letās set up default, fixed-width, and variable-width fonts using the variables defined and set above.
(set-face-attribute 'default nil
:font mg-default-font
:height mg-default-font-size
:weight 'regular)
(set-face-attribute 'fixed-pitch nil
:font mg-default-font
:height mg-default-font-size
:weight 'regular)
(set-face-attribute 'variable-pitch nil
:font mg-default-variable-font
:height mg-default-variable-font-size
:weight 'regular)
adjusting screen elements
I donāt think I need a toolbar or scrollbar on a graphics display. I do want to see how big the file is, and I want column numbers displayed in the modeline along with the current line. I donāt need a blinking cursor, though. Not when Iām highlighting the current line.
(size-indication-mode)
(column-number-mode)
(when (display-graphic-p)
(tool-bar-mode 0)
(scroll-bar-mode 0)
(blink-cursor-mode 0)
(setq scroll-margin 0
scroll-conservatively 100000
scroll-preserve-screen-position 1)
(if (version<= "29.1" emacs-version)
(pixel-scroll-precision-mode 1)))
`pixel-scroll-precision-mode` is new in Emacs 29.1. Iāve got to check `emacs-version` because Iām still using Emacs 28.2 on Debian.
modus themes
Letās set a different theme from the default. The built-in modus themes are pretty sweet.
(require-theme 'modus-themes)
(setq modus-themes-bold-constructs t
modus-themes-italic-constructs t)
(load-theme 'modus-operandi)
(define-key global-map (kbd "<f5>") #'modus-themes-toggle)
Iām not going to explicitly load the theme yet, because the modus themes have light and dark variants and I want to use both at the appropriate time:
modus-operandi
during the daymodus-vivendi
at night
Thereās a package I can use to automate theme switching, but
I also have the theme toggle bound to F5
.
current bufferās filename as frame title
This is probably most useful to people using multiple Emacs frames. Thatās usually not me, though.
(setq frame-title-format
'((:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name)) "%b"))))
whitespace visibility settings
Here are some settings that should make text editing easier.
(add-hook 'text-mode-hook (lambda ()
(setq show-trailing-whitespace t
indicate-empty-lines t
indicate-buffer-boundaries 'left)))
(add-hook 'prog-mode-hook (lambda ()
(setq show-trailing-whitespace t
indicate-empty-lines t
indicate-buffer-boundaries 'left)))
I donāt want these settings active in eshell
or
vterm
.
newline at the end
Since I live in UNIX, I want to make sure thereās a newline at the end of the file when I save. Just in case.
(setq-default require-final-newline t)
single space after sentences
Apparently Emacs thinks Iām going to type two spaces after a sentence. Like hell I willā¦
(setq sentence-end-double-space nil)
some indentation settings
Iām not happy with the way Emacs handles tabs and indentation. Maybe this will help.
(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(setq c-basic-offset 4)
(setq js-indent-level 2)
(setq css-indent-offset 2)
decluttering the working directory
Iām fine with Emacs creating temp files, but it would be nice if they all went into temp directory.
(make-directory "~/.emacs.d/auto-save/" t)
(make-directory "~/.emacs.d/backup/" t)
(make-directory "~/.emacs.d/eshell/" t)
(setq auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save/" t)))
(setq backup-directory-alist '(("." . "~/.emacs.d/backup/")))
(setq backup-by-copying t)
(setq create-lockfiles nil)
kill a whole line
If Iām at the start of a line (column 0) and kill a line, I want it to take the newline at the end, too.
(setq kill-whole-line t)
dired tweaks
I like using dired
in Emacs as my file manager,
even if my OS or desktop environment provides its own file
mangler. The interface is consistent across platforms.
(with-eval-after-load 'dired
(require 'dired-x)
(define-key dired-mode-map "K" 'kill-this-buffer))
(setq dired-recursive-deletes 'always
dired-recursive-copies 'always
dired-deletion-confirmer 'y-or-n-p
dired-clean-up-buffers-too t
delete-by-moving-to-trash t
dired-dwim-target t
dired-listing-switches "-hal --group-directories-first")
Iāve got a few quality-of-life settings in place.
- If Iām deleting a directory, I definitely want recursive delete.
- If Iām copying a directory, I likewise want recursive copy.
- A simply āyā or ānā should be answer enough; donāt make me type āyesā or ānoā.
- If Iām deleting a directory but have subdirectories open in dired buffers, I want the buffers killed off, too.
- When I delete, I want to move to Trash. Just in case I fucked up.
- When permitted,
dired
does a reasonably good job of figuring out where I want to put things when I go to copy or move files, so Iāll let it pick out a default destination. dired
usesls
to generate listings, so I pass switches that will list one item per line, show hidden files/directories, and give sizes in human-readable units. I also want directories listed first.- Pressing āKā should kill a dired buffer. Pressing āqā only buries the buffer.
donāt make me type yes/no
āNuff said.
(fset 'yes-or-no-p 'y-or-n-p)
automatic reload
If a file changes outside of Emacs (because I pulled a new version from a remote git repository), I want Emacs to reload it.
(global-auto-revert-mode t)
show line numbers on the left when coding
If Iām working on a code file, I want line numbers on the left.
(dolist (mode '(prog-mode-hook))
(add-hook mode (lambda () (display-line-numbers-mode 1))))
garbage collection when not focused
If Iāve switched to another app, like a browser, I want Emacs to do garbage collection.
(add-hook 'focus-out-hook 'garbage-collect)
time and date in modeline?
If Iām going to run Emacs full-screen, having the time and date in the modeline would be cool. I only want the time and date, though. Not the load average. Nor a mail notification. And weāll update the modeline every 10 seconds to avoid running down the battery.
(setq display-time-day-and-date t
display-time-interval 10
display-time-format "%H:%M"
display-time-default-load-average nil
display-time-use-mail-icon nil)
(display-time-mode 1)
highlight current line
I want to highlight the current line. I know itās silly.
(global-hl-line-mode 1)
go big or go $HOME
On macOS I want Emacs to run full-screen. On GNU/Linux maximized will do.
(setq frame-inhibit-implied-resize t)
(cond ((eq system-type 'darwin)
(add-hook 'window-setup-hook 'toggle-frame-fullscreen t))
((eq system-type 'gnu/linux)
(add-hook 'window-setup-hook 'toggle-frame-maximized t)
(menu-bar-mode 0)))
Iām not disabling the menu on macOS because Emacs plays nicely with the menu bar.
diminish minor modes
Minor modes tend to clutter the modeline unless diminished.
(diminish 'subword-mode)
(diminish 'visual-line-mode)
(diminish 'buffer-face-mode)
(diminish 'eldoc-mode)
recent files
It might be handy to have Emacs track recently opened files as well as maintaining session state.
(require 'recentf)
(recentf-mode t)
(setq recentf-max-saved-items 50)
(add-to-list 'ivy-sort-functions-alist
'(counsel-recentf . file-newer-than-file-p))
preserve session
Emacs has a module called desktop
that I can use
to save my current session in case I need to restart Emacs for
whatever reason. Ideally, any files have open in a given session
will re-open when I restart the session.
(require 'desktop)
(defvar mg-desktop-path "~/.emacs.d/session/")
(make-directory mg-desktop-path t)
(setq desktop-path (list mg-desktop-path))
(when (file-exists-p (desktop-full-file-name mg-desktop-path))
(desktop-read mg-desktop-path))
(desktop-save-mode 1)
(add-hook 'kill-emacs-hook (lambda () (desktop-save mg-desktop-path)))
(add-hook 'focus-out-hook (lambda () (desktop-save mg-desktop-path)))
The potential downsides are as follows:
- The more buffers I had open, the longer it will take to reopen them.
- Emacs will try to open any windows and frames I had open.
- If I have EMMS playing, Emacs might try to start that up again, too.
start in eshell
It looks like desktop
doesnāt keep my
eshell
buffer open, and I always want it
available.
(eshell)
using this configuration
You are welcome to take what you will from it for your own use. Youāre likewise welcome to use the whole thing, but Iād advise against it unless you know what youāre doing and are much closer to Emacs guruhood than I am.
As Sacha Chua suggests in her own
config, you might want to take small individual pieces and
test them in your *scratch*
using
M-x eval-region
to see if you like how Emacs
behaves afterward before adding them to your config.
You are also welcome to email me if you have questions or want to suggest an improvement that might help me.