Emacs Configuration File
Introduction
This is my Emacs configuration, written in Org mode thanks to Howard Abrahams. Other people that have inspired this are Mike Zamansky, and David Wilson. Make sure to check out their work!
Boostrapping the configuration
Emacs configuration directory
Emacs expects to find configurations in one of several different
locations. I will use ~/.emacs.d/ on MacOS and ~/.config/emacs/ on
Linux. For more details, you can read about the The Emacs Initialization
File in the Emacs manual.
For Emacs to use the configurations in this file, clone the repository
and then create symbolic links from the configuration directory to files
init.el and emacs.org in this repo.
cd git clone git@gitlab.com:rickardsundin/dotfiles.git cd ~/.emacs.d # or ~/.config/emacs ln -s ~/dotfiles/init.el ln -s ~/dotfiles/emacs.org
Emacs on MacOS
Installation
MacOS no longer comes with Emacs preinstalled, (versions before
Catalina has it at /usr/bin/emacs), but it is easy to install the latest version
using Homebrew. I like to use the emacs-plus formula, since it comes
with some nifty features and options.
brew install emacs-plus
Running as a service
Homebrew can make Emacs run as a service in the background, and ensure
it starts automatically at login. When the service is running,
emacsclient can be used to open new editor windows connected to the
already running Emacs service.
brew services start emacs-plus
If you want to be able to launch emacsclient from Spotlight (or
Alfred), follow this instruction from StackOverflow to create a MacOS
application using Automator.
Choose to make an "Application", then choose "Run Shell Script", and add a [the] call to emacsclient:
/usr/local/bin/emacsclient -n -c -a "" – "$@"
Then change "Pass input": use "as arguments" instead of "to stdin".
The added "$@" is where any optional arguments passed to this shell script will be placed.
Feel free too change the application icon to something nicer than the default Automator icon.
I have also defined some shell aliases for quickly opening files using
emacsclient from the terminal. See Emacs related in the file .bashrc.
Permission issues
This solves some issues with MacOS permissions and Emacs. See Github issue in emacs-plus for more info.
(when (string= system-type "darwin") (setq dired-use-ls-dired t insert-directory-program "/opt/homebrew/bin/gls" dired-listing-switches "-aBhl --group-directories-first"))
Emacs on Linux
Building from source
Install required dependencies.
sudo apt build-dep emacs
Clone the git repository and branch of your choice (or the entire repo if you have enougth time and storage).
git clone --single-branch --branch emacs-29 https://git.savannah.gnu.org/git/emacs.git
cd emacs/
sudo apt build-dep emacs
./autogen.sh
./configure
make bootstrap -j16
sudo make install
Running as a service
Starting emacs as a service.
systemctl --user enable emacs
Restarting the Emacs service.
systemctl --user restart emacs
Basics
Personal info
Set some basic personal info.
(setq user-full-name "Rickard Sundin")
Appearance
Maximize the size of new windows (a.k.a "frames").
(add-to-list 'default-frame-alist '(fullscreen . maximized))
Hide the toolbar. I never use it, and am not that fond of the look of the icons.
(tool-bar-mode -1)
Hide the scrollbars, for a cleaner look. There is information in the mode line to help with figuring out what part of the current file that is being displayed.
(set-scroll-bar-mode nil)
Setting this value allows for the Emacs window (a.k.a frame) go all the way to the edge of my screen.
(setq frame-resize-pixelwise t)
Remove the startup message and the message explaining the scratch buffer.
(setq inhibit-startup-message t initial-scratch-message "")
Show row numbers by default in all modes that show code.
(add-hook 'prog-mode-hook 'display-line-numbers-mode)
Display the current column on the mode line. By default, it will only display the row number.
(setq column-number-mode t)
Show current time in mode line.
(setq display-time-24hr-format t) (setq display-time-default-load-average nil) (display-time-mode 1)
The default visible bell draws a big warning sign with an exclamation mark in the middle of the frame. I prefer this slick implementaion that flashes the mode line instead.
(setq visible-bell nil) (setq ring-bell-function (lambda () (invert-face 'mode-line) (run-with-timer 0.1 nil 'invert-face 'mode-line)))
Avoid having org-fill-paragraph insert double spaces between sentences.
(setq sentence-end-double-space nil)
No tabs, only spaces.
(setq-default indent-tabs-mode nil)
Delete trailing whitespace before saving buffers.
(add-hook 'before-save-hook 'delete-trailing-whitespace)
Make sure the calendar starts the week on Mondays.
(setq calendar-week-start-day 1)
Show week numbers in calendar.
(setq calendar-intermonth-text '(propertize (format "%2d" (car (calendar-iso-from-absolute (calendar-absolute-from-gregorian (list month day year))))) 'font-lock-face 'font-lock-warning-face))
Add a header to the week number in calendar.
(setq calendar-intermonth-header (propertize "w" 'font-lock-face 'font-lock-keyword-face))
Font
Set fonts and sizes for MacOS and Linux.
(pcase system-type ('darwin (set-face-attribute 'default nil :family "Menlo" :height 180) (set-face-attribute 'variable-pitch nil :family "Charter" :height 220) (set-face-attribute 'fixed-pitch nil :family "Menlo" :height 180)) ('gnu/linux (set-face-attribute 'default nil :family "Fira Code" :height 120) (set-face-attribute 'variable-pitch nil :family "Bitstream Charter" :height 140) (set-face-attribute 'fixed-pitch nil :family "Fira Code" :height 120)))
Backup files
Keep all backup files in one place.
(setq backup-directory-alist `(("." . ,(locate-user-emacs-file "backups"))))
Lock files config from the Emacs wiki.
(setq lock-file-name-transforms '(("\\`/.*/\\([^/]+\\)\\'" "/var/tmp/\\1" t)))
Custom file
Move customization variables to a separate file (not in init.el) and load it.
(setq custom-file (locate-user-emacs-file "custom-vars.el")) (load custom-file 'noerror 'nomessage)
Package archives
By default, packages are loaded from GNU Elpa and NonGNU Elpa, but I want to also load some packages that are only published in Melpa. Make sure to use https here.
(with-eval-after-load 'package (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t))
Use package
By using use-package, which is included in Emacs since version 29, package management and configuration is kept together which gives better readabiltiy and maintainablility.
I want to ensure that all packages are automatically installed if not
already present on the current system. Alternatively it can be
specified by adding :require t for each package.
(use-package use-package :ensure nil ;; rely on the built in version :custom (use-package-always-ensure t))
Mac stuff
When launching a GUI application in MacOS it does not by default pick up
environment variables from .profile. Here is a solution.
(use-package exec-path-from-shell :config (when (memq window-system '(mac ns)) (exec-path-from-shell-initialize)))
Color themes
The default color scheme is not my cup of tea, but fortunately it is easy to change. All of the themes I use are created by Protesilaos.
Modus-themes
The Modus themes, Operandi (light) and Vivendi (dark) are sofisticated and very well designed themes, that are built into Emacs (as of version 28).
(use-package emacs :custom (modus-themes-mixed-fonts t "Use monospaced fonts in tables and blocks") :config (require-theme 'modus-themes) (load-theme 'modus-vivendi))
Ef-themes
Ef-themes are a set of more colorful, but still very legible, themes.
It comes with the function ef-themes-load-random for when you have a
hard time making up your mind.
(use-package ef-themes :custom (ef-themes-mixed-fonts t))
Synk theme with desktop
Change the theme when the surrounding environment changes between light and dark mode. On MacOS, emacs-plus provides a hook that triggers when the mode is swithed. On Linux (at least with KDE), we can hook into dbus and listen for a signal.
(pcase system-type ('darwin (defun my/apply-theme (appearance) "Load theme, taking current system APPEARANCE into consideration." (pcase appearance ('light (modus-themes-load-theme 'modus-operandi)) ('dark (modus-themes-load-theme 'modus-vivendi)))) (add-hook 'ns-system-appearance-change-functions #'my/apply-theme)) ('gnu/linux (defun theme--handle-dbus-event (a setting values) "Handler for FreeDesktop theme changes." (when (string= setting "ColorScheme") (let ((scheme (car values))) (cond ((string-match-p "Dark" scheme) (ef-themes-load-random 'dark)) ((string-match-p "Light" scheme) (ef-themes-load-random 'light)) (t (message "I don't know how to handle scheme: %s" scheme)))))) (require 'dbus) (dbus-register-signal :session "org.freedesktop.portal" "/org/freedesktop/portal/desktop" "org.freedesktop.impl.portal.Settings" "SettingChanged" #'theme--handle-dbus-event)))
Vim
Evil-mode is a near-perfect vim-emulator, so if you are considering switching from Vim, you should enable it.
(use-package evil :init (setq evil-want-integration t) (setq evil-want-keybinding nil) :config (evil-mode 1))
A small fix to prevent an issue when loading evil-collection before magit-forge. See evil-collection#563 for more details.
Evil-collection is a collection of vim keybindings for many Emacs modules, that is not covered by default evil-mode.
(setq forge-add-default-bindings nil)
(use-package evil-collection :after evil :diminish evil-collection-unimpaired-mode :config (evil-collection-init))
Which key?
Enable which-key-mode, bundled with Emacs as of version 30, which displays available keybindings in a popup.
(which-key-mode)
When it is installed, I can type a partial command sequence, for exampel C-x, and after one second a list of all keyboard shortcuts
starting with that sequence is presented.
If there are more commands than will fit in the buffer window, is is possible to press C-h n to go to the next page and C-h p to go back again.
Undo tree
Undo-tree allows you to recover any past state of a buffer.
(use-package undo-tree :diminish undo-tree-mode :custom (undo-tree-history-directory-alist `(("." . ,(locate-user-emacs-file ".cache")))) :config (global-undo-tree-mode))
Dired
Dired is a major mode for directory browsing and editing, so plays the role of a file manager.
Default to the directory of another displayed Dired buffer for operations like copy or move (rename) files.
(setq dired-dwim-target t)
Iedit
Iedit helps renaming things in the same file.
Hitting C-; triggers iedit-mode that will select the word you are
currently standing on and all other instances of the same word in the
current buffer. Use TAB and Shift-TAB to navigate to next and previous
occurance. Editing within the selection will affect all instances.
Press C-; again to exit iedit-mode.
(use-package iedit)
All the icons
If running this for the first time, ensure to run M-x
all-the-icons-install-fonts to install the required fonts on the
system.
(use-package all-the-icons :if (display-graphic-p))
Search tools
Isearch
Configure isearch to display a number for the current match and the total number of matches in the minibuffer.
(setq isearch-lazy-count t)
Ripgrep (rg)
Ripgrep is a line-oriented search tool that recursively searches the current directory for a regex pattern.
brew install ripgrep
Alternatives
Completions
Vertico provides a completion UI which is a bit nicer than what Emacs provides by default. It is used to navigate candidates and select one when opening files, running commands, or switching between projects.
(use-package vertico :config (vertico-mode))
Save minibuffer history.
(savehist-mode)
Orderless solves the problem when you can't remember if the command
was named package-install or install-package and matches the segments
you type regardless of the order.
(use-package orderless :custom (completion-styles '(orderless basic)) (completion-category-overrides '((file (styles partial-completion)))))
Marginalia adds more information to completion candidates in the minibuffer.
(use-package marginalia :config (marginalia-mode))
Vertico-posframe shows selection candidates in a modal frame instead of using the minibuffer.
(use-package vertico-posframe :custom (vertico-posframe-mode 1))
Alternatives
Mode line
The mode line is the bottom part of the editor, where things like filename and cursor position is usually displayed. The mood-line is a nice clean configuration.
(use-package mood-line :custom (mood-line-show-encoding-information t) :config (mood-line-mode))
Utilities
Define a function to indent a region if selected, otherwise the whole buffer. Credits to Bozhidar Batsov.
(defun my-indent-buffer () "Indent the currently visited buffer." (interactive) (indent-region (point-min) (point-max))) (defun my-indent-region-or-buffer () "Delete trailing whitespace and indent. Applies to a region if selected, otherwise the whole buffer." (interactive) (save-excursion (if (region-active-p) (progn (delete-trailing-whitespace (region-beginning) (region-end)) (indent-region (region-beginning) (region-end)) (message "Indented selected region.")) (progn (delete-trailing-whitespace) (my-indent-buffer) (message "Indented buffer."))))) (global-set-key (kbd "M-s-l") #'my-indent-region-or-buffer)
Buffers
(use-package ibuffer-project :bind (("C-x C-b" . ibuffer)) :init (add-hook 'ibuffer-hook (lambda () (setq ibuffer-filter-groups (ibuffer-project-generate-filter-groups)) (unless (eq ibuffer-sorting-mode 'project-file-relative) (ibuffer-do-sort-by-project-file-relative)))))
Project
A project in this context is a set of files that belong together. Usually, this means files that are in the same Git repository.
Operations you might want to do on a project includes:
- jump to a file
- search (and possibly replace) within files
- run the code, or run tests
This config makes it easier to open Magit or Vterm in a project.
(with-eval-after-load 'project (defun project-vterm () "Start Vterm in the current project's root directory. If a buffer already exists for running Vterm in the project's root, switch to it. Otherwise, create a new Vterm buffer. With \\[universal-argument] prefix arg, create a new Vterm buffer even if one already exists." (interactive) (defvar vterm-buffer-name) (let* ((default-directory (project-root (project-current t))) (vterm-buffer-name (project-prefixed-buffer-name "vterm")) (vterm-buffer (get-buffer vterm-buffer-name))) (if (and vterm-buffer (not current-prefix-arg)) (pop-to-buffer vterm-buffer (bound-and-true-p display-comint-buffer-action)) (vterm)))) (define-key project-prefix-map "m" #'magit-project-status) (define-key project-prefix-map "t" #'project-vterm) (add-to-list 'project-switch-commands '(magit-project-status "Magit") t) (add-to-list 'project-switch-commands '(project-vterm "Vterm") t) (add-to-list 'project-kill-buffer-conditions '(major-mode . vterm-mode)))
Alternatives
In the past, I have used the excellent Projectile library, but have realized that all features I was using exists in project.el, which is already built into Emacs.
Shell
Kill the buffer when the shell process exits.
(defun my-shell-mode-hook () "Custom `shell-mode' behaviours." ;; Kill the buffer when the shell process exits. (let* ((proc (get-buffer-process (current-buffer))) (sentinel (process-sentinel proc))) (set-process-sentinel proc `(lambda (process signal) ;; Call the original process sentinel first. (funcall #',sentinel process signal) ;; Kill the buffer on an exit signal. (and (memq (process-status process) '(exit signal)) (buffer-live-p (process-buffer process)) (kill-buffer (process-buffer process))))))) (add-hook 'shell-mode-hook 'my-shell-mode-hook)
Enable executing shell code block in org-mode.
(org-babel-do-load-languages 'org-babel-load-languages '((shell . t)))
Vterm
Vterm is a better terminal emulator than eshell or shell.
(use-package vterm :config (setq vterm-copy-exclude-prompt t) (setq vterm-max-scrollback 100000))
Git
Starting to get the hang of using Git through Magit. If you only copy one thing from this file, this is probably it.
(use-package magit :bind ("C-x g" . magit-status) ("C-c h" . magit-log-buffer-file) :custom (magit-diff-refine-hunk 'all) (magit-clone-default-directory "~/Projects/"))
Show todos in the magit status page.
(use-package magit-todos)
The package Forge enables Magit to work better with Github and Gitlab.
(use-package forge :after magit :custom (forge-topic-list-limit '(60 . -5)))
Show git status for each file.
(use-package git-gutter :diminish git-gutter-mode :init (global-git-gutter-mode t))
Org-mode
Make org-mode documents look a bit better:
- Replace the
...that is shown by default when there is hidden content. Use the org-bullets package to make headers look cleaner.
(use-package org :ensure nil ;; I rely on the built in version of org-mode :hook (org-mode . auto-fill-mode) (org-mode . variable-pitch-mode) (org-mode . (lambda () (display-line-numbers-mode 0))) :bind (("C-c a" . org-agenda) ("C-c c" . org-capture)) :custom (org-hide-emphasis-markers t) (org-pretty-entities t) (org-ellipsis "↴") (org-fontify-whole-block-delimiter-line nil) (org-fontify-quote-and-verse-blocks t) (org-blank-before-new-entry '((heading . always) (plain-list-item . nil))) (org-export-with-section-numbers nil) (org-export-with-toc nil) (org-use-sub-superscripts :{}) (org-export-with-sub-superscripts nil)) (use-package org-modern :custom (org-modern-star 'replace) :init (global-org-modern-mode))
Tasks (a.k.a. Todos)
Log the date and time when a task is completed.
(setq org-log-done t)
Define my set of todo-states, and replace the keywords with symbols.
(setq org-todo-keywords '((sequence "TODO(t)" "DOING(i)" "WAITING(w)" "|" "DONE(d)" "CANCELED(c)")))
Display a small arrow next to the currently clocked in task. (Code by romto)
(defun org-clock-flag-active-task () "Identify the clocked-in task with a fringe arrow on its header line." (save-excursion (org-clock-goto) (make-variable-buffer-local 'overlay-arrow-position) (setq overlay-arrow-position (make-marker)) (set-marker overlay-arrow-position (point)))) (defun org-clock-unflag-active-task () "Remove the fringe arrow from the most recent clocked task." (with-current-buffer (marker-buffer (car org-clock-history)) (setq overlay-arrow-position nil))) (add-hook 'org-clock-in-hook 'org-clock-flag-active-task) (add-hook 'org-clock-out-hook 'org-clock-unflag-active-task)
Capture
(setq org-default-notes-file "~/Documents/org-roam/Inbox.org") (setq org-capture-templates '(("i" "Inbox" entry (file "" "~/Documents/org-roam/Inbox.org") "* TODO %?\n %u\n %a") ("t" "Task (scheduled)" entry (file "~/Documents/org-roam/Inbox.org") "* TODO %?\nSCHEDULED: %^{Scheduled}t\n %u\n %a") ("c" "Chore" entry (file "~/Documents/org-roam/Chores.org") "* TODO %?\n %u\n %a")))
Agenda
Populate the agenda using all org-roam files tagged with project. Code
stolen from David Wilsons Build your Org agenda from Org Roam notes.
(with-eval-after-load 'org-roam (defun my/org-roam-filter-by-tag (tag-name) (lambda (node) (member tag-name (org-roam-node-tags node)))) (defun my/org-roam-list-notes-by-tag (tag-name) (mapcar #'org-roam-node-file (seq-filter (my/org-roam-filter-by-tag tag-name) (org-roam-node-list)))) (defun my/org-roam-refresh-agenda-list () (interactive) (setq org-agenda-files (my/org-roam-list-notes-by-tag "project"))) ;; Build the agenda list the first time for the session (my/org-roam-refresh-agenda-list))
When using agenda to view todo items, I want to hide items which are scheduled or have a deadline, since they will show up on the calendar. I also want to set the deadline warning to 4 days (the default is 14).
(setopt org-agenda-todo-ignore-scheduled 'all) (setopt org-deadline-warning-days 4) (setopt org-agenda-window-setup 'current-window)
Refile
(setq org-refile-targets '(("~/Documents/org/archived.org" :maxlevel . 1) ("~/Documents/org/projects.org" :maxlevel . 1))) (advice-add 'org-refile :after 'org-save-all-org-buffers)
Paste images from copy buffer into org documents
For this to work on MacOS you first need to install the pngpaste utility.
brew install pngpaste
Then configure org-download to put pasted images in a directory
named images in the same directory as the org file.
(use-package org-download :after org :defer nil :custom (org-download-method 'directory) (org-download-image-dir "images") (org-download-heading-lvl nil) (org-download-timestamp "%Y%m%d-%H%M%S_") (org-image-actual-width 300) (org-download-screenshot-method "/opt/homebrew/bin/pngpaste %s") :bind ("C-s-p" . org-download-screenshot) :config (require 'org-download))
Link to Magit buffers (like git commits) in org documents
The author of Magit also made the package orgit that provides a convenient way to create links to Magit buffers.
(use-package orgit)
Journal
I have found that org-journal works well for daily journaling.
(use-package org-journal :config (setq org-journal-date-format "%Y-%m-%d, %a"))
Org-roam
Org-roam is a knowledge management system built on top of org-mode. See explanation for the config in System Crafters videos.
(use-package org-roam :init (make-directory "~/Documents/org-roam/daily" t) :custom (org-roam-directory "~/Documents/org-roam") (org-roam-completion-everywhere t) :bind (("C-c n l" . org-roam-buffer-toggle) ("C-c n f" . org-roam-node-find) ("C-c n i" . org-roam-node-insert) :map org-mode-map ("C-M-i" . completion-at-point) :map org-roam-dailies-map ("Y" . org-roam-dailies-capture-yesterday) ("T" . org-roam-dailies-capture-tomorrow)) :bind-keymap ("C-c n d" . org-roam-dailies-map) :config (require 'org-roam-dailies) (org-roam-db-autosync-enable))
Snippets
YASnippet is a template system for Emacs. It allows you to type an abbreviation and automatically expand it into function templates.
(use-package yasnippet :config (yas-global-mode 1))
Install the official collection of snippets for yasnippet.
(use-package yasnippet-snippets :after yasnippet)
Languages
Corfu provides in-buffer completion.
(use-package corfu :custom (corfu-auto t) (corfu-auto-delay 2.0) (corfu-popupinfo-delay '(2.0 0.4)) :init (global-corfu-mode) (corfu-popupinfo-mode))
Flycheck provides on-the-fly syntax checking.
Most of my emacs lisp are Emacs configuration snippets, and not
complete elisp packages. By disabling emacs-lisp-checkdoc, Flycheck
will not complain about missing comments. Running M-x checkdoc will
still perform that check, and also assist with creating documentation
that is up to standards.
(use-package flycheck :diminish flycheck-mode :config (setq-default flycheck-disabled-checkers '(emacs-lisp-checkdoc)) (add-hook 'after-init-hook #'global-flycheck-mode))
HTML
Emmet-mode is useful whenever you quickly need to type some HTML. Autostart it on any markup modes
(use-package emmet-mode :config (add-hook 'sgml-mode-hook 'emmet-mode))
Java
Make sure to install a Java Language Server.
brew install jdtls
Javascript
(setq js-indent-level 2)
(use-package js2-mode :mode "\\.[c|m]js[x]?\\'")
Typescript
(use-package typescript-mode :mode "\\.\\(ts\\|tsx\\)\\'" :config (setq typescript-indent-level 2))
Vue.js
New config:
(require 'eglot) (define-derived-mode pbgc-vue-mode web-mode "pbVue" "A major mode derived from web-mode, for editing .vue files with LSP support.") (add-to-list 'auto-mode-alist '("\\.vue\\'" . pbgc-vue-mode)) (defun pbgc-vue-custom () (flycheck-mode t) (eglot-ensure)) (add-hook 'pbgc-vue-mode-hook 'pbgc-vue-custom) (defun vue-eglot-init-options () (let ((tsdk-path (expand-file-name "lib" (string-trim-right (shell-command-to-string "npm list --global --parseable typescript | head -n1")) ))) `(:typescript (:tsdk ,tsdk-path :languageFeatures (:completion (:defaultTagNameCase "both" :defaultAttrNameCase "kebabCase" :getDocumentNameCasesRequest nil :getDocumentSelectionRequest nil) :diagnostics (:getDocumentVersionRequest nil)) :documentFeatures (:documentFormatting (:defaultPrintWidth 100 :getDocumentPrintWidthRequest nil) :documentSymbol t :documentColor t))))) ;; Volar (add-to-list 'eglot-server-programs `(pbgc-vue-mode . ("vls" "--stdio" :initializationOptions ,(vue-eglot-init-options))))
Install prettier. It can be activated to run on save everywhere by
running M-x global-prettier-mode.
(use-package prettier)
Flycheck
Ensure that flycheck reports on eslint warnings, using config borrowed from http://codewinds.com/blog/2015-04-02-emacs-flycheck-eslint-jsx.html
(flycheck-add-mode 'javascript-eslint 'pbgc-vue-mode) (defun my/use-eslint-from-node-modules () (let* ((root (locate-dominating-file (or (buffer-file-name) default-directory) "node_modules")) (eslint (and root (expand-file-name "node_modules/eslint/bin/eslint.js" root)))) (when (and eslint (file-executable-p eslint)) (setq-local flycheck-javascript-eslint-executable eslint)))) (add-hook 'flycheck-mode-hook #'my/use-eslint-from-node-modules)
Restclient
Mode to use Emacs as a REST client.
(use-package restclient :mode ("\\.rest\\'" . restclient-mode))
Use restclient in org-mode source blocks.
(use-package ob-restclient :config (org-babel-do-load-languages 'org-babel-load-languages '((restclient . t))))
SQL
Use SQL in org-mode source blocks.
(org-babel-do-load-languages 'org-babel-load-languages '((sql . t)))
PlantUML
(use-package plantuml-mode :config (setq org-plantuml-jar-path "/usr/local/opt/plantuml/libexec/plantuml.jar") (org-babel-do-load-languages 'org-babel-load-languages '((plantuml . t))))
Mermaid
https://emacstil.com/til/2021/09/19/org-mermaid/
(use-package ob-mermaid :config (setq ob-mermaid-cli-path "/usr/local/bin/mmdc"))
Redisplay inline images after generation
(add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images)
CSV
This helps when working with files containing comma-separated values.
(use-package csv-mode)
Yaml
(use-package yaml-mode :mode "\\.yml\\'")
Simple HTTP server
This package provides a simple way of serving up files from a local directory, by invoking `M-x httpd-serve-directory`.
(use-package simple-httpd)
Klondike
A relaxing solitary card game.
(use-package klondike :hook ((klondike-mode . turn-off-evil-mode) (klondike-picker-mode . turn-off-evil-mode) (klondike-select-mode . turn-off-evil-mode)))
Utility functions
(defun my/func-region (start end func) "run a function over the region between START and END in current buffer." (save-excursion (let ((text (delete-and-extract-region start end))) (insert (funcall func text)))))
Interactive functions to encode and decode url strings.
(defun url-encode-region (start end) "urlencode the region between START and END in current buffer." (my/func-region start end #'url-hexify-string)) (defun url-decode-region (start end) "de-urlencode the region between START and END in current buffer." (my/func-region start end #'url-unhex-string))