summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
m---------catppuccin/emacs0
-rw-r--r--emacs-init.el461
-rw-r--r--home-configuration.scm80
4 files changed, 539 insertions, 5 deletions
diff --git a/.gitmodules b/.gitmodules
index acaec0d0..89e8ef65 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -16,3 +16,6 @@
[submodule "catppuccin/polybar"]
path = catppuccin/polybar
url = https://github.com/catppuccin/polybar
+[submodule "catppuccin/emacs"]
+ path = catppuccin/emacs
+ url = https://github.com/catppuccin/emacs
diff --git a/catppuccin/emacs b/catppuccin/emacs
new file mode 160000
+Subproject b4be30de73aa295ab56a20c21dff07fba3dec05
diff --git a/emacs-init.el b/emacs-init.el
new file mode 100644
index 00000000..5b31082e
--- /dev/null
+++ b/emacs-init.el
@@ -0,0 +1,461 @@
+;;; init.el --- Emacs configuration. -*- lexical-binding: t -*-
+;;; Commentary:
+;;; Code:
+
+(defun tw/xdg-emacs-subdir (type name)
+ "Get the name of a subdirectory called NAME under $XDG_<TYPE>_HOME/emacs."
+ (expand-file-name
+ (concat (string-trim-right name "/") "/")
+ (expand-file-name
+ "emacs/" (pcase type
+ ('cache (or (getenv "XDG_CACHE_HOME") "~/.cache/"))
+ ('config (or (getenv "XDG_CONFIG_HOME") "~/.config/"))
+ ('data (or (getenv "XDG_DATA_HOME") "~/.local/share/"))
+ ;; The following two are Guix/GuixSD extensions.
+ ('log (or (getenv "XDG_LOG_HOME") "~/.local/var/log/"))
+ ('state (or (getenv "XDG_STATE_HOME") "~/.local/var/lib/"))
+ (_ (error "Unknown XDG directory type: %S" type))))))
+
+;; Global/built-in Custom settings
+;; Apply these as early as possible so that e.g. the native-comp files go to the right place.
+(mapc (apply-partially #'apply #'customize-set-variable)
+ `((native-comp-async-report-warnings-errors silent "Don't pop up Warnings buffer for native compilation.")
+ (native-compile-target-directory ,(tw/xdg-emacs-subdir 'cache "eln") "Put native-compiled binaries in the cache.")
+ (inhibit-startup-screen t "Don't show the startup screen with help links.")
+ (indent-tabs-mode nil "Always use spaces to indent.")
+ (menu-bar-mode nil "Hide the menu bar globally.")
+ (tool-bar-mode nil "Hide the tool bar globally.")
+ (tooltip-mode nil "Show tooltips in the echo area instead.")
+ (global-hl-line-mode t "Highlight the current line in all buffers.")
+ (column-number-mode t "Show the column number in the statusline.")
+ (backup-directory-alist (("." . ,(tw/xdg-emacs-subdir 'data "backup"))) "Save all backup files in one place to avoid clutter.")
+ (scroll-up-aggressively 0.0 "Don't recenter the window if the point moves off the page.")
+ (scroll-down-aggressively 0.0 "Don't recenter the window if the point moves off the page.")
+ (package-archives nil "Don't fetch packages from the internet; only get them from Guix.")
+ (recentf-max-saved-items 10000 "Save lots of recently-opened files.")))
+
+(defalias 'yes-or-no-p #'y-or-n-p
+ "Always use `y-or-n-p' when asking for confirmation.")
+
+;; Custom modes depending on file names.
+(mapc (apply-partially #'add-to-list 'auto-mode-alist)
+ `((,(rx (or bos "/") "PKGBUILD" eos) . sh-mode)
+ (,(rx ".install" eos) . sh-mode)
+ (,(rx bos "/tmp/neomutt-") . mail-mode)
+ (,(rx "." (1+ anything) "rc" eos) . conf-unix-mode)
+ (,(rx ".gnuplot" eos) . gnuplot-mode)
+ (,(rx ".aurora" eos) . python-mode)))
+
+;; Load settings set through Custom.
+;; (setq custom-file (locate-user-emacs-file "custom.el"))
+;; (when (file-readable-p custom-file)
+;; (load custom-file))
+
+;; `use-package' requirements.
+(require 'package)
+(package-initialize t)
+(eval-when-compile
+ (require 'use-package))
+(use-package diminish) ; for using :diminish later
+(use-package bind-key) ; for using :bind later
+
+;; Look and feel
+(set-face-attribute 'default nil :family "Hermit" :height 100)
+
+(use-package autothemer
+ ;; The "catppuccin" theme is linked to the appropriate variant by guix home.
+ :config (load-theme 'catppuccin-mocha t))
+
+(defun tw/get-catppuccin-color (name)
+ "Get the hex code of the Catppuccin color named NAME."
+ (cl-loop for color in (autothemer--theme-colors autothemer-current-theme)
+ when (string= (autothemer--color-name color) name)
+ return (autothemer--color-value color)))
+
+(custom-set-faces
+ `(cursor ((default :background ,(tw/get-catppuccin-color "rosewater"))) t
+ "Make the cursor \"rosewater\", as recommended by Catppuccin upstream, overriding catppuccin/emacs."))
+
+;; Some packages below have `:commands (...) :demand t'.
+;; We need :commands for the byte-compiler, but we want to load the package immediately.
+
+;; General editor behaviour.
+(use-package ivy
+ :commands (ivy-mode) :demand t
+ :config (ivy-mode +1)
+ :diminish ivy-mode)
+
+(use-package counsel ; extra niceties for `ivy-mode'
+ :after (ivy evil) ; evil for :bind-ing to <leader>
+ :bind (("<leader>SPC" . counsel-M-x) ; <leader><leader> doesn't work
+ ("<leader>fr" . counsel-buffer-or-recentf)
+ :map evil-visual-state-map
+ ("<leader>SPC" . counsel-M-x))
+ :commands (counsel-mode) :demand t
+ :config (counsel-mode +1)
+ :diminish counsel-mode)
+
+(use-package rainbow-mode
+ :after (evil)
+ :bind (("<leader>tR" . rainbow-mode)))
+
+(use-package linum
+ :hook (prog-mode . linum-mode))
+
+(use-package which-key
+ :commands (which-key-mode) :demand t
+ :config (which-key-mode +1)
+ :diminish which-key-mode)
+
+(use-package undo-tree
+ :after (evil) ; for our :bind-ing
+ :bind (("<leader>U" . undo-tree-visualize))
+ :custom
+ (undo-tree-history-directory-alist
+ `(("." . ,(tw/xdg-emacs-subdir 'data "undo-tree-history")))
+ "Store all `undo-tree' history in a single directory, instead of next to the associated file.")
+ :commands (global-undo-tree-mode)
+ :demand t ; this is required so that the :config stanza is actually run asap despite :bind
+ :config (global-undo-tree-mode +1))
+
+;; IDE-like features.
+(use-package vc
+ :after (which-key evil)
+ :init (which-key-add-key-based-replacements
+ "<leader>g" '("vc" . "Version control")
+ "<leader>gM" '("merge" . "Version control merging"))
+ :bind-keymap ("<leader>g" . vc-prefix-map))
+
+(use-package company
+ :hook (prog-mode . company-mode)
+ ;; Use TAB for selecting completions. Config from:
+ ;; https://github.com/company-mode/company-mode/blob/master/company-tng.el
+ :bind (:map company-active-map
+ ([tab] . company-select-next)
+ ([backtab] . company-select-previous))
+ :custom
+ (company-minimum-prefix-length 2 "Start showing completion candidates slightly earlier.")
+ (company-idle-delay (lambda () (if (company-in-string-or-comment) nil 0.3))
+ "Automatically show completions when editing non-comment parts of code.")
+ :diminish company-mode)
+
+(use-package company-quickhelp
+ :after (company autothemer) ; autothemer needed for `tw/get-catppuccin-color'
+ :hook (company-mode . company-quickhelp-mode)
+ :custom
+ (company-quickhelp-delay 0.2 "Automatically show quickhelp for completions.")
+ (company-quickhelp-color-background (tw/get-catppuccin-color "surface0") "Give the quickhelp tooltip a nicer background colour.")
+ (company-quickhelp-color-foreground (tw/get-catppuccin-color "text") "Give the quickhelp tooltip the default text colour."))
+
+(use-package company-posframe
+ :after (company company-quickhelp)
+ :hook (company-mode . company-posframe-mode)
+ :diminish company-posframe-mode)
+
+(use-package flymake
+ :after (evil which-key)
+ :hook (prog-mode . flymake-mode)
+ :init (which-key-add-key-based-replacements
+ "<leader>e" '("errors" . "Flymake"))
+ :bind (("<leader>el" . flymake-show-buffer-diagnostics)
+ ("<leader>ep" . flymake-show-project-diagnostics))
+ :custom
+ (flymake-suppress-zero-counters t "Don't show severity counters that are zero at all."))
+
+(use-package flymake-collection
+ :after (flymake)
+ ;; This needs to be called in `after-init-hook' so that all other
+ ;; packages' `:flymake-hook's are processed before f-c-hook-setup is
+ ;; called. See https://github.com/mohkale/flymake-collection.
+ :hook (after-init . flymake-collection-hook-setup))
+
+;; Language Server Protocol.
+(defun tw/help-is-eldoc (&rest _)
+ "Set up `evil-lookup-func' to display the `eldoc' buffer."
+ (setq-local evil-lookup-func #'eldoc-doc-buffer))
+
+(use-package eglot
+ ;; I have clang (for clangd) and python-lsp-server installed.
+ :hook (python-mode c-mode c++-mode)
+ :custom
+ (eglot-autoshutdown t "Shut down language servers after deleting their last associated buffer.")
+ (eglot-sync-connect 0.1 "Wait for the language server in the background if it takes longer than 100ms.")
+ :config
+ (advice-add 'eglot :after #'tw/help-is-eldoc))
+
+;; Non-LSP language modes.
+(use-package mmm-mode
+ :commands (mmm-mode))
+(use-package ledger-mode
+ :mode (rx ".journal" eos))
+(use-package cmake-mode
+ :mode (rx (or (: (or bos "/") "CMakeLists.txt") ".cmake") eos))
+(use-package puppet-mode
+ :mode (rx ".pp" eos))
+(use-package web-mode
+ :mode (rx ".htm" (? "l") eos))
+(use-package yaml-mode
+ :mode (rx ".y" (? "a") "ml" eos))
+(use-package rec-mode
+ :mode (rx ".rec" eos))
+(use-package hcl-mode
+ :mode (rx "." (or "hcl" "nomad") eos))
+(use-package graphviz-dot-mode
+ :mode (rx ".dot" eos)
+ :custom (graphviz-dot-view-command "xdot %s" "Use xdot for previewing graphviz files."))
+
+(use-package geiser
+ :after (evil)
+ :commands (geiser geiser-eval-buffer geiser-eval-definition geiser-eval-region geiser-eval-last-sexp)
+ :hook (scheme-mode . geiser-autodoc-mode)
+ :config
+ (evil-define-key '(normal visual) scheme-mode-map
+ (kbd "<localleader>i") #'geiser
+ (kbd "<localleader>eb") #'geiser-eval-buffer
+ (kbd "<localleader>ef") #'geiser-eval-definition
+ (kbd "<localleader>er") #'geiser-eval-region
+ (kbd "<localleader>el") #'geiser-eval-last-sexp)
+ :defines scheme-mode-map)
+
+(use-package geiser-racket
+ :after (geiser))
+(use-package geiser-guile
+ :after (geiser))
+
+;; My own custom packages, and stuff that isn't on MELPA.
+;; (use-package actionlint ; TODO: port to flymake
+;; :after (flycheck)
+;; :load-path "include/")
+;; (use-package alidist-mode ; TODO: port to flymake
+;; :after (flycheck mmm-mode)
+;; :mode (rx (or bos "/") "alidist/" (1+ anything) ".sh" eos)
+;; :load-path "include/")
+
+(use-package bemscript-mode
+ :load-path "include/"
+ :mode (rx ".bem" eos))
+
+(use-package ifm-mode
+ :load-path "include/"
+ :mode (rx ".ifm" eos))
+
+(use-package pam-env-mode
+ :load-path "include/"
+ :mode (rx (or bos "/") (or "pam_env.conf" ".pam_environment") eos))
+
+(use-package environmentd-mode
+ :load-path "include/"
+ :mode (rx (or bos "/")
+ (or (: (? "etc/") "environment")
+ (: ".environment.d/" (1+ (not ?\/)) ".conf"))
+ eos))
+
+(use-package org-latex-classes
+ :after (ox-latex)
+ :load-path "include/")
+
+(use-package ob-rec
+ ;; `org-babel' hooks for `rec-mode'
+ :after (org org-babel)
+ :load-path "include/")
+
+(use-package vcard-mode
+ :load-path "include/vcard-mode/"
+ :mode (rx "." (or "vcf" "vcard") eos))
+
+;; Vim keybindings.
+(defun tw/switch-to-other-buffer ()
+ "Switch to the last-used buffer."
+ (switch-to-buffer (other-buffer)))
+
+(defun tw/new-buffer ()
+ "Open a new, empty buffer."
+ (interactive)
+ (switch-to-buffer (generate-new-buffer "untitled")))
+
+(use-package evil
+ :after (which-key)
+ :commands (evil-mode evil-ex-nohighlight)
+ :init (setq evil-want-keybinding nil) ; evil-collection needs this
+ :custom
+ (evil-undo-system 'undo-tree "Use `undo-tree' for evil's undo-redo function.")
+ (evil-want-minibuffer t "Use evil bindings in the minibuffer too.")
+ (evil-want-C-u-scroll t "Scroll on C-u in normal mode, not `universal-argument'.")
+ (evil-want-C-u-delete t "Delete line on C-u in insert mode, not `universal-argument'.")
+ (evil-want-Y-yank-to-eol t "Yank from point to end-of-line on Y.")
+ :config
+ (evil-mode +1)
+ (evil-set-leader '(normal visual) (kbd "SPC")) ; <leader>
+ (evil-set-leader '(normal visual) (kbd "\\") t) ; <localleader>
+ (evil-define-key '(normal insert visual replace) 'global
+ (kbd "C-s") #'save-buffer)
+ ;; Global major-mode-independent keys should be defined here. Major
+ ;; mode-dependent keys (e.g. for launching a REPL) should go under
+ ;; <localleader> instead. Use `use-package' `:bind' for those.
+ (evil-define-key '(normal visual) 'global
+ ;; These keybindings mirror the default Spacemacs ones because I have
+ ;; muscle memory of those.
+ (kbd "<leader>:") #'eval-expression
+ (kbd "<leader>TAB") #'tw/switch-to-other-buffer
+ (kbd "<leader>bb") #'switch-to-buffer
+ (kbd "<leader>bd") #'kill-current-buffer
+ (kbd "<leader>bn") #'tw/new-buffer
+ (kbd "<leader>br") #'revert-buffer-quick
+ (kbd "<leader>bx") #'kill-buffer-and-window
+ (kbd "<leader>ff") #'find-file
+ (kbd "<leader>fs") #'save-buffer
+ (kbd "<leader>h") help-map
+ (kbd "<leader>sc") #'evil-ex-nohighlight
+ (kbd "<leader>tl") #'toggle-truncate-lines
+ (kbd "<leader>u") #'universal-argument
+ (kbd "<leader>w") evil-window-map
+ (kbd "<leader>wd") #'evil-window-delete ; analogous to "<leader>bd"
+ (kbd "<leader>wx") #'kill-buffer-and-window) ; analogous to "<leader>bx"
+ (which-key-add-key-based-replacements
+ ;; Names are a `cons' of a short name and a long name.
+ ;; E.g. for <leader>b, "buffer" is shown under "b" in the "<leader>" menu,
+ ;; while "Buffers" is shown as the title in the "<leader>b" menu.
+ "<leader>b" '("buffer" . "Buffers")
+ "<leader>f" '("file" . "Files")
+ "<leader>h" '("help" . "General help and documentation")
+ "<leader>q" '("quit" . "Finish editing the current buffer in emacsclient")
+ "<leader>s" '("search" . "Search operations and options")
+ "<leader>t" '("toggle" . "Toggles and quick settings")
+ "<leader>w" '("window" . "Windows"))
+ :functions (evil-define-key evil-set-leader
+ evil-define-key* evil-window-delete evil-delay)
+ :defines (evil-visual-state-map))
+
+(use-package evil-collection
+ :after (evil)
+ :commands (evil-collection-init) :demand t
+ :config (evil-collection-init))
+
+(use-package evil-org
+ :after (evil org)
+ :hook (org-mode . evil-org-mode)
+ :config
+ (evil-define-key '(normal visual) org-mode-map
+ (kbd "<localleader>\\") #'org-ctrl-c-ctrl-c
+ (kbd "<localleader>'") #'org-edit-src-code
+ (kbd "<localleader>e") #'org-export-dispatch)
+ (evil-define-key '(normal visual) org-src-mode-map
+ (kbd "<localleader>'") #'org-edit-src-exit
+ (kbd "<localleader>\\") #'org-edit-src-save
+ (kbd "<localleader>a") #'org-edit-src-abort))
+
+(use-package evil-replace-with-register
+ :after (evil)
+ :commands (evil-replace-with-register-install) :demand t
+ :custom ; (evil-replace-with-register-key "gR" "Use the default key.")
+ :config (evil-replace-with-register-install))
+
+(use-package evil-commentary
+ :after (evil)
+ :commands (evil-commentary-mode) :demand t
+ :config (evil-commentary-mode +1))
+
+(use-package evil-expat
+ :after (evil))
+
+(use-package evil-surround
+ :after (evil)
+ :commands (global-evil-surround-mode) :demand t
+ :config (global-evil-surround-mode +1))
+
+(use-package evil-smartparens
+ :after (evil smartparens)
+ :hook (smartparens-enabled-hook . evil-smartparens-mode))
+
+(use-package evil-multiedit
+ ;; See: https://github.com/hlissner/evil-multiedit#usage
+ :commands (evil-multiedit-default-keybinds) :demand t
+ :config (evil-multiedit-default-keybinds))
+
+(use-package evil-args
+ :after (evil)
+ :config
+ ;; Bind evil-args text objects only.
+ ;; See https://github.com/wcsmith/evil-args for more bindings.
+ (define-key evil-inner-text-objects-map "a" 'evil-inner-arg)
+ (define-key evil-outer-text-objects-map "a" 'evil-outer-arg))
+
+(use-package evil-numbers
+ :after (evil)
+ :bind (("<leader>+" . evil-numbers/inc-at-pt)
+ ("<leader>-" . evil-numbers/dec-at-pt)))
+
+(use-package evil-goggles ; visual previews for edit operations
+ :after (evil)
+ :commands (evil-goggles-mode evil-goggles-use-diff-faces) :demand t
+ :config
+ (evil-goggles-mode +1)
+ (evil-goggles-use-diff-faces)
+ :diminish evil-goggles-mode)
+
+(use-package evil-traces ; visual previews for :ex commands
+ :after (evil)
+ :commands (evil-traces-mode evil-traces-use-diff-faces) :demand t
+ :config
+ (evil-traces-mode +1)
+ (evil-traces-use-diff-faces)
+ :diminish evil-traces-mode)
+
+(use-package evil-markdown
+ :after (evil)
+ :hook (markdown-mode . evil-markdown-mode))
+
+;; Lisp features
+(use-package smartparens
+ :commands (smartparens-global-mode) :demand t
+ :config
+ (smartparens-global-mode +1)
+ (defun tw/sp-no-pair-single-quotes-p (id action context)
+ "Return whether ` and ' shouldn't be auto-paired in the current `major-mode'."
+ (memq major-mode (cons 'minibuffer-mode sp-lisp-modes)))
+ ;; Don't auto-pair ` and ' chars in Lisp modes or the minibuffer.
+ ;; Modify the global pair to not apply there.
+ ;; The CLOSE parameter is not used in this case, so it is nil.
+ (sp-pair "`" nil :unless '(tw/sp-no-pair-single-quotes-p))
+ (sp-pair "'" nil :unless '(tw/sp-no-pair-single-quotes-p
+ sp-in-comment-p sp-in-string-p))
+ (sp-local-pair 'lisp-mode "`" "'"
+ :actions '(wrap insert autoskip)
+ :when '(sp-in-comment-p sp-in-string-p))
+ :functions (sp-pair sp-local-pair))
+
+(use-package aggressive-indent
+ :hook (; (scheme-mode . aggressive-indent-mode)
+ ((emacs-lisp-mode common-lisp-mode) . aggressive-indent-mode)))
+
+(defun tw/lisp-evil-setup ()
+ "Set up evil in general `lisp-mode' buffers."
+ (setq-local evil-symbol-word-search t
+ ;; https://github.com/wcsmith/evil-args#customization
+ evil-args-delimiters '(" ")))
+
+(add-hook 'lisp-mode-hook #'tw/lisp-evil-setup)
+
+;; buffer-locally set `evil-lookup-func' (used on K keys) for
+;; languages where something better than man pages is available
+;; (e.g. `describe-symbol' for elisp).
+(defun tw/elisp-lookup-func ()
+ "Show help in `emacs-lisp-mode' buffers."
+ (let ((sym (symbol-at-point)))
+ (if sym (describe-symbol sym)
+ (call-interactively #'describe-symbol))))
+
+(defun tw/emacs-lisp-evil-setup ()
+ "Set up evil in `emacs-lisp-mode' buffers."
+ (setq-local evil-lookup-func #'tw/elisp-lookup-func))
+
+(add-hook 'emacs-lisp-mode-hook #'tw/emacs-lisp-evil-setup)
+
+(evil-define-key '(normal visual) emacs-lisp-mode-map
+ (kbd "<localleader>eb") #'eval-buffer
+ (kbd "<localleader>ef") #'eval-defun
+ (kbd "<localleader>er") #'eval-region
+ (kbd "<localleader>el") #'eval-last-sexp
+ (kbd "<localleader>ep") #'eval-print-last-sexp)
+
+;;; init.el ends here
diff --git a/home-configuration.scm b/home-configuration.scm
index 4c88248b..9e9a3590 100644
--- a/home-configuration.scm
+++ b/home-configuration.scm
@@ -204,6 +204,10 @@ replacement spec (to which `regexp-substitute/global' is applied)."
,(local-file #.(string-append "catppuccin/dunst/src/"
catppuccin-theme-variant ".conf")
"dunst-theme.conf"))
+ ("emacs/init.el" ,(local-file "emacs-init.el"))
+ (#.(string-append "emacs/catppuccin-" catppuccin-theme-variant "-theme.el")
+ ,(local-file #.(string-append "catppuccin/emacs/catppuccin-"
+ catppuccin-theme-variant "-theme.el")))
("gtk-2.0/gtkrc" ,(local-file "gtk2.ini"))
("gtk-3.0/settings.ini" ,(local-file "gtk3.ini"))
("i3/config" ,(local-file "i3.conf"))
@@ -338,12 +342,78 @@ replacement spec (to which `regexp-substitute/global' is applied)."
,@(specifications->packages gui-packages)
,@(specifications->packages
'(;; CLI tools
- "adb" "dos2unix" "file" "fzf" "git" "graphviz" "imagemagick" "jq"
- "lesspipe" "nvme-cli" "openssh" "powertop" "pulsemixer" "pv"
- "python" "rsync" "sbcl" "smartmontools" "source-highlight"
- "tk" "tmux" "tree" "xxd" "zip" "unzip"
+ "adb" "dos2unix" "file" "fzf" "git" "graphviz" "hledger"
+ "imagemagick" "jq" "lesspipe" "nvme-cli" "openssh" "powertop"
+ "pulsemixer" "pv" "python" "rsync" "sbcl" "smartmontools"
+ "source-highlight" "tk" "tmux" "tree" "xxd" "zip" "unzip"
+
+ ;; Language servers
+ "clang" ; for clangd
+ "python-lsp-server"
+ ;; Supported OotB by eglot, but not packaged by guix:
+ ;; https://github.com/mads-hartmann/bash-language-server
+ ;; https://github.com/regen100/cmake-language-server
+ ;; https://github.com/hrsh7th/vscode-langservers-extracted ; {html,css,json}-languageserver
+ ;; https://github.com/golang/tools/tree/master/gopls ; maybe?
+ ;; https://github.com/artempyanykh/marksman ; Markdown
+ ;; https://github.com/jeapostrophe/racket-langserver
+ ;; https://github.com/astoff/digestif ; (La)TeX
+ ;; https://github.com/redhat-developer/yaml-language-server
+ ;; Needs eglot config + not packaged (from lsp-mode):
+ ;; https://github.com/graphql/graphiql/tree/main/packages/graphql-language-service-cli#readme
+ ;; https://github.com/haskell/haskell-language-server / https://github.com/haskell/ghcide
+ ;; https://github.com/eclipse/lemminx
+
;; Emacs
- "emacs" "emacs-use-package" "emacs-editorconfig" ; TODO: set up EditorConfig
+ "emacs"
+ "emacs-use-package"
+ "emacs-eglot"
+ "emacs-counsel"
+ "emacs-ivy" "emacs-ivy-posframe"
+ "emacs-company" "emacs-company-quickhelp" "emacs-company-posframe"
+ "emacs-autothemer" ; for catppuccin/emacs
+ "emacs-undo-tree"
+ "emacs-aggressive-indent"
+ "emacs-which-key"
+ "emacs-smart-mode-line"
+ "emacs-diminish"
+ "emacs-rainbow-mode"
+ "emacs-guix"
+ ;; TODO: "emacs-editorconfig" "emacs-sly" "emacs-sly-macrostep"
+ "emacs-org" ; "emacs-org-modern" theme?
+
+ "emacs-evil"
+ "emacs-evil-collection"
+ "emacs-evil-expat" ; for :reverse, :remove, :rename, :colo, :g*, ... ex commands
+ "emacs-evil-surround"
+ ;; "emacs-evil-owl" ; tests failing
+ "emacs-evil-args"
+ "emacs-evil-smartparens"
+ "emacs-evil-numbers"
+ "emacs-evil-multiedit"
+ "emacs-evil-goggles"
+ "emacs-evil-traces"
+ "emacs-evil-commentary"
+ "emacs-evil-replace-with-register"
+ "emacs-evil-org"
+ "emacs-evil-markdown"
+ "emacs-evil-tex"
+ "emacs-evil-text-object-python"
+
+ "emacs-geiser" "emacs-geiser-racket" "emacs-geiser-guile"
+ "emacs-ac-geiser" "emacs-macrostep-geiser"
+ "emacs-ledger-mode" ; "emacs-hledger-mode"
+ "emacs-flymake-collection" ; "emacs-flymake-flycheck" ; if needed
+ "emacs-cmake-mode"
+ "emacs-graphviz-dot-mode"
+ "emacs-hcl-mode"
+ "emacs-mmm-mode"
+ "emacs-puppet-mode"
+ "emacs-web-mode"
+ "emacs-rec-mode"
+ "emacs-yaml-mode"
+
+ "shellcheck"
;; Shell
"zsh" "zsh-autosuggestions" "zsh-syntax-highlighting" "zsh-autopair"
;; Ranger can do code highlighting using python-pygments and