Table of Contents
My Emacs settings
A fresh Emacs installation loads with custom programs that can be accessed
with Elisp forms. Forms may implement complete programs of almost any type.
To illustrate, Emacs has built into it a Tetris implementation, which can be
played by typing in the keyboard the Meta command then followed by the
program's name (M-x tetris
).
Org Mode is a productivity program implemented in Elisp and available in Emacs.
Org Mode's markup allows organizing any file into heading sections as long as the
file name extension ends with .org
. Org mode can interpret and convert these
markup symbols to HTML – like other popular static site generators that, instead,
understand and convert from Markdown.
The content inside this file can be accessed through the internet on my personal site, generated by using Org Mode's publishing system and deployed with GitHub.
Try pulling the main file in the blog repo then navigate to it in Emacs.
Type M-x org-babel-tangle
to override the main configuration file with these
settings. Save time by using the keychord shortcut C-c C-v C-t
instead.
Emacs documents all of its variables. When in doubt, call
M-x describe-variable
or M-x describe-function
.
Keychords may also be used: C-h v [variable symbol]
,
C-h f [function symbol]
respectively.
Setup
Package manager
Get extra functionality by pointing to MELPA package directory.
(require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
Default Emacs UI
(menu-bar-mode -1) ; Disable for more headspace (tool-bar-mode -1) ; Remove toolbar (scroll-bar-mode -1) ; Remove scroll bar (save-place-mode 1) ; Remember cursor position (load-theme 'modus-vivendi nil)
General
(setq-default inhibit-startup-message t ; Don't show default emacs startup screen window-combination-resize t ; Resize windows proportionally display-time-default-load-average nil ; Don't show system load time in modeline indent-tabs-mode nil ; Stop using tabs to indent tab-width 4 ; Change default tab width ;; My machine has enough memory to increase the default values gc-cons-threshold 50000000 large-file-warning-threshold 100000000 ;; Increase default max recursion depth (when coding in Elisp) max-specpdl-size 19500 max-lisp-eval-depth 24000 bidi-paragraph-direction 'left-to-right ; Just work with left to right langs bidi-inhibit-bpa t ;; Directories delete-by-moving-to-trash t auto-revert-check-vc-info t use-short-answers t) ;; Toggle features not available in a fresh Emacs install (put 'downcase-region 'disabled nil) ; Allow use of C-x C-l (downcase region) (put 'upcase-region 'disabled nil) ; Allow use of C-x C-u (capitalize region) (put 'narrow-to-region 'disabled nil) ; Allows to narrow region ;; Useful Register setup when appending/prepending (setq register-separator ?+) (set-register register-separator "\n\n") ;; (set-register ?z '(file . "")) ;; Useful functionality (add-hook 'before-save-hook 'delete-trailing-whitespace) (add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p) (global-set-key (kbd "C-x k") 'kill-this-buffer) (global-so-long-mode 1) ;; Change Emacs backup files location (setq backup-directory-alist '(("." . "~/.config/emacs"))) ;; This change prevents the crashing of the React server after any file change (setq create-lockfiles nil) ;; inherit PATH from shell, depends on `exec-path-from-shell' package (exec-path-from-shell-initialize) (setq project-vc-extra-root-markers '("tsconfig.json" "build.clj")) (setq project-vc-ignores '("node_modules"))
Custom prefix keys
Some functions get called often but are not binded to a keychord by default. Custom prefix keys allows defining a key and bind it to a function.
;; Keys may be binded globally like below (global-set-key (kbd "<C-M-return>") 'delete-other-windows) ;; Define C-z key map (define-prefix-command 'my-super-z-map) ;; Bind C-z to custom prefix command (global-set-key (kbd "C-z") 'my-super-z-map) ;; Set of mapped keys in `C-z' (define-key my-super-z-map (kbd "o") 'browse-url-at-point) (define-key my-super-z-map (kbd "a") 'add-file-local-variable-prop-line)
Org
(with-eval-after-load 'org (visual-line-mode 1) ; wrap lines (setq org-src-fontify-natively t ; highlight syntax in code source blocks org-catch-invisible-edits t)) ;; Org Babel Setup (org-babel-do-load-languages 'org-babel-load-languages '((shell . t) (latex . t) (python . t) (ditaa . t)))
Extras
Nice to have packages and functionality. Most of these improve coding experience.
- Electricity
;; Electric Layout Mode (add-hook 'css-mode 'electric-layout-mode) ; insert newline after the insertion of '{' (electric-indent-mode +1) ; toggle on the fly re-indentation ;; Electric Pairs (add-hook 'mhtml-mode-hook 'electric-pair-local-mode) (add-hook 'emacs-lisp-mode-hook 'electric-pair-local-mode) (add-hook 'clojure-mode-hook 'electric-pair-local-mode) (add-hook 'lisp-interaction-mode-hook 'electric-pair-local-mode) (add-hook 'web-mode-hook 'electric-pair-local-mode) (add-hook 'ielm-mode-hook 'electric-pair-local-mode) (add-hook 'js-mode-hook 'electric-pair-local-mode) (add-hook 'typescript-mode-hook 'electric-pair-local-mode) (add-hook 'org-mode-hook 'electric-pair-local-mode) (add-hook 'scheme-mode-hook 'electric-pair-local-mode) (add-hook 'python-mode-hook 'electric-pair-local-mode) (add-hook 'css-mode-hook 'electric-pair-local-mode) ;; Add extra pairs for js-mode (defvar js-mode-electric-pairs '((?` . ?`)) "Electric pairs for js-mode.") (defun js-mode-add-electric-pairs () (setq-local electric-pair-pairs (append electric-pair-pairs js-mode-electric-pairs)) (setq-local electric-pair-text-pairs electric-pair-pairs)) (add-hook 'js-mode-hook 'js-mode-add-electric-pairs) (add-hook 'mhtml-mode-hook 'js-mode-add-electric-pairs) ; needs it for `script` tags ;; Subword Mode (add-hook 'js-mode-hook #'subword-mode) (add-hook 'js-jsx-mode-hook #'subword-mode) (add-hook 'typescript-mode-hook #'subword-mode) (add-hook 'python-mode-hook #'subword-mode) (add-hook 'c-mode-hook #'subword-mode) (add-hook 'clojure-mode-hook #'subword-mode) ;; Enable Dash font-locking (eval-after-load 'dash '(dash-enable-font-lock))
- Prettify Symbols
(global-prettify-symbols-mode t) (defun my-add-pretty-lambda () "Make some word or string show as pretty Unicode symbols" (push '("lambda" . 955) prettify-symbols-alist) ; λ (push '("->" . 8594) prettify-symbols-alist) ; → (push '("=>" . 8658) prettify-symbols-alist) ; ⇒ (push '("map" . 8614) prettify-symbols-alist) ; ↦ ) (add-hook 'tex-mode-hook 'my-add-pretty-lambda) (add-hook 'emacs-lisp-mode-hook (lambda () "Beautify Emacs Symbols" (push '("<=" . "≤") prettify-symbols-alist))) (add-hook 'scheme-mode-hook (lambda () "Beautify Emacs Symbols" (push '("<=" . "≤") prettify-symbols-alist))) (add-hook 'clojure-mode-hook (lambda () "Beautify Clojure Symbols" (push '("map" . 8614) prettify-symbols-alist) (push '("->" . 8594) prettify-symbols-alist)))
Packages
Dired
(setq dired-recursive-copies 'always ; “always” means no asking dired-recursive-deletes 'top ; “top” means ask once dired-dwim-target t) (add-hook 'dired-mode-hook '(lambda () (dired-hide-details-mode 1))) (put 'dired-find-alternate-file 'disabled nil)
Vertico / Orderless / CtrlF / Marginalia / Consult
Better buffer search and improved minibuffer experience
(vertico-mode) (marginalia-mode) (setq completion-styles '(orderless basic) completion-category-overrides '((file (styles basic partial-completion)))) (advice-add #'vertico--setup :after (lambda (&rest _) (setq-local completion-auto-help nil completion-show-inline-help nil))) ;; Consult (global-set-key (kbd "C-x b") 'consult-buffer) (global-set-key (kbd "C-x 4 b") 'consult-buffer-other-window) (global-set-key (kbd "M-s G") 'consult-git-grep) (global-set-key (kbd "M-g g") 'consult-goto-line) (global-set-key (kbd "M-g M-g") 'consult-goto-line) (global-set-key (kbd "M-g f") 'consult-flymake) (global-set-key (kbd "C-x p b") 'consult-project-buffer) (global-set-key (kbd "M-s l") 'consult-line) ;; Use Consult to select xref locations with preview (setq xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref) ;; Enable vertico-multiform (vertico-multiform-mode) ;; Configure the display per completion category. ;; Use the grid display for files and a buffer ;; for the consult-grep commands. (setq vertico-multiform-categories '( ;;(file grid) (consult-grep buffer)))
Corfu & Cape
Auto-completion in Emacs.
;; TAB cycle if there are only few candidates (setq completion-cycle-threshold 3) (setq tab-always-indent 'complete) (setq corfu-auto t) (global-corfu-mode) ;; Cape ;; Add `completion-at-point-functions', used by `completion-at-point'. (add-to-list 'completion-at-point-functions #'cape-file) (add-to-list 'completion-at-point-functions #'cape-dabbrev) (add-to-list 'completion-at-point-functions #'cape-keyword) (add-to-list 'completion-at-point-functions #'cape-sgml) (add-to-list 'completion-at-point-functions #'cape-symbol)
Web Development
(setq css-indent-offset 2) (add-hook 'js-mode-hook (lambda () (define-key js-mode-map (kbd "M-.") 'xref-find-definitions))) ;; Configure Eglot Eslint/Flymake with JSX and TSX ;; wraps `flymake-eslint-enable' to run only root dirs with `.eslintrc' file (defun me/flymake-eslint-enable-maybe () "Enable `flymake-eslint' based on the project configuration. Search for the project ESLint configuration to determine whether the buffer should be checked." (when-let* ((root (locate-dominating-file (buffer-file-name) "package.json")) (rc (locate-file ".eslintrc" (list root) '(".js" ".json")))) (make-local-variable 'exec-path) (push (file-name-concat root "node_modules" ".bin") exec-path) (flymake-eslint-enable))) (add-hook 'eglot-managed-mode-hook (lambda () (me/flymake-eslint-enable-maybe))) (add-hook 'typescript-mode-hook (lambda () (setq-local eglot-stay-out-of '(flymake)) (eglot-ensure))) (add-hook 'js-mode-hook (lambda () (setq-local eglot-stay-out-of '(flymake)) (eglot-ensure))) (add-hook 'js-jsx-mode-hook (lambda () (setq-local eglot-stay-out-of '(flymake)) (eglot-ensure)))
Rainbow Delimiters
(custom-set-faces '(rainbow-delimiters-depth-1-face ((t (:foreground "blue violet")))) '(rainbow-delimiters-depth-2-face ((t (:foreground "red")))) '(rainbow-delimiters-depth-3-face ((t (:foreground "cyan3")))) '(rainbow-delimiters-depth-4-face ((t (:foreground "blue")))) '(rainbow-delimiters-depth-5-face ((t (:foreground "gold")))) '(rainbow-delimiters-depth-6-face ((t (:foreground "lavender")))) '(rainbow-delimiters-depth-7-face ((t (:foreground "ivory")))) '(rainbow-delimiters-depth-8-face ((t (:foreground "magenta")))) '(rainbow-delimiters-depth-9-face ((t (:foreground "red"))))) (add-hook 'clojure-mode-hook #'rainbow-delimiters-mode) (add-hook 'emacs-lisp-mode-hook #'rainbow-delimiters-mode) (add-hook 'ielm-mode-hook #'rainbow-delimiters-mode) (add-hook 'lisp-interaction-mode-hook #'rainbow-delimiters-mode) (add-hook 'lisp-mode-hook #'rainbow-delimiters-mode)
Clojure
(setq cider-clojure-cli-aliases "-M:dev" cider-eval-result-prefix "=>" cider-repl-display-help-banner nil) (remove-hook 'flymake-diagnostic-functions #'flymake-proc-legacy-flymake) (add-hook 'clojure-mode-hook #'flymake-kondor-setup) (add-hook 'clojure-mode-hook (lambda () (add-hook 'after-save-hook #'eglot-format-buffer nil 'make-it-local))) (add-hook 'clojure-mode-hook 'eglot-ensure)
Dev tools
;; Tree-sitter ;; activate tree-sitter on any buffer containing code for which it has a parser available (global-tree-sitter-mode) ;; you can easily see the difference tree-sitter-hl-mode makes for python, ts or tsx ;; by switching on and off (add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode) ;; we choose this instead of tsx-mode so that eglot can automatically figure out language for server ;; see https://github.com/joaotavora/eglot/issues/624 and https://github.com/joaotavora/eglot#handling-quirky-servers (define-derived-mode typescriptreact-mode typescript-mode "TypeScript TSX") ;; use our derived mode for tsx files (add-to-list 'auto-mode-alist '("\\.tsx?\\'" . typescriptreact-mode)) ;; by default, typescript-mode is mapped to the treesitter typescript parser ;; use our derived mode to map both .tsx AND .ts -> typescriptreact-mode -> treesitter tsx (add-to-list 'tree-sitter-major-mode-language-alist '(typescriptreact-mode . tsx))