dotfiles/dot_config/emacs/init.el.tmpl

1759 lines
52 KiB
Cheetah

;;; init.el --- GNU Emacs Initialization File -*- lexical-binding: t; -*-
;; Author: Andrew Scott <git at andyscott dot me>
;; 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:
<https://github.com/progfolio/.emacs.d?tab=readme-ov-file#use-package>"
(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:
<https://github.com/progfolio/elpaca/issues/216>"
(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
("<escape>" . 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-<left>" . shrink-window-horizontally)
("S-C-<right>" . enlarge-window-horizontally)
("S-C-<down>" . shrink-window)
("S-C-<up>" . 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
("<tab>" . 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: <https://github.com/joaotavora/eglot/discussions/898#discussioncomment-2609402>
(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