alexforsale's literate Emacs configuration 2.0
Table of Contents
- The new configuration
- early-init.el
- init.el
- Modules
- Evil external
- configuration
- evil-collection external
- evil-terminal-cursor-changer external
- evil-surround external
- evil-embrace external
- evil-escape external
- evil-exchange external
- evil-nerd-commenter external
- evil-traces external
- evil-visualstar external
- evil-vimish-fold external
- evil-multiedit external
- evil-org-mode external
- evil-goggles external
- avy external
- Keybindings
- Builtins
- UI
- Shells and Terminals
- Editing
- IDE stuffs
- Org-mode
- variables
- org-mode core package builtin
- org-contrib external
- org-entities builtin
- org-faces builtin
- org-archive builtin
- org-capture builtin
- org-refile builtin
- org-fold builtin
- org-id builtin
- org-num builtin
- org-crypt builtin
- org-attach builtin
- org-agenda builtin
- org-clock builtin
- org-timer builtin
- org-eldoc builtin
- org-superstar external
- org-fancy-priorities external
- org-modern external
- org-download external
- org-roam external
- org-roam-ui external
- org-protocol-capture-html external
- pdf-tools external
- Tools
- Programming languages
- Completion
- Dired
- Evil external
- minimal Emacs
The new configuration
My old configuration got bloated after accumulating external packages, and sometimes it's just a test package that I forgot to remove, or some packages I've added that I don't really use.
So this time I want to really focus on the builtins, and only the builtins that I really use.
early-init.el
GC Threshold
A common way of speeding up Emacs startup. The variable gc-cons-threshold is the number of bytes consing between garbage collection.
Garbage collection can happen automatically once this many bytes have been allocated since the last garbage collection.
Here I set this to a variable most-positive-fixnum which value is set automatically.
most-positive-fixnum
2305843009213693951
(setopt gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.6)
The gc-cons-percentage default to 0.1, is the portion of the heap used for allocation.
I set the value differently when Emacs is starting up, by setting this variable into emacs-startup-hook that runs after Emacs loaded the init files.
(add-hook 'emacs-startup-hook
(lambda ()
(setopt gc-cons-threshold (* 16 1024 1024) ; 16mb
gc-cons-percentage 0.1)))
Language
Set UTF-8 as the default coding system
(set-language-environment "UTF-8")
Set initial frame
Here I disable the menu-bar, tool-bar and vertical scroll bar.
(add-to-list 'default-frame-alist '(menu-bar-lines . 0)) (add-to-list 'initial-frame-alist '(menu-bar-lines . 0)) (add-to-list 'initial-frame-alist '(tool-bar-lines . 0)) (add-to-list 'default-frame-alist '(tool-bar-lines . 0)) (add-to-list 'initial-frame-alist '(vertical-scroll-bars)) (add-to-list 'default-frame-alist '(vertical-scroll-bars)) (add-to-list 'initial-frame-alist '(fullscreen . maximized)) (add-to-list 'default-frame-alist '(fullscreen . maximized))
Define the location of custom-file
The custom-file is used to save customization settings for future use.
(customize-set-variable 'custom-file (expand-file-name "custom.el" user-emacs-directory)) (when (file-exists-p custom-file) (load custom-file))
Setup package
Now much more simpler since use-package is built into Emacs. It's actually not used since I'm using straight.el.
(with-eval-after-load 'package (setopt package-enable-at-startup nil) ;; Add `melpa` to `package-archives`. (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) ;; gnu-devel (add-to-list 'package-archives '("gnu-devel" . "https://elpa.gnu.org/devel/") t) (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/") t) (unless package-archive-contents (package-refresh-contents)))
By setting the variable use-package-compute-statistics to t, we'll be able to have reports to see which packages are taking too much time to set up.
(customize-set-variable 'use-package-compute-statistics t) (require 'use-package)
init.el
Tangle this org-file
This file is already added in my git repositories for initial Emacs loading. But I also include it here to make sure there's no changes made.
(require 'ob-tangle) (when (file-exists-p (expand-file-name "index.org" user-emacs-directory)) (org-babel-tangle-file (expand-file-name "index.org" user-emacs-directory)))
Variables and helper functions
Identity
(setopt user-mail-address "alexforsale@yahoo.com" user-full-name "Kristian Alexander P")
merge-list-to-list function archive
This function is just a wrapper to easily merge lists. I don't think I need it anymore.
;;; From https://emacs.stackexchange.com/questions/38008/adding-many-items-to-a-list/68048#68048 (defun merge-list-to-list (dst src) "Merges content of the 2nd list with the 1st one" (set dst (append (eval dst) src)))
define +config/org-directory variable
(cond ((file-directory-p (expand-file-name "Sync/org" (getenv "HOME"))) (customize-set-variable '+config/org-directory (expand-file-name "Sync/org" (getenv "HOME")))) ((string-match-p "microsoft" (shell-command-to-string "uname -a")) (if (file-directory-p "/mnt/c/Users/SyncthingServiceAcct/Default Folder/org") (customize-set-variable '+config/org-directory "/mnt/c/Users/SyncthingServiceAcct/Default Folder/org"))))
I put my org files inside syncthing default directory (~/Sync if on Linux) so it will automatically synced to all my devices. But on windows WSL the location will vary depending on how you install syncthing so I won't even bother set it up.
Load each modular configuration file.
evil
All evil-mode specific configuration and evil related packages goes here.
(require 'config-evil (expand-file-name "modules/config-evil.el" user-emacs-directory) t)
Keybinding
Most keybindings here depends on evil-mode, so it will be loaded after.
(require 'config-keybinding (expand-file-name "modules/config-keybinding.el" user-emacs-directory) t)
UI
(require 'config-ui (expand-file-name "modules/config-ui.el" user-emacs-directory) t)
Configuration for Emacs's looks and feels.
builtins
(require 'config-builtins (expand-file-name "modules/config-builtins.el" user-emacs-directory) t)
The more I understand the meat inside Emacs the less external packages I'll use (hopefully).
completion
(require 'config-completion (expand-file-name "modules/config-completion.el" user-emacs-directory) t)
For now this is for vertico and friends.
shells
(require 'config-shells (expand-file-name "modules/config-shells.el" user-emacs-directory) t)
Mostly vterm configurations. Eshell looks promising, but still hard to configure.
editing
(require 'config-editing (expand-file-name "modules/config-editing.el" user-emacs-directory) t)
Tweaks to make my editing experience nicer.
IDE
(require 'config-ide (expand-file-name "modules/config-ide.el" user-emacs-directory) t)
All of LSP, git, flycheck, and projectile configuration.
org
(require 'config-org (expand-file-name "modules/config-org.el" user-emacs-directory) t)
Most of my changes are in here, the more configurable org-mode, the more unusable to me.
tools
(require 'config-tools (expand-file-name "modules/config-tools.el" user-emacs-directory) t)
Small packages that helps Emacs interacts with its surrounding. I have direnv, exec-path-from-shell for, you guess it, shells. There's also ox-hugo for blogging with hugo.
dired
(require 'config-dired (expand-file-name "modules/config-dired.el" user-emacs-directory) t)
I don't use dired that much, but when I do, I at least know my way around.
treemacs
(require 'config-treemacs (expand-file-name "modules/config-treemacs.el" user-emacs-directory) t)
It's like NERDtree in vim, but in Emacs, I kinda understand why vim need this functionality. C-x C-f with vertico and marginalia already do the same in Emacs. So it's not important to me, but still nice to have.
(require 'config-mail (expand-file-name "modules/config-mail.el" user-emacs-directory) t)
Email in Emacs with the help of notmuch, offlineimap, afew, and davmail for my Exchange mails.
programming modes
(require 'config-progmodes (expand-file-name "modules/config-progmodes.el" user-emacs-directory) t)
Doing stuffs in linux will eventually makes you edit files from various programming languages. This here is just to make me read them comfortly.
local overrides
(require 'config-overrides (expand-file-name "modules/config-overrides.el" user-emacs-directory) t)
Modules
Evil external
configuration
Mostly copied from doom or the official documentation.
(use-package evil :ensure t :hook (after-change-major-mode . (lambda () (setopt evil-shift-width tab-width))) :preface (customize-set-variable 'evil-want-keybinding nil) (customize-set-variable 'evil-want-integration t) (customize-set-variable 'evil-undo-system 'undo-redo) (customize-set-variable 'evil-want-C-i-jump nil) ;; fix TAB in terminal org-mode (customize-set-variable 'evil-want-C-u-scroll t) ;; move universal arg to <leader> u (customize-set-variable 'evil-want-C-u-delete t) ;; delete back to indentation in insert state (customize-set-variable 'evil-want-C-g-bindings t) :custom (evil-undo-system #'undo-redo) (evil-search-module 'evil-search) (evil-ex-search-vim-style-regexp t) (evil-ex-interactive-search-highlight 'selected-window) (evil-kbd-macro-suppress-motion-error t) (evil-visual-update-x-selection-p nil) :config (unless noninteractive (setopt save-silently t)) (setopt evil-normal-state-cursor 'box evil-insert-state-cursor 'bar evil-visual-state-cursor 'hollow) (evil-select-search-module 'evil-search-module 'isearch) (evil-mode 1) (with-eval-after-load 'eldoc (eldoc-add-command 'evil-normal-state 'evil-insert 'evil-change 'evil-delete 'evil-replace)) ;; from doom (defun +evil/window-split-and-follow () "Split current window horizontally, then focus new window. If `evil-split-window-below' is non-nil, the new window isn't focused." (interactive) (let ((evil-split-window-below (not evil-split-window-below))) (call-interactively #'evil-window-split))) (defun +evil/window-vsplit-and-follow () "Split current window vertically, then focus new window. If `evil-vsplit-window-right' is non-nil, the new window isn't focused." (interactive) (let ((evil-vsplit-window-right (not evil-vsplit-window-right))) (call-interactively #'evil-window-vsplit))))
Notes:
evil-search-modules- I switched this to
isearchsince the defaultevil-searchdidn't search through collapsed headings inorg-mode. evil-want-keybindings- I set this to nil so it won't load
evil-keybindings.el. evil-want-integration- Loads
evil-integration.el. evil-undo-system- Use
undo-redowhich is natively available in Emacs 28. evil-want-C-i-jump- Set to nil so
C-iwill insert a tab character, needed when I'm using Emacs inside a terminal. evil-want-C-u-scroll- Set
C-uto scrolls up (like Vim), I'm not using it for prefix arguments since it's already mapped toSPC uin normal mode. evil-want-C-u-delete- The same for insert mode, set
C-uto deletes back to indentation in insert state, prefix argument is set toC-c SPC uin insert mode. evil-want-C-g-bindings- Set a consistent bindings for
C-g, though it also depends on the packages. evil-ex-search-vim-style-regexp- Enables Vim-style backlash codes in search patterns.
evil-ex-interactive-search-highlight- Set the interactive highlighting only to
selected-window. evil-visual-update-x-selection-p- Not updating the
X PRIMARYselection with the current visual region, not sure how it works under wayland though.
I've also steal two functions from Doomemacs,
+evil/window-vsplit-and-follow- which is bound to
SPC w v. +evil/window-split-and-follow- which is bound to
SPC w s.
Why is this the first package in my list? My right hand fingers always land on h, j, k, l. You can't teach old dog new tricks. I've used the vanilla keybindings, it's great but it's faster with /evil-mode.
- Useful keybindings
Not a full list of keybindings, just ones that I should remember to use.
keybindings function description normal-state ] bevil-next-bufferGo to the COUNTth next buffer in the buffer list. normal-state [ bevil-previous-bufferGo to the COUNTth previous buffer in the buffer list. normal-state ] SPCevil-collection-unimpaired-insert-newline-belowInsert COUNT blank line(s) below current line. normal-state [ SPCevil-collection-unimpaired-insert-newline-aboveInsert COUNT blank line(s) above current line.
evil-collection external
This is a collection of Evil bindings for the parts of Emacs that Evil does not cover properly by default, such as help-mode, M-x calendar, Eshell and more.
(use-package evil-collection :after evil :ensure t :init (evil-collection-init) :config (with-eval-after-load 'dired (evil-collection-dired-setup)) (with-eval-after-load 'calendar (evil-collection-calendar-setup)) :custom (evil-collection-setup-minibuffer t) (evil-collection-calendar-want-org-bindings t))
evil-terminal-cursor-changer external
Change cursor shape and color by evil state in terminal.
(use-package evil-terminal-cursor-changer :hook (tty-setup . evil-terminal-cursor-changer-activate) :ensure t :config (setopt evil-motion-state-cursor 'box) ; █ (setopt evil-visual-state-cursor 'box) ; █ (setopt evil-normal-state-cursor 'box) ; █ (setopt evil-insert-state-cursor 'bar) ; ⎸ (setopt evil-emacs-state-cursor 'hbar) ; _ )
evil-surround external
This package emulates surround.vim by Tim Pope. The functionality is wrapped into a minor mode.
(use-package evil-surround :after evil :ensure t :commands (global-evil-surround-mode evil-surround-edit evil-Surround-edit evil-surround-region) :hook (html-mode . (lambda () (push '(?~ . ("<" . ">")) evil-surround-pairs-alist))) (org-mode . (lambda () (push '(?~ . ("~" . "~")) evil-surround-pairs-alist))) (org-mode . (lambda () (push '(?~ . ("<" . ">")) evil-surround-pairs-alist))) (org-mode . (lambda () (push '(?$ . ("\\(" . "\\)")) evil-surround-pairs-alist))) :init (global-evil-surround-mode 1))
- Usage
- Add surrounding
You can surround in visual-state with
S<textobject>orgS<textobject>. Or in normal-state withys<textobject>oryS<textobject>. I'm still using theShift Iin visual mode, and theysin normal mode conflicts withwhich-key-mode. - Change surrounding
You can change a surrounding with
cs<old-textobject><new-textobject>.
- Add surrounding
evil-embrace external
This package provides evil integration of embrace.el. Since evil-surround provides a similar set of features as embrace.el, this package aims at adding the goodies of embrace.el to evil-surround and making evil-surround even better.
(use-package evil-embrace :ensure t :commands embrace-add-pair embrace-add-pair-regexp :hook (LaTeX-mode . embrace-LaTeX-mode-hook) :hook (LaTeX-mode . +evil-embrace-latex-mode-hook-h) :hook (org-mode . embrace-org-mode-hook) :hook (ruby-mode . embrace-ruby-mode-hook) :hook (emacs-lisp-mode . embrace-emacs-lisp-mode-hook) :init (with-eval-after-load 'evil-surround (evil-embrace-enable-evil-surround-integration)) :config ;; from doom (defun +evil--embrace-latex () "LaTeX command support for embrace." (cons (format "\\%s{" (read-string "\\")) "}")) (defun +evil-embrace-latex-mode-hook-h () (dolist (pair '((?\' . ("`" . "\'")) (?\" . ("``" . "\'\'")))) (delete (car pair) evil-embrace-evil-surround-keys) ;; Avoid `embrace-add-pair' because it would overwrite the default ;; rules, which we want for other modes (push (cons (car pair) (make-embrace-pair-struct :key (car pair) :left (cadr pair) :right (cddr pair) :left-regexp (regexp-quote (cadr pair)) :right-regexp (regexp-quote (cddr pair)))) embrace--pairs-list)) (embrace-add-pair-regexp ?l "\\[a-z]+{" "}" #'+evil--embrace-latex)) (defun +evil-embrace-angle-bracket-modes-hook-h () (let ((var (make-local-variable 'evil-embrace-evil-surround-keys))) (set var (delq ?< evil-embrace-evil-surround-keys)) (set var (delq ?> evil-embrace-evil-surround-keys))) (embrace-add-pair-regexp ?< "\\_<[a-z0-9-_]+<" ">" #'+evil--embrace-angle-brackets) (embrace-add-pair ?> "<" ">")))
evil-escape external
Customizable key sequence to escape from insert state and everything else in Emacs. In short, when in insert-mode, you can easily switch to normal-mode just by quickly type jk.
(use-package evil-escape :after evil :ensure t :hook (evil-after-load . evil-escape-mode) :init (setopt evil-escape-excluded-states '(normal visual multiedit emacs motion) evil-escape-excluded-major-modes '(neotree-mode treemacs-mode vterm-mode dired-mode) evil-escape-key-sequence "jk" evil-escape-delay 0.15) (evil-escape-mode 1) (evil-define-key* '(insert replace visual operator) 'global "\C-g" #'evil-escape))
evil-exchange external
(use-package evil-exchange :ensure t :init (evil-exchange-install))
Easy text exchange operator for Evil. This is the port of vim-exchange by Tom McDonald.
evil-nerd-commenter external
A Nerd Commenter emulation, help you comment code efficiently. For example, you can press 99,ci to comment out 99 lines (only works if you set the (evilnc-default-hotkeys t)).
(use-package evil-nerd-commenter :after evil :ensure t :commands (evilnc-comment-operator evilnc-inner-comment evilnc-outer-commenter) :bind ([remap comment-line] . evilnc-comment-or-uncomment-lines) :init (setopt my/evilnc-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "gc") (cons "Comment" my/evilnc-map)) (evil-define-key* nil my/evilnc-map "c" '("comment/uncomment" . evilnc-comment-operator)))
evil-traces external
evil-traces is a port of traces.vim. It enables visual previews for certain evil-ex commands.
(use-package evil-traces :after evil :ensure t :config (evil-traces-mode))
evil-visualstar external
This is a port of one of the many visual-star plugins for Vim to work with evil-mode.
(use-package evil-visualstar :ensure t :commands (evil-visualstar/begin-search evil-visualstar/begin-search-forward evil-visualstar/begin-search-backward) :init (evil-define-key* 'visual 'global "*" #'evil-visualstar/begin-search-forward "#" #'evil-visualstar/begin-search-backward))
evil-vimish-fold external
Integration of vimish-fold with evil
Adds standard vim keybindings of . Fold now can be created with zf and zd to create and delete folds (via vimish-fold) respectively<leader>zf in a region, after that, it hooks into evil so the usual vim keybindings for fold toggling (za), opening (zo), closing (zc) etc all work as expected with vimish-fold.
Finally, also supports navigation between folds using zj and zk.
This provides a near-complete vim folding experience in evil for Emacs.
(use-package evil-vimish-fold :ensure t :demand t :bind (([remap evil-toggle-fold] . vimish-fold-toggle) ([remap evil-close-fold] . vimish-fold-refold) ([remap evil-open-fold] . vimish-fold-unfold) ([remap evil-close-folds] . vimish-fold-refold-all) ([remap evil-open-folds] . vimish-fold-unfold-all)) :commands (evil-vimish-fold/next-fold evil-vimish-fold/previous-fold evil-vimish-fold/delete evil-vimish-fold/delete-all evil-vimish-fold/create evil-vimish-fold/create-line) :init (setopt evil-vimish-fold-mode-lighter " ⮒") (setopt evil-vimish-fold-target-modes '(prog-mode conf-mode text-mode)) (setopt my/vimish-fold-map (make-sparse-keymap)) :config (global-evil-vimish-fold-mode +1))
evil-multiedit external
(use-package evil-multiedit :ensure t :config (defun make-evil-multiedit-case-sensitive (fn &rest args) (let ((case-fold-search (not iedit-case-sensitive))) (apply fn args))) (advice-add #'evil-multiedit-match-and-next :around #'make-evil-multiedit-case-sensitive) (evil-multiedit-default-keybinds) (evil-define-key 'normal 'global (kbd "M-d") #'evil-multiedit-match-symbol-and-next (kbd "M-D") #'evil-multiedit-match-symbol-and-prev) (evil-define-key 'visual 'global "R" #'evil-multiedit-match-all (kbd "M-d") #'evil-multiedit-match-and-next (kbd "M-D") #'evil-multiedit-match-and-prev) (evil-define-key '(visual normal) 'global (kbd "C-M-d") #'evil-multiedit-restore) (with-eval-after-load 'evil-mutliedit (evil-define-key 'multiedit 'global (kbd "M-d") #'evil-multiedit-match-and-next (kbd "M-S-d") #'evil-multiedit-match-and-prev (kbd "RET") #'evil-multiedit-toggle-or-restrict-region) (evil-define-key '(multiedit multiedit-insert) 'global (kbd "C-n") #'evil-multiedit-next (kbd "C-p") #'evil-multiedit-prev)))
Hlissner's implementation of multiple-cursor for evil-mode.
evil-org-mode external
Supplemental evil-mode keybindings to emacs org-mode.
(use-package evil-org :after org :ensure t :hook (org-mode . (lambda () evil-org-mode)) :config (require 'evil-org-agenda) (evil-org-agenda-set-keys))
evil-goggles external
Display visual hint on evil edit operations.
(use-package evil-goggles :ensure t :config (evil-goggles-mode) (evil-goggles-use-diff-faces))
avy external
By using gK or gJ in normal or visual mode.
(use-package avy :ensure t :config (setopt avy-background t) (setopt avy-timeout-seconds 0.5) (evil-define-key* '(normal visual) 'global "gJ" 'evil-avy-goto-line-below "gK" 'evil-avy-goto-line-above))
Keybindings
Leader key
This is taken from vim, The leader key in Vim and Neovim is a special key used as a prefix for custom keyboard shortcuts, also known as mappings. It creates a "namespace" for user-defined commands, allowing you to create personalized shortcuts without conflicting with Vim's default commands.
(with-eval-after-load 'evil (evil-set-leader '(normal visual) (kbd "SPC")))
1st level commands
These commands is used often so it will need a faster keybindings (<leader> <key>).
(with-eval-after-load 'evil (evil-global-set-key 'normal (kbd "<leader>:") '("execute commands" . execute-extended-command)) (evil-global-set-key 'normal (kbd "<leader>;") '("eval expression" . eval-expression)) (evil-global-set-key 'normal (kbd "<leader>u") '("universal arguments" . universal-argument)))
A
(with-eval-after-load 'evil (setopt my/a-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>a") (cons "Act" my/a-map)))
C
For now it's reserved only for org-capture.
(with-eval-after-load 'evil (setopt my/c-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>c") (cons "C" my/c-map)) (with-eval-after-load 'org (evil-define-key* nil my/c-map "c" '("org-capture" . org-capture))))
B
All keybindings will go with <leader>b.
(with-eval-after-load 'evil (setopt my/buffer-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>b") (cons "Buffer" my/buffer-map)) (evil-define-key* nil my/buffer-map "." '("set bookmark" . bookmark-set) "[" '("previous buffer" . previous-buffer) "]" '("next buffer" . next-buffer) "c" '("clone indirect buffer" . clone-indirect-buffer) "C" '("clone indirect buffer other window" . clone-indirect-buffer-other-window) "d" '("kill buffer" . kill-buffer) "i" '("ibuffer" . ibuffer) "k" '("kill buffer" . kill-buffer) "l" '("switch to last buffer" . evil-switch-to-windows-last-buffer) "m" '("switch to message buffer". (lambda () (interactive) (switch-to-buffer "*Messages*"))) "n" '("next buffer" . next-buffer) "N" '("new buffer" . evil-buffer-new) "p" '("previous buffer" . previous-buffer) "o" '("other buffer" . (lambda () (interactive) (switch-to-buffer nil))) "r" '("revert buffer" . revert-buffer) "R" '("rename buffer" . rename-buffer) "s" '("save buffer" . save-buffer) "x" '("switch to scratch buffer" . (lambda () (interactive) (switch-to-buffer "*scratch*"))) "z" '("bury buffer" . bury-buffer)))
- repeat-map
These function will be available for the
repeat-mode.(with-eval-after-load 'evil (defvar my/buffer-map-repeat-map (let ((map (make-sparse-keymap))) (define-key map "n" #'next-buffer) (define-key map "p" #'previous-buffer) (define-key map "[" #'previous-buffer) (define-key map "]" #'next-buffer) map) "Keymap for my/buffer-map repeat") (put 'next-buffer 'repeat-map 'my/buffer-map-repeat-map) (put 'previous-buffer 'repeat-map 'my/buffer-map-repeat-map))
F
Perhaps the most used keybindings, <leader>f.
(with-eval-after-load 'evil (setopt my/file-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>f") (cons "Files" my/file-map)) (evil-define-key* nil my/file-map "f" '("find file" . find-file) "d" '("jump to current directory" . dired-jump) "i" '("open init file" . (lambda () (interactive) (find-file (expand-file-name "init.el" user-emacs-directory)))) "k" '("delete frame" . delete-frame) "r" '("recent file" . recentf) "s" '("save buffer" . save-buffer) "S" '("Save as" . (lambda () (interactive "F") (write-file "./" t))) "t" '("find-file other tab" . find-file-other-tab) "w" '("find file other window" . find-file-other-window)))
G
All git-related commands goes here, <leader>g.
(with-eval-after-load 'evil (setopt my/g-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>g") (cons "G" my/g-map)))
H
This key <leader>h just simulate the standard Emacs C-h.
(with-eval-after-load 'evil (evil-define-key* '(normal visual) 'global (kbd "<leader>h") (cons "Help" help-map)))
I
Commands for quick insertion <leader>i.
(with-eval-after-load 'evil (setopt my/insert-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>i") (cons "I" my/insert-map)) (evil-define-key* nil my/insert-map "c" '("insert character" . insert-char)) (evil-define-key* nil my/insert-map "d" '("duplicate-dwim" . duplicate-dwim)))
O
Misc quick commands, also for org-mode <leader>o.
(with-eval-after-load 'evil (setopt my/org-mode-map (make-sparse-keymap)) (setopt my/open-map (make-sparse-keymap)) (setopt my/open-org (make-sparse-keymap)) (setopt my/open-roam-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>o") (cons "O" my/open-map)) (evil-define-key* nil my/open-map (kbd "o") (cons "Org files" my/open-org)) (with-eval-after-load 'org-roam (evil-define-key* nil my/open-map (kbd "r") (cons "Org Roam" my/open-roam-map))) (evil-define-key* nil my/open-map "a" '("Org Agenda" . org-agenda) "c" '("Org Capture" . org-capture) "L" '("Store org link" . org-store-link) "l" '("Avy open link" . link-hint-open-link)) (with-eval-after-load 'notmuch (evil-define-key* nil my/open-map "m" '("mail" . notmuch))) (evil-define-key* nil my/open-org (kbd "n") '("Notes" . (lambda () (interactive) (find-file (expand-file-name "notes.org" +config/org-directory)))) (kbd "r") '("Routines" . (lambda () (interactive) (find-file (expand-file-name "routines.org" +config/org-directory)))) (kbd "p") '("Personal" . (lambda () (interactive) (find-file (expand-file-name "personal.org" +config/org-directory)))) (kbd "P") '("Projects" . (lambda () (interactive) (find-file (expand-file-name "projects.org" +config/org-directory)))) (kbd "R") '("Last refiled" . org-refile-goto-last-stored) (kbd "C") '("Last Capture" . org-capture-goto-last-stored)))
S
Maybe the third most used keys, <leader>s.
(with-eval-after-load 'evil (setopt my/search-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>s") (cons "S" my/search-map)))
T
(with-eval-after-load 'evil (setopt my/tab-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>t") (cons "T" my/tab-map)))
W
The second most used keybindings, I will try to use the default vim keys.
(with-eval-after-load 'evil (setopt my/window-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>w") (cons "W" my/window-map)) (evil-define-key* nil my/window-map "C-o" '("delete other window" . delete-other-windows) "[" '("left window" . evil-window-left) "]" '("right window" . evil-window-right) "=" '("enlarge window" . enlarge-window) "-" '("shrink window" . shrink-window) "}" '("enlarge horizontal" . enlarge-window-horizontally) "{" '("shrink horizontal" . shrink-window-horizontally) "+" '("increase height" . evil-window-increase-height) "-" '("decrease height" . evil-window-decrease-height) "<" '("decrease width" . evil-window-decrease-width) ">" '("increase width" . evil-window-increase-width) "b" '("bottom right" . evil-window-bottom-right) "c" '("delete" . evil-window-delete) "d" '("delete" . evil-window-delete) "h" '("left window" . evil-window-left) "f" '("find file other window" . ffap-other-window) "j" '("down window" . evil-window-down) "k" '("up window" . evil-window-up) "l" '("window right" . evil-window-right) "n" '("new window" . evil-window-new) "o" '("delete other" . delete-other-windows) "m" '("mru" . evil-window-mru) "q" '("quit window" . evil-quit) "r" '("rotate downward" . evil-window-rotate-downwards) "R" '("rotate upward" . evil-window-rotate-upwards) "s" '("split horizontally and follow" . +evil/window-split-and-follow) "T" '("tear off window" . tear-off-window) "t" '("top left window" . evil-window-top-left) "u" '("undo" . winner-undo) "v" '("split vertical and follow" . +evil/window-vsplit-and-follow) "w" '("other window" . other-window) "W" '("previous window" . evil-window-prev) "x" '("exchange window" . evil-window-exchange) "|" '("set width" . evil-window-set-width) (kbd "<left>") '("left window" . evil-window-left) (kbd "<right>") '("right window" . evil-window-right) (kbd "<down>") '("down window" . evil-window-down) (kbd "<up>") '("up window" . evil-window-up)))
- repeat-map
(with-eval-after-load 'evil (defvar my/window-split-repeat-map (let ((map (make-sparse-keymap))) (define-key map "s" #'+evil/window-split-and-follow) (define-key map "v" #'+evil/window-vsplit-and-follow) map) "Keymap for my/window-exchange repeat") (put '+evil/window-split-and-follow 'repeat-map 'my/window-split-repeat-map) (put '+evil/window-vsplit-and-follow 'repeat-map 'my/window-split-repeat-map)) (with-eval-after-load 'evil (defvar my/window-exchange-repeat-map (let ((map (make-sparse-keymap))) (define-key map "x" #'evil-window-exchange) map) "Keymap for my/window-exchange repeat") (put 'evil-window-exchange 'repeat-map 'my/window-exchange-repeat-map)) (with-eval-after-load 'evil (defvar my/winner-undo-repeat-map (let ((map (make-sparse-keymap))) (define-key map "u" #'winner-undo) map) "Keymap for my/winner-undo repeat") (put 'winner-undo 'repeat-map 'my/winner-undo-repeat-map)) (with-eval-after-load 'evil (defvar my/window-rotate-repeat-map (let ((map (make-sparse-keymap))) (define-key map "r" #'evil-window-rotate-downwards) (define-key map "R" #'evil-window-rotate-downwards) map) "Keymap for my/window-rotate repeat") (put 'evil-window-rotate-upwards 'repeat-map 'my/window-rotate-repeat-map) (put 'evil-window-rotate-downwards 'repeat-map 'my/window-rotate-repeat-map)) (with-eval-after-load 'evil (defvar my/window-size-repeat-map (let ((map (make-sparse-keymap))) (define-key map "=" #'enlarge-window) (define-key map "_" #'shrink-window) (define-key map "{" #'enlarge-window-horizontally) (define-key map "}" #'shrink-window-horizontally) (define-key map "<" #'evil-window-decrease-width) (define-key map ">" #'evil-window-increase-width) (define-key map "+" #'evil-window-increase-height) (define-key map "-" #'evil-window-decrease-height) map) "Keymap for my/buffer-map repeat") (put 'evil-window-increase-height 'repeat-map 'my/window-size-repeat-map) (put 'evil-window-decrease-height 'repeat-map 'my/window-size-repeat-map) (put 'evil-window-decrease-width 'repeat-map 'my/window-size-repeat-map) (put 'evil-window-increase-width 'repeat-map 'my/window-size-repeat-map) (put 'enlarge-window-horizontally 'repeat-map 'my/window-size-repeat-map) (put 'shrink-window-horizontally 'repeat-map 'my/window-size-repeat-map) (put 'enlarge-window 'repeat-map 'my/window-size-repeat-map) (put 'shrink-window 'repeat-map 'my/window-size-repeat-map))
Q
Also used for reloading configuration (like Doomemacs) <leader>q.
(with-eval-after-load 'evil (setopt my/quit-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>q") (cons "Q" my/quit-map)) (evil-define-key* nil my/quit-map "R" '("restart Emacs" . restart-emacs) "r" '("reload configuration" . (lambda () (interactive) (load user-init-file))) "q" '("quit Emacs and save" . save-buffers-kill-terminal)))
Z keys
This is for other evil packages that need its own keybinding, and tbf, there's already a lot of them in the g and z keys.
(with-eval-after-load 'evil (setopt my/z-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>z") (cons "Z" my/z-map)))
Builtins
base builtin
(use-package emacs :ensure nil :config (delete-selection-mode 1) (transient-mark-mode 1) (setopt use-short-answers t delete-by-moving-to-trash t create-lockfiles nil load-prefer-newer t read-buffer-completion-ignore-case t read-file-name-completion-ignore-case t))
repeat-mode builtin
(use-package repeat :ensure nil :init (repeat-mode +1))
files builtin
Usually configurations related to file manipulations.
(use-package files :ensure nil :config (nconc auto-mode-alist '(("/LICENSE\\'" . text-mode) ("\\.log\\'" . text-mode) ("rc\\'" . conf-mode) ("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode))) :hook ((prog-mode text-mode) . auto-save-visited-mode) :custom (auto-save-visited-interval 10) (find-file-suppress-same-file-warnings t) ;;(confirm-kill-emacs #'yes-or-no-p) ; confirm when exiting (confirm-kill-processes nil) ; don't confirm killing processes (revert-without-query (list ".")) (find-file-visit-truename t) ; `find-file' will visit the actual file (make-backup-files nil) (version-control t) (backup-by-copying t) (delete-old-versions t) (kept-new-versions 6) (kept-old-versions 2) (auto-save-include-big-deletions t) (auto-save-list-file-prefix (expand-file-name ".autosave/" user-emacs-directory)) (backup-directory-alist `(("." . ,(expand-file-name ".backup" user-emacs-directory)))) (auto-mode-case-fold nil) (require-final-newline t))
savehist builtin
Saving the minibuffer history.
(use-package savehist :init (savehist-mode 1) :custom (savehist-file (expand-file-name "history" user-emacs-directory)) (savehist-save-minibuffer-history t) (savehist-autosave-interval nil) (savehist-coding-system 'utf-8) (savehist-additional-variables '(evil-jumps-history command-history kill-ring register-alist mark-ring global-mark-ring search-ring regexp-search-ring)))
comint builtin
(use-package comint :ensure nil :config (setopt comint-prompt-read-only t comint-buffer-maximum-size 2048) (evil-define-key* '(normal visual) comint-mode-map "q" '(lambda () (interactive) (kill-buffer nil))))
UI
base UI builtin
(use-package emacs :ensure nil :config (when (bound-and-true-p tooltip-mode) (tooltip-mode -1)) (setopt hscroll-margin 2 hscroll-step 1 scroll-conservatively 10 scroll-margin 0 scroll-preserve-screen-position t auto-window-vscroll nil window-resize-pixelwise t frame-resize-pixelwise t use-dialog-box nil use-file-dialog nil echo-keystrokes 0.02 resize-mini-windows 'grow-only inhibit-startup-screen t inhibit-compacting-font-caches t minibuffer-prompt-properties '(read-only t intangible t cursor-intangible t face minibuffer-prompt)))
font-core builtin
(use-package font-core :ensure nil :init (global-font-lock-mode t))
which-key builtin
Emacs package that displays available keybindings in popup. This is one of the top Emacs packages that I must have in my configuration. Now built in into Emacs.
(use-package which-key :ensure nil :custom (which-key-lighter "") (which-key-sort-order #'which-key-key-order-alpha) (which-key-sort-uppercase-first nil) (which-key-add-column-padding 1) (which-key-max-display-columns nil) (which-key-min-display-lines 6) (which-key-compute-remaps t) (which-key-side-window-slot -10) (which-key-separator " → ") (which-key-allow-evil-operators nil) (which-key-use-C-h-commands t) (which-key-show-remaining-keys t) (which-key-show-prefix 'bottom) (which-key-show-operator-state-maps nil) :config (which-key-mode) (which-key-setup-side-window-bottom) (which-key-setup-minibuffer) (define-key which-key-mode-map (kbd "C-x <f5>") 'which-key-C-h-dispatch))
winner builtin
(use-package winner :ensure nil :init (winner-mode +1) :config (setopt winner-boring-buffers '("*Completions*" "*Compile-Log*" "*inferior-lisp*" "*Fuzzy Completions*" "*Apropos*" "*Help*" "*cvs*" "*Buffer List*" "*Ibuffer*" "*esh command on file*")))
marginalia external
(use-package marginalia :ensure t :bind (:map minibuffer-local-map ("M-A" . marginalia-cycle)) :init (marginalia-mode))
nerd-icons-completion external
(use-package nerd-icons-completion :after marginalia :ensure t :hook (marginalia-mode . nerd-icons-completion-marginalia-setup) :config (nerd-icons-completion-mode))
rainbow-mode external
(use-package rainbow-mode :hook (prog-mode . rainbow-mode) :ensure t :config (setopt rainbow-html-colors-major-mode-list '(prog-mode conf-mode html-mode css-mode php-mode nxml-mode xml-mode) rainbow-html-colors t))
rainbow-identifiers external
(use-package rainbow-identifiers :ensure t :hook (prog-mode . rainbow-identifiers-mode))
rainbow-delimiters external
(use-package rainbow-delimiters :ensure t :hook (prog-mode . rainbow-delimiters-mode) :config (setopt rainbow-delimiters-max-face-count 4))
indent-bars external
(use-package indent-bars :ensure t :hook (prog-mode . indent-bars-mode))
nerd-icons external
(use-package nerd-icons :ensure t)
doom-themes external
(use-package doom-themes :ensure t :custom (doom-themes-enable-bold t) (doom-themes-enable-italic t) :config (load-theme 'doom-moonlight t) (doom-themes-visual-bell-config) (doom-themes-org-config))
doom-modeline external
(use-package doom-modeline :ensure t :hook (after-init . doom-modeline-mode) :config (setopt doom-modeline-project-detection 'auto doom-modeline-indent-info t))
window builtin
(use-package window :ensure nil :config (setopt split-width-threshold 160 split-height-threshold nil))
Shells and Terminals
vterm external
(use-package vterm :ensure t :demand t :commands vterm-mode :config (setopt my/vterm-map (make-sparse-keymap)) (evil-define-key* '(normal visual) 'global (kbd "<leader>v") (cons "Vterm" my/vterm-map)) (evil-define-key* nil my/vterm-map "V" '("terminal" . vterm)) (evil-collection-vterm-setup) (add-hook 'vterm-mode-hook (lambda () (setq-local global-hl-line-mode nil) (setq-local hscroll-margin 0))) (setopt vterm-kill-buffer-on-exit t) (evil-set-initial-state #'vterm-mode 'insert))
multi-vterm external
(use-package multi-vterm :after vterm :ensure t :config (setopt multi-vterm-dedicated-window-height-percent 20) (evil-define-key* nil my/vterm-map "v" '("toggle terminal" . multi-vterm-dedicated-toggle)) (global-set-key (kbd "C-\\") #'multi-vterm-dedicated-toggle) (evil-define-key 'insert vterm-mode-map (kbd "C-\\") #'multi-vterm-dedicated-toggle) (evil-define-key* 'normal vterm-mode-map (kbd ",c") #'multi-vterm) (evil-define-key* 'normal vterm-mode-map (kbd ",n") #'multi-vterm-next) (evil-define-key* 'normal vterm-mode-map (kbd ",p") #'multi-vterm-prev))
Editing
saveplace builtin
When closing a file (like when exiting Emacs or killing a buffer), the point (or cursor) in that buffer will be saved. I find this a must-have feature.
(use-package saveplace :init (save-place-mode 1) :custom (save-place-file (expand-file-name "places" user-emacs-directory)))
recentf builtin
(use-package recentf :bind ("C-c f" . recentf) :commands recentf-open-files :init (recentf-mode 1) :custom (recentf-auto-cleanup t) (recentf-max-saved-items 250) (recentf-max-menu-items 300) (recentf-exclude `("/elpa/" ;; ignore all files in elpa directory "recentf" ;; remove the recentf load file ".*?autoloads.el$" "treemacs-persist" "company-statistics-cache.el" ;; ignore company cache file "/intero/" ;; ignore script files generated by intero "/journal/" ;; ignore daily journal files ".gitignore" ;; ignore `.gitignore' files in projects "/tmp/" ;; ignore temporary files "NEWS" ;; don't include the NEWS file for recentf "bookmarks" "bmk-bmenu" ;; ignore bookmarks file in .emacs.d "loaddefs.el" "^/\\(?:ssh\\|su\\|sudo\\)?:" ;; ignore tramp/ssh files (concat "^" (regexp-quote (or (getenv "XDG_RUNTIME_DIR") "/run"))))))
Even though I use consult-find-file the actual recentf package is still used (I think).
autorevert builtin
Here I'm using global-auto-revert-mode to automatically revert all opened buffer.
(use-package autorevert :hook (focus-in . doom-auto-revert-buffers-h) :hook (after-save . doom-auto-revert-buffers-h) :hook (prog-mode . doom-auto-revert-buffer-h) :custom (auto-revert-interval 60) (auto-revert-use-notify nil) (global-auto-revert-non-file-buffers t) (auto-revert-verbose t) (auto-revert-stop-on-user-input nil) (revert-without-query (list ".")) :config (defun doom-visible-buffer-p (buf) "Return non-nil if BUF is visible." "Return non-nil if BUF is not visible." (not (doom-visible-buffer-p buf))) (defun doom-visible-buffers (&optional buffer-list all-frames) "Return a list of visible buffers (i.e. not buried)." (let ((buffers (delete-dups (cl-loop for frame in (if all-frames (visible-frame-list) (list (selected-frame))) if (window-list frame) nconc (mapcar #'window-buffer it))))) (if buffer-list (cl-delete-if (lambda (b) (memq b buffer-list)) buffers) (delete-dups buffers)))) (defun doom-auto-revert-buffer-h () "Auto revert current buffer, if necessary." (unless (or auto-revert-mode (active-minibuffer-window)) (let ((auto-revert-mode t)) (auto-revert-handler)))) (defun doom-auto-revert-buffers-h () "Auto revert stale buffers in visible windows, if necessary." (dolist (buf (doom-visible-buffers)) (with-current-buffer buf (doom-auto-revert-buffer-h)))))
mouse builtin
(use-package mouse :ensure nil :config (setopt mouse-yank-at-point t))
subword builtin
(use-package subword :ensure nil :init (global-subword-mode 1))
text-mode builtin
(use-package text-mode :ensure nil :hook (((text-mode prog-mode) . visual-line-mode) (prog-mode . (lambda () (setq-local sentence-end-double-space t)))) :config (setq-default sentence-end-double-space nil) (setopt sentence-end-without-period nil) (setopt colon-double-space nil) (setopt adaptive-fill-mode t))
select builtin
(use-package select :ensure nil :custom (select-enable-clipboard t))
ws-butler external
(use-package ws-butler :ensure t :hook ((prog-mode text-mode) . ws-butler-mode))
IDE stuffs
treesit-auto external
(add-to-list 'treesit-language-source-alist '(html "https://github.com/tree-sitter/tree-sitter-html")) (add-to-list 'treesit-language-source-alist '(json "https://github.com/tree-sitter/tree-sitter-json")) (use-package treesit-auto :ensure t :custom (treesit-auto-install 'prompt) :config (add-hook 'yaml-ts-mode-hook '(lambda () (setq-local tab-width 2))) (add-hook 'json-ts-mode-hook '(lambda () (setq-local tab-width 2))) (add-hook 'python-ts-mode-hook '(lambda () (setq-local tab-width 4))) (add-hook 'c-ts-mode-hook '(lambda () (setq-local tab-width 4))) ;; mjs (add-to-list 'auto-mode-alist '("\\.mjs\\'" . js-ts-mode)) (treesit-auto-add-to-auto-mode-alist 'all) (global-treesit-auto-mode))
lsp-mode external
(use-package lsp-mode :ensure t :hook ((nix-ts-mode lua-ts-mode python-ts-mode html-ts-mode yaml-ts-mode toml-ts-mode json-ts-mode bash-ts-mode js-ts-mode rust-ts-mode css-ts-mode typescript-ts-mode c-ts-mode) . lsp-deferred) :hook (lsp-completion-mode . my/lsp-mode-setup-completion) :commands (lsp lsp-deferred) :init (setopt lsp-keymap-prefix "C-c l") (defun my/lsp-mode-setup-completion () (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults)) '(orderless)) (add-hook 'orderless-style-dispatchers #'my/orderless-dispatch-flex-first nil 'local) (setq-local completion-at-point-functions (list (cape-capf-buster #'lsp-completion-at-point)))) :config (evil-define-key 'normal lsp-mode-map (kbd "gD") 'lsp-goto-implementation (kbd "gA") 'lsp-execute-code-action (kbd "gr") 'lsp-find-references (kbd "gR") 'lsp-rename (kbd "K") 'lsp-describe-thing-at-point (kbd "<leader>ma") 'lsp-avy-lens (kbd "<leader>aA") 'lsp-execute-code-action) :custom (lsp-completion-provider :none)) (use-package lsp-ui :ensure t :commands lsp-ui-mode)
yasnippets external
This is provided by yasnippet.
(use-package yasnippet :ensure t :config (yas-global-mode) (define-key yas-keymap [tab] 'yas-next-field) (setopt yas-snippets-dir (list (expand-file-name "snippets" user-emacs-directory) (expand-file-name "straight/build/yasnippet-snippets/snippets" user-emacs-directory))) (evil-define-key* nil my/insert-map "s" '("insert snippet" . consult-yasnippet))) (use-package consult-yasnippet :ensure t) (use-package yasnippet-snippets :ensure t)
yasnippet-capf external
(use-package yasnippet-capf :after cape :ensure t :config (add-to-list 'completion-at-point-functions #'yasnippet-capf))
projectile external
A project interaction library for Emacs, with little external dependency as possible.
(use-package projectile :ensure t :demand t :commands (projectile-project-root projectile-project-name projectile-project-p projectile-locate-dominating-file projectile-relevant-known-projects) :bind (([remap evil-jump-to-tag] . projectile-find-tag) ([remap find-tag] . projectile-find-tag)) :hook (dired-before-readin . projectile-track-known-projects-find-file-hook) :custom (projectile-cache-file (expand-file-name ".projects" user-emacs-directory)) (projectile-auto-discover nil) (projectile-enable-caching (not noninteractive)) (projectile-globally-ignored-files '("DS_Store" "TAGS")) (projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o")) (projectile-kill-buffers-filter 'kill-only-files) (projectile-known-projects-file (expand-file-name ".projectile_projects.eld" user-emacs-directory)) (projectile-ignored-projects '("~/")) (projectile-project-search-path `(,(expand-file-name "Projects" (getenv "HOME")))) (projectile-project-root-files-bottom-up (append '(".projectile" ".project" ".git") (when (executable-find "hg") '(".hg")) (when (executable-find "bzr") '(".bzr")))) (projectile-project-root-files-top-down-recurring '("Makefile")) (compilation-buffer-name-function #'projectile-compilation-buffer-name) (compilation-save-buffers-predicate #'projectile-current-project-buffer-p) (projectile-git-submodule-command nil) (projectile-indexing-method 'hybrid) :config (global-set-key [remap evil-jump-to-tag] #'projectile-find-tag) (global-set-key [remap find-tag] #'projectile-find-tag) (projectile-mode +1) (put 'projectile-git-submodule-command 'initial-value projectile-git-submodule-command) (evil-define-key* '(normal visual) 'global (kbd "<leader>SPC") '("find project file" . projectile-find-file)) (evil-define-key* '(normal visual) 'global (kbd "<leader>p") (cons "Project" projectile-command-map)))
perspective external
Useful when I'm working on several projectile projects at once. With each perspective having their own separate buffer list.
(use-package perspective :ensure t :demand t :config (persp-mode) (setopt persp-initial-frame-name "Main" persp-suppress-no-prefix-key-warning t) (if (featurep 'no-littering) (setopt persp-state-default-file (expand-file-name ".perspective-state" no-littering-var-directory)) (setopt persp-state-default-file (expand-file-name ".perspective-state" user-emacs-directory))) (global-set-key [remap switch-to-buffer] #'persp-switch-to-buffer*) (when (featurep 'consult) (require 'consult) (unless (boundp 'persp-consult-source) (defvar persp-consult-source (list :name "Perspective" :narrow ?s :category 'buffer :state #'consult--buffer-state :history 'buffer-name-history :default t :items #'(lambda () (consult--buffer-query :sort 'visibility :predicate '(lambda (buf) (persp-is-current-buffer buf t)) :as #'buffer-name))))) (consult-customize consult--source-buffer :hidden t :default nil) (add-to-list 'consult-buffer-sources persp-consult-source)) (evil-define-key* '(normal visual) 'global (kbd "<leader>TAB") (cons "Perspective" perspective-map)) (evil-define-key* nil perspective-map (kbd "TAB") '("swich to last used perspective" . persp-switch-last) "P" '("switch project" . projectile-persp-switch-project)) :init (customize-set-variable 'persp-mode-prefix-key (kbd "C-c TAB")) :bind (([remap switch-to-buffer] . persp-switch-to-buffer*) ([remap kill-buffer] . persp-kill-buffer*)) :hook (kill-emacs . persp-state-save))
persp-projectile external
(use-package persp-projectile :ensure t :after perspective :commands projectile-persp-switch-project)
smartparens external
I've tried to use the built-in electric-pair for a while, it just doesn't have the default configuration for many of the major-modes that I frequently used, and I don't like spending time configuring for each of them. So smartparens it is!
(use-package smartparens :ensure t :hook (text-mode markdown-mode prog-mode) :config (require 'smartparens-config))
consult-lsp external
(use-package consult-lsp :ensure t :after consult lsp :config (define-key lsp-mode-map [remap xref-find-apropos] #'consult-lsp-symbols))
dap-mode external
(use-package dap-mode :ensure t)
Org-mode
variables
- +config/org-directory
This is for checking the correct directory for
org-modefiles between my various machines.(if (not +config/org-directory) (cond ((file-directory-p (expand-file-name "Dropbox/org" (getenv "HOME"))) (setopt org-directory (expand-file-name "Dropbox/org" (getenv "HOME")))) ((file-directory-p (expand-file-name "Sync/org" (getenv "HOME"))) (setopt org-directory (expand-file-name "Sync/org" (getenv "HOME")))) ((file-directory-p (expand-file-name "Documents/google-drive/org" (getenv "HOME"))) (setopt org-directory (expand-file-name "Documents/google-drive/org" (getenv "HOME"))))) (customize-set-variable 'org-directory +config/org-directory))
org-mode core package builtin
(defun +confing/org-mode-keybindings () (with-eval-after-load 'evil (setopt my/org-note-map (make-sparse-keymap)) (evil-define-key* '(normal visual) org-mode-map (kbd "<leader>m") (cons "org-mode" my/org-mode-map)) (evil-define-key* nil my/org-mode-map "n" (cons "Notes" my/org-note-map)) (evil-define-key* nil my/org-mode-map (kbd "M-l") 'org-insert-last-stored-link (kbd "C-w") '("Refile" . org-refile)) (evil-define-key nil my/org-note-map "c" '("capture" . org-capture))) (global-set-key (kbd "C-c l") #'org-store-link) (global-set-key (kbd "C-c a") #'org-agenda) (global-set-key (kbd "C-c c") #'org-capture)) (use-package org :demand t :commands org-tempo :hook (org-mode . flyspell-mode) :hook ((org-mode . org-indent-mode) (org-mode . +config/org-prettify-symbols) (org-mode . variable-pitch-mode)) :config (with-eval-after-load 'evil (setopt my/org-note-map (make-sparse-keymap)) (evil-define-key* '(normal visual) org-mode-map (kbd "<leader>m") (cons "org-mode" my/org-mode-map)) (evil-define-key* nil my/org-mode-map "n" (cons "Notes" my/org-note-map)) (evil-define-key* nil my/org-mode-map (kbd "M-l") 'org-insert-last-stored-link (kbd "C-w") '("Refile" . org-refile)) (evil-define-key nil my/org-note-map "c" '("capture" . org-capture))) (with-eval-after-load 'evil-collection (evil-collection-org-setup)) (global-set-key (kbd "C-c l") #'org-store-link) (global-set-key (kbd "C-c a") #'org-agenda) (global-set-key (kbd "C-c c") #'org-capture) (cond ((file-directory-p (expand-file-name "braindump/org" org-directory)) (customize-set-variable '+config/org-roam-directory (expand-file-name "braindump/org" org-directory))) ((file-directory-p (expand-file-name "Projects/personal/braindump/org" (getenv "HOME"))) (customize-set-variable '+config/org-roam-directory (expand-file-name "Projects/personal/braindump/org" (getenv "HOME"))))) (cond ((file-directory-p (expand-file-name "alexforsale.github.io" org-directory)) (customize-set-variable '+config/blog-directory (expand-file-name "alexforsale.github.io" org-directory))) ((file-directory-p (expand-file-name "Projects/personal/alexforsale.github.io" (getenv "HOME"))) (customize-set-variable '+config/blog-directory (expand-file-name "Projects/personal/alexforsale.github.io" (getenv "HOME"))))) (modify-syntax-entry ?= "$" org-mode-syntax-table) (modify-syntax-entry ?~ "$" org-mode-syntax-table) (modify-syntax-entry ?_ "$" org-mode-syntax-table) (modify-syntax-entry ?+ "$" org-mode-syntax-table) (modify-syntax-entry ?/ "$" org-mode-syntax-table) (modify-syntax-entry ?* "$" org-mode-syntax-table) (add-to-list 'org-modules 'org-tempo t) (add-to-list 'org-structure-template-alist '("sh" . "src sh")) (add-to-list 'org-structure-template-alist '("co" . "src conf")) (add-to-list 'org-structure-template-alist '("lisp" . "src lisp")) (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) (add-to-list 'org-structure-template-alist '("sc" . "src scheme")) (add-to-list 'org-structure-template-alist '("ts" . "src typescript")) (add-to-list 'org-structure-template-alist '("py" . "src python")) (add-to-list 'org-structure-template-alist '("go" . "src go")) (add-to-list 'org-structure-template-alist '("yaml" . "src yaml")) (add-to-list 'org-structure-template-alist '("js" . "src js")) (add-to-list 'org-structure-template-alist '("json" . "src json")) (add-to-list 'org-structure-template-alist '("n" . "note")) (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (awk . t) (C . t) (css . t) (calc . t) (ditaa . t) ; needs the `ditaa' package (dot . t ) ; `graphviz' (screen . t) (haskell . t) (java . t) (js . t) (latex . t) (lisp . t) (lua . t) (org . t) (perl . t) (plantuml . t) (python .t) (ruby . t) (shell . t) (sed . t) (scheme . t) (sql . t) (sqlite . t))) (setq-default org-use-sub-superscripts '{}) (add-to-list 'org-babel-tangle-lang-exts '("js" . "js")) (defun +config/org-prettify-symbols () (push '("[ ]" . "☐") prettify-symbols-alist) (push '("[X]" . "☑") prettify-symbols-alist) (prettify-symbols-mode)) (require 'org-tempo) :custom (org-highlight-latex-and-related '(native script entities)) (org-replace-disputed-keys t) (org-indirect-buffer-display 'current-window) (org-enforce-todo-dependencies t) (org-fontify-whole-heading-line t) (org-return-follows-link t) (org-mouse-1-follows-link t) (org-image-actual-width nil) (org-adapt-indentation nil) (org-startup-indented t) (org-link-descriptive nil) (org-log-done 'time) (org-log-refile 'time) (org-log-redeadline 'time) (org-log-reschedule 'time) (org-log-into-drawer t) (org-clone-delete-id t) (org-default-notes-file (expand-file-name "notes.org" org-directory)) (org-insert-heading-respect-content nil) (org-pretty-entities t) (org-use-property-inheritance t) (org-priority-highest ?A) (org-priority-lowest ?D) (org-priority-default ?B) (org-todo-keywords '((sequence "TODO(t!)" ; A task that needs doing & is ready to do "NEXT(n!)" ; Tasks that can be delayed "PROG(p!)" ; A task that is in progress "WAIT(w!)" ; Something external is holding up this task "HOLD(h!)" ; This task is paused/on hold because of me "|" "DONE(d!)" ; Task successfully completed "DELEGATED(l!)" ; Task is delegated "NOTES(o!)" ; set as notes "KILL(k!)") ; Task was cancelled, aborted or is no longer applicable )) (org-todo-keyword-faces '(("PROG" . (:foreground "#268bd2" :weight bold)) ("WAIT" . (:foreground "#b58900" :weight bold)) ("HOLD" . (:foreground "#859900" :weight bold)) ("NEXT" . (:foreground "#2aa198" :weight bold)) ("NOTES" . "#6c7c80") ("DELEGATED" . "#d33682") ("KILL" . "#a3be8c"))))
org-contrib external
(use-package org-contrib :ensure t)
org-entities builtin
(use-package org-entities :ensure nil :config (setopt org-entities-user '(("flat" "\\flat" nil "" "" "266D" "♭") ("sharp" "\\sharp" nil "" "" "266F" "♯"))))
org-faces builtin
(use-package org-faces :ensure nil :custom (org-fontify-quote-and-verse-blocks t))
org-archive builtin
(use-package org-archive :ensure nil :after org :custom (org-archive-tag "archive") (org-archive-subtree-save-file-p t) (org-archive-mark-done t) (org-archive-reversed-order t) (org-archive-location (concat (expand-file-name "archives.org" org-directory) "::datetree/* Archived Tasks")))
org-capture builtin
(use-package org-capture :after org :ensure nil :demand t :config (org-capture-put :kill-buffer t) (setq org-capture-templates ;; this is the default from `doom'. `(("i" "Inbox - Goes Here first!" entry (file+headline ,(expand-file-name "inbox.org" org-directory) "Inbox") "** %?\n%i\n%a" :prepend t) ;; ("r" "Request" entry (file+headline ,(expand-file-name "inbox.org" org-directory) "Request") ;; (file ,(expand-file-name "request.template" org-directory))) ("l" "Links" entry (file+headline ,(expand-file-name "links.org" org-directory) "Links")))))
org-refile builtin
(use-package org-refile :ensure nil :after org :hook (org-after-refile-insert . save-buffer) :custom (org-refile-targets `((,(expand-file-name "projects.org" org-directory) :maxlevel . 1) (,(expand-file-name "notes.org" org-directory) :maxlevel . 1) (,(expand-file-name "routines.org" org-directory) :maxlevel . 3) (,(expand-file-name "personal.org" org-directory) :maxlevel . 1))) (org-refile-use-outline-path 't) (org-outline-path-complete-in-steps nil))
org-fold builtin
(use-package org-fold :ensure nil :after org org-contrib :custom (org-catch-invisible-edits 'smart))
org-id builtin
(use-package org-id :ensure nil :after org :custom (org-id-locations-file-relative t) (org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id))
org-num builtin
(use-package org-num :ensure nil :after org :custom (org-num-face '(:inherit org-special-keyword :underline nil :weight bold)) (org-num-skip-tags '("noexport" "nonum")))
org-crypt builtin
(use-package org-crypt ; built-in :ensure nil :after org :commands org-encrypt-entries org-encrypt-entry org-decrypt-entries org-decrypt-entry ;;:hook (org-reveal-start . org-decrypt-entry) :preface ;; org-crypt falls back to CRYPTKEY property then `epa-file-encrypt-to', which ;; is a better default than the empty string `org-crypt-key' defaults to. (defvar org-crypt-key nil) (with-eval-after-load 'org (add-to-list 'org-tags-exclude-from-inheritance "crypt")) :config (setopt epa-file-encrypt-to "alexforsale@yahoo.com"))
org-attach builtin
(use-package org-attach :ensure nil :after org :commands (org-attach-new org-attach-open org-attach-open-in-emacs org-attach-reveal-in-emacs org-attach-url org-attach-set-directory org-attach-sync) :config (unless org-attach-id-dir (setq-default org-attach-id-dir (expand-file-name ".attach/" org-directory))) (with-eval-after-load 'projectile (add-to-list 'projectile-globally-ignored-directories org-attach-id-dir)) :custom (org-attach-auto-tag nil))
org-agenda builtin
(use-package org-agenda :ensure nil :after org :custom (org-agenda-breadcrumbs-separator " → ") (org-agenda-files (list (concat org-directory "/"))) (org-agenda-file-regexp "\\`[^.].*\\.org\\|[0-9]+$\\'") (org-agenda-include-inactive-timestamps t) (org-agenda-window-setup 'only-window) (org-stuck-projects '("+{project*}-killed-Archives/-DONE-KILL-DELEGATED" ("TODO" "NEXT" "IDEA" "PROG") nil "")) :config (with-eval-after-load 'evil (evil-set-initial-state #'org-agenda-mode 'normal) (evil-define-key 'normal org-agenda-mode-map "q" 'org-agenda-quit)) (setopt org-agenda-custom-commands `(("w" "Work Agenda and all TODOs" ((agenda "" ((org-agenda-span 1) (org-agenda-start-on-weekday t) (org-agenda-block-separator nil) (org-agenda-use-time-grid t) (org-agenda-day-face-function (lambda (date) 'org-agenda-date)) (org-agenda-format-date "%A %-e %B %Y") (org-agenda-overriding-header "\nToday\n"))) (tags-todo "TODO=\"TODO\"|\"NEXT\"" ((org-agenda-block-separator nil) (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done)) (org-agenda-use-time-grid nil) (org-agenda-overriding-header "\nIncomplete\n"))) (agenda "" ((org-agenda-span 7) (org-agenda-start-on-weekday 1) (org-agenda-block-separator nil) (org-agenda-use-time-grid nil) (org-agenda-overriding-header "\nWeekly\n")))) ((org-agenda-tag-filter-preset '("-personal" "-home")))) ("h" "Home Agenda and all personal TODOs" ((agenda "" ((org-agenda-span 1) (org-agenda-start-on-weekday t) (org-agenda-block-separator nil) (org-agenda-use-time-grid t) (org-agenda-day-face-function (lambda (date) 'org-agenda-date)) (org-agenda-format-date "%A %-e %B %Y") (org-agenda-overriding-header "\nToday\n"))) (tags-todo "TODO=\"TODO\"|\"NEXT\"" ((org-agenda-block-separator nil) (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done)) (org-agenda-use-time-grid nil) (org-agenda-overriding-header "\nIncomplete\n"))) (agenda "" ((org-agenda-span 7) (org-agenda-start-on-weekday 1) (org-agenda-block-separator nil) (org-agenda-use-time-grid nil) (org-agenda-overriding-header "\nWeekly\n")))) ;; ((org-agenda-tag-filter-preset '("+personal"))) ))))
org-clock builtin
(use-package org-clock :ensure nil :after org :commands org-clock-save :hook (kill-emacs . org-clock-save) :custom (org-persist 'history) (org-clock-in-resume t) (org-clock-out-remove-zero-time-clocks t) (org-clock-history-length 20) (org-show-notification-handler "notify-send") (org-agenda-skip-scheduled-if-deadline-is-shown t) :config (org-clock-persistence-insinuate) (with-eval-after-load 'evil (setopt my/org-clock-mode-map (make-sparse-keymap)) (evil-define-key* nil my/org-mode-map (kbd "C") (cons "Org Clock" my/org-clock-mode-map)) (evil-define-key* nil my/org-clock-mode-map "d" '("display clock" . org-clock-display) (kbd "C-d") '("display clock" . org-clock-display) "e" '("modify clock estimate" . org-clock-modify-effort-estimate) "i" '("clock in" . org-clock-in) "l" '("clock in last clock" . org-clock-in-last) (kbd "C-x") '("clock in last clock" . org-clock-in-last) "o" '("clock out" . org-clock-out) "g" '("goto clock" . org-clock-goto) (kbd "C-j") '("goto clock" . org-clock-goto) "q" '("cancel clock" . org-clock-cancel) (kbd "q") '("cancel clock" . org-clock-cancel))))
org-timer builtin
(use-package org-timer :ensure nil :config (setopt org-timer-format "Timer :: %s"))
org-eldoc builtin
(use-package org-eldoc :ensure nil :after org org-contrib :config (puthash "org" #'ignore org-eldoc-local-functions-cache) ;;(puthash "plantuml" #'ignore org-eldoc-local-functions-cache) (puthash "python" #'python-eldoc-function org-eldoc-local-functions-cache) :custom (org-eldoc-breadcrumb-separator " → "))
org-superstar external
(use-package org-superstar :ensure t :hook (org-mode . org-superstar-mode) :custom (org-superstar-leading-bullet ?\s) (org-superstar-leading-fallback ?\s) (org-hide-leading-stars nil) (org-indent-mode-turns-on-hiding-stars nil) (org-superstar-todo-bullet-alist '(("TODO" . 9744) ("[ ]" . 9744) ("DONE" . 9745) ("[X]" . 9745))) :config (org-superstar-configure-like-org-bullets))
org-fancy-priorities external
(use-package org-fancy-priorities ; priority icons :ensure t :defer t :hook (org-mode . org-fancy-priorities-mode) :hook (org-agenda-mode . org-fancy-priorities-mode) :custom (org-fancy-priorities-list '("⚡" "⬆" "⬇" "☕")))
org-modern external
(use-package org-modern :ensure t :demand t :config (set-face-attribute 'org-modern-symbol nil :family "Iosevka Nerd Font") (setq ;; Edit settings org-auto-align-tags nil org-tags-column 0 org-fold-catch-invisible-edits 'show-and-error org-special-ctrl-a/e t org-insert-heading-respect-content t ;; Org styling, hide markup etc. org-hide-emphasis-markers nil ; set to nil for easier editing org-ellipsis "…" ;; Agenda styling org-agenda-tags-column 0 org-agenda-block-separator ?─ org-agenda-time-grid '((daily today require-timed) (800 1000 1200 1400 1600 1800 2000) " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄") org-agenda-current-time-string "◀── now ─────────────────────────────────────────────────") (global-org-modern-mode))
org-download external
(use-package org-download :ensure t :after org :commands org-download-dnd org-download-yank org-download-screenshot org-download-clipboard org-download-dnd-base64 :config (unless org-download-image-dir (setopt org-download-image-dir org-attach-id-dir)) (setopt org-download-method 'attach org-download-timestamp "_%Y%m%d_%H%M%S" org-download-screenshot-method (cond ((featurep :system 'macos) "screencapture -i %s") ((featurep :system 'linux) (cond ((executable-find "maim") "maim -s %s") ((executable-find "scrot") "scrot -s %s") ((executable-find "gnome-screenshot") "gnome-screenshot -a -f %s")))) org-download-heading-lvl nil org-download-link-format "[[download:%s]]\n" org-download-annotate-function (lambda (_link) "") org-download-link-format-function (lambda (filename) (if (eq org-download-method 'attach) (format "[[attachment:%s]]\n" (org-link-escape (file-relative-name filename (org-attach-dir)))) ;; Handle non-image files a little differently. Images should be ;; inserted as normal with previews. Other files, like pdfs or zips, ;; should be linked to, with an icon indicating the type of file. (format (concat (unless (image-type-from-file-name filename) (concat (+org-attach-icon-for filename) " ")) org-download-link-format) (org-link-escape (funcall org-download-abbreviate-filename-function filename))))) org-download-abbreviate-filename-function (lambda (path) (if (file-in-directory-p path org-download-image-dir) (file-relative-name path org-download-image-dir) path))))
org-roam external
I've tried different Emacs packages for note taking. Although this is not a lightweight solution, but it's still the best one for me. And I publish it to my personal blog.
(use-package org-roam :ensure t :if (not (equal 'windows-nt system-type)) :demand t :after org :custom (org-roam-directory +config/org-roam-directory) (org-roam-complete-everywhere t) (org-roam-capture-templates '(("d" "default" plain "#+author: %n\n#+date: %t\n#+description: \n#+hugo_base_dir: ..\n#+hugo_section: posts\n#+hugo_categories: other\n#+property: header-args :exports both\n#+hugo_tags: \n%?" :if-new (file+head "%<%Y-%m-%d_%H-%M-%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("p" "programming" plain "#+author: %n\n#+date: %t\n#+description: \n#+hugo_base_dir: ..\n#+hugo_section: posts\n#+hugo_categories: programming\n#+property: header-args :exports both\n#+hugo_tags: \n%?" :if-new (file+head "%<%Y-%m-%d_%H-%M-%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("t" "tech" plain "#+author: %n\n#+date: %t\n#+description: \n#+hugo_base_dir: ..\n#+hugo_section: posts\n#+hugo_categories: tech\n#+property: header-args :exports both\n#+hugo_tags: \n%?" :if-new (file+head "%<%Y-%m-%d_%H-%M-%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t))) (org-roam-capture-ref-templates '(("r" "ref" plain "#+author: %n\n#+date: %t\n#+description: \n#+hugo_base_dir: ..\n#+hugo_section: posts\n#+hugo_categories: reference\n#+property: header-args :exports both\n#+hugo_tags: \n%?\n* Links\n- %l" :target (file+head "${slug}.org" "#+title: ${title}") :unnarrowed t))) :config (org-roam-setup) (org-roam-db-autosync-mode) (require 'org-roam-protocol) (with-eval-after-load 'evil-collection (evil-collection-org-roam-setup)) (with-eval-after-load 'evil (evil-define-key* nil my/open-roam-map "a" '("add alias" . org-roam-alias-add) "c" '("roam capture" . org-roam-capture) "f" '("find roam node" . org-roam-node-find) "i" '("insert roam node at point" . org-roam-node-insert) "l" '("toggle roam buffer" . org-roam-buffer-toggle) "r" '("remove alias" . org-roam-alias-remove))))
To be fair, this package is very powerful, but for me, at least, not all its feature is needed. I'll try to start simple, and make additional configuration as needed.
- org-roam-protocol
This is from the orgroam-manual.
[Desktop Entry] Name=Org-Protocol Exec=emacsclient %u Icon=emacs-icon Type=Application Terminal=false MimeType=x-scheme-handler/org-protocol
org-roam-ui external
(use-package org-roam-ui :ensure t :after org-roam ;; or :after org ;; normally we'd recommend hooking orui after org-roam, but since org-roam does not have ;; a hookable mode anymore, you're advised to pick something yourself ;; if you don't care about startup time, use ;; :hook (after-init . org-roam-ui-mode) :config (setopt org-roam-ui-sync-theme t org-roam-ui-follow t org-roam-ui-update-on-save t org-roam-ui-open-on-start t))
org-protocol-capture-html external
Requires pandoc
(use-package org-protocol-capture-html :load-path "site-lisp/org-protocol-capture-html" :after org :config (add-to-list 'org-capture-templates `("w" "Web site" entry (file+headline ,(expand-file-name "links.org" org-directory) "Links") "** %a :website:\n\n:PROPERTIES:\n:CREATED: %U\n:END:\n %?\n\n%:initial")))
pdf-tools external
(use-package pdf-tools :ensure t :config (pdf-tools-install) (setq-default pdf-view-display-size 'fit-width) (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward) :custom (pdf-annot-activate-created-annotations t "automatically annotate highlights"))
Tools
server builtin
(use-package server :ensure nil :config (unless (server-running-p) (server-start)) (require 'org-protocol))
magit external
(use-package magit :ensure t :demand t :config (evil-collection-magit-repos-setup) (evil-collection-magit-section-setup) (evil-collection-magit-setup) (evil-set-initial-state #'git-commit-mode 'insert) (evil-define-key* nil my/g-map "g" '("git status" . magit-status)) :custom (magit-revision-show-gravatars '("^Author: " . "^Commit: ")) (magit-diff-refine-hunk 'all) (magit-log-arguments '("-n100" "--graph" "--decorate")))
pass external
(use-package password-store :ensure t :demand t :config (setopt password-store-password-length 12) (setopt auth-sources '(password-store "~/.authinfo.gpg" "~/.netrc"))) (use-package password-store-otp :ensure t :defer t :after password-store) (use-package pass :ensure t :defer t :config (with-eval-after-load 'evil-collection (evil-collection-pass-setup))) (use-package auth-source-pass :ensure nil :init (auth-source-pass-enable))
Elpaca complains about different of pass version installed. But it installed just fine.
pinentry external
(use-package pinentry :ensure t :defer t :config (pinentry-start))
fzf external
(use-package fzf :if (executable-find "fzf") :ensure t :config (setopt my/fzf-map (make-sparse-keymap)) (evil-define-key* nil my/file-map (kbd "z") (cons "fzf" my/fzf-map)) (evil-define-key* nil my/fzf-map "b" '("fzf find in buffer" . fzf-find-in-buffer) "f" '("fzf" . fzf-find-file) "d" '("fzf dir" . fzf-directory) "r" '("fzf recentf" . fzf-recentf)) (evil-define-key* nil my/search-map "z" '("fzf-grep" . fzf-grep)) (evil-define-key* nil my/buffer-map "z" '("fzf switch buffer" . fzf-switch-buffer)) (evil-define-key* nil projectile-command-map "z" '("fzf projectile" . fzf-projectile)) (setopt fzf/args "-x --color dark --print-query --margin=1,0 --no-hscroll" fzf/executable "fzf" fzf/git-grep-args "-i --line-number %s" ;; command used for `fzf-grep-*` functions ;; example usage for ripgrep: ;; fzf/grep-command "rg --no-heading -nH" fzf/grep-command "rg --no-heading -nH" ;; If nil, the fzf buffer will appear at the top of the window fzf/position-bottom t fzf/window-height 15))
rg external
Packaged as ripgrep in archlinux. The :if keyword won't load this if the executable not found.
(use-package rg :ensure t :if (executable-find "rg") :defer t :config (evil-collection-rg-setup))
ox-hugo external
Blogging tools
(use-package ox-hugo :ensure t :if (executable-find "hugo") :after ox)
- org-capture template for blog
(defun my/create-blog-capture-file () "Create a subdirectory and `org-mode' file under `+config/blog-directory'." (interactive) (let* ((name (read-string "slug: ")) (content-dir (expand-file-name "content-org/" +config/blog-directory))) (unless (file-directory-p (expand-file-name name content-dir)) (make-directory (expand-file-name name content-dir))) (expand-file-name (concat name ".org") (expand-file-name name content-dir)))) (add-to-list 'org-capture-templates '("h" "Hugo Post" plain (file my/create-blog-capture-file) "#+options: ':nil -:nil ^:nil num:nil toc:nil #+author: %n #+title: %^{Title} #+description: #+date: %t #+hugo_categories: %^{Categories|misc|desktop|emacs|learning} #+hugo_tags: %^{Tags} #+hugo_auto_set_lastmod: t #+hugo_section: posts #+hugo_base_dir: ../../ #+language: en #+startup: inlineimages * %?" :jump-to-captured t))
notmuch external
(use-package notmuch :if (executable-find "notmuch") :ensure t :defer t :commands (notmuch) :hook (message-setup . mml-secure-sign-pgpmime) :config (global-set-key (kbd "<XF86Mail>") 'notmuch) (setq notmuch-fcc-dirs nil notmuch-search-result-format '(("date" . "%12s ") ("count" . "%-7s ") ("authors" . "%-30s ") ("subject" . "%-72s ") ("tags" . "(%s)")) notmuch-tag-formats '(("unread" (propertize tag 'face 'notmuch-tag-unread)) ("flagged" (propertize tag 'face 'notmuch-tag-flagged) (notmuch-tag-format-image-data tag (notmuch-tag-star-icon)))) notmuch-tagging-keys '(("a" notmuch-archive-tags "Archive") ("u" notmuch-show-mark-read-tags "Mark read") ("f" ("+flagged") "Flag") ("s" ("+spam" "-inbox") "Mark as spam") ("d" ("+deleted" "-inbox") "Delete")) notmuch-saved-searches '((:name "flagged" :query "tag:flagged" :key "f") (:name "archive" :query "tag:archive" :key "i") (:name "inbox" :query "tag:inbox" :key "i") (:name "sent" :query "tag:sent" :key "s") (:name "drafts" :query "tag:draft" :key "d") (:name "all mail" :query "*" :key "a") (:name "unread" :query "tag:unread" :key "u") (:name "Today" :query "date:today AND NOT tag:spam AND NOT tag:bulk" :key "T" :search-type 'tree :sort-order 'newest-first) (:name "This Week" :query "date:weeks AND NOT tag:spam AND NOT tag:bulk" :key "W" :search-type 'tree :sort-order 'newest-first) (:name "This Month" :query "date:months AND NOT tag:spam AND NOT tag:bulk" :key "M" :search-type 'tree :sort-order 'newest-first) (:name "flagged" :query "tag:flagged AND NOT tag:spam AND NOT tag:bulk" :key "f" :search-type 'tree :sort-order 'newest-first) (:name "spam" :query "tag:spam")) notmuch-archive-tags '("-inbox" "-unread" "+archive")) (setq-default notmuch-search-oldest-first nil) (if (executable-find "gpg2") (setopt notmuch-crypto-gpg-program "gpg2") (setopt notmuch-crypto-gpg-program "gpg")) (setopt notmuch-crypto-process-mime t mml-secure-openpgp-sign-with-sender t) (define-key notmuch-show-mode-map "S" (lambda () "Mark message as spam" (interactive) (notmuch-show-tag (list +spam -new))))) (use-package notmuch-indicator :if (executable-find "notmuch") :ensure t :config (setopt notmuch-indicator-args '((:terms "tag:unread and tag:inbox" :label "U" :label-face success))) (notmuch-indicator-mode)) (use-package consult-notmuch :after consult :ensure t :if (executable-find "notmuch") :config (add-to-list 'consult-buffer-sources 'consult-notmuch-buffer-source)) (use-package ol-notmuch :ensure t :if (executable-find "notmuch")) (use-package notmuch-maildir :ensure t :if (executable-find "notmuch") :config (notmuch-maildir-inject-section)) (use-package message :ensure nil :if (executable-find "notmuch") :custom (message-directory (expand-file-name ".mail" (getenv "HOME"))) (message-sendmail-envelope-from 'header)) (use-package sendmail :ensure nil :if (executable-find "notmuch") :custom (mail-specify-envelope-from t) (mail-envelope-from 'header) (send-mail-function 'sendmail-send-it) (sendmail-program (executable-find "msmtp")))
Programming languages
display-line-numbers builtin
(use-package display-line-numbers :ensure nil :hook (prog-mode . display-line-numbers-mode) :config (setopt display-line-numbers-type 'relative))
lisp builtin
(use-package eldoc :ensure nil :hook ((emacs-lisp-mode lisp-interaction-mode ielm-mode) . eldoc-mode))
make-mode builtin
(use-package make-mode :ensure nil :config (add-hook 'makefile-mode-hook 'indent-tabs-mode))
executable builtin
(use-package executable :ensure nil :hook (after-save . executable-make-buffer-file-executable-if-script-p))
nix-ts-mode external
(use-package nix-ts-mode :ensure t :mode "\\.nix\\'" :config (add-hook 'nix-ts-mode-hook (lambda () (setq-local tab-width 2))))
yuck-mode external
(use-package yuck-mode :ensure t)
astro-ts-mode external
(use-package astro-ts-mode :ensure t :mode "\\.astro\\'" :hook (astro-ts-mode . lsp-deferred) :config (setq treesit-language-source-alist '((astro "https://github.com/virchau13/tree-sitter-astro"))))
Completion
Vertico external
(use-package vertico :ensure t :hook (rfn-eshadow-update-overlay . vertico-directory-tidy) :custom ;; (vertico-scroll-margin 0) ;; Different scroll margin (vertico-count 15) ;; Show more candidates (vertico-resize nil) ;; Grow and shrink the Vertico minibuffer (vertico-cycle t) ;; Enable cycling for `vertico-next/previous' :config (advice-add #'tmm-add-prompt :after #'minibuffer-hide-completions) (keymap-set vertico-map "?" #'minibuffer-completion-help) :init (vertico-mode)) ;; Emacs minibuffer configurations. (use-package emacs :custom ;; Enable context menu. `vertico-multiform-mode' adds a menu in the minibuffer ;; to switch display modes. (context-menu-mode t) ;; Support opening new minibuffers from inside existing minibuffers. (enable-recursive-minibuffers t) ;; Hide commands in M-x which do not work in the current mode. Vertico ;; commands are hidden in normal buffers. This setting is useful beyond ;; Vertico. (read-extended-command-predicate #'command-completion-default-include-p) ;; Do not allow the cursor in the minibuffer prompt (minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt)))
- Extensions
- vertico-directory
(use-package vertico-directory :after vertico :ensure nil ;; More convenient directory navigation commands :bind (:map vertico-map ("RET" . vertico-directory-enter) ("DEL" . vertico-directory-delete-char) ("M-DEL" . vertico-directory-delete-word)) ;; Tidy shadowed file names :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
- vertico-quick
(use-package vertico-quick :after vertico :ensure nil :bind (:map vertico-map ("M-q" . vertico-quick-insert) ("C-q" . vertico-quick-exit)))
- vertico-multiform
(use-package vertico-multiform :ensure nil :init (vertico-multiform-mode) :config (setopt vertico-multiform-commands `((describe-symbol (vertico-sort-function . vertico-sort-alpha)) (consult-outline buffer ,(lambda (_) (text-scale-set -1))) (org-ctrl-c-ctrl-c flat))) (defun sort-directories-first (files) (setopt files (vertico-sort-history-length-alpha files)) (nconc (seq-filter (lambda (x) (string-suffix-p "/" x)) files) (seq-remove (lambda (x) (string-suffix-p "/" x)) files))) (setopt vertico-multiform-categories '((symbol (vertico-sort-function . vertico-sort-alpha)) (file (vertico-sort-function . sort-directories-first)))))
- vertico-directory
orderless external
(use-package orderless :ensure t :init ;; Configure a custom style dispatcher (see the Consult wiki) ;; (setopt orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-dispatch) ;; orderless-component-separator #'orderless-escapable-split-on-space) (setopt completion-styles '(orderless basic substring partial-completion) completion-category-defaults nil completion-category-overrides '((file (styles orderless partial-completion))) orderless-component-separator #'orderless-escapable-split-on-space) (set-face-attribute 'completions-first-difference nil :inherit nil))
partial-completion and flex are built-ins completion-styles.
corfu external
(use-package corfu :ensure t :custom (corfu-cycle t) (corfu-auto t) (corfu-auto-delay 0.18) (corfu-auto-prefix 2) (corfu-quit-no-match 'separator) (corfu-preselect 'prompt) (corfu-count 16) (corfu-max-width 120) (corfu-on-exact-match nil) (corfu-quit-no-match corfu-quit-at-boundary) (completion-cycle-threshold 3) (text-mode-ispell-word-completion nil) :hook (lsp-completion-mode . my/lsp-mode-setup-completion) :init (defun my/orderless-dispatch-flex-first (_pattern index _total) (and (eq index 0) 'orderless-flex)) (defun my/lsp-mode-setup-completion () (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults)) '(orderless)) ;; Optionally configure the first word as flex filtered. (add-hook 'orderless-style-dispatchers #'my/orderless-dispatch-flex-first nil 'local) ;; Optionally configure the cape-capf-buster. (setq-local completion-at-point-functions (list (cape-capf-buster #'lsp-completion-at-point)))) :config (add-to-list 'completion-category-overrides `(lsp-capf (styles ,@completion-styles))) ;;(add-to-list 'corfu-auto-commands #'lispy-colon) (add-hook 'evil-insert-state-exit-hook #'corfu-quit) (with-eval-after-load 'exwm (advice-add #'corfu--make-frame :around (defun +corfu--make-frame-a (oldfun &rest args) (cl-letf (((symbol-function #'frame-parent) (lambda (frame) (or (frame-parameter frame 'parent-frame) exwm-workspace--current)))) (apply oldfun args)) (when exwm--connection (set-frame-parameter corfu--frame 'parent-frame nil)))) (advice-add #'corfu--popup-redirect-focus :override (defun +corfu--popup-redirect-focus-a () (redirect-frame-focus corfu--frame (or (frame-parent corfu--frame) exwm-workspace--current))))) (defun corfu-enable-always-in-minibuffer () "Enable Corfu in the minibuffer if Vertico/Mct are not active." (unless (or (bound-and-true-p mct--active) (bound-and-true-p vertico--input) (eq (current-local-map) read-passwd-map)) ;; (setq-local corfu-auto nil) ;; Enable/disable auto completion (setq-local corfu-echo-delay nil ;; Disable automatic echo and popup corfu-popupinfo-delay nil) (corfu-mode 1))) (add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1) :init (global-corfu-mode))
This is the basic configuration, with the addition of enabling corfu in the minibuffer.
- corfu-history external
(use-package corfu-history :ensure nil :hook ((corfu-mode . corfu-history-mode)) :config (with-eval-after-load 'savehist (add-to-list 'savehist-additional-variables 'corfu-history)))
- corfu-popupinfo external
(use-package corfu-popupinfo :ensure nil :hook ((corfu-mode . corfu-popupinfo-mode)) :config (setopt corfu-popupinfo-delay '(0.5 . 1.0)) (setopt corfu-popupinfo-hide nil))
consult external
- consult main package
(use-package consult :ensure t :demand t :hook (completion-list-mode . consult-preview-at-point-mode) :init ;; Optionally configure the register formatting. This improves the register ;; preview for `consult-register', `consult-register-load', ;; `consult-register-store' and the Emacs built-ins. (setopt register-preview-delay 0.5 register-preview-function #'consult-register-format) ;; Optionally tweak the register preview window. ;; This adds thin lines, sorting and hides the mode line of the window. (advice-add #'register-preview :override #'consult-register-window) ;; Use Consult to select xref locations with preview (setopt xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref) ;; Configure other variables and modes in the :config section, ;; after lazily loading the package. :config ;; Optionally configure preview. The default value ;; is 'any, such that any key triggers the preview. ;; (setopt consult-preview-key 'any) ;; (setopt consult-preview-key "M-.") ;; (setopt consult-preview-key '("S-<down>" "S-<up>")) ;; For some commands and buffer sources it is useful to configure the ;; :preview-key on a per-command basis using the `consult-customize' macro. (consult-customize consult-theme :preview-key '(:debounce 0.2 any) consult-ripgrep consult-git-grep consult-grep consult-bookmark consult-recent-file consult-xref consult--source-bookmark consult--source-file-register consult--source-recent-file consult--source-project-recent-file ;; :preview-key "M-." :preview-key '(:debounce 0.4 any)) ;; Optionally configure the narrowing key. ;; Both < and C-+ work reasonably well. (setopt consult-narrow-key "<") ;; "C-+" ;; Optionally make narrowing help available in the minibuffer. ;; You may want to use `embark-prefix-help-command' or which-key instead. ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help) ;; By default `consult-project-function' uses `project-root' from project.el. ;; Optionally configure a different project root function. ;;;; 1. project.el (the default) ;;(setopt consult-project-function #'consult--default-project--function) ;;;; 2. vc.el (vc-root-dir) ;; (setopt consult-project-function (lambda (_) (vc-root-dir))) ;;;; 3. locate-dominating-file ;; (setopt consult-project-function (lambda (_) (locate-dominating-file "." ".git"))) ;;;; 4. projectile.el (projectile-project-root) (with-eval-after-load 'projectile (autoload 'projectile-project-root "projectile") (setopt consult-project-function (lambda (_) (projectile-project-root)))) ;;;; 5. No project support ;; (setopt consult-project-function nil)) (setopt consult-line-numbers-widen t consult-async-min-input 2 consult-async-refresh-delay 0.15 consult-async-input-throttle 0.2 consult-async-input-debounce 0.1) (with-eval-after-load 'evil (evil-define-key* '(normal visual) 'global (kbd "<leader>.") '("Store register" . consult-register-store) (kbd "<leader> C-.") '("Load register" . consult-register-load)) (evil-define-key* nil my/file-map "r" '("recent files" . consult-recent-file)) (evil-define-key* nil my/buffer-map "b" '("buffers" . consult-buffer) "B" '("project buffers" . consult-project-buffer)) (evil-define-key* nil my/open-map "O" '("Open agenda files" . consult-org-agenda)) (with-eval-after-load 'org (evil-define-key* nil my/org-mode-map "O" '("search heading" . consult-org-heading))) (evil-define-key* nil my/search-map "a" '("grep search" . consult-grep) "b" '("search bookmarks" . consult-bookmark) "B" '("search global mark" . consult-global-mark) "d" '("search directory" . consult-dir) "f" '("consult find" . consult-find) "F" '("focus line" . consult-focus-line) "h" '("isearch history" . consult-isearch-history) "m" '("search mark" . consult-mark) "i" '("imenu" . consult-imenu) "o" '("search outline" . consult-outline) "s" '("search line" . consult-line) "S" '("search multi line" . consult-line-multi) "\"" '("search register" . consult-register)) (evil-define-key* '(normal visual) 'global (kbd "M-y") 'consult-yank-pop) (with-eval-after-load 'consult-notmuch (evil-define-key* nil my/search-map "M" '("search mail" . consult-notmuch))) (cond ((executable-find "fd") (evil-define-key* nil my/search-map "A" '("fd search" . consult-fd))) (t (evil-define-key* nil my/search-map "A" '("find search" . consult-find)))) (when (executable-find "rg") (evil-define-key* nil my/search-map "r" '("search ripgrep" . consult-ripgrep)))) (keymap-set isearch-mode-map "M-e" #'consult-isearch-history) (keymap-set isearch-mode-map "M-l" #'consult-line) (keymap-set isearch-mode-map "M-L" #'consult-line-multi) (keymap-set minibuffer-local-map "M-s" #'consult-history) (keymap-set minibuffer-local-map "M-r" #'consult-history) (global-set-key [remap Info-search] 'consult-info) (global-set-key [remap yank-pop] 'consult-yank-pop) (global-set-key [remap bookmark-jump] 'consult-bookmark) (global-set-key [remap evil-show-marks] 'consult-mark) (global-set-key [remap evil-show-registers] 'consult-register) (global-set-key [remap goto-line] 'consult-goto-line) (global-set-key [remap imenu] 'consult-imenu) (global-set-key [remap locate] 'consult-locate) (global-set-key [remap load-theme] 'consult-theme) (global-set-key [remap man] 'consult-man) (global-set-key [remap recentf-open-files] 'consult-recent-file) (global-set-key [remap switch-to-buffer] 'consult-buffer) (global-set-key [remap switch-to-buffer-other-frame] 'consult-buffer-other-frame) (global-set-key [remap switch-to-buffer-other-window] 'consult-buffer-other-window))
Apart from the
consult-projectile-function, this is pretty much the default. - consult-dir
(use-package consult-dir :ensure t :bind (:map vertico-map ("C-x C-d" . consult-dir) ("C-x C-j" . consult-dir-jump-file)))
embark external
(use-package embark :ensure t :defer t :bind (("C-." . embark-act) ;; pick some comfortable binding ("C-;" . embark-dwim) ;; good alternative: M-. ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings' :init ;; Optionally replace the key help with a completing-read interface (setopt prefix-help-command #'embark-prefix-help-command) ;; Show the Embark target at point via Eldoc. You may adjust the ;; Eldoc strategy, if you want to see the documentation from ;; multiple providers. Beware that using this can be a little ;; jarring since the message shown in the minibuffer can be more ;; than one line, causing the modeline to move up and down: ;; (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target) ;; (setopt eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly) :config (global-set-key (kbd "C-.") #'embark-act) (global-set-key (kbd "C-;") #'embark-dwim) (global-set-key (kbd "C-h b") #'embark-bindings) (evil-collection-embark-setup) (evil-define-key nil my/a-map (kbd ";") '("Embark DWIM" . embark-dwim) (kbd "a") '("Embark Act" . embark-act)) (setopt which-key-use-C-h-commands nil prefix-help-command #'embark-prefix-help-command) ;; Hide the mode line of the Embark live/completions buffers (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none)))))
This is a package that I should learn more, but the configuration is overwhealming.
embark-consult external
(use-package embark-consult :ensure t :hook (embark-collect-mode . consult-preview-at-point-mode))
consult integration for embark.
cape external
(use-package cape :ensure t ;; Bind dedicated completion commands ;; Alternative prefix keys: C-c p, M-p, M-+, ... :bind (("C-c p p" . completion-at-point) ;; capf ("C-c p t" . complete-tag) ;; etags ("C-c p d" . cape-dabbrev)) ;; or dabbrev-completion :hook (prog-mode . +corfu-add-cape-file-h) ((org-mode markdown-mode) . +corfu-add-cape-elisp-block-h) :init ;; Add to the global default value of `completion-at-point-functions' which is ;; used by `completion-at-point'. The order of the functions matters, the ;; first function returning a result wins. Note that the list of buffer-local ;; completion functions takes precedence over the global list. (add-hook 'completion-at-point-functions #'cape-dabbrev) (add-hook 'completion-at-point-functions #'cape-file) (add-hook 'completion-at-point-functions #'cape-elisp-block) :config (setopt cape-dabbrev-check-other-buffers t) (defun +corfu-add-cape-file-h () (add-hook 'completion-at-point-functions #'cape-file -10 t)) (defun +corfu-add-cape-elisp-block-h () (add-hook 'completion-at-point-functions #'cape-elisp-block 0 t)) (with-eval-after-load 'lsp-mode (advice-add #'lsp-completion-at-point :around #'cape-wrap-noninterruptible) (advice-add #'lsp-completion-at-point :around #'cape-wrap-nonexclusive)) (advice-add #'comint-completion-at-point :around #'cape-wrap-nonexclusive) (advice-add #'pcomplete-completions-at-point :around #'cape-wrap-nonexclusive) ;; From the `cape' readme. Without this, Eshell autocompletion is broken on ;; Emacs28. (when (< emacs-major-version 29) (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent) (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify)))
kind-icon external
(use-package kind-icon :if (display-graphic-p) :ensure t :after corfu :config (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
Dired
all-the-icons-dired external
(use-package all-the-icons-dired :ensure t :hook (dired-mode . all-the-icons-dired-mode))
minimal Emacs
minimal-init.el
This file is intended to be used on a remote system, so configuration should only exists on this one file only. No external packages, the sole purpose is to edit files.
(add-to-list 'default-frame-alist '(menu-bar-lines . 0)) (add-to-list 'initial-frame-alist '(menu-bar-lines . 0)) (add-to-list 'initial-frame-alist '(tool-bar-lines . 0)) (add-to-list 'default-frame-alist '(tool-bar-lines . 0)) (add-to-list 'initial-frame-alist '(vertical-scroll-bars)) (add-to-list 'default-frame-alist '(vertical-scroll-bars)) (add-to-list 'initial-frame-alist '(fullscreen . maximized)) (add-to-list 'default-frame-alist '(fullscreen . maximized)) (setopt user-mail-address "alexforsale@yahoo.com" user-full-name "Kristian Alexander P") (use-package repeat :ensure nil :init (repeat-mode +1)) (use-package files :ensure nil :config (nconc auto-mode-alist '(("/LICENSE\\'" . text-mode) ("\\.log\\'" . text-mode) ("rc\\'" . conf-mode) ("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode))) :hook ((prog-mode text-mode) . auto-save-visited-mode) :custom (auto-save-visited-interval 10) (find-file-suppress-same-file-warnings t) ;;(confirm-kill-emacs #'yes-or-no-p) ; confirm when exiting (confirm-kill-processes nil) ; don't confirm killing processes (revert-without-query (list ".")) (find-file-visit-truename t) ; `find-file' will visit the actual file (make-backup-files nil) (version-control t) (backup-by-copying t) (delete-old-versions t) (kept-new-versions 6) (kept-old-versions 2) (auto-save-include-big-deletions t) (auto-save-list-file-prefix (expand-file-name ".autosave/" user-emacs-directory)) (backup-directory-alist `(("." . ,(expand-file-name ".backup" user-emacs-directory)))) (auto-mode-case-fold nil) (require-final-newline t)) (use-package savehist :init (savehist-mode 1) :custom (savehist-file (expand-file-name "history" user-emacs-directory)) (savehist-save-minibuffer-history t) (savehist-autosave-interval nil) (savehist-coding-system 'utf-8) (savehist-additional-variables '(evil-jumps-history command-history kill-ring register-alist mark-ring global-mark-ring search-ring regexp-search-ring))) (use-package comint :ensure nil :config (setopt comint-prompt-read-only t comint-buffer-maximum-size 2048) (evil-define-key* '(normal visual) comint-mode-map "q" '(lambda () (interactive) (kill-buffer nil)))) (use-package font-core :ensure nil :init (global-font-lock-mode t)) (use-package winner :ensure nil :init (winner-mode +1) :config (setopt winner-boring-buffers '("*Completions*" "*Compile-Log*" "*inferior-lisp*" "*Fuzzy Completions*" "*Apropos*" "*Help*" "*cvs*" "*Buffer List*" "*Ibuffer*" "*esh command on file*"))) (use-package window :ensure nil :config (setopt split-width-threshold 160 split-height-threshold nil)) (use-package saveplace :init (save-place-mode 1) :custom (save-place-file (expand-file-name "places" user-emacs-directory))) (use-package recentf :bind ("C-c f" . recentf) :commands recentf-open-files :init (recentf-mode 1) :custom (recentf-auto-cleanup t) (recentf-max-saved-items 250) (recentf-max-menu-items 300) (recentf-exclude `("/elpa/" ;; ignore all files in elpa directory "recentf" ;; remove the recentf load file ".*?autoloads.el$" "treemacs-persist" "company-statistics-cache.el" ;; ignore company cache file "/intero/" ;; ignore script files generated by intero "/journal/" ;; ignore daily journal files ".gitignore" ;; ignore `.gitignore' files in projects "/tmp/" ;; ignore temporary files "NEWS" ;; don't include the NEWS file for recentf "bookmarks" "bmk-bmenu" ;; ignore bookmarks file in .emacs.d "loaddefs.el" "^/\\(?:ssh\\|su\\|sudo\\)?:" ;; ignore tramp/ssh files (concat "^" (regexp-quote (or (getenv "XDG_RUNTIME_DIR") "/run")))))) (use-package autorevert :hook (focus-in . doom-auto-revert-buffers-h) :hook (after-save . doom-auto-revert-buffers-h) :hook (prog-mode . doom-auto-revert-buffer-h) :custom (auto-revert-interval 60) (auto-revert-use-notify nil) (global-auto-revert-non-file-buffers t) (auto-revert-verbose t) (auto-revert-stop-on-user-input nil) (revert-without-query (list ".")) :config (defun doom-visible-buffer-p (buf) "Return non-nil if BUF is visible." "Return non-nil if BUF is not visible." (not (doom-visible-buffer-p buf))) (defun doom-visible-buffers (&optional buffer-list all-frames) "Return a list of visible buffers (i.e. not buried)." (let ((buffers (delete-dups (cl-loop for frame in (if all-frames (visible-frame-list) (list (selected-frame))) if (window-list frame) nconc (mapcar #'window-buffer it))))) (if buffer-list (cl-delete-if (lambda (b) (memq b buffer-list)) buffers) (delete-dups buffers)))) (defun doom-auto-revert-buffer-h () "Auto revert current buffer, if necessary." (unless (or auto-revert-mode (active-minibuffer-window)) (let ((auto-revert-mode t)) (auto-revert-handler)))) (defun doom-auto-revert-buffers-h () "Auto revert stale buffers in visible windows, if necessary." (dolist (buf (doom-visible-buffers)) (with-current-buffer buf (doom-auto-revert-buffer-h))))) (use-package mouse :ensure nil :config (setopt mouse-yank-at-point t)) (use-package subword :ensure nil :init (global-subword-mode 1)) (use-package text-mode :ensure nil :hook (((text-mode prog-mode) . visual-line-mode) (prog-mode . (lambda () (setq-local sentence-end-double-space t)))) :config (setq-default sentence-end-double-space nil) (setopt sentence-end-without-period nil) (setopt colon-double-space nil) (setopt adaptive-fill-mode t)) (use-package select :ensure nil :custom (select-enable-clipboard t)) (use-package executable :ensure nil :hook (after-save . executable-make-buffer-file-executable-if-script-p))
