alexforsale's literate Emacs configuration

Table of Contents

This repository is my personal Emacs configuration. In case you don't know what Emacs is, I won't be the one explaining. To me Emacs is crucial and should exists in all of my machines, including the proprietary ones. In fact, this repository is the first one that I clone into my new machines (with my dotfiles being the second one).

The Goal

I used to blindly copying and pasting every snippets of Emacs configuration I found over the internet. The result usually is me having to mix and match them into one configuration, which is fine until it broke, and I start from scratch again and the cycle repeats.

Keep it simple

If the default configuration for a certain package is enough, don't add more.

Reproducible

This configuration should be usable in many systems.

This configuration is for me, not for anyone else

It's good if anyone who stumble into this repository find it useful, but the priority is to make it useful for me now. I'm trying to stop adding configuration that someday would be useful.

Editor first, IDE second

I'm not a programmer, I use Emacs mainly for editing files, tasks management, note-taking.

Documented

  • List every external packages needed for this configuration

Mnemonic keybindings

Try setting a sensible keybindings, especially for external packages. Don't mess with the default keybindings if possible.

Use org-mode

This way I don't have to separate each configurations into a separate modules.

  • Use noweb1

    I also learned that tangling too many codeblocks took a while. Now I use noweb, the output will only be one file config.el.

  • init.el and config.el

    init.el is for the essential configurations, everything else goes to config.el.

Try to minimize the use of external packages

More dependencies means more bloats, avoid it when possible.

  • External packages I can't live without

Evil

evil   external

Mostly copied from doom or the official documentation2.

 1: (use-package evil
 2:   :ensure t
 3:   :demand t
 4:   :preface
 5:   (customize-set-variable 'evil-want-keybinding nil)
 6:   (customize-set-variable 'evil-want-integration t)
 7:   (customize-set-variable 'evil-undo-system 'undo-redo)
 8:   (customize-set-variable 'evil-want-C-i-jump nil) ;; fix TAB in terminal org-mode 
 9:   (customize-set-variable 'evil-want-C-u-scroll t) ;; move universal arg to <leader> u
10:   (customize-set-variable 'evil-want-C-u-delete t) ;; delete back to indentation in insert state
11:   (customize-set-variable 'evil-want-C-g-bindings t)
12:   :custom
13:   (evil-undo-system #'undo-redo)
14:   (evil-search-module 'evil-search)
15:   (evil-ex-search-vim-style-regexp t)
16:   (evil-ex-interactive-search-highlight 'selected-window)
17:   (evil-kbd-macro-suppress-motion-error t)
18:   (evil-visual-update-x-selection-p nil)
19:   :config
20:   (setq evil-normal-state-cursor 'box
21:         evil-insert-state-cursor 'bar
22:         evil-visual-state-cursor 'hollow)
23:   (evil-select-search-module 'evil-search-module 'evil-search)
24:   (evil-mode 1)
25:   (with-eval-after-load 'eldoc
26:     (eldoc-add-command 'evil-normal-state
27:                        'evil-insert
28:                        'evil-change
29:                        'evil-delete
30:                        'evil-replace)))

evil-collection   external

For parts of Emacs not covered by Evil3.

1: (use-package evil-collection
2:   :ensure t
3:   :after evil
4:   :init
5:   (evil-collection-init)
6:   :custom
7:   (evil-collection-setup-minibuffer t)
8:   (evil-collection-calendar-want-org-bindings t))

Variables and helper functions

Identity

1: (setq user-mail-address "alexforsale@yahoo.com"
2:       user-full-name "Kristian Alexander P")

+config/user-modules-directory

This variable is needed in order for Emacs to locate this configuration files.

1: (defvar +config/user-modules-directory (expand-file-name "modules/" user-emacs-directory)
2:   "User modules directory.")

add module directory to load-path

1: (when (file-directory-p +config/user-modules-directory)
2:   (add-to-list 'load-path +config/user-modules-directory))

merge-list-to-list function

This function is just a wrapper to easily merge lists.

1: ;;; From https://emacs.stackexchange.com/questions/38008/adding-many-items-to-a-list/68048#68048
2: (defun merge-list-to-list (dst src)
3:   "Merges content of the 2nd list with the 1st one"
4:   (set dst
5:        (append (eval dst) src)))

define +config/org-directory variable

1: (when (file-directory-p (expand-file-name "Sync/org" (getenv "HOME")))
2:   (customize-set-variable '+config/org-directory (expand-file-name "Sync/org" (getenv "HOME"))))

Keybindings

general.el

Keybindings in Emacs is always been my struggle, my brain isn't big enough to memorize all the default keybindings (though over the years my fingers started to memorize some of them). At first I started using hydra, it's a wonderful package for customized keybindings. But configuring them feels like a chore, considering I'm still working my way on finding my own comfort in keybindings.

 1: (use-package general
 2:   :ensure t
 3:   :init
 4:   (general-evil-setup t)
 5:   (general-auto-unbind-keys)
 6:   :config
 7:   (general-override-mode)
 8:   (general-create-definer +config/leader-key
 9:     :keymaps 'override
10:     :states  '(insert emacs normal hybrid motion visual operator)
11:     :prefix "SPC"
12:     :non-normal-prefix "C-c SPC")
13:   (general-create-definer +config/local-leader
14:     :keymaps 'override
15:     :states '(emacs normal hybrid motion visual operator)
16:     :prefix "SPC m"
17:     :non-normal-prefix "C-c SPC m"
18:     "" '(:ignore t :which-key (lambda (arg) `(,(cadr (split-string (car arg) " ")) . ,(replace-regexp-in-string "-mode$" "" (symbol-name major-mode))))))
19:   ;; useful macro
20:   (defmacro +config/leader-menu! (name infix-key &rest body)
21:     "Create a definer NAME `+config/leader-NAME' wrapping `+config/leader-key'.
22:       Create prefix map: `+config/leader-NAME-map'. Prefix bindings in BODY with INFIX-KEY."
23:     (declare (indent 2))
24:     `(progn
25:        (general-create-definer ,(intern (concat "+config/leader-" name))
26:          :wrapping +config/leader-key
27:          :prefix-map (quote ,(intern (concat "+config/leader-" name "-map")))
28:          :infix ,infix-key
29:          :wk-full-keys nil
30:          "" '(:ignore t :which-key ,name))
31:        (,(intern (concat "+config/leader-" name))
32:         ,@body))))

What I'm doing before is setting the general keybindings inside their respective use-package declarations. So in org-roam, I set a general keybinding. The problem with this is, if the package is deferred (with the keyword :defer t), the keybindings won't show. I prefer to have the keybindings inside the use-package declaration, this way if I decided not to use the package(s), their custom keybindings will also be removed. The other way for this is to use the :demand t keyword, with the down side of having a longer initialization time.

Packages keybindings

  • First level menu
     1: ;; First level menu
     2: (+config/leader-menu! "activities" "C-a")
     3: (+config/leader-menu! "buffer" "b")
     4: (+config/leader-menu! "files" "f")
     5: (+config/leader-menu! "find" "gf")
     6: (+config/leader-menu! "go" "g")
     7: (+config/leader-menu! "insert" "i")
     8: (+config/leader-menu! "mail" "M-m")
     9: (+config/leader-menu! "mark" "m")
    10: (+config/leader-menu! "notes" "n")
    11: (+config/leader-menu! "open" "o")
    12: (+config/leader-menu! "quit" "q")
    13: (+config/leader-menu! "register" "gr")
    14: (+config/leader-menu! "tree" "t")
    15: (+config/leader-menu! "tab" "t TAB")
    16: (+config/leader-menu! "vterm" "tv")
    17: (+config/leader-menu! "window" "w")
    
  • First level keybinding
    1: ;; keybindings
    2: (+config/leader-key
    3:   ";" 'pp-eval-expression
    4:   ":" 'execute-extended-command
    5:   "^" '(subword-capitalize :wk "Capitalize subword")
    6:   "u" 'universal-argument)
    
  • buffer
     1: ;; buffer
     2: (+config/leader-buffer
     3:   "[" '(previous-buffer :wk "previous buffer")
     4:   "]" '(next-buffer :wk "next buffer")
     5:   "TAB" '((lambda () (interactive) (switch-to-buffer nil)) :wk "other-buffer")
     6:   "b" '(switch-to-buffer :wk "switch to buffer")
     7:   "s" '(basic-save-buffer :wk "save buffer")
     8:   "c" '(clone-indirect-buffer :wk "clone buffer")
     9:   "C" '(clone-indirect-buffer-other-window :wk "clone buffer other window")
    10:   "d" '(kill-current-buffer :wk "kill current buffer")
    11:   "i" 'ibuffer
    12:   "k" '(kill-buffer :wk "kill buffer")
    13:   "l" '(evil-switch-to-windows-last-buffer :wk "Switch to last open buffer")
    14:   "m" '((lambda () (interactive) (switch-to-buffer "*Messages*")) :wk "switch to messages buffer")
    15:   "n" '(next-buffer :wk "next buffer")
    16:   "N" '(evil-buffer-new :wk "New unnamed buffer")
    17:   "p" '(previous-buffer :wk "previous buffer")
    18:   "o" '((lambda () (interactive) (switch-to-buffer nil)) :wk "other-buffer")
    19:   "r" '(revert-buffer-quick :wk "revert buffer")
    20:   "R" '(rename-buffer :wk "rename buffer")
    21:   "x" '((lambda () (interactive) (switch-to-buffer "*scratch*")) :wk "switch to scratch buffer")
    22:   "z" '(bury-buffer :wk "bury buffer"))
    
  • Editing
    • smartparens
       1: (with-eval-after-load 'smartparens
       2:   (general-nvmap
       3:    :keymaps 'smartparens-mode-map
       4:    "<" 'sp-backward-barf-sexp
       5:    "C-<" 'sp-backward-slurp-sexp
       6:    ">" 'sp-forward-slurp-sexp
       7:    "C->" 'sp-forward-barf-sexp)
       8:   (general-define-key
       9:    :keymaps 'smartparens-mode-map
      10:    "M-DEL" 'sp-unwrap-sexp))
      
  • dired
     1: (general-nvmap
     2:   'dired-mode-map
     3:   "g$" 'dired-hide-subdir
     4:   "g?" 'dired-summary
     5:   "gG" 'dired-do-chgrp
     6:   "gj" 'dired-next-dirline
     7:   "gk" 'dired-prev-dirline
     8:   "go" 'dired-view-file
     9:   "gO" 'dired-find-file-other-window
    10:   "gy" 'dired-show-file-type)
    
  • files
     1: ;; files
     2: (+config/leader-files
     3:   "D" 'dired
     4:   "d" 'dired-jump
     5:   "f" '(find-file :wk "find file")
     6:   "F" '(find-file-other-frame :wk "find file other frame")
     7:   "k" 'delete-frame
     8:   "r" 'recentf
     9:   "S" '(write-file :wk "save file")
    10:   "s" '(save-buffer :wk "save buffer")
    11:   "w" '(find-file-other-window :wk "find file other window"))
    
  • find
    1: ;; find
    2: (+config/leader-find
    3:   "g" 'grep
    4:   "r" '(rgrep :wk "recursive grep"))
    
  • help
    1: ;; help
    2: (+config/leader-key
    3:   "h" (general-simulate-key "C-h"
    4:         :state '(normal visual)
    5:         :name general-SPC-h-simulates-C-h
    6:         :docstring "Simulates C-h in normal and visual mode."
    7:         :which-key "Help"))
    
  • insert
    1: ;; insert
    2: (+config/leader-insert
    3:   "u" '(insert-char :wk "insert character"))
    
  • mark
     1: ;; mark
     2: (+config/leader-mark
     3:   "m" '(bookmark-set :wk "set bookmark")
     4:   "b" '(bookmark-jump :wk "jump to bookmark")
     5:   "B" '(bookmark-jump-other-window :wk "jump to bookmark other window")
     6:   "C-c b" '(bookmark-jump-other-frame :wk "jump to bookmark other frame")
     7:   "c" '(consult-bookmark :wk "consult bookmark") ;; require `consult' package
     8:   "l" '(bookmark-bmenu-list :wk "list bookmarks")
     9:   "L" '(bookmark-load :wk "load bookmark")
    10:   "d" '(bookmark-delete :wk "delete bookmark")
    11:   "D" '(bookmark-delete-all :wk "delete all bookmarks")
    12:   "s" '(bookmark-save :wk "save bookmark")
    13:   "r" '(bookmark-rename :wk "rename bookmark"))
    
  • open
    1: ;; open
    2: (+config/leader-open
    3:   "i" '((lambda () (interactive) (find-file user-init-file)) :wk "open Emacs configuration file"))
    
  • org-mode
     1: (general-define-key
     2:  :keymaps 'override
     3:  "C-c l" '(org-store-link :wk "Store link")
     4:  "C-c a" '(org-agenda :wk "Org Agenda")
     5:  "C-c c" '(org-capture :wk "Org Capture")
     6:  "C-c C-s" 'org-schedule)
     7: 
     8: (+config/leader-notes
     9:   "a" 'org-agenda
    10:   "c" 'org-capture
    11:   "C" 'org-capture-goto-last-stored
    12:   "r" 'org-refile-goto-last-stored)
    13: 
    14: ;; (+config/local-leader
    15: ;;   :major-modes 'org-mode
    16: ;;   :keymaps 'org-mode-map
    17: ;;   "a" '(:ignore t :wk "action")
    18: ;;   "s" '(:ignore t :wk "search"))
    19: 
    20: (+config/local-leader
    21:   :keymaps 'org-mode-map
    22:   "C-a" 'org-attach
    23:   "C-b" 'org-backward-heading-same-level
    24:   "C-c" 'org-ctrl-c-ctrl-c
    25:   "C-d" 'org-deadline
    26:   "C-e" 'org-export-dispatch
    27:   "C-f" 'org-forward-heading-same-level
    28:   "C-j" 'org-goto
    29:   "C-k" 'org-kill-note-or-show-branches
    30:   "C-l" 'org-insert-link
    31:   "C-n" 'org-next-visible-heading
    32:   "C-o" 'org-open-at-point
    33:   "C-p" 'org-previous-visible-heading
    34:   "C-q" 'org-set-tags-command
    35:   "C-r" 'org-fold-reveal
    36:   "C-s" 'org-schedule
    37:   "C-t" 'org-todo
    38:   "C-w" 'org-refile
    39:   "C-y" 'org-evaluate-time-range
    40:   "C-z" 'org-add-note
    41:   "M-b" 'org-previous-block
    42:   "M-f" 'org-next-block
    43:   "M-l" 'org-insert-last-stored-link
    44:   "M-w" 'org-refile-copy
    45:   "C-^" 'org-up-element
    46:   "C-_" 'org-down-element
    47:   "C-<" 'org-promote-subtree
    48:   "C->" 'org-demote-subtree
    49:   "C-," 'org-insert-structure-template
    50:   "C-*" 'org-list-make-subtree
    51:   "{" 'org-table-toggle-formula-debugger
    52:   "}" 'org-table-toggle-coordinate-overlays
    53:   "`" 'org-table-edit-field
    54:   "\\" 'org-match-sparse-tree
    55:   "^" 'org-sort
    56:   "[" 'org-agenda-file-to-front
    57:   "]" 'org-remove-file
    58:   "@" 'org-mark-subtree
    59:   "?" 'org-table-field-info
    60:   "=" 'org-table-eval-formula
    61:   ">" 'org-goto-calendar
    62:   "+" 'org-table-sum
    63:   "<" 'org-date-from-calendar
    64:   ";" 'org-toggle-comment
    65:   ":" 'org-toggle-fixed-width
    66:   "/" 'org-sparse-tree
    67:   "," 'org-priority
    68:   "." 'org-timestamp
    69:   "*" 'org-ctrl-c-star
    70:   "-" 'org-ctrl-c-minus
    71:   "#" 'org-update-statistics-cookies
    72:   "$" 'org-archive-subtree
    73:   "%" 'org-mark-ring-push
    74:   "'" 'org-edit-special
    75:   "TAB" '(org-clock-in :wk "clock-in")
    76:   "!" '(org-reload :wk "reload org")
    77:   "[" '(org-mark-ring-goto :wk "Jump to previous position in the mark ring")
    78:   "b" '(:ignore t :wk "buffer")
    79:   "bs" '(org-save-all-org-buffers :wk "save all org buffer")
    80:   "f" '(:ignore t :wk "files")
    81:   "fs" '(org-save-all-org-buffers :wk "save all org buffer")
    82:   "s" '(org-schedule :wk "org schedule")
    83:   "i" '(:ignore t :wk "insert")
    84:   "id" '(org-insert-drawer :wk "insert drawer")
    85:   "i@" '(org-cite-insert :wk "insert citation")
    86:   "if" '(org-footnote-action :wk "footnote")
    87:   "i C-f" '(org-emphasize :wk "insert emphasize")
    88:   "il" '(org-insert-link :wk "insert link")
    89:   "iD" '(org-deadline :wk "insert deadline")
    90:   "is" '(org-schedule :wk "insert schedule")
    91:   "ip" '(org-set-property :wk "insert property")
    92:   "it" '(org-insert-time-stamp :wk "insert time-stamp at point"))
    
  • quit
    1: ;; quit
    2: (+config/leader-quit
    3:   "q" '(save-buffers-kill-terminal :wk "quit and save")
    4:   "R" '(restart-emacs :wk "restart Emacs"))
    
  • register
     1: ;; register
     2: (+config/leader-register
     3:   ;; "#" '(consult-register :wk "consult-register") ;; require `consult' package
     4:   "+" '(increment-register :wk "augment content of register")
     5:   "C-@" '(point-to-register :wk "store current point to register")
     6:   "C-SPC" '(point-to-register :wk "store current point to register")
     7:   "M-w" '(copy-rectangle-as-kill :wk "copy region-rectangle and save")
     8:   "SPC" '(point-to-register :wk "store current point to register")
     9:   "c" '(clear-rectangle :wk "blank out region-rectangle")
    10:   "d" '(delete-rectangle :wk "delete region-rectangle")
    11:   "f" '(frameset-to-register :wk "store frameset to register")
    12:   "g" '(insert-register :wk "insert register")
    13:   "i" '(insert-register :wk "insert register")
    14:   "j" '(jump-to-register :wk "jump to register")
    15:   "k" '(kill-rectangle :wk "cut rectangle into killed-rectangle")
    16:   "l" '(bookmark-bmenu-list :wk "display existing bookmarks")
    17:   "m" '(bookmark-set :wk "set bookmark")
    18:   "M" '(bookmark-set-no-overwrite :wk "set bookmark no overwrite")
    19:   "n" '(number-to-register :wk "store a number in a register")
    20:   "N" '(rectangle-number-lines :wk "insert number in front of region-rectangle")
    21:   "o" '(open-rectangle :wk "blank out region-rectangle")
    22:   "r" '(copy-rectangle-to-register :wk "copy rectangle-region to register")
    23:   "s" '(copy-to-register :wk "copy region to register")
    24:   "t" '(string-rectangle :wk "replace rectangle with string")
    25:   "x" '(copy-to-register :wk "copy region to register")
    26:   "w" '(window-configuration-to-register :wk "store window configuration to register")
    27:   "y" '(yank-rectangle :wk "yank last killed rectangle with upper left corner at point"))
    
  • window
     1: ;; window
     2: (+config/leader-window
     3:   "C-o" '(delete-other-windows :wk "delete other windows")
     4:   "[" '(evil-window-left :wk "left window")
     5:   "]" '(evil-window-right :wk "right window")
     6:   "+" '(enlarge-window :wk "enlarge window")
     7:   "-" '(shrink-window :wk "shrink window")
     8:   "}" '(enlarge-window-horizontally :wk "enlarge window horizontally")
     9:   "{" '(shrink-window-horizontally :wk "shrink window horizontally")
    10:   "+" 'evil-window-increase-height
    11:   "-" 'evil-window-decrease-height
    12:   ":" 'evil-ex
    13:   "<" 'evil-window-decrease-width
    14:   "=" 'balance-windows
    15:   ">" 'evil-window-increase-height
    16:   "_" 'evil-window-set-height
    17:   "b" 'evil-window-bottom-right
    18:   "c" 'evil-window-delete
    19:   "d" '(delete-window :wk "delete window")
    20:   "h" 'evil-window-left
    21:   "f" '(ffap-other-window :wk "ffap other window")
    22:   "j" 'evil-window-down
    23:   "k" 'evil-window-up
    24:   "l" 'evil-window-right
    25:   "n" 'evil-window-new
    26:   "p" 'evil-window-mru
    27:   "q" 'evil-quit
    28:   "r" 'evil-window-rotate-downwards
    29:   "R" 'evil-window-rotate-upwards
    30:   "s" 'evil-window-split
    31:   "T" '(tear-off-window :wk "tear off window")
    32:   "t" 'evil-window-top-left
    33:   "u" 'winner-undo
    34:   "v" 'evil-window-vsplit
    35:   "w" '(other-window :wk "other window")
    36:   "W" 'evil-window-prev
    37:   "x" 'evil-window-exchange
    38:   "|" 'evil-window-set-width
    39:   "<left>" 'evil-window-left
    40:   "<right>" 'evil-window-right
    41:   "<down>" 'evil-window-down
    42:   "<up>" 'evil-win-up)
    

UI

I suppose here is the most external packages used.

Doom themes and modelines

  • doom-themes   external

    A megapack of themes for GNU Emacs4. I'm not the kind of guy who enjoys ricing, I look every once in a while for a nice colorscheme and then I just stick it everywhere else. Been a solarized fans most of the time, now I'm trying nord.

     1: (use-package doom-themes
     2:   :ensure t
     3:   :demand t
     4:   :config
     5:   ;; Global settings (defaults)
     6:   (setq doom-themes-enable-bold t    ; if nil, bold is universally disabled
     7:         doom-themes-enable-italic t) ; if nil, italics is universally disabled
     8:   (load-theme 'doom-nord t)
     9: 
    10:   ;; Enable flashing mode-line on errors
    11:   (doom-themes-visual-bell-config)
    12:   ;; Enable custom neotree theme (all-the-icons must be installed!)
    13:   ;; (doom-themes-neotree-config)
    14:   ;; or for treemacs users
    15:   (setq doom-themes-treemacs-theme "doom-atom") ; use "doom-colors" for less minimal icon theme
    16:   (doom-themes-treemacs-config)
    17:   ;; Corrects (and improves) org-mode's native fontification.
    18:   (doom-themes-org-config))
    
  • doom-modeline   external

    A fancy and fast mode-line inspired by minimalism design5. I'm using their themes, why not the modeline as well? I used mostly the default settings apart from project detection and indent info for showing the current indentation style (useful when editing yaml files).

    1: (use-package doom-modeline
    2:   :ensure
    3:   :init
    4:   (doom-modeline-mode 1)
    5:   :config
    6:   (setq doom-modeline-project-detection 'projectile
    7:         doom-modeline-indent-info t))
    
  • modus-vivendi   disabled

    I use this theme when I'm not using any external theme.

    1: (use-package custom
    2:   :ensure nil
    3:   :init
    4:   (load-theme 'modus-vivendi t))
    

ace-window   external

(use-package ace-window
  :ensure
  :config
  (setq aw-keys '(?q ?w ?e ?r ?t ?a ?s ?d ?f ?z ?x ?c ?v)
        aw-background nil
        aw-frame-size 2)
  (custom-set-faces
   '(aw-leading-char-face
     ((t (:inherit ace-jump-face-foreground :height 4.0)))))
  :bind ([remap other-window] . ace-window))

all-the-icons   external

A utility package to collect various Icon Fonts and propertize them within Emacs6.

1: (use-package all-the-icons
2:   :ensure
3:   :if (display-graphic-p))

This needs a manual intervention from the user to install the fonts (by running the all-the-icons-install-fonts command).

dashboard   external

An extensible emacs dashboard7.

emacs-dashboard.png

Figure 1: Emacs dashboard

My sole reason for using dashboard is to avoid seeing an empty scratch buffer each time I opened a new Emacs frame.

 1: ;; use-package with package.el:
 2: (use-package dashboard
 3:   :ensure t
 4:   :demand t
 5:   :init
 6:   (setq dashboard-set-heading-icons t
 7:         dashboard-icon-type 'all-the-icons)
 8:   (setq dashboard-heading-icons '((recents   . "history")
 9:                                   (bookmarks . "bookmark")
10:                                   (agenda    . "calendar")
11:                                   (projects  . "rocket")
12:                                   (registers . "database")))
13:   :custom
14:   (initial-buffer-choice (lambda () (get-buffer-create "*dashboard*")))
15:   (dashboard-startup-banner 'logo)
16:   (dashboard-set-heading-icons t)
17:   (dashboard-set-file-icons t)
18:   (dashboard-display-icons-p t)
19:   (dashboard-icon-type 'nerd-icons)
20:   (dashboard-projects-switch-function 'projectile-persp-switch-project)
21:   (dashboard-week-agenda t)
22:   (dashboard-filter-agenda-entry nil)
23:   (dashboard-startup-banner 'logo)
24:   (dashboard-center-content t)
25:   (dashboard-vertically-center-content t)
26:   (dashboard-agenda-sort-strategy
27:   '(todo-state-up time-down priority-down todo-state-down time-up priority-up))
28:   (dashboard-navigation-cycle t)
29:   (dashboard-banner-logo-title nil)
30:   (dashboard-set-heading-icons t)
31:   (dashboard-set-footer nil)
32:   (dashboard-projects-backend 'projectile)
33:   (dashboard-display-icons-p t)
34:   (dashboard-items '((recents . 3)
35:                      (bookmarks . 2)
36:                      (projects . 5)
37:                      (agenda . 8)
38:                      (registers . 2)))
39:   :config
40:   (dashboard-setup-startup-hook))

which-key   external

Emacs package that displays available keybindings in popup8. This is one of the top Emacs packages that I must have in my configuration.

 1: (use-package which-key
 2:   :ensure
 3:   :demand t
 4:   :custom
 5:   (which-key-lighter "")
 6:   (which-key-sort-order #'which-key-key-order-alpha)
 7:   (which-key-sort-uppercase-first nil)
 8:   (which-key-add-column-padding 1)
 9:   (which-key-max-display-columns nil)
10:   (which-key-min-display-lines 6)
11:   (which-key-compute-remaps t)
12:   (which-key-side-window-slot -10)
13:   (which-key-separator " → ")
14:   (which-key-allow-evil-operators t)
15:   (which-key-use-C-h-commands t)
16:   (which-key-show-remaining-keys t)
17:   (which-key-show-prefix 'bottom)
18:   :config
19:   (which-key-mode)
20:   (which-key-setup-side-window-bottom)
21:   (which-key-setup-minibuffer)
22:   (define-key which-key-mode-map (kbd "C-x <f5>") 'which-key-C-h-dispatch))

Fonts

1: (set-face-attribute 'default nil :family "Iosevka Nerd Font Mono")
2: (set-face-attribute 'variable-pitch nil :family "Iosevka Nerd Font Mono")
  • font-core
    1: (use-package font-core
    2:   :init
    3:   (global-font-lock-mode t))
    

rainbow-mode, rainbow-identifiers, and rainbow-delimiters   external

Making Emacs more colourful.

 1: (use-package rainbow-mode
 2:   :ensure
 3:   :hook (prog-mode . rainbow-mode))
 4: 
 5: (use-package rainbow-identifiers
 6:   :ensure
 7:   :hook (prog-mode . rainbow-identifiers-mode))
 8: 
 9: (use-package rainbow-delimiters
10:   :ensure
11:   :hook (prog-mode . rainbow-delimiters-mode))

helpful   external

Since Emacs is a self-documenting editor9. It's certainly nice to have a more contextual help buffers.

helpful_source.png

Figure 2: Helpful will also show the source code when available

helpful_docstring.png

Figure 3: more prettier docstring

helpful_bindings.png

Figure 4: helpful will also display any keybindings related

 1: (use-package helpful
 2:   :ensure
 3:   :bind
 4:   ("C-h f" . helpful-function)
 5:   ([remap describe-symbol] . helpful-symbol)
 6:   ([remap describe-variable] . helpful-variable)
 7:   ([remap describe-command] . helpful-command)
 8:   ([remap describe-key] . helpful-key)
 9:   :custom
10:   (helpful-max-buffers 2)
11:   :config
12:   (with-eval-after-load 'general
13:     (general-define-key
14:      "C-h F" 'helpful-function
15:      :keymaps 'prog-mode-map
16:      "C-c C-d" 'helpful-at-point)
17:     (general-nvmap
18:       :keymaps 'prog-mode-map
19:       "K" '(helpful-at-point :wk "helpful at point")
20:       "gr" '(helpful-update :wk "update"))))

hl-line

Enable line highlighting in all buffers.

1: (use-package hl-line
2:   :config
3:   (global-hl-line-mode 1))

nerd-icons   external

(use-package nerd-icons
  :ensure t
  :custom
  ;; The Nerd Font you want to use in GUI
  ;; "Symbols Nerd Font Mono" is the default and is recommended
  ;; but you can use any other Nerd Font if you want
  (nerd-icons-font-family "Symbols Nerd Font Mono"))

nerd-fonts   external

This package still not available at Melpa, so I have to clone it as a submodule. in archlinux, these fonts is conveniently grouped in nerd-fonts, which is needed for this and the nerd-icons package.

1: (when (file-directory-p (expand-file-name "site-lisp/nerd-fonts" user-emacs-directory))
2:   (add-to-list 'load-path (expand-file-name "site-lisp/nerd-fonts" user-emacs-directory)))
3: 
4: (use-package nerd-fonts)

paren

1: (use-package paren
2:   :config
3:   (show-paren-mode 1)
4:   :custom
5:   (show-paren-style 'mixed))

Builtins

base

Usually configuration that defined at the C source code.

 1: (use-package emacs
 2:   :ensure nil
 3:   :init
 4:   ;; Add prompt indicator to `completing-read-multiple'.
 5:   ;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
 6:   (defun crm-indicator (args)
 7:     (cons (format "[CRM%s] %s"
 8:                   (replace-regexp-in-string
 9:                    "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
10:                    crm-separator)
11:                   (car args))
12:           (cdr args)))
13:   (advice-add #'completing-read-multiple :filter-args #'crm-indicator)
14:   ;; Do not allow the cursor in the minibuffer prompt
15:   (setq minibuffer-prompt-properties
16:         '(read-only t cursor-intangible t face minibuffer-prompt))
17:   (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
18:   ;; Emacs 28: Hide commands in M-x which do not work in the current mode.
19:   ;; Vertico commands are hidden in normal buffers.
20:   (setq read-extended-command-predicate
21:         #'command-completion-default-include-p
22:         tab-always-indent 'complete)
23:   ;; Enable recursive minibuffers
24:   (setq enable-recursive-minibuffers t)
25:   :custom
26:   (read-buffer-completion-ignore-case t)
27:   (use-short-answers t)
28:   (use-dialog-box-p nil)
29:   (window-resize-pixelwise t)
30:   (frame-resize-pixelwise t)
31:   (ring-bell-function #'ignore)
32:   (scroll-preserve-screen-position t)
33:   (scroll-conservatively 101)
34:   (fast-but-imprecise-scrolling t)
35:   (truncate-partial-width-windows nil)
36:   (fill-column 80)
37:   (enable-recursive-minibuffers t)
38:   (use-file-dialog nil)
39:   (create-lockfiles nil)
40:   (delete-by-moving-to-trash t)
41:   (inhibit-startup-screen t)
42:   :config
43:   (setq completion-ignore-case t
44:         load-prefer-newer t
45:         auto-window-vscroll nil
46:         inhibit-compacting-font-caches t
47:         redisplay-skip-fontification-on-input t)
48:   (set-default 'indicate-empty-lines t)
49:   (setq-default x-stretch-cursor t))

files

Usually configurations related to file manipulations.

(use-package files
  :config
  (defun full-auto-save ()
    (interactive)
    (save-excursion
      (dolist (buf (buffer-list))
        (set-buffer buf)
        (if (and (buffer-file-name) (buffer-modified-p))
            (basic-save-buffer)))))
  (add-hook 'auto-save-hook 'full-auto-save)
  (nconc
   auto-mode-alist
   '(("/LICENSE\\'" . text-mode)
     ("\\.log\\'" . text-mode)
     ("rc\\'" . conf-mode)
     ("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode)))
  :custom
  (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 
  (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))

saveplace

1: (use-package saveplace
2:   :init
3:   (save-place-mode 1)
4:   :custom
5:   (save-place-file (expand-file-name "places" user-emacs-directory)))

autorevert

1: (use-package autorevert
2:   :init
3:   (global-auto-revert-mode 1)
4:   :custom
5:   (auto-revert-interval 60)
6:   (global-auto-revert-non-file-buffers t)
7:   (auto-revert-verbose nil)
8:   (auto-revert-stop-on-user-input t))

savehist

 1: (use-package savehist
 2:   :init
 3:   (savehist-mode 1)
 4:   :custom
 5:   (savehist-file (expand-file-name "history" user-emacs-directory))
 6:   (savehist-coding-system 'utf-8)
 7:   (savehist-additional-variables
 8:    '(evil-jumps-history
 9:      kill-ring
10:      register-alist
11:      mark-ring
12:      global-mark-ring
13:      search-ring
14:      regexp-search-ring)))

recentf

 1: (use-package recentf
 2:   :bind ("C-c f" . recentf)
 3:   :custom
 4:   (recentf-max-saved-items 250)
 5:   (recentf-max-menu-items 300)
 6:   (recentf-exclude
 7:    `("/elpa/" ;; ignore all files in elpa directory
 8:      "recentf" ;; remove the recentf load file
 9:      ".*?autoloads.el$"
10:      "treemacs-persist"
11:      "company-statistics-cache.el" ;; ignore company cache file
12:      "/intero/" ;; ignore script files generated by intero
13:      "/journal/" ;; ignore daily journal files
14:      ".gitignore" ;; ignore `.gitignore' files in projects
15:      "/tmp/" ;; ignore temporary files
16:      "NEWS" ;; don't include the NEWS file for recentf
17:      "bookmarks"  "bmk-bmenu" ;; ignore bookmarks file in .emacs.d
18:      "loaddefs.el"
19:      "^/\\(?:ssh\\|su\\|sudo\\)?:" ;; ignore tramp/ssh files
20:      (concat "^" (regexp-quote (or (getenv "XDG_RUNTIME_DIR")))))))

server

(use-package server
  :config
  (unless (server-running-p)
    (server-start))
  (require 'org-protocol))

prog-mode

 1: (use-package prog-mode
 2:   :hook ((prog-mode . prettify-symbols-mode)
 3:          (prog-mode . visual-line-mode)
 4:          ;; (prog-mode . (lambda () (electric-pair-mode 1)))
 5:          )
 6:   :config
 7:   (setq prettify-symbols-alist
 8:         '(("|>" . "▷")
 9:           ("<|" . "◁")
10:           ("->>" . "↠  ")
11:           ("->" . "→ ")
12:           ("<-" . "← ")
13:           ("=>" . "⇒"))))

bookmark

1: (use-package bookmark
2:   :custom
3:   (bookmark-save-flag 1)
4:   (bookmark-default-file (expand-file-name ".bookmark" user-emacs-directory)))

tramp

1: (use-package tramp
2:   :custom
3:   (tramp-backup-directory-alist backup-directory-alist)
4:   (tramp-auto-save-directory (expand-file-name ".tramp-autosave/" user-emacs-directory)))

epg-config

1: (use-package epg-config
2:   :custom
3:   (epg-pinentry-mode 'loopback))

simple

 1: (use-package simple
 2:   :custom
 3:   (save-interprogram-paste-before-kill t)
 4:   (shift-select-mode nil)
 5:   (kill-do-not-save-duplicates t)
 6:   (shift-select-mode nil)
 7:   (set-mark-command-repeat-pop t)
 8:   (indent-tabs-mode nil)
 9:   (column-number-mode t)
10:   (idle-update-delay 1.0)
11:   :config
12:   (with-eval-after-load 'evil
13:     (evil-set-initial-state #'message-mode 'insert)))

vc-hooks

By default visiting / opening symlinked file will ask if we want to visit the actual file.

1: (use-package vc-hooks
2:   :ensure nil
3:   :custom
4:   (vc-follow-symlinks t))

Completions

Vertico frameworks

I call this framework since usually these packages are what people use together, though they work fine separately.

  • vertico
    • Basic configuration
       1: (use-package vertico
       2:   :ensure
       3:   :init
       4:   (vertico-mode)
       5:   ;; Different scroll margin
       6:   ;; (setq vertico-scroll-margin 0)
       7:   ;; Show more candidates
       8:   ;; (setq vertico-count 20)
       9:   ;; Grow and shrink the Vertico minibuffer
      10:   ;; (setq vertico-resize t)
      11:   ;; Optionally enable cycling for `vertico-next' and `vertico-previous'.
      12:   (setq vertico-cycle t)
      13:   )
      14: 
      15: ;; A few more useful configurations...
      16: (use-package emacs
      17:   :init
      18:   ;; Add prompt indicator to `completing-read-multiple'.
      19:   ;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
      20:   (defun crm-indicator (args)
      21:     (cons (format "[CRM%s] %s"
      22:                   (replace-regexp-in-string
      23:                    "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
      24:                    crm-separator)
      25:                   (car args))
      26:           (cdr args)))
      27:   (advice-add #'completing-read-multiple :filter-args #'crm-indicator)
      28:   ;; Do not allow the cursor in the minibuffer prompt
      29:   (setq minibuffer-prompt-properties
      30:         '(read-only t cursor-intangible t face minibuffer-prompt))
      31:   (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
      32:   ;; Support opening new minibuffers from inside existing minibuffers.
      33:   (setq enable-recursive-minibuffers t)
      34:   ;; Emacs 28 and newer: Hide commands in M-x which do not work in the current
      35:   ;; mode.  Vertico commands are hidden in normal buffers. This setting is
      36:   ;; useful beyond Vertico.
      37:   (setq read-extended-command-predicate #'command-completion-default-include-p))
      
    • Extensions
      • vertico-directory
         1: (use-package vertico-directory
         2:   :after vertico
         3:   :ensure nil
         4:   ;; More convenient directory navigation commands
         5:   :bind (:map vertico-map
         6:               ("RET" . vertico-directory-enter)
         7:               ("DEL" . vertico-directory-delete-char)
         8:               ("M-DEL" . vertico-directory-delete-word))
         9:   ;; Tidy shadowed file names
        10:   :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
        
      • vertico-quick
        1: (use-package vertico-quick
        2:   :after vertico
        3:   :ensure nil
        4:   :bind (:map vertico-map
        5:               ("M-q" . vertico-quick-insert)
        6:               ("C-q" . vertico-quick-exit)))
        
  • marginalia
    1: ;; Enable rich annotations using the Marginalia package
    2: (use-package marginalia
    3:   :ensure
    4:   :bind (:map minibuffer-local-map
    5:               ("M-A" . marginalia-cycle))
    6:   :init
    7:   (marginalia-mode))
    
  • corfu
    • Basic Configuration
      (use-package corfu
        :ensure
        :custom
        (corfu-cycle t)
        (corfu-auto t)
        (corfu-quit-no-match 'separator)
        (corfu-preselect 'prompt)
        (completion-cycle-threshold 3)
        :init
        (global-corfu-mode))
      
  • consult
  • Basic Configuration
     1: (use-package consult
     2:   :ensure
     3:   :hook (completion-list-mode . consult-preview-at-point-mode)
     4:   :init
     5:   ;; Optionally configure the register formatting. This improves the register
     6:   ;; preview for `consult-register', `consult-register-load',
     7:   ;; `consult-register-store' and the Emacs built-ins.
     8:   (setq register-preview-delay 0.5
     9:         register-preview-function #'consult-register-format)
    10:   ;; Optionally tweak the register preview window.
    11:   ;; This adds thin lines, sorting and hides the mode line of the window.
    12:   (advice-add #'register-preview :override #'consult-register-window)
    13:   ;; Use Consult to select xref locations with preview
    14:   (setq xref-show-xrefs-function #'consult-xref
    15:         xref-show-definitions-function #'consult-xref)
    16:   ;; Configure other variables and modes in the :config section,
    17:   ;; after lazily loading the package.
    18:   :config
    19:   ;; Optionally configure preview. The default value
    20:   ;; is 'any, such that any key triggers the preview.
    21:   ;; (setq consult-preview-key 'any)
    22:   ;; (setq consult-preview-key "M-.")
    23:   ;; (setq consult-preview-key '("S-<down>" "S-<up>"))
    24:   ;; For some commands and buffer sources it is useful to configure the
    25:   ;; :preview-key on a per-command basis using the `consult-customize' macro.
    26:   (consult-customize
    27:    consult-theme :preview-key '(:debounce 0.2 any)
    28:    consult-ripgrep consult-git-grep consult-grep
    29:    consult-bookmark consult-recent-file consult-xref
    30:    consult--source-bookmark consult--source-file-register
    31:    consult--source-recent-file consult--source-project-recent-file
    32:    ;; :preview-key "M-."
    33:    :preview-key '(:debounce 0.4 any))
    34:   ;; Optionally configure the narrowing key.
    35:   ;; Both < and C-+ work reasonably well.
    36:   (setq consult-narrow-key "<") ;; "C-+"
    37:   ;; Optionally make narrowing help available in the minibuffer.
    38:   ;; You may want to use `embark-prefix-help-command' or which-key instead.
    39:   ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)
    40:   ;; By default `consult-project-function' uses `project-root' from project.el.
    41:   ;; Optionally configure a different project root function.
    42: ;;;; 1. project.el (the default)
    43:   ;; (setq consult-project-function #'consult--default-project--function)
    44: ;;;; 2. vc.el (vc-root-dir)
    45:   ;; (setq consult-project-function (lambda (_) (vc-root-dir)))
    46: ;;;; 3. locate-dominating-file
    47:   ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
    48: ;;;; 4. projectile.el (projectile-project-root)
    49:   ;; (autoload 'projectile-project-root "projectile")
    50:   ;; (setq consult-project-function (lambda (_) (projectile-project-root)))
    51: ;;;; 5. No project support
    52:   ;; (setq consult-project-function nil))
    53: )
    54: 
    
  • orderless
    • Basic Configuration
      1: (use-package orderless
      2:   :ensure
      3:   :init
      4:   ;; Configure a custom style dispatcher (see the Consult wiki)
      5:   ;; (setq orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-dispatch)
      6:   ;;       orderless-component-separator #'orderless-escapable-split-on-space)
      7:   (setq completion-styles '(orderless basic)
      8:         completion-category-defaults nil
      9:         completion-category-overrides '((file (styles partial-completion)))))
      
  • nerd-icons-corfu
    1: (use-package nerd-icons-corfu
    2:   :ensure
    3:   :config
    4:   (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)
    5:   (setq nerd-icons-corfu-mapping
    6:         '((array :style "cod" :icon "symbol_array" :face font-lock-type-face)
    7:           (boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face)
    8:           ;; ...
    9:           (t :style "cod" :icon "code" :face font-lock-warning-face))))
    
  • nerd-icons-completion
    1: (use-package nerd-icons-completion
    2:   :ensure
    3:   :hook (marginalia-mode . nerd-icons-completion-marginalia-setup)
    4:   :config
    5:   (nerd-icons-completion-mode))
    

Shells

eshell

emacs-eshell.png

Figure 5: eshell in action

A shell-like command interpreter implemented in Emacs Lisp.

1: (use-package eshell
2:   :ensure nil
3:   :custom
4:   (eshell-history-size 10000)
5:   (eshell-hist-ignore-dups t)
6:   (eshell-buffer-maximum-lines 10000)
7:   (eshell-scroll-to-bottom-on-input t)
8:   (eshell-destroy-buffer-when-process-dies t)
9:   (eshell-prompt-regexp "^[^\)]*[\)] "))

eshell-syntax-highlighting

1: (use-package eshell-syntax-highlighting
2:   :ensure
3:   :defer t
4:   :after eshell
5:   :config
6:   (eshell-syntax-highlighting-global-mode +1))

esh-autosuggest

1: (use-package esh-autosuggest
2:   :defer t
3:   :hook (eshell-mode . esh-autosuggest-mode)
4:   ;; If you have use-package-hook-name-suffix set to nil, uncomment and use the
5:   ;; line below instead:
6:   ;; :hook (eshell-mode-hook . esh-autosuggest-mode)
7:   :ensure t)

sh-script

 1: (use-package sh-script
 2:   :mode ("\\.bats\\'" . sh-mode)
 3:   :mode ("\\.\\(?:zunit\\|env\\)\\'" . sh-mode)
 4:   :mode ("/bspwmrc\\'" . sh-mode)
 5:   :hook (sh-mode-local-vars . lsp-deferred)
 6:   :hook (sh-mode-local-vars . tree-sitter-mode)
 7:   :config
 8:   (with-eval-after-load 'lsp
 9:     (add-hook 'sh-mode-hook #'lsp-deferred)
10:     (add-hook 'shell-mode-hook #'lsp-deferred)
11:     (add-hook 'sh-mode-local-vars-hook #'lsp-deferred))
12:   (with-eval-after-load 'rainbow-delimiters
13:     (add-hook 'sh-mode #'rainbow-delimiters-mode))
14:   ;; recognize function names with dashes in them
15:   (setq sh-indent-after-continuation 'always)
16:   (add-to-list 'sh-imenu-generic-expression
17:                '(sh (nil "^\\s-*function\\s-+\\([[:alpha:]_-][[:alnum:]_-]*\\)\\s-*\\(?:()\\)?" 1)
18:                     (nil "^\\s-*\\([[:alpha:]_-][[:alnum:]_-]*\\)\\s-*()" 1)))
19:   (with-eval-after-load 'smartparens
20:     (sp-local-pair 'sh-mode "`" "`" :unless '(sp-point-before-word-p sp-point-before-same-p))))

vterm

 1: (use-package vterm
 2:   :ensure
 3:   :defer t
 4:   :commands vterm-mode
 5:   :config
 6:   (add-hook 'vterm-mode-hook
 7:             (lambda ()
 8:               (setq-local global-hl-line-mode nil)
 9:               (setq-local hscroll-margin 0)))
10:   (setq vterm-kill-buffer-on-exit t)
11:   :general
12:   (+config/leader-menu! "vterm"
13:       "tv"
14:     "RET" 'vterm-toggle
15:     "v" 'vterm))

multi-vterm

 1: (use-package multi-vterm
 2:   :ensure
 3:   :defer t
 4:   :after vterm
 5:   :general
 6:   (general-iemap
 7:     :keymaps 'vterm-mode-map
 8:     "C-SPC" '(:ignore t :wk "multi vterm")
 9:     "C-SPC a" '(multi-vterm :wk "new vterm buffer")
10:     "C-SPC n" '(multi-vterm-next :wk "next vterm buffer")
11:     "C-SPC p" '(multi-vterm-prev :wk "previous vterm buffer")))

vterm-toggle   disabled

 1: (use-package vterm-toggle
 2:   :ensure
 3:   :defer t
 4:   :after vterm
 5:   :commands vterm-toggle
 6:   :bind
 7:   (:map vterm-mode-map
 8:         ("C-<return>" . vterm-toggle-insert-cd))
 9:   :config
10:   (setq vterm-toggle-fullscreen-p nil)
11:   (add-to-list 'display-buffer-alist
12:                '((lambda (buffer-or-name _)
13:                    (let ((buffer (get-buffer buffer-or-name)))
14:                      (with-current-buffer buffer
15:                        (or (equal major-mode 'vterm-mode)
16:                            (string-prefix-p vterm-buffer-name (buffer-name buffer))))))
17:                  (display-buffer-reuse-window display-buffer-at-bottom)
18:                  ;;(display-buffer-reuse-window display-buffer-in-direction)
19:                  ;;display-buffer-in-direction/direction/dedicated is added in emacs27
20:                  ;;(direction . bottom)
21:                  (dedicated . t) ;dedicated is supported in emacs27
22:                  (reusable-frames . visible)
23:                  (window-height . 0.4))))

bash-completion   disabled

1: (use-package bash-completion
2:   :ensure
3:   :defer t
4:   :config
5:   (bash-completion-setup)
6:   :hook
7:   (shell-dynamic-complete-function bash-completion-dynamic-complete))

Editing

select

1: (use-package select
2:   :custom
3:   (select-enable-clipboard t))

transient-mark-mode

Highlight region.

1: (transient-mark-mode 1)

delete-selection-mode

When enabled, typed text replaces the selection if the selection is active. Otherwise, typed text is just inserted at point regardless of any selection.

1: (delete-selection-mode 1)

subword

1: (use-package subword
2:   :init
3:   (global-subword-mode 1))

text-mode

1: (use-package text-mode
2:   :ensure nil
3:   :hook (text-mode . visual-line-mode)
4:   :config
5:   (setq-default sentence-end-double-space nil))

ws-butler

(use-package ws-butler
  :ensure
  :hook (prog-mode . ws-butler-mode))

smartparens

I still have a mixed feeling for this package, but it still easier to configure than the builtin electric-pair-mode. Also, should this be in the Lisp section?

 1: ;; smartparens
 2: (use-package smartparens
 3:   :ensure
 4:   :demand t
 5:   :init
 6:   (smartparens-global-mode)
 7:   :config
 8:   ;; smartparens recognizes `slime-mrepl-mode', but not `sly-mrepl-mode', so...
 9:   (add-to-list 'sp-lisp-modes 'sly-mrepl-mode)
10:   (require 'smartparens-config)
11:   (add-hook 'eval-expression-minibuffer-setup-hook #'smartparens-mode)
12:   ;; Overlays are too distracting and not terribly helpful. show-parens does
13:   ;; this for us already (and is faster), so...
14:   (setq sp-highlight-pair-overlay nil
15:         sp-highlight-wrap-overlay nil
16:         sp-highlight-wrap-tag-overlay nil)
17:   (show-smartparens-global-mode 1)
18:   (smartparens-global-mode 1)
19:   ;; Fix usage of ' in Lisp modes
20:   ;; THANKS: https://github.com/Fuco1/smartparens/issues/286#issuecomment-32324743
21:   ;; (eval) is used as a hack to quiet Flycheck errors about (sp-with-modes)
22:   (eval
23:    '(sp-with-modes sp-lisp-modes
24:       ;; disable ', it's the quote character!
25:       (sp-local-pair "'" nil :actions nil)
26:       ;; also only use the pseudo-quote inside strings where it serve as
27:       ;; hyperlink.
28:       (sp-local-pair "`" "'" :when '(sp-in-string-p sp-in-comment-p))
29:       (sp-local-pair "`" nil
30:                      :skip-match (lambda (ms mb me)
31:                                    (cond
32:                                     ((equal ms "'")
33:                                      (or (sp--org-skip-markup ms mb me)
34:                                          (not (sp-point-in-string-or-comment))))
35:                                     (t (not (sp-point-in-string-or-comment))))))))
36:   (sp-with-modes '(html-mode sgml-mode nxml-mode web-mode)
37:     (sp-local-pair "<" ">"))
38: 
39:   (defun sp--markdown-skip-asterisk (ms mb me)
40:     (save-excursion
41:       (goto-char mb)
42:       (save-match-data (looking-at "^\\* "))))
43: 
44:   (sp-with-modes 'markdown-mode
45:     (sp-local-pair "*" "*"
46:                    :unless '(sp-point-after-word-p sp-point-at-bol-p)
47:                    :skip-match 'sp--markdown-skip-asterisk)
48:     (sp-local-pair "**" "**")
49:     (sp-local-pair "_" "_" :unless '(sp-point-after-word-p)))
50: 
51:   ;;; org-mode
52:   (defun sp--org-skip-asterisk (ms mb me)
53:     (or (and (= (line-beginning-position) mb)
54:              (eq 32 (char-after (1+ mb))))
55:         (and (= (1+ (line-beginning-position)) me)
56:              (eq 32 (char-after me)))))
57:   (defun sp--org-inside-LaTeX (id action context)
58:     (org-inside-LaTeX-fragment-p))
59:   (sp-with-modes 'org-mode
60:     (sp-local-pair "*" "*"
61:                    :unless '(sp-point-after-word-p sp--org-inside-LaTeX sp-point-at-bol-p)
62:                    :skip-match 'sp--org-skip-asterisk)
63:     (sp-local-pair "/" "/" :unless '(sp-point-after-word-p sp--org-inside-LaTeX))
64:     (sp-local-pair "~" "~" :unless '(sp-point-after-word-p sp--org-inside-LaTeX))
65:     (sp-local-pair "=" "=" :unless '(sp-point-after-word-p sp--org-inside-LaTeX))
66:     (sp-local-pair "\\[" "\\]"))
67: 
68:   ;; haskell
69:   (add-to-list 'sp-no-reindent-after-kill-modes 'haskell-mode)
70: 
71:   ;; You're likely writing lisp in the minibuffer, therefore, disable these
72:   ;; quote pairs, which lisps doesn't use for strings:
73:   (sp-local-pair '(minibuffer-mode minibuffer-inactive-mode) "'" nil :actions nil)
74:   (sp-local-pair '(minibuffer-mode minibuffer-inactive-mode) "`" nil :actions nil)
75:   )

The keybinding I got from the example configuration messes up my evil-mode. I have them commented for now.

IDE stuffs

magit   external

emacs-magit.png

Figure 6: Emacs magit

 1: (use-package magit
 2:   :ensure
 3:   :demand t
 4:   :config
 5:   (evil-set-initial-state #'git-commit-mode 'insert)
 6:   :custom
 7:   (magit-revision-show-gravatars '("^Author:     " . "^Commit:     "))
 8:   (magit-diff-refine-hunk 'all)
 9:   (magit-log-arguments '("-n100" "--graph" "--decorate"))
10:   :general
11:   (+config/leader-go
12:     "g" 'magit-status))

projectile   external

A project interaction library for Emacs, with little external dependency as possible.

 1: (use-package projectile
 2:   :ensure t
 3:   :demand t
 4:   :bind (([remap evil-jump-to-tag] . projectile-find-tag)
 5:          ([remap find-tag] . projectile-find-tag))
 6:   :hook (dired-before-readin . projectile-track-known-projects-find-file-hook)
 7:   :custom
 8:   (projectile-cache-file (expand-file-name ".projects" user-emacs-directory))
 9:   (projectile-auto-discover nil)
10:   (projectile-enable-caching (not noninteractive))
11:   (projectile-globally-ignored-files '("DS_Store" "TAGS"))
12:   (projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o"))
13:   (projectile-kill-buffers-filter 'kill-only-files)
14:   (projectile-known-projects-file (expand-file-name ".projectile_projects.eld" user-emacs-directory))
15:   (projectile-ignored-projects '("~/"))
16:   (projectile-project-root-files-bottom-up
17:    (append '(".projectile" ".project" ".git")
18:            (when (executable-find "hg")
19:              '(".hg"))
20:            (when (executable-find "bzr")
21:              '(".bzr"))))
22:   (projectile-project-root-files-top-down-recurring '("Makefile"))
23:   (compilation-buffer-name-function #'projectile-compilation-buffer-name)
24:   (compilation-save-buffers-predicate #'projectile-current-project-buffer-p)
25:   (projectile-git-submodule-command nil)
26:   (projectile-indexing-method 'hybrid)
27:   :config
28:   (projectile-mode +1)
29:   (put 'projectile-git-submodule-command 'initial-value projectile-git-submodule-command)
30:   :general
31:   (+config/leader-key
32:     "SPC" 'projectile-find-file
33:     "p" '(:keymap projectile-command-map :package projectile :wk "projectile")))

diff-hl   external

emacs-diff-hl-indicator.png

Figure 7: highlighted uncommited changes

 1: (use-package diff-hl
 2:   :ensure
 3:   :hook (find-file . diff-hl-mode)
 4:   :hook (vc-dir-mode . diff-hl-dir-mode)
 5:   :hook (dired-mode . diff-hl-dired-mode)
 6:   :hook (diff-hl-mode . diff-hl-flydiff-mode)
 7:   :hook (diff-hl-mode . diff-hl-show-hunk-mouse-mode)
 8:   :hook (magit-pre-refresh-hook . diff-hl-magit-pre-refresh)
 9:   :hook (magit-post-refresh-hook . diff-hl-magit-post-refresh)
10:   :init
11:   (global-diff-hl-mode)
12:   :custom
13:   (vc-git-diff-switches '("--histogram")
14:                         diff-hl-flydiff-delay 0.5
15:                         diff-hl-show-staged-changes nil)
16:   :config
17:   (when (featurep 'flycheck)
18:     (setq flycheck-indication-mode 'right-fringe)))

perspective   external

Useful when I'm working on several projectile projects at once. With each perspective having their own separate buffer list.

 1: (use-package perspective
 2:   :ensure
 3:   :config
 4:   (setq persp-initial-frame-name "Main"
 5:         persp-suppress-no-prefix-key-warning t)
 6:   (if (featurep 'no-littering)
 7:       (setq persp-state-default-file (expand-file-name ".perspective-state" no-littering-var-directory))
 8:     (setq persp-state-default-file (expand-file-name ".perspective-state" user-emacs-directory)))
 9:   (global-set-key [remap switch-to-buffer] #'persp-switch-to-buffer*)
10:   (when (featurep 'consult)
11:     (require 'consult)
12:     (unless (boundp 'persp-consult-source)
13:       (defvar persp-consult-source
14:         (list :name     "Perspective"
15:               :narrow   ?s
16:               :category 'buffer
17:               :state    #'consult--buffer-state
18:               :history  'buffer-name-history
19:               :default  t
20:               :items
21:               #'(lambda () (consult--buffer-query :sort 'visibility
22:                                                   :predicate '(lambda (buf) (persp-is-current-buffer buf t))
23:                                                   :as #'buffer-name)))))
24:     (consult-customize consult--source-buffer :hidden t :default nil)
25:     (add-to-list 'consult-buffer-sources persp-consult-source))
26:   :init
27:   (customize-set-variable 'persp-mode-prefix-key (kbd "C-c TAB"))
28:   (unless (equal persp-mode t)
29:     (persp-mode 1))
30:   :bind (([remap switch-to-buffer] . persp-switch-to-buffer*)
31:          ([remap kill-buffer] . persp-kill-buffer*))
32:   :hook (kill-emacs . persp-state-save)
33:   :general
34:   (general-def
35:     :keymaps 'perspective-map
36:     "TAB" '(persp-switch-last :wk "switch to last perspective")
37:     "P" 'projectile-persp-switch-project)
38:   (+config/leader-key
39:     "TAB" (general-simulate-key "C-c TAB"
40:             :state '(normal visual)
41:             :name general-SPC-h-simulates-C-c-TAB
42:             :docstring "Simulates C-c TAB in normal and visual mode."
43:             :which-key "Perspective"))
44:   (+config/leader-key
45:     "C-x" '(persp-switch-to-scratch-buffer :wk "switch to scratch buffer")))

persp-projectile   external

1: (use-package persp-projectile
2:   :ensure t
3:   :after perspective
4:   :commands projectile-persp-switch-project
5:   :general
6:   (general-def
7:     :keymaps 'perspective-map
8:     "P" 'projectile-persp-switch-project))

git-link   external

 1: (use-package git-link
 2:   :demand
 3:   :ensure
 4:   :commands (git-link git-link-commit git-link-homepage)
 5:   :general
 6:   (+config/leader-go
 7:     "G" '(:ignore t :wk "git")
 8:     "Gl" 'git-link
 9:     "Gh" 'git-link-homepage
10:     "Gc" 'git-link-commit))

git-messenger   external

emacs-git-messenger.png

Figure 8: git messenger popup message

 1: (use-package git-messenger
 2:   :ensure
 3:   :config
 4:   (with-eval-after-load 'general
 5:     (+config/leader-go
 6:       "Gm" 'git-messenger:popup-message))
 7:   :custom
 8:   ;; Enable magit-show-commit instead of pop-to-buffer
 9:   (git-messenger:use-magit-popup t)
10:   (git-messenger:show-detail t))

git-timemachine   external

1: (use-package git-timemachine
2:   :ensure
3:   :after magit
4:   :general
5:   (+config/leader-go
6:     "Gt" 'git-timemachine-toggle))

org-project-capture   external

1: (use-package org-project-capture
2:   :bind (("C-c n p" . org-project-capture-project-todo-completing-read))
3:   :ensure t
4:   :config
5:   (progn
6:     (setq org-project-capture-backend
7:           (make-instance 'org-project-capture-projectile-backend))  ; Replace with your backend of choice
8:     (setq org-project-capture-projects-file (expand-file-name "projects.org" org-directory))
9:     (org-project-capture-single-file)))

lsp   external

emacs-lsp.png

Figure 9: Emacs lsp in action

  • Basic configuration
    • LSP
       1: (use-package lsp-mode
       2:   :ensure
       3:   :init
       4:   (setq lsp-keymap-prefix "C-c C-l")
       5:   (defun my/orderless-dispatch-flex-first (_pattern index _total)
       6:     (and (eq index 0) 'orderless-flex))
       7:   (defun my/lsp-mode-setup-completion ()
       8:     (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))
       9:           '(orderless)))
      10:   (add-hook 'orderless-style-dispatchers #'my/orderless-dispatch-flex-first nil 'local)
      11:   (when (featurep 'cape)
      12:     (setq-local completion-at-point-functions (list (cape-capf-buster #'lsp-completion-at-point))))
      13:   :hook
      14:   (lsp-mode . lsp-enable-which-key-integration)
      15:   (lsp-completion-mode . my/lsp-mode-setup-completion)
      16:   ((c-mode c++-mode xml-mode python-mode
      17:            yaml-mode toml-mode python-mode-local-vars
      18:            lua-mode jinja2-mode
      19:            json-mode html-mode
      20:            web-mode html-mode-local-vars-hook
      21:            web-mode-local-vars-hook nxml-mode-local-vars-hook
      22:            scss-mode-local-vars css-mode-local-vars
      23:            less-css-mode-local-vars css-mode
      24:            typescript-mode javascript-mode
      25:            js2-mode typescript-tsx-mode) . lsp-deferred)
      26:   :config
      27:   (setq lsp-toml-command
      28:         (if (file-exists-p (expand-file-name ".cargo/bin/taplo" "~"))
      29:             (expand-file-name ".cargo/bin/taplo" "~")
      30:           "taplo")
      31:         lsp-rust-rls-server-command "rls"
      32:         lsp-eldoc-render-all t
      33:         lsp-enable-snippet nil
      34:         lsp-enable-indentation nil
      35:         lsp-prefer-flymake nil
      36:         lsp-keep-workspace-alive nil
      37:         lsp-modeline-code-actions-segments '(count icon name))
      38:   (when (featurep 'exwm)
      39:     (advice-add #'corfu--make-frame :around
      40:                 (defun +corfu--make-frame-a (oldfun &rest args)
      41:                   (cl-letf (((symbol-function #'frame-parent)
      42:                              (lambda (frame)
      43:                                (or (frame-parameter frame 'parent-frame)
      44:                                    exwm-workspace--current))))
      45:                     (apply oldfun args))
      46:                   (when exwm--connection
      47:                     (set-frame-parameter corfu--frame 'parent-frame nil))))
      48: 
      49:     (advice-add #'corfu--popup-redirect-focus :override
      50:                 (defun +corfu--popup-redirect-focus-a ()
      51:                   (redirect-frame-focus corfu--frame
      52:                                         (or (frame-parent corfu--frame)
      53:                                             exwm-workspace--current)))))
      54:   :custom
      55:   (lsp-completion-provider :none)
      56:   :general
      57:   (+config/leader-key
      58:     :keymaps 'lsp-mode-map
      59:     "l" (general-simulate-key "C-c C-l"
      60:           :name general-SPC-l-simulates-C-c-C-l
      61:           :docstring "Simulates C-c C-l"
      62:           :which-key "LSP")))
      
    • lsp-ui
       1: (use-package lsp-ui
       2:   :ensure
       3:   :defer t
       4:   :hook (lsp-mode . lsp-ui-mode)
       5:   :init
       6:   (setq lsp-ui-sideline-enable t
       7:         lsp-ui-sideline-update-mode 'line
       8:         lsp-ui-sideline-show-code-actions t
       9:         lsp-ui-sideline-show-hover t
      10:         lsp-ui-doc-enable t
      11:         lsp-ui-doc-include-signature t
      12:         lsp-ui-doc-show-with-cursor t
      13:         lsp-eldoc-enable-hover nil ; Disable eldoc displays in minibuffer
      14:         lsp-ui-doc-position 'at-point
      15:         lsp-ui-imenu-enable t
      16:         lsp-ui-sideline-ignore-duplicate t
      17:         lsp-ui-peek-enable t)
      18:   :config
      19:   (define-key lsp-ui-mode-map [remap xref-find-definitions] #'lsp-ui-peek-find-definitions)
      20:   (define-key lsp-ui-mode-map [remap xref-find-references] #'lsp-ui-peek-find-references)
      21:   (add-to-list 'lsp-language-id-configuration '(jinja2-mode . "jinja2") t)
      22:   (add-to-list 'lsp-language-id-configuration '("\\.js2$" . "jinja2") t)
      23:   :general
      24:   (general-define-key
      25:    :keymaps '(lsp-ui-mode-map)
      26:    [remap xref-find-definitions] 'lsp-ui-peek-find-definitions
      27:    [remap xref-find-references] 'lsp-ui-peek-find-references
      28:    "M-." 'lsp-ui-peek-find-definitions
      29:    "M-?" 'lsp-ui-peek-find-references))
      
    • consult-lsp
      1: (use-package consult-lsp
      2:   :ensure
      3:   :after consult lsp
      4:   :bind
      5:   (:map lsp-mode-map
      6:         ([remap xref-find-apropos] . consult-lsp-symbols)))
      

org-mode

org-mode

  1: (use-package org
  2:   :commands org-tempo
  3:   :preface
  4:   (if (not +config/org-directory)
  5:       (cond
  6:        ((file-directory-p
  7:          (expand-file-name "Dropbox/org" (getenv "HOME")))
  8:         (setq org-directory (expand-file-name "Dropbox/org" (getenv "HOME"))))
  9:        ((file-directory-p
 10:          (expand-file-name "Sync/org" (getenv "HOME")))
 11:         (setq org-directory (expand-file-name "Sync/org" (getenv "HOME"))))
 12:        ((file-directory-p
 13:          (expand-file-name "Documents/google-drive/org" (getenv "HOME")))
 14:         (setq org-directory (expand-file-name "Documents/google-drive/org" (getenv "HOME")))))
 15:     (customize-set-variable 'org-directory +config/org-directory))
 16:   :hook ((org-mode . org-indent-mode)
 17:          (org-mode . +config/org-prettify-symbols))
 18:   :config
 19:   (global-set-key (kbd "C-c l") #'org-store-link)
 20:   (global-set-key (kbd "C-c a") #'org-agenda)
 21:   (global-set-key (kbd "C-c c") #'org-capture)
 22:   (when(file-directory-p (expand-file-name "braindump/org" org-directory))
 23:     (customize-set-variable '+config/org-roam-directory
 24:                             (expand-file-name "braindump/org" org-directory)))
 25:   (when (file-directory-p (expand-file-name "alexforsale.github.io" org-directory))
 26:     (customize-set-variable '+config/blog-directory
 27:                             (expand-file-name "alexforsale.github.io" org-directory)))
 28:   (modify-syntax-entry ?= "$" org-mode-syntax-table)
 29:   (modify-syntax-entry ?~ "$" org-mode-syntax-table)
 30:   (modify-syntax-entry ?_ "$" org-mode-syntax-table)
 31:   (modify-syntax-entry ?+ "$" org-mode-syntax-table)
 32:   (modify-syntax-entry ?/ "$" org-mode-syntax-table)
 33:   (modify-syntax-entry ?* "$" org-mode-syntax-table)
 34:   (add-to-list 'org-modules 'org-tempo t)
 35:   (add-to-list 'org-structure-template-alist '("sh" . "src sh"))
 36:   (add-to-list 'org-structure-template-alist '("co" . "src conf"))
 37:   (add-to-list 'org-structure-template-alist '("lisp" . "src lisp"))
 38:   (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
 39:   (add-to-list 'org-structure-template-alist '("sc" . "src scheme"))
 40:   (add-to-list 'org-structure-template-alist '("ts" . "src typescript"))
 41:   (add-to-list 'org-structure-template-alist '("py" . "src python"))
 42:   (add-to-list 'org-structure-template-alist '("go" . "src go"))
 43:   (add-to-list 'org-structure-template-alist '("yaml" . "src yaml"))
 44:   (add-to-list 'org-structure-template-alist '("js" . "src js"))
 45:   (add-to-list 'org-structure-template-alist '("json" . "src json"))
 46:   (add-to-list 'org-structure-template-alist '("n" . "note"))
 47:   (org-babel-do-load-languages
 48:    'org-babel-load-languages
 49:    '((emacs-lisp . t)
 50:      (awk . t)
 51:      (C . t)
 52:      (css . t)
 53:      (calc . t)
 54:      ;; (ditaa . t) ; needs the `ditaa' package
 55:      ;; (diagrams . t) ; `ob-diagrams'
 56:      ;; (dot . t ) ; `graphviz'
 57:      (screen . t)
 58:      (haskell . t)
 59:      (java . t)
 60:      (js . t)
 61:      (latex . t)
 62:      (lisp . t)
 63:      (lua . t)
 64:      (org . t)
 65:      (perl . t)
 66:      (plantuml . t)
 67:      (python .t)
 68:      (ruby . t)
 69:      (shell . t)
 70:      (sed . t)
 71:      (scheme . t)
 72:      (sql . t)
 73:      (sqlite . t)))
 74:   (setq-default org-use-sub-superscripts '{})
 75:   (add-to-list 'org-babel-tangle-lang-exts '("js" . "js"))
 76:   (defun +config/org-prettify-symbols ()
 77:     (push '("[ ]" . "☐") prettify-symbols-alist)
 78:     (push '("[X]" . "☑") prettify-symbols-alist)
 79:     (prettify-symbols-mode))
 80:   :custom
 81:   (org-replace-disputed-keys t)
 82:   (org-indirect-buffer-display 'current-window)
 83:   (org-enforce-todo-dependencies t)
 84:   (org-fontify-whole-heading-line t)
 85:   (org-return-follows-link t)
 86:   (org-mouse-1-follows-link t)
 87:   (org-image-actual-width nil)
 88:   (org-adapt-indentation nil)
 89:   (org-startup-indented t)
 90:   (org-link-descriptive nil)
 91:   (org-log-done 'time)
 92:   (org-log-refile 'time)
 93:   (org-log-redeadline 'time)
 94:   (org-log-reschedule 'time)
 95:   (org-log-into-drawer t)
 96:   (org-clone-delete-id t)
 97:   (org-default-notes-file (expand-file-name "notes.org" org-directory))
 98:   (org-insert-heading-respect-content nil)
 99:   (org-pretty-entities t)
100:   (org-use-property-inheritance t)
101:   (org-priority-highest ?A)
102:   (org-priority-lowest ?D)
103:   (org-priority-default ?B)
104:   (org-todo-keywords
105:    '((sequence
106:       "TODO(t!)"  ; A task that needs doing & is ready to do
107:       "NEXT(n!)"  ; Tasks that can be delayed
108:       "PROG(p!)"  ; A task that is in progress
109:       "WAIT(w!)"  ; Something external is holding up this task
110:       "HOLD(h!)"  ; This task is paused/on hold because of me
111:       "|"
112:       "DONE(d!)"  ; Task successfully completed
113:       "DELEGATED(l!)" ; Task is delegated
114:       "KILL(k!)") ; Task was cancelled, aborted or is no longer applicable
115:      ))
116:   (org-todo-keyword-faces
117:    '(("PROG" . (:foreground "#5e81ac" :weight bold))
118:      ("WAIT" . (:foreground "#ebcb8b" :weight bold))
119:      ("HOLD" . (:foreground "#d08770" :weight bold))
120:      ("NEXT" . (:foreground "#81a1c1" :weight bold))
121:      ("DELEGATED" . "#8fbcbb")
122:      ("KILL" . "#a3be8c"))))

org-faces

1: (use-package org-faces
2:   :custom
3:   (org-fontify-quote-and-verse-blocks t))

org-archive

1: (use-package org-archive
2:   :after org
3:   :custom
4:   (org-archive-tag "archive")
5:   (org-archive-subtree-save-file-p t)
6:   (org-archive-mark-done t)
7:   (org-archive-reversed-order t)
8:   (org-archive-location (concat (expand-file-name "archives.org" org-directory) "::datetree/* Archived Tasks")))

org-capture

 1: (use-package org-capture
 2:   :after org
 3:   :demand t
 4:   :config
 5:   (org-capture-put :kill-buffer t)
 6:   (setq org-capture-templates ;; this is the default from `doom'.
 7:         `(("i" "Inbox - Goes Here first!" entry
 8:            (file+headline ,(expand-file-name "inbox.org" org-directory) "Inbox")
 9:            "** %?\n%i\n%a" :prepend t)
10:           ("r" "Request" entry (file+headline ,(expand-file-name "inbox.org" org-directory) "Request")
11:            (file ,(expand-file-name "request.template" org-directory)))
12:           ("l" "Links" entry
13:            (file+headline ,(expand-file-name "links.org" org-directory) "Links")))))

org-refile

 1: (use-package org-refile
 2:   :after org
 3:   :hook (org-after-refile-insert . save-buffer)
 4:   :custom
 5:   (org-refile-targets
 6:    `((,(expand-file-name "projects.org" org-directory) :maxlevel . 1)
 7:      (,(expand-file-name "routines.org" org-directory) :maxlevel . 1)
 8:      (,(expand-file-name "personal.org" org-directory) :maxlevel . 1)))
 9:   (org-refile-use-outline-path 'file)
10:   (org-outline-path-complete-in-steps nil))

org-fold

1: (use-package org-fold
2:   :after org org-contrib
3:   :custom
4:   (org-catch-invisible-edits 'smart))

org-id

1: (use-package org-id
2:   :after org
3:   :custom
4:   (org-id-locations-file-relative t)
5:   (org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id))

org-num

1: (use-package org-num
2:   :after org
3:   :custom
4:   (org-num-face '(:inherit org-special-keyword :underline nil :weight bold))
5:   (org-num-skip-tags '("noexport" "nonum")))

org-crypt

 1: (use-package org-crypt ; built-in
 2:   :after org
 3:   :commands org-encrypt-entries org-encrypt-entry org-decrypt-entries org-decrypt-entry
 4:   ;;:hook (org-reveal-start . org-decrypt-entry)
 5:   :preface
 6:   ;; org-crypt falls back to CRYPTKEY property then `epa-file-encrypt-to', which
 7:   ;; is a better default than the empty string `org-crypt-key' defaults to.
 8:   (defvar org-crypt-key nil)
 9:   (with-eval-after-load 'org
10:     (add-to-list 'org-tags-exclude-from-inheritance "crypt")))

org-attach

 1: (use-package org-attach
 2:   :after org
 3:   :commands (org-attach-new
 4:              org-attach-open
 5:              org-attach-open-in-emacs
 6:              org-attach-reveal-in-emacs
 7:              org-attach-url
 8:              org-attach-set-directory
 9:              org-attach-sync)
10:   :config
11:   (unless org-attach-id-dir
12:     (setq-default org-attach-id-dir (expand-file-name ".attach/" org-directory)))
13:   (with-eval-after-load 'projectile
14:     (add-to-list 'projectile-globally-ignored-directories org-attach-id-dir))
15:   :custom
16:   (org-attach-auto-tag nil))

org-agenda

 1: (use-package org-agenda
 2:   :after org
 3:   :custom
 4:   (org-agenda-files (list (concat org-directory "/")))
 5:   (org-agenda-file-regexp "\\`[^.].*\\.org\\|[0-9]+$\\'")
 6:   (org-agenda-include-inactive-timestamps t)
 7:   (org-agenda-window-setup 'only-window)
 8:   (org-stuck-projects '("+{project*}-killed-Archives/-DONE-KILL-DELEGATED"
 9:                         ("TODO" "NEXT" "IDEA" "PROG")
10:                         nil ""))
11:   :config
12:   (with-eval-after-load 'evil
13:     (evil-set-initial-state #'org-agenda-mode 'normal))
14:   (setq org-agenda-custom-commands
15:         `(("w" "Work Agenda and all TODOs"
16:            ((agenda ""
17:                     ((org-agenda-span 1)
18:                      (org-agenda-start-on-weekday t)
19:                      (org-agenda-block-separator nil)
20:                      (org-agenda-use-time-grid t)
21:                      (org-agenda-day-face-function (lambda (date) 'org-agenda-date))
22:                      (org-agenda-format-date "%A %-e %B %Y")
23:                      (org-agenda-overriding-header "\nToday\n")))
24:             (tags-todo "TODO=\"TODO\"|\"NEXT\""
25:                        ((org-agenda-block-separator nil)
26:                         (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done))
27:                         (org-agenda-use-time-grid nil)
28:                         (org-agenda-overriding-header "\nIncomplete\n")))
29:             (agenda ""
30:                     ((org-agenda-span 7)
31:                      (org-agenda-start-on-weekday 1)
32:                      (org-agenda-block-separator nil)
33:                      (org-agenda-use-time-grid nil)
34:                      (org-agenda-overriding-header "\nWeekly\n"))))
35:            ((org-agenda-tag-filter-preset '("-personal" "-home"))))
36:           ("h" "Home Agenda and all personal TODOs"
37:            ((agenda ""
38:                     ((org-agenda-span 1)
39:                      (org-agenda-start-on-weekday t)
40:                      (org-agenda-block-separator nil)
41:                      (org-agenda-use-time-grid t)
42:                      (org-agenda-day-face-function (lambda (date) 'org-agenda-date))
43:                      (org-agenda-format-date "%A %-e %B %Y")
44:                      (org-agenda-overriding-header "\nToday\n")))
45:             (tags-todo "TODO=\"TODO\"|\"NEXT\""
46:                        ((org-agenda-block-separator nil)
47:                         (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done))
48:                         (org-agenda-use-time-grid nil)
49:                         (org-agenda-overriding-header "\nIncomplete\n")))
50:             (agenda ""
51:                     ((org-agenda-span 7)
52:                      (org-agenda-start-on-weekday 1)
53:                      (org-agenda-block-separator nil)
54:                      (org-agenda-use-time-grid nil)
55:                      (org-agenda-overriding-header "\nWeekly\n"))))
56:            ((org-agenda-tag-filter-preset '("+personal")))))))

org-clock

 1: (use-package org-clock
 2:   :after org
 3:   :commands org-clock-save
 4:   :hook (kill-emacs . org-clock-save)
 5:   :custom
 6:   (org-persist 'history)
 7:   (org-clock-in-resume t)
 8:   (org-clock-out-remove-zero-time-clocks t)
 9:   (org-clock-history-length 20)
10:   (org-show-notification-handler "notify-send")
11:   (org-agenda-skip-scheduled-if-deadline-is-shown t)
12:   :config
13:   (org-clock-persistence-insinuate))

org-timer

1: (use-package org-timer
2:   :config
3:   (setq org-timer-format "Timer :: %s"))

org-eldoc

1: (use-package org-eldoc
2:   :after org org-contrib
3:   :config
4:   (puthash "org" #'ignore org-eldoc-local-functions-cache)
5:   (puthash "plantuml" #'ignore org-eldoc-local-functions-cache)
6:   (puthash "python" #'python-eldoc-function org-eldoc-local-functions-cache)
7:   :custom
8:   (org-eldoc-breadcrumb-separator " → "))

org-superstar   external

 1: (use-package org-superstar
 2:   :ensure
 3:   :hook (org-mode . org-superstar-mode)
 4:   :custom
 5:   (org-superstar-leading-bullet ?\s)
 6:   (org-superstar-leading-fallback ?\s)
 7:   (org-hide-leading-stars nil)
 8:   (org-indent-mode-turns-on-hiding-stars nil)
 9:   (org-superstar-todo-bullet-alist
10:    '(("TODO" . 9744)
11:      ("[ ]"  . 9744)
12:      ("DONE" . 9745)
13:      ("[X]"  . 9745)))
14:   :config
15:   (org-superstar-configure-like-org-bullets))

org-fancy-priority   external

1: (use-package org-fancy-priorities ; priority icons
2:   :ensure
3:   :defer t
4:   :hook (org-mode . org-fancy-priorities-mode)
5:   :hook (org-agenda-mode . org-fancy-priorities-mode)
6:   :custom
7:   (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))

Other Tools

make-mode

1: (use-package make-mode
2:   :config
3:   (add-hook 'makefile-mode-hook 'indent-tabs-mode))

executable

1: (use-package executable
2:   :hook
3:   (after-save . executable-make-buffer-file-executable-if-script-p))

pinentry

1: (use-package pinentry
2:   :ensure
3:   :defer t
4:   :config
5:   (pinentry-start))

pass

 1: (use-package password-store
 2:   :ensure
 3:   :defer t
 4:   :config
 5:   (setq password-store-password-length 12))
 6: 
 7: (use-package password-store-otp
 8:   :ensure
 9:   :defer t
10:   :after password-store)
11: 
12: (use-package pass
13:   :ensure
14:   :defer t)
15: 
16: (use-package auth-source-pass
17:   :init
18:   (auth-source-pass-enable))

rg

Packaged as ripgrep in archlinux. The :if keyword won't load this if the executable not found.

1: (use-package rg
2:   :if (executable-find "rg")
3:   :ensure
4:   :defer t)

Dired

Stands for Directory Editor (I guess), is a builtin file manager for Emacs.

dired

 1: (use-package dired
 2:   :commands dired-jump
 3:   :init
 4:   (setq dired-dwim-target t ; guess a default target directory
 5:         dired-hide-details-hide-symlink-targets nil ; don't hide symbolic link targets
 6:         dired-auto-revert-buffer #'dired-buffer-stale-p ; revert stale only
 7:         dired-recursive-copies 'always ; always copy recursively
 8:         dired-recursive-deletes 'top ; ask only for top-level
 9:         dired-create-destination-dirs 'ask
10:         dired-clean-confirm-killing-deleted-buffers nil))

image-dired

1: (use-package image-dired
2:   :config
3:   (setq image-dired-thumb-size 150))

dired-x

 1: (use-package dired-x
 2:   :hook (dired-mode . dired-omit-mode)
 3:   :config
 4:   (setq dired-omit-files
 5:         (concat dired-omit-files
 6:                 "\\|^\\.DS_Store\\'"
 7:                 "\\|^\\.project\\(?:ile\\)?\\'"
 8:                 "\\|^\\.\\(?:svn\\|git\\)\\'"
 9:                 "\\|^\\.ccls-cache\\'"
10:                 "\\|\\(?:\\.js\\)?\\.meta\\'"
11:                 "\\|\\.\\(?:elc\\|o\\|pyo\\|swp\\|class\\)\\'"))
12:   ;; Disable the prompt about whether I want to kill the Dired buffer for a
13:   ;; deleted directory. Of course I do!
14:   (setq dired-clean-confirm-killing-deleted-buffers nil)
15:   (let ((cmd "xdg-open"))
16:     (setq dired-guess-shell-alist-user
17:           `(("\\.\\(?:docx\\|pdf\\|djvu\\|eps\\)\\'" ,cmd)
18:             ("\\.\\(?:jpe?g\\|png\\|gif\\|xpm\\)\\'" ,cmd)
19:             ("\\.\\(?:xcf\\)\\'" ,cmd)
20:             ("\\.csv\\'" ,cmd)
21:             ("\\.tex\\'" ,cmd)
22:             ("\\.\\(?:mp4\\|mkv\\|avi\\|flv\\|rm\\|rmvb\\|ogv\\)\\(?:\\.part\\)?\\'" ,cmd)
23:             ("\\.\\(?:mp3\\|flac\\)\\'" ,cmd)
24:             ("\\.html?\\'" ,cmd)
25:             ("\\.md\\'" ,cmd)))))

fd-dired   external

Needs an external package fd, or fd-find

1: (use-package fd-dired
2:   :ensure
3:   :if (executable-find "fd")
4:   :defer t
5:   :init
6:   (global-set-key [remap find-dired] #'fd-dired))

dired-git-info

 1: (use-package dired-git-info
 2:   :ensure
 3:   :defer t
 4:   ;; :hook
 5:   ;; (dired-after-readin . dired-git-info-auto-enable)
 6:   :config
 7:   ;; (setq +dired--git-info-p (bound-and-true-p dired-git-info-mode))
 8:   ;; (when +dired--git-info-p
 9:   ;;   (dired-git-info-mode -1))
10:   (setq dgi-auto-hide-details-p nil))

dired-aux

1: (use-package dired-aux
2:   :config
3:   (setq dired-create-destination-dirs 'ask
4:         dired-vc-rename-file t))

dired-rsync

1: (use-package dired-rsync
2:   :ensure
3:   :defer t)

diredfl

1: (use-package diredfl
2:   :ensure
3:   :defer t
4:   :hook (dired-mode . diredfl-global-mode))

TODO Treemacs

treemacs

  1: (use-package treemacs
  2:   :ensure
  3:   :hook ((treemacs-mode . (lambda () (hs-minor-mode -1))))
  4:   :config
  5:   (setq treemacs-hide-gitignored-files-mode t
  6:         treemacs-no-png-images t
  7:         treemacs-silent-refresh t
  8:         treemacs-sorting 'mod-time-desc
  9:         treemacs-python-executable (executable-find "python3")
 10:         treemacs-collapse-dirs (if treemacs-python-executable 3 0)
 11:         treemacs-deferred-git-apply-delay 0.5
 12:         treemacs-directory-name-transformer #'identity
 13:         treemacs-display-in-side-window t
 14:         treemacs-eldoc-display 'simple
 15:         treemacs-file-event-delay 2000
 16:         treemacs-file-extension-regex treemacs-last-period-regex-value
 17:         treemacs-file-follow-delay 0.2
 18:         treemacs-file-name-transformer #'identity
 19:         treemacs-follow-after-init t
 20:         treemacs-expand-after-init t
 21:         treemacs-find-workspace-method 'find-for-file-or-pick-first
 22:         treemacs-git-command-pipe ""
 23:         treemacs-goto-tag-strategy 'refetch-index
 24:         treemacs-header-scroll-indicators '(nil . "^^^^^^")
 25:         treemacs-hide-dot-git-directory t
 26:         treemacs-indentation 2
 27:         treemacs-indentation-string " "
 28:         treemacs-is-never-other-window nil
 29:         treemacs-max-git-entries 5000
 30:         treemacs-missing-project-action 'ask
 31:         treemacs-move-forward-on-expand nil
 32:         treemacs-no-delete-other-windows t
 33:         treemacs-project-follow-cleanup nil
 34:         treemacs-persist-file (expand-file-name ".cache/treemacs-persist" user-emacs-directory)
 35:         treemacs-position 'left
 36:         treemacs-read-string-input 'from-child-frame
 37:         treemacs-recenter-distance 0.1
 38:         treemacs-recenter-after-file-follow nil
 39:         treemacs-recenter-after-tag-follow nil
 40:         treemacs-recenter-after-project-jump 'always
 41:         treemacs-recenter-after-project-expand 'on-distance
 42:         treemacs-litter-directories '("/node_modules" "/.venv" "/.cask")
 43:         treemacs-project-follow-into-home nil
 44:         treemacs-show-cursor nil
 45:         treemacs-show-hidden-files t
 46:         treemacs-silent-filewatch t
 47:         treemacs-select-when-already-in-treemacs 'move-back
 48:         treemacs-space-between-root-nodes t
 49:         treemacs-tag-follow-cleanup t
 50:         treemacs-tag-follow-delay 1.5
 51:         treemacs-text-scale nil
 52:         treemacs-user-mode-line-format nil
 53:         treemacs-user-header-line-format nil
 54:         treemacs-wide-toggle-width 70
 55:         treemacs-width 35
 56:         treemacs-width-increment 1
 57:         treemacs-width-is-initially-locked t
 58:         treemacs-workspace-switch-cleanup nil)
 59:   (treemacs-peek-mode 1)
 60:   (treemacs-filewatch-mode t)
 61:   (treemacs-follow-mode t)
 62:   (treemacs-fringe-indicator-mode 'always)
 63:   (when treemacs-python-executable
 64:     (treemacs-git-commit-diff-mode t))
 65:   (pcase (cons (not (null (executable-find "git")))
 66:                (not (null treemacs-python-executable)))
 67:     (`(t . t)
 68:      (treemacs-git-mode 'deferred))
 69:     (`(t . _)
 70:      (treemacs-git-mode 'simple)))
 71:   :bind
 72:   (:map global-map
 73:         ("M-0"       . treemacs-select-window)
 74:         ("C-x t 1"   . treemacs-delete-other-windows)
 75:         ("C-x t t"   . treemacs)
 76:         ("C-x t d"   . treemacs-select-directory)
 77:         ("C-x t B"   . treemacs-bookmark)
 78:         ("C-x t C-t" . treemacs-find-file)
 79:         ("C-x t M-t" . treemacs-find-tag))
 80:   :general
 81:   (+config/leader-tree
 82:     "t" 'treemacs
 83:     "p" 'treemacs-add-and-display-current-project-exclusively)
 84: 
 85:   (general-define-key
 86:    :keymaps 'treemacs-mode-map
 87:    "[mouse-1]" 'treemacs-single-click-expand-action)
 88: 
 89:   (general-nvmap
 90:     :keymaps 'treemacs-mode-map
 91:     "gr" '(treemacs-refresh :wk "refresh tree")
 92:     "zm" '(:ignore t :wk "move")
 93:     "zmf" '(treemacs-move-file :wk "move file")
 94:     "zmd" '(treemacs-move-project-down :wk "move project down")
 95:     "zmu" '(treemacs-move-project-up :wk "move project up")
 96:     "zr" '(:ignore t :wk "rename")
 97:     "zrf" '(treemacs-rename-file :wk "rename file")
 98:     "zrp" '(treemacs-rename-project :wk "rename project")
 99:     "zrw" '(treemacs-rename-workspace :wk "rename workspace")
100:     "zc" '(:ignore t :wk "create/clean")
101:     "zcC" '(treemacs-cleanup-litter :wk "cleanup litter")
102:     "zcd" '(treemacs-create-dir :wk "create directory")
103:     "zcf" '(treemacs-create-file :wk "create file")
104:     "zd" '(treemacs-delete-file :wk "delete file")))

treemacs-projectile

1: (use-package treemacs-projectile
2:   :ensure
3:   :after treemacs)

treemacs-icons-dired

1: (use-package treemacs-icons-dired
2:   :ensure
3:   :after treemacs
4:   :hook (dired-mode . treemacs-icons-dired-enable-once))

treemacs-magit

1: (use-package treemacs-magit
2:   :ensure
3:   :after treemacs magit)

treemacs-evil

1: (use-package treemacs-evil
2:   :ensure
3:   :after treemacs evil)

lsp-treemacs

emacs-lsp-treemacs-symbol.png

Figure 10: symbols in lsp-treemacs

 1: (use-package lsp-treemacs
 2:   :ensure
 3:   :after treemacs lsp
 4:   :config
 5:   (lsp-treemacs-sync-mode 1)
 6:   :general
 7:   (general-define-key
 8:    :keymaps 'treemacs-mode-map
 9:    "S" 'lsp-treemacs-symbols
10:    "X" 'lsp-treemacs-errors-list
11:    "Y" 'lsp-treemacs-call-hierarchy))

treemacs-perspective

1: (use-package treemacs-perspective
2:   :ensure
3:   :after treemacs perspective
4:   :config
5:   (treemacs-set-scope-type 'Perspectives))

treemacs-tab-bar

1: (use-package treemacs-tab-bar
2:   :ensure
3:   :after treemacs)

treemacs-nerd-icons

1: (use-package treemacs-nerd-icons
2:   :ensure
3:   :after treemacs
4:   :config
5:   (treemacs-load-theme "nerd-icons"))

Mail

notmuch   external

 1: (use-package notmuch
 2:   :ensure
 3:   :if (executable-find "notmuch")
 4:   :defer t
 5:   :commands (notmuch)
 6:   :hook
 7:   (message-setup . mml-secure-sign-pgpmime)
 8:   :config
 9:   (global-set-key (kbd "<XF86Mail>") 'notmuch)
10:   (setq notmuch-fcc-dirs nil
11:         notmuch-search-result-format
12:         '(("date" . "%12s ")
13:           ("count" . "%-7s ")
14:           ("authors" . "%-30s ")
15:           ("subject" . "%-72s ")
16:           ("tags" . "(%s)"))
17:         notmuch-tag-formats
18:         '(("unread"
19:            (propertize tag 'face 'notmuch-tag-unread))
20:           ("flagged"
21:            (propertize tag 'face 'notmuch-tag-flagged)
22:            (notmuch-tag-format-image-data tag
23:                                           (notmuch-tag-star-icon))))
24:         notmuch-tagging-keys
25:         '(("a" notmuch-archive-tags "Archive")
26:           ("u" notmuch-show-mark-read-tags "Mark read")
27:           ("f" ("+flagged") "Flag")
28:           ("s" ("+spam" "-inbox") "Mark as spam")
29:           ("d" ("+deleted" "-inbox") "Delete"))
30:         notmuch-saved-searches
31:         '((:name "flagged" :query "tag:flagged" :key "f")
32:           (:name "sent" :query "tag:sent" :key "s")
33:           (:name "drafts"  :query "tag:draft" :key "d")
34:           (:name "all mail" :query "*" :key "a")
35:           (:name "unread" :query "tag:unread" :key "u")
36:           (:name "zum" :query "tag:zum" :key "z")
37:           (:name "mkn" :query "tag:mkn" :key "c")
38:           (:name "gmail" :query "tag:gmail" :key "g")
39:           (:name "hotmail" :query "tag:hotmail" :key "h")
40:           (:name "yahoo" :query "tag:yahoo" :key "h")
41:           (:name "ymail" :query "tag:ymail" :key "m")
42:           (:name "Today"
43:                  :query "date:today AND NOT tag:spam AND NOT tag:bulk"
44:                  :key "T"
45:                  :search-type 'tree
46:                  :sort-order 'newest-first)
47:           (:name "This Week"
48:                  :query "date:weeks AND NOT tag:spam AND NOT tag:bulk"
49:                  :key "W"
50:                  :search-type 'tree
51:                  :sort-order 'newest-first)
52:           (:name "This Month"
53:                  :query "date:months AND NOT tag:spam AND NOT tag:bulk"
54:                  :key "M"
55:                  :search-type 'tree
56:                  :sort-order 'newest-first)
57:           (:name "flagged"
58:                  :query "tag:flagged AND NOT tag:spam AND NOT tag:bulk"
59:                  :key "f"
60:                  :search-type 'tree
61:                  :sort-order 'newest-first)
62:           (:name "spam" :query "tag:spam"))
63:         notmuch-archive-tags '("-inbox" "-unread"))
64:   (setq-default notmuch-search-oldest-first nil)
65:   (if (executable-find "gpg2")
66:       (setq notmuch-crypto-gpg-program "gpg2")
67:     (setq notmuch-crypto-gpg-program "gpg"))
68:   (setq notmuch-crypto-process-mime t
69:         mml-secure-openpgp-sign-with-sender t)
70:   (define-key notmuch-show-mode-map "S"
71:               (lambda ()
72:                 "Mark message as spam"
73:                 (interactive)
74:                 (notmuch-show-tag (list +spam -new))))
75:   :general
76:   (+config/leader-menu! "mail" "M-m"
77:     "m" '(notmuch :wk "Notmuch Mail"))
78: 
79:   (+config/leader-mail
80:     "m" '(notmuch :wk "open notmuch mail")
81:     "M" '(compose-mail :wk "new mail"))
82: 
83:   (general-nmap 'notmuch-common-keymap
84:     "gr" 'notmuch-refresh-this-buffer
85:     "gR" 'notmuch-poll-and-refresh-this-buffer))

notmuch-indicator   external

1: (use-package notmuch-indicator
2:   :ensure
3:   :config
4:   (setq notmuch-indicator-args
5:         '((:terms "tag:unread and tag:inbox" :label "U" :label-face success)))
6:   (notmuch-indicator-mode))

consult-notmuch   external

1: (use-package consult-notmuch
2:   :ensure
3:   :after consult
4:   :config
5:   (add-to-list 'consult-buffer-sources 'consult-notmuch-buffer-source))

ol-notmuch   external

1: (use-package ol-notmuch
2:   :ensure)

notmuch-maildir   external

1: (use-package notmuch-maildir
2:   :ensure
3:   :config
4:   (notmuch-maildir-inject-section))

message

1: (use-package message
2:   :custom
3:   (message-directory (expand-file-name ".mail" (getenv "HOME")))
4:   (message-sendmail-envelope-from 'header))

sendmail

1: (use-package sendmail
2:   :custom
3:   (mail-specify-envelope-from t)
4:   (mail-envelope-from 'header)
5:   (send-mail-function 'sendmail-send-it)
6:   (sendmail-program (executable-find "msmtp")))

Programming languages

Lisp

  • lispy
    1: (use-package lispy
    2:   :ensure
    3:   :hook ((emacs-lisp-mode . lispy-mode)
    4:          (lisp-mode . lispy-mode)
    5:          (scheme-mode . lispy-mode)
    6:          (geiser-mode . lispy-mode)))
    
  • lispyville
    1: (use-package lispyville
    2:   :ensure
    3:   :hook (lispy-mode . lispyville-mode))
    
  • Emacs-lisp
    • elisp-mode
       1: (when (locate-library "aggressive-indent")
       2:   (add-hook 'lisp-mode-hook #'aggressive-indent-mode)
       3:   (add-hook 'clojure-mode-hook #'aggressive-indent-mode)
       4:   (add-hook 'scheme-mode-hook #'aggressive-indent-mode))
       5: 
       6: ;;;; emacs-lisp -n
       7: (use-package elisp-mode
       8:   :diminish emacs-lisp-mode
       9:   :diminish elisp-mode
      10:   :diminish outline-minor-mode
      11:   :diminish lisp-data-mode
      12:   :mode ("\\.Cask\\'" . emacs-lisp-mode)
      13:   :ensure nil
      14:   :hook (emacs-lisp-mode . (lambda ()
      15:                              (outline-minor-mode)
      16:                              (rainbow-delimiters-mode))))
      
      • ielm
         1: (use-package ielm
         2:   :ensure nil
         3:   ;;:hook (ielm-mode . (turn-on-smartparens-mode))
         4:   :config
         5:   (setq ielm-font-lock-keywords
         6:         (append '(("\\(^\\*\\*\\*[^*]+\\*\\*\\*\\)\\(.*$\\)"
         7:                    (1 font-lock-comment-face)
         8:                    (2 font-lock-constant-face)))
         9:                 (when (require 'highlight-numbers nil t)
        10:                   (highlight-numbers--get-regexp-for-mode 'emacs-lisp-mode))
        11:                 (cl-loop for (matcher . match-highlights)
        12:                          in (append lisp-el-font-lock-keywords-2
        13:                                     lisp-cl-font-lock-keywords-2)
        14:                          collect
        15:                          `((lambda (limit)
        16:                              (when ,(if (symbolp matcher)
        17:                                         `(,matcher limit)
        18:                                       `(re-search-forward ,matcher limit t))
        19:                                ;; Only highlight matches after the prompt
        20:                                (> (match-beginning 0) (car comint-last-prompt))
        21:                                ;; Make sure we're not in a comment or string
        22:                                (let ((state (syntax-ppss)))
        23:                                  (not (or (nth 3 state)
        24:                                           (nth 4 state))))))
        25:                            ,@match-highlights)))))
        
    • macrostep   external
      1: (use-package macrostep
      2:   :ensure
      3:   :defer t
      4:   :bind (:map emacs-lisp-mode-map
      5:               ("C-c e" . macrostep-expand)))
      
  • Common lisp
     1: ;;;; common-lisp
     2: (when (file-directory-p (expand-file-name "site-lisp/sly-stepper" user-emacs-directory))
     3:   (add-to-list 'load-path (expand-file-name "site-lisp/sly-stepper" user-emacs-directory)))
     4: (when (file-directory-p (expand-file-name "site-lisp/sly-quicklisp" user-emacs-directory))
     5:   (add-to-list 'load-path (expand-file-name "site-lisp/sly-quicklisp" user-emacs-directory)))
     6: (when (file-directory-p (expand-file-name "site-lisp/sly-macrostep" user-emacs-directory))
     7:   (add-to-list 'load-path (expand-file-name "site-lisp/sly-macrostep" user-emacs-directory)))
     8: 
     9: (defvar inferior-lisp-program "sbcl")
    10: (when (executable-find "ros")
    11:   (setq inferior-lisp-program "ros -Q run"))
    12: 
    13: (add-hook 'lisp-mode-hook #'rainbow-delimiters-mode)
    
    • sly   external
      1: (use-package sly
      2:   :ensure
      3:   :commands sly-autoloads
      4:   :hook ((lisp-mode-local-vars . rainbow-delimiters-mode)
      5:          (lisp-mode . sly-editing-mode))
      6:   :config
      7:   (require 'sly-autoloads))
      
  • clojure
    • cider   external
      1: ;;;; clojure
      2: (use-package cider
      3:   :ensure
      4:   :defer t)
      
    • clj-refactor   external
      1: (use-package clj-refactor
      2:   :ensure
      3:   :defer t
      4:   :hook (clojure-mode . +config/clojure-mode-hook)
      5:   :config
      6:   (defun +config/clojure-mode-hook ()
      7:     (clj-refactor-mode 1)
      8:     ;; This choice of keybinding leaves cider-macroexpand-1 unbound
      9:     (cljr-add-keybindings-with-prefix "C-c r")))
      
  • Scheme
    • geiser   external
       1: ;;;; scheme
       2: (use-package geiser
       3:   :ensure
       4:   :defer t
       5:   :diminish geiser-autodoc-mode
       6:   ;; :hook (geiser-repl-mode . turn-on-smartparens-strict-mode)
       7:   :init
       8:   (setq geiser-autodoc-identifier-format "%s → %s"
       9:         geiser-repl-per-project-p t
      10:         geiser-repl-history-filename (concat user-emacs-directory "geiser-history")))
      
    • geiser-guile   external
       1: (use-package geiser-guile
       2:   :ensure
       3:   :defer t
       4:   :config
       5:   (let ((nonguix-path (expand-file-name "Projects/guix/nonguix"
       6:                                         (getenv "HOME")))
       7:         (personal-path (expand-file-name "Projects/guix/devel/src"
       8:                                          (getenv "HOME"))))
       9:     (when (file-directory-p nonguix-path)
      10:       (add-to-list 'geiser-guile-load-path nonguix-path))
      11:     (when (file-directory-p personal-path)
      12:       (add-to-list 'geiser-guile-load-path personal-path))))
      
    • macrostep-geiser   external
      1: (use-package macrostep-geiser
      2:   :ensure
      3:   :defer t
      4:   :after geiser-mode geiser-repl
      5:   :hook ((geiser-mode geiser-repl-mode) . macrostep-geiser-setup)
      6:   :bind (:map geiser-mode-map
      7:               ("C-c e" . macrostep-expand)))
      

C and C++

  • cc-mode   builtin
     1: (use-package cc-mode
     2:   :mode ("\\.mm\\'" . objc-mode)
     3:   :mode ("\\.h\\'" . +cc-c-c++-objc-mode)
     4:   :hook (c-mode-common . rainbow-delimiters-mode)
     5:   ;; :hook (c++-mode-local-vars . c++-ts-mode)
     6:   ;; :hook (c-mode-common . c-ts-base-mode)
     7:   ;; :hook (cmake-mode-local-vars . cmake-ts-mode)
     8:   :config
     9:   (setq c-basic-offset tab-width
    10:         c-backspace-function #'delete-backward-char)
    11:   (with-eval-after-load 'ffap
    12:     (add-to-list 'ffap-alist '(c-mode . ffap-c-mode))))
    

XML

  • nxml-mode
    1: (use-package nxml-mode
    2:   :mode "\\.p\\(?:list\\|om\\)\\'" ; plist, pom
    3:   :mode "\\.xs\\(?:d\\|lt\\)\\'"   ; xslt, xsd
    4:   :mode "\\.rss\\'"
    5:   :config
    6:   (setq nxml-slash-auto-complete-flag t
    7:         nxml-auto-insert-xml-declaration-flag t))
    

YAML

  • yaml-mode   external
     1: (use-package yaml-mode
     2:   :ensure
     3:   :config
     4:   (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
     5:   (add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode))
     6:   (setq tab-width 2)
     7:   ;; (when (treesit-available-p)
     8:   ;;   (add-to-list 'major-mode-remap-alist '(yaml-mode . yaml-ts-mode)))
     9:   :hook
    10:   ((yaml-mode . (lambda ()
    11:                   (define-key yaml-mode-map "\C-m" 'newline-and-indent)))
    12:    (yaml-mode . (lambda ()
    13:                   (run-hooks 'prog-mode-hook)))))
    

TOML

  • toml-mode   external
     1: (use-package toml-mode
     2:   :ensure
     3:   :mode
     4:   ("\\.toml\\'" . toml-mode)
     5:   :config
     6:   ;; (when (treesit-available-p)
     7:   ;;    (add-to-list 'major-mode-remap-alist '(toml-mode . toml-ts-mode)))
     8:   (with-eval-after-load 'lsp-mode
     9:     (setq lsp-toml-command (executable-find "taplo")))
    10:   (add-to-list 'lsp-language-id-configuration '("\\.toml$" . "toml")))
    

Lua

  • lua-mode   external
    1: (use-package lua-mode
    2:   :ensure
    3:   :defer t
    4:   :config
    5:   (with-eval-after-load 'lsp-mode
    6:     (setq lsp-lua-hint-enable t
    7:           lsp-lua-hint-set-type t)))
    

Jinja2

  • jinja2-mode   external
     1: (use-package jinja2-mode
     2:   :ensure
     3:   :defer t
     4:   :config
     5:   ;; The default behavior is to reindent the whole buffer on save. This is
     6:   ;; disruptive and imposing. There are indentation commands available; the user
     7:   ;; can decide when they want their code reindented.
     8:   (setq jinja2-enable-indent-on-save nil)
     9:   (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
    10:   (add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode)))
    

Json

  • json-mode
    1: (use-package json-mode
    2:   :ensure)
    

Web

  • web-mode   external
     1: (defun +config/django-web-mode ()
     2:   "Set web-engine to django if `manage.py' detected in `projectile-project-root'."
     3:   (if (projectile-project-p)
     4:       (if (file-exists-p (concat (projectile-project-root) "manage.py"))
     5:           (web-mode-set-engine "django"))))
     6: 
     7: (defun +config/web-mode-fix-js-comment ()
     8:   "Fix comment handling in `web-mode' for JavaScript (from `doom')."
     9:   (when (member web-mode-content-type '("javascript" "jsx"))
    10:     ;; For some reason the default is to insert HTML comments even
    11:     ;; in JavaScript.
    12:     (setq-local comment-start "//")
    13:     (setq-local comment-end "")
    14:     ;; Needed since otherwise the default value generated by
    15:     ;; `comment-normalize-vars' will key off the syntax and think
    16:     ;; that a single "/" starts a comment, which completely borks
    17:     ;; auto-fill.
    18:     (setq-local comment-start-skip "// *")))
    19: 
    20: (use-package web-mode
    21:   :ensure
    22:   :defer t
    23:   :mode "\\.[px]?html?\\'"
    24:   :mode "\\.\\(?:tpl\\|blade\\)\\(?:\\.php\\)?\\'"
    25:   :mode "\\.erb\\'"
    26:   :mode "\\.[lh]?eex\\'"
    27:   :mode "\\.jsp\\'"
    28:   :mode "\\.as[cp]x\\'"
    29:   :mode "\\.ejs\\'"
    30:   :mode "\\.hbs\\'"
    31:   :mode "\\.mustache\\'"
    32:   :mode "\\.svelte\\'"
    33:   :mode "\\.twig\\'"
    34:   :mode "\\.jinja2?\\'"
    35:   :mode "\\.eco\\'"
    36:   :mode "wp-content/themes/.+/.+\\.php\\'"
    37:   :mode "templates/.+\\.php\\'"
    38:   :init
    39:   ;; If the user has installed `vue-mode' then, by appending this to
    40:   ;; `auto-mode-alist' rather than prepending it, its autoload will have
    41:   ;; priority over this one.
    42:   (add-to-list 'auto-mode-alist '("\\.vue\\'" . web-mode) 'append)
    43:   :mode "\\.vue\\'"
    44:   :config
    45:   (setq web-mode-markup-indent-offset 2
    46:         web-mode-enable-auto-closing t
    47:         web-mode-auto-close-style 1
    48:         web-mode-css-indent-offset 2
    49:         web-mode-code-indent-offset 2
    50:         web-mode-enable-auto-pairing nil
    51:         web-mode-enable-block-face t
    52:         web-mode-enable-comment-interpolation t
    53:         web-mode-enable-heredoc-fontification t
    54:         web-mode-enable-css-colorization t
    55:         web-mode-enable-part-face t
    56:         web-mode-enable-current-element-highlight t
    57:         web-mode-enable-current-column-highlight t
    58:         web-mode-style-padding 1
    59:         web-mode-script-padding 1
    60:         web-mode-block-padding 0
    61:         web-mode-comment-style 2
    62:         web-mode-enable-curly-brace-indentation t
    63:         web-mode-enable-auto-quoting nil
    64:         web-mode-engines-alist
    65:         '(("php" . "\\.phtml\\'")
    66:           ("blade" . "\\.blade\\'")
    67:           ("elixir" . "\\.eex\\'")
    68:           ("phoenix" . "\\.[lh]eex\\'")))
    69:   ;; web-mode-extra-auto-pairs
    70:   ;; '(("erb" . (("beg" "end")))
    71:   ;;   ("php" . (("beg" "end")))))
    72:   (with-eval-after-load 'smartparens
    73:     (sp-local-pair 'web-mode "<" nil :actions :rem)
    74:     (sp-local-pair 'web-mode "{%" " %}")
    75:     (sp-local-pair 'web-mode "{{" " }}")
    76:     (sp-local-pair 'web-mode "<!--" " -->")
    77:     )
    78:   (defun +config/web-mode-hook ()
    79:     "Hooks for Web mode."
    80:     (local-set-key (kbd "RET") 'newline-and-indent))
    81:   ;; Use // instead of /* as the default comment delimited in JS
    82:   (with-eval-after-load 'web-mode
    83:     (setf (alist-get "javascript" web-mode-comment-formats nil nil #'equal)
    84:           "//"))
    85:   :hook ((html-mode-local-vars-hook
    86:           mhtml-mode-local-vars-hook) . tree-sitter)
    87:   :hook (web-mode . +config/django-web-mode)
    88:   :general
    89:   (general-nvmap
    90:     :keymaps 'web-mode-map
    91:     "gn" 'web-mode-navigate)
    92:   (general-vmap
    93:    :keymaps 'web-mode-map
    94:     "gs" 'web-mode-surround))
    
  • emmet-mode   external
     1: (use-package emmet-mode
     2:   :ensure
     3:   :defer t
     4:   :hook (css-mode web-mode html-mode haml-mode nxml-mode rjsx-mode reason-mode)
     5:   :config
     6:   (when (require 'yasnippet nil t)
     7:     (add-hook 'emmet-mode-hook #'yas-minor-mode-on))
     8:   (setq emmet-move-cursor-between-quotes t)
     9:   :general
    10:   (general-vmap
    11:     :keymaps 'emmet-mode-keymap
    12:     "TAB" 'emmet-wrap-with-markup)
    13:   (general-def
    14:     :keymaps 'emmet-mode-keymap
    15:     "M-E" 'emmet-expand-line))
    
  • skewer-mode   external
    1: (use-package skewer-mode
    2:   :ensure
    3:   :defer t
    4:   :hook ((web-mode . skewer-html-mode)
    5:          (js2-mode . skewer-mode)))
    
  • lsp-tailwindcss   external
    1: (use-package lsp-tailwindcss
    2:   :ensure
    3:   :init
    4:   (setq lsp-tailwindcss-add-on-mode t))
    
  • sass-mode   external
    1: (use-package sass-mode
    2:   :ensure
    3:   :defer t
    4:   :hook (scss-mode . rainbow-mode))
    
  • css-eldoc   external
    1: (use-package css-eldoc
    2:   :ensure
    3:   :defer t
    4:   :commands turn-on-css-eldoc
    5:   ;;add a hook if you want always to see the selector options in the minibuffer
    6:   :config
    7:   (add-hook 'css-mode-hook 'turn-on-css-eldoc)
    8:   (add-hook 'scss-mode-hook 'turn-on-css-eldoc))
    
  • com-css-sort   external
    1: (use-package com-css-sort
    2:   :ensure
    3:   :defer t
    4:   :commands (com-css-sort com-css-sort-attributes-block com-css-sort-attributes-document)
    5:   :config
    6:   (setq com-css-sort-sort-type 'alphabetic-sort))
    
  • css-mode
    1: (use-package css-mode
    2:   :hook ((css-mode
    3:           stylus-mode) . rainbow-mode)
    4:   :hook (css-mode-local-vars . tree-sitter)
    5:   :config
    6:   (with-eval-after-load 'skewer-mode
    7:     (add-hook 'css-mode-hook 'skewer-css-mode)))
    
  • javascript
      1: (defvar +javascript-npm-conf (make-hash-table :test 'equal))
      2: 
      3: ;;;###autoload
      4: (defun +javascript-npm-conf (&optional project-root refresh-p)
      5:   "Retrieves an alist of this project's 'package.json'. If REFRESH-P is non-nil
      6: ignore the cache."
      7:   (let ((project-root (or project-root (doom-project-root))))
      8:     (or (and (not refresh-p)
      9:              (gethash project-root +javascript-npm-conf))
     10:         (let ((package-file (expand-file-name "package.json" project-root)))
     11:           (when-let (json (and (file-exists-p package-file)
     12:                                (require 'json)
     13:                                (json-read-file package-file)))
     14:             (puthash project-root json +javascript-npm-conf))))))
     15: 
     16: ;;;###autoload
     17: (defun +javascript-npm-dep-p (packages &optional project-root refresh-p)
     18:   (when-let (data (and (bound-and-true-p +javascript-npm-mode)
     19:                        (+javascript-npm-conf project-root refresh-p)))
     20:     (let ((deps (append (cdr (assq 'dependencies data))
     21:                         (cdr (assq 'devDependencies data)))))
     22:       (cond ((listp packages)
     23:              (funcall (if (eq (car packages) 'and)
     24:                           #'cl-every
     25:                         #'cl-some)
     26:                       (lambda (pkg) (assq pkg deps))
     27:                       (if (listp packages) packages (list packages))))
     28:             ((symbolp packages)
     29:              (assq packages deps))
     30:             (t (error "Expected a package symbol or list, got %s" packages))))))
     31: 
     32: ;;;###autoload
     33: (defun +javascript-add-npm-path-h ()
     34:   "Add node_modules/.bin to `exec-path'."
     35:   (when-let ((search-directory (or (doom-project-root) default-directory))
     36:              (node-modules-parent (locate-dominating-file search-directory "node_modules/"))
     37:              (node-modules-dir (expand-file-name "node_modules/.bin/" node-modules-parent)))
     38:     (make-local-variable 'exec-path)
     39:     (add-to-list 'exec-path node-modules-dir)
     40:     (doom-log ":lang:javascript: add %s to $PATH" (expand-file-name "node_modules/" node-modules-parent))))
     41: 
     42: 
     43: ;;
     44: ;; Commands
     45: 
     46: ;;;###autoload
     47: (defun +javascript/open-repl ()
     48:   "Open a Javascript REPL. Meaning either `skewer-repl', if any of the
     49: skewer-*-mode's are enabled, or `nodejs-repl' otherwise."
     50:   (interactive)
     51:   (call-interactively
     52:    (if (and (featurep 'skewer-mode)
     53:             (or (bound-and-true-p skewer-mode)
     54:                 (bound-and-true-p skewer-css-mode)
     55:                 (bound-and-true-p skewer-html-mode)))
     56:        #'skewer-repl
     57:      #'nodejs-repl))
     58:   (current-buffer))
     59: 
     60: ;;;###autoload
     61: (defun +javascript/skewer-this-buffer ()
     62:   "Toggle a globalized skewer-mode, attaching an external browser (once),
     63: initiating an internal httpd server (once) and enabling the appropriate
     64: skewer-mode for the current buffer.
     65: 
     66: Run this for any buffer you want to skewer."
     67:   (interactive)
     68:   (when (bound-and-true-p impatient-mode)
     69:     (error "Skewer-mode isn't compatible with impatient mode"))
     70:   (require 'skewer-mode)
     71:   (unless (process-status "httpd")
     72:     (run-skewer))
     73:   (pcase major-mode
     74:     ((or 'css-mode 'scss-mode 'less-css-mode)
     75:      (unless (bound-and-true-p skewer-css-mode)
     76:        (skewer-css-mode +1)))
     77:     ((or 'web-mode 'html-mode)
     78:      (unless (bound-and-true-p skewer-html-mode)
     79:        (skewer-html-mode +1)))
     80:     ('js2-mode
     81:      (unless (bound-and-true-p skewer-mode)
     82:        (skewer-mode +1)))
     83:     (_ (error "Invalid mode %s" major-mode))))
     84: 
     85: ;;;###autoload
     86: (defun +javascript/skewer-cleanup ()
     87:   "Disable skewer-mode globally and disable the httpd server."
     88:   (interactive)
     89:   (when (process-status "httpd")
     90:     (httpd-stop))
     91:   (dolist (buf (buffer-list))
     92:     (with-current-buffer buf
     93:       (if (bound-and-true-p skewer-mode)
     94:           (skewer-mode -1))
     95:       (if (bound-and-true-p skewer-css-mode)
     96:           (skewer-css-mode -1))
     97:       (if (bound-and-true-p skewer-html-mode)
     98:           (skewer-html-mode -1)))))
     99: 
    100: ;;
    101: ;; Hooks
    102: 
    103: ;;;###autoload
    104: (defun +javascript-cleanup-tide-processes-h ()
    105:   "Clean up dangling tsserver processes if there are no more buffers with
    106: `tide-mode' active that belong to that server's project."
    107:   (when tide-mode
    108:     (unless (cl-loop with project-name = (tide-project-name)
    109:                      for buf in (delq (current-buffer) (buffer-list))
    110:                      if (and (buffer-local-value 'tide-mode buf)
    111:                              (with-current-buffer buf
    112:                                (string= (tide-project-name) project-name)))
    113:                      return buf)
    114:       (kill-process (tide-current-server)))))
    115: 
    116: ;;
    117: ;; Advice
    118: 
    119: ;;;###autoload
    120: (defun +javascript-tide-project-root-a ()
    121:   "Resolve to `doom-project-root' if `tide-project-root' fails."
    122:   (or tide-project-root
    123:       (or (locate-dominating-file default-directory "tsconfig.json")
    124:           (locate-dominating-file default-directory "jsconfig.json"))))
    125: 
    126: (with-eval-after-load 'projectile
    127:   (add-to-list 'projectile-globally-ignored-directories "^node_modules$")
    128:   (add-to-list 'projectile-globally-ignored-directories "^flow-typed$"))
    
  • js2-mode   external
     1: (use-package js2-mode
     2:   :ensure
     3:   :defer t
     4:   :interpreter ("node" . js2-mode)
     5:   :hook (js2-mode . rainbow-delimiters-mode)
     6:   :hook (js2-mode . js2-imenu-extras-mode)
     7:   :hook (js2-mode . (lambda () (push '("function" . ?ƒ) prettify-symbols-alist)))
     8:   :config
     9:   (with-eval-after-load 'skewer-mode
    10:     (add-hook 'js2-mode 'skewer-mode))
    11:   (setq-default js2-basic-indent 2
    12:                 js2-basic-offset 2
    13:                 js2-auto-indent-p t
    14:                 js2-cleanup-whitespace t
    15:                 js2-enter-indents-newline t
    16:                 js2-indent-on-enter-key t
    17:                 js2-global-externs (list "window" "module" "require" "buster" "sinon" "assert" "refute" "setTimeout" "clearTimeout" "setInterval" "clearInterval" "location" "__dirname" "console" "JSON" "jQuery" "$")))
    
  • js2-refactor   external
     1: (use-package js2-refactor
     2:   :ensure
     3:   :defer t
     4:   :hook (js2-mode . js2-refactor-mode)
     5:   :init
     6:   (js2r-add-keybindings-with-prefix "C-c C-r")
     7:   :config
     8:   (setq js2-skip-preprocessor-directives t)
     9:   :general
    10:   (general-nvmap
    11:     :keymap 'js2-refactor-mode-map
    12:     "zr" (general-simulate-key "C-c C-r"
    13:            :name general-z-r-simulates-C-c-C-r
    14:            :docstring "Simulates C-c C-r"
    15:            :which-key "JS2 Refactor")))
    
  • rjsx-mode   external
     1: (use-package rjsx-mode
     2:   :ensure
     3:   :defer t
     4:   :mode "\\.[mc]?js\\'"
     5:   :mode "\\.es6\\'"
     6:   :mode "\\.pac\\'"
     7:   :hook (rjsx-mode . rainbow-delimiters-mode)
     8:   :hook (rjsx-mode . rainbow-mode)
     9:   :bind (([remap comment-dwim ] . rjsx-comment-dwim))
    10:   :init
    11:   (with-eval-after-load 'compilation
    12:     (add-to-list 'compilation-error-regexp-alist 'node)
    13:     (add-to-list 'compilation-error-regexp-alist-alist '(node "^[[:blank:]]*at \\(.*(\\|\\)\\(.+?\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)"
    14:                                                               2 3 4)))
    15:   :config
    16:   (with-eval-after-load 'compilation
    17:     (add-to-list 'compilation-error-regexp-alist 'node)
    18:     (add-to-list 'compilation-error-regexp-alist-alist
    19:                  '(node "^[[:blank:]]*at \\(.*(\\|\\)\\(.+?\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)"
    20:                         2 3 4)))
    21:   (setq js-chain-indent t
    22:         ;; These have become standard in the JS community
    23:         js2-basic-offset 2
    24:         ;; Don't mishighlight shebang lines
    25:         js2-skip-preprocessor-directives t
    26:         ;; let flycheck handle this
    27:         js2-mode-show-parse-errors nil
    28:         js2-mode-show-strict-warnings nil
    29:         ;; Flycheck provides these features, so disable them: conflicting with
    30:         ;; the eslint settings.
    31:         js2-strict-missing-semi-warning nil
    32:         ;; maximum fontification
    33:         js2-highlight-level 3
    34:         js2-idle-timer-delay 0.15)
    35:   :general
    36:   (general-nvmap
    37:     :keymaps 'rjsx-mode-map
    38:     "'" 'rjsx-jump-tag
    39:     "gj" 'rjsx-jump-closing-tag
    40:     "gk" 'rjsx-jump-opening-tag
    41:     "gr" 'rjsx-rename-tag-at-point
    42:     "z>" 'rjsx-electric-gt
    43:     "z<" 'rjsx-electric-lt))
    
  • xref-js2   external
    1: (use-package xref-js2
    2:   :ensure
    3:   :defer t
    4:   :if (executable-find "ag") ; silver-searcher
    5:   :config
    6:   (add-hook 'js2-mode-hook (lambda ()
    7:                              (add-hook 'xref-backend-functions #'xref-js2-xref-backend nil t))))
    
  • typescript-mode   external
     1: (use-package typescript-mode
     2:   :ensure
     3:   :defer t
     4:   :hook (typescript-mode . rainbow-delimiters-mode)
     5:   :hook (typescript-tsx-mode . rainbow-delimiters-mode)
     6:   :hook (typescript-mode . (lambda () (setq comment-line-break-function #'js2-line-break
     7:                                             typescript-indent-level (or (and (bound-and-true-p tide-mode)
     8:                                                                              (plist-get (tide-tsfmt-options) :indentSize))
     9:                                                                         typescript-indent-level)
    10:                                             emmet-expand-jsx-className? t)))
    11:   :init
    12:   (add-to-list 'auto-mode-alist
    13:                (cons "\\.tsx\\'" #'typescript-mode))
    14:   (with-eval-after-load 'flycheck
    15:     (flycheck-add-mode 'javascript-eslint 'web-mode)
    16:     (flycheck-add-mode 'javascript-eslint 'typescript-mode)
    17:     (flycheck-add-mode 'javascript-eslint 'typescript-tsx-mode)
    18:     (flycheck-add-mode 'typescript-tslint 'typescript-tsx-mode))
    19:   (defun +javascript-disable-tide-checkers-h ()
    20:     (add-to-list 'flycheck-disabled-checkers 'javascript-jshint)
    21:     (add-to-list 'flycheck-disabled-checkers 'tsx-tide)
    22:     (add-to-list 'flycheck-disabled-checkers 'jsx-tide))
    23:   (add-hook 'typescript-tsx-mode-hook #'+javascript-disable-tide-checkers-h)
    24:   :config
    25:   (when (fboundp 'web-mode)
    26:     (define-derived-mode typescript-tsx-mode web-mode "TypeScript-TSX"))
    27:   (autoload 'js2-line-break "js2-mode" nil t))
    
  • tide   external
     1: (use-package tide
     2:   :ensure
     3:   :defer t
     4:   :hook (tide-mode . tide-hl-identifier-mode)
     5:   :config
     6:   (setq tide-completion-detailed t
     7:         tide-always-show-documentation t
     8:         tide-server-max-response-length 524288
     9:         tide-completion-setup-company-backend nil)
    10:   (add-hook 'tide-mode-hook (lambda () (add-hook 'kill-buffer-hook #'+javascript-cleanup-tide-processes-h nil 'local))))
    
  • npm-mode   external
    1: (use-package npm-mode
    2:   :ensure
    3:   :defer t)
    
  • nodejs-repl   external
    1: (use-package nodejs-repl
    2:   :ensure
    3:   :defer t)
    

Latex

  • auctex
     1: (use-package auctex
     2:   :ensure nil
     3:   :mode (("\\.tex\\'" . latex-mode)
     4:          ("\\.latex\\'" . latex-mode))
     5:   :commands (latex-mode LaTeX-mode plain-tex-mode)
     6:   :init
     7:   (progn
     8:     (add-hook 'LaTeX-mode-hook #'LaTeX-preview-setup)
     9:     (add-hook 'LaTeX-mode-hook #'flyspell-mode)
    10:     (add-hook 'LaTeX-mode-hook #'turn-on-reftex)
    11:     (setq-default TeX-engine 'xetex)
    12:     (setq TeX-auto-save nil
    13:           TeX-parse-self nil
    14:           TeX-save-query nil
    15:           TeX-PDF-mode t)
    16:     (setq-default TeX-master nil)))
    
  • preview
    1: (use-package preview
    2:   :ensure nil
    3:   :after auctex
    4:   :commands LaTeX-preview-setup
    5:   :init
    6:   (progn
    7:     (setq-default preview-scale 1.4
    8:                   preview-scale-function '(lambda () (* (/ 10.0 (preview-document-pt)) preview-scale)))))
    
  • reftex
    1: (use-package reftex
    2:   :ensure nil
    3:   :commands turn-on-reftex
    4:   :init
    5:   (setq reftex-plug-into-AUCTeX t))
    
  • bibtex
    1: (use-package bibtex
    2:   :config
    3:   (setq bibtex-autokey-year-length 4
    4:         bibtex-autokey-name-year-separator "-"
    5:         bibtex-autokey-year-title-separator "-"
    6:         bibtex-autokey-titleword-separator "-"
    7:         bibtex-autokey-titlewords 2
    8:         bibtex-autokey-titlewords-stretch 1
    9:         bibtex-autokey-titleword-length 5))
    
  • LaTex
     1: ;; Auto-fill for LaTeX
     2: (defun lem-latex-auto-fill ()
     3:   "Turn on auto-fill for LaTeX mode."
     4:   (turn-on-auto-fill)
     5:   (set-fill-column 80)
     6:   (setq default-justification 'left))
     7: (add-hook 'LaTeX-mode-hook #'lem-latex-auto-fill)
     8: 
     9: ;; Compilation command
    10: (add-hook 'LaTeX-mode-hook (lambda () (setq compile-command "latexmk -pdflatex=xelatex -f -pdf %f")))
    11: 
    12: ;; Prevent ispell from verifying some LaTeX commands
    13: ;; http://stat.genopole.cnrs.fr/dw/~jchiquet/fr/latex/emacslatex
    14: (defvar lem-ispell-tex-skip-alists
    15:   '("cite" "nocite"
    16:     "includegraphics"
    17:     "author" "affil"
    18:     "ref" "eqref" "pageref"
    19:     "label"))
    20: (setq ispell-tex-skip-alists
    21:       (list
    22:        (append (car ispell-tex-skip-alists)
    23:                (mapcar #'(lambda (cmd) (list (concat "\\\\" cmd) 'ispell-tex-arg-end)) lem-ispell-tex-skip-alists))
    24:        (cadr ispell-tex-skip-alists)))
    25: 
    26: ;; Indentation with align-current in LaTeX environments
    27: (defvar lem-LaTeX-align-environments '("tabular" "tabular*"))
    28: (add-hook 'LaTeX-mode-hook
    29:           (lambda ()
    30:             (require 'align)
    31:             (setq LaTeX-indent-environment-list
    32:                   ;; For each item in the list...
    33:                   (mapcar (lambda (item)
    34:                             ;; The car is an environment
    35:                             (let ((env (car item)))
    36:                               ;; If this environment is in our list...
    37:                               (if (member env lem-LaTeX-align-environments)
    38:                                   ;; ...then replace this item with a correct one
    39:                                   (list env 'align-current)
    40:                                 ;; else leave it alone
    41:                                 item)))
    42:                           LaTeX-indent-environment-list))))
    43: 
    44: ;; Use dvipdfmx to convert DVI files to PDF in AUCTeX
    45: (eval-after-load 'tex
    46:   '(add-to-list 'TeX-command-list
    47:                 '("DVI to PDF" "dvipdfmx %d" TeX-run-command t t) t))
    48: 
    49: ;; SyncTeX (http://www.emacswiki.org/emacs/AUCTeX#toc19)
    50: (defun synctex/un-urlify (fname-or-url)
    51:   "A trivial function that replaces a prefix of file:/// with just /."
    52:   (if (string= (substring fname-or-url 0 8) "file:///")
    53:       (substring fname-or-url 7)
    54:     fname-or-url))
    

Markdown   external

  • Basic Configuration
     1: (use-package markdown-mode
     2:   :ensure)
     3: 
     4: (use-package markdown-ts-mode
     5:   :ensure
     6:   :init
     7:   (add-to-list 'major-mode-remap-alist '(markdown-mode . markdown-ts-mode)))
     8: 
     9: (use-package poly-markdown
    10:   :ensure
    11:   :init :mode
    12:   (("README\\.md\\'" . gfm-mode)
    13:    ("\\.md$" . markdown-ts-mode)
    14:    ("\\.markdown$" . markdown-ts-mode)))
    15: 
    16: (use-package edit-indirect
    17:   :ensure
    18:   :after markdown-mode)
    

Python

  • python   builtin
     1: (use-package python
     2:   :mode ("[./]flake8\\'" . conf-mode)
     3:   :mode ("/Pipfile\\'" . conf-mode)
     4:   :hook ((python-mode . lsp-deferred)
     5:          (python-mode . lsp-ui-mode)
     6:          (python-mode . lsp-ui-doc-mode)
     7:          ;; (python-mode . guess-style-guess-tab-mode)
     8:          (python-mode-local-vars . (lambda ()
     9:                                      (lsp-deferred)
    10:                                      (tree-sitter))))
    11:   :config
    12:   (if (executable-find "ipython")
    13:       (setq python-interpreter (executable-find "ipython"))
    14:     (setq python-interpreter (executable-find "python3")))
    15:   (when (featurep 'projectile)
    16:     (add-to-list 'projectile-globally-ignored-directories "^\\.venv$"))
    17:   (let ((directories `("/usr/bin/" "/usr/local/bin/" "/opt/bin" ,(expand-file-name ".local/bin/" (getenv "HOME")))))
    18:     (dolist (directory directories) (when (file-directory-p directory)(add-to-list 'python-shell-exec-path directory))))
    19:   (setq python-indent-guess-indent-offset nil
    20:         python-shell-completion-native-enable nil
    21:         python-shell-exec-path (list "/usr/bin/" "/usr/local/bin" (expand-file-name ".local/bin/" (getenv "HOME")))
    22:         python-indent-guess-indent-offset-verbose nil)
    23:   (when (featurep 'lsp-mode)
    24:     (setq lsp-pylsp-plugins-rope-completion-enabled t ; needs python-rope package
    25:           lsp-pylsp-plugins-mccabe-enabled t ; needs python-mccabe package
    26:           lsp-ruff-lsp-python-path (executable-find "python3")
    27:           )
    28:     (when (executable-find "black")
    29:       (setq lsp-pylsp-plugins-black-enabled t))
    30:     (when (executable-find "autopep8")
    31:       (setq lsp-pylsp-plugins-autopep8-enabled t))
    32:     (when (executable-find "flake8")
    33:       (setq lsp-pylsp-plugins-flake8-enabled t))
    34:     (when (executable-find "pycodestyle")
    35:       (setq lsp-pylsp-plugins-pycodestyle-enabled t))
    36:     (when (executable-find "pydocstyle")
    37:       (setq lsp-pylsp-plugins-pydocstyle-enabled t))
    38:     (when (executable-find "pylint")
    39:       (setq lsp-pylsp-plugins-pylint-enabled t))
    40:     (when (executable-find "pyflakes")
    41:       (setq lsp-pylsp-plugins-pyflakes-enabled t))
    42:     (when (executable-find "yapf")
    43:       (setq lsp-pylsp-plugins-yapf-enabled t)))
    44:   (when (featurep 'flycheck)
    45:     (setq flycheck-python-mypy-executable (executable-find "mypy")
    46:           flycheck-python-flake8-executable (executable-find "flake8")
    47:           flycheck-python-pylint-executable (executable-find "pylint")
    48:           flycheck-python-pyright-executable (executable-find "pyright")))
    49:   :general
    50:   (+config/local-leader
    51:     :keymaps 'python-mode-map
    52:     "d" '(:ignore t :wk "doc")))
    
  • pydoc   external
    1: (use-package pydoc
    2:   :ensure
    3:   :general
    4:   (general-def
    5:     :keymaps 'python-mode-map
    6:     "C-c C-d" 'pydoc-at-point-no-jedi))
    
  • ob-ipython
    1: (use-package ob-ipython
    2:   :ensure
    3:   :defer t
    4:   :init
    5:   (setq ob-ipython-resources-dir ".ob-ipython-resrc")
    6:   (with-eval-after-load 'org-src
    7:     (add-to-list 'org-src-lang-modes '("ipython" . python)))
    8:   (with-eval-after-load 'ob-async
    9:     (add-to-list 'ob-async-no-async-languages-alist "ipython")))
    
  • pip-requirements   external
    1: (use-package pip-requirements
    2:   :ensure
    3:   :defer t
    4:   :config
    5:   (add-hook 'pip-requirements-mode-hook #'pip-requirements-auto-complete-setup))
    
  • inferior-python-mode
    1: (use-package inferior-python-mode
    2:   :ensure nil
    3:   ;;:hook (inferior-python-mode . hide-mode-line-mode)
    4:   :config
    5:   (+config/local-leader
    6:     :keymaps 'python-mode-map
    7:     "r" '(run-python :wk "run python")))
    
  • lsp-pyright   external
     1: (use-package lsp-pyright
     2:   :ensure
     3:   :after lsp-mode
     4:   :hook (python-mode . (lambda ()
     5:                          (lsp-deferred)
     6:                          (lsp-ui-mode)
     7:                          (lsp-ui-doc-mode)))
     8:   :config
     9:   (setq lsp-pyright-python-executable-cmd
    10:         (if (executable-find "python3")
    11:             (executable-find "python3")
    12:           "python")))
    
  • python-docstring   external
    1: (use-package python-docstring
    2:   :ensure
    3:   :diminish
    4:   :hook (python-mode . python-docstring-mode)
    5:   :general
    6:   (+config/local-leader
    7:     :keymaps 'python-mode-map
    8:     "dq" 'python-docstring-fill))
    
  • pipenv   external
     1: (use-package pipenv
     2:   :ensure
     3:   :diminish
     4:   :after python
     5:   :commands pipenv-project-p
     6:   :hook (python-mode . pipenv-mode)
     7:   :init
     8:   (setq pipenv-projectile-after-switch-function
     9:         #'pipenv-projectile-after-switch-extended
    10:         pipenv-executable (executable-find "pipenv"))
    11:   :general
    12:   (+config/local-leader
    13:     :keymaps 'python-mode-map
    14:     "p" '(:keymap pipenv-command-map :package pipenv :wk "pipenv")))
    
  • pyvenv   external
     1: (use-package pyvenv
     2:   :ensure t
     3:   :config
     4:   (pyvenv-mode t)
     5:   ;; Set correct Python interpreter
     6:   (setq pyvenv-post-activate-hooks
     7:         (list (lambda ()
     8:                 (setq python-shell-interpreter (concat pyvenv-virtual-env ".venv/bin/python3")))))
     9:   (setq pyvenv-post-deactivate-hooks
    10:         (list (lambda ()
    11:                 (setq python-shell-interpreter "python3")))))
    
  • flycheck-pycheckers   external
    1: (use-package flycheck-pycheckers
    2:   :ensure
    3:   :after flycheck
    4:   :config
    5:   (with-eval-after-load 'flycheck
    6:     (add-hook 'flycheck-mode-hook #'flycheck-pycheckers-setup)))
    
  • ein   external
    1: (use-package ein
    2:   :ensure t)
    

Rust

  • rust-mode
     1: ;;;###autoload
     2: (defun +rust-cargo-project-p ()
     3:   "Return t if this is a cargo project."
     4:   (locate-dominating-file buffer-file-name "Cargo.toml"))
     5: 
     6: ;;; Custom Cargo commands
     7: 
     8: (autoload 'rustic-run-cargo-command "rustic-cargo")
     9: ;;;###autoload
    10: (defun +rust/cargo-audit ()
    11:   "Run 'cargo audit' for the current project."
    12:   (interactive)
    13:   (rustic-run-cargo-command "cargo audit"))
    14: 
    15: (with-eval-after-load 'projectile
    16:   (add-to-list 'projectile-project-root-files "Cargo.toml"))
    17: 
    18: (use-package rust-mode)
    
  • rustic   external
     1: (use-package rustic
     2:   :ensure
     3:   :mode ("\\.rs$" . rustic-mode)
     4:   :init
     5:   (with-eval-after-load 'rustic-flycheck
     6:     (remove-hook 'rustic-mode-hook #'flycheck-mode)
     7:     (remove-hook 'rustic-mode-hook #'flymake-mode-off)
     8:     (remove-hook 'flycheck-mode-hook #'rustic-flycheck-setup))
     9:   (with-eval-after-load 'org-src
    10:     (defalias 'org-babel-execute:rust #'org-babel-execute:rustic))
    11:   :config
    12:   (add-hook 'rustic-mode-hook #'rainbow-delimiters-mode)
    13:   (setq rustic-indent-method-chain t
    14:         rustic-lsp-client 'lsp-mode)
    15:   (add-hook 'rustic-mode-local-vars-hook #'rustic-setup-lsp 'append)
    16:   (add-hook 'rustic-mode-local-vars-hook #'flycheck-mode)
    17:   ;; (add-hook 'rustic-mode-local-vars-hook #'tree-sitter! 'append)
    18:   (with-eval-after-load 'lsp
    19:     (setq lsp-rust-analyzer-display-parameter-hints t)))
    
  • flycheck-rust   external
    1: (use-package flycheck-rust
    2:   :ensure
    3:   :after flycheck
    4:   :config
    5:   (with-eval-after-load 'rustic
    6:     (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)))
    

Ansible

  • ansible   external
     1: (use-package ansible
     2:   :ensure
     3:   :defer t
     4:   :if (executable-find "ansible")
     5:   :ensure
     6:   :commands ansible-auto-decrypt-encrypt
     7:   :hook (ansible . 'ansible-auto-decrypt-encrypt)
     8:   :init
     9:   (put 'ansible-vault-password-file 'safe-local-variable #'stringp)
    10:   :config
    11:   (setq ansible-section-face 'font-lock-variable-name-face
    12:         ansible-task-label-face 'font-lock-doc-face)
    13:   :general
    14:   (+config/local-leader
    15:     :keymaps 'yaml-mode-map
    16:     "a" '(:ignore t :wk ansible)
    17:     "ad" 'ansible-decrypt-buffer
    18:     "ae" 'ansible-encrypt-buffer))
    
  • ansible-doc   external
    1: (use-package ansible-doc
    2:   :after ansible
    3:   :ensure
    4:   :hook (yaml-mode . ansible-doc-mode)
    5:   :config
    6:   (when (featurep 'evil)
    7:     (evil-set-initial-state '(ansible-doc-module-mode) 'emacs)))
    

Perl

  • cperl-mode   external
    1: (use-package cperl-mode
    2:   :ensure
    3:   :defer t
    4:   :mode ("\\.\\([pP][Llm]\\|al\\)\\'" . cperl-mode))
    

Haskell

  • haskell-mode   external
     1: (use-package haskell-mode
     2:   :ensure t
     3:   :defer t
     4:   :init
     5:   (setq flymake-allowed-file-name-masks nil)
     6:   :custom
     7:   (haskell-process-load-or-reload-prompt t)
     8:   (haskell-process-auto-import-loaded-modules t)
     9:   (haskell-process-log t)
    10:   (haskell-tags-on-save t))
    
  • lsp-haskell   external
    (use-package lsp-haskell
      :ensure t
      :defer t
      :after lsp)
    

The Configuration

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 atuomatically 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
    
    1: (setq gc-cons-threshold most-positive-fixnum 
    2:     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.

    1: (add-hook 'emacs-startup-hook
    2:         (lambda ()
    3:           (setq gc-cons-threshold (* 16 1024 1024) ; 16mb
    4:                 gc-cons-percentage 0.1)))
    
  • Language

    Set UTF-8 as the default coding system

    1: (set-language-environment "UTF-8")
    
  • Set initial frame

    Here I disable the menu-bar, tool-bar and vertical scroll bar.

    1: (push '(menu-bar-lines . 0) default-frame-alist)
    2: (push '(tool-bar-lines . 0) default-frame-alist)
    3: (push '(vertical-scroll-bars) default-frame-alist)
    
  • Define the location of custom-file

    The custom-file is used to save customization settings for future use.

    1: (customize-set-variable 'custom-file (expand-file-name "custom.el" user-emacs-directory))
    2: (when (file-exists-p custom-file)
    3:   (load custom-file))
    
  • Setup package

    Now much more simpler since [[https://github.com/jwiegley/use-package][use-package]] is built into Emacs.

    1: (require 'package)
    2: ;; Add `melpa` to `package-archives`.
    3: (add-to-list 'package-archives
    4:              '("melpa" . "https://melpa.org/packages/"))
    5: ;; gnu-devel
    6: (add-to-list 'package-archives '("gnu-devel" . "https://elpa.gnu.org/devel/"))
    7: (setq package-quickstart t)
    
  • use-package
    1: (require 'use-package)
    2: 
    3: (custom-set-variables
    4:  '(use-package-enable-imenu-support t)
    5:  '(use-package-always-defer nil)
    6:  '(use-package-verbose nil)
    7:  '(use-package-check-before-init t)
    8:  '(use-package-compute-statistics t))
    
    • use-package-ignore-unknown-keywords is set to t to avoid error signaling, since I'm also use general.el that uses a :general keyword in use-package.
    • use-package-enable-imenu-support to make imenu to see a use-package declarations.
    • use-package-check-before-init to have use-package check the package existence before executing the :init block.

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.

    1: (require 'ob-tangle)
    2: 
    3: (when (file-exists-p (expand-file-name "index.org" user-emacs-directory))
    4:   (org-babel-tangle-file (expand-file-name "index.org" user-emacs-directory)))
    5: 
    6: (require 'config (expand-file-name "config.el" user-emacs-directory))
    

config.el

  • The configuration
       1: ;; Variables, and helper functions
       2: (setq user-mail-address "alexforsale@yahoo.com"
       3:       user-full-name "Kristian Alexander P")
       4: (defvar +config/user-modules-directory (expand-file-name "modules/" user-emacs-directory)
       5:   "User modules directory.")
       6: (when (file-directory-p +config/user-modules-directory)
       7:   (add-to-list 'load-path +config/user-modules-directory))
       8: ;;; From https://emacs.stackexchange.com/questions/38008/adding-many-items-to-a-list/68048#68048
       9: (defun merge-list-to-list (dst src)
      10:   "Merges content of the 2nd list with the 1st one"
      11:   (set dst
      12:        (append (eval dst) src)))
      13: (when (file-directory-p (expand-file-name "Sync/org" (getenv "HOME")))
      14:   (customize-set-variable '+config/org-directory (expand-file-name "Sync/org" (getenv "HOME"))))
      15: ;; keybindings
      16: (use-package general
      17:   :ensure t
      18:   :init
      19:   (general-evil-setup t)
      20:   (general-auto-unbind-keys)
      21:   :config
      22:   (general-override-mode)
      23:   (general-create-definer +config/leader-key
      24:     :keymaps 'override
      25:     :states  '(insert emacs normal hybrid motion visual operator)
      26:     :prefix "SPC"
      27:     :non-normal-prefix "C-c SPC")
      28:   (general-create-definer +config/local-leader
      29:     :keymaps 'override
      30:     :states '(emacs normal hybrid motion visual operator)
      31:     :prefix "SPC m"
      32:     :non-normal-prefix "C-c SPC m"
      33:     "" '(:ignore t :which-key (lambda (arg) `(,(cadr (split-string (car arg) " ")) . ,(replace-regexp-in-string "-mode$" "" (symbol-name major-mode))))))
      34:   ;; useful macro
      35:   (defmacro +config/leader-menu! (name infix-key &rest body)
      36:     "Create a definer NAME `+config/leader-NAME' wrapping `+config/leader-key'.
      37:       Create prefix map: `+config/leader-NAME-map'. Prefix bindings in BODY with INFIX-KEY."
      38:     (declare (indent 2))
      39:     `(progn
      40:        (general-create-definer ,(intern (concat "+config/leader-" name))
      41:          :wrapping +config/leader-key
      42:          :prefix-map (quote ,(intern (concat "+config/leader-" name "-map")))
      43:          :infix ,infix-key
      44:          :wk-full-keys nil
      45:          "" '(:ignore t :which-key ,name))
      46:        (,(intern (concat "+config/leader-" name))
      47:         ,@body))))
      48: ;; First level menu
      49: (+config/leader-menu! "activities" "C-a")
      50: (+config/leader-menu! "buffer" "b")
      51: (+config/leader-menu! "files" "f")
      52: (+config/leader-menu! "find" "gf")
      53: (+config/leader-menu! "go" "g")
      54: (+config/leader-menu! "insert" "i")
      55: (+config/leader-menu! "mail" "M-m")
      56: (+config/leader-menu! "mark" "m")
      57: (+config/leader-menu! "notes" "n")
      58: (+config/leader-menu! "open" "o")
      59: (+config/leader-menu! "quit" "q")
      60: (+config/leader-menu! "register" "gr")
      61: (+config/leader-menu! "tree" "t")
      62: (+config/leader-menu! "tab" "t TAB")
      63: (+config/leader-menu! "vterm" "tv")
      64: (+config/leader-menu! "window" "w")
      65: ;; keybindings
      66: (+config/leader-key
      67:   ";" 'pp-eval-expression
      68:   ":" 'execute-extended-command
      69:   "^" '(subword-capitalize :wk "Capitalize subword")
      70:   "u" 'universal-argument)
      71: ;; buffer
      72: (+config/leader-buffer
      73:   "[" '(previous-buffer :wk "previous buffer")
      74:   "]" '(next-buffer :wk "next buffer")
      75:   "TAB" '((lambda () (interactive) (switch-to-buffer nil)) :wk "other-buffer")
      76:   "b" '(switch-to-buffer :wk "switch to buffer")
      77:   "s" '(basic-save-buffer :wk "save buffer")
      78:   "c" '(clone-indirect-buffer :wk "clone buffer")
      79:   "C" '(clone-indirect-buffer-other-window :wk "clone buffer other window")
      80:   "d" '(kill-current-buffer :wk "kill current buffer")
      81:   "i" 'ibuffer
      82:   "k" '(kill-buffer :wk "kill buffer")
      83:   "l" '(evil-switch-to-windows-last-buffer :wk "Switch to last open buffer")
      84:   "m" '((lambda () (interactive) (switch-to-buffer "*Messages*")) :wk "switch to messages buffer")
      85:   "n" '(next-buffer :wk "next buffer")
      86:   "N" '(evil-buffer-new :wk "New unnamed buffer")
      87:   "p" '(previous-buffer :wk "previous buffer")
      88:   "o" '((lambda () (interactive) (switch-to-buffer nil)) :wk "other-buffer")
      89:   "r" '(revert-buffer-quick :wk "revert buffer")
      90:   "R" '(rename-buffer :wk "rename buffer")
      91:   "x" '((lambda () (interactive) (switch-to-buffer "*scratch*")) :wk "switch to scratch buffer")
      92:   "z" '(bury-buffer :wk "bury buffer"))
      93: (with-eval-after-load 'smartparens
      94:   (general-nvmap
      95:    :keymaps 'smartparens-mode-map
      96:    "<" 'sp-backward-barf-sexp
      97:    "C-<" 'sp-backward-slurp-sexp
      98:    ">" 'sp-forward-slurp-sexp
      99:    "C->" 'sp-forward-barf-sexp)
     100:   (general-define-key
     101:    :keymaps 'smartparens-mode-map
     102:    "M-DEL" 'sp-unwrap-sexp))
     103: (general-nvmap
     104:   'dired-mode-map
     105:   "g$" 'dired-hide-subdir
     106:   "g?" 'dired-summary
     107:   "gG" 'dired-do-chgrp
     108:   "gj" 'dired-next-dirline
     109:   "gk" 'dired-prev-dirline
     110:   "go" 'dired-view-file
     111:   "gO" 'dired-find-file-other-window
     112:   "gy" 'dired-show-file-type)
     113: ;; files
     114: (+config/leader-files
     115:   "D" 'dired
     116:   "d" 'dired-jump
     117:   "f" '(find-file :wk "find file")
     118:   "F" '(find-file-other-frame :wk "find file other frame")
     119:   "k" 'delete-frame
     120:   "r" 'recentf
     121:   "S" '(write-file :wk "save file")
     122:   "s" '(save-buffer :wk "save buffer")
     123:   "w" '(find-file-other-window :wk "find file other window"))
     124: ;; find
     125: (+config/leader-find
     126:   "g" 'grep
     127:   "r" '(rgrep :wk "recursive grep"))
     128: ;; help
     129: (+config/leader-key
     130:   "h" (general-simulate-key "C-h"
     131:         :state '(normal visual)
     132:         :name general-SPC-h-simulates-C-h
     133:         :docstring "Simulates C-h in normal and visual mode."
     134:         :which-key "Help"))
     135: ;; insert
     136: (+config/leader-insert
     137:   "u" '(insert-char :wk "insert character"))
     138: ;; mark
     139: (+config/leader-mark
     140:   "m" '(bookmark-set :wk "set bookmark")
     141:   "b" '(bookmark-jump :wk "jump to bookmark")
     142:   "B" '(bookmark-jump-other-window :wk "jump to bookmark other window")
     143:   "C-c b" '(bookmark-jump-other-frame :wk "jump to bookmark other frame")
     144:   "c" '(consult-bookmark :wk "consult bookmark") ;; require `consult' package
     145:   "l" '(bookmark-bmenu-list :wk "list bookmarks")
     146:   "L" '(bookmark-load :wk "load bookmark")
     147:   "d" '(bookmark-delete :wk "delete bookmark")
     148:   "D" '(bookmark-delete-all :wk "delete all bookmarks")
     149:   "s" '(bookmark-save :wk "save bookmark")
     150:   "r" '(bookmark-rename :wk "rename bookmark"))
     151: ;; open
     152: (+config/leader-open
     153:   "i" '((lambda () (interactive) (find-file user-init-file)) :wk "open Emacs configuration file"))
     154: (general-define-key
     155:  :keymaps 'override
     156:  "C-c l" '(org-store-link :wk "Store link")
     157:  "C-c a" '(org-agenda :wk "Org Agenda")
     158:  "C-c c" '(org-capture :wk "Org Capture")
     159:  "C-c C-s" 'org-schedule)
     160: 
     161: (+config/leader-notes
     162:   "a" 'org-agenda
     163:   "c" 'org-capture
     164:   "C" 'org-capture-goto-last-stored
     165:   "r" 'org-refile-goto-last-stored)
     166: 
     167: ;; (+config/local-leader
     168: ;;   :major-modes 'org-mode
     169: ;;   :keymaps 'org-mode-map
     170: ;;   "a" '(:ignore t :wk "action")
     171: ;;   "s" '(:ignore t :wk "search"))
     172: 
     173: (+config/local-leader
     174:   :keymaps 'org-mode-map
     175:   "C-a" 'org-attach
     176:   "C-b" 'org-backward-heading-same-level
     177:   "C-c" 'org-ctrl-c-ctrl-c
     178:   "C-d" 'org-deadline
     179:   "C-e" 'org-export-dispatch
     180:   "C-f" 'org-forward-heading-same-level
     181:   "C-j" 'org-goto
     182:   "C-k" 'org-kill-note-or-show-branches
     183:   "C-l" 'org-insert-link
     184:   "C-n" 'org-next-visible-heading
     185:   "C-o" 'org-open-at-point
     186:   "C-p" 'org-previous-visible-heading
     187:   "C-q" 'org-set-tags-command
     188:   "C-r" 'org-fold-reveal
     189:   "C-s" 'org-schedule
     190:   "C-t" 'org-todo
     191:   "C-w" 'org-refile
     192:   "C-y" 'org-evaluate-time-range
     193:   "C-z" 'org-add-note
     194:   "M-b" 'org-previous-block
     195:   "M-f" 'org-next-block
     196:   "M-l" 'org-insert-last-stored-link
     197:   "M-w" 'org-refile-copy
     198:   "C-^" 'org-up-element
     199:   "C-_" 'org-down-element
     200:   "C-<" 'org-promote-subtree
     201:   "C->" 'org-demote-subtree
     202:   "C-," 'org-insert-structure-template
     203:   "C-*" 'org-list-make-subtree
     204:   "{" 'org-table-toggle-formula-debugger
     205:   "}" 'org-table-toggle-coordinate-overlays
     206:   "`" 'org-table-edit-field
     207:   "\\" 'org-match-sparse-tree
     208:   "^" 'org-sort
     209:   "[" 'org-agenda-file-to-front
     210:   "]" 'org-remove-file
     211:   "@" 'org-mark-subtree
     212:   "?" 'org-table-field-info
     213:   "=" 'org-table-eval-formula
     214:   ">" 'org-goto-calendar
     215:   "+" 'org-table-sum
     216:   "<" 'org-date-from-calendar
     217:   ";" 'org-toggle-comment
     218:   ":" 'org-toggle-fixed-width
     219:   "/" 'org-sparse-tree
     220:   "," 'org-priority
     221:   "." 'org-timestamp
     222:   "*" 'org-ctrl-c-star
     223:   "-" 'org-ctrl-c-minus
     224:   "#" 'org-update-statistics-cookies
     225:   "$" 'org-archive-subtree
     226:   "%" 'org-mark-ring-push
     227:   "'" 'org-edit-special
     228:   "TAB" '(org-clock-in :wk "clock-in")
     229:   "!" '(org-reload :wk "reload org")
     230:   "[" '(org-mark-ring-goto :wk "Jump to previous position in the mark ring")
     231:   "b" '(:ignore t :wk "buffer")
     232:   "bs" '(org-save-all-org-buffers :wk "save all org buffer")
     233:   "f" '(:ignore t :wk "files")
     234:   "fs" '(org-save-all-org-buffers :wk "save all org buffer")
     235:   "s" '(org-schedule :wk "org schedule")
     236:   "i" '(:ignore t :wk "insert")
     237:   "id" '(org-insert-drawer :wk "insert drawer")
     238:   "i@" '(org-cite-insert :wk "insert citation")
     239:   "if" '(org-footnote-action :wk "footnote")
     240:   "i C-f" '(org-emphasize :wk "insert emphasize")
     241:   "il" '(org-insert-link :wk "insert link")
     242:   "iD" '(org-deadline :wk "insert deadline")
     243:   "is" '(org-schedule :wk "insert schedule")
     244:   "ip" '(org-set-property :wk "insert property")
     245:   "it" '(org-insert-time-stamp :wk "insert time-stamp at point"))
     246: ;; quit
     247: (+config/leader-quit
     248:   "q" '(save-buffers-kill-terminal :wk "quit and save")
     249:   "R" '(restart-emacs :wk "restart Emacs"))
     250: ;; register
     251: (+config/leader-register
     252:   ;; "#" '(consult-register :wk "consult-register") ;; require `consult' package
     253:   "+" '(increment-register :wk "augment content of register")
     254:   "C-@" '(point-to-register :wk "store current point to register")
     255:   "C-SPC" '(point-to-register :wk "store current point to register")
     256:   "M-w" '(copy-rectangle-as-kill :wk "copy region-rectangle and save")
     257:   "SPC" '(point-to-register :wk "store current point to register")
     258:   "c" '(clear-rectangle :wk "blank out region-rectangle")
     259:   "d" '(delete-rectangle :wk "delete region-rectangle")
     260:   "f" '(frameset-to-register :wk "store frameset to register")
     261:   "g" '(insert-register :wk "insert register")
     262:   "i" '(insert-register :wk "insert register")
     263:   "j" '(jump-to-register :wk "jump to register")
     264:   "k" '(kill-rectangle :wk "cut rectangle into killed-rectangle")
     265:   "l" '(bookmark-bmenu-list :wk "display existing bookmarks")
     266:   "m" '(bookmark-set :wk "set bookmark")
     267:   "M" '(bookmark-set-no-overwrite :wk "set bookmark no overwrite")
     268:   "n" '(number-to-register :wk "store a number in a register")
     269:   "N" '(rectangle-number-lines :wk "insert number in front of region-rectangle")
     270:   "o" '(open-rectangle :wk "blank out region-rectangle")
     271:   "r" '(copy-rectangle-to-register :wk "copy rectangle-region to register")
     272:   "s" '(copy-to-register :wk "copy region to register")
     273:   "t" '(string-rectangle :wk "replace rectangle with string")
     274:   "x" '(copy-to-register :wk "copy region to register")
     275:   "w" '(window-configuration-to-register :wk "store window configuration to register")
     276:   "y" '(yank-rectangle :wk "yank last killed rectangle with upper left corner at point"))
     277: ;; window
     278: (+config/leader-window
     279:   "C-o" '(delete-other-windows :wk "delete other windows")
     280:   "[" '(evil-window-left :wk "left window")
     281:   "]" '(evil-window-right :wk "right window")
     282:   "+" '(enlarge-window :wk "enlarge window")
     283:   "-" '(shrink-window :wk "shrink window")
     284:   "}" '(enlarge-window-horizontally :wk "enlarge window horizontally")
     285:   "{" '(shrink-window-horizontally :wk "shrink window horizontally")
     286:   "+" 'evil-window-increase-height
     287:   "-" 'evil-window-decrease-height
     288:   ":" 'evil-ex
     289:   "<" 'evil-window-decrease-width
     290:   "=" 'balance-windows
     291:   ">" 'evil-window-increase-height
     292:   "_" 'evil-window-set-height
     293:   "b" 'evil-window-bottom-right
     294:   "c" 'evil-window-delete
     295:   "d" '(delete-window :wk "delete window")
     296:   "h" 'evil-window-left
     297:   "f" '(ffap-other-window :wk "ffap other window")
     298:   "j" 'evil-window-down
     299:   "k" 'evil-window-up
     300:   "l" 'evil-window-right
     301:   "n" 'evil-window-new
     302:   "p" 'evil-window-mru
     303:   "q" 'evil-quit
     304:   "r" 'evil-window-rotate-downwards
     305:   "R" 'evil-window-rotate-upwards
     306:   "s" 'evil-window-split
     307:   "T" '(tear-off-window :wk "tear off window")
     308:   "t" 'evil-window-top-left
     309:   "u" 'winner-undo
     310:   "v" 'evil-window-vsplit
     311:   "w" '(other-window :wk "other window")
     312:   "W" 'evil-window-prev
     313:   "x" 'evil-window-exchange
     314:   "|" 'evil-window-set-width
     315:   "<left>" 'evil-window-left
     316:   "<right>" 'evil-window-right
     317:   "<down>" 'evil-window-down
     318:   "<up>" 'evil-win-up)
     319: (provide 'config-keybindings)
     320: ;;; config-keybindings.el ends.here
     321: ;; evil
     322: (use-package evil
     323:   :ensure t
     324:   :demand t
     325:   :preface
     326:   (customize-set-variable 'evil-want-keybinding nil)
     327:   (customize-set-variable 'evil-want-integration t)
     328:   (customize-set-variable 'evil-undo-system 'undo-redo)
     329:   (customize-set-variable 'evil-want-C-i-jump nil) ;; fix TAB in terminal org-mode 
     330:   (customize-set-variable 'evil-want-C-u-scroll t) ;; move universal arg to <leader> u
     331:   (customize-set-variable 'evil-want-C-u-delete t) ;; delete back to indentation in insert state
     332:   (customize-set-variable 'evil-want-C-g-bindings t)
     333:   :custom
     334:   (evil-undo-system #'undo-redo)
     335:   (evil-search-module 'evil-search)
     336:   (evil-ex-search-vim-style-regexp t)
     337:   (evil-ex-interactive-search-highlight 'selected-window)
     338:   (evil-kbd-macro-suppress-motion-error t)
     339:   (evil-visual-update-x-selection-p nil)
     340:   :config
     341:   (setq evil-normal-state-cursor 'box
     342:         evil-insert-state-cursor 'bar
     343:         evil-visual-state-cursor 'hollow)
     344:   (evil-select-search-module 'evil-search-module 'evil-search)
     345:   (evil-mode 1)
     346:   (with-eval-after-load 'eldoc
     347:     (eldoc-add-command 'evil-normal-state
     348:                        'evil-insert
     349:                        'evil-change
     350:                        'evil-delete
     351:                        'evil-replace)))
     352: (use-package evil-collection
     353:   :ensure t
     354:   :after evil
     355:   :init
     356:   (evil-collection-init)
     357:   :custom
     358:   (evil-collection-setup-minibuffer t)
     359:   (evil-collection-calendar-want-org-bindings t))
     360: ;; UI
     361: (use-package ace-window
     362:   :ensure
     363:   :config
     364:   (setq aw-keys '(?q ?w ?e ?r ?t ?a ?s ?d ?f ?z ?x ?c ?v)
     365:         aw-background nil
     366:         aw-frame-size 2)
     367:   (custom-set-faces
     368:    '(aw-leading-char-face
     369:      ((t (:inherit ace-jump-face-foreground :height 4.0)))))
     370:   :bind ([remap other-window] . ace-window))
     371: (use-package doom-themes
     372:   :ensure t
     373:   :demand t
     374:   :config
     375:   ;; Global settings (defaults)
     376:   (setq doom-themes-enable-bold t    ; if nil, bold is universally disabled
     377:         doom-themes-enable-italic t) ; if nil, italics is universally disabled
     378:   (load-theme 'doom-nord t)
     379: 
     380:   ;; Enable flashing mode-line on errors
     381:   (doom-themes-visual-bell-config)
     382:   ;; Enable custom neotree theme (all-the-icons must be installed!)
     383:   ;; (doom-themes-neotree-config)
     384:   ;; or for treemacs users
     385:   (setq doom-themes-treemacs-theme "doom-atom") ; use "doom-colors" for less minimal icon theme
     386:   (doom-themes-treemacs-config)
     387:   ;; Corrects (and improves) org-mode's native fontification.
     388:   (doom-themes-org-config))
     389: (use-package doom-modeline
     390:   :ensure
     391:   :init
     392:   (doom-modeline-mode 1)
     393:   :config
     394:   (setq doom-modeline-project-detection 'projectile
     395:         doom-modeline-indent-info t))
     396: ;; use-package with package.el:
     397: (use-package dashboard
     398:   :ensure t
     399:   :demand t
     400:   :init
     401:   (setq dashboard-set-heading-icons t
     402:         dashboard-icon-type 'all-the-icons)
     403:   (setq dashboard-heading-icons '((recents   . "history")
     404:                                   (bookmarks . "bookmark")
     405:                                   (agenda    . "calendar")
     406:                                   (projects  . "rocket")
     407:                                   (registers . "database")))
     408:   :custom
     409:   (initial-buffer-choice (lambda () (get-buffer-create "*dashboard*")))
     410:   (dashboard-startup-banner 'logo)
     411:   (dashboard-set-heading-icons t)
     412:   (dashboard-set-file-icons t)
     413:   (dashboard-display-icons-p t)
     414:   (dashboard-icon-type 'nerd-icons)
     415:   (dashboard-projects-switch-function 'projectile-persp-switch-project)
     416:   (dashboard-week-agenda t)
     417:   (dashboard-filter-agenda-entry nil)
     418:   (dashboard-startup-banner 'logo)
     419:   (dashboard-center-content t)
     420:   (dashboard-vertically-center-content t)
     421:   (dashboard-agenda-sort-strategy
     422:   '(todo-state-up time-down priority-down todo-state-down time-up priority-up))
     423:   (dashboard-navigation-cycle t)
     424:   (dashboard-banner-logo-title nil)
     425:   (dashboard-set-heading-icons t)
     426:   (dashboard-set-footer nil)
     427:   (dashboard-projects-backend 'projectile)
     428:   (dashboard-display-icons-p t)
     429:   (dashboard-items '((recents . 3)
     430:                      (bookmarks . 2)
     431:                      (projects . 5)
     432:                      (agenda . 8)
     433:                      (registers . 2)))
     434:   :config
     435:   (dashboard-setup-startup-hook))
     436: (use-package all-the-icons
     437:   :ensure
     438:   :if (display-graphic-p))
     439: (use-package which-key
     440:   :ensure
     441:   :demand t
     442:   :custom
     443:   (which-key-lighter "")
     444:   (which-key-sort-order #'which-key-key-order-alpha)
     445:   (which-key-sort-uppercase-first nil)
     446:   (which-key-add-column-padding 1)
     447:   (which-key-max-display-columns nil)
     448:   (which-key-min-display-lines 6)
     449:   (which-key-compute-remaps t)
     450:   (which-key-side-window-slot -10)
     451:   (which-key-separator " → ")
     452:   (which-key-allow-evil-operators t)
     453:   (which-key-use-C-h-commands t)
     454:   (which-key-show-remaining-keys t)
     455:   (which-key-show-prefix 'bottom)
     456:   :config
     457:   (which-key-mode)
     458:   (which-key-setup-side-window-bottom)
     459:   (which-key-setup-minibuffer)
     460:   (define-key which-key-mode-map (kbd "C-x <f5>") 'which-key-C-h-dispatch))
     461: (set-face-attribute 'default nil :family "Iosevka Nerd Font Mono")
     462: (set-face-attribute 'variable-pitch nil :family "Iosevka Nerd Font Mono")
     463: (use-package font-core
     464:   :init
     465:   (global-font-lock-mode t))
     466: (use-package rainbow-mode
     467:   :ensure
     468:   :hook (prog-mode . rainbow-mode))
     469: 
     470: (use-package rainbow-identifiers
     471:   :ensure
     472:   :hook (prog-mode . rainbow-identifiers-mode))
     473: 
     474: (use-package rainbow-delimiters
     475:   :ensure
     476:   :hook (prog-mode . rainbow-delimiters-mode))
     477: (use-package helpful
     478:   :ensure
     479:   :bind
     480:   ("C-h f" . helpful-function)
     481:   ([remap describe-symbol] . helpful-symbol)
     482:   ([remap describe-variable] . helpful-variable)
     483:   ([remap describe-command] . helpful-command)
     484:   ([remap describe-key] . helpful-key)
     485:   :custom
     486:   (helpful-max-buffers 2)
     487:   :config
     488:   (with-eval-after-load 'general
     489:     (general-define-key
     490:      "C-h F" 'helpful-function
     491:      :keymaps 'prog-mode-map
     492:      "C-c C-d" 'helpful-at-point)
     493:     (general-nvmap
     494:       :keymaps 'prog-mode-map
     495:       "K" '(helpful-at-point :wk "helpful at point")
     496:       "gr" '(helpful-update :wk "update"))))
     497: (use-package hl-line
     498:   :config
     499:   (global-hl-line-mode 1))
     500: (use-package nerd-icons
     501:   :ensure t
     502:   :custom
     503:   ;; The Nerd Font you want to use in GUI
     504:   ;; "Symbols Nerd Font Mono" is the default and is recommended
     505:   ;; but you can use any other Nerd Font if you want
     506:   (nerd-icons-font-family "Symbols Nerd Font Mono"))
     507: (when (file-directory-p (expand-file-name "site-lisp/nerd-fonts" user-emacs-directory))
     508:   (add-to-list 'load-path (expand-file-name "site-lisp/nerd-fonts" user-emacs-directory)))
     509: 
     510: (use-package nerd-fonts)
     511: (use-package paren
     512:   :config
     513:   (show-paren-mode 1)
     514:   :custom
     515:   (show-paren-style 'mixed))
     516: ;; builtins
     517: (use-package emacs
     518:   :ensure nil
     519:   :init
     520:   ;; Add prompt indicator to `completing-read-multiple'.
     521:   ;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
     522:   (defun crm-indicator (args)
     523:     (cons (format "[CRM%s] %s"
     524:                   (replace-regexp-in-string
     525:                    "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
     526:                    crm-separator)
     527:                   (car args))
     528:           (cdr args)))
     529:   (advice-add #'completing-read-multiple :filter-args #'crm-indicator)
     530:   ;; Do not allow the cursor in the minibuffer prompt
     531:   (setq minibuffer-prompt-properties
     532:         '(read-only t cursor-intangible t face minibuffer-prompt))
     533:   (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
     534:   ;; Emacs 28: Hide commands in M-x which do not work in the current mode.
     535:   ;; Vertico commands are hidden in normal buffers.
     536:   (setq read-extended-command-predicate
     537:         #'command-completion-default-include-p
     538:         tab-always-indent 'complete)
     539:   ;; Enable recursive minibuffers
     540:   (setq enable-recursive-minibuffers t)
     541:   :custom
     542:   (read-buffer-completion-ignore-case t)
     543:   (use-short-answers t)
     544:   (use-dialog-box-p nil)
     545:   (window-resize-pixelwise t)
     546:   (frame-resize-pixelwise t)
     547:   (ring-bell-function #'ignore)
     548:   (scroll-preserve-screen-position t)
     549:   (scroll-conservatively 101)
     550:   (fast-but-imprecise-scrolling t)
     551:   (truncate-partial-width-windows nil)
     552:   (fill-column 80)
     553:   (enable-recursive-minibuffers t)
     554:   (use-file-dialog nil)
     555:   (create-lockfiles nil)
     556:   (delete-by-moving-to-trash t)
     557:   (inhibit-startup-screen t)
     558:   :config
     559:   (setq completion-ignore-case t
     560:         load-prefer-newer t
     561:         auto-window-vscroll nil
     562:         inhibit-compacting-font-caches t
     563:         redisplay-skip-fontification-on-input t)
     564:   (set-default 'indicate-empty-lines t)
     565:   (setq-default x-stretch-cursor t))
     566: (use-package files
     567:   :config
     568:   (defun full-auto-save ()
     569:     (interactive)
     570:     (save-excursion
     571:       (dolist (buf (buffer-list))
     572:         (set-buffer buf)
     573:         (if (and (buffer-file-name) (buffer-modified-p))
     574:             (basic-save-buffer)))))
     575:   (add-hook 'auto-save-hook 'full-auto-save)
     576:   (nconc
     577:    auto-mode-alist
     578:    '(("/LICENSE\\'" . text-mode)
     579:      ("\\.log\\'" . text-mode)
     580:      ("rc\\'" . conf-mode)
     581:      ("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode)))
     582:   :custom
     583:   (confirm-kill-emacs #'yes-or-no-p) ; confirm when exiting
     584:   (confirm-kill-processes nil) ; don't confirm killing processes
     585:   (revert-without-query (list "."))
     586:   (find-file-visit-truename t) ; `find-file' will visit the actual file 
     587:   (version-control t)
     588:   (backup-by-copying t)
     589:   (delete-old-versions t)
     590:   (kept-new-versions 6)
     591:   (kept-old-versions 2)
     592:   (auto-save-include-big-deletions t)
     593:   (auto-save-list-file-prefix (expand-file-name ".autosave/" user-emacs-directory))
     594:   (backup-directory-alist `(("." . ,(expand-file-name ".backup" user-emacs-directory))))
     595:   (auto-mode-case-fold nil)
     596:   (require-final-newline t))
     597: (use-package saveplace
     598:   :init
     599:   (save-place-mode 1)
     600:   :custom
     601:   (save-place-file (expand-file-name "places" user-emacs-directory)))
     602: (use-package autorevert
     603:   :init
     604:   (global-auto-revert-mode 1)
     605:   :custom
     606:   (auto-revert-interval 60)
     607:   (global-auto-revert-non-file-buffers t)
     608:   (auto-revert-verbose nil)
     609:   (auto-revert-stop-on-user-input t))
     610: (use-package savehist
     611:   :init
     612:   (savehist-mode 1)
     613:   :custom
     614:   (savehist-file (expand-file-name "history" user-emacs-directory))
     615:   (savehist-coding-system 'utf-8)
     616:   (savehist-additional-variables
     617:    '(evil-jumps-history
     618:      kill-ring
     619:      register-alist
     620:      mark-ring
     621:      global-mark-ring
     622:      search-ring
     623:      regexp-search-ring)))
     624: (use-package recentf
     625:   :bind ("C-c f" . recentf)
     626:   :custom
     627:   (recentf-max-saved-items 250)
     628:   (recentf-max-menu-items 300)
     629:   (recentf-exclude
     630:    `("/elpa/" ;; ignore all files in elpa directory
     631:      "recentf" ;; remove the recentf load file
     632:      ".*?autoloads.el$"
     633:      "treemacs-persist"
     634:      "company-statistics-cache.el" ;; ignore company cache file
     635:      "/intero/" ;; ignore script files generated by intero
     636:      "/journal/" ;; ignore daily journal files
     637:      ".gitignore" ;; ignore `.gitignore' files in projects
     638:      "/tmp/" ;; ignore temporary files
     639:      "NEWS" ;; don't include the NEWS file for recentf
     640:      "bookmarks"  "bmk-bmenu" ;; ignore bookmarks file in .emacs.d
     641:      "loaddefs.el"
     642:      "^/\\(?:ssh\\|su\\|sudo\\)?:" ;; ignore tramp/ssh files
     643:      (concat "^" (regexp-quote (or (getenv "XDG_RUNTIME_DIR")))))))
     644: (use-package server
     645:   :config
     646:   (unless (server-running-p)
     647:     (server-start))
     648:   (require 'org-protocol))
     649: (use-package prog-mode
     650:   :hook ((prog-mode . prettify-symbols-mode)
     651:          (prog-mode . visual-line-mode)
     652:          ;; (prog-mode . (lambda () (electric-pair-mode 1)))
     653:          )
     654:   :config
     655:   (setq prettify-symbols-alist
     656:         '(("|>" . "▷")
     657:           ("<|" . "◁")
     658:           ("->>" . "↠  ")
     659:           ("->" . "→ ")
     660:           ("<-" . "← ")
     661:           ("=>" . "⇒"))))
     662: (use-package bookmark
     663:   :custom
     664:   (bookmark-save-flag 1)
     665:   (bookmark-default-file (expand-file-name ".bookmark" user-emacs-directory)))
     666: (use-package tramp
     667:   :custom
     668:   (tramp-backup-directory-alist backup-directory-alist)
     669:   (tramp-auto-save-directory (expand-file-name ".tramp-autosave/" user-emacs-directory)))
     670: (use-package epg-config
     671:   :custom
     672:   (epg-pinentry-mode 'loopback))
     673: (use-package simple
     674:   :custom
     675:   (save-interprogram-paste-before-kill t)
     676:   (shift-select-mode nil)
     677:   (kill-do-not-save-duplicates t)
     678:   (shift-select-mode nil)
     679:   (set-mark-command-repeat-pop t)
     680:   (indent-tabs-mode nil)
     681:   (column-number-mode t)
     682:   (idle-update-delay 1.0)
     683:   :config
     684:   (with-eval-after-load 'evil
     685:     (evil-set-initial-state #'message-mode 'insert)))
     686: ;; completion
     687: (use-package vertico
     688:   :ensure
     689:   :init
     690:   (vertico-mode)
     691:   ;; Different scroll margin
     692:   ;; (setq vertico-scroll-margin 0)
     693:   ;; Show more candidates
     694:   ;; (setq vertico-count 20)
     695:   ;; Grow and shrink the Vertico minibuffer
     696:   ;; (setq vertico-resize t)
     697:   ;; Optionally enable cycling for `vertico-next' and `vertico-previous'.
     698:   (setq vertico-cycle t)
     699:   )
     700: 
     701: ;; A few more useful configurations...
     702: (use-package emacs
     703:   :init
     704:   ;; Add prompt indicator to `completing-read-multiple'.
     705:   ;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
     706:   (defun crm-indicator (args)
     707:     (cons (format "[CRM%s] %s"
     708:                   (replace-regexp-in-string
     709:                    "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
     710:                    crm-separator)
     711:                   (car args))
     712:           (cdr args)))
     713:   (advice-add #'completing-read-multiple :filter-args #'crm-indicator)
     714:   ;; Do not allow the cursor in the minibuffer prompt
     715:   (setq minibuffer-prompt-properties
     716:         '(read-only t cursor-intangible t face minibuffer-prompt))
     717:   (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
     718:   ;; Support opening new minibuffers from inside existing minibuffers.
     719:   (setq enable-recursive-minibuffers t)
     720:   ;; Emacs 28 and newer: Hide commands in M-x which do not work in the current
     721:   ;; mode.  Vertico commands are hidden in normal buffers. This setting is
     722:   ;; useful beyond Vertico.
     723:   (setq read-extended-command-predicate #'command-completion-default-include-p))
     724: (use-package vertico-directory
     725:   :after vertico
     726:   :ensure nil
     727:   ;; More convenient directory navigation commands
     728:   :bind (:map vertico-map
     729:               ("RET" . vertico-directory-enter)
     730:               ("DEL" . vertico-directory-delete-char)
     731:               ("M-DEL" . vertico-directory-delete-word))
     732:   ;; Tidy shadowed file names
     733:   :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
     734: (use-package vertico-quick
     735:   :after vertico
     736:   :ensure nil
     737:   :bind (:map vertico-map
     738:               ("M-q" . vertico-quick-insert)
     739:               ("C-q" . vertico-quick-exit)))
     740: ;; Enable rich annotations using the Marginalia package
     741: (use-package marginalia
     742:   :ensure
     743:   :bind (:map minibuffer-local-map
     744:               ("M-A" . marginalia-cycle))
     745:   :init
     746:   (marginalia-mode))
     747: (use-package corfu
     748:   :ensure
     749:   :custom
     750:   (corfu-cycle t)
     751:   (corfu-auto t)
     752:   (corfu-quit-no-match 'separator)
     753:   (corfu-preselect 'prompt)
     754:   (completion-cycle-threshold 3)
     755:   :init
     756:   (global-corfu-mode))
     757: (use-package consult
     758:   :ensure
     759:   :hook (completion-list-mode . consult-preview-at-point-mode)
     760:   :init
     761:   ;; Optionally configure the register formatting. This improves the register
     762:   ;; preview for `consult-register', `consult-register-load',
     763:   ;; `consult-register-store' and the Emacs built-ins.
     764:   (setq register-preview-delay 0.5
     765:         register-preview-function #'consult-register-format)
     766:   ;; Optionally tweak the register preview window.
     767:   ;; This adds thin lines, sorting and hides the mode line of the window.
     768:   (advice-add #'register-preview :override #'consult-register-window)
     769:   ;; Use Consult to select xref locations with preview
     770:   (setq xref-show-xrefs-function #'consult-xref
     771:         xref-show-definitions-function #'consult-xref)
     772:   ;; Configure other variables and modes in the :config section,
     773:   ;; after lazily loading the package.
     774:   :config
     775:   ;; Optionally configure preview. The default value
     776:   ;; is 'any, such that any key triggers the preview.
     777:   ;; (setq consult-preview-key 'any)
     778:   ;; (setq consult-preview-key "M-.")
     779:   ;; (setq consult-preview-key '("S-<down>" "S-<up>"))
     780:   ;; For some commands and buffer sources it is useful to configure the
     781:   ;; :preview-key on a per-command basis using the `consult-customize' macro.
     782:   (consult-customize
     783:    consult-theme :preview-key '(:debounce 0.2 any)
     784:    consult-ripgrep consult-git-grep consult-grep
     785:    consult-bookmark consult-recent-file consult-xref
     786:    consult--source-bookmark consult--source-file-register
     787:    consult--source-recent-file consult--source-project-recent-file
     788:    ;; :preview-key "M-."
     789:    :preview-key '(:debounce 0.4 any))
     790:   ;; Optionally configure the narrowing key.
     791:   ;; Both < and C-+ work reasonably well.
     792:   (setq consult-narrow-key "<") ;; "C-+"
     793:   ;; Optionally make narrowing help available in the minibuffer.
     794:   ;; You may want to use `embark-prefix-help-command' or which-key instead.
     795:   ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)
     796:   ;; By default `consult-project-function' uses `project-root' from project.el.
     797:   ;; Optionally configure a different project root function.
     798: ;;;; 1. project.el (the default)
     799:   ;; (setq consult-project-function #'consult--default-project--function)
     800: ;;;; 2. vc.el (vc-root-dir)
     801:   ;; (setq consult-project-function (lambda (_) (vc-root-dir)))
     802: ;;;; 3. locate-dominating-file
     803:   ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
     804: ;;;; 4. projectile.el (projectile-project-root)
     805:   ;; (autoload 'projectile-project-root "projectile")
     806:   ;; (setq consult-project-function (lambda (_) (projectile-project-root)))
     807: ;;;; 5. No project support
     808:   ;; (setq consult-project-function nil))
     809: )
     810: 
     811: (use-package orderless
     812:   :ensure
     813:   :init
     814:   ;; Configure a custom style dispatcher (see the Consult wiki)
     815:   ;; (setq orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-dispatch)
     816:   ;;       orderless-component-separator #'orderless-escapable-split-on-space)
     817:   (setq completion-styles '(orderless basic)
     818:         completion-category-defaults nil
     819:         completion-category-overrides '((file (styles partial-completion)))))
     820: (use-package nerd-icons-corfu
     821:   :ensure
     822:   :config
     823:   (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)
     824:   (setq nerd-icons-corfu-mapping
     825:         '((array :style "cod" :icon "symbol_array" :face font-lock-type-face)
     826:           (boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face)
     827:           ;; ...
     828:           (t :style "cod" :icon "code" :face font-lock-warning-face))))
     829: (use-package nerd-icons-completion
     830:   :ensure
     831:   :hook (marginalia-mode . nerd-icons-completion-marginalia-setup)
     832:   :config
     833:   (nerd-icons-completion-mode))
     834: ;; shells
     835: (use-package eshell
     836:   :ensure nil
     837:   :custom
     838:   (eshell-history-size 10000)
     839:   (eshell-hist-ignore-dups t)
     840:   (eshell-buffer-maximum-lines 10000)
     841:   (eshell-scroll-to-bottom-on-input t)
     842:   (eshell-destroy-buffer-when-process-dies t)
     843:   (eshell-prompt-regexp "^[^\)]*[\)] "))
     844: (use-package eshell-syntax-highlighting
     845:   :ensure
     846:   :defer t
     847:   :after eshell
     848:   :config
     849:   (eshell-syntax-highlighting-global-mode +1))
     850: (use-package esh-autosuggest
     851:   :defer t
     852:   :hook (eshell-mode . esh-autosuggest-mode)
     853:   ;; If you have use-package-hook-name-suffix set to nil, uncomment and use the
     854:   ;; line below instead:
     855:   ;; :hook (eshell-mode-hook . esh-autosuggest-mode)
     856:   :ensure t)
     857: (use-package sh-script
     858:   :mode ("\\.bats\\'" . sh-mode)
     859:   :mode ("\\.\\(?:zunit\\|env\\)\\'" . sh-mode)
     860:   :mode ("/bspwmrc\\'" . sh-mode)
     861:   :hook (sh-mode-local-vars . lsp-deferred)
     862:   :hook (sh-mode-local-vars . tree-sitter-mode)
     863:   :config
     864:   (with-eval-after-load 'lsp
     865:     (add-hook 'sh-mode-hook #'lsp-deferred)
     866:     (add-hook 'shell-mode-hook #'lsp-deferred)
     867:     (add-hook 'sh-mode-local-vars-hook #'lsp-deferred))
     868:   (with-eval-after-load 'rainbow-delimiters
     869:     (add-hook 'sh-mode #'rainbow-delimiters-mode))
     870:   ;; recognize function names with dashes in them
     871:   (setq sh-indent-after-continuation 'always)
     872:   (add-to-list 'sh-imenu-generic-expression
     873:                '(sh (nil "^\\s-*function\\s-+\\([[:alpha:]_-][[:alnum:]_-]*\\)\\s-*\\(?:()\\)?" 1)
     874:                     (nil "^\\s-*\\([[:alpha:]_-][[:alnum:]_-]*\\)\\s-*()" 1)))
     875:   (with-eval-after-load 'smartparens
     876:     (sp-local-pair 'sh-mode "`" "`" :unless '(sp-point-before-word-p sp-point-before-same-p))))
     877: (use-package vterm
     878:   :ensure
     879:   :defer t
     880:   :commands vterm-mode
     881:   :config
     882:   (add-hook 'vterm-mode-hook
     883:             (lambda ()
     884:               (setq-local global-hl-line-mode nil)
     885:               (setq-local hscroll-margin 0)))
     886:   (setq vterm-kill-buffer-on-exit t)
     887:   :general
     888:   (+config/leader-menu! "vterm"
     889:       "tv"
     890:     "RET" 'vterm-toggle
     891:     "v" 'vterm))
     892: (use-package multi-vterm
     893:   :ensure
     894:   :defer t
     895:   :after vterm
     896:   :general
     897:   (general-iemap
     898:     :keymaps 'vterm-mode-map
     899:     "C-SPC" '(:ignore t :wk "multi vterm")
     900:     "C-SPC a" '(multi-vterm :wk "new vterm buffer")
     901:     "C-SPC n" '(multi-vterm-next :wk "next vterm buffer")
     902:     "C-SPC p" '(multi-vterm-prev :wk "previous vterm buffer")))
     903: (use-package vterm-toggle
     904:   :ensure
     905:   :defer t
     906:   :after vterm
     907:   :commands vterm-toggle
     908:   :bind
     909:   (:map vterm-mode-map
     910:         ("C-<return>" . vterm-toggle-insert-cd))
     911:   :config
     912:   (setq vterm-toggle-fullscreen-p nil)
     913:   (add-to-list 'display-buffer-alist
     914:                '((lambda (buffer-or-name _)
     915:                    (let ((buffer (get-buffer buffer-or-name)))
     916:                      (with-current-buffer buffer
     917:                        (or (equal major-mode 'vterm-mode)
     918:                            (string-prefix-p vterm-buffer-name (buffer-name buffer))))))
     919:                  (display-buffer-reuse-window display-buffer-at-bottom)
     920:                  ;;(display-buffer-reuse-window display-buffer-in-direction)
     921:                  ;;display-buffer-in-direction/direction/dedicated is added in emacs27
     922:                  ;;(direction . bottom)
     923:                  (dedicated . t) ;dedicated is supported in emacs27
     924:                  (reusable-frames . visible)
     925:                  (window-height . 0.4))))
     926: (use-package bash-completion
     927:   :ensure
     928:   :defer t
     929:   :config
     930:   (bash-completion-setup)
     931:   :hook
     932:   (shell-dynamic-complete-function bash-completion-dynamic-complete))
     933: ;; editing
     934: (use-package select
     935:   :custom
     936:   (select-enable-clipboard t))
     937: (transient-mark-mode 1)
     938: (delete-selection-mode 1)
     939: (use-package subword
     940:   :init
     941:   (global-subword-mode 1))
     942: (use-package text-mode
     943:   :ensure nil
     944:   :hook (text-mode . visual-line-mode)
     945:   :config
     946:   (setq-default sentence-end-double-space nil))
     947: (use-package ws-butler
     948:   :ensure
     949:   :hook (prog-mode . ws-butler-mode))
     950: ;; smartparens
     951: (use-package smartparens
     952:   :ensure
     953:   :demand t
     954:   :init
     955:   (smartparens-global-mode)
     956:   :config
     957:   ;; smartparens recognizes `slime-mrepl-mode', but not `sly-mrepl-mode', so...
     958:   (add-to-list 'sp-lisp-modes 'sly-mrepl-mode)
     959:   (require 'smartparens-config)
     960:   (add-hook 'eval-expression-minibuffer-setup-hook #'smartparens-mode)
     961:   ;; Overlays are too distracting and not terribly helpful. show-parens does
     962:   ;; this for us already (and is faster), so...
     963:   (setq sp-highlight-pair-overlay nil
     964:         sp-highlight-wrap-overlay nil
     965:         sp-highlight-wrap-tag-overlay nil)
     966:   (show-smartparens-global-mode 1)
     967:   (smartparens-global-mode 1)
     968:   ;; Fix usage of ' in Lisp modes
     969:   ;; THANKS: https://github.com/Fuco1/smartparens/issues/286#issuecomment-32324743
     970:   ;; (eval) is used as a hack to quiet Flycheck errors about (sp-with-modes)
     971:   (eval
     972:    '(sp-with-modes sp-lisp-modes
     973:       ;; disable ', it's the quote character!
     974:       (sp-local-pair "'" nil :actions nil)
     975:       ;; also only use the pseudo-quote inside strings where it serve as
     976:       ;; hyperlink.
     977:       (sp-local-pair "`" "'" :when '(sp-in-string-p sp-in-comment-p))
     978:       (sp-local-pair "`" nil
     979:                      :skip-match (lambda (ms mb me)
     980:                                    (cond
     981:                                     ((equal ms "'")
     982:                                      (or (sp--org-skip-markup ms mb me)
     983:                                          (not (sp-point-in-string-or-comment))))
     984:                                     (t (not (sp-point-in-string-or-comment))))))))
     985:   (sp-with-modes '(html-mode sgml-mode nxml-mode web-mode)
     986:     (sp-local-pair "<" ">"))
     987: 
     988:   (defun sp--markdown-skip-asterisk (ms mb me)
     989:     (save-excursion
     990:       (goto-char mb)
     991:       (save-match-data (looking-at "^\\* "))))
     992: 
     993:   (sp-with-modes 'markdown-mode
     994:     (sp-local-pair "*" "*"
     995:                    :unless '(sp-point-after-word-p sp-point-at-bol-p)
     996:                    :skip-match 'sp--markdown-skip-asterisk)
     997:     (sp-local-pair "**" "**")
     998:     (sp-local-pair "_" "_" :unless '(sp-point-after-word-p)))
     999: 
    1000:   ;;; org-mode
    1001:   (defun sp--org-skip-asterisk (ms mb me)
    1002:     (or (and (= (line-beginning-position) mb)
    1003:              (eq 32 (char-after (1+ mb))))
    1004:         (and (= (1+ (line-beginning-position)) me)
    1005:              (eq 32 (char-after me)))))
    1006:   (defun sp--org-inside-LaTeX (id action context)
    1007:     (org-inside-LaTeX-fragment-p))
    1008:   (sp-with-modes 'org-mode
    1009:     (sp-local-pair "*" "*"
    1010:                    :unless '(sp-point-after-word-p sp--org-inside-LaTeX sp-point-at-bol-p)
    1011:                    :skip-match 'sp--org-skip-asterisk)
    1012:     (sp-local-pair "/" "/" :unless '(sp-point-after-word-p sp--org-inside-LaTeX))
    1013:     (sp-local-pair "~" "~" :unless '(sp-point-after-word-p sp--org-inside-LaTeX))
    1014:     (sp-local-pair "=" "=" :unless '(sp-point-after-word-p sp--org-inside-LaTeX))
    1015:     (sp-local-pair "\\[" "\\]"))
    1016: 
    1017:   ;; haskell
    1018:   (add-to-list 'sp-no-reindent-after-kill-modes 'haskell-mode)
    1019: 
    1020:   ;; You're likely writing lisp in the minibuffer, therefore, disable these
    1021:   ;; quote pairs, which lisps doesn't use for strings:
    1022:   (sp-local-pair '(minibuffer-mode minibuffer-inactive-mode) "'" nil :actions nil)
    1023:   (sp-local-pair '(minibuffer-mode minibuffer-inactive-mode) "`" nil :actions nil)
    1024:   )
    1025: ;; IDE stuffs
    1026: ;; org-mode
    1027: (use-package org
    1028:   :commands org-tempo
    1029:   :preface
    1030:   (if (not +config/org-directory)
    1031:       (cond
    1032:        ((file-directory-p
    1033:          (expand-file-name "Dropbox/org" (getenv "HOME")))
    1034:         (setq org-directory (expand-file-name "Dropbox/org" (getenv "HOME"))))
    1035:        ((file-directory-p
    1036:          (expand-file-name "Sync/org" (getenv "HOME")))
    1037:         (setq org-directory (expand-file-name "Sync/org" (getenv "HOME"))))
    1038:        ((file-directory-p
    1039:          (expand-file-name "Documents/google-drive/org" (getenv "HOME")))
    1040:         (setq org-directory (expand-file-name "Documents/google-drive/org" (getenv "HOME")))))
    1041:     (customize-set-variable 'org-directory +config/org-directory))
    1042:   :hook ((org-mode . org-indent-mode)
    1043:          (org-mode . +config/org-prettify-symbols))
    1044:   :config
    1045:   (global-set-key (kbd "C-c l") #'org-store-link)
    1046:   (global-set-key (kbd "C-c a") #'org-agenda)
    1047:   (global-set-key (kbd "C-c c") #'org-capture)
    1048:   (when(file-directory-p (expand-file-name "braindump/org" org-directory))
    1049:     (customize-set-variable '+config/org-roam-directory
    1050:                             (expand-file-name "braindump/org" org-directory)))
    1051:   (when (file-directory-p (expand-file-name "alexforsale.github.io" org-directory))
    1052:     (customize-set-variable '+config/blog-directory
    1053:                             (expand-file-name "alexforsale.github.io" org-directory)))
    1054:   (modify-syntax-entry ?= "$" org-mode-syntax-table)
    1055:   (modify-syntax-entry ?~ "$" org-mode-syntax-table)
    1056:   (modify-syntax-entry ?_ "$" org-mode-syntax-table)
    1057:   (modify-syntax-entry ?+ "$" org-mode-syntax-table)
    1058:   (modify-syntax-entry ?/ "$" org-mode-syntax-table)
    1059:   (modify-syntax-entry ?* "$" org-mode-syntax-table)
    1060:   (add-to-list 'org-modules 'org-tempo t)
    1061:   (add-to-list 'org-structure-template-alist '("sh" . "src sh"))
    1062:   (add-to-list 'org-structure-template-alist '("co" . "src conf"))
    1063:   (add-to-list 'org-structure-template-alist '("lisp" . "src lisp"))
    1064:   (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
    1065:   (add-to-list 'org-structure-template-alist '("sc" . "src scheme"))
    1066:   (add-to-list 'org-structure-template-alist '("ts" . "src typescript"))
    1067:   (add-to-list 'org-structure-template-alist '("py" . "src python"))
    1068:   (add-to-list 'org-structure-template-alist '("go" . "src go"))
    1069:   (add-to-list 'org-structure-template-alist '("yaml" . "src yaml"))
    1070:   (add-to-list 'org-structure-template-alist '("js" . "src js"))
    1071:   (add-to-list 'org-structure-template-alist '("json" . "src json"))
    1072:   (add-to-list 'org-structure-template-alist '("n" . "note"))
    1073:   (org-babel-do-load-languages
    1074:    'org-babel-load-languages
    1075:    '((emacs-lisp . t)
    1076:      (awk . t)
    1077:      (C . t)
    1078:      (css . t)
    1079:      (calc . t)
    1080:      ;; (ditaa . t) ; needs the `ditaa' package
    1081:      ;; (diagrams . t) ; `ob-diagrams'
    1082:      ;; (dot . t ) ; `graphviz'
    1083:      (screen . t)
    1084:      (haskell . t)
    1085:      (java . t)
    1086:      (js . t)
    1087:      (latex . t)
    1088:      (lisp . t)
    1089:      (lua . t)
    1090:      (org . t)
    1091:      (perl . t)
    1092:      (plantuml . t)
    1093:      (python .t)
    1094:      (ruby . t)
    1095:      (shell . t)
    1096:      (sed . t)
    1097:      (scheme . t)
    1098:      (sql . t)
    1099:      (sqlite . t)))
    1100:   (setq-default org-use-sub-superscripts '{})
    1101:   (add-to-list 'org-babel-tangle-lang-exts '("js" . "js"))
    1102:   (defun +config/org-prettify-symbols ()
    1103:     (push '("[ ]" . "☐") prettify-symbols-alist)
    1104:     (push '("[X]" . "☑") prettify-symbols-alist)
    1105:     (prettify-symbols-mode))
    1106:   :custom
    1107:   (org-replace-disputed-keys t)
    1108:   (org-indirect-buffer-display 'current-window)
    1109:   (org-enforce-todo-dependencies t)
    1110:   (org-fontify-whole-heading-line t)
    1111:   (org-return-follows-link t)
    1112:   (org-mouse-1-follows-link t)
    1113:   (org-image-actual-width nil)
    1114:   (org-adapt-indentation nil)
    1115:   (org-startup-indented t)
    1116:   (org-link-descriptive nil)
    1117:   (org-log-done 'time)
    1118:   (org-log-refile 'time)
    1119:   (org-log-redeadline 'time)
    1120:   (org-log-reschedule 'time)
    1121:   (org-log-into-drawer t)
    1122:   (org-clone-delete-id t)
    1123:   (org-default-notes-file (expand-file-name "notes.org" org-directory))
    1124:   (org-insert-heading-respect-content nil)
    1125:   (org-pretty-entities t)
    1126:   (org-use-property-inheritance t)
    1127:   (org-priority-highest ?A)
    1128:   (org-priority-lowest ?D)
    1129:   (org-priority-default ?B)
    1130:   (org-todo-keywords
    1131:    '((sequence
    1132:       "TODO(t!)"  ; A task that needs doing & is ready to do
    1133:       "NEXT(n!)"  ; Tasks that can be delayed
    1134:       "PROG(p!)"  ; A task that is in progress
    1135:       "WAIT(w!)"  ; Something external is holding up this task
    1136:       "HOLD(h!)"  ; This task is paused/on hold because of me
    1137:       "|"
    1138:       "DONE(d!)"  ; Task successfully completed
    1139:       "DELEGATED(l!)" ; Task is delegated
    1140:       "KILL(k!)") ; Task was cancelled, aborted or is no longer applicable
    1141:      ))
    1142:   (org-todo-keyword-faces
    1143:    '(("PROG" . (:foreground "#5e81ac" :weight bold))
    1144:      ("WAIT" . (:foreground "#ebcb8b" :weight bold))
    1145:      ("HOLD" . (:foreground "#d08770" :weight bold))
    1146:      ("NEXT" . (:foreground "#81a1c1" :weight bold))
    1147:      ("DELEGATED" . "#8fbcbb")
    1148:      ("KILL" . "#a3be8c"))))
    1149: (use-package org-faces
    1150:   :custom
    1151:   (org-fontify-quote-and-verse-blocks t))
    1152: (use-package org-archive
    1153:   :after org
    1154:   :custom
    1155:   (org-archive-tag "archive")
    1156:   (org-archive-subtree-save-file-p t)
    1157:   (org-archive-mark-done t)
    1158:   (org-archive-reversed-order t)
    1159:   (org-archive-location (concat (expand-file-name "archives.org" org-directory) "::datetree/* Archived Tasks")))
    1160: (use-package org-capture
    1161:   :after org
    1162:   :demand t
    1163:   :config
    1164:   (org-capture-put :kill-buffer t)
    1165:   (setq org-capture-templates ;; this is the default from `doom'.
    1166:         `(("i" "Inbox - Goes Here first!" entry
    1167:            (file+headline ,(expand-file-name "inbox.org" org-directory) "Inbox")
    1168:            "** %?\n%i\n%a" :prepend t)
    1169:           ("r" "Request" entry (file+headline ,(expand-file-name "inbox.org" org-directory) "Request")
    1170:            (file ,(expand-file-name "request.template" org-directory)))
    1171:           ("l" "Links" entry
    1172:            (file+headline ,(expand-file-name "links.org" org-directory) "Links")))))
    1173: (use-package org-refile
    1174:   :after org
    1175:   :hook (org-after-refile-insert . save-buffer)
    1176:   :custom
    1177:   (org-refile-targets
    1178:    `((,(expand-file-name "projects.org" org-directory) :maxlevel . 1)
    1179:      (,(expand-file-name "routines.org" org-directory) :maxlevel . 1)
    1180:      (,(expand-file-name "personal.org" org-directory) :maxlevel . 1)))
    1181:   (org-refile-use-outline-path 'file)
    1182:   (org-outline-path-complete-in-steps nil))
    1183: (use-package org-num
    1184:   :after org
    1185:   :custom
    1186:   (org-num-face '(:inherit org-special-keyword :underline nil :weight bold))
    1187:   (org-num-skip-tags '("noexport" "nonum")))
    1188: (use-package org-fold
    1189:   :after org org-contrib
    1190:   :custom
    1191:   (org-catch-invisible-edits 'smart))
    1192: (use-package org-id
    1193:   :after org
    1194:   :custom
    1195:   (org-id-locations-file-relative t)
    1196:   (org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id))
    1197: (use-package org-crypt ; built-in
    1198:   :after org
    1199:   :commands org-encrypt-entries org-encrypt-entry org-decrypt-entries org-decrypt-entry
    1200:   ;;:hook (org-reveal-start . org-decrypt-entry)
    1201:   :preface
    1202:   ;; org-crypt falls back to CRYPTKEY property then `epa-file-encrypt-to', which
    1203:   ;; is a better default than the empty string `org-crypt-key' defaults to.
    1204:   (defvar org-crypt-key nil)
    1205:   (with-eval-after-load 'org
    1206:     (add-to-list 'org-tags-exclude-from-inheritance "crypt")))
    1207: (use-package org-attach
    1208:   :after org
    1209:   :commands (org-attach-new
    1210:              org-attach-open
    1211:              org-attach-open-in-emacs
    1212:              org-attach-reveal-in-emacs
    1213:              org-attach-url
    1214:              org-attach-set-directory
    1215:              org-attach-sync)
    1216:   :config
    1217:   (unless org-attach-id-dir
    1218:     (setq-default org-attach-id-dir (expand-file-name ".attach/" org-directory)))
    1219:   (with-eval-after-load 'projectile
    1220:     (add-to-list 'projectile-globally-ignored-directories org-attach-id-dir))
    1221:   :custom
    1222:   (org-attach-auto-tag nil))
    1223: (use-package org-clock
    1224:   :after org
    1225:   :commands org-clock-save
    1226:   :hook (kill-emacs . org-clock-save)
    1227:   :custom
    1228:   (org-persist 'history)
    1229:   (org-clock-in-resume t)
    1230:   (org-clock-out-remove-zero-time-clocks t)
    1231:   (org-clock-history-length 20)
    1232:   (org-show-notification-handler "notify-send")
    1233:   (org-agenda-skip-scheduled-if-deadline-is-shown t)
    1234:   :config
    1235:   (org-clock-persistence-insinuate))
    1236: (use-package org-agenda
    1237:   :after org
    1238:   :custom
    1239:   (org-agenda-files (list (concat org-directory "/")))
    1240:   (org-agenda-file-regexp "\\`[^.].*\\.org\\|[0-9]+$\\'")
    1241:   (org-agenda-include-inactive-timestamps t)
    1242:   (org-agenda-window-setup 'only-window)
    1243:   (org-stuck-projects '("+{project*}-killed-Archives/-DONE-KILL-DELEGATED"
    1244:                         ("TODO" "NEXT" "IDEA" "PROG")
    1245:                         nil ""))
    1246:   :config
    1247:   (with-eval-after-load 'evil
    1248:     (evil-set-initial-state #'org-agenda-mode 'normal))
    1249:   (setq org-agenda-custom-commands
    1250:         `(("w" "Work Agenda and all TODOs"
    1251:            ((agenda ""
    1252:                     ((org-agenda-span 1)
    1253:                      (org-agenda-start-on-weekday t)
    1254:                      (org-agenda-block-separator nil)
    1255:                      (org-agenda-use-time-grid t)
    1256:                      (org-agenda-day-face-function (lambda (date) 'org-agenda-date))
    1257:                      (org-agenda-format-date "%A %-e %B %Y")
    1258:                      (org-agenda-overriding-header "\nToday\n")))
    1259:             (tags-todo "TODO=\"TODO\"|\"NEXT\""
    1260:                        ((org-agenda-block-separator nil)
    1261:                         (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done))
    1262:                         (org-agenda-use-time-grid nil)
    1263:                         (org-agenda-overriding-header "\nIncomplete\n")))
    1264:             (agenda ""
    1265:                     ((org-agenda-span 7)
    1266:                      (org-agenda-start-on-weekday 1)
    1267:                      (org-agenda-block-separator nil)
    1268:                      (org-agenda-use-time-grid nil)
    1269:                      (org-agenda-overriding-header "\nWeekly\n"))))
    1270:            ((org-agenda-tag-filter-preset '("-personal" "-home"))))
    1271:           ("h" "Home Agenda and all personal TODOs"
    1272:            ((agenda ""
    1273:                     ((org-agenda-span 1)
    1274:                      (org-agenda-start-on-weekday t)
    1275:                      (org-agenda-block-separator nil)
    1276:                      (org-agenda-use-time-grid t)
    1277:                      (org-agenda-day-face-function (lambda (date) 'org-agenda-date))
    1278:                      (org-agenda-format-date "%A %-e %B %Y")
    1279:                      (org-agenda-overriding-header "\nToday\n")))
    1280:             (tags-todo "TODO=\"TODO\"|\"NEXT\""
    1281:                        ((org-agenda-block-separator nil)
    1282:                         (org-agenda-skip-function '(org-agenda-skip-if-todo 'nottodo 'done))
    1283:                         (org-agenda-use-time-grid nil)
    1284:                         (org-agenda-overriding-header "\nIncomplete\n")))
    1285:             (agenda ""
    1286:                     ((org-agenda-span 7)
    1287:                      (org-agenda-start-on-weekday 1)
    1288:                      (org-agenda-block-separator nil)
    1289:                      (org-agenda-use-time-grid nil)
    1290:                      (org-agenda-overriding-header "\nWeekly\n"))))
    1291:            ((org-agenda-tag-filter-preset '("+personal")))))))
    1292: (use-package org-timer
    1293:   :config
    1294:   (setq org-timer-format "Timer :: %s"))
    1295: (use-package org-eldoc
    1296:   :after org org-contrib
    1297:   :config
    1298:   (puthash "org" #'ignore org-eldoc-local-functions-cache)
    1299:   (puthash "plantuml" #'ignore org-eldoc-local-functions-cache)
    1300:   (puthash "python" #'python-eldoc-function org-eldoc-local-functions-cache)
    1301:   :custom
    1302:   (org-eldoc-breadcrumb-separator " → "))
    1303: (use-package org-superstar
    1304:   :ensure
    1305:   :hook (org-mode . org-superstar-mode)
    1306:   :custom
    1307:   (org-superstar-leading-bullet ?\s)
    1308:   (org-superstar-leading-fallback ?\s)
    1309:   (org-hide-leading-stars nil)
    1310:   (org-indent-mode-turns-on-hiding-stars nil)
    1311:   (org-superstar-todo-bullet-alist
    1312:    '(("TODO" . 9744)
    1313:      ("[ ]"  . 9744)
    1314:      ("DONE" . 9745)
    1315:      ("[X]"  . 9745)))
    1316:   :config
    1317:   (org-superstar-configure-like-org-bullets))
    1318: (use-package org-fancy-priorities ; priority icons
    1319:   :ensure
    1320:   :defer t
    1321:   :hook (org-mode . org-fancy-priorities-mode)
    1322:   :hook (org-agenda-mode . org-fancy-priorities-mode)
    1323:   :custom
    1324:   (org-fancy-priorities-list '("⚡" "⬆" "⬇" "☕")))
    1325: (use-package org-modern
    1326:   :ensure t
    1327:   :demand t
    1328:   :config
    1329:   (set-face-attribute 'org-modern-symbol nil :family "Iosevka Nerd Font")
    1330:   (setq
    1331:    ;; Edit settings
    1332:    org-auto-align-tags nil
    1333:    org-tags-column 0
    1334:    org-fold-catch-invisible-edits 'show-and-error
    1335:    org-special-ctrl-a/e t
    1336:    org-insert-heading-respect-content t
    1337:    ;; Org styling, hide markup etc.
    1338:    org-hide-emphasis-markers nil ; set to nil for easier editing
    1339:    org-ellipsis "…"
    1340:    ;; Agenda styling
    1341:    org-agenda-tags-column 0
    1342:    org-agenda-block-separator ?─
    1343:    org-agenda-time-grid
    1344:    '((daily today require-timed)
    1345:      (800 1000 1200 1400 1600 1800 2000)
    1346:      " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
    1347:    org-agenda-current-time-string
    1348:    "◀── now ─────────────────────────────────────────────────")
    1349:   (global-org-modern-mode))
    1350: ;; tools
    1351: (use-package make-mode
    1352:   :config
    1353:   (add-hook 'makefile-mode-hook 'indent-tabs-mode))
    1354: (use-package executable
    1355:   :hook
    1356:   (after-save . executable-make-buffer-file-executable-if-script-p))
    1357: (use-package pinentry
    1358:   :ensure
    1359:   :defer t
    1360:   :config
    1361:   (pinentry-start))
    1362: (use-package password-store
    1363:   :ensure
    1364:   :defer t
    1365:   :config
    1366:   (setq password-store-password-length 12))
    1367: 
    1368: (use-package password-store-otp
    1369:   :ensure
    1370:   :defer t
    1371:   :after password-store)
    1372: 
    1373: (use-package pass
    1374:   :ensure
    1375:   :defer t)
    1376: 
    1377: (use-package auth-source-pass
    1378:   :init
    1379:   (auth-source-pass-enable))
    1380: (use-package rg
    1381:   :if (executable-find "rg")
    1382:   :ensure
    1383:   :defer t)
    1384: ;; dired
    1385: (use-package dired
    1386:   :commands dired-jump
    1387:   :init
    1388:   (setq dired-dwim-target t ; guess a default target directory
    1389:         dired-hide-details-hide-symlink-targets nil ; don't hide symbolic link targets
    1390:         dired-auto-revert-buffer #'dired-buffer-stale-p ; revert stale only
    1391:         dired-recursive-copies 'always ; always copy recursively
    1392:         dired-recursive-deletes 'top ; ask only for top-level
    1393:         dired-create-destination-dirs 'ask
    1394:         dired-clean-confirm-killing-deleted-buffers nil))
    1395: (use-package image-dired
    1396:   :config
    1397:   (setq image-dired-thumb-size 150))
    1398: (use-package dired-x
    1399:   :hook (dired-mode . dired-omit-mode)
    1400:   :config
    1401:   (setq dired-omit-files
    1402:         (concat dired-omit-files
    1403:                 "\\|^\\.DS_Store\\'"
    1404:                 "\\|^\\.project\\(?:ile\\)?\\'"
    1405:                 "\\|^\\.\\(?:svn\\|git\\)\\'"
    1406:                 "\\|^\\.ccls-cache\\'"
    1407:                 "\\|\\(?:\\.js\\)?\\.meta\\'"
    1408:                 "\\|\\.\\(?:elc\\|o\\|pyo\\|swp\\|class\\)\\'"))
    1409:   ;; Disable the prompt about whether I want to kill the Dired buffer for a
    1410:   ;; deleted directory. Of course I do!
    1411:   (setq dired-clean-confirm-killing-deleted-buffers nil)
    1412:   (let ((cmd "xdg-open"))
    1413:     (setq dired-guess-shell-alist-user
    1414:           `(("\\.\\(?:docx\\|pdf\\|djvu\\|eps\\)\\'" ,cmd)
    1415:             ("\\.\\(?:jpe?g\\|png\\|gif\\|xpm\\)\\'" ,cmd)
    1416:             ("\\.\\(?:xcf\\)\\'" ,cmd)
    1417:             ("\\.csv\\'" ,cmd)
    1418:             ("\\.tex\\'" ,cmd)
    1419:             ("\\.\\(?:mp4\\|mkv\\|avi\\|flv\\|rm\\|rmvb\\|ogv\\)\\(?:\\.part\\)?\\'" ,cmd)
    1420:             ("\\.\\(?:mp3\\|flac\\)\\'" ,cmd)
    1421:             ("\\.html?\\'" ,cmd)
    1422:             ("\\.md\\'" ,cmd)))))
    1423: (use-package fd-dired
    1424:   :ensure
    1425:   :if (executable-find "fd")
    1426:   :defer t
    1427:   :init
    1428:   (global-set-key [remap find-dired] #'fd-dired))
    1429: (use-package dired-git-info
    1430:   :ensure
    1431:   :defer t
    1432:   ;; :hook
    1433:   ;; (dired-after-readin . dired-git-info-auto-enable)
    1434:   :config
    1435:   ;; (setq +dired--git-info-p (bound-and-true-p dired-git-info-mode))
    1436:   ;; (when +dired--git-info-p
    1437:   ;;   (dired-git-info-mode -1))
    1438:   (setq dgi-auto-hide-details-p nil))
    1439: (use-package dired-aux
    1440:   :config
    1441:   (setq dired-create-destination-dirs 'ask
    1442:         dired-vc-rename-file t))
    1443: (use-package dired-rsync
    1444:   :ensure
    1445:   :defer t)
    1446: (use-package diredfl
    1447:   :ensure
    1448:   :defer t
    1449:   :hook (dired-mode . diredfl-global-mode))
    1450: ;; treemacs
    1451: (use-package treemacs
    1452:   :ensure
    1453:   :hook ((treemacs-mode . (lambda () (hs-minor-mode -1))))
    1454:   :config
    1455:   (setq treemacs-hide-gitignored-files-mode t
    1456:         treemacs-no-png-images t
    1457:         treemacs-silent-refresh t
    1458:         treemacs-sorting 'mod-time-desc
    1459:         treemacs-python-executable (executable-find "python3")
    1460:         treemacs-collapse-dirs (if treemacs-python-executable 3 0)
    1461:         treemacs-deferred-git-apply-delay 0.5
    1462:         treemacs-directory-name-transformer #'identity
    1463:         treemacs-display-in-side-window t
    1464:         treemacs-eldoc-display 'simple
    1465:         treemacs-file-event-delay 2000
    1466:         treemacs-file-extension-regex treemacs-last-period-regex-value
    1467:         treemacs-file-follow-delay 0.2
    1468:         treemacs-file-name-transformer #'identity
    1469:         treemacs-follow-after-init t
    1470:         treemacs-expand-after-init t
    1471:         treemacs-find-workspace-method 'find-for-file-or-pick-first
    1472:         treemacs-git-command-pipe ""
    1473:         treemacs-goto-tag-strategy 'refetch-index
    1474:         treemacs-header-scroll-indicators '(nil . "^^^^^^")
    1475:         treemacs-hide-dot-git-directory t
    1476:         treemacs-indentation 2
    1477:         treemacs-indentation-string " "
    1478:         treemacs-is-never-other-window nil
    1479:         treemacs-max-git-entries 5000
    1480:         treemacs-missing-project-action 'ask
    1481:         treemacs-move-forward-on-expand nil
    1482:         treemacs-no-delete-other-windows t
    1483:         treemacs-project-follow-cleanup nil
    1484:         treemacs-persist-file (expand-file-name ".cache/treemacs-persist" user-emacs-directory)
    1485:         treemacs-position 'left
    1486:         treemacs-read-string-input 'from-child-frame
    1487:         treemacs-recenter-distance 0.1
    1488:         treemacs-recenter-after-file-follow nil
    1489:         treemacs-recenter-after-tag-follow nil
    1490:         treemacs-recenter-after-project-jump 'always
    1491:         treemacs-recenter-after-project-expand 'on-distance
    1492:         treemacs-litter-directories '("/node_modules" "/.venv" "/.cask")
    1493:         treemacs-project-follow-into-home nil
    1494:         treemacs-show-cursor nil
    1495:         treemacs-show-hidden-files t
    1496:         treemacs-silent-filewatch t
    1497:         treemacs-select-when-already-in-treemacs 'move-back
    1498:         treemacs-space-between-root-nodes t
    1499:         treemacs-tag-follow-cleanup t
    1500:         treemacs-tag-follow-delay 1.5
    1501:         treemacs-text-scale nil
    1502:         treemacs-user-mode-line-format nil
    1503:         treemacs-user-header-line-format nil
    1504:         treemacs-wide-toggle-width 70
    1505:         treemacs-width 35
    1506:         treemacs-width-increment 1
    1507:         treemacs-width-is-initially-locked t
    1508:         treemacs-workspace-switch-cleanup nil)
    1509:   (treemacs-peek-mode 1)
    1510:   (treemacs-filewatch-mode t)
    1511:   (treemacs-follow-mode t)
    1512:   (treemacs-fringe-indicator-mode 'always)
    1513:   (when treemacs-python-executable
    1514:     (treemacs-git-commit-diff-mode t))
    1515:   (pcase (cons (not (null (executable-find "git")))
    1516:                (not (null treemacs-python-executable)))
    1517:     (`(t . t)
    1518:      (treemacs-git-mode 'deferred))
    1519:     (`(t . _)
    1520:      (treemacs-git-mode 'simple)))
    1521:   :bind
    1522:   (:map global-map
    1523:         ("M-0"       . treemacs-select-window)
    1524:         ("C-x t 1"   . treemacs-delete-other-windows)
    1525:         ("C-x t t"   . treemacs)
    1526:         ("C-x t d"   . treemacs-select-directory)
    1527:         ("C-x t B"   . treemacs-bookmark)
    1528:         ("C-x t C-t" . treemacs-find-file)
    1529:         ("C-x t M-t" . treemacs-find-tag))
    1530:   :general
    1531:   (+config/leader-tree
    1532:     "t" 'treemacs
    1533:     "p" 'treemacs-add-and-display-current-project-exclusively)
    1534: 
    1535:   (general-define-key
    1536:    :keymaps 'treemacs-mode-map
    1537:    "[mouse-1]" 'treemacs-single-click-expand-action)
    1538: 
    1539:   (general-nvmap
    1540:     :keymaps 'treemacs-mode-map
    1541:     "gr" '(treemacs-refresh :wk "refresh tree")
    1542:     "zm" '(:ignore t :wk "move")
    1543:     "zmf" '(treemacs-move-file :wk "move file")
    1544:     "zmd" '(treemacs-move-project-down :wk "move project down")
    1545:     "zmu" '(treemacs-move-project-up :wk "move project up")
    1546:     "zr" '(:ignore t :wk "rename")
    1547:     "zrf" '(treemacs-rename-file :wk "rename file")
    1548:     "zrp" '(treemacs-rename-project :wk "rename project")
    1549:     "zrw" '(treemacs-rename-workspace :wk "rename workspace")
    1550:     "zc" '(:ignore t :wk "create/clean")
    1551:     "zcC" '(treemacs-cleanup-litter :wk "cleanup litter")
    1552:     "zcd" '(treemacs-create-dir :wk "create directory")
    1553:     "zcf" '(treemacs-create-file :wk "create file")
    1554:     "zd" '(treemacs-delete-file :wk "delete file")))
    1555: (use-package treemacs-projectile
    1556:   :ensure
    1557:   :after treemacs)
    1558: (use-package treemacs-icons-dired
    1559:   :ensure
    1560:   :after treemacs
    1561:   :hook (dired-mode . treemacs-icons-dired-enable-once))
    1562: (use-package treemacs-magit
    1563:   :ensure
    1564:   :after treemacs magit)
    1565: (use-package treemacs-evil
    1566:   :ensure
    1567:   :after treemacs evil)
    1568: (use-package lsp-treemacs
    1569:   :ensure
    1570:   :after treemacs lsp
    1571:   :config
    1572:   (lsp-treemacs-sync-mode 1)
    1573:   :general
    1574:   (general-define-key
    1575:    :keymaps 'treemacs-mode-map
    1576:    "S" 'lsp-treemacs-symbols
    1577:    "X" 'lsp-treemacs-errors-list
    1578:    "Y" 'lsp-treemacs-call-hierarchy))
    1579: (use-package treemacs-perspective
    1580:   :ensure
    1581:   :after treemacs perspective
    1582:   :config
    1583:   (treemacs-set-scope-type 'Perspectives))
    1584: (use-package treemacs-tab-bar
    1585:   :ensure
    1586:   :after treemacs)
    1587: (use-package treemacs-nerd-icons
    1588:   :ensure
    1589:   :after treemacs
    1590:   :config
    1591:   (treemacs-load-theme "nerd-icons"))
    1592: ;; mail
    1593: (use-package notmuch
    1594:   :ensure
    1595:   :if (executable-find "notmuch")
    1596:   :defer t
    1597:   :commands (notmuch)
    1598:   :hook
    1599:   (message-setup . mml-secure-sign-pgpmime)
    1600:   :config
    1601:   (global-set-key (kbd "<XF86Mail>") 'notmuch)
    1602:   (setq notmuch-fcc-dirs nil
    1603:         notmuch-search-result-format
    1604:         '(("date" . "%12s ")
    1605:           ("count" . "%-7s ")
    1606:           ("authors" . "%-30s ")
    1607:           ("subject" . "%-72s ")
    1608:           ("tags" . "(%s)"))
    1609:         notmuch-tag-formats
    1610:         '(("unread"
    1611:            (propertize tag 'face 'notmuch-tag-unread))
    1612:           ("flagged"
    1613:            (propertize tag 'face 'notmuch-tag-flagged)
    1614:            (notmuch-tag-format-image-data tag
    1615:                                           (notmuch-tag-star-icon))))
    1616:         notmuch-tagging-keys
    1617:         '(("a" notmuch-archive-tags "Archive")
    1618:           ("u" notmuch-show-mark-read-tags "Mark read")
    1619:           ("f" ("+flagged") "Flag")
    1620:           ("s" ("+spam" "-inbox") "Mark as spam")
    1621:           ("d" ("+deleted" "-inbox") "Delete"))
    1622:         notmuch-saved-searches
    1623:         '((:name "flagged" :query "tag:flagged" :key "f")
    1624:           (:name "sent" :query "tag:sent" :key "s")
    1625:           (:name "drafts"  :query "tag:draft" :key "d")
    1626:           (:name "all mail" :query "*" :key "a")
    1627:           (:name "unread" :query "tag:unread" :key "u")
    1628:           (:name "zum" :query "tag:zum" :key "z")
    1629:           (:name "mkn" :query "tag:mkn" :key "c")
    1630:           (:name "gmail" :query "tag:gmail" :key "g")
    1631:           (:name "hotmail" :query "tag:hotmail" :key "h")
    1632:           (:name "yahoo" :query "tag:yahoo" :key "h")
    1633:           (:name "ymail" :query "tag:ymail" :key "m")
    1634:           (:name "Today"
    1635:                  :query "date:today AND NOT tag:spam AND NOT tag:bulk"
    1636:                  :key "T"
    1637:                  :search-type 'tree
    1638:                  :sort-order 'newest-first)
    1639:           (:name "This Week"
    1640:                  :query "date:weeks AND NOT tag:spam AND NOT tag:bulk"
    1641:                  :key "W"
    1642:                  :search-type 'tree
    1643:                  :sort-order 'newest-first)
    1644:           (:name "This Month"
    1645:                  :query "date:months AND NOT tag:spam AND NOT tag:bulk"
    1646:                  :key "M"
    1647:                  :search-type 'tree
    1648:                  :sort-order 'newest-first)
    1649:           (:name "flagged"
    1650:                  :query "tag:flagged AND NOT tag:spam AND NOT tag:bulk"
    1651:                  :key "f"
    1652:                  :search-type 'tree
    1653:                  :sort-order 'newest-first)
    1654:           (:name "spam" :query "tag:spam"))
    1655:         notmuch-archive-tags '("-inbox" "-unread"))
    1656:   (setq-default notmuch-search-oldest-first nil)
    1657:   (if (executable-find "gpg2")
    1658:       (setq notmuch-crypto-gpg-program "gpg2")
    1659:     (setq notmuch-crypto-gpg-program "gpg"))
    1660:   (setq notmuch-crypto-process-mime t
    1661:         mml-secure-openpgp-sign-with-sender t)
    1662:   (define-key notmuch-show-mode-map "S"
    1663:               (lambda ()
    1664:                 "Mark message as spam"
    1665:                 (interactive)
    1666:                 (notmuch-show-tag (list +spam -new))))
    1667:   :general
    1668:   (+config/leader-menu! "mail" "M-m"
    1669:     "m" '(notmuch :wk "Notmuch Mail"))
    1670: 
    1671:   (+config/leader-mail
    1672:     "m" '(notmuch :wk "open notmuch mail")
    1673:     "M" '(compose-mail :wk "new mail"))
    1674: 
    1675:   (general-nmap 'notmuch-common-keymap
    1676:     "gr" 'notmuch-refresh-this-buffer
    1677:     "gR" 'notmuch-poll-and-refresh-this-buffer))
    1678: (use-package notmuch-indicator
    1679:   :ensure
    1680:   :config
    1681:   (setq notmuch-indicator-args
    1682:         '((:terms "tag:unread and tag:inbox" :label "U" :label-face success)))
    1683:   (notmuch-indicator-mode))
    1684: (use-package consult-notmuch
    1685:   :ensure
    1686:   :after consult
    1687:   :config
    1688:   (add-to-list 'consult-buffer-sources 'consult-notmuch-buffer-source))
    1689: (use-package ol-notmuch
    1690:   :ensure)
    1691: (use-package notmuch-maildir
    1692:   :ensure
    1693:   :config
    1694:   (notmuch-maildir-inject-section))
    1695: (use-package message
    1696:   :custom
    1697:   (message-directory (expand-file-name ".mail" (getenv "HOME")))
    1698:   (message-sendmail-envelope-from 'header))
    1699: (use-package sendmail
    1700:   :custom
    1701:   (mail-specify-envelope-from t)
    1702:   (mail-envelope-from 'header)
    1703:   (send-mail-function 'sendmail-send-it)
    1704:   (sendmail-program (executable-find "msmtp")))
    1705: ;; programming
    1706: ;; (use-package lispy
    1707: ;;   :ensure
    1708: ;;   :hook ((emacs-lisp-mode . lispy-mode)
    1709: ;;          (lisp-mode . lispy-mode)
    1710: ;;          (scheme-mode . lispy-mode)
    1711: ;;          (geiser-mode . lispy-mode)))
    1712: ;; (use-package lispyville
    1713: ;;   :ensure
    1714: ;;   :hook (lispy-mode . lispyville-mode))
    1715: (when (locate-library "aggressive-indent")
    1716:   (add-hook 'lisp-mode-hook #'aggressive-indent-mode)
    1717:   (add-hook 'clojure-mode-hook #'aggressive-indent-mode)
    1718:   (add-hook 'scheme-mode-hook #'aggressive-indent-mode))
    1719: 
    1720: ;;;; emacs-lisp -n
    1721: (use-package elisp-mode
    1722:   :diminish emacs-lisp-mode
    1723:   :diminish elisp-mode
    1724:   :diminish outline-minor-mode
    1725:   :diminish lisp-data-mode
    1726:   :mode ("\\.Cask\\'" . emacs-lisp-mode)
    1727:   :ensure nil
    1728:   :hook (emacs-lisp-mode . (lambda ()
    1729:                              (outline-minor-mode)
    1730:                              (rainbow-delimiters-mode))))
    1731: (use-package ielm
    1732:   :ensure nil
    1733:   ;;:hook (ielm-mode . (turn-on-smartparens-mode))
    1734:   :config
    1735:   (setq ielm-font-lock-keywords
    1736:         (append '(("\\(^\\*\\*\\*[^*]+\\*\\*\\*\\)\\(.*$\\)"
    1737:                    (1 font-lock-comment-face)
    1738:                    (2 font-lock-constant-face)))
    1739:                 (when (require 'highlight-numbers nil t)
    1740:                   (highlight-numbers--get-regexp-for-mode 'emacs-lisp-mode))
    1741:                 (cl-loop for (matcher . match-highlights)
    1742:                          in (append lisp-el-font-lock-keywords-2
    1743:                                     lisp-cl-font-lock-keywords-2)
    1744:                          collect
    1745:                          `((lambda (limit)
    1746:                              (when ,(if (symbolp matcher)
    1747:                                         `(,matcher limit)
    1748:                                       `(re-search-forward ,matcher limit t))
    1749:                                ;; Only highlight matches after the prompt
    1750:                                (> (match-beginning 0) (car comint-last-prompt))
    1751:                                ;; Make sure we're not in a comment or string
    1752:                                (let ((state (syntax-ppss)))
    1753:                                  (not (or (nth 3 state)
    1754:                                           (nth 4 state))))))
    1755:                            ,@match-highlights)))))
    1756: (use-package macrostep
    1757:   :ensure
    1758:   :defer t
    1759:   :bind (:map emacs-lisp-mode-map
    1760:               ("C-c e" . macrostep-expand)))
    1761: ;;;; common-lisp
    1762: (when (file-directory-p (expand-file-name "site-lisp/sly-stepper" user-emacs-directory))
    1763:   (add-to-list 'load-path (expand-file-name "site-lisp/sly-stepper" user-emacs-directory)))
    1764: (when (file-directory-p (expand-file-name "site-lisp/sly-quicklisp" user-emacs-directory))
    1765:   (add-to-list 'load-path (expand-file-name "site-lisp/sly-quicklisp" user-emacs-directory)))
    1766: (when (file-directory-p (expand-file-name "site-lisp/sly-macrostep" user-emacs-directory))
    1767:   (add-to-list 'load-path (expand-file-name "site-lisp/sly-macrostep" user-emacs-directory)))
    1768: 
    1769: (defvar inferior-lisp-program "sbcl")
    1770: (when (executable-find "ros")
    1771:   (setq inferior-lisp-program "ros -Q run"))
    1772: 
    1773: (add-hook 'lisp-mode-hook #'rainbow-delimiters-mode)
    1774: (use-package sly
    1775:   :ensure
    1776:   :commands sly-autoloads
    1777:   :hook ((lisp-mode-local-vars . rainbow-delimiters-mode)
    1778:          (lisp-mode . sly-editing-mode))
    1779:   :config
    1780:   (require 'sly-autoloads))
    1781: ;;;; clojure
    1782: (use-package cider
    1783:   :ensure
    1784:   :defer t)
    1785: (use-package clj-refactor
    1786:   :ensure
    1787:   :defer t
    1788:   :hook (clojure-mode . +config/clojure-mode-hook)
    1789:   :config
    1790:   (defun +config/clojure-mode-hook ()
    1791:     (clj-refactor-mode 1)
    1792:     ;; This choice of keybinding leaves cider-macroexpand-1 unbound
    1793:     (cljr-add-keybindings-with-prefix "C-c r")))
    1794: ;;;; scheme
    1795: (use-package geiser
    1796:   :ensure
    1797:   :defer t
    1798:   :diminish geiser-autodoc-mode
    1799:   ;; :hook (geiser-repl-mode . turn-on-smartparens-strict-mode)
    1800:   :init
    1801:   (setq geiser-autodoc-identifier-format "%s → %s"
    1802:         geiser-repl-per-project-p t
    1803:         geiser-repl-history-filename (concat user-emacs-directory "geiser-history")))
    1804: (use-package geiser-guile
    1805:   :ensure
    1806:   :defer t
    1807:   :config
    1808:   (let ((nonguix-path (expand-file-name "Projects/guix/nonguix"
    1809:                                         (getenv "HOME")))
    1810:         (personal-path (expand-file-name "Projects/guix/devel/src"
    1811:                                          (getenv "HOME"))))
    1812:     (when (file-directory-p nonguix-path)
    1813:       (add-to-list 'geiser-guile-load-path nonguix-path))
    1814:     (when (file-directory-p personal-path)
    1815:       (add-to-list 'geiser-guile-load-path personal-path))))
    1816: 
    1817: (use-package cc-mode
    1818:   :mode ("\\.mm\\'" . objc-mode)
    1819:   :mode ("\\.h\\'" . +cc-c-c++-objc-mode)
    1820:   :hook (c-mode-common . rainbow-delimiters-mode)
    1821:   ;; :hook (c++-mode-local-vars . c++-ts-mode)
    1822:   ;; :hook (c-mode-common . c-ts-base-mode)
    1823:   ;; :hook (cmake-mode-local-vars . cmake-ts-mode)
    1824:   :config
    1825:   (setq c-basic-offset tab-width
    1826:         c-backspace-function #'delete-backward-char)
    1827:   (with-eval-after-load 'ffap
    1828:     (add-to-list 'ffap-alist '(c-mode . ffap-c-mode))))
    1829: (use-package nxml-mode
    1830:   :mode "\\.p\\(?:list\\|om\\)\\'" ; plist, pom
    1831:   :mode "\\.xs\\(?:d\\|lt\\)\\'"   ; xslt, xsd
    1832:   :mode "\\.rss\\'"
    1833:   :config
    1834:   (setq nxml-slash-auto-complete-flag t
    1835:         nxml-auto-insert-xml-declaration-flag t))
    1836: (use-package yaml-mode
    1837:   :ensure
    1838:   :config
    1839:   (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
    1840:   (add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode))
    1841:   (setq tab-width 2)
    1842:   ;; (when (treesit-available-p)
    1843:   ;;   (add-to-list 'major-mode-remap-alist '(yaml-mode . yaml-ts-mode)))
    1844:   :hook
    1845:   ((yaml-mode . (lambda ()
    1846:                   (define-key yaml-mode-map "\C-m" 'newline-and-indent)))
    1847:    (yaml-mode . (lambda ()
    1848:                   (run-hooks 'prog-mode-hook)))))
    1849: (use-package toml-mode
    1850:   :ensure
    1851:   :mode
    1852:   ("\\.toml\\'" . toml-mode)
    1853:   :config
    1854:   ;; (when (treesit-available-p)
    1855:   ;;    (add-to-list 'major-mode-remap-alist '(toml-mode . toml-ts-mode)))
    1856:   (with-eval-after-load 'lsp-mode
    1857:     (setq lsp-toml-command (executable-find "taplo")))
    1858:   (add-to-list 'lsp-language-id-configuration '("\\.toml$" . "toml")))
    1859: (use-package lua-mode
    1860:   :ensure
    1861:   :defer t
    1862:   :config
    1863:   (with-eval-after-load 'lsp-mode
    1864:     (setq lsp-lua-hint-enable t
    1865:           lsp-lua-hint-set-type t)))
    1866: (use-package jinja2-mode
    1867:   :ensure
    1868:   :defer t
    1869:   :config
    1870:   ;; The default behavior is to reindent the whole buffer on save. This is
    1871:   ;; disruptive and imposing. There are indentation commands available; the user
    1872:   ;; can decide when they want their code reindented.
    1873:   (setq jinja2-enable-indent-on-save nil)
    1874:   (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
    1875:   (add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode)))
    1876: (use-package json-mode
    1877:   :ensure)
    1878: (defun +config/django-web-mode ()
    1879:   "Set web-engine to django if `manage.py' detected in `projectile-project-root'."
    1880:   (if (projectile-project-p)
    1881:       (if (file-exists-p (concat (projectile-project-root) "manage.py"))
    1882:           (web-mode-set-engine "django"))))
    1883: 
    1884: (defun +config/web-mode-fix-js-comment ()
    1885:   "Fix comment handling in `web-mode' for JavaScript (from `doom')."
    1886:   (when (member web-mode-content-type '("javascript" "jsx"))
    1887:     ;; For some reason the default is to insert HTML comments even
    1888:     ;; in JavaScript.
    1889:     (setq-local comment-start "//")
    1890:     (setq-local comment-end "")
    1891:     ;; Needed since otherwise the default value generated by
    1892:     ;; `comment-normalize-vars' will key off the syntax and think
    1893:     ;; that a single "/" starts a comment, which completely borks
    1894:     ;; auto-fill.
    1895:     (setq-local comment-start-skip "// *")))
    1896: 
    1897: (use-package web-mode
    1898:   :ensure
    1899:   :defer t
    1900:   :mode "\\.[px]?html?\\'"
    1901:   :mode "\\.\\(?:tpl\\|blade\\)\\(?:\\.php\\)?\\'"
    1902:   :mode "\\.erb\\'"
    1903:   :mode "\\.[lh]?eex\\'"
    1904:   :mode "\\.jsp\\'"
    1905:   :mode "\\.as[cp]x\\'"
    1906:   :mode "\\.ejs\\'"
    1907:   :mode "\\.hbs\\'"
    1908:   :mode "\\.mustache\\'"
    1909:   :mode "\\.svelte\\'"
    1910:   :mode "\\.twig\\'"
    1911:   :mode "\\.jinja2?\\'"
    1912:   :mode "\\.eco\\'"
    1913:   :mode "wp-content/themes/.+/.+\\.php\\'"
    1914:   :mode "templates/.+\\.php\\'"
    1915:   :init
    1916:   ;; If the user has installed `vue-mode' then, by appending this to
    1917:   ;; `auto-mode-alist' rather than prepending it, its autoload will have
    1918:   ;; priority over this one.
    1919:   (add-to-list 'auto-mode-alist '("\\.vue\\'" . web-mode) 'append)
    1920:   :mode "\\.vue\\'"
    1921:   :config
    1922:   (setq web-mode-markup-indent-offset 2
    1923:         web-mode-enable-auto-closing t
    1924:         web-mode-auto-close-style 1
    1925:         web-mode-css-indent-offset 2
    1926:         web-mode-code-indent-offset 2
    1927:         web-mode-enable-auto-pairing nil
    1928:         web-mode-enable-block-face t
    1929:         web-mode-enable-comment-interpolation t
    1930:         web-mode-enable-heredoc-fontification t
    1931:         web-mode-enable-css-colorization t
    1932:         web-mode-enable-part-face t
    1933:         web-mode-enable-current-element-highlight t
    1934:         web-mode-enable-current-column-highlight t
    1935:         web-mode-style-padding 1
    1936:         web-mode-script-padding 1
    1937:         web-mode-block-padding 0
    1938:         web-mode-comment-style 2
    1939:         web-mode-enable-curly-brace-indentation t
    1940:         web-mode-enable-auto-quoting nil
    1941:         web-mode-engines-alist
    1942:         '(("php" . "\\.phtml\\'")
    1943:           ("blade" . "\\.blade\\'")
    1944:           ("elixir" . "\\.eex\\'")
    1945:           ("phoenix" . "\\.[lh]eex\\'")))
    1946:   ;; web-mode-extra-auto-pairs
    1947:   ;; '(("erb" . (("beg" "end")))
    1948:   ;;   ("php" . (("beg" "end")))))
    1949:   (with-eval-after-load 'smartparens
    1950:     (sp-local-pair 'web-mode "<" nil :actions :rem)
    1951:     (sp-local-pair 'web-mode "{%" " %}")
    1952:     (sp-local-pair 'web-mode "{{" " }}")
    1953:     (sp-local-pair 'web-mode "<!--" " -->")
    1954:     )
    1955:   (defun +config/web-mode-hook ()
    1956:     "Hooks for Web mode."
    1957:     (local-set-key (kbd "RET") 'newline-and-indent))
    1958:   ;; Use // instead of /* as the default comment delimited in JS
    1959:   (with-eval-after-load 'web-mode
    1960:     (setf (alist-get "javascript" web-mode-comment-formats nil nil #'equal)
    1961:           "//"))
    1962:   :hook ((html-mode-local-vars-hook
    1963:           mhtml-mode-local-vars-hook) . tree-sitter)
    1964:   :hook (web-mode . +config/django-web-mode)
    1965:   :general
    1966:   (general-nvmap
    1967:     :keymaps 'web-mode-map
    1968:     "gn" 'web-mode-navigate)
    1969:   (general-vmap
    1970:    :keymaps 'web-mode-map
    1971:     "gs" 'web-mode-surround))
    1972: (use-package emmet-mode
    1973:   :ensure
    1974:   :defer t
    1975:   :hook (css-mode web-mode html-mode haml-mode nxml-mode rjsx-mode reason-mode)
    1976:   :config
    1977:   (when (require 'yasnippet nil t)
    1978:     (add-hook 'emmet-mode-hook #'yas-minor-mode-on))
    1979:   (setq emmet-move-cursor-between-quotes t)
    1980:   :general
    1981:   (general-vmap
    1982:     :keymaps 'emmet-mode-keymap
    1983:     "TAB" 'emmet-wrap-with-markup)
    1984:   (general-def
    1985:     :keymaps 'emmet-mode-keymap
    1986:     "M-E" 'emmet-expand-line))
    1987: (use-package skewer-mode
    1988:   :ensure
    1989:   :defer t
    1990:   :hook ((web-mode . skewer-html-mode)
    1991:          (js2-mode . skewer-mode)))
    1992: (use-package lsp-tailwindcss
    1993:   :ensure
    1994:   :init
    1995:   (setq lsp-tailwindcss-add-on-mode t))
    1996: (use-package sass-mode
    1997:   :ensure
    1998:   :defer t
    1999:   :hook (scss-mode . rainbow-mode))
    2000: (use-package css-eldoc
    2001:   :ensure
    2002:   :defer t
    2003:   :commands turn-on-css-eldoc
    2004:   ;;add a hook if you want always to see the selector options in the minibuffer
    2005:   :config
    2006:   (add-hook 'css-mode-hook 'turn-on-css-eldoc)
    2007:   (add-hook 'scss-mode-hook 'turn-on-css-eldoc))
    2008: 
    2009: 
    2010: (defvar +javascript-npm-conf (make-hash-table :test 'equal))
    2011: 
    2012: ;;;###autoload
    2013: (defun +javascript-npm-conf (&optional project-root refresh-p)
    2014:   "Retrieves an alist of this project's 'package.json'. If REFRESH-P is non-nil
    2015: ignore the cache."
    2016:   (let ((project-root (or project-root (doom-project-root))))
    2017:     (or (and (not refresh-p)
    2018:              (gethash project-root +javascript-npm-conf))
    2019:         (let ((package-file (expand-file-name "package.json" project-root)))
    2020:           (when-let (json (and (file-exists-p package-file)
    2021:                                (require 'json)
    2022:                                (json-read-file package-file)))
    2023:             (puthash project-root json +javascript-npm-conf))))))
    2024: 
    2025: ;;;###autoload
    2026: (defun +javascript-npm-dep-p (packages &optional project-root refresh-p)
    2027:   (when-let (data (and (bound-and-true-p +javascript-npm-mode)
    2028:                        (+javascript-npm-conf project-root refresh-p)))
    2029:     (let ((deps (append (cdr (assq 'dependencies data))
    2030:                         (cdr (assq 'devDependencies data)))))
    2031:       (cond ((listp packages)
    2032:              (funcall (if (eq (car packages) 'and)
    2033:                           #'cl-every
    2034:                         #'cl-some)
    2035:                       (lambda (pkg) (assq pkg deps))
    2036:                       (if (listp packages) packages (list packages))))
    2037:             ((symbolp packages)
    2038:              (assq packages deps))
    2039:             (t (error "Expected a package symbol or list, got %s" packages))))))
    2040: 
    2041: ;;;###autoload
    2042: (defun +javascript-add-npm-path-h ()
    2043:   "Add node_modules/.bin to `exec-path'."
    2044:   (when-let ((search-directory (or (doom-project-root) default-directory))
    2045:              (node-modules-parent (locate-dominating-file search-directory "node_modules/"))
    2046:              (node-modules-dir (expand-file-name "node_modules/.bin/" node-modules-parent)))
    2047:     (make-local-variable 'exec-path)
    2048:     (add-to-list 'exec-path node-modules-dir)
    2049:     (doom-log ":lang:javascript: add %s to $PATH" (expand-file-name "node_modules/" node-modules-parent))))
    2050: 
    2051: 
    2052: ;;
    2053: ;; Commands
    2054: 
    2055: ;;;###autoload
    2056: (defun +javascript/open-repl ()
    2057:   "Open a Javascript REPL. Meaning either `skewer-repl', if any of the
    2058: skewer-*-mode's are enabled, or `nodejs-repl' otherwise."
    2059:   (interactive)
    2060:   (call-interactively
    2061:    (if (and (featurep 'skewer-mode)
    2062:             (or (bound-and-true-p skewer-mode)
    2063:                 (bound-and-true-p skewer-css-mode)
    2064:                 (bound-and-true-p skewer-html-mode)))
    2065:        #'skewer-repl
    2066:      #'nodejs-repl))
    2067:   (current-buffer))
    2068: 
    2069: ;;;###autoload
    2070: (defun +javascript/skewer-this-buffer ()
    2071:   "Toggle a globalized skewer-mode, attaching an external browser (once),
    2072: initiating an internal httpd server (once) and enabling the appropriate
    2073: skewer-mode for the current buffer.
    2074: 
    2075: Run this for any buffer you want to skewer."
    2076:   (interactive)
    2077:   (when (bound-and-true-p impatient-mode)
    2078:     (error "Skewer-mode isn't compatible with impatient mode"))
    2079:   (require 'skewer-mode)
    2080:   (unless (process-status "httpd")
    2081:     (run-skewer))
    2082:   (pcase major-mode
    2083:     ((or 'css-mode 'scss-mode 'less-css-mode)
    2084:      (unless (bound-and-true-p skewer-css-mode)
    2085:        (skewer-css-mode +1)))
    2086:     ((or 'web-mode 'html-mode)
    2087:      (unless (bound-and-true-p skewer-html-mode)
    2088:        (skewer-html-mode +1)))
    2089:     ('js2-mode
    2090:      (unless (bound-and-true-p skewer-mode)
    2091:        (skewer-mode +1)))
    2092:     (_ (error "Invalid mode %s" major-mode))))
    2093: 
    2094: ;;;###autoload
    2095: (defun +javascript/skewer-cleanup ()
    2096:   "Disable skewer-mode globally and disable the httpd server."
    2097:   (interactive)
    2098:   (when (process-status "httpd")
    2099:     (httpd-stop))
    2100:   (dolist (buf (buffer-list))
    2101:     (with-current-buffer buf
    2102:       (if (bound-and-true-p skewer-mode)
    2103:           (skewer-mode -1))
    2104:       (if (bound-and-true-p skewer-css-mode)
    2105:           (skewer-css-mode -1))
    2106:       (if (bound-and-true-p skewer-html-mode)
    2107:           (skewer-html-mode -1)))))
    2108: 
    2109: ;;
    2110: ;; Hooks
    2111: 
    2112: ;;;###autoload
    2113: (defun +javascript-cleanup-tide-processes-h ()
    2114:   "Clean up dangling tsserver processes if there are no more buffers with
    2115: `tide-mode' active that belong to that server's project."
    2116:   (when tide-mode
    2117:     (unless (cl-loop with project-name = (tide-project-name)
    2118:                      for buf in (delq (current-buffer) (buffer-list))
    2119:                      if (and (buffer-local-value 'tide-mode buf)
    2120:                              (with-current-buffer buf
    2121:                                (string= (tide-project-name) project-name)))
    2122:                      return buf)
    2123:       (kill-process (tide-current-server)))))
    2124: 
    2125: ;;
    2126: ;; Advice
    2127: 
    2128: ;;;###autoload
    2129: (defun +javascript-tide-project-root-a ()
    2130:   "Resolve to `doom-project-root' if `tide-project-root' fails."
    2131:   (or tide-project-root
    2132:       (or (locate-dominating-file default-directory "tsconfig.json")
    2133:           (locate-dominating-file default-directory "jsconfig.json"))))
    2134: 
    2135: (with-eval-after-load 'projectile
    2136:   (add-to-list 'projectile-globally-ignored-directories "^node_modules$")
    2137:   (add-to-list 'projectile-globally-ignored-directories "^flow-typed$"))
    2138: (use-package js2-mode
    2139:   :ensure
    2140:   :defer t
    2141:   :interpreter ("node" . js2-mode)
    2142:   :hook (js2-mode . rainbow-delimiters-mode)
    2143:   :hook (js2-mode . js2-imenu-extras-mode)
    2144:   :hook (js2-mode . (lambda () (push '("function" . ?ƒ) prettify-symbols-alist)))
    2145:   :config
    2146:   (with-eval-after-load 'skewer-mode
    2147:     (add-hook 'js2-mode 'skewer-mode))
    2148:   (setq-default js2-basic-indent 2
    2149:                 js2-basic-offset 2
    2150:                 js2-auto-indent-p t
    2151:                 js2-cleanup-whitespace t
    2152:                 js2-enter-indents-newline t
    2153:                 js2-indent-on-enter-key t
    2154:                 js2-global-externs (list "window" "module" "require" "buster" "sinon" "assert" "refute" "setTimeout" "clearTimeout" "setInterval" "clearInterval" "location" "__dirname" "console" "JSON" "jQuery" "$")))
    2155: (use-package xref-js2
    2156:   :ensure
    2157:   :defer t
    2158:   :if (executable-find "ag") ; silver-searcher
    2159:   :config
    2160:   (add-hook 'js2-mode-hook (lambda ()
    2161:                              (add-hook 'xref-backend-functions #'xref-js2-xref-backend nil t))))
    2162: (use-package js2-refactor
    2163:   :ensure
    2164:   :defer t
    2165:   :hook (js2-mode . js2-refactor-mode)
    2166:   :init
    2167:   (js2r-add-keybindings-with-prefix "C-c C-r")
    2168:   :config
    2169:   (setq js2-skip-preprocessor-directives t)
    2170:   :general
    2171:   (general-nvmap
    2172:     :keymap 'js2-refactor-mode-map
    2173:     "zr" (general-simulate-key "C-c C-r"
    2174:            :name general-z-r-simulates-C-c-C-r
    2175:            :docstring "Simulates C-c C-r"
    2176:            :which-key "JS2 Refactor")))
    2177: (use-package rjsx-mode
    2178:   :ensure
    2179:   :defer t
    2180:   :mode "\\.[mc]?js\\'"
    2181:   :mode "\\.es6\\'"
    2182:   :mode "\\.pac\\'"
    2183:   :hook (rjsx-mode . rainbow-delimiters-mode)
    2184:   :hook (rjsx-mode . rainbow-mode)
    2185:   :bind (([remap comment-dwim ] . rjsx-comment-dwim))
    2186:   :init
    2187:   (with-eval-after-load 'compilation
    2188:     (add-to-list 'compilation-error-regexp-alist 'node)
    2189:     (add-to-list 'compilation-error-regexp-alist-alist '(node "^[[:blank:]]*at \\(.*(\\|\\)\\(.+?\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)"
    2190:                                                               2 3 4)))
    2191:   :config
    2192:   (with-eval-after-load 'compilation
    2193:     (add-to-list 'compilation-error-regexp-alist 'node)
    2194:     (add-to-list 'compilation-error-regexp-alist-alist
    2195:                  '(node "^[[:blank:]]*at \\(.*(\\|\\)\\(.+?\\):\\([[:digit:]]+\\):\\([[:digit:]]+\\)"
    2196:                         2 3 4)))
    2197:   (setq js-chain-indent t
    2198:         ;; These have become standard in the JS community
    2199:         js2-basic-offset 2
    2200:         ;; Don't mishighlight shebang lines
    2201:         js2-skip-preprocessor-directives t
    2202:         ;; let flycheck handle this
    2203:         js2-mode-show-parse-errors nil
    2204:         js2-mode-show-strict-warnings nil
    2205:         ;; Flycheck provides these features, so disable them: conflicting with
    2206:         ;; the eslint settings.
    2207:         js2-strict-missing-semi-warning nil
    2208:         ;; maximum fontification
    2209:         js2-highlight-level 3
    2210:         js2-idle-timer-delay 0.15)
    2211:   :general
    2212:   (general-nvmap
    2213:     :keymaps 'rjsx-mode-map
    2214:     "'" 'rjsx-jump-tag
    2215:     "gj" 'rjsx-jump-closing-tag
    2216:     "gk" 'rjsx-jump-opening-tag
    2217:     "gr" 'rjsx-rename-tag-at-point
    2218:     "z>" 'rjsx-electric-gt
    2219:     "z<" 'rjsx-electric-lt))
    2220: (use-package typescript-mode
    2221:   :ensure
    2222:   :defer t
    2223:   :hook (typescript-mode . rainbow-delimiters-mode)
    2224:   :hook (typescript-tsx-mode . rainbow-delimiters-mode)
    2225:   :hook (typescript-mode . (lambda () (setq comment-line-break-function #'js2-line-break
    2226:                                             typescript-indent-level (or (and (bound-and-true-p tide-mode)
    2227:                                                                              (plist-get (tide-tsfmt-options) :indentSize))
    2228:                                                                         typescript-indent-level)
    2229:                                             emmet-expand-jsx-className? t)))
    2230:   :init
    2231:   (add-to-list 'auto-mode-alist
    2232:                (cons "\\.tsx\\'" #'typescript-mode))
    2233:   (with-eval-after-load 'flycheck
    2234:     (flycheck-add-mode 'javascript-eslint 'web-mode)
    2235:     (flycheck-add-mode 'javascript-eslint 'typescript-mode)
    2236:     (flycheck-add-mode 'javascript-eslint 'typescript-tsx-mode)
    2237:     (flycheck-add-mode 'typescript-tslint 'typescript-tsx-mode))
    2238:   (defun +javascript-disable-tide-checkers-h ()
    2239:     (add-to-list 'flycheck-disabled-checkers 'javascript-jshint)
    2240:     (add-to-list 'flycheck-disabled-checkers 'tsx-tide)
    2241:     (add-to-list 'flycheck-disabled-checkers 'jsx-tide))
    2242:   (add-hook 'typescript-tsx-mode-hook #'+javascript-disable-tide-checkers-h)
    2243:   :config
    2244:   (when (fboundp 'web-mode)
    2245:     (define-derived-mode typescript-tsx-mode web-mode "TypeScript-TSX"))
    2246:   (autoload 'js2-line-break "js2-mode" nil t))
    2247: (use-package tide
    2248:   :ensure
    2249:   :defer t
    2250:   :hook (tide-mode . tide-hl-identifier-mode)
    2251:   :config
    2252:   (setq tide-completion-detailed t
    2253:         tide-always-show-documentation t
    2254:         tide-server-max-response-length 524288
    2255:         tide-completion-setup-company-backend nil)
    2256:   (add-hook 'tide-mode-hook (lambda () (add-hook 'kill-buffer-hook #'+javascript-cleanup-tide-processes-h nil 'local))))
    2257: (use-package npm-mode
    2258:   :ensure
    2259:   :defer t)
    2260: (use-package nodejs-repl
    2261:   :ensure
    2262:   :defer t)
    2263: (use-package auctex
    2264:   :ensure nil
    2265:   :mode (("\\.tex\\'" . latex-mode)
    2266:          ("\\.latex\\'" . latex-mode))
    2267:   :commands (latex-mode LaTeX-mode plain-tex-mode)
    2268:   :init
    2269:   (progn
    2270:     (add-hook 'LaTeX-mode-hook #'LaTeX-preview-setup)
    2271:     (add-hook 'LaTeX-mode-hook #'flyspell-mode)
    2272:     (add-hook 'LaTeX-mode-hook #'turn-on-reftex)
    2273:     (setq-default TeX-engine 'xetex)
    2274:     (setq TeX-auto-save nil
    2275:           TeX-parse-self nil
    2276:           TeX-save-query nil
    2277:           TeX-PDF-mode t)
    2278:     (setq-default TeX-master nil)))
    2279: (use-package preview
    2280:   :ensure nil
    2281:   :after auctex
    2282:   :commands LaTeX-preview-setup
    2283:   :init
    2284:   (progn
    2285:     (setq-default preview-scale 1.4
    2286:                   preview-scale-function '(lambda () (* (/ 10.0 (preview-document-pt)) preview-scale)))))
    2287: (use-package reftex
    2288:   :ensure nil
    2289:   :commands turn-on-reftex
    2290:   :init
    2291:   (setq reftex-plug-into-AUCTeX t))
    2292: (use-package bibtex
    2293:   :config
    2294:   (setq bibtex-autokey-year-length 4
    2295:         bibtex-autokey-name-year-separator "-"
    2296:         bibtex-autokey-year-title-separator "-"
    2297:         bibtex-autokey-titleword-separator "-"
    2298:         bibtex-autokey-titlewords 2
    2299:         bibtex-autokey-titlewords-stretch 1
    2300:         bibtex-autokey-titleword-length 5))
    2301: ;; Auto-fill for LaTeX
    2302: (defun lem-latex-auto-fill ()
    2303:   "Turn on auto-fill for LaTeX mode."
    2304:   (turn-on-auto-fill)
    2305:   (set-fill-column 80)
    2306:   (setq default-justification 'left))
    2307: (add-hook 'LaTeX-mode-hook #'lem-latex-auto-fill)
    2308: 
    2309: ;; Compilation command
    2310: (add-hook 'LaTeX-mode-hook (lambda () (setq compile-command "latexmk -pdflatex=xelatex -f -pdf %f")))
    2311: 
    2312: ;; Prevent ispell from verifying some LaTeX commands
    2313: ;; http://stat.genopole.cnrs.fr/dw/~jchiquet/fr/latex/emacslatex
    2314: (defvar lem-ispell-tex-skip-alists
    2315:   '("cite" "nocite"
    2316:     "includegraphics"
    2317:     "author" "affil"
    2318:     "ref" "eqref" "pageref"
    2319:     "label"))
    2320: (setq ispell-tex-skip-alists
    2321:       (list
    2322:        (append (car ispell-tex-skip-alists)
    2323:                (mapcar #'(lambda (cmd) (list (concat "\\\\" cmd) 'ispell-tex-arg-end)) lem-ispell-tex-skip-alists))
    2324:        (cadr ispell-tex-skip-alists)))
    2325: 
    2326: ;; Indentation with align-current in LaTeX environments
    2327: (defvar lem-LaTeX-align-environments '("tabular" "tabular*"))
    2328: (add-hook 'LaTeX-mode-hook
    2329:           (lambda ()
    2330:             (require 'align)
    2331:             (setq LaTeX-indent-environment-list
    2332:                   ;; For each item in the list...
    2333:                   (mapcar (lambda (item)
    2334:                             ;; The car is an environment
    2335:                             (let ((env (car item)))
    2336:                               ;; If this environment is in our list...
    2337:                               (if (member env lem-LaTeX-align-environments)
    2338:                                   ;; ...then replace this item with a correct one
    2339:                                   (list env 'align-current)
    2340:                                 ;; else leave it alone
    2341:                                 item)))
    2342:                           LaTeX-indent-environment-list))))
    2343: 
    2344: ;; Use dvipdfmx to convert DVI files to PDF in AUCTeX
    2345: (eval-after-load 'tex
    2346:   '(add-to-list 'TeX-command-list
    2347:                 '("DVI to PDF" "dvipdfmx %d" TeX-run-command t t) t))
    2348: 
    2349: ;; SyncTeX (http://www.emacswiki.org/emacs/AUCTeX#toc19)
    2350: (defun synctex/un-urlify (fname-or-url)
    2351:   "A trivial function that replaces a prefix of file:/// with just /."
    2352:   (if (string= (substring fname-or-url 0 8) "file:///")
    2353:       (substring fname-or-url 7)
    2354:     fname-or-url))
    2355: (use-package markdown-mode
    2356:   :ensure)
    2357: 
    2358: (use-package markdown-ts-mode
    2359:   :ensure
    2360:   :init
    2361:   (add-to-list 'major-mode-remap-alist '(markdown-mode . markdown-ts-mode)))
    2362: 
    2363: (use-package poly-markdown
    2364:   :ensure
    2365:   :init :mode
    2366:   (("README\\.md\\'" . gfm-mode)
    2367:    ("\\.md$" . markdown-ts-mode)
    2368:    ("\\.markdown$" . markdown-ts-mode)))
    2369: 
    2370: (use-package edit-indirect
    2371:   :ensure
    2372:   :after markdown-mode)
    2373: (use-package python
    2374:   :mode ("[./]flake8\\'" . conf-mode)
    2375:   :mode ("/Pipfile\\'" . conf-mode)
    2376:   :hook ((python-mode . lsp-deferred)
    2377:          (python-mode . lsp-ui-mode)
    2378:          (python-mode . lsp-ui-doc-mode)
    2379:          ;; (python-mode . guess-style-guess-tab-mode)
    2380:          (python-mode-local-vars . (lambda ()
    2381:                                      (lsp-deferred)
    2382:                                      (tree-sitter))))
    2383:   :config
    2384:   (if (executable-find "ipython")
    2385:       (setq python-interpreter (executable-find "ipython"))
    2386:     (setq python-interpreter (executable-find "python3")))
    2387:   (when (featurep 'projectile)
    2388:     (add-to-list 'projectile-globally-ignored-directories "^\\.venv$"))
    2389:   (let ((directories `("/usr/bin/" "/usr/local/bin/" "/opt/bin" ,(expand-file-name ".local/bin/" (getenv "HOME")))))
    2390:     (dolist (directory directories) (when (file-directory-p directory)(add-to-list 'python-shell-exec-path directory))))
    2391:   (setq python-indent-guess-indent-offset nil
    2392:         python-shell-completion-native-enable nil
    2393:         python-shell-exec-path (list "/usr/bin/" "/usr/local/bin" (expand-file-name ".local/bin/" (getenv "HOME")))
    2394:         python-indent-guess-indent-offset-verbose nil)
    2395:   (when (featurep 'lsp-mode)
    2396:     (setq lsp-pylsp-plugins-rope-completion-enabled t ; needs python-rope package
    2397:           lsp-pylsp-plugins-mccabe-enabled t ; needs python-mccabe package
    2398:           lsp-ruff-lsp-python-path (executable-find "python3")
    2399:           )
    2400:     (when (executable-find "black")
    2401:       (setq lsp-pylsp-plugins-black-enabled t))
    2402:     (when (executable-find "autopep8")
    2403:       (setq lsp-pylsp-plugins-autopep8-enabled t))
    2404:     (when (executable-find "flake8")
    2405:       (setq lsp-pylsp-plugins-flake8-enabled t))
    2406:     (when (executable-find "pycodestyle")
    2407:       (setq lsp-pylsp-plugins-pycodestyle-enabled t))
    2408:     (when (executable-find "pydocstyle")
    2409:       (setq lsp-pylsp-plugins-pydocstyle-enabled t))
    2410:     (when (executable-find "pylint")
    2411:       (setq lsp-pylsp-plugins-pylint-enabled t))
    2412:     (when (executable-find "pyflakes")
    2413:       (setq lsp-pylsp-plugins-pyflakes-enabled t))
    2414:     (when (executable-find "yapf")
    2415:       (setq lsp-pylsp-plugins-yapf-enabled t)))
    2416:   (when (featurep 'flycheck)
    2417:     (setq flycheck-python-mypy-executable (executable-find "mypy")
    2418:           flycheck-python-flake8-executable (executable-find "flake8")
    2419:           flycheck-python-pylint-executable (executable-find "pylint")
    2420:           flycheck-python-pyright-executable (executable-find "pyright")))
    2421:   :general
    2422:   (+config/local-leader
    2423:     :keymaps 'python-mode-map
    2424:     "d" '(:ignore t :wk "doc")))
    2425: 
    2426: (use-package ob-ipython
    2427:   :ensure
    2428:   :defer t
    2429:   :init
    2430:   (setq ob-ipython-resources-dir ".ob-ipython-resrc")
    2431:   (with-eval-after-load 'org-src
    2432:     (add-to-list 'org-src-lang-modes '("ipython" . python)))
    2433:   (with-eval-after-load 'ob-async
    2434:     (add-to-list 'ob-async-no-async-languages-alist "ipython")))
    2435: (use-package pip-requirements
    2436:   :ensure
    2437:   :defer t
    2438:   :config
    2439:   (add-hook 'pip-requirements-mode-hook #'pip-requirements-auto-complete-setup))
    2440: 
    2441: (use-package lsp-pyright
    2442:   :ensure
    2443:   :after lsp-mode
    2444:   :hook (python-mode . (lambda ()
    2445:                          (lsp-deferred)
    2446:                          (lsp-ui-mode)
    2447:                          (lsp-ui-doc-mode)))
    2448:   :config
    2449:   (setq lsp-pyright-python-executable-cmd
    2450:         (if (executable-find "python3")
    2451:             (executable-find "python3")
    2452:           "python")))
    2453: (use-package python-docstring
    2454:   :ensure
    2455:   :diminish
    2456:   :hook (python-mode . python-docstring-mode)
    2457:   :general
    2458:   (+config/local-leader
    2459:     :keymaps 'python-mode-map
    2460:     "dq" 'python-docstring-fill))
    2461: (use-package pipenv
    2462:   :ensure
    2463:   :diminish
    2464:   :after python
    2465:   :commands pipenv-project-p
    2466:   :hook (python-mode . pipenv-mode)
    2467:   :init
    2468:   (setq pipenv-projectile-after-switch-function
    2469:         #'pipenv-projectile-after-switch-extended
    2470:         pipenv-executable (executable-find "pipenv"))
    2471:   :general
    2472:   (+config/local-leader
    2473:     :keymaps 'python-mode-map
    2474:     "p" '(:keymap pipenv-command-map :package pipenv :wk "pipenv")))
    2475: 
    2476: 
    2477: (use-package ein
    2478:   :ensure t)
    2479: ;;;###autoload
    2480: (defun +rust-cargo-project-p ()
    2481:   "Return t if this is a cargo project."
    2482:   (locate-dominating-file buffer-file-name "Cargo.toml"))
    2483: 
    2484: ;;; Custom Cargo commands
    2485: 
    2486: (autoload 'rustic-run-cargo-command "rustic-cargo")
    2487: ;;;###autoload
    2488: (defun +rust/cargo-audit ()
    2489:   "Run 'cargo audit' for the current project."
    2490:   (interactive)
    2491:   (rustic-run-cargo-command "cargo audit"))
    2492: 
    2493: (with-eval-after-load 'projectile
    2494:   (add-to-list 'projectile-project-root-files "Cargo.toml"))
    2495: 
    2496: (use-package rust-mode)
    2497: (use-package rustic
    2498:   :ensure
    2499:   :mode ("\\.rs$" . rustic-mode)
    2500:   :init
    2501:   (with-eval-after-load 'rustic-flycheck
    2502:     (remove-hook 'rustic-mode-hook #'flycheck-mode)
    2503:     (remove-hook 'rustic-mode-hook #'flymake-mode-off)
    2504:     (remove-hook 'flycheck-mode-hook #'rustic-flycheck-setup))
    2505:   (with-eval-after-load 'org-src
    2506:     (defalias 'org-babel-execute:rust #'org-babel-execute:rustic))
    2507:   :config
    2508:   (add-hook 'rustic-mode-hook #'rainbow-delimiters-mode)
    2509:   (setq rustic-indent-method-chain t
    2510:         rustic-lsp-client 'lsp-mode)
    2511:   (add-hook 'rustic-mode-local-vars-hook #'rustic-setup-lsp 'append)
    2512:   (add-hook 'rustic-mode-local-vars-hook #'flycheck-mode)
    2513:   ;; (add-hook 'rustic-mode-local-vars-hook #'tree-sitter! 'append)
    2514:   (with-eval-after-load 'lsp
    2515:     (setq lsp-rust-analyzer-display-parameter-hints t)))
    2516: (use-package flycheck-rust
    2517:   :ensure
    2518:   :after flycheck
    2519:   :config
    2520:   (with-eval-after-load 'rustic
    2521:     (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)))
    2522: (use-package ansible
    2523:   :ensure
    2524:   :defer t
    2525:   :if (executable-find "ansible")
    2526:   :ensure
    2527:   :commands ansible-auto-decrypt-encrypt
    2528:   :hook (ansible . 'ansible-auto-decrypt-encrypt)
    2529:   :init
    2530:   (put 'ansible-vault-password-file 'safe-local-variable #'stringp)
    2531:   :config
    2532:   (setq ansible-section-face 'font-lock-variable-name-face
    2533:         ansible-task-label-face 'font-lock-doc-face)
    2534:   :general
    2535:   (+config/local-leader
    2536:     :keymaps 'yaml-mode-map
    2537:     "a" '(:ignore t :wk ansible)
    2538:     "ad" 'ansible-decrypt-buffer
    2539:     "ae" 'ansible-encrypt-buffer))
    2540: (use-package ansible-doc
    2541:   :after ansible
    2542:   :ensure
    2543:   :hook (yaml-mode . ansible-doc-mode)
    2544:   :config
    2545:   (when (featurep 'evil)
    2546:     (evil-set-initial-state '(ansible-doc-module-mode) 'emacs)))
    2547: (use-package cperl-mode
    2548:   :ensure
    2549:   :defer t
    2550:   :mode ("\\.\\([pP][Llm]\\|al\\)\\'" . cperl-mode))
    2551: (use-package haskell-mode
    2552:   :ensure t
    2553:   :defer t
    2554:   :init
    2555:   (setq flymake-allowed-file-name-masks nil)
    2556:   :custom
    2557:   (haskell-process-load-or-reload-prompt t)
    2558:   (haskell-process-auto-import-loaded-modules t)
    2559:   (haskell-process-log t)
    2560:   (haskell-tags-on-save t))
    2561: (use-package lsp-haskell
    2562:   :ensure t
    2563:   :defer t
    2564:   :after lsp)
    2565: (use-package magit
    2566:   :ensure
    2567:   :demand t
    2568:   :config
    2569:   (evil-set-initial-state #'git-commit-mode 'insert)
    2570:   :custom
    2571:   (magit-revision-show-gravatars '("^Author:     " . "^Commit:     "))
    2572:   (magit-diff-refine-hunk 'all)
    2573:   (magit-log-arguments '("-n100" "--graph" "--decorate"))
    2574:   :general
    2575:   (+config/leader-go
    2576:     "g" 'magit-status))
    2577: (use-package projectile
    2578:   :ensure t
    2579:   :demand t
    2580:   :bind (([remap evil-jump-to-tag] . projectile-find-tag)
    2581:          ([remap find-tag] . projectile-find-tag))
    2582:   :hook (dired-before-readin . projectile-track-known-projects-find-file-hook)
    2583:   :custom
    2584:   (projectile-cache-file (expand-file-name ".projects" user-emacs-directory))
    2585:   (projectile-auto-discover nil)
    2586:   (projectile-enable-caching (not noninteractive))
    2587:   (projectile-globally-ignored-files '("DS_Store" "TAGS"))
    2588:   (projectile-globally-ignored-file-suffixes '(".elc" ".pyc" ".o"))
    2589:   (projectile-kill-buffers-filter 'kill-only-files)
    2590:   (projectile-known-projects-file (expand-file-name ".projectile_projects.eld" user-emacs-directory))
    2591:   (projectile-ignored-projects '("~/"))
    2592:   (projectile-project-root-files-bottom-up
    2593:    (append '(".projectile" ".project" ".git")
    2594:            (when (executable-find "hg")
    2595:              '(".hg"))
    2596:            (when (executable-find "bzr")
    2597:              '(".bzr"))))
    2598:   (projectile-project-root-files-top-down-recurring '("Makefile"))
    2599:   (compilation-buffer-name-function #'projectile-compilation-buffer-name)
    2600:   (compilation-save-buffers-predicate #'projectile-current-project-buffer-p)
    2601:   (projectile-git-submodule-command nil)
    2602:   (projectile-indexing-method 'hybrid)
    2603:   :config
    2604:   (projectile-mode +1)
    2605:   (put 'projectile-git-submodule-command 'initial-value projectile-git-submodule-command)
    2606:   :general
    2607:   (+config/leader-key
    2608:     "SPC" 'projectile-find-file
    2609:     "p" '(:keymap projectile-command-map :package projectile :wk "projectile")))
    2610: (use-package diff-hl
    2611:   :ensure
    2612:   :hook (find-file . diff-hl-mode)
    2613:   :hook (vc-dir-mode . diff-hl-dir-mode)
    2614:   :hook (dired-mode . diff-hl-dired-mode)
    2615:   :hook (diff-hl-mode . diff-hl-flydiff-mode)
    2616:   :hook (diff-hl-mode . diff-hl-show-hunk-mouse-mode)
    2617:   :hook (magit-pre-refresh-hook . diff-hl-magit-pre-refresh)
    2618:   :hook (magit-post-refresh-hook . diff-hl-magit-post-refresh)
    2619:   :init
    2620:   (global-diff-hl-mode)
    2621:   :custom
    2622:   (vc-git-diff-switches '("--histogram")
    2623:                         diff-hl-flydiff-delay 0.5
    2624:                         diff-hl-show-staged-changes nil)
    2625:   :config
    2626:   (when (featurep 'flycheck)
    2627:     (setq flycheck-indication-mode 'right-fringe)))
    2628: (use-package perspective
    2629:   :ensure
    2630:   :config
    2631:   (setq persp-initial-frame-name "Main"
    2632:         persp-suppress-no-prefix-key-warning t)
    2633:   (if (featurep 'no-littering)
    2634:       (setq persp-state-default-file (expand-file-name ".perspective-state" no-littering-var-directory))
    2635:     (setq persp-state-default-file (expand-file-name ".perspective-state" user-emacs-directory)))
    2636:   (global-set-key [remap switch-to-buffer] #'persp-switch-to-buffer*)
    2637:   (when (featurep 'consult)
    2638:     (require 'consult)
    2639:     (unless (boundp 'persp-consult-source)
    2640:       (defvar persp-consult-source
    2641:         (list :name     "Perspective"
    2642:               :narrow   ?s
    2643:               :category 'buffer
    2644:               :state    #'consult--buffer-state
    2645:               :history  'buffer-name-history
    2646:               :default  t
    2647:               :items
    2648:               #'(lambda () (consult--buffer-query :sort 'visibility
    2649:                                                   :predicate '(lambda (buf) (persp-is-current-buffer buf t))
    2650:                                                   :as #'buffer-name)))))
    2651:     (consult-customize consult--source-buffer :hidden t :default nil)
    2652:     (add-to-list 'consult-buffer-sources persp-consult-source))
    2653:   :init
    2654:   (customize-set-variable 'persp-mode-prefix-key (kbd "C-c TAB"))
    2655:   (unless (equal persp-mode t)
    2656:     (persp-mode 1))
    2657:   :bind (([remap switch-to-buffer] . persp-switch-to-buffer*)
    2658:          ([remap kill-buffer] . persp-kill-buffer*))
    2659:   :hook (kill-emacs . persp-state-save)
    2660:   :general
    2661:   (general-def
    2662:     :keymaps 'perspective-map
    2663:     "TAB" '(persp-switch-last :wk "switch to last perspective")
    2664:     "P" 'projectile-persp-switch-project)
    2665:   (+config/leader-key
    2666:     "TAB" (general-simulate-key "C-c TAB"
    2667:             :state '(normal visual)
    2668:             :name general-SPC-h-simulates-C-c-TAB
    2669:             :docstring "Simulates C-c TAB in normal and visual mode."
    2670:             :which-key "Perspective"))
    2671:   (+config/leader-key
    2672:     "C-x" '(persp-switch-to-scratch-buffer :wk "switch to scratch buffer")))
    2673: (use-package persp-projectile
    2674:   :ensure t
    2675:   :after perspective
    2676:   :commands projectile-persp-switch-project
    2677:   :general
    2678:   (general-def
    2679:     :keymaps 'perspective-map
    2680:     "P" 'projectile-persp-switch-project))
    2681: (use-package git-link
    2682:   :demand
    2683:   :ensure
    2684:   :commands (git-link git-link-commit git-link-homepage)
    2685:   :general
    2686:   (+config/leader-go
    2687:     "G" '(:ignore t :wk "git")
    2688:     "Gl" 'git-link
    2689:     "Gh" 'git-link-homepage
    2690:     "Gc" 'git-link-commit))
    2691: (use-package git-messenger
    2692:   :ensure
    2693:   :config
    2694:   (with-eval-after-load 'general
    2695:     (+config/leader-go
    2696:       "Gm" 'git-messenger:popup-message))
    2697:   :custom
    2698:   ;; Enable magit-show-commit instead of pop-to-buffer
    2699:   (git-messenger:use-magit-popup t)
    2700:   (git-messenger:show-detail t))
    2701: (use-package git-timemachine
    2702:   :ensure
    2703:   :after magit
    2704:   :general
    2705:   (+config/leader-go
    2706:     "Gt" 'git-timemachine-toggle))
    2707: (use-package org-project-capture
    2708:   :bind (("C-c n p" . org-project-capture-project-todo-completing-read))
    2709:   :ensure t
    2710:   :config
    2711:   (progn
    2712:     (setq org-project-capture-backend
    2713:           (make-instance 'org-project-capture-projectile-backend))  ; Replace with your backend of choice
    2714:     (setq org-project-capture-projects-file (expand-file-name "projects.org" org-directory))
    2715:     (org-project-capture-single-file)))
    2716: (use-package lsp-mode
    2717:   :ensure
    2718:   :init
    2719:   (setq lsp-keymap-prefix "C-c C-l")
    2720:   (defun my/orderless-dispatch-flex-first (_pattern index _total)
    2721:     (and (eq index 0) 'orderless-flex))
    2722:   (defun my/lsp-mode-setup-completion ()
    2723:     (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))
    2724:           '(orderless)))
    2725:   (add-hook 'orderless-style-dispatchers #'my/orderless-dispatch-flex-first nil 'local)
    2726:   (when (featurep 'cape)
    2727:     (setq-local completion-at-point-functions (list (cape-capf-buster #'lsp-completion-at-point))))
    2728:   :hook
    2729:   (lsp-mode . lsp-enable-which-key-integration)
    2730:   (lsp-completion-mode . my/lsp-mode-setup-completion)
    2731:   ((c-mode c++-mode xml-mode python-mode
    2732:            yaml-mode toml-mode python-mode-local-vars
    2733:            lua-mode jinja2-mode
    2734:            json-mode html-mode
    2735:            web-mode html-mode-local-vars-hook
    2736:            web-mode-local-vars-hook nxml-mode-local-vars-hook
    2737:            scss-mode-local-vars css-mode-local-vars
    2738:            less-css-mode-local-vars css-mode
    2739:            typescript-mode javascript-mode
    2740:            js2-mode typescript-tsx-mode) . lsp-deferred)
    2741:   :config
    2742:   (setq lsp-toml-command
    2743:         (if (file-exists-p (expand-file-name ".cargo/bin/taplo" "~"))
    2744:             (expand-file-name ".cargo/bin/taplo" "~")
    2745:           "taplo")
    2746:         lsp-rust-rls-server-command "rls"
    2747:         lsp-eldoc-render-all t
    2748:         lsp-enable-snippet nil
    2749:         lsp-enable-indentation nil
    2750:         lsp-prefer-flymake nil
    2751:         lsp-keep-workspace-alive nil
    2752:         lsp-modeline-code-actions-segments '(count icon name))
    2753:   (when (featurep 'exwm)
    2754:     (advice-add #'corfu--make-frame :around
    2755:                 (defun +corfu--make-frame-a (oldfun &rest args)
    2756:                   (cl-letf (((symbol-function #'frame-parent)
    2757:                              (lambda (frame)
    2758:                                (or (frame-parameter frame 'parent-frame)
    2759:                                    exwm-workspace--current))))
    2760:                     (apply oldfun args))
    2761:                   (when exwm--connection
    2762:                     (set-frame-parameter corfu--frame 'parent-frame nil))))
    2763: 
    2764:     (advice-add #'corfu--popup-redirect-focus :override
    2765:                 (defun +corfu--popup-redirect-focus-a ()
    2766:                   (redirect-frame-focus corfu--frame
    2767:                                         (or (frame-parent corfu--frame)
    2768:                                             exwm-workspace--current)))))
    2769:   :custom
    2770:   (lsp-completion-provider :none)
    2771:   :general
    2772:   (+config/leader-key
    2773:     :keymaps 'lsp-mode-map
    2774:     "l" (general-simulate-key "C-c C-l"
    2775:           :name general-SPC-l-simulates-C-c-C-l
    2776:           :docstring "Simulates C-c C-l"
    2777:           :which-key "LSP")))
    2778: (use-package lsp-ui
    2779:   :ensure
    2780:   :defer t
    2781:   :hook (lsp-mode . lsp-ui-mode)
    2782:   :init
    2783:   (setq lsp-ui-sideline-enable t
    2784:         lsp-ui-sideline-update-mode 'line
    2785:         lsp-ui-sideline-show-code-actions t
    2786:         lsp-ui-sideline-show-hover t
    2787:         lsp-ui-doc-enable t
    2788:         lsp-ui-doc-include-signature t
    2789:         lsp-ui-doc-show-with-cursor t
    2790:         lsp-eldoc-enable-hover nil ; Disable eldoc displays in minibuffer
    2791:         lsp-ui-doc-position 'at-point
    2792:         lsp-ui-imenu-enable t
    2793:         lsp-ui-sideline-ignore-duplicate t
    2794:         lsp-ui-peek-enable t)
    2795:   :config
    2796:   (define-key lsp-ui-mode-map [remap xref-find-definitions] #'lsp-ui-peek-find-definitions)
    2797:   (define-key lsp-ui-mode-map [remap xref-find-references] #'lsp-ui-peek-find-references)
    2798:   (add-to-list 'lsp-language-id-configuration '(jinja2-mode . "jinja2") t)
    2799:   (add-to-list 'lsp-language-id-configuration '("\\.js2$" . "jinja2") t)
    2800:   :general
    2801:   (general-define-key
    2802:    :keymaps '(lsp-ui-mode-map)
    2803:    [remap xref-find-definitions] 'lsp-ui-peek-find-definitions
    2804:    [remap xref-find-references] 'lsp-ui-peek-find-references
    2805:    "M-." 'lsp-ui-peek-find-definitions
    2806:    "M-?" 'lsp-ui-peek-find-references))
    2807: (use-package consult-lsp
    2808:   :ensure
    2809:   :after consult lsp
    2810:   :bind
    2811:   (:map lsp-mode-map
    2812:         ([remap xref-find-apropos] . consult-lsp-symbols)))
    

Footnotes:

Date: 2024-04-20 Sat 00:00

Author: Kristian Alexander P

Created: 2024-05-09 Thu 10:52