#+TITLE: My Ever Changing Literate Emacs Configuration #+AUTHOR: xulfer #+PROPERTY: header-args :tangle init.el :noweb yes :exports code # For PDF export allow line wrapping. #+LATEX_HEADER: \usepackage{listings} #+LATEX_HEADER: \lstset{breaklines=true, breakatwhitespace=true, basicstyle=\ttfamily\footnotesize, columns=fullflexible} #+begin_src emacs-lisp :exports none :tangle no ;; This asks for a file which it uses to store the processed org ;; data with the includes into. It can be anything and can safely ;; be deleted afterwards. I think README.org is a good file to ;; pick if using a repository. (defun tangle-literate-config () "Tangle config files with proper include handling." (interactive) (let ((org-confirm-babel-evaluate nil)) ;; Create a temporary buffer with expanded includes (with-temp-buffer (insert-file-contents "config.org") (org-mode) ;; This expands all #+INCLUDE directives (org-export-expand-include-keyword) ;; Now tangle from this buffer which has everything in one place (org-babel-tangle nil "init.el")) (message "Configuration tangled!"))) #+end_src #+BEGIN_SRC emacs-lisp :exports none ;;; init.el -*- lexical-binding: t; -*- ;;; Code: #+END_SRC #+begin_src emacs-lisp :tangle early-init.el :exports none ;;; early-init.el -*- lexical-binding: t; -*- ;;; Code: #+end_src * Quick Look [[./img/preview.png]] Just the usual flex of doing as little editing as possible in a screenshot. * Motivation Over a surprisingly short amount of time my emacs configuration has become quite a mess. Almost every visit to it requiring some digging to get to the relevant configuration. So as a result I've decided to make a literate configuration. Mostly for my own mental house keeping. However, if some poor soul reads this and finds it useful, then that's a bonus. ** Inspirations, and sometimes outright copy/paste sources - [[https://github.com/progfolio/.emacs.d][Progfolio's Config]] * Initial Bits and Bobs Before anything else the appearance, and some performance settings need to be tweaked as they can cause issues if done mid-start. ** Initial setup The LSP packages perform better with plists so an environment variable needs to be set to inform them that this is intended. I've also removed default package handling as I intend to use another package manager. Lastly I suppress some compilation warnings. #+begin_src emacs-lisp :tangle early-init.el (setq package-enable-at-startup nil) (setq inhibit-default-init nil) (setq native-comp-async-report-warnings-errors nil) (setenv "LSP_USE_PLISTS" "true") (setq lsp-use-plists t) #+end_src ** Appearance I like a minimal look, so I disable menu bars, tool bars, all the bars. I have Emacs loading as a blank slate with only the scratch buffer open. #+begin_src emacs-lisp :tangle early-init.el (defvar default-file-name-handler-alist file-name-handler-alist) (setq file-name-handler-alist nil) (push '(menu-bar-lines . 0) default-frame-alist) (push '(tool-bar-lines . 0) default-frame-alist) (push '(vertical-scroll-bars) default-frame-alist) (setq server-client-instructions nil) (when (and (fboundp 'startup-redirect-eln-cache) (fboundp 'native-comp-available-p) (native-comp-available-p)) (startup-redirect-eln-cache (convert-standard-filename (expand-file-name "var/eln-cache/" user-emacs-directory)))) (setq frame-inhibit-implied-resize t) (advice-add #'x-apply-session-resources :override #'ignore) (setq desktop-restore-forces-onscreen nil) (setq ring-bell-function #'ignore inhibit-startup-screen t) (push '(font . "Victor Mono-13") default-frame-alist) (set-face-font 'default "Victor Mono-13") (set-face-font 'variable-pitch "Victor Mono-13") (copy-face 'default 'fixed-pitch) (provide 'early-init) ;;; early-init.el ends here ;; Local Variables: ;; no-byte-compile: t ;; no-native-compile: t ;; no-update-autoloads: t ;; End: #+end_src * Package Management I am using [[https://github.com/progfolio/elpaca][Elpaca]] as my package manager. I've found it to be quite quick, and easy to use. #+name: elpaca-boilerplate #+begin_src emacs-lisp :exports none :tangle no (defvar elpaca-installer-version 0.11) (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :depth 1 :inherit ignore :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package))) (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (add-to-list 'load-path (if (file-exists-p build) build repo)) (unless (file-exists-p repo) (make-directory repo t) (when (<= emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) ((zerop (apply #'call-process `("git" nil ,buffer t "clone" ,@(when-let* ((depth (plist-get order :depth))) (list (format "--depth=%d" depth) "--no-single-branch")) ,(plist-get order :repo) ,repo)))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory \".\" 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (let ((load-source-file-function nil)) (load "./elpaca-autoloads")))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca `(,@elpaca-order)) (if debug-on-error (setq use-package-verbose t use-package-expand-minimally nil use-package-compute-statistics t) (setq use-package-verbose nil use-package-expand-minimally t)) #+end_src Elpaca supports =use-package= so hook that up, and add a =use-feature= macro that adds a similar construct for configuring already loaded emacs packages and features. #+begin_src emacs-lisp <> (defmacro use-feature (name &rest args) "Like `use-package' but accounting for asynchronous installation. NAME and ARGS are in `use-package'." (declare (indent defun)) `(use-package ,name :ensure nil ,@args)) (elpaca elpaca-use-package (require 'elpaca-use-package) (elpaca-use-package-mode) (setq use-package-always-ensure t)) #+end_src #+INCLUDE: "config/editing.org" :minlevel 1 #+INCLUDE: "config/gc.org" :minlevel 1 #+INCLUDE: "config/tidy.org" :minlevel 1 #+INCLUDE: "config/auth.org" :minlevel 1 #+INCLUDE: "config/profiling.org" :minlevel 1 #+INCLUDE: "config/general.org" :minlevel 1 #+INCLUDE: "config/formatting.org" :minlevel 1 #+INCLUDE: "config/documentation.org" :minlevel 1 #+INCLUDE: "config/social.org" :minlevel 1 #+INCLUDE: "config/modal.org" :minlevel 1 #+INCLUDE: "config/qol.org" :minlevel 1 #+INCLUDE: "config/bufferlo.org" :minlevel 1 #+INCLUDE: "config/error.org" :minlevel 1 ** Flycheck I've found flycheck to be an excellent checker. Capable of interacting with many backends at once. Be they linters, or LSPs. #+begin_src emacs-lisp (use-package flycheck :ensure t :init (global-flycheck-mode)) #+end_src Of course it's always useful to have a debugger handy. #+begin_src emacs-lisp (use-package dap-mode :defer t) #+end_src ======= #+INCLUDE: "config/error.org" :minlevel 1 >>>>>>> 7a6516d (Moved error section into its own file.) * Modern Completion Stack I'm using modern to mean current, and as the colloquial usage given by the community at large. At least based on my observations anyway. Most of these serve to bolster the existing facilities of emacs rather than replace them. ** Prescient [[https://github.com/radian-software/prescient.el][Prescient]] provides sorting for completion candidates; So recently used, and frequent selections come first. #+begin_src emacs-lisp (use-package prescient :defer t :config (prescient-persist-mode)) (use-package corfu-prescient :after (corfu prescient) :config (corfu-prescient-mode)) (use-package vertico-prescient :after (prescient vertico)) #+end_src ** Corfu [[https://github.com/minad/corfu][Corfu]] provides completion within buffers from various sources. Though it doesn't provide much in the way of sources itself. It works in conjunction with the other packages in this section to provide it with candidates. #+begin_src emacs-lisp (use-package corfu :custom (corfu-auto t) ;; Enable auto completion (corfu-preselect 'directory) ;; Select the first candidate, except for directories :init (global-corfu-mode) (corfu-popupinfo-mode) ;; Show docs next to candidates. :config ;; Free the RET key for less intrusive behavior. ;; Option 1: Unbind RET completely ;; (keymap-unset corfu-map "RET") ;; Option 2: Use RET only in shell modes (keymap-set corfu-map "RET" `( menu-item "" nil :filter ,(lambda (&optional _) (and (derived-mode-p 'eshell-mode 'comint-mode) #'corfu-send))))) #+end_src ** Cape The [[https://github.com/minad/cape][Cape]] package (Completion At Point Extensions) provides access to [[https://github.com/minad/corfu][Corfu]] to various backends. Things like file completions and simple buffer completion are examples of good backends to add here. Other backends are listed [[https://github.com/minad/cape#available-capfs][here]]. #+begin_src emacs-lisp (use-package cape :bind ("M-" . cape-prefix-map) :init (add-hook 'completion-at-point-functions #'cape-dabbrev) (add-hook 'completion-at-point-functions #'cape-file) (add-hook 'completion-at-point-functions #'cape-elisp-block)) #+end_src ** Orderless This provides numerous flexible methods for matching completion candidates. Rather than just matching strings exactly it can also match portions, or a custom regular expression, and more. [[https://stable.melpa.org/#/orderless][Link]] #+begin_src emacs-lisp (use-package orderless :ensure t :custom (completion-styles '(orderless basic)) (completion-category-defaults nil) (completion-category-overrides '((file (styles partial-completion))))) #+end_src ** Vertico [[https://github.com/minad/vertico][Vertico]] is one of the *best* minibuffer improvement packages out there. Combined with the other packages in this section it makes minibuffer completions concise, and descriptive. #+begin_src emacs-lisp (use-package vertico :demand t :custom (vertico-cycle t) :config (setf (car vertico-multiline) "\n") ;; don't replace newlines (vertico-mode) (vertico-prescient-mode) (define-key vertico-map (kbd "C-h") #'+minibuffer-up-dir)) #+end_src ** Marginalia [[https://github.com/minad/marginalia][Marginalia]] adds completion annotations on the right side of the minibuffer. #+begin_src emacs-lisp (use-package marginalia :defer 2 :config (marginalia-mode) (setf (alist-get 'elpaca-info marginalia-command-categories) 'elpaca)) #+end_src ** Consult #+begin_quote [[https://github.com/minad/consult][Consult]] provides search and navigation commands based on the emacs completion function completing-read. #+end_quote Think about this as a tightly integrate search that can tie into many aspects of a project, and convey the results to various completion facilities. #+begin_src emacs-lisp (use-package consult :ensure t :bind (;; C-c bindings in `mode-specific-map' ("C-c M-x" . consult-mode-command) ("C-c h" . consult-history) ("C-c k" . consult-kmacro) ("C-c m" . consult-man) ("C-c i" . consult-info) ([remap Info-search] . consult-info) ;; C-x bindings in `ctl-x-map' ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command ("C-x b" . consult-buffer) ;; orig. switch-to-buffer ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame ("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab ("C-x r b" . consult-bookmark) ;; orig. bookmark-jump ("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer ;; Custom M-# bindings for fast register access ("M-#" . consult-register-load) ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated) ("C-M-#" . consult-register) ;; Other custom bindings ("M-y" . consult-yank-pop) ;; orig. yank-pop ;; M-g bindings in `goto-map' ("M-g e" . consult-compile-error) ("M-g f" . consult-flymake) ;; Alternative: consult-flycheck ("M-g g" . consult-goto-line) ;; orig. goto-line ("M-g M-g" . consult-goto-line) ;; orig. goto-line ("M-g o" . consult-outline) ;; Alternative: consult-org-heading ("M-g m" . consult-mark) ("M-g k" . consult-global-mark) ("M-g i" . consult-imenu) ("M-g I" . consult-imenu-multi) ;; M-s bindings in `search-map' ("M-s d" . consult-find) ;; Alternative: consult-fd ("M-s c" . consult-locate) ("M-s g" . consult-grep) ("M-s G" . consult-git-grep) ("M-s r" . consult-ripgrep) ("M-s l" . consult-line) ("M-s L" . consult-line-multi) ("M-s k" . consult-keep-lines) ("M-s u" . consult-focus-lines) ;; Isearch integration ("M-s e" . consult-isearch-history) :map isearch-mode-map ("M-e" . consult-isearch-history) ;; orig. isearch-edit-string ("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string ("M-s l" . consult-line) ;; needed by consult-line to detect isearch ("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch ;; Minibuffer history :map minibuffer-local-map ("M-s" . consult-history) ;; orig. next-matching-history-element ("M-r" . consult-history)) ;; orig. previous-matching-history-element ;; Enable automatic preview at point in the *Completions* buffer. This is ;; relevant when you use the default completion UI. :hook (completion-list-mode . consult-preview-at-point-mode) ;; The :init configuration is always executed (Not lazy) :init ;; Tweak the register preview for `consult-register-load', ;; `consult-register-store' and the built-in commands. This improves the ;; register formatting, adds thin separator lines, register sorting and hides ;; the window mode line. (advice-add #'register-preview :override #'consult-register-window) (setq register-preview-delay 0.5) ;; Use Consult to select xref locations with preview (setq xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref) ;; Configure other variables and modes in the :config section, ;; after lazily loading the package. :config ;; Optionally configure preview. The default value ;; is 'any, such that any key triggers the preview. ;; (setq consult-preview-key 'any) ;; (setq consult-preview-key "M-.") ;; (setq consult-preview-key '("S-" "S-")) ;; For some commands and buffer sources it is useful to configure the ;; :preview-key on a per-command basis using the `consult-customize' macro. (consult-customize consult-theme :preview-key '(:debounce 0.2 any) consult-ripgrep consult-git-grep consult-grep consult-man consult-bookmark consult-recent-file consult-xref consult--source-bookmark consult--source-file-register consult--source-recent-file consult--source-project-recent-file ;; :preview-key "M-." :preview-key '(:debounce 0.4 any)) ;; Optionally configure the narrowing key. ;; Both < and C-+ work reasonably well. (setq consult-narrow-key "<") ;; "C-+" ;; Optionally make narrowing help available in the minibuffer. ;; You may want to use `embark-prefix-help-command' or which-key instead. ;; (keymap-set consult-narrow-map (concat consult-narrow-key " ?") #'consult-narrow-help) ) #+end_src * Files I've been increasingly using [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html][dired]], and [[https://github.com/alexluigit/dirvish][dirvish]] to handle files for a while now. At times it can be a bit cumbersome, but with time it could easily be all I need. ** Dired I mostly just modify the dired list command switches, and have [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html][dired]] open new directories in the same buffer. This comes with some benefits, and drawbacks but for now it seems to work best this way. #+begin_src emacs-lisp (use-feature dired :commands (dired) :custom (dired-listing-switches "-l --almost-all --human-readable --group-directories-first --no-group") :config (put 'dired-find-alternate-file 'disabled nil)) #+end_src ** Dirvish [[https://github.com/alexluigit/dirvish][Dirvish]] is a very exceptional [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html][dired]] enhancement. With this package one can have similar functionality to vifm, yazi, and so on all within the comfort of emacs. I have most of the comforts enabled here; however they come with certain dependencies. It will function without them however. #+begin_src emacs-lisp (use-package dirvish :ensure t :init (dirvish-override-dired-mode) :custom (dirvish-quick-access-entries ; It's a custom option, `setq' won't work '(("h" "~/" "Home") ("d" "~/Downloads/" "Downloads") ("s" "/ssh:192.168.88.1" "SSH server"))) :config (dirvish-peek-mode) ; Preview files in minibuffer (dirvish-side-follow-mode) ; similar to `treemacs-follow-mode' (setq dirvish-mode-line-format '(:left (sort symlink) :right (omit yank index))) (setq dirvish-attributes ; The order *MATTERS* for some attributes '(vc-state subtree-state nerd-icons collapse git-msg file-time file-size) dirvish-side-attributes '(vc-state nerd-icons collapse file-size)) ;; open large directory (over 20000 files) asynchronously with `fd' command (setq dirvish-large-directory-threshold 20000) (setq insert-directory-program (if (eq system-type 'gnu/linux) "ls" "gls")) :bind ; Bind `dirvish-fd|dirvish-side|dirvish-dwim' as you see fit (("C-c f" . dirvish) :map dirvish-mode-map ; Dirvish inherits `dired-mode-map' (";" . dired-up-directory) ; So you can adjust `dired' bindings here ("?" . dirvish-dispatch) ; [?] a helpful cheatsheet ("a" . dirvish-setup-menu) ; [a]ttributes settings:`t' toggles mtime, `f' toggles fullframe, etc. ("f" . dirvish-file-info-menu) ; [f]ile info ("o" . dirvish-quick-access) ; [o]pen `dirvish-quick-access-entries' ("s" . dirvish-quicksort) ; [s]ort flie list ("r" . dirvish-history-jump) ; [r]ecent visited ("l" . dirvish-ls-switches-menu) ; [l]s command flags ("v" . dirvish-vc-menu) ; [v]ersion control commands ("*" . dirvish-mark-menu) ("y" . dirvish-yank-menu) ("N" . dirvish-narrow) ("^" . dirvish-history-last) ("TAB" . dirvish-subtree-toggle) ("M-f" . dirvish-history-go-forward) ("M-b" . dirvish-history-go-backward) ("M-e" . dirvish-emerge-menu))) #+end_src ** Diredfl This package just adds a bit of color to dired output. Looks good, but nothing too fancy. #+begin_src emacs-lisp (use-package diredfl :after (dired dirvish) :ensure t :hook (dired-mode-hook . diredfl-mode) (dirvish-directory-view-mode . diredfl-mode) :config (set-face-attribute 'diredfl-dir-name nil :bold t)) #+end_src ** Projects I use [[https://github.com/bbatsov/projectile][Projectile]] for project management. It provides everything I need in a fairly small, logical key map. #+begin_src emacs-lisp (use-package projectile :ensure t :init (setq projectile-project-search-path '(("~/Project" . 3))) :config (define-key projectile-mode-map (kbd "C-c C-p") 'projectile-command-map) (global-set-key (kbd "C-c p") 'projectile-command-map) (projectile-mode +1)) #+end_src ** Helpful Settings I have some settings for tidying up files on save, and keeping backup files together. #+begin_src emacs-lisp (use-feature files ;;:hook ;;(before-save . delete-trailing-whitespace) :config ;; source: http://steve.yegge.googlepages.com/my-dot-emacs-file (defun rename-file-and-buffer (new-name) "Renames both current buffer and file it's visiting to NEW-NAME." (interactive "sNew name: ") (let ((name (buffer-name)) (filename (buffer-file-name))) (if (not filename) (message "Buffer '%s' is not visiting a file." name) (if (get-buffer new-name) (message "A buffer named '%s' already exists." new-name) (progn (rename-file filename new-name 1) (rename-buffer new-name) (set-visited-file-name new-name) (set-buffer-modified-p nil)))))) :custom (require-final-newline t "Automatically add newline at end of file") (backup-by-copying t) (delete-old-versions t) (kept-new-versions 10) (kept-old-versions 5) (version-control t) (safe-local-variable-values '((eval load-file "./init-dev.el") (org-clean-refile-inherit-tags)) "Store safe local variables here instead of in emacs-custom.el")) #+end_src * Terminal I've been using [[https://codeberg.org/akib/emacs-eat][eat]] (Emulate A Terminal) in place of vterm lately as it has better emacs integration without too big of a performance hit. It doesn't handle fancy terminal applications quite as well, but so far has performed well. #+begin_src emacs-lisp (use-package eat :ensure (:type git :host codeberg :repo "akib/emacs-eat" :files ("*.el" ("term" "term/*.el") "*.texi" "*.ti" ("terminfo/e" "terminfo/e/*") ("terminfo/65" "terminfo/65/*") ("integration" "integration/*") (:exclude ".dir-locals.el" "*-tests.el"))) :hook (eat-mode-hook . eat-char-mode) (eshell-load-hook . eat-eshell-mode) (eshell-load-hook . eat-eshell-visual-command-mode) :custom (eat-kill-buffer-on-exit t) :config (setopt eat-shell-prompt-annotation-delay 0) (setopt eat-very-visible-cursor-type '(t nil nil)) (setopt eat-default-cursor-type '(t nil nil)) (setq process-adaptive-read-buffering nil) (setq read-process-output-max (* 4 1024 1024)) ;; Compile terminfo if needed (eat-compile-terminfo)) #+end_src Many of these settings are there to reduce flickering. They may not be needed long term. * Look and Feel I've already touched on some appearance settings so far, but I feel themes and such deserve their own space. ** Themes I'm currently only using solarized light as it seems to be the most readable theme. Perhaps I might toggle light/dark mode based on time, or lighting in the future. #+begin_src emacs-lisp (use-package color-theme-solarized :ensure (:host github :repo "sellout/emacs-color-theme-solarized" :files ("*.el")) :no-require t :init (customize-set-variable 'frame-background-mode 'dark) (load-theme 'solarized t)) #+end_src I like using catppuccin from time to time as well. #+begin_src emacs-lisp (use-package catppuccin-theme :ensure t) #+end_src ** Modeline Doom emacs has a great modeline in my opinion so I'm using theirs almost as is. It comes with some pretty nice customization features should it be necessary. #+begin_src emacs-lisp (use-package doom-modeline :defer 2 :config (doom-modeline-mode) :custom (doom-modeline-time-analogue-clock nil) (doom-modeline-time-icon nil) (doom-modeline-unicode-fallback nil) (doom-modeline-buffer-encoding 'nondefault) (display-time-load-average nil) (doom-modeline-icon t "Show icons in the modeline")) #+end_src * VCS When it comes to git, (which is all that's configured for now), the easy choice is [[https://magit.vc/][Magit]]. I've kept the configuration pretty minimal. Only adding forge support really. #+begin_src emacs-lisp (use-package magit :defer t :custom (magit-repository-directories (list (cons elpaca-repos-directory 1))) (magit-diff-refine-hunk 'all) :config (transient-bind-q-to-quit)) (use-package forge :after (magit)) #+end_src * Language Server Protocol LSP can be quite helpful for completions that are non-trivial. There are many flavors of LSP for Emacs, but I'm only familiar with eglot, and [[https://emacs-lsp.github.io/lsp-mode/#language-server-protocol-support-for-emacs][lsp-mode]]. Eglot is built into emacs core now, and uses other built in component well. However lsp-mode has some extra features that I think are worth having while also performing pretty well. Plus it uses packages that I already add even without the package. #+begin_src emacs-lisp ;; LSP (use-package lsp-mode :init ;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l") (setq lsp-keymap-prefix "C-c l") :hook (;; replace XXX-mode with concrete major-mode(e. g. python-mode) (c-ts-mode . lsp-deferred) (clojure-ts-mode . lsp-deferred) (elixir-ts-mode . lsp-deferred) (gleam-ts-mode . lsp-deferred) (python-ts-mode . lsp-deferred) (rust-ts-mode . lsp-deferred) (slint-mode . lsp-deferred) (zig-mode . lsp-deferred) ;; if you want which-key integration (lsp-mode . lsp-enable-which-key-integration)) :commands lsp-deferred :config (setq lsp-elixir-server-command '("elixir-ls"))) ;; optionally (use-package lsp-ui :commands lsp-ui-mode) #+end_src * Tree Sitter Tree sitter is included with emacs, but there are a couple of packages that make managing tree sitter easier. Mainly with automatically updating, and using tree sitter versions of major modes, and installing the parsers if needed. #+begin_src emacs-lisp ;; Treesit (setq treesit-language-source-alist '((rust "https://github.com/tree-sitter/tree-sitter-rust"))) (use-package treesit-auto :custom (treesit-auto-install 'prompt) :config (treesit-auto-add-to-auto-mode-alist 'all) (global-treesit-auto-mode)) (use-package treesit-fold :ensure t :defer t) #+end_src * Major Modes I use quite a few major modes. Mostly those using tree-sitter; Which should be selected automatically. As most of these are pretty straight forward I won't bother with an explanation on each. #+begin_src emacs-lisp ;; Markdown (use-package markdown-mode :ensure t :mode ("\\.md\\'" . gfm-mode) :init (setq markdown-command "multimarkdown") :bind (:map markdown-mode-map ("C-c C-e" . markdown-do))) (use-package slint-mode :defer t :config (add-to-list 'auto-mode-alist '("\\.slint\\'" . slint-mode))) (use-package zig-mode :defer t :config (add-to-list 'auto-mode-alist '("\\.\\(zig\\|zon\\)\\'" . zig-mode))) (use-package rainbow-mode :commands (rainbow-mode)) ;; Clojure (use-package clojure-ts-mode :ensure t :hook ((clojure-ts-mode . cider-mode) (clojure-ts-mode . rainbow-delimiters-mode) (clojure-ts-mode . clj-refactor-mode))) ;; Gleam (use-package gleam-ts-mode :mode (rx ".gleam" eos)) (use-package cider :ensure t :defer t) (use-package inf-elixir :defer t) ;; Go (use-package go-mode :demand t :mode "\\.go\\'") ;; Meson (use-package meson-mode :demand t :mode "\\.build\\'") ;; rust-mode (use-package rust-mode :ensure t :init (setq rust-mode-treesitter-derive t)) (use-package rustic :ensure (:host github :repo "emacs-rustic/rustic") :after (rust-ts-mode) :config (setq rustic-cargo-clippy-trigger-fix 'on-compile rustic-rustfmt-args "+nightly")) ;; Scheme (use-package geiser-chez :ensure t) #+end_src * Org Mode Org mode is a handy note taking, todo list managing, journal writing, and literate programming tool among other things. I use it for writing some of my configurations, and managing my notes. #+begin_src emacs-lisp (use-feature org :defer t :config (setq org-confirm-babel-evaluate nil) :custom (org-ellipsis (nth 5 '("↴" "˅" "…" " ⬙" " ▽" "▿"))) (org-priority-lowest ?D) (org-fontify-done-headline t) (global-set-key (kbd "C-c l") #'org-store-link) (global-set-key (kbd "C-c a") #'org-agenda) (global-set-key (kbd "C-c c") #'org-capture)) #+end_src ** Htmlize The [[https://github.com/emacsorphanage/htmlize/blob/master/htmlize.el#start-of-content][htmlize]] package enables exporting org documents, and other buffers into HTML format. #+begin_src emacs-lisp (use-package htmlize :after (org) :defer t) #+end_src ** Org Modern [[https://github.com/minad/org-modern][org-modern]] provides a cleaner representation of org documents while being edited. It displays the intended formatting without all the markup. #+begin_src emacs-lisp (use-package org-modern :after (org) :config (global-org-modern-mode) (remove-hook 'org-agenda-finalize-hook 'org-modern-agenda)) #+end_src ** Literate Tools These are packages useful for literate programming, and its presentation. Though not necessarily exlusive to literate programming as they can improve the look of most any org document. #+begin_src emacs-lisp (use-feature ob-tangle :after (org) :custom (org-src-window-setup 'current-window) (org-src-preserve-indentation t)) ;; Maybe unnecessary... I'll see. (use-package org-contrib) (use-package org-make-toc :commands (org-make-toc)) #+end_src ** Note Taking Org-roam is my go to for note taking. While out of the box it isn't quite as snazzy as something like Obsidian it does offer a lot of flexibility that no other note taking tool has. #+begin_src emacs-lisp (use-package org-roam :after (org) :ensure t :bind (("C-c n l" . org-roam-buffer-toggle) ("C-c n f" . org-roam-node-find) ("C-c n i" . org-roam-node-insert)) :config (setq org-roam-directory "~/Documents/org-roam" org-roam-dailies-directory "daily/") (setq org-roam-capture-templates '(("d" "default plain" plain "%?" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")) ("D" "default encrypted" plain "%?" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org.gpg" "#+title: ${title}\n")))) (setq org-roam-dailies-capture-templates '(("d" "default" plain "%?" :target (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n\n* Tasks\n\n* Notes")))) (org-roam-db-autosync-mode)) (use-package orgmdb :ensure t) (use-package org-roam-ui :after (org-roam) :ensure t :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)) #+end_src #+INCLUDE: "config/custom.org" :minlevel 1 #+begin_src emacs-lisp :exports none (maybe-load-rel "custom.el") (provide 'init) ;;; init.el ends here #+end_src