;;; init.el --- GNU Emacs Initialization File -*- lexical-binding: t; -*- ;; Author: Andrew Scott ;; URL: https://codeberg.org/andyscott/dotfiles ;; Keywords: convenience, tools ;; This file is not part of GNU Emacs. ;; Permission is hereby granted, free of charge, to any person obtaining a copy of this ;; software and associated documentation files (the "Software"), to deal in the Software ;; without restriction, including without limitation the rights to use, copy, modify, ;; merge, publish, distribute, sublicense, and/or sell copies of the Software, and to ;; permit persons to whom the Software is furnished to do so. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ;; INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ;; PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ;;; Commentary: ;; My Emacs initialization file. ;;; Code: ;;;; Debug Init ;;;;; Debug on Error ;; (setq debug-on-error t) ;;;;; Profiling ;;;;;; Use Package Report ;; (with-eval-after-load 'elpaca ;; (add-hook 'elpaca-after-init-hook #'use-package-report)) ;;;;;; Profiler ;; (profiler-start 'cpu+mem) ;; (with-eval-after-load 'elpaca ;; (add-hook 'elpaca-after-init-hook (lambda () ;; (profiler-stop) ;; (profiler-report)))) ;;;; package Management ;;;;; Elpaca (defvar elpaca-installer-version 0.7) (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 :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) (load "./elpaca-autoloads"))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca `(,@elpaca-order)) (defmacro use-feature (name &rest args) "Like `use-package' but without updating built-in packages. NAME and ARGS are in `use-package'. Credit to @progfolio: " (declare (indent defun)) `(use-package ,name :ensure nil ,@args)) (defun +elpaca-build-steps-with-unload (pkg) "Some built-in PKG need special handling for upgrades. Unloads PKG before continuing with build. See: " (append (butlast (if (file-exists-p (file-name-concat elpaca-builds-directory (symbol-name pkg))) elpaca--pre-built-steps elpaca-build-steps)) (list `(lambda (e) (when (featurep ',pkg) (unload-feature ',pkg t)) (elpaca--continue-build e)) 'elpaca--activate-package))) ;; Unload and build `seq' (elpaca `(seq :build ,(+elpaca-build-steps-with-unload 'seq))) ;;;;; use-package (elpaca elpaca-use-package (require 'elpaca-use-package) (elpaca-use-package-mode) (setopt use-package-always-ensure t ;; NOTE: Comment/remove stats when done profiling startup use-package-compute-statistics t)) ;;;;;; use-package and debugging (if debug-on-error (setopt use-package-verbose t use-package-expand-minimally nil use-package-compute-statistics t) (setopt use-package-verbose nil use-package-expand-minimally t)) ;; NOTE: Must wait for `elpaca--queues' to be processed (elpaca-wait) ;;;;;; use-package keyword order ;; :disabled ;; :load-path ;; :requires ;; :defines ;; :functions ;; :preface ;; :if :when :unless ;; :no-require ;; :catch ;; :after ;; :custom ;; :custom-face ;; :bind ;; :bind* ;; :bind-keymap ;; :bind-keymap* ;; :interpreter ;; :mode ;; :magic ;; :magic-fallback ;; :hook ;; :commands ;; :autoload ;; :init ;; :defer ;; :demand ;; :load ;; :config ;;;; Basic options ;;;;; ANSI Escape Codes (Operating System Commands) (use-feature ansi-osc :custom (ansi-osc-for-compilation-buffer t "Collect and handle OSC sequences") :hook (ansi-osc-compilation-filter . compilation-filter)) ;;;;; Auto Revert (use-feature autorevert :custom (auto-revert-interval 10 "Increase time between file checks") :hook (elpaca-after-init . global-auto-revert-mode)) ;;;;; Buffer Menu (use-feature ibuffer :bind ("C-x C-b" . ibuffer)) ;;;;; Customization settings & commands (use-feature cus-edit :custom (custom-file null-device "Fall into the nothingness that awaits you...")) (use-feature custom :custom (custom-safe-themes t)) ;;;;; "Electric" ;;;;;; Electric Indent/Quote/Newline (use-feature electric :hook ;; REVIEW: See local var `electric-indent-inhibit' ((org-mode python-mode python-ts-mode) . (lambda () (electric-indent-local-mode -1)))) ;;;;;; Electric Pair Mode (use-feature elec-pair :hook ((conf-mode markdown-mode org-mode prog-mode) . electric-pair-local-mode)) ;;;;; Emacs (use-feature emacs :bind (:map global-map ;; Disable `suspend-frame' shortcut (currently overwritten by `undo-fu' anyway) ("C-z" . nil) ("C-x k" . my-kill-buffer) ("C-x 4 C-0" . as/kill-buffer-and-other-window) ;; Escape behaves like C-g ("" . keyboard-escape-quit)) :custom (auto-window-vscroll nil "Stop scro my window") (completion-ignore-case t "Ignore case for completions") (cursor-type 'bar "Cursor appearance") (enable-recursive-minibuffers t "Allow minibuffer commands in the minibuffer") (fast-but-imprecise-scrolling t "Don't fontify when scrolling") (fill-column 79 "Increase default column for line wrapping") (history-delete-duplicates t "Delete identical elements when adding to history") (indicate-empty-lines t "Show empty lines in fringe") (inhibit-compacting-font-caches t "More memory, potentially more responsive") (minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt) "Disable prompt in minibuffer") (next-screen-context-lines 0 "Keep point position when scrolling") (read-buffer-completion-ignore-case t "Ignore case for buffer name completions") (scroll-step 1 "Try scrolling N lines before recentering") (scroll-conservatively 101 "I'll tell /you/ when to recenter") (scroll-preserve-screen-position t "Point keeps screen position when moved vertically") (sentence-end-double-space nil "Single space ends sentences") (tab-always-indent 'complete "Complete at point if line is already indented") ;; REVIEW ;; tab-first-completion 'word-or-paren-or-punct (use-short-answers t "Never make me fully type 'yes' and 'no'") :custom-face {{- if eq .chezmoi.hostname "helix" }} (default ((t (:font "Hack" :height 135)))) (fixed-pitch ((t (:font "Hack" :height 135)))) (variable-pitch ((t (:font "Liberation Sans" :height 150)))) {{- else }} (default ((t (:font "Hack" :height 120)))) (fixed-pitch ((t (:font "Hack" :height 120)))) (variable-pitch ((t (:font "Liberation Sans" :height 120)))) {{- end }} :hook (minibuffer-setup . cursor-intangible-mode) (elpaca-after-init . (lambda () (message "Emacs loaded in %s with %d garbage collections." (format "%.2f seconds" (float-time (time-subtract (current-time) before-init-time))) gcs-done))) :config (defun display-startup-echo-area-message () "Somehow less awful than messing with `inhibit-startup-echo-area-message' I could use advice, but I'll never want to see this message.") (defun my-kill-buffer () "Like `kill-buffer' but with a diff option" (interactive) (catch 'quit (save-window-excursion (let (done) (when (and buffer-file-name (buffer-modified-p)) (while (not done) (let ((response (read-char-choice (format "Save file %s? (y, n, d, q) " (buffer-file-name)) '(?y ?n ?d ?q)))) (setq done (cond ((eq response ?q) (throw 'quit nil)) ((eq response ?y) (save-buffer) t) ((eq response ?n) (set-buffer-modified-p nil) t) ((eq response ?d) (diff-buffer-with-file) nil)))))) (kill-buffer (current-buffer)) (force-mode-line-update))))) (defun as/kill-buffer-and-other-window () "Kill the most recently selected buffer and delete it's window" (interactive) (other-window -1) (when (not (one-window-p)) (my-kill-buffer) (delete-window))) (defun crm-indicator (args) "For `vertico' / Adds a prompt indicator to `completing-read-multiple'" (cons (format "[CRM%s] %s" (replace-regexp-in-string "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" "" crm-separator) (car args)) (cdr args))) (advice-add #'completing-read-multiple :filter-args #'crm-indicator)) ;;;;; Fill Column Indicator (use-feature display-fill-column-indicator :hook ((conf-mode prog-mode) . display-fill-column-indicator-mode)) ;;;;; Spell checking ;;;;;; Flyspell (use-feature flyspell :custom (flyspell-use-meta-tab nil "Disable correction with M-TAB") :hook (((git-commit-mode text-mode) . flyspell-mode))) ;;;;;; Flyspell Correction Functions (use-package flyspell-correct :after (flyspell) :bind (:map flyspell-mode-map ("C-M-." . flyspell-correct-wrapper))) ;;;;; Frame & Cursor Blink (use-feature frame :custom (blink-cursor-delay 1.0 "Increase time between blinks") (blink-cursor-interval 0.75 "Increase blink length")) ;;;;; Help System (use-feature help :defer t :custom (help-enable-variable-value-editing t "Allow editing in *Help* buffers") (help-window-select t "Always select *Help* buffers")) ;;;;;; Better Help Buffers (`helpful.el') (use-package helpful :bind ("C-h f" . helpful-callable) ("C-h v" . helpful-variable) ("C-h x" . helpful-command) ("C-c C-d" . helpful-at-point) ("C-c F" . helpful-function)) ;;;;; Keybind Hints ;;;;;; Which Key ;; NOTE: Will be built-in for Emacs 30? (use-package which-key :custom (which-key-idle-delay 0.3 "Decrease idle delay") (which-key-use-C-h-commands nil "Using `embark-prefix-help-command'") :hook (elpaca-after-init . which-key-mode)) ;;;;; Display Line Number Mode (use-feature display-line-numbers :custom (display-line-numbers-grow-only t "Maintain width for large files") :hook ((conf-mode prog-mode) . display-line-numbers-mode)) ;;;;; Mini-buffer ;;;;;; Mini-buffer Settings (use-feature minibuffer :custom (read-file-name-completion-ignore-case t "Ignore file name case for minibuffer completions")) ;;;;;; Mini-buffer History (use-feature savehist :custom (savehist-additional-variables '(command-history compile-command kill-buffer kill-ring) "Add additional variables to history") (savehist-autosave-interval 120 "Decrease time between auto-saves") (savehist-file (expand-file-name "savehist" xdg_cache_home) "Move history file to XDG_CACHE_HOME") :hook (elpaca-after-init . savehist-mode)) ;;;;;; Embark (Context Menu) (use-package embark :custom (prefix-help-command #'embark-prefix-help-command "Change function to run when `help-char' follows a prefix key") :bind (("C-." . embark-act) ("C-;" . embark-dwim) ("C-h B" . embark-bindings) ("C-c M-k" . embark-kill-buffer-and-window)) :defer 3 :config ;; Hide the mode line (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none))))) ;;;;;; Embark + Consult (use-package embark-consult :if (and (elpaca-installed-p 'embark) (elpaca-installed-p 'consult)) :hook (embark-collect-mode . consult-preview-at-point-mode)) ;;;;; Terminal Encoding (use-feature mule :defer t :config (unless (display-graphic-p) (set-terminal-coding-system 'utf-8))) ;;;;; Show Paren Mode (use-feature paren :custom (show-paren-context-when-offscreen 'child-frame "Show context in frame at top left") (show-paren-style 'mixed "Show parens if visible, otherwise the whole expression") (show-paren-when-point-inside-paren t "Show paren when just inside parens") :hook ((conf-mode markdown-mode prog-mode) . show-paren-local-mode)) ;;;;; Mouse (use-feature mouse :custom (mouse-1-click-follows-link 'double "I /hate/ when mouse-1 is unexpectedly remapped (org)") (mouse-scroll-delay 0.15 "Decrease delay")) ;;;;;; Mouse Wheel (use-feature mwheel :custom (mouse-wheel-follow-mouse t "Scroll window under mouse") (mouse-wheel-progressive-speed nil "Don't increase scroll speed with wheel") (mouse-wheel-scroll-amount '(1 ((shift) . 1) ((meta) . 0.5) ((control meta) . global-text-scale) ((control) . text-scale)) "Amount to scroll with and without modifiers")) ;;;;;; Pixel Scroll Precision Mode (use-feature pixel-scroll :unless (pixel-scroll-precision-mode) :defer 1 :config (pixel-scroll-precision-mode)) ;;;;; Comments (use-feature newcomment :custom (comment-style 'multi-line "Use one comment for all lines, end without extra line")) ;;;;; Shell Mode (use-feature shell :defer t :hook (shell-mode . ansi-color-for-comint-mode-on)) ;;;;; Basic Commands (`simple.el') (use-feature simple :custom (read-extended-command-predicate #'command-completion-default-include-p "Exclude non-current mode completions, include no-mode completions") (indent-tabs-mode nil "Tabs for C, and C alone") :hook ((conf-mode prog-mode) . column-number-mode) (git-commit-mode . auto-fill-mode)) ;;;;; Typing Breaks (use-feature type-break :custom (type-break-keystroke-threshold '(nil . nil) "Disable keystroke limit") :defer t) ;;;;; Whitespace (use-feature whitespace :custom ;; (whitespace-action 'auto-cleanup) (whitespace-line-column nil "Use `fill-column' instead") (whitespace-style '(lines-char missing-newline-at-eof space-after-tab space-before-tab tabs trailing) "Clean up without visualizing whitespace") :hook (elpaca-after-init . whitespace-mode) :config ;; TODO: Fix `whitespace-action' above? (add-hook 'before-save-hook #'whitespace-cleanup)) ;;;;; Undo/Redo ;;;;;; Undo Fu (use-package undo-fu :defer 3 :bind (("C-z" . undo-fu-only-undo) ("C-S-z" . undo-fu-only-redo))) ;;;;;; Vundo (use-package vundo :custom (vundo-glyph-alist vundo-unicode-symbols) :defer 3) ;;;;;; Undo Fu Persistence (use-package undo-fu-session :if (elpaca-installed-p 'undo-fu) :after (undo-fu) :custom (undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'") "Don't track changes to these files") (undo-fu-session-directory (expand-file-name "undo-fu-session" xdg_cache_home) "Relocate to XDG_CACHE_HOME") :config (undo-fu-session-global-mode)) ;;;;; Windows ;;;;;; Window Settings (use-feature window :custom (switch-to-buffer-obey-display-actions t "Respect other settings when switching buffers") :bind (:map global-map ;; Automatically select new window when splitting ("C-x 2" . (lambda () (interactive)(split-window-below) (other-window 1))) ("C-x 3" . (lambda () (interactive)(split-window-right) (other-window 1))) ;; Resizing buffers ("S-C-" . shrink-window-horizontally) ("S-C-" . enlarge-window-horizontally) ("S-C-" . shrink-window) ("S-C-" . enlarge-window))) ;;;;;; Ace Window (use-package ace-window :bind ("C-c w" . ace-window)) ;;;;; Mode-line ;;;;;; Show Current/Total Matches (Anzu) (use-package anzu :defer 3 :config (global-anzu-mode)) ;;;; Appearance ;;;;; Startup ;;;;;; Grid (use-package grid :ensure (:host github :repo "ichernyshovvv/grid.el")) ;;;;;; Enlight (use-package enlight :if (elpaca-installed-p 'grid) :after (grid) :hook (elpaca-after-init . enlight-open) :config (setopt enlight-content (grid-get-row `(,(enlight-menu '(("Files" ("Find File" find-file "f") ("Recent Files" consult-recent-file "r") ("Projects" project-switch-project "p") ("Treemacs" treemacs "t")))) " " ,(enlight-menu '(("Org" ("Super Agenda" (org-agenda nil "u") "u") ("Time Blocking" org-timeblock "b") ("Consult Notes" (consult-notes) "n") ("Denote" (call-interactively 'denote-open-or-create) "d")))) " " ,(enlight-menu `(("Settings" ("Elpaca" elpaca-manager "L") ("Emacs" (progn (find-file ,user-init-file)) "I") ("Denote" (progn (find-file ,(replace-regexp-in-string "init.el" "lisp/init-denote.el" user-init-file))) "D") ("Org" (progn (find-file ,(replace-regexp-in-string "init.el" "lisp/init-org.el" user-init-file))) "O")))))))) ;;;;; Mode line ;;;;;; Moody (use-package moody :custom (x-underline-at-descent-line t "Place underline at bottom of mode line") ;; :defer 1 :hook (elpaca-after-init . (lambda () (moody-replace-eldoc-minibuffer-message-function) (moody-replace-mode-line-buffer-identification) (moody-replace-mode-line-front-space) (moody-replace-vc-mode)))) ;;;;;; Minor Mode Menu (Minions) (use-package minions :after (moody) :config (minions-mode)) ;;;;; Colors ;;;;;; Rainbow Mode (use-package rainbow-mode :hook ((conf-mode prog-mode toml-ts-mode yaml-ts-mode) . rainbow-mode)) ;;;;; Icons ;;;;;; Kind Icon (use-package kind-icon :disabled t :after (corfu) :custom (kind-icon-default-face 'corfu-default "Don't default to frame colors if otherwise unspecified") :config (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)) ;;;;;; Nerd Icons (use-package nerd-icons :defer 1) ;;;;;;; Nerd Icons + Completion (use-package nerd-icons-completion :if (and (elpaca-installed-p 'nerd-icons) (elpaca-installed-p 'marginalia)) :after (nerd-icons marginalia) :config (nerd-icons-completion-mode) :hook (marginalia-mode . nerd-icons-completion-marginalia-setup)) ;;;;;;; Nerd Icons + Corfu (use-package nerd-icons-corfu :if (and (elpaca-installed-p 'nerd-icons) (elpaca-installed-p 'corfu)) :after (nerd-icons corfu) :config (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)) ;;;;;;; Nerd Icons + Dired (use-package nerd-icons-dired :if (elpaca-installed-p 'nerd-icons) :hook (dired-mode . nerd-icons-dired-mode)) ;;;;;;; Nerd Icons + ibuffer (use-package nerd-icons-ibuffer :if (elpaca-installed-p 'nerd-icons) :hook (ibuffer-mode . nerd-icons-ibuffer-mode)) ;;;;;;; Nerd Icons + Treemacs (use-package treemacs-nerd-icons :if (and (elpaca-installed-p 'nerd-icons) (elpaca-installed-p 'treemacs)) :after (nerd-icons treemacs) :config (treemacs-load-theme "nerd-icons")) ;;;;; Highlighting ;;;;;; Indent Bars (use-package indent-bars :custom (indent-bars-color '(highlight :face-bg nil :blend 0.375)) (indent-bars-color-by-depth '(:regexp "orderless-match-face-\\([0-9]+\\)" :blend 1) "Default 'outline' faces are pretty boring with doom-spacegrey") (indent-bars-highlight-current-depth '(:blend 0.75) "Default `:pattern' requires `:stipple', revisit for Emacs 30") (indent-bars-no-descend-lists t "Only show 1 level for lists & continued lines") (indent-bars-prefer-character t "`:stipple' unsupported with PGTK until Emacs 30") (indent-bars-treesit-support t "Enable `treesit' support") ;; (indent-bars-treesit-wrap '((c argument_list parameter_list init_declarator)) "Seems to not have any effect?") :hook (prog-mode . indent-bars-mode)) ;;;;;; HL Todo ;; FIXME (defun as/hl-todo-previous-mark-done (arg) (interactive "p") (save-excursion ;; (goto-char (point-max)) (let ((hl-todo-wrap-movement nil)) (hl-todo-previous arg)) `(string-match ,(concat (hl-todo--regexp) "\\=") ,(thing-at-point 'line t)) (replace-match "DONE" t t) )) (use-package hl-todo :ensure (hl-todo :depth nil) :custom (hl-todo-highlight-punctuation ":!?" "Highlight additional punctuation characters") (hl-todo-include-modes '(conf-mode markdown-mode prog-mode)) (hl-todo-keyword-faces '(("DEBUG" warning bold) ("DONE" success italic) ("HACK" warning bold) ("FIXME" error bold) ("NOTE" homoglyph italic) ("REVIEW" homoglyph italic) ("TODO" homoglyph bold)) "Customize faces for todo keywords") :bind (:map hl-todo-mode-map ("C-c C-t p" . hl-todo-previous) ("C-c C-t n" . hl-todo-next) ("C-c C-t o" . hl-todo-occur) ("C-c C-t i" . hl-todo-insert)) :hook (elpaca-after-init . global-hl-todo-mode)) ;;;;;;; Consult + HL Todo (use-package consult-todo :if (and (elpaca-installed-p 'hl-todo) (elpaca-installed-p 'consult)) :after (hl-todo) :bind (:map hl-todo-mode-map ("C-c C-t c" . consult-todo) ("C-c C-t C-c" . consult-todo-all))) ;;;;; Line Wrapping ;;;;;; Visual Fill Column (use-package visual-fill-column :custom (visual-fill-column-enable-sensible-window-split t "Don't take margins into account when splitting") :defer t) ;;;;;; Adaptive Wrap (use-package adaptive-wrap :defer t) ;;;;; Themes ;;;;;; Catppuccin (use-package catppuccin-theme ;; :disabled :if (eq custom-safe-themes t) :custom (catppuccin-flavor 'macchiato "Set variant to macchiato (medium-dark)") :defer t :config (catppuccin-reload) ;; (load-theme 'catppuccin t) ) ;;;;;; Doom (use-package doom-themes :if (eq custom-safe-themes t) :custom (doom-spacegrey-brighter-comments t "More visible comment colors") (doom-spacegrey-brighter-modeline t "More visible mode line colors") (doom-spacegrey-comment-bg nil "Don't lighten comment background") (doom-themes-enable-bold t "Enable bold text faces") (doom-themes-enable-italic t "Enable italic text faces") (doom-themes-org-fontify-special-tags nil "Disable # and @") :config (doom-themes-org-config) ;; (doom-themes-treemacs-config) ; requires `all-the-icons' (load-theme 'doom-spacegrey t)) (use-package miasma-theme :ensure (:host github :repo "/daut/miasma-theme.el") :config ;; (load-theme 'miasma t) ) ;;;;;; Nimbus (use-package nimbus-theme :if (eq custom-safe-themes t) :defer t) ;;;;;; Zerodark (use-package zerodark-theme ;; Requires `all-the-icons' :disabled t :defer t) ;;;; Files ;;;;; File Management ;;;;;; Dired (use-feature dired :custom (dired-kill-when-opening-new-dired-buffer t "Kill current buffer when opening a new directory") (dired-mouse-drag-files t "Allow drag-and-drop") :commands (dired)) ;;;;;; Treemacs (use-package treemacs :commands (treemacs) :custom (treemacs-eldoc-display 'simple "Only show absolute path") (treemacs-is-never-other-window t "Disallow `other-window' and related functions") (treemacs-persist-file (expand-file-name "treemacs-persist" xdg_cache_home) "Relocate to XDG_CACHE_HOME") ;; (treemacs-text-scale 1 "Scale sidebar text") (treemacs-width-is-initially-locked t "Enforce using commands to resize") :config (add-to-list 'treemacs-litter-directories "/zig-cache") (add-to-list 'treemacs-litter-directories "/.zig-cache") ;; (treemacs-resize-icons 18) (treemacs-follow-mode) (treemacs-filewatch-mode) (treemacs-fringe-indicator-mode 'always) (treemacs-git-commit-diff-mode) (treemacs-git-mode 'deferred) ;; (treemacs-hide-gitignored-files-mode nil) (treemacs-indent-guide-mode) :init (bind-keys :prefix-map as/treemacs-prefix-map :prefix "C-c t" ("0" . treemacs-select-window) ("1" . treemacs-delete-other-windows) ("t" . treemacs) ("d" . treemacs-select-directory) ("B" . treemacs-bookmark) ("C-f" . treemacs-find-file) ("M-t" . treemacs-find-tag))) (use-package treemacs-magit :if (and (elpaca-installed-p 'magit) (elpaca-installed-p 'treemacs)) :after (treemacs magit)) ;;;;; Auto-save & Backups (use-feature files :custom (backup-by-copying t "Copy to back up, don't rename the current file") (confirm-kill-processes nil "Don't ask about processes, just exit") (delete-old-versions t "Delete excess backups") (kept-new-versions 5 "Increase number of new backups to keep") (kept-old-versions 3 "Increase number of old backups to keep") (require-final-newline t "Add newline to end of file") (version-control t "Use version numbers for backup files") :init (let ((auto_save_directory (concat xdg_cache_home "auto-save-list/"))) (unless (file-directory-p auto_save_directory) (make-directory auto_save_directory)) (setopt backup-directory-alist `((".*" . ,auto_save_directory)) auto-save-list-file-prefix (concat auto_save_directory "saves-") auto-save-file-name-transforms `((".*" ,auto_save_directory t))))) ;;;;;; Recent Files (use-feature recentf :custom (recentf-auto-cleanup 600 "Clean up the list every 10 minutes, not when I load a related mode") (recentf-max-menu-items 100 "Increase maximum number of items in the menu") (recentf-max-saved-items 100 "Maximum number of items to save to the recentf file") (recentf-save-file (expand-file-name "recentf" xdg_cache_home) "Relocate to XDG_CACHE_HOME") :hook (elpaca-after-init . recentf-mode)) ;;;;;; Save Place Mode (use-feature saveplace :custom (save-place-file (expand-file-name "places" xdg_cache_home) "Relocate to XDG_CACHE_HOME") :hook (elpaca-after-init . save-place-mode)) ;;;; Citations ;;;;; BibTex (use-feature bibtex :after (ebib) :custom (bibtex-autokey-additional-names "EtAl" "Append if not all names can be used") (bibtex-autokey-edit-before-use t "Allow key editing") (bibtex-autokey-expand-strings t "Expand strings when extracting from BibTex") (bibtex-autokey-name-case-convert-function #'capitalize "Captialize names in reference keys") (bibtex-autokey-name-year-separator "" "Don't separate name and year in reference keys") (bibtex-autokey-names 2 "Use 2 names for reference keys") (bibtex-autokey-names-stretch 1 "Allow an extra name in reference keys if it would mean using all names") (bibtex-autokey-titlewords 3 "Use 3 words from title for reference keys") (bibtex-autokey-titlewords-stretch 1 "Allow an extra title word in reference keys if it would end a sentence") (bibtex-autokey-titleword-length #'infty "Disable title word character limit in reference keys") (bibtex-autokey-titleword-separator "" "Don't separate title words") (bibtex-autokey-titleword-case-convert-function #'capitalize "Capitalize title words in reference keys") (bibtex-autokey-year-length 4 "Use full year in reference keys") (bibtex-autokey-year-title-separator "" "Don't separate year and title in reference keys")) ;;;;; Biblio (use-package biblio :if (elpaca-installed-p 'ebib) :after (ebib) :custom (biblio-bibtex-use-autokey t "Automatically generate new BibTex keys")) ;;;;; Biblio OpenLibrary (ISBN lookup) (use-package biblio-openlibrary :ensure (biblio-openlibrary :host github :repo "fabcontigiani/biblio-openlibrary") :if (elpaca-installed-p 'biblio) :after (biblio)) ;;;;; Ebib (use-package ebib :commands (ebib) :custom (ebib-autogenerate-keys t "Enabled by default, and I want to keep it that way") (ebib-bibtex-dialect 'biblatex "Use biblatex, not BibTex") (ebib-use-timestamp t "Create a timestamp when adding an entry") (ebib-filters-default-file (expand-file-name "ebib-filters" user-emacs-directory) "Relocate filters file") (ebib-allow-identical-fields t "Merge repeated fields") (ebib-file-associations '(("pdf" . nil) ("ps" . "gs")) "Specify default programs for file types") (ebib-import-target-directory (expand-file-name "~/Nextcloud/Library/") "Directory for `ebib-download-url' and `ebib-import-file'") (ebib-default-directory (expand-file-name "~/Nextcloud/Library/") "Default directory when, ex., prompting user") (ebib-preload-bib-files `(,(expand-file-name "~/Nextcloud/Library/Bibliography/Library.bib")) "Bib files to autoload") ;; (ebib-bib-search dirs nil "Directory to seach for multiple .bib files") ;;; Editing ;; (ebib-save-xrefs-first nil "Save entries with cross-references first - required for cross-referencing unless sort order is changed") ;; (ebib-sort-order nil "Change sort order of .bib files - be sure to unset `ebib-save-xrefs-first'") (ebib-filters-ignore-case t "True by default, and I want to keep it that way") ;;; Downloading/Filenames ;;; Notes ;; ebib-notes-storage 'multiple-notes-per-file ; probabably set to `multiple-notes-per-file' for org? ;; (ebib-notes-locations nil "Set locations for notes") ;; (ebib-notes-default-file nil "Doesn't matter for `org-capture' but can still be set") ;;; Org-capture ;; (ebib-notes-use-org-capture nil "Skip `org-capture' and use this template") ;; (ebib-org-capture nil "Function to call `org-capture' from `ebib'") ;;; Reading list ;; (ebib-reading-list-file nil "Set reading list location") ;; (ebib-reading-list-todo-marker "TODO" "Default todo state for reading list") ;; (ebib-reading-list-template "" "Format for reading list todo items") ;; (ebib-reading-list-add-item-function "" "Change where new reading list items are added") ;; (ebib-reading-list-remove-item "" "Function run when removing an item from the list - default is to mark DONE") ;;; Keywords ;; (ebib-keywords nil "Keywords always available for completion") ;;; org-ebib ;; (org-ebib-link-type 'key "Type of link produced by `org-store-link' on entries") ) (use-package ebib-biblio :ensure nil ; It's included with `ebib' so I don't want to try and build it :if (and (elpaca-installed-p 'biblio) (elpaca-installed-p 'ebib)) :after (ebib biblio) :bind (:map ebib-index-mode-map ("B" . ebib-biblio-import-doi)) (:map biblio-selection-mode-map ("e" . ebib-biblio-selection-import))) ;;;; Completion ;;;;; Cape (`completion-at-point' extensions) (use-package cape :bind-keymap ("M-p" . cape-prefix-map) :config (advice-add 'eglot-completion-at-point :around #'cape-wrap-buster) (advice-add 'eglot-completion-at-point :around #'cape-wrap-noninterruptible) :defer 3 ;; :hook ;; (completion-at-point-functions . cape-dabbrev) ;; (completion-at-point-functions . cape-file) ;; (completion-at-point-functions . cape-elisp-block) ) ;;;;; Mini-buffer Completion ;;;;;; Annnotations (Marginalia) (use-package marginalia :defer 1 :config (marginalia-mode)) ;;;;;; UI (Vertico) (use-package vertico :custom (vertico-cycle t "Cycle with `vertico-next' and `vertico-previous'") (vertico-count 15 "Maximum number of candidates to display") ;; (vertico-multiform-categories ;; '((file (vertico-sort-function . vertico-sort-alpha))) ;; "Sort files alphabetically") (vertico-resize t "Allow both shrinking and growing") (vertico-scroll-margin 1 "Reduce lines at top and bottom when scrolling") :config (vertico-mode) ;; (setopt vertico-multiform-categories '((file (vertico-sort-function . vertico-sort-alpha)))) ;; (vertico-multiform-mode) ) ;;;;;; Completions (Consult) (use-package consult :custom (consult-narrow-key "<" "Prefix for completion narrowing") ;; Register formatting (register-preview-delay 0.6 "Decrease wait time for register preview") (register-preview-function #'consult-register-format "Use `consult' for register previews") ;; Select xref locations with preview (xref-show-xrefs-function #'consult-xref "Use `consult' for external reference search results") (xref-show-definitions-function #'consult-xref "Use `consult' to display external reference search results") :bind (;; C-c bindings in `mode-specific-map' ("C-c M-x" . consult-mode-command) ("C-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 r b" . consult-bookmark) ; orig. bookmark-jump ("C-x p b" . consult-project-buffer) ; orig. project-switch-to-buffer ("C-x M-r" . consult-recent-file) ;; 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) ("M-s D" . 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 ) :config ;; Register preview window (advice-add #'register-preview :override #'consult-register-window)) ;;;;;; Consult Dir (directory switching in mini-buffer) (use-package consult-dir :if (and (elpaca-installed-p 'consult) (elpaca-installed-p 'vertico)) :after (consult vertico) :bind (("C-x C-d" . consult-dir) :map vertico-map ("C-x C-d" . consult-dir) ("C-x C-j" . consult-dir-jump-file))) ;;;;; Completion in Region ;;;;;; Corfu (use-package corfu :ensure (corfu :files (:defaults "extensions/*")) :defer 3 :custom ;; (corfu-auto t "Enable auto-completion") (corfu-cycle t "Enable cycling with `corfu-next' and `corfu-previous'") :config (when (>= emacs-major-version 30) (setopt text-mode-ispell-word-completion nil)) (global-corfu-mode) (corfu-popupinfo-mode)) ;;;;;; Completion Styles ;;;;;;; Orderless (use-package orderless :custom (completion-styles '(basic substring orderless) "Add `orderless', remove `emacs22' & `partial-completion'") (completion-category-overrides '((file (styles basic substring partial-completion)) (eglot (styles basic substring orderless)) (eglot-capf (styles basic substring orderless))) "Override file for `tramp' and add orderless to `eglot'") (orderless-matching-styles '(orderless-literal orderless-regexp ;; orderless-flex orderless-prefixes orderless-initialism ) "Add prefixes and initialism") :defer 1) ;;;; Abbreviations ;;;;; Template Expansion ;;;;;; Yasnippet (use-package yasnippet :bind (:map yas-minor-mode-map ("" . nil) ("TAB" . nil) ("C-c y i" . yas-insert-snippet) ("C-c y v" . yas-visit-snippet-file)) :config (yas-reload-all) ; needed if not using `yas-global-mode' :hook ((org-mode prog-mode) . yas-minor-mode-on)) ;;;;;; Yasnippet Snippets (use-package yasnippet-snippets :if (elpaca-installed-p 'yasnippet) :after (yasnippet)) ;;;;;; Yasnippet + Consult (use-package consult-yasnippet :if (and (elpaca-installed-p 'consult) (elpaca-installed-p 'yasnippet)) :after (consult yasnippet) :bind (:map yas-minor-mode-map ("C-c y c" . consult-yasnippet))) ;;;; Programming ;;;;; Compiling (use-feature compile :custom (compilation-ask-about-save nil "Just save, don't ask") (compilation-scroll-output 'first-error "Stop scrolling at first error") :defer t :hook (compilation-filter . ansi-color-compilation-buffer)) ;;;;;; Documentation ;;;;;; Creating Documentation ;;;;;;; Doxygen (use-package gendoxy :after (c-ts-mode) :ensure (:host gitlab :repo "mp81ss_repo/gendoxy") :bind (:map c-ts-mode-map ("C-c c d" . gendoxy-tag) ("C-c c D" . gendoxy-tag-header)) (:map c++-ts-mode-map ("C-c c d" . gendoxy-tag) ("C-c c D" . gendoxy-tag-header))) ;;;;;; Reading Documentation ;;;;;;; DevDocs (use-package devdocs :bind ("C-h D" . devdocs-lookup)) ;;;;;;; Eldoc Box (use-package eldoc-box :custom (setopt eldoc-box-max-pixel-height 200) (setopt eldoc-box-max-pixel-width 355) :custom-face (eldoc-box-body ((t (:font "Liberation Sans" :height 120)))) :bind ("C-c h" . eldoc-box-help-at-point) :hook (eglot-managed-mode . eldoc-box-hover-mode)) ;;;;; Debugging ;;;;;; Realgud (use-package realgud :defer t) (use-package realgud-lldb :defer t) ;;;;; Formatting ;;;;;; Apheleia (use-package apheleia :defer t) ;;;;;; Clang Format (use-package clang-format :after (c-ts-mode) :custom (clang-format-style "file" "Default to using .clang-format file") :bind (:map c-ts-mode-map ("C-c c f" . clang-format-buffer) ("C-c c F" . clang-format-region)) (:map c++-ts-mode-map ("C-c c f" . clang-format-buffer) ("C-c c F" . clang-format-region))) ;;;;;; Reformatter ;; Required for "zig fmt" functions (use-package reformatter :if (elpaca-installed-p 'zig-mode) :after (zig-mode)) ;;;;; Languages ;;;;;; C (defun as/c-ts-mode-setup () "Set indentation style and offset for `c-ts-mode' or `c++-ts-mode'." (if (eq major-mode #'c-ts-mode) (progn (setq-local c-ts-mode-indent-offset 8 c-ts-mode-indent-style 'linux indent-tabs-mode t) (when (elpaca-installed-p 'clang-format) (setq-local clang-format-fallback-style "webkit"))) (progn (setq-local c-ts-mode-indent-offset 4 c-ts-mode-indent-style 'k&r) (when (elpaca-installed-p 'clang-format) (setq-local clang-format-fallback-style "llvm")))) (when (elpaca-installed-p 'indent-bars) (when (eq indent-bars-mode t) (indent-bars-reset)))) (use-feature c-ts-mode :hook (c-ts-mode . as/c-ts-mode-setup) :defer t) ;;;;;; C++ (use-feature c++-ts-mode :hook (c++-ts-mode . as/c-ts-mode-setup) :init (add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode)) :defer t) (use-package modern-cpp-font-lock ;; REVIEW: Not sure if I need this with `treesit.el' :disabled t :hook (c++-ts-mode . modern-c++-font-lock-mode)) ;;;;;; Python (use-feature python :init (add-to-list 'major-mode-remap-alist '(python-mode . python-ts-mode)) :defer t) (use-package pyenv-mode :hook (python-ts-mode . pyenv-mode)) ;;;;;; Rust (use-package rust-mode :custom (rust-mode-treesitter-derive t "Derive `rust-mode' from `rust-ts-mode'") :defer t) (use-package cargo-mode :bind (:map cargo-minor-mode-map ("C-c a" . nil)) :bind-keymap ("C-c g" . cargo-mode-command-map) :config ;; Mode uses `comint' by default (setq-local compilation-scroll-output t) :hook (rust-ts-mode . cargo-minor-mode)) ;;;;;; Web (i.e. JavaScript, PHP) ;; REVIEW: Testing astro-ts-mode ;; (define-derived-mode astro-mode web-mode "astro") (use-package web-mode :custom ;; (web-mode-attr-value-indent-offset 2 "HTML attribute indentation") (web-mode-code-indent-offset 2 "Decrease indentation in web languages") (web-mode-css-indent-offset 2 "Decrease indentation for CSS") (web-mode-markup-indent-offset 2 "Decrease indentation for markup") (web-mode-enable-front-matter-block t "Mode should recognize front matter") (web-mode-engines-alist '(("blade" . "\\.blade\\.") ("razor" . "\\.cshtml\\'")) "Add .NET to the mode") :mode ;; ("\\.astro\\'" . astro-mode) ("\\.\\(cshtml\\|html?\\|razor\\)\\'" . web-mode)) (use-package astro-ts-mode :defer t) ;;;;;; Zig (use-package zig-mode :custom (zig-format-on-save nil "Don't automatically format") :hook (zig-mode . zig-ts-mode) :defer t :config (defun zig-compile () "Save buffer and compile using `zig build`. Overrides `zig-compile' in `zig-mode.el'." (interactive) (save-buffer) (zig--run-cmd "build"))) (use-package zig-ts-mode :ensure (:host codeberg :repo "meow_king/zig-ts-mode") :mode ("\\.\\(zig\\|zon\\)\\'") :config (setopt fill-column 100)) ;;;;; Language Server Protocol (LSP) ;;;;;; Eglot (use-feature eglot :custom (eglot-autoshutdown t "Stop LSP server when all buffers are closed") (eglot-ignored-server-capabilities '(:colorProvider ; "Decorate color references" ;; :documentFormattingProvider ; "Format buffer" ;; :documentHighlightProvider ; "Highlight symbols automatically" :documentOnTypeFormattingProvider ; "On-type formatting" ;; :documentRangeFormattingProvider ; "Format portion of buffer" :hoverProvider ; "Documentation on hover" ;; :inlayHintProvider ; "Inlay hints" ) "Ignore uncommented LSP options") :bind (:map eglot-mode-map ("C-c e a" . eglot-code-actions) ("C-c e i" . eglot-inlay-hints-mode) ("C-c e i" . eglot-inlay-hints-mode) ("C-c e o" . eglot-code-actions-organize-imports) ("C-c e r" . eglot-rename) ("C-c e f" . eglot-format)) :hook ((astro-ts-mode bash-ts-mode c-ts-mode c++-ts-mode python-ts-mode rust-ts-mode sh-script zig-ts-mode) . eglot-ensure) (eglot-managed-mode . (lambda () ;; Turn hints off right away rather than disable (eglot-inlay-hints-mode -1) ;; Show flymake diagnostics before documentation ;; See: (setq-local eldoc-documentation-functions (cons #'flymake-eldoc-function (remove #'flymake-eldoc-function eldoc-documentation-functions))) (setq-local eldoc-documentation-strategy #'eldoc-documentation-compose))) :config (add-to-list 'eglot-server-programs '(astro-ts-mode . ("astro-ls" "--stdio" :initializationOptions (:typescript (:tsdk "/usr/lib/node_modules/typescript/lib"))))) (add-to-list 'eglot-server-programs '((rust-ts-mode rust-mode) . ("rustup" "run" "stable" "rust-analyzer" :initializationOptions (:check (:command "clippy"))))) (add-to-list 'eglot-server-programs '(zig-ts-mode . ("zls")))) ;;;;;; Eglot Booster (use-package eglot-booster :ensure (eglot-booster :host github :repo "jdtsmith/eglot-booster") :if (executable-find "emacs-lsp-booster") :after (eglot) :config (eglot-booster-mode)) ;;;;;; Consult + Eglot (LSP workspace/symbols UI) (use-package consult-eglot :if (elpaca-installed-p 'consult) :after (eglot) :bind (:map eglot-mode-map ("C-c e s" . consult-eglot-symbols))) ;;;;; Markup & Data Serialization ;;;;;; Markdown (use-package markdown-mode :custom (markdown-hide-markup t "Hide markers for italic/bold etm.") (markdown-hide-urls t "Hide reference links") :bind (:map markdown-mode-map ("C-M-i" . fill-paragraph)) :hook (markdown-mode . visual-line-fill-column-mode) :commands (markdown-mode)) ;;;;;; YAML (use-package yaml-pro :hook (yaml-ts-mode . yaml-pro-ts-mode)) ;;;;; Syntax Checking ;;;;;; Flymake (use-feature flymake :custom (flymake-fringe-indicator-position 'right-fringe "Move to right side") :bind (:map flymake-mode-map ("C-c f c" . consult-flymake) ("C-c f d" . flymake-show-buffer-diagnostics) ("C-c f D" . flymake-show-project-diagnostics) ("C-c f n" . flymake-goto-next-error) ("C-c f p" . flymake-goto-prev-error) ("C-M-;" . flymake-goto-next-error) ("C-M-'" . flymake-goto-prev-error)) :hook (prog-mode . flymake-mode)) ;;;;; Tree-sitter ;;;;;; Treesit (use-feature treesit :custom (treesit-font-lock-level 4 "Increase decoration level") :defer t) ;;;;;; Treesit Auto (use-package treesit-auto ;; :after (treesit) :custom (treesit-auto-install t "Install missing grammars without prompting") :hook (elpaca-after-init . global-treesit-auto-mode) :config (setq c_tsauto_config (make-treesit-auto-recipe :lang 'c :ts-mode 'c-ts-mode :remap 'c-mode :url "https://github.com/tree-sitter/tree-sitter-c" :revision "v0.20.7" :ext "\\.c\\'")) (setq cpp_tsauto_config (make-treesit-auto-recipe :lang 'cpp :ts-mode 'c++-ts-mode :remap 'c++-mode :url "https://github.com/tree-sitter/tree-sitter-cpp" :revision "v0.21.0" :ext "\\.cpp\\'")) ;; FIXME: This doesn't work, still need to use `treesit-install-language-grammar' (setq zig_tsauto_config (make-treesit-auto-recipe :lang 'zig :ts-mode 'zig-ts-mode ;; :remap 'zig-mode :url "https://github.com/maxxnino/tree-sitter-zig" :revision "v1.0.2" :ext "\\.\\(zig\\|zon\\)\\'" :source-dir "src")) (add-to-list 'treesit-auto-recipe-list c_tsauto_config) (add-to-list 'treesit-auto-recipe-list cpp_tsauto_config) (add-to-list 'treesit-auto-recipe-list zig_tsauto_config) (add-to-list 'treesit-auto-langs 'zig) (treesit-auto-add-to-auto-mode-alist 'all)) ;;;; Document Viewing ;;;;; DJVU ;; Mostly to stop `org-noter' from complaining (use-package djvu :defer t) ;;;;; EPUB (use-package nov :custom (nov-text-width t "Set low, it goes over anyway") :mode ("\\.epub\\'" . nov-mode) :hook (nov-mode . visual-line-mode) (nov-mode . visual-fill-column-mode) (nov-mode . (lambda () (face-remap-add-relative 'variable-pitch :family "Liberation Serif" :height 1.1) (setq-local visual-fill-column-center-text t)))) ;;;;; PDF (use-package pdf-tools :ensure (pdf-tools :pre-build ("./server/autobuild") :files (:defaults ("lisp/*" "server/epdfinfo"))) :custom (pdf-info-epdfinfo-program (expand-file-name "pdf-tools/server/epdfinfo" elpaca-builds-directory) "Builds in `elpaca' directory, see `:ensure'") (pdf-view-resiz-efactor 1.1 "Increase view size") (pdf-view-display-size 'fit-page "Fit page, not screen width") :mode ("\\.pdf\\'" . pdf-view-mode) :hook (pdf-view-mode . pdf-annot-minor-mode) (pdf-view-mode . pdf-view-midnight-minor-mode)) ;;;;; Outline Mode (use-feature outline :bind ("C-c M-o" . outline-minor-mode) :custom (outline-minor-mode-cycle t "Enable TAB (show/hide) & S-TAB (show/hide all)")) ;;;; RSS (use-package elfeed :custom (elfeed-db-directory (expand-file-name "elfeed" user-emacs-directory) "Relocate database") (elfeed-feeds '(("https://sachachua.com/blog/category/emacs-news/feed/" emacs) ("https://www.mozilla.org/en-US/careers/feed/" jobs) ("https://remotive.com/remote-jobs/feed/software-dev/" jobs) ("https://archlinux.org/feeds/news/" linux) ("https://artixlinux.org/feed.php" linux) ("https://www.debian.org/News/news" linux) ("https://news.opensuse.org/feed/" linux) ("https://rockylinux.org/rss.xml" linux) ("https://ziglang.org/devlog/index.xml" programming) ("https://ziglang.org/news/index.xml" programming) ("https://blog.rust-lang.org/" programming)) "The feeds") (elfeed-sort-order 'ascending "Oldest at top") :commands (elfeed) :config (add-hook 'elfeed-new-entry-hook (elfeed-make-tagger :feed-url "remotive\\.com" ;; REVIEW :entry-title "\\.\\(Senior.*\\|Staff.*\\|Principal.*\\)\\'" ;; :entry-title "Senior.*" :add 'junk :remove 'unread))) ;;;; Projects (use-feature project :custom (project-vc-extra-root-markers '("Cargo.toml") "Add Rust manifest file") :commands (project-find-dir project-find-file project-switch-project)) ;;;; Version Control ;;;;; Magit (use-package magit :custom (magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1 "I don't know what this actually does, I've had it set for years... let's see!") ;; #'magit-display-buffer-same-window-except-diff-v1) (transient-history-file (expand-file-name "transient-history" xdg_cache_home) "Relocate to XDG_CACHE_HOME") :defer t) ;;;;;; Transient ;; Magit requires higher version than built-in (use-package transient :defer t) ;;;;; Magit + Highlight Todos (use-package magit-todos :if (and (elpaca-installed-p 'magit) (elpaca-installed-p 'hl-todo)) :hook (magit-mode . magit-todos-mode)) (use-feature vc-hooks :custom (vc-follow-symlinks t "Always follow symlinks") :defer t) (add-to-list 'load-path "~/.config/emacs/lisp/") (require 'init-org) (require 'init-denote) (provide 'init) ;;; init.el ends here