§ 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-attach-id-dir
is the location of files linked to Org via Org-Attach.my-init/org-agenda-file
is the general Org Agenda taskdumpsterdrawer.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
no blinking cursor;
no visible menus;
modus themes (prefer built-in);
85% transparency level;
custom cursor colors for dark and light theme.
NOTE: at emacsclient
start up the cursor appears dark-grey
regardless. The advice e.g. here apparently don't help.
;;FIXME: variables for colors (use-package my-appearance :init (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))) (defun my-init/set-cursor-color-based-on-theme () (interactive) (cond ;; Add cases for specific themes ((string-equal (car custom-enabled-themes) "modus-vivendi") (set-cursor-color "LightSkyBlue")) ((string-equal (car custom-enabled-themes) "modus-operandi") (set-cursor-color "MediumSlateBlue")) ;; Default fallback color if no match (t (set-cursor-color "LightSkyBlue")))) (defun my-init/after-frame-creation (frame) (with-selected-frame frame (my-init/set-cursor-color-based-on-theme))) :hook ((load-theme . my-init/set-cursor-color-based-on-theme) (modus-themes-post-load . my-init/set-cursor-color-based-on-theme) (after-make-frame-functions . my-init/after-frame-creation)))
§ 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. I once've been using
its alternative, Moody
, but it's less convenient.
(use-package mood-line :ensure t :config (mood-line-mode))
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))))
Pulsate-highlight the cursor line on window switching actions:
(use-package pulsar :ensure t :custom (pulsar-pulse t) :hook (after-init . pulsar-global-mode) (next-error . pulsar-pulse-line) :config (add-to-list 'pulsar-pulse-functions 'ace-window) (add-to-list 'pulsar-pulse-functions 'evil-window-next) (add-to-list 'pulsar-pulse-functions 'flycheck-next-error) (add-to-list 'pulsar-pulse-functions 'flyspell-goto-next-error) (add-to-list 'pulsar-pulse-functions 'recenter-top-bottom))
§ 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 "bc" 'my-init/set-cursor-color-based-on-theme "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")))
§ 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) (projectile-enable-caching t) :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
§ 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"))
§ 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))
§ Tree-Sitter & Eglot
§ Treesit + Combobulate
Incorporation of the tree-sitter
library in Emacs made it possible
to enable Structured Navigation and Editing of code in various
programming modes via packages like Combobulate.
At the moment when I'm reviewing my setup, the grammars for those
languages in which this functionality is desired, should be made
discoverable by the treesit
package. I'm installing a bunch of them
with Guix; more are available in remote git repositories.
(use-package treesit :demand t :init (push '(css-mode . css-ts-mode) major-mode-remap-alist) (push '(sh-mode . bash-ts-mode) major-mode-remap-alist) (push '(python-mode . python-ts-mode) major-mode-remap-alist) (push '(javascript-mode . js-ts-mode) major-mode-remap-alist) (push '(js-json-mode . json-ts-mode) major-mode-remap-alist) (push '(typescript-mode . typescript-ts-mode) major-mode-remap-alist) (push '(c-mode . c-ts-mode) major-mode-remap-alist) (push '(c++-mode . c++-ts-mode) major-mode-remap-alist) (setq treesit-extra-load-path `(,(format "%s/.guix-profile/lib/tree-sitter" (getenv "HOME")))))
(use-package combobulate :hook ((prog-mode . combobulate-mode)))
§ Eglot for Language Server Protocol configuration
I've switched from lsp-mode
to eglot
since the latter is built-in,
easier configurable and interplays better with standard Emacs
features.
Following my favorite style of toolbox settings - the less it blinks
and the faster it works the better - I switch off unnecessary
capabilities like :documentHighlightProvider
and json messages
buffer. That gives me an okay-ish performance with desired code
introspection behavior. Suits me for the time being.
(use-package eglot :ensure t :defer t :general (my-leader-def ;; FIXME: activate these shortcuts only for eglot-mode :states '(normal visual emacs) ;; "l" '(:keymap ;; eglot-mode-map ;; :package eglot ;; :which-key "Language Commands") "l" '(:ignore t :which-key "Language Commands") ;; "lk" #'eldoc-box-help-at-point "lm" #'imenu "ld" #'eldoc "lt" #'eglot-find-typeDefinition "lD" #'eglot-find-declaration "li" #'eglot-find-implementation "lr" #'eglot-rename "lf" #'eglot-format "lF" #'eglot-format-buffer "lR" #'eglot-reconnect) :hook ((f90-mode fortran-mode c++-mode c-mode python-ts-mode) . eglot-ensure) (python-ts-mode . flyspell-prog-mode) (python-ts-mode . superword-mode) (python-ts-mode . hs-minor-mode) (python-ts-mode . (lambda () (set-fill-column 88))) (eglot-managed-mode . (lambda () (flymake-mode 1) (yas-minor-mode 1))) :init ;; Language server configuration (setq eglot-server-programs '((f90-mode . ("fortls" "--lowercase_intrinsics" "--use_signature_help" "--variable_hover" "--hover_signature")) (fortran-mode . ("fortls" "--lowercase_intrinsics" "--use_signature_help" "--variable_hover" "--hover_signature")) (c++-mode . ("/usr/bin/clangd")) (c-mode . ("/usr/bin/clangd")) (python-ts-mode . ("pylsp")))) :custom ;; General settings (eldoc-idle-delay 0.75) ; Delay for eldoc to avoid performance hits (company-idle-delay 0.75) ; Delay for company completion (flymake-no-changes-timeout 0.5) ; Reduce timeout for diagnostics (eglot-events-buffer-size 0) ; Disable events buffer (eglot-autoshutdown t) ; Automatically shut down servers when buffer is closed (eglot-ignored-server-capabilities '(:documentHighlightProvider :codeLensProvider)) ; Skip unnecessary capabilities (eldoc-echo-area-use-multiline-p nil) ; Prevent eldoc from resizing echo area ;; Python-specific configuration (eglot-workspace-configuration '((:pylsp . (:configurationSources ["flake8"] :plugins (:pycodestyle (:enabled :json-false) :mccabe (:enabled :json-false) :pyflakes (:enabled :json-false) :flake8 (:enabled :json-false :maxLineLength 88) :ruff (:enabled t :lineLength 88) :pydocstyle (:enabled t :convention "numpy") :yapf (:enabled :json-false) :autopep8 (:enabled :json-false) :black (:enabled t :line_length 88 :cache_config t)))))))
§ 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-attach-store-link-p 'file) (org-attach-id-dir my-init/org-attach-id-dir) (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-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))
§ EAT: Emulate a Terminal in Emacs
(use-package eat :ensure t :hook (eshell-load . eat-eshell-mode) :general (my-leader-def :states '(normal visual emacs) "ast" 'eat))
§ 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 (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))