My Emacs Configuration
1. My personal configuration
1.1. Design
I belive that one should explore what one has before finding something new. And so, why would one install packages for Emacs?
I've used it as my main editor for a while now, and have yet to find something I miss built-in to the editor and tool.
Let us take an example, magit and vc-mode. Magit is a popular git frontend for emacs, which many see as one of the best features of the tool. But why?
I have talked to multiple people that have never even looked at the built-in alternative, vc-mode.
In vc-mode I can easily stage files with one keybind, push, pull, stash, use git tags, don partial commits and more with a simple UI. Once someone said they wished for a way to browse the git log, but vc-mode has just this, and from here you can see, edit and browse the log and open the diffs from each commit.
This is just one of many examples of tooling in Emacs that many simply have never tried or even know of.
This is the base idea for my configuration. Use what I have and check what I have before I go looking for an external tool or package to solve a problem I may alreddy have a tool for avalable.
At the moment I have 0 external packages for my Emacs configuration, and if you use emacs version 30.1 or above you will have all that I use, where which-key is tyhe notable new feature.
If you want everything you may check my configuration over at *Codeberg*.
I have structured my configuration so that first i set the options, then i set values then last comes functions and keybinds. Like this:
(option 0/nil) (setq option value) (defun func (function)) (mode-set-key (kbd "keybind") 'function)
2. my configuration
First i require some shipped packages so that i am 100% sure they are loaded first thing, before the configurations are set (mostly for diary).
;;; minimal configuration (require 'diary-lib) (require 'rmail) (require 'erc)
After that I set all the options that are toggles, like fido-vertical-mode and electric-pair-mode.
;;; basic opetions (electric-pair-mode 1) (fido-vertical-mode 1) (repeat-mode 1) (which-key-mode 1) (save-place-mode 1) (global-hl-line-mode 1) (savehist-mode 1) (recentf-mode 1) (global-auto-revert-mode 1) (global-display-line-numbers-mode 1) (column-number-mode 1) (display-time-mode 1) (global-completion-preview-mode 1) ;;(etags-regen-mode 1)
Here I just disable the visual clutter that is UI buttons.
;;; clean the UI (tool-bar-mode 0) (menu-bar-mode 0) (scroll-bar-mode 0)
Then I set hooks, commands that are autoran on a condition, like for example startup or a specific mode.
;; autohooks (add-hook 'before-save-hook 'delete-trailing-whitespace ) (add-hook 'prog-mode-hook #'prettify-symbols-mode ) (add-hook 'org-mode-hook #'prettify-symbols-mode ) (add-hook 'scheme-mode-hook #'imenu-add-menubar-index ) (add-hook 'diary-fancy-display-hook 'diary-fancy-display ) (add-hook 'calendar-mode-hook 'shrink-window-if-larger-than-buffer ) ;;; binds: d - diary selected date, s: diary file, i d; insert diary,
Here i set it to pulse, so visually highlight the line for a moment on the specified commands.
;;; advice add (advice-add 'find-file :after #'my/pulse-line) (advice-add 'switch-to-buffer :after #'my/pulse-line) (advice-add 'my/move-line-down :after #'my/pulse-line) (advice-add 'my/move-line-up :after #'my/pulse-line)
After that I start to set all the setq options. Here I make a better startupscreen and set how much emacs should remember back in time with actions like file naviagtion.
;;; remember what i did (setq recentf-max-saved-items 100 history-length 100 kept-new-versions 10 inhibit-splash-screen t initial-scratch-message "" inhibit-startup-screen t
Then i set the diary file and for it to auto follow symlinks to vc managed directories for my startup screen.
;;; diary vc-follow-symlinks t diary-file "~/diary" calendar-date-style 'iso
And now I set where backupfiles are saved.
;;; set backups to .emacs.d and disable the bell ring-bell-function 'ignore display-line-numbers-type 'relative backup-directory-alist `(("." . ,user-emacs-directory)) auto-save-file-name-transforms `((".*" ,user-emacs-directory t)) auto-save-list-file-prefix user-emacs-directory
This is a simple `ERC` setup.
;;; irc epa-pinentry-mode 'loopback auth-sources '("~/.authinfo.gpg") erc-nick "Trondelag-Alice" erc-user-full-name "Trondelag" erc-autojoin-channels-alist '(("libera.chat" "#technicalrenaissance")) erc-use-auth-source-for-nickserv-password t erc-hide-list '("JOIN" "PART" "QUIT" "NICK" "MODE") erc-prompt-for-password nil
Options for xref and how it behaves, for M-./M-g i.
xref-show-definitions-function #'xref-show-definitions-completing-read xref-show-xrefs-function #'xref-show-definitions-completing-read xref-auto-jump-to-first-definition 'unique
Simple rmail/email setup.
;;; email user-full-name "Alice" user-mail-address "trondelagcutie@yahoo.com" send-mail-function 'smtpmail-send-it smtpmail-smtp-server "smtp.mail.yahoo.com" smtpmail-smtp-service 465 smtpmail-stream-type 'ssl rmail-movemail-program "/usr/local/bin/movemail" rmail-primary-inbox-list '("imaps://trondelagcutie%40yahoo.com@imap.mail.yahoo.com:993")
How emacs make backupfiles.
;;; how to backup backup-by-copying t delete-old-versions t version-control t create-lockfiles nil ;;; CLOCK IN MODELINE FORMAT display-time-24hr-format t display-time-default-load-average nil
Y-N insted of yes-no.
;;; small options use-short-answers t tags-revert-without-query t
My completion style and how it shows up.
;;; completions completion-styles '(basic partial-completion flex file-name) completions-format 'vertical completions-format 'one-column completions-max-height 8 icomplete-scroll t tab-always-indent 'complete savehist-additional-variables '(kill-ring search-ring regexp-search-ring) completion-preview-minimum-symbol-length 2 completion-preview-delay 0.02 display-buffer-alist '(("\\*Completions\\*" (display-buffer-at-bottom) (window-height . 10))) completion-auto-select t completions-detailed t completions-max-height 10 icomplete-prospects-height 10 completions-group-format (propertize " %s " 'face '(:inherit shadow :slant italic)) completions-group t read-file-name-completion-ignore-case t read-buffer-completion-ignore-case t
Enable symbol replacement for things like lambda to be shown as the lambda symbol.
;;; prettify the symbols prettify-symbols-unprettify-at-point t)
Set options to have smooth scrolling, show trailing whitespace.
;;; smoother scrolling (setq-default scroll-conservatively 101 scroll-margin 10 indent-tabs-mode nil buffer-file-coding-system 'utf-8-auto-unix show-trailing-whitespace t imenu-auto-rescan t
Set what to show in the modeline.
;;; modeline header-line-format '("[ "display-time-string"] " "["vc-mode" ] " "[ %f ]") mode-line-format '("%e" "[%b] " "[%l:%c] " "["mode-name"] " " [%*] ")
Sets which symbols should be affected by prettify.
prettify-symbols-alist '(("==" . "≡") ("===" . "≣") ("!=" . "≠") ("!==" . "≢") (">=" . "≥") ("<=" . "≤") ("->" . "→") ("<-" . "←") ("<->" . "↔") ("<=>" . "⇔") ("->>" . "↠") ("<<-" . "↞") ("~>" . "↝") ("|>" . "▷") ("<|" . "◁") ("map" . "↦") ("lambda" . "λ") ("alpha" . "α") ("beta" . "β") ("gamma" . "γ") ("delta" . "δ") ("pi" . "π") ("sum" . "∑") ("..." . "…") ("::" . "∷") (">>" . "»") ("<<" . "«") ("sqrt" . "√") ("integral" . "∫") ("forall" . "∀") ("exists" . "∃")))
Enable recursive minibuffers for completion in minibuffers and a keymap for it.
;;; setopts (setopt enable-recursive-minibuffers t) ;;; eval after load (with-eval-after-load 'completion-preview (define-key completion-preview-active-mode-map (kbd "M-n") #'completion-preview-next-candidate) (define-key completion-preview-active-mode-map (kbd "M-p") #'completion-preview-prev-candidate))
Function that highlights line for a moment.
;;; smal defun (defun my/pulse-line (&rest _) (pulse-momentary-highlight-one-line (point)))
Function that moves selected line one line up.
;;; general functions (defun my/move-line-up () (interactive) (transpose-lines 1) (forward-line -2))
Function that moves line one line down.
(defun my/move-line-down () (interactive) (forward-line 1) (transpose-lines 1) (forward-line -1))
A function that lets me have something like vims visual block mode for editing.
(defun my/visual-block-mode () "something like vims visual block to a keybind, so i can edit multiple lines at once for the same thing" (interactive) (unless cua-mode (cua-mode 1)) (cua-rectangle-mark-mode 1))
Finds directories down and gives it to find-file wich has fuzzy search, so a fuzzy file finder, like ivy or fzf.
(defun my/find () "fuzzy from current directory" (interactive) (let* ((files (directory-files-recursively default-directory "")) (chosen (completing-read "Find file: " files))) (when chosen (find-file chosen))))
This remakes the `TAGS` file.
(defun my/recompile-etags () "a command to generate etags 'TAGS' file for the current projects" (interactive) (let ((default-directory (vc-root-dir))) (call-process-shell-command "find . -type f \\( -name '*.el' -o -name '*.[ch]' -o -name '*.scm' \\) -print0 | xargs -0 etags -o TAGS")))
A function that pushes current git repo withouth an ssh agent active.
(defun my/push () "git push so it works on my machine and setup" (interactive) (let ((display-buffer-alist '(("\\*Async Shell Command\\*" display-buffer-no-window)))) (shell-command "git push &")) (message "Pushing..."))
Here I simple set some keybinds to my functions and some built-ins that I use a lot.
;;; keybinds (global-set-key (kbd "C-|" ) 'my/visual-block-mode) (global-set-key (kbd "C-c c s ") 'eshell ) (global-set-key (kbd "C-c c g ") 'grep-find ) (global-set-key (kbd "C-c c f ") 'my/find ) (global-set-key (kbd "C-c c b ") 'ibuffer ) (global-set-key (kbd "C-c c r ") 'recentf ) (global-set-key (kbd "C-c C ") 'compile ) (global-set-key (kbd "C-c p ") 'my/move-line-up ) (global-set-key (kbd "C-c n ") 'my/move-line-down ) (global-set-key (kbd "C-c d ") 'duplicate-line ) (global-set-key (kbd "C-c c n ") 'narrow-to-region ) (global-set-key (kbd "C-c c w ") 'widen ) (global-set-key (kbd "C-c c P ") 'my/push )
Sets move line functions to be repeatable.
(windmove-default-keybindings 'shift) ;;; repetemodeable (defvar-keymap move-line-repeat-map "p" #'my/move-line-up "n" #'my/move-line-down) (put #'my/move-line-down 'repeat-map 'move-line-repeat-map) (put #'my/move-line-up 'repeat-map 'move-line-repeat-map)
Makes the base startup-screen the diary for the next week.
(defun my/start () (diary 7) (delete-window)) (add-hook 'emacs-startup-hook 'my/start)