Ivory Siege Tower

mobile construct built of thoughts and parentheses

Literate Emacs init.el

emacs init_el project setup

§ Bootstrapping use-package

Modern emacs is best configured - if not used from frameworks like doom/ or spacemacs - declaratively with use-package/ macro.

  ;;; Declarative setup with `use-package'.
  (require 'package)
  (setq package-archives
        `(,@package-archives
          ("melpa" . "https://melpa.org/packages/")
          ("org" . "https://orgmode.org/elpa/")))
  (package-initialize)

  ;; probably, to enable the autoloads...
  (setq package-enable-at-startup nil)

  ;; explicit default signature checking policy
  (setq package-check-signature 'allow-unsigned)

  ;; init 'use-package
  (unless (package-installed-p 'use-package)
    (package-refresh-contents)
    (package-install 'use-package))

  (eval-when-compile
    (require 'use-package))

  (put 'use-package 'lisp-indent-function 1)
  (setq use-package-always-ensure t)
  (setq use-package-verbose t)
  (setq use-package-minimum-reported-time 0.01)
  ;; :diminish keyword
  (use-package diminish)

  ;; :bind keyword
  (use-package bind-key)

  ;; :quelpa keyword
  (use-package quelpa)
  (use-package quelpa-use-package
    :config
    (setq use-package-ensure-function 'quelpa))

§ System Packages

Those well detect guix as a package manager.

  (use-package system-packages            ;
    :custom
    (system-packages-noconfirm t))
  (use-package use-package-ensure-system-package)

§ Custom Variables Used in Configurations

The concrete definitions of the following vars are private and not exported. Anyways, here's their meanings:

  • my-init/grimoire-dir points to the location of Grimoire - my universal entry-point for Org-mode stuff synchronized across machines.

  • my-init/org-roam-dir stands for the root of Org-Roam-ed files.

  • my-init/org-download-dir is the location of files downloaded directly into Org.

  • my-init/org-agenda-file is the general Org Agenda task dumpster drawer.

  • my-init/org-backlog-file is the list of media sources to pay attention sometime.

  • my-init/worklog-path is a relative path to the work-related Org-Roam daily directories.

  • my-init/org-remark-notes-file denotes a file to store Org-Remarks.

§ Emacs core package setup

This is self-explanatory, mostly. The locale is set to default system locale. Encoding is of course utf-8. UI set to visual minimalism, with close to perfect modus-themes. Version control will be dispatched to magit, therefore the built-in one is off. File autosaves stored under separate distinct paths.

Access to lisp local source files and rust custom dynamic modules also wired here. I might reorganize the form when have more clear view on how to package my own stuff.

  (use-package emacs
    :ensure nil
    :init
    (setq flycheck-disabled-checkers '(emacs-lisp-checkdoc))
    (setq system-time-locale "C")
    (set-default 'truncate-lines t)
    (set-scroll-bar-mode 'nil)

    ;;; Path to Guix-installed packages
    (add-to-list 'load-path "~/.guix-profile/share/emacs/site-lisp") 
    ;;; I also need to get all the MELPA-installed packages on
    (let ((default-directory "~/.emacs.d/elpa/"))
       (normal-top-level-add-subdirs-to-load-path))
    (guix-emacs-autoload-packages)

    (add-to-list 'load-path
                 (format "%s/.guix-profile/share/emacs/site-lisp" (getenv "HOME"))) ;; Emails: Mu4e from GUIX
    (put 'narrow-to-region 'disabled nil)
    (put 'downcase-region 'disabled nil)
    (set-face-attribute 'default nil :height 140 :family "Iosevka Extended")
    (set-face-attribute 'fixed-pitch nil :family "Iosevka Extended")
    (set-face-attribute 'variable-pitch nil :family "Iosevka Extended")

    ;; Agda-mode set manually:
    ;; (load-file (let ((coding-system-for-read 'utf-8))
    ;;              (shell-command-to-string "agda-mode locate")))

    (let ((default-directory "~/.emacs.d/lisp-dev/"))
      (normal-top-level-add-subdirs-to-load-path))

    ;; For Rust dynamic modules.
    ;; https://github.com/ubolonton/emacs-module-rs/tree/master/rs-module
    ;;NOTE: Subject to many possible changes/reorganizations.
    (add-to-list 'load-path (file-truename "~/.emacs.d/dynmods"))
    (when (file-exists-p (file-truename "~/.emacs.d/dynmods/rs_module.so"))
     (module-load (file-truename "~/.emacs.d/dynmods/rs_module.so"))
     (defun load-rs-module (mod-name)
       (rs-module/load
        (file-truename
         (format "~/.emacs.d/dynmods/%s.so" mod-name)))))

    :custom
    ;; I know I won't overload myself with warnings UNLESS I need them:
    (warning-minimum-level :emergency)    

    (scroll-step 1)
    (inhibit-startup-screen t "Don't show splash screen")
    (use-dialog-box nil "Disable dialog boxes")
    (enable-recursive-minibuffers t "Allow minibuffer commands in the minibuffer")
    (indent-tabs-mode nil "Spaces!")
    (delete-old-versions -1)
    (version-control nil)
    (auto-save-default nil)
    (auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save-list/" t)))
    (ring-bell-function 'ignore)
    (coding-system-for-read 'utf-8)
    (coding-system-for-write 'utf-8)
    (sentence-end-double-space nil)
    (default-fill-column 80)
    (initial-scratch-message ";; -*- lexical-binding: t -*-\n;;; Good morning, Captain!\n\n")
    (debug-on-quit nil)
    (column-number-mode 1)
    (reb-re-syntax 'string))

§ Appearance

Temporarily (?) external instructions for appearance:

  • no blinking cursor;

  • no visible menus;

  • modus themes (prefer built-in);

  • 85% transparency level;

  • custom cursor color (overriden by theme).

  (blink-cursor-mode 0)
  (menu-bar-mode -1)
  (tool-bar-mode -1)

  (require-theme 'modus-themes)
  (load-theme 'modus-vivendi t)

  (set-frame-parameter (selected-frame) 'alpha '(85 . 50))
  (add-to-list 'default-frame-alist '(alpha . (85 . 50)))

  ;; (setq default-frame-alist
  ;;       (append default-frame-alist
  ;;               '((cursor-color . "MediumSlateBlue"))))

§ File backups and saving options

E.g. if a newline in the end of the file is mandatory... creo que no.

Also, commented out a hook for deleting trailing whitespaces in file lines upon saving. Don't remember why but, perhaps, because of the artist-mode. Less processing anyway.

  (use-package files
    :ensure nil
    ;; :hook
    ;; (before-save . delete-trailing-whitespace)
    :custom
    (require-final-newline nil)
    ;; backup settings
    (backup-by-copying t)
    (backup-directory-alist `(("." . "~/.emacs.d/backups")))
    (delete-old-versions t)
    (kept-new-versions 6)
    (kept-old-versions 2)
    (version-control t))                  ; version numbers for backup files

Customization tools. Alternatively, one can use (make-temp-file "emacs-custom").

In order not to use customizations, set custom-file to null-device.

  (use-package cus-edit
    :ensure nil
    :custom
    (custom-file (make-temp-file "emacs-custom")))

§ EasyPG Assistant

Is here for encrypting files with GnuPG.

  (use-package epa
    :ensure nil
    :custom
    (epg-gpg-program "gpg")
    (epa-pinentry-mode nil))

§ Buffer Names from Files

  (use-package uniquify
    :ensure nil
    :custom
    (uniquify-buffer-name-style 'forward))

§ Miscellaneous

Load some of the packages from my elisp definitions.

  (require 'my-misc)

§ Setup for Calculations

Shortcuts for inline metric prefix conversions for region-selected numbers. Based on a macro from My Elisp Definitions.

Elisp modules defined there are available because in the init section for the emacs #'use-package form in the top I've added their location to the 'load-path.

Regex match removes underscore in optional formatting for Rust number.

  (require 'my-math)

  (defun my-region/convert-zero-to-tera (start end)
    (interactive "r")
    (if (use-region-p)
        (let* ((regionp (buffer-substring start end))
               (num (string-to-number
                     (replace-regexp-in-string "_+" "" regionp))))
          (message "%s T"
                   (my-math/convert-metric-prefix-for num _ T 4)))))

  (defun my-region/convert-yocto-to-zero (start end)
    (interactive "r")
    (if (use-region-p)
        (let* ((regionp (buffer-substring start end))
               (num (string-to-number
                     (replace-regexp-in-string "_+" "" regionp))))
          (message "%s"
                   (my-math/convert-metric-prefix-for num y _ 6)))))

Additional units and constants used with calc during thermal transport studies.

If it grows beyond meaningful limits (unlikely to happen), I might move this piece to calc.el

  (use-package calc
    :config
    (setq var-ff "0.0483776900146")       ; thermal transport flux conversion factor

    (eval-after-load "calc-units"
      '(progn
         (setq math-additional-units
               '((Bohr  "5.29177249*10^(-11) m"
                        "Bohr radius [ hbar^2/(m*e^2) ]" atU)
                 (Eryd  "2.1798741*10^(-18) J"
                        "Rydberg energy [ e^2/(2*a0) ]" atU)
                 (Ehart "4.3597482*10^(-18) J"
                        "Hartree energy [ e^2/a0 ]" atU)
                 (tryd  "4.83776865318*10^(-17) s"
                        "Rydberg time unit [ hbar/E_Ryd ]" atU)
                 (thart "2.41888432659*10^(-17) s"
                        "Hartree time unit [ hbar/E_Hart ]" atU)
                 (vryd "1.09384563182*10^(6) m s^(-1)"
                       "Rydberg velocity unit [ a0*E_Ryd/hbar ]" atU)
                 (vhart  "2.18769126364*10^(6) m s^(-1)"
                         "Hartree velocity unit [ a0*E_Hart/hbar ]" atU))
               math-units-table nil))))

§ Appearance tweaks

Font icons for Org sections etc. To finish installation invoke M-x all-the-icons-install-fonts

Guix outputs a plethora of related packages when searching for all-the-icons.

  (use-package all-the-icons
    :config
    (load
     (expand-file-name
      (file-truename
       (format "%s/org/category-icons.el"
               my-init/grimoire-dir)))))

Mood-line is a clean, minimalistic mode-line. Moody is an alternative, but it's less convenient.

  (use-package mood-line
    :ensure t
    :config (mood-line-mode))

  ;; (use-package moody
  ;;   :ensure t
  ;;   :config
  ;;   (setq x-underline-at-descent-line t)
  ;;   (moody-replace-mode-line-buffer-identification)
  ;;   (moody-replace-vc-mode)
  ;;   (moody-replace-eldoc-minibuffer-message-function))

In-buffer line bookmarks.

  (use-package bm
    :ensure t
    :bind (("<C-f2>" . bm-toggle)
           ("<f2>"   . bm-next)
           ("<S-f2>" . bm-previous)))

Golden ratio for frames and rainbows. For the latter, rainbow-mode and -delimeters is a yes, rainbow-identifiers - no.

The Golden ratio toggle switch will be included in the general.el use-package form, since General hasn't been imported yet.

  (use-package golden-ratio :ensure t)

  (use-package rainbow-delimiters
    :hook
    (prog-mode . rainbow-delimiters-mode))

  (use-package rainbow-mode
    :diminish rainbow-mode
    :hook prog-mode)

Highlight matching parens:

  (use-package paren
    :ensure nil
    :config (show-paren-mode t))

Highlight annotation keywords in both programming modes and Org:

  (use-package hl-todo
    :hook
    (prog-mode . hl-todo-mode)
    (org-mode  . hl-todo-mode)
    :config
    (setq hl-todo-highlight-punctuation ":"
          hl-todo-keyword-faces
          `(("TODO"       warning bold)
            ("FIXME"      error bold)
            ("HACK"       font-lock-constant-face bold)
            ("REVIEW"     font-lock-keyword-face bold)
            ("NOTE"       success bold)
            ("DEPRECATED" font-lock-doc-face bold))))

§ General.el for custom shortcuts declarations

As from a while ago, when I migrated from spacemacs to vanilla emacs, I still use general.el + which-key combo to define custom shortcuts.

However, only recently did I start refactoring the configuration, placing shortcuts definitions for packages together with their own use-package forms.

Throwing them altogether into general's use-package works too, but is not modular nor elegant (that way one has to always refer to it when adding/ removing/ editing/ a set of packages installed).

  (use-package general
    :ensure t
    :config
    (general-define-key
     ;; replace default keybindings
     "C-s" 'swiper             ; search for string in current buffer
     "M-x"  '(lambda () (interactive) (counsel-M-x ""))) ; replace default M-x with ivy backend
    ;; "M-]" 'scheme-smart-complete)

    (general-create-definer my-leader-def
      ;; :prefix my-leader
      :prefix "M-SPC")

    (general-create-definer my-local-leader-def
      ;; :prefix my-local-leader
      :prefix "M-SPC m")

    (my-leader-def
      :states '(normal visual emacs)

      ;; Root
      "/"   'counsel-ag
      ;; "TAB" 'dired-sidebar-toggle-sidebar
      "TAB" '(switch-to-next-buffer :which-key "next buffer")

      ;; Selected region conversions
      "."   '(:ignore t :which-key "Convert Selected")
      ".t"  'my-region/convert-zero-to-tera
      ".y"  'my-region/convert-yocto-to-zero

      ;; Windows
      "w"   '(:ignore t :which-key "Windows")
      "ww"  'other-window
      "wh"  'split-window-below
      "wv"  'split-window-right
      "wo"  'delete-other-windows
      "wd"  'delete-window

      ;; Commands
      "c"   '(:ignore t :which-key "Commands")
      "cc"  'org-capture
      "cf"  'flyspell-correct-word-before-point
      "cd"  '(:ignore t :which-key "Counsel-Dash")
      "cda"  'dash-docs-activate-docset
      "cdd"  'counsel-dash-at-point
      "cl"  'org-store-link
      "ct"  'counsel-tramp
      "cy"  '(:ignore t :which-key "Yas")
      "cyy" 'yas-insert-snippet
      "cyn" 'yas-new-snippet
      "cyv" 'yas-visit-snippet-file
      "+"   '((lambda () (interactive)
                (my-misc/change-default-face-height-globally 20))
              :which-key "+")
      "-"   '((lambda () (interactive)
                (my-misc/change-default-face-height-globally -20))
              :which-key "-")

      ;; Applications
      "a"   '(:ignore t :which-key "Applications")
      "aa"  '(:ignore t :which-key "AI gptel menu")
      "aaa" 'gptel-send
      "aas" 'gptel-send
      "aam" 'gptel-menu
      "aag" 'gptel
      "ad"  'dired
      "af"  'elfeed
      "ao"  'org-agenda
      ;; "ae"  'go-social-with-bitlbee
      "as"  '(:ignore t :which-key "Shell selection")
      "ass" 'shell
      "ase" 'eshell
      "asa" 'ansi-term

      "aw"  '(:ignore t :which-key "Work Calendar")
      "awd" '((lambda () (interactive)
                (let ((org-roam-dailies-directory my-init/worklog-path))
                  (org-roam-dailies-goto-date)))
              :which-key "Worklog Date")
      "aw." '((lambda () (interactive)
                (let ((org-roam-dailies-directory my-init/worklog-path))
                  (org-roam-dailies-goto-today)))
              :which-key "Worklog Today")

      ;; Smerge
      "s" '(:keymap smerge-basic-map
                    :package smerge-mode
                    :which-key "Smerge")

      ;; Toggles
      "t"   '(:ignore t :which-key "Toggles")
      "tg"  'golden-ratio-mode
      "tl"  'toggle-truncate-lines
      "ts"  'toggle-scroll-bar

      ;; Buffers
      "b"   '(:ignore t :which-key "Buffers")
      "bb"  'ivy-switch-buffer
      "bk"  'kill-buffer
      "ba"  'auto-fill-mode
      "bf"  'flyspell-buffer

      ;; Shortcuts
      "e"   '(:ignore t :which-key "Edit")
      "ed"  '((lambda() (interactive)
                (switch-to-buffer
                 (find-file-noselect "~/.emacs.d/init.el")))
              :which-key "dotemacs config")
      "eb"  '((lambda() (interactive)
                (switch-to-buffer
                 (find-file-noselect "~/.bashrc")))
              :which-key "bashrc")
      "es"  '((lambda() (interactive)
                (switch-to-buffer
                 (find-file-noselect "~/.stumpwmrc")))
              :which-key "stumpwm config")

      ;; Org-mode
      ;; Contains links to Grimoire
      "o"   '(:ignore t :which-key "Open...")
      "ow"  '(my-misc/open-link-in-eww :which-key "link in EWW")
      "oe"  '(my-misc/open-link-in-eww :which-key "link in EWW")

      "ot"  '((lambda() (interactive)
                (switch-to-buffer
                 (find-file-noselect my-init/org-agenda-file)))
              :which-key "Todos and Agenda")
      "ob"  '((lambda() (interactive)
                (switch-to-buffer
                 (find-file-noselect my-init/org-backlog-file)))
              :which-key "Backlog")
      "oj"  '((lambda() (interactive)
                (switch-to-buffer
                 (find-file-noselect
                  (format "%s/org/journal.org.gpg" my-init/grimoire-dir))))
              :which-key "my olde Journal (for reference, no new edits)")
      "or" '((lambda() (interactive)
               (switch-to-buffer
                (find-file-noselect "~/Refs/phd.bib")))
             :which-key "Main Bibtex file")
      "on" '((lambda() (interactive)
               (switch-to-buffer
                (find-file-noselect
                 (file-truename (format "%s/papers.org" my-init/org-roam-dir)))))
             :which-key "Research Notes")

      ;; LSP-enhanced programming control
      "l"   '(:ignore t :which-key "Language Commands")
      ;; NOTE: not using flycheck at this point
      ;; "ll"   '(:keymap flycheck-command-map
      ;;          :package flycheck
      ;;          :which-key "Flycheck")
      "lm" 'imenu
      "lq" 'lsp-shutdown-workspace
      "lw" 'lsp-restart-workspace
      "lh" 'lsp-describe-thing-at-point
      "lr" 'lsp-rename
      "ld" 'lsp-find-definition
      "li" 'lsp-find-references
      "lp" 'lsp-ui-peek-find-references
      "lu" 'lsp-ui-mode))

§ Utility packages

Better menus for package-install. No guix so far.

  (use-package paradox :config (paradox-enable))

company-mode for autocompletion. Many extensions in guix.

  (use-package company
    :ensure t
    :config
    (add-hook 'after-init-hook 'global-company-mode))

One of such extensions: a front-end with icons.

  (use-package company-box
    :diminish t
    :hook (company-mode . company-box-mode))

which-key to get useful keystroke hints.

  (use-package which-key
    :ensure t
    :custom
    (which-key-idle-delay 0.5)
    (which-key-add-column-padding 2)
    :config
    (which-key-mode))

Automatically revert buffers when files on disk change.

  (use-package autorevert
    :ensure t
    :diminish auto-revert-mode)

wgrep & swiper

  (use-package wgrep)
  (use-package swiper)

silversearcher is a faster grep

  (use-package ag
    :defer t
    :ensure-system-package (ag . silversearcher-ag)
    :custom
    (ag-highlight-search t "Highlight the current search term."))

§ Elisp Development Tools

Transliteration to ASCII package:

  (use-package unidecode)

Data structures and sequence processing packages.

In principle, those are re-used through the following imports. But I leave them here explicitly.

  (use-package s)
  (use-package dash)
  (use-package ht)
  (use-package mustache)

All of them available in Guix, no need for Quelpa-ing.

One of the outcomes of these imports is the definition of handy threading macro found in dash.el, e.g. ->, ->> and -->. I can start using them straight away in the following definitions.

§ Yasnippet

A load of snippets that I care by habit, but rarely use...

  (use-package yasnippet
    :ensure yasnippet-snippets
    :config
    (setq yas-snippet-dirs
          (-> (format "%s/snippets" my-init/grimoire-dir)
              (file-truename)
              (list)
              (append yas-snippet-dirs))))

§ Kill Ring manipulations

Undo-tree provides a more familiar undoing, ready to be used together with evil-mode. In order to get the kill-ring history I also plug in the browse-kill-ring.

  (use-package undo-tree
    :ensure t
    :config (global-undo-tree-mode)
    :custom
    (undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))))

  (use-package browse-kill-ring
    :ensure t
    :general
    (my-leader-def
      :states '(normal visual emacs)
      "y" 'browse-kill-ring))

§ Magit

THE git interface like no other, nowhere...

  (use-package magit
    :ensure t
    :general
    (my-leader-def
      :states '(normal visual emacs)
      "g"   'magit-status
      "M-g" 'magit-dispatch))

Together with git-gutter, to watch for changed lines in fringes:

  (use-package git-gutter+
    :ensure t
    :config
    (use-package git-gutter-fringe+)
    (global-git-gutter+-mode))

§ Completion Tandem: Ivy and Counsel

§ Ivy

The completion framework of choice.

  (use-package ivy
    :ensure t
    :custom
    (ivy-use-virtual-buffers t)
    (ivy-count-format "(%d/%d) ")
    :config
    (ivy-mode 1))

  (use-package ivy-yasnippet)

  ;; (use-package ivy-bibtex :ensure t)
  (use-package helm-bibtex :ensure t)

Additionally, use Ivy completion in XREF buffers (useful for output of LSP search results to separate buffers with '#ivy-occur C-c C-o).

  (use-package ivy-xref
    :ensure t
    :init (setq xref-show-definitions-function
                #'ivy-xref-show-defs))

§ Counsel

Ivy's loyal companion.

  (use-package counsel :ensure t)

§ TRAMP

I only add completion support, for now.

  (use-package counsel-tramp)

§ Dash Docsets

counsel-dash provides searching through Dash docsets in emacs. Many of those are snapshots of invaluable online resources.

  (use-package counsel-dash
    ;;
    :custom
    (dash-docs-docsets-path "~/Grimoire/docsets")
    (dash-docs-docsets-url "https://raw.github.com/Kapeli/feeds/master")
    ;; (counsel-dash-docsets-url "https://raw.github.com/Kapeli/feeds/master")
    (dash-docs-use-workaround-for-emacs-bug nil) ; for 26.3 fixes conn bug
    (counsel-dash-browser-func 'browse-url)      ; or 'eww
    :hook
    (c-mode . (lambda () (setq-local counsel-dash-docsets '("C"))))
    (c++-mode . (lambda () (setq-local counsel-dash-docsets '("C++"))))
    (f90-mode . (lambda () (setq-local counsel-dash-docsets '("Fortran" "MPI" "OpenMP"))))
    (fortran-mode . (lambda () (setq-local counsel-dash-docsets '("Fortran" "MPI" "OpenMP"))))
    (scheme-mode . (lambda () (setq-local counsel-dash-docsets '("R5RS"))))
    (sly-mode . (lambda () (setq-local counsel-dash-docsets '("Common Lisp"))))
    (emacs-lisp-mode . (lambda () (setq-local counsel-dash-docsets '("Emacs Lisp"))))
    (dockerfile-mode . (lambda () (setq-local counsel-dash-docsets '("Docker")))))

§ Projectile

It is a project management tool that uses the frameworks above.

  (use-package projectile :ensure t
    :custom
    (projectile-completion-system 'ivy)
    :config
    (use-package counsel-projectile :ensure t)
    (counsel-projectile-mode)
    (projectile-load-known-projects)
    :diminish
    projectile-mode
    :general
    (my-leader-def
      :states '(normal visual emacs)
      "p" '(:keymap
            projectile-command-map
            :package projectile
            :which-key "Projectile (Counsel)")))

§ Programming modes

§ General syntax checks with Flycheck

  (use-package flycheck
    :ensure t
    :hook (after-init . global-flycheck-mode))

§ Diagrams

Classic graphviz diagrams specifications.

  (use-package graphviz-dot-mode)

§ Markup

Generic .yaml formatting.

  (use-package yaml-mode)

Separate mode for docker, extending on the .yaml.

  (use-package dockerfile-mode
    :config
    (add-to-list
     'auto-mode-alist
     '("Dockerfile\\'" . dockerfile-mode)))

Common Workflows Language is a concretization of .yaml too.

  (use-package cwl-mode)

§ Gnuplot

  (use-package gnuplot)
  (use-package gnuplot-mode)

§ Lisps

Enhancing the Lisp coding.

In case I need a lot slurp/barf-ing control over lisp forms - I'll try out lispy.

  (use-package elec-pair
    :ensure nil
    :config
    (require 'elec-pair)
    (defun my-init/electric-pair-local-text-mode ()
      "Advise and wrap electric pairs in text mode."
      (add-function :before-until electric-pair-inhibit-predicate
                    (lambda (c) (eq c ?<)))
      (electric-pair-local-mode))
  
    :hook ((prog-mode . electric-pair-local-mode)
           (text-mode . my-init/electric-pair-local-text-mode)))

TODO: switch from evil-cleverparens to LispyVille.

  (use-package evil-cleverparens
    :hook
    (sly-mode . evil-cleverparens-mode)
    (emacs-lisp-mode . evil-cleverparens-mode))

§ Emacs Lisp

Definitions' visual highlighting:

  (use-package highlight-defined
    :ensure t
    :hook (emacs-lisp-mode . highlight-defined-mode))

  (use-package highlight-quoted
    :ensure t
    :hook (emacs-lisp-mode . highlight-quoted-mode))

Sexy elisp form evaluation result overlay:

  (use-package eros
    :hook (emacs-lisp-mode . eros-mode))

Suggest.el in searching for forms

  (use-package suggest)

§ Common Lisp

Sly is neat development of SLIME attitude towards consing the Lisp.

  (use-package sly
    :config (setq inferior-lisp-program "sbcl"))

§ Python

For python development, elpy feels Okay.

  (use-package elpy
    :ensure t
    :custom (python-shell-interpreter "python")
    :init
    (progn (setenv "WORKON_HOME" (format "%s/envs/" (getenv "HOME")))
           (define-key elpy-refactor-map (kbd "b")
                       (cons (format "%slack format code"
                                     (propertize "b" 'face 'bold))
                             'elpy-black-fix-code))
           (elpy-enable)))

Flymake-python-pyflakes setup for code inspection.

  (use-package flymake-python-pyflakes
    :hook (python-mode . flymake-python-pyflakes-load)
    :custom (flymake-python-pyflakes-executable "flake8"))

Flymake-ruff for code linting.

  (use-package flymake-ruff
    :ensure t
    :hook (python-mode . flymake-ruff-load))

§ Js & Typescript

Js/Js2 mode setup instructions are a mess. The following seems to work okay.

  (use-package js2-mode
    :config
    (add-to-list 'auto-mode-alist '("\\.js\\'" . js-mode))
    (add-hook 'js-mode-hook 'js2-minor-mode)
    (add-to-list 'interpreter-mode-alist '("node" . js2-mode)))

Tide is cool Typescript IDE-like mode. Like it!

  (use-package tide
    :ensure t
    :config
    (defun setup-tide-mode ()
      (interactive)
      (tide-setup)
      (flycheck-mode +1)
      (setq flycheck-check-syntax-automatically '(save mode-enabled))
      (eldoc-mode +1)
      (tide-hl-identifier-mode +1)
      (company-mode +1))

    ;; aligns annotation to the right hand side
    (setq company-tooltip-align-annotations t)

    ;; formats the buffer before saving
    (add-hook 'before-save-hook 'tide-format-before-save)

    (add-hook 'typescript-mode-hook #'setup-tide-mode))

Web temlpates and snippets editing.

  (use-package web-mode
    :config
    (add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode))
    (add-hook 'web-mode-hook
              (lambda ()
                (when (string-equal "tsx" (file-name-extension buffer-file-name))
                  (setup-tide-mode))))

    ;; enable typescript - tslint checker
    (flycheck-add-mode 'typescript-tslint 'web-mode))

§ Rust

No surprises here, all set up borrowed from the page on top of the search. Using Rustic, that integrates well with LSP.

  (use-package rust-mode :ensure t)

  (use-package rustic
    :ensure t
    :config
    (setq lsp-eldoc-hook nil)
    (setq lsp-enable-symbol-highlighting nil)
    (setq lsp-signature-auto-activate nil)
    (setq lsp-ui-doc-enable nil)
    ;; (setq lsp-ui-mode-hook nil)
    ;; (setq rustic-compile-rustflags "-C link-arg=-s")
    (setq rustic-format-on-save t))

§ Haskell

Haskell-mode setup according to the tutorial:

  (use-package haskell-mode
    :ensure t
    :defer t
    :hook (haskell-mode . hindent-mode))
    ;;
    ;; Quite slow those ones. No need at this point.
    ;;
    ;; :config
    ;; (let ((my-cabal-path (expand-file-name "~/.cabal/bin")))
    ;;   (setenv "PATH" (concat my-cabal-path path-separator (getenv "PATH")))
    ;;   (add-to-list 'exec-path my-cabal-path))
    ;; :custom (haskell-tags-on-save t))

  (use-package hindent
    :after haskell-mode)  

  (use-package company-ghci
    :after haskell-mode)

§ Formal Proof Systems

No much setup needed for those goodies so far, apart from their compiler installation.

The programming environments are essentially unified by the proof-general.

  (use-package proof-general)

  (use-package company-coq
    :hook (coq-mode . company-coq-mode))

§ Language Server Protocol

A great alternative to "conventional" development environments, LSP support bumps programming experience in emacs up to a next level, especially for statically compiled languages.

  (use-package lsp-mode
    :ensure t
    :hook
    (f90-mode . lsp-deferred)
    (fortran-mode . lsp-deferred)
    (c++-mode . lsp-deferred)
    (c-mode . lsp-deferred)
    ;; (lsp-mode . lsp-ui-mode)
    :commands (lsp lsp-deferred)

    :init
    (setf lsp-clients-clangd-executable "/usr/bin/clangd")
    
    :custom
    (lsp-enable-snippet t)
    (lsp-auto-guess-root nil)

    ;; NOTE: eldoc clogging fortls trouble, switched off:
    (lsp-eldoc-enable-hover nil)

    (lsp-eldoc-enable-signature-help nil)
    (lsp-eldoc-prefer-signature-help t)
    (lsp-signature-render-all nil)
    (lsp-eldoc-render-all nil)

    (lsp-clangd-binary-path "/usr/bin/clangd")
    (lsp-clients-clangd-library-directories )
    (setf flycheck-clang-include-path '("/usr/include"))

    (lsp-clients-fortls-args '("--lowercase_intrinsics"
                               "--use_signature_help"
                               "--variable_hover"
                               "--hover_signature"))

    (lsp-rust-analyzer-cargo-watch-command "clippy")
    (lsp-rust-analyzer-server-display-inlay-hints t)

    :config
    (use-package lsp-ui
      :ensure t
      :config
      (set-face-attribute 'lsp-ui-doc-background  nil :height 140 :family "Iosevka")
      :custom
      ;; lsp-ui-doc
      (lsp-ui-doc-enable t)
      (lsp-ui-doc-header t)
      (lsp-ui-doc-include-signature t)
      (lsp-ui-doc-position 'top) ;; top, bottom, or at-point
      (lsp-ui-doc-max-width 120)
      (lsp-ui-doc-max-height 30)
      (lsp-ui-doc-use-childframe t)
      (lsp-ui-doc-use-webkit nil)

      ;; lsp-ui-sideline
      (lsp-ui-sideline-enable nil)

      ;; lsp-ui-peek
      (lsp-ui-peek-enable t)
      (lsp-ui-peek-peek-height 25)
      (lsp-ui-peek-list-width 35)
      (lsp-ui-peek-fontify 'on-demand)) ;; never, on-demand, or always

    (remove-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake)
    (add-hook 'lsp-mode-hook 'yas-minor-mode)

    (add-to-list 'lsp-language-id-configuration '(fortran-mode . "fortran"))
    (add-to-list 'lsp-language-id-configuration '(f90-mode . "fortran"))
    (add-to-list 'lsp-language-id-configuration '(c-mode . "c"))) 

Clang-format for linting C++ code.

  (use-package clang-format
    :config
    (load "/usr/share/emacs/site-lisp/clang-format/clang-format.el"))

§ Org-mode Setup

§ Babel Imports

Asynchronous execution of orgmode source blocks:

  (use-package ob-async :ensure t)

§ Org Itself

At start, 'org-agenda-files tracks the root of the Roam repository. #'my-init/extend-org-agenda allows me to add and browse current directory/ project.

  (use-package org :ensure org-contrib
    :init
    (setq org-agenda-files (list my-init/org-roam-dir))
    (defun my-init/extend-org-agenda ()
        "Extend Org agenda with files in the current directory."
        (interactive)
        (let ((dir (my-misc/my-current-dir)))
          (dolist (file
                   (if (y-or-n-p "Recursive?")
                       (directory-files-recursively dir "\\.org$")
                     (directory-files dir t "\\.org$")))
            (push file org-agenda-files))))  

    :config
    (setq org-format-latex-options
          (plist-put org-format-latex-options :scale 2.0))

    (org-babel-do-load-languages
     'org-babel-load-languages
     '((org . t)
       (emacs-lisp . t)
       (lisp . t)
       (scheme . t)
       (shell . t)
       (awk . t)
       (gnuplot . t)
       (python . t)
       (fortran . t)
       (ditaa . t)))

    :custom
    (org-image-actual-width nil)
    (org-babel-lisp-eval-fn #'sly-eval)
    (org-confirm-babel-evaluate nil)
    (org-startup-indented t)
    (org-hide-leading-stars nil)
    (org-enforce-todo-dependencies t)
    (org-agenda-todo-list-sublevels nil)
    (org-cycle-separator-lines -1)
    (org-log-repeat nil)
    ;; (org-extend-today-until 3)
    (org-agenda-span 1)
    (org-blank-before-new-entry '((heading . t) (plain-list-item . nil)))
    (org-src-tab-acts-natively nil)
    (org-ditaa-jar-path "~/bin/ditaa/ditaa-0.11.0-standalone.jar")
    (org-capture-templates
     '(("b" "Backlog" item (file+olp+datetree my-init/org-backlog-file "Backlog | Incoming")
        "- %i")
       ("t" "Todo" entry (file+headline my-init/org-agenda-file "Agenda")
        "* TODO  %?\n  %i\n  %a")
       ("p" "Plain at point" plain
        (file+function buffer-name (lambda () (goto-char (point))))
        "%i"))))

§ Exports from Org

Additional dispatches for:

  • ReStructured_Text

Also, path to reveal.js.

  (use-package ox-rst)

  (use-package ox-reveal
    :custom
    (org-reveal-root
     (format "file://%s/talks/_org_reveal/reveal.js"
             (file-truename my-init/grimoire-dir))))

§ Orgmode Tweaks

Decorating outlines with Org-Bullets.

The sample bullets' list:

  • default: ◉ ○ ✸ ✿

  • large: ♥ ● ◇ ✚ ✜ ☯ ◆ ♠ ♣ ♦ ☢ ❀ ◆ ◖ ▶

  • small: ► • ★ ▸

  • ellipsis: ▼ ↴ ⬎ ⤷ … ⋱

   (use-package org-bullets
     :custom
     (org-bullets-bullet-list '("◉"))
     (org-ellipsis "⋱")
     :hook (org-mode . org-bullets-mode))

Auto-tangling feature, quite useful IMO when authoring sources within Org:

   (use-package org-auto-tangle
     :defer t
     :init (setf org-auto-tangle-default t)
     :hook (org-mode . org-auto-tangle-mode))

§ Org Extensions

§ Edraw

Editing diagrams within Org-mode.

  (use-package edraw
    :quelpa (edraw :fetcher github :repo "misohena/el-easydraw")
    :config (use-package edraw-org :after org))

§ Org-Remark

Highlights and note-taking for texts, including eww: pages and nov EPUBs.

  (use-package org-remark
    :after org
    :ensure t
    :bind (("C-c m m" . #'org-remark-mark)
           ("C-c m o" . #'org-remark-open)
           ("C-c m ]" . #'org-remark-view-next)
           ("C-c m [" . #'org-remark-view-prev)
           ("C-c m r" . #'org-remark-remove)
           ("C-c m d" . #'org-remark-delete))
    :custom
    (org-remark-notes-file-name
     my-init/org-remark-notes-file)
    :config
    (org-remark-global-tracking-mode +1)
    (with-eval-after-load 'eww
      (org-remark-eww-mode +1))
    (with-eval-after-load 'nov
      (org-remark-nov-mode +1))
    (with-eval-after-load 'info
      (org-remark-info-mode +1)))

§ Org-Present

Presenting inside Emacs buffers.

hide-mode-line is recommended for full immersion, but worked unstable for me.

  (use-package org-present
    :ensure t 
    :hook (org-present-mode . hide-mode-line-mode)
    :bind (("s-." . org-present-next)
           ("s-," . org-present-prev)))

§ Org-Books

Simple catalogization tool. It's registry is part of my digital garden.

  (use-package org-books
    :custom
    (org-books-file
     (file-truename
      (format "%s/books_revised.org"
              my-init/org-roam-dir))))

§ Org-Download

Image drag-and-drop for Org-mode.

  (use-package org-download
    :ensure t
    :defer t
    :after org
    :init
    (with-eval-after-load 'org (org-download-enable))
    :custom
    (org-download-screenshot-method "mate-screenshot -a")
    (org-download-image-org-width 600)
    ;; :bind
    ;; (:map org-mode-map
    ;;       (("s-Y" . org-download-screenshot)
    ;;        ("s-y" . org-download-yank)))
    :config
    (setq-default org-download-image-dir my-init/org-download-dir))

§ Org-Ref

Citations management in Org.

After having adopted Org-Roam, the notes files are created per-paper and become Roam nodes.

  (use-package org-ref
    ;; :after (org ivy-bibtex)
    :after (org helm-bibtex)

    :general (:keymaps 'org-mode-map "C-c ]" 'org-ref-insert-link)

    :custom
    (bibtex-completion-bibliography '("~/Refs/fusion.bib"
                                      "~/Refs/phd.bib"
                                      "~/Refs/cs.bib"
                                      "~/Refs/math.bib"
                                      "~/Refs/web3.bib"
                                      "~/Refs/formal.bib"))
    (bibtex-completion-library-path '("~/Refs/pdfs/"))
    (bibtex-completion-notes-path
     (file-truename (format "%s/research/paper-notes/" my-init/org-roam-dir)))
    (bibtex-completion-additional-search-fields '(keywords))
    (bibtex-completion-notes-template-multiple-files
     "#+category: research\n#+title: ${title} (${year})\n#+auto_tangle: nil\n#+filetags: research paper_notes ${=type=}\n
    ,,*${author-or-editor}*\n\nSee [[cite:&${=key=}]]\n")
    (bibtex-completion-pdf-open-function (lambda (fpath)
                                           (call-process "atril" nil 0 nil fpath)))
    ;; autokey formatting:
    (bibtex-autokey-year-length 4)
    (bibtex-autokey-name-year-separator "-")
    (bibtex-autokey-year-title-separator "-")
    (bibtex-autokey-titleword-separator "-")
    (bibtex-autokey-titlewords 2)
    (bibtex-autokey-titlewords-stretch 1)
    (bibtex-autokey-titleword-length 5)
    ;; Ivy backend:
    (org-ref-insert-link-function 'org-ref-insert-link-hydra/body)
    (org-ref-insert-cite-function 'org-ref-cite-insert-ivy)
    (org-ref-insert-label-function 'org-ref-insert-label-link)
    (org-ref-insert-ref-function 'org-ref-insert-ref-link)
    (org-ref-cite-onclick-function (lambda (_) (org-ref-citation-hydra/body)))

    :init (require 'org-ref-ivy))

org-ref-prettify formats org-ref links

  (use-package org-ref-prettify
    :defer t
    :hook (org-mode . org-ref-prettify-mode))

§ Org-Roam

Provides the stuff vanilla Org is lacking to become one space killer notetaking extension for emacs. Namely, database that indexes the notes in Org-Roam repository, and a handy elisp structure defined for the Roam Nodes representation.

Forms the foundation of my digital garden.

  (use-package org-roam
    :ensure t
    :custom
    (org-roam-directory my-init/org-roam-dir)
    (org-roam-db-location
     (file-truename (format "%s/org/org-roam.db" my-init/grimoire-dir)))

    ;; Daily note taking
    (org-roam-dailies-directory "daily/")
    (org-roam-dailies-capture-templates
     '(("d" "default" entry
        "* %?"
        :target (file+head "%<%Y-%m-%d>.org"
                           "#+title: %<%Y-%m-%d>\n"))))

    ;; Generic capture templates. Mind the subdirs in
    (org-roam-capture-templates
     '(("d" "default" plain "%?"
        :target (file+head "${slug}.org"
                           "#+title: ${title}\n#+auto_tangle: nil\n")
        :unnarrowed t)
       ("l" "Lit-Notes" plain "%?"
        :target (file+head "literature/${slug}.org"
                           "#+category: books\n#+title: ${title}\n#+auto_tangle: nil\n#+filetags: read\n")
        :unnarrowed t)
       ("m" "Media" plain "%?"
        :target (file+head "media/${slug}.org"
                           "#+category: media\n#+title: ${title}\n#+auto_tangle: nil\n#+filetags: media\n")
        :unnarrowed t)
       ("k" "Kata-Log" plain "%?"
        :target (file+head "kata-log/${slug}.org"
                           "#+title: ${title}\n#+auto_tangle: nil\n#+filetags: kata\n")
        :unnarrowed t)
       ("p" "Projects" plain "%?"
        :target (file+head "projects/${slug}.org"
                           "#+category: projects\n#+title: ${title}\n#+auto_tangle: nil\n#+filetags: project\n")
        :unnarrowed t)
       ("g" "Gaming" plain "%?"
        :target (file+head "gaming/${slug}.org"
                           "#+category: prpgs\n#+title: ${title}\n#+auto_tangle: nil\n#+filetags: gaming\n")
        :unnarrowed t)
       ("a" "Art" plain "%?"
        :target (file+head "art/${slug}.org"
                           "#+title: ${title}\n#+auto_tangle: nil\n#+filetags: art\n")
        :unnarrowed t)
       ("r" "Research" plain "%?"
        :target (file+head "research/${slug}.org"
                           "#+category: research\n#+title: ${title}\n#+auto_tangle: nil\n#+filetags: research\n")
        :unnarrowed t)
       ("t" "Engineering & Tech" plain "%?"
        :target (file+head "tech/${slug}.org"
                           "#+title: ${title}\n#+auto_tangle: nil\n#+filetags: tech\n")
        :unnarrowed t)
       ("u" "Setup & Utilities" plain "%?"
        :target (file+head "setup-utils/${slug}.org"
                           "#+title: ${title}\n#+auto_tangle: nil\n#+filetags: setup\n")
        :unnarrowed t)
       ("w" "Work Files & Specific" plain "%?"
        :target (file+head "work/${slug}.org"
                           "#+title: ${title}\n#+auto_tangle: nil\n#+filetags: work\n")
        :unnarrowed t)))

    :config
    (load (expand-file-name "~/.emacs.d/lisp-dev/my-elisp-collection/my-org.el"))
    (require 'my-org)
    (add-to-list 'display-buffer-alist
                 '("\\*org-roam\\*"
                   (display-buffer-in-direction)
                   (direction . right)
                   (window-width . 0.26)
                   (window-height . fit-window-to-buffer)))
    (org-roam-db-autosync-mode)
    :general
    (my-leader-def
      :states '(normal visual emacs)
      "ar"  '(:ignore t :which-key "Org-Roam")
      "arr" 'org-roam-node-find
      "arh" 'my-org/roamify-header
      "ari" 'org-roam-node-insert
      "arb" 'org-roam-buffer-toggle
      "arc" 'org-roam-capture
      "ard" 'org-roam-dailies-goto-date
      "ar." 'org-roam-dailies-goto-today))
§ Deft

Horizontal text-search throughout Roam repo.

  (use-package deft
    :after org
    :bind ("C-c n d" . deft)
    :custom
    (deft-recursive t)
    (deft-use-filter-string-for-filename t)
    (deft-default-extension "org")
    (deft-directory org-roam-directory))
§ Org-Roam-UI

Mindblowing visualization of the Roam nodes relations graph.

  (use-package org-roam-ui
    :config
    (setq org-roam-ui-sync-theme t
          org-roam-ui-follow t
          org-roam-ui-update-on-save t
          org-roam-ui-open-on-start t))

§ Org-AI

AI integration with Org mode to superpower textual tasks.

gptel is very handy since it can be used uniformly in Emacs, not only in org-buffers, as well as in its own buffer.

I also like its transient menu and, most importantly, working through Ollama.ai with local models! With orca-mini I have an ever-ready and free assistant in Org that works on a modest laptop environment.

  (use-package gptel
    :init
    (setq gptel-my-backend
          (gptel-make-ollama
           "Ollama"                       ;Any name of your choosing
           :host "localhost:11434"        ;Where it's running
           :models '("orca-mini:latest"   ;Installed models
                     "mistral:latest"
                     "codellama:latest"
                     "codegemma:latest")
           :stream t))
    :config
    (setq-default gptel-backend gptel-my-backend)
    (setq-default gptel-model "orca-mini:latest")
    (setq-default gptel-default-mode 'org-mode)
    (setq-default gptel-api-key (getenv "OPENAI_TOKEN"))
    :hook (org-mode . gptel-mode))  

Org-AI requires dedicated source block formatting within Org. Not very convenient, however it can generate images, so I keep it too.

  (use-package org-ai
    :ensure t
    :commands (org-ai-mode
               org-ai-global-mode)
    :init
    (add-hook 'org-mode-hook #'org-ai-mode) ; enable org-ai in org-mode
    (org-ai-global-mode)        ; installs global keybindings on C-c M-a
    :config
    (setq org-ai-openai-api-token (getenv "OPENAI_TOKEN"))
    (setq org-ai-default-chat-model "gpt-3.5-turbo") 
    (org-ai-install-yasnippets))

Khoj project adds AI-assistance on top of Org-Roam knowledgebase. Looks like the future of smart note-taking.

  (use-package khoj
   :ensure t
   :pin melpa
   :bind ("C-c s" . 'khoj)
   :config (setq khoj-server-is-local t
                 khoj-server-url "http://localhost:42110"
                 khoj-org-directories (list my-init/org-roam-dir)))

§ Applications that Rock

Those packages add up to awesomeness of my Emacs setup being full-scale apps on their own.

Even more - Emacs makes possible to glue them into one-state-interoperable-soup that's oh so tasty...

E.g. I can drag into the org-mode links not only to emails, but also pinpointing telegram threads. Awesome!

§ Translations

Emacs interface to Google Translate.

  (use-package google-translate
    :init (require 'google-translate-smooth-ui)
    :bind ("C-c t" . google-translate-smooth-translate))

§ PDF-Tools

  (use-package pdf-tools
     :pin manual
     :config
     (pdf-tools-install)
     (setq-default pdf-view-display-size 'fit-width)
     (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward)
     :custom
     (pdf-annot-activate-created-annotations t "automatically annotate highlights"))

§ Nov-mode

A major-mode to read e-books within emacs.

  (use-package nov
    :config
    (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)))

§ Decide

For random choices for RPGs and not only.

  (use-package decide)

§ Elfeed

RSS-reader, tweaked to import feed list from Orgmode.

  (use-package elfeed
    :ensure elfeed-org
    :custom
    ;; Entries older than 2 weeks are marked as read
    (elfeed-search-filter "@2-weeks-ago +unread -reddit")
    :config
    ;; FIXME:
    (setq elfeed-db-directory "~/Feeds/elfeed-db")
    (add-hook 'elfeed-new-entry-hook
              (elfeed-make-tagger :before "2 weeks ago"
                                  :remove 'unread))
    (elfeed-org)
    (setq rmh-elfeed-org-files
          (list
           (file-truename (format "%s/feeds.org" my-init/org-roam-dir))
           (file-truename (format "%s/podcasts.org" my-init/org-roam-dir)))))

§ Telega

THE client for telegram. 146% awesome and useful!

Also, an example where guix packages shine: server, client and unofficial contrib extensions all to be installed and kept updated easily with Guix.

  (use-package telega
    :commands (telega)
    :defer t
    :init
    (setq telega-root-show-avatars '(scale rotate90))
    (setq telega-chat-show-avatars '(scale rotate90))
    (setq telega-use-images '(scale rotate90))
    (setq telega-emoji-font-family "Iosevka Extended")
    ;; (setq telega-emoji-use-images t)
    ;; (setq telega-tdlib-max-version "1.8.4")
    (setq telega-server-libs-prefix "~/.guix-profile") ; to use TDLib obtained with Guix
    (setq telega-emoji-use-images nil)                 ; to fix rendering of reactions
    :custom
    (telega-mode-line-mode 1)
    :config (require 'ol-telega)  ; <- can also play with shortened urls
    :general
    (my-leader-def
      :states '(normal visual emacs)
      "at"  'telega))

§ Mu4e

Mu4e is an email client that works as front-end for emails fetched by offlineimap and indexed by mu.

That utility chain at the moment is not present in Guix, and the setup is quite intimate to be publicly exported. So just trust me it's there too. Mu4e.

§ Evil-mode

Vim keystrokes are recorded on the back of my skull, exactly where the nerves start leading towards my fingertips.

Of the vanilla emacs shortcuts I know by heart only a small subset, still navigating over my buffers with evil - vim emulation for emacs. And know that I am not ashamed of it, at all!

  (use-package evil
    :ensure t
    :init (setq evil-want-keybinding nil)
    :config
    (evil-set-undo-system 'undo-tree)
    (evil-mode 1))

evil-collection brings predictable evil behaviour in various modes, e.g. dired and mu4e.

  (use-package evil-collection
    :after evil
    :ensure t
    :diminish t
    :config
    (evil-collection-init))

Binding keys for various keymaps in evil can be done via evil-leader package. I'm not doing that at the moment, but anyways.

Check the docs for description of evil-leader.

  (use-package evil-leader)

A minor mode extension that emulates surround.vim

  (use-package evil-surround
    :ensure t
    :config (global-evil-surround-mode 1))