mirror of
https://codeberg.org/andyscott/dotfiles.git
synced 2024-12-22 09:53:10 -05:00
1085 lines
39 KiB
EmacsLisp
1085 lines
39 KiB
EmacsLisp
;;; init.el --- GNU Emacs Initialization File -*- lexical-binding: t; -*-
|
|
|
|
;; Author: Andrew Scott <git at andyscott dot me>
|
|
;; Keywords: convenience, tools
|
|
;; URL: https://codeberg.org/andyscott/dotfiles
|
|
|
|
;; This file is not part of GNU Emacs.
|
|
|
|
;; Copyright (c) 2023 Andrew Scott
|
|
|
|
;; MIT No Attribution
|
|
|
|
;; 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:
|
|
|
|
;; Profile init time
|
|
;; Replace `emacs-startup-hook' w/ `elpaca-after-init-hook' to profile `Elpaca'
|
|
(add-hook 'emacs-startup-hook
|
|
(lambda ()
|
|
(message "Emacs loaded in %s with %d garbage collections."
|
|
(format "%.2f seconds"
|
|
(float-time
|
|
(time-subtract (current-time) before-init-time)))
|
|
gcs-done)))
|
|
|
|
;; View profiler report after init
|
|
;; (profiler-start 'cpu+mem)
|
|
;; (add-hook 'elpaca-after-init-hook (lambda () (profiler-stop) (profiler-report)))
|
|
|
|
;; Profile function performance
|
|
;; (require 'elp)
|
|
;; (with-eval-after-load file
|
|
;; (elp-instrument-package file))
|
|
;; (add-hook 'elpaca-after-init-hook
|
|
;; (lambda () (elp-results) (elp-restore-package (intern file))))
|
|
|
|
;; 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))
|
|
|
|
;; Ensure `Elpaca' doesn't pull built-in packages from source
|
|
(defmacro use-feature (name &rest args)
|
|
"Like `use-package' but accounting for asynchronous installation.
|
|
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))
|
|
|
|
(elpaca elpaca-use-package
|
|
(require 'elpaca-use-package)
|
|
(elpaca-use-package-mode)
|
|
(setopt use-package-always-ensure t
|
|
;; REVIEW - apparently `use-package-always-pin' doesn't work with `Elpaca'
|
|
;; TODO - remove stats when done profiling startup
|
|
use-package-compute-statistics t))
|
|
|
|
(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))
|
|
|
|
;; Wait for `Elpaca' to process current queue
|
|
(elpaca-wait)
|
|
|
|
;;; Built-in Packages:
|
|
|
|
;; Revert a buffer if the file has changed
|
|
(use-feature autorevert
|
|
:config
|
|
(setopt auto-revert-interval 10)
|
|
(global-auto-revert-mode)
|
|
:defer 5
|
|
:init (setopt auto-revert-interval 0.01))
|
|
|
|
(use-feature bibtex
|
|
:after (ebib)
|
|
:config (setopt bibtex-autokey-additional-names "EtAl"
|
|
bibtex-autokey-edit-before-use t ; "t" by default
|
|
bibtex-autokey-expand-strings t
|
|
bibtex-autokey-name-case-convert-function #'capitalize
|
|
bibtex-autokey-name-year-separator ""
|
|
bibtex-autokey-names-stretch 1
|
|
bibtex-autokey-titlewords 2
|
|
bibtex-autokey-titlewords-stretch 1
|
|
bibtex-autokey-titleword-length #'infty
|
|
bibtex-autokey-titleword-separator ""
|
|
bibtex-autokey-titleword-case-convert-function #'capitalize
|
|
bibtex-autokey-year-length 4
|
|
bibtex-autokey-year-length 4
|
|
bibtex-autokey-year-title-separator ""))
|
|
|
|
(use-feature c-ts-mode
|
|
:commands (c-ts-mode)
|
|
:config
|
|
(setopt c-ts-mode-indent-style 'linux
|
|
c-ts-mode-indent-offset 8
|
|
indent-tabs-mode t))
|
|
|
|
|
|
(use-feature c++-ts-mode
|
|
:commands (c++-ts-mode)
|
|
:config
|
|
(setopt c++-ts-mode-indent-style 'gnu
|
|
c-ts-mode-indent-offset 4))
|
|
|
|
;; Customize compilation & related buffers
|
|
(use-feature compile
|
|
:commands (compile recompile)
|
|
:config (setopt compilation-ask-about-save nil
|
|
compilation-scroll-output 'first-error)
|
|
:hook (compilation-filter . ansi-color-compilation-buffer))
|
|
|
|
;; Write external customizations to /dev/null
|
|
(use-feature cus-edit
|
|
:init (setopt custom-file null-device))
|
|
|
|
;; Library for creating/customizing user options
|
|
(use-feature custom
|
|
:config (setopt custom-safe-themes t))
|
|
|
|
;; File manager
|
|
(use-feature dired
|
|
:commands (dired)
|
|
:config
|
|
(setopt dired-kill-when-opening-new-dired-buffer t
|
|
dired-mouse-drag-files t))
|
|
|
|
;; Customize fill column indicator
|
|
(use-feature display-fill-column-indicator
|
|
:hook ((conf-mode
|
|
markdown-mode
|
|
prog-mode) . display-fill-column-indicator-mode))
|
|
|
|
;; Customize line number display
|
|
(use-feature display-line-numbers
|
|
:hook ((conf-mode
|
|
prog-mode) . display-line-numbers-mode))
|
|
|
|
;; Customize LSP options
|
|
(use-feature eglot
|
|
:bind
|
|
(:map eglot-mode-map
|
|
("C-c e a" . eglot-code-actions)
|
|
("C-c e o" . eglot-code-actions-organize-imports)
|
|
("C-c e r" . eglot-rename)
|
|
("C-c e f" . eglot-format))
|
|
:config
|
|
(add-to-list 'eglot-server-programs '(astro-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")))))
|
|
(setopt eglot-autoshutdown t
|
|
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"
|
|
))
|
|
:hook ((astro-mode
|
|
bash-ts-mode
|
|
c-ts-mode
|
|
c++-ts-mode
|
|
python-ts-mode
|
|
rust-ts-mode
|
|
sh-script
|
|
zig-mode) . eglot-ensure))
|
|
|
|
;; Automatic parenthesis/brackets matching
|
|
(use-feature elec-pair
|
|
:hook ((conf-mode
|
|
markdown-mode
|
|
prog-mode) . electric-pair-mode))
|
|
|
|
;; Options defined in C source code & other misc. global customizations
|
|
(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)
|
|
;; Escape behaves like C-g
|
|
("<escape>" . keyboard-escape-quit)
|
|
;; Resizing buffers
|
|
("S-C-<left>" . shrink-window-horizontally)
|
|
("S-C-<right>" . enlarge-window-horizontally)
|
|
("S-C-<down>" . shrink-window)
|
|
("S-C-<up>" . enlarge-window))
|
|
:config
|
|
(setopt completion-ignore-case t
|
|
cursor-type 'bar
|
|
enable-recursive-minibuffers t
|
|
fill-column 79
|
|
history-delete-duplicates t
|
|
minibuffer-prompt-properties ; Disable prompt in minibuffer
|
|
'(read-only t cursor-intangible t face minibuffer-prompt)
|
|
read-buffer-completion-ignore-case t
|
|
scroll-step 1
|
|
scroll-conservatively 1000
|
|
scroll-preserve-screen-position t
|
|
sentence-end-double-space nil
|
|
tab-always-indent 'complete
|
|
use-short-answers t)
|
|
:hook (minibuffer-setup . cursor-intangible-mode)
|
|
:init
|
|
(defun my-kill-buffer ()
|
|
(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)))))
|
|
;; For Vertico
|
|
(defun crm-indicator (args)
|
|
(cons (format "[CRM%s] %s"
|
|
(replace-regexp-in-string
|
|
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
|
|
crm-separator)
|
|
(car args))
|
|
(cdr args)))
|
|
(advice-add #'completing-read-multiple :filter-args #'crm-indicator))
|
|
|
|
;; Customize file handling & automatic backups
|
|
(use-feature files
|
|
:config
|
|
(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))))
|
|
(setopt backup-by-copying t
|
|
confirm-kill-processes nil
|
|
delete-old-versions t
|
|
kept-new-versions 5
|
|
kept-old-versions 3
|
|
require-final-newline t
|
|
version-control t)
|
|
;; Treesit doesn't play nice in Emacs 29
|
|
;; REVIEW: Putting this here for now because `major-mode-remap-alist' belongs to `files'
|
|
(add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode))
|
|
(add-to-list 'major-mode-remap-alist '(python-mode . python-ts-mode)))
|
|
|
|
;; Customize syntax checking
|
|
(use-feature flymake
|
|
:bind
|
|
(:map flymake-mode-map
|
|
("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)))
|
|
|
|
;; Customize spell checking
|
|
(use-feature flyspell
|
|
:hook
|
|
(((git-commit-mode
|
|
org-mode) . flyspell-mode))
|
|
:init (setopt flyspell-use-meta-tab nil))
|
|
|
|
;; Customize frame behavior/cursor blinking
|
|
(use-feature frame
|
|
:config (setopt blink-cursor-delay 1.0
|
|
blink-cursor-interval 0.75))
|
|
|
|
(use-feature help
|
|
:config (setopt help-enable-variable-value-editing t
|
|
help-window-select t)
|
|
:defer 3)
|
|
|
|
(use-feature minibuffer
|
|
:config (setopt read-file-name-completion-ignore-case t))
|
|
|
|
;; Ensure UTF-8 terminal encoding
|
|
(use-feature mule
|
|
:config (unless (display-graphic-p)
|
|
(set-terminal-coding-system 'utf-8)))
|
|
|
|
;; Customize mouse wheel
|
|
(use-feature mwheel
|
|
:config
|
|
(setopt mouse-wheel-follow-mouse t
|
|
mouse-wheel-progressive-speed nil
|
|
mouse-wheel-scroll-amount '(2 ((shift) . 1))))
|
|
|
|
;; Customize comment insertion
|
|
(use-feature newcomment
|
|
:config (setopt comment-style 'multi-line))
|
|
|
|
;; Visualize matching parenthesis/brackets
|
|
(use-feature paren
|
|
:hook ((conf-mode
|
|
markdown-mode
|
|
prog-mode) . show-paren-mode))
|
|
|
|
;; Enable smooth mouse wheel scrolling when available
|
|
(when (fboundp 'pixel-scroll-precision-mode)
|
|
(use-feature pixel-scroll
|
|
:config (pixel-scroll-precision-mode)
|
|
:defer 1))
|
|
|
|
;; Customize project management
|
|
(use-feature project
|
|
:commands (project-find-dir project-find-file project-switch-project)
|
|
:config (setopt project-vc-extra-root-markers '("Cargo.toml")))
|
|
|
|
;; Customize handling of recent files
|
|
(use-feature recentf
|
|
:config
|
|
(setopt recentf-auto-cleanup 600
|
|
recentf-max-menu-items 100
|
|
recentf-max-saved-items 100
|
|
recentf-save-file (expand-file-name "recentf" xdg_cache_home))
|
|
(recentf-mode))
|
|
|
|
;; Customize saving mini-buffer history
|
|
(use-feature savehist
|
|
:config
|
|
(setopt savehist-additional-variables '(compile-command kill-buffer kill-ring)
|
|
savehist-autosave-interval 120
|
|
savehist-file (expand-file-name "history" xdg_cache_home))
|
|
(savehist-mode)
|
|
:defer 1)
|
|
|
|
;; Customize saving place in files
|
|
(use-feature saveplace
|
|
:config
|
|
(setopt save-place-file (expand-file-name "places" xdg_cache_home))
|
|
(save-place-mode))
|
|
|
|
;; Unload `seq' before `Elpaca' starts building
|
|
;; https://github.com/progfolio/elpaca/issues/216#issuecomment-1868444883
|
|
(defun +elpaca-unload-seq (e)
|
|
(and (featurep 'seq) (unload-feature 'seq t))
|
|
(elpaca--continue-build e))
|
|
|
|
(defun +elpaca-seq-build-steps ()
|
|
(append (butlast (if (file-exists-p (expand-file-name "seq" elpaca-builds-directory))
|
|
elpaca--pre-built-steps elpaca-build-steps))
|
|
(list '+elpaca-unload-seq 'elpaca--activate-package)))
|
|
|
|
(use-package seq
|
|
:ensure `(seq :build ,(+elpaca-seq-build-steps)))
|
|
|
|
(use-feature shell
|
|
:hook (shell-mode . ansi-color-for-comint-mode-on))
|
|
|
|
;; "A grab-bag of basic Emacs commands"
|
|
(use-feature simple
|
|
:config
|
|
(setopt indent-tabs-mode nil
|
|
read-extended-command-predicate #'command-completion-default-include-p)
|
|
:hook
|
|
(((conf-mode
|
|
prog-mode) . column-number-mode)
|
|
(text-mode . auto-fill-mode)))
|
|
|
|
;; Customize tree-sitter parsing
|
|
(use-feature treesit
|
|
:config (setopt treesit-font-lock-level 4)
|
|
:defer 1)
|
|
|
|
;; Remember to take breaks
|
|
(use-feature type-break
|
|
:config (setopt type-break-keystroke-threshold '(nil . nil))
|
|
:commands (type-break-mode))
|
|
|
|
;; Customize whitespace visualization & cleanup
|
|
(use-feature whitespace
|
|
:config
|
|
(add-hook 'before-save-hook #'whitespace-cleanup)
|
|
(setopt whitespace-line-column nil
|
|
whitespace-style '(lines-char
|
|
missing-newline-at-eof
|
|
space-after-tab
|
|
space-before-tab
|
|
tabs
|
|
trailing))
|
|
:hook
|
|
((conf-mode
|
|
prog-mode
|
|
text-mode) . whitespace-mode))
|
|
|
|
;;; Packages:
|
|
|
|
;; `other-window' replacement
|
|
(use-package ace-window
|
|
:commands (ace-window)
|
|
:bind ("C-c w" . ace-window))
|
|
|
|
;; Shows current/total matches in mode line
|
|
(use-package anzu
|
|
:config (global-anzu-mode)
|
|
:defer 3)
|
|
|
|
;; Auto-format
|
|
(use-package apheleia
|
|
:defer t)
|
|
|
|
(use-package biblio
|
|
:after (ebib)
|
|
:config (setopt biblio-bibtex-use-autokey t))
|
|
|
|
;; Extensions for `completion-at-point'
|
|
(use-package cape
|
|
:bind ("M-p" . cape-prefix-map))
|
|
|
|
;; TODO: pick a theme
|
|
;; Catppuccin theme
|
|
(use-package catppuccin-theme
|
|
:disabled
|
|
:config
|
|
(setopt catppuccin-flavor 'macchiato)
|
|
;; (catppuccin-reload)
|
|
;; (load-theme 'catppuccin t)
|
|
)
|
|
|
|
;; C/C++ formatting
|
|
;; Ad hoc format file: clang-format -style=webkit -dump-config > .clang-format
|
|
(use-package clang-format
|
|
:commands (clang-format clang-format-buffer clang-format-region)
|
|
:config (setopt clang-format-fallback-style "webkit"
|
|
clang-format-style "file"))
|
|
|
|
;; Search and navigation
|
|
(use-package consult
|
|
:bind (;; C-c bindings in `mode-specific-map'
|
|
("C-c M-x" . consult-mode-command)
|
|
("C-c h" . consult-history)
|
|
("C-c k" . consult-kmacro)
|
|
("C-c m" . consult-man)
|
|
("C-c i" . consult-info)
|
|
([remap Info-search] . consult-info)
|
|
;; C-x bindings in `ctl-x-map'
|
|
("C-x M-:" . consult-complex-command) ; orig. repeat-complex-command
|
|
("C-x b" . consult-buffer) ; orig. switch-to-buffer
|
|
("C-x 4 b" . consult-buffer-other-window) ; orig. switch-to-buffer-other-window
|
|
("C-x 5 b" . consult-buffer-other-frame) ; orig. switch-to-buffer-other-frame
|
|
("C-x 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)
|
|
:map as/org-prefix-map ; orig. previous-matching-history-element
|
|
("h" . consult-org-heading)
|
|
("a" . consult-org-agenda))
|
|
:config
|
|
(setopt consult-narrow-key "<")
|
|
:init
|
|
;; Register formatting
|
|
(setopt register-preview-delay 0.6
|
|
register-preview-function #'consult-register-format)
|
|
;; Register preview window
|
|
(advice-add #'register-preview :override #'consult-register-window)
|
|
;; Select xref locations with preview
|
|
(setopt xref-show-xrefs-function #'consult-xref
|
|
xref-show-definitions-function #'consult-xref))
|
|
|
|
(use-package consult-dir
|
|
:after (consult)
|
|
:bind (("C-x C-d" . consult-dir)
|
|
:map vertico-map
|
|
("C-x C-d" . consult-dir)
|
|
("C-x C-j" . consult-dir-jump-file)))
|
|
|
|
;; UI for the workspace/symbols procedure calls
|
|
(use-package consult-eglot
|
|
:after (eglot)
|
|
:bind
|
|
(:map eglot-mode-map
|
|
("C-c e s" . consult-eglot-symbols)))
|
|
|
|
;; In-buffer completion with popup menu
|
|
(use-package company
|
|
:disabled
|
|
:bind
|
|
(:map company-active-map
|
|
("RET" . nil)
|
|
("[return]" . nil)
|
|
("TAB" . company-complete-selection)
|
|
("<tab>" . company-complete-selection)
|
|
("C-n" . company-select-next)
|
|
("C-p" . company-select-previous))
|
|
:config
|
|
(setopt company-global-modes '(not gud-mode not comint-mode)
|
|
company-tooltip-align-annotations t)
|
|
:hook (prog-mode . company-mode))
|
|
|
|
;; In-buffer completion with popup menu
|
|
(use-package corfu
|
|
:config
|
|
(advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)
|
|
(advice-add 'eglot-completion-at-point :around #'cape-wrap-noninterruptible)
|
|
(setopt corfu-auto nil
|
|
corfu-cycle t
|
|
corfu-preview-current nil)
|
|
(global-corfu-mode)
|
|
(corfu-history-mode)
|
|
(corfu-popupinfo-mode)
|
|
:defer 3
|
|
:ensure (corfu :files (:defaults "extensions/*")))
|
|
|
|
(use-package ebib
|
|
;;; Functions:
|
|
;; ebib-list-recent ; list entries added within the given # of days
|
|
;; ebib-download-url ; attempt to download file, rename, and save to target directory, filename determined by `ebib-name-transform-function'
|
|
;; ebib-import-file ; import a local file, file is renamed and moved, works for more than pdf, name deterined by `ebib-name-transform-function'
|
|
;;; ebib-biblio
|
|
;; ebib-biblio-selection-import ; function to import entry from biblio into ebib
|
|
;; ebib-biblio-import-doi ; function to import an entry while in ebib UI, can also choose different key
|
|
|
|
;;; keymaps
|
|
;; ebib-index-mode-map
|
|
;; ebib-entry-mode-map
|
|
;; ebib-strings-mode-map
|
|
;; ebib-multiline-mode-map
|
|
;; ebib-search-map
|
|
;; ebib-filters-map
|
|
;; ebib-keywords-map
|
|
;; ebib-reading-list-map
|
|
;; ebib-log-mode-map
|
|
:commands (ebib)
|
|
:config
|
|
|
|
;; ebib-autogenerate-keys ; default t
|
|
(setopt ebib-bibtex-dialect 'biblatex
|
|
ebib-use-timestamp t ; create timestamp when entry added to db, note that "When importing or exporting entries, existing timestamps are overwritten."
|
|
ebib-filters-default-file (expand-file-name "ebib-filters" user-emacs-directory) ; file location to save filters
|
|
ebib-allow-identical-fields t ; merge repeated fields into one, separated by `ebib-keywords-separator'
|
|
ebib-file-associations '(("pdf" . nil)
|
|
("ps" . "gs")) ; specify which programs to use for which file types, or remove to open in emacs
|
|
ebib-import-target-directory "~/Nextcloud/Library/" ; set directory for `ebib-download-url' and `ebib-import-file'
|
|
;; ebib-default-directory "~/Nextcloud/Library/"; "This mainly determines which directory is the default directory when reading a file name from the user"
|
|
ebib-preload-bib-files '("~/Nextcloud/Library/bib/library.bib") ; autoload list of .bib files when started
|
|
;; ebib-bib-search dirs ; specify directory to search for multiple bib files when starting
|
|
;; ebib-extra-fields ; probably not needed
|
|
|
|
;;; UI
|
|
;; ebib-index-columns ; change displayed UI fields
|
|
;; ebib-field-transformation-functions ; new/change UI fields
|
|
;; ebib-field-sort-functions-alist ; customize UI sorting
|
|
;; ebib-edit-fields-functions ; disable/enable completion for different UI fields
|
|
;; ebib-multiline-display-function ; customize multiline values in UI
|
|
;; ebib-multiline-display-max-lines ; customize multiline values in UI
|
|
;; ebib-hidden-fields ; control which UI fields are hidden
|
|
;; ebib-save-indent-as-bibtex ; spaces instead of tabs in bib files, uses value of `bibtex-entry-offset' and `bibtex-field-indentation' to compute # of spaces
|
|
;; ebib-biblatex-ineritances ; customize biblatex inheritance
|
|
|
|
;;; Editing
|
|
;; ebib-save-xrefs-first ; must be enabled for cross-referencing to work, unless sort order changed?
|
|
;; ebib-sort-order ; change sort order of bib file - default is by key - make sure to unset `ebib-save-xrefs-first'
|
|
;; ebib-multiline-major-mode ; customize major mode for `ebib-multiline-edit-mode'
|
|
;; ebib-citation-commands ; might need to customize if using BibTex, which I'm not
|
|
;; ebib-citations-insert-multiple ; enable adding multiple citations at once, likely not needed
|
|
;; ebib-filters-ignore-case ; case-insensitive search filters are default
|
|
|
|
;;; Downloading/Filenames
|
|
;; ebib-name-transform-function ; modify file name that ebib searches for when associating a file with an entry
|
|
;; ebib-url-download-transformations ; sets how URLs are converted when attempting to download
|
|
|
|
;;; Notes
|
|
;; ebib-notes-storage 'multiple-notes-per-file ; probabably set to `multiple-notes-per-file' for org?
|
|
;; ebib-notes-locations ; files/directories containing notes
|
|
;; ebib-notes-default-file ; not used if creating note via org capture, but can still be set
|
|
|
|
;;; Org-capture
|
|
;; ebib-notes-use-org-capture ; set to desired keybind for ebib to skip org capture selection and use the one specified
|
|
;; ebib-org-capture ; function to call org capture from ebib
|
|
|
|
;;; Reading list
|
|
;; ebib-reading-list-file ; location of reading list
|
|
;; ebib-reading-list-todo-marker ; change default todo state for reading list items
|
|
;; ebib-reading-list-template ; change format of reading list items, available options in `ebib-reading-list-template-specifiers'
|
|
;; ebib-reading-list-add-item-function ; change where new items should be added
|
|
;; ebib-reading-list-remove-item ; by default only set to `ebib-reading-list-mark-item-as-done' - doesn't actually remove anything
|
|
|
|
;;; Keywords
|
|
;; ebib-keywords ; specify named keywords always available for completion
|
|
|
|
;;; Display options
|
|
;; ebib-windows ; customization group to change display
|
|
|
|
;;; Copying from ebib
|
|
;; ebib-reference-templates and ebib-citation-template ; change how entries are copied into kill ring
|
|
|
|
;;; org-ebib
|
|
;; org-ebib-link-type 'multiple-notes-per-file ; specify type of link produced by `org-store-link' on bib entries
|
|
)
|
|
)
|
|
|
|
(use-package ebib-biblio
|
|
:after (ebib biblio)
|
|
:bind
|
|
(:map ebib-index-mode-map
|
|
("B" . ebib-biblio-import-doi))
|
|
(:map biblio-selection-mode-map
|
|
("e" . ebib-biblio-selection-import))
|
|
:ensure nil)
|
|
|
|
;; Use `emacs-lsp-booster' with `Eglot'
|
|
(use-package eglot-booster
|
|
:after eglot
|
|
:config (eglot-booster-mode)
|
|
:ensure (eglot-booster :host github :repo "jdtsmith/eglot-booster"))
|
|
|
|
;; Command menu for items around point
|
|
(use-package embark
|
|
:bind
|
|
(("C-." . embark-act)
|
|
("C-;" . embark-dwim)
|
|
("C-h B" . embark-bindings))
|
|
:config
|
|
;; Hide the Embark live/completions buffer mode line
|
|
(add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
|
|
nil
|
|
(window-parameters (mode-line-format . none))))
|
|
:defer 3
|
|
:init (setopt prefix-help-command #'embark-prefix-help-command))
|
|
|
|
;; Integration between `embark' and `consult'
|
|
(use-package embark-consult
|
|
:hook (embark-collect-mode . consult-preview-at-point-mode))
|
|
|
|
;; Startup screen
|
|
(use-package enlight
|
|
:after (grid)
|
|
: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"
|
|
("My Agenda" (org-agenda nil "y") "y")
|
|
("Work Agenda" (org-agenda nil "w") "w")
|
|
("Time blocking" org-timeblock "b")
|
|
("Match Tags" (org-agenda nil "m") "m"))))
|
|
" "
|
|
,(enlight-menu
|
|
`(("Settings"
|
|
("Elpaca" elpaca-manager "L")
|
|
("Emacs"
|
|
(progn
|
|
(find-file ,user-init-file))
|
|
"I")
|
|
("Enlight"
|
|
(progn
|
|
(find-file ,user-init-file)
|
|
(goto-char (point-min))
|
|
(search-forward "use-package enlight"))
|
|
"E")
|
|
("Org"
|
|
(progn
|
|
(find-file ,(replace-regexp-in-string "init.el" "lisp/init-org.el" user-init-file)))
|
|
"O")))))))
|
|
(enlight-open))
|
|
|
|
;; Correction functions for `flyspell'
|
|
(use-package flyspell-correct
|
|
:after (flyspell)
|
|
:bind
|
|
(:map flyspell-mode-map
|
|
("C-M-." . flyspell-correct-wrapper)))
|
|
|
|
;; Grid for `enlight'
|
|
(use-package grid
|
|
:ensure (:host github :repo "ichernyshovvv/grid.el"))
|
|
|
|
;; Highlight keywords
|
|
(use-package hl-todo
|
|
: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))
|
|
:config
|
|
(setopt hl-todo-highlight-punctuation ":!?"
|
|
hl-todo-keyword-faces '(("DEBUG" warning bold)
|
|
("HACK" warning bold)
|
|
("FIXME" error bold)
|
|
("NOTE" homoglyph italic)
|
|
("REVIEW" homoglyph italic)
|
|
("TODO" homoglyph bold)))
|
|
:ensure (hl-todo :depth nil)
|
|
:hook (prog-mode . hl-todo-mode))
|
|
|
|
;; Search `hl-todo' buffers with `consult'
|
|
(use-package consult-todo
|
|
: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)))
|
|
|
|
;; Icons for `corfu'
|
|
(use-package kind-icon
|
|
:disabled
|
|
:after (corfu)
|
|
:config
|
|
;; Using nerd icons below
|
|
;; (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)
|
|
(setopt kind-icon-default-face 'corfu-default))
|
|
|
|
;; Git
|
|
;; Required by `magit' for menus
|
|
(use-package transient
|
|
:defer t)
|
|
|
|
(use-package magit
|
|
:bind ("C-M-;" . magit-status)
|
|
:config
|
|
(setopt magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1
|
|
transient-history-file (expand-file-name "transient-history" xdg_cache_home)))
|
|
|
|
;; Show `hl-todo' keywords in `magit' status buffers
|
|
(use-package magit-todos
|
|
:hook (magit-mode . magit-todos-mode))
|
|
|
|
;; Better annotations
|
|
(use-package marginalia
|
|
:config (marginalia-mode)
|
|
:defer 1)
|
|
|
|
;; File format/markup support
|
|
(use-package markdown-mode
|
|
:bind
|
|
(:map markdown-mode-map
|
|
("C-M-i" . fill-paragraph))
|
|
:commands (markdown-mode))
|
|
|
|
;; Better C++ font locking
|
|
(use-package modern-cpp-font-lock
|
|
:hook (c++-ts-mode . modern-c++-font-lock-mode))
|
|
|
|
;; Mode line
|
|
(use-package moody
|
|
:config
|
|
(setq x-underline-at-descent-line t)
|
|
(moody-replace-eldoc-minibuffer-message-function)
|
|
(moody-replace-mode-line-buffer-identification)
|
|
(moody-replace-mode-line-front-space)
|
|
(moody-replace-vc-mode)
|
|
:defer 1)
|
|
|
|
;; Menu for minor modes in `minor-mode-list'
|
|
(use-package minions
|
|
:after (moody)
|
|
:config (minions-mode))
|
|
|
|
;; Nerd icons for various modes & packages
|
|
(use-package nerd-icons
|
|
:defer 1)
|
|
|
|
(use-package nerd-icons-completion
|
|
:after (nerd-icons marginalia)
|
|
:config (nerd-icons-completion-mode)
|
|
:hook (marginalia-mode . nerd-icons-completion-marginalia-setup))
|
|
|
|
(use-package nerd-icons-corfu
|
|
:after (nerd-icons corfu)
|
|
:config
|
|
(add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter))
|
|
|
|
(use-package nerd-icons-dired
|
|
:hook (dired-mode . nerd-icons-dired-mode))
|
|
|
|
(use-package nerd-icons-ibuffer
|
|
:hook (ibuffer-mode . nerd-icons-ibuffer-mode))
|
|
|
|
;; TODO: pick a theme
|
|
(use-package nimbus-theme
|
|
:config (load-theme 'nimbus))
|
|
|
|
;; EPUB
|
|
(use-package nov
|
|
:config (setopt nov-text-width 100)
|
|
:mode ("\\.epub\\'" . nov-mode))
|
|
|
|
;; Completion style
|
|
(use-package orderless
|
|
:config
|
|
(setopt completion-styles '(orderless basic)
|
|
completion-category-overrides '((file (styles basic partial-completion)))
|
|
orderless-matching-styles '(orderless-regexp
|
|
orderless-literal
|
|
orderless-initialism))
|
|
:defer 1)
|
|
|
|
;; Better PDF viewing and navigation
|
|
(use-package pdf-tools
|
|
:config
|
|
(setopt pdf-info-epdfinfo-program (expand-file-name "pdf-tools/server/epdfinfo" elpaca-builds-directory)
|
|
pdf-view-resize-factor 1.1
|
|
pdf-view-display-size 'fit-page)
|
|
:ensure (pdf-tools :pre-build ("./server/autobuild") :files (:defaults ("lisp/*" "server/epdfinfo")))
|
|
:hook (pdf-view-mod . pdf-view-midnight-minor-mode)
|
|
:mode ("\\.pdf\\'" . pdf-view-mode))
|
|
|
|
;; Project Management - disabled, see `project' built-in package
|
|
(use-package projectile
|
|
:disabled
|
|
:bind ("C-c p" . projectile-command-map)
|
|
:config
|
|
(setopt projectile-known-projects-file (expand-file-name "projectile-bookmarks" xdg_cache_home)
|
|
projectile-project-search-path '(("~/Nextcloud/Projects/src/" . 2)))
|
|
(add-to-list 'projectile-globally-ignored-directories "*node_modules")
|
|
(projectile-mode))
|
|
|
|
;; Visualize color names
|
|
(use-package rainbow-mode
|
|
:hook ((conf-mode
|
|
prog-mode
|
|
toml-ts-mode) . rainbow-mode))
|
|
|
|
;; `gud' rewrite with additional features
|
|
(use-package realgud
|
|
:defer t)
|
|
|
|
;; `realgud' front-end for LLDB
|
|
(use-package realgud-lldb
|
|
:defer t)
|
|
|
|
(use-package rust-mode
|
|
:init (setopt rust-mode-treesitter-derive t)
|
|
:commands (rust-mode))
|
|
|
|
(use-package treemacs
|
|
:defer t
|
|
:commands (treemacs)
|
|
:config
|
|
(setopt treemacs-eldoc-display 'simple
|
|
treemacs-hide-dot-git-directory nil
|
|
treemacs-is-never-other-window t
|
|
treemacs-persist-file (expand-file-name "treemacs-persist" xdg_cache_home)
|
|
treemacs-text-scale 2
|
|
treemacs-width-is-initially-locked t)
|
|
(add-to-list 'treemacs-litter-directories "./zig-cache")
|
|
(treemacs-resize-icons 22)
|
|
(treemacs-follow-mode t)
|
|
(treemacs-filewatch-mode t)
|
|
(treemacs-fringe-indicator-mode 'always)
|
|
(treemacs-git-commit-diff-mode t)
|
|
(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
|
|
:after (treemacs magit))
|
|
|
|
;; Automatically download tree-sitter grammars
|
|
(use-package treesit-auto
|
|
:defer 1
|
|
:config
|
|
(setopt treesit-auto-install t)
|
|
(setq as/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 as/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\\'"))
|
|
(add-to-list 'treesit-auto-recipe-list as/c-tsauto-config)
|
|
(add-to-list 'treesit-auto-recipe-list as/cpp-tsauto-config)
|
|
;; (push as/c-tsauto-config treesit-auto-recipe-list)
|
|
;; (push as/cpp-tsauto-config treesit-auto-recipe-list)
|
|
(treesit-auto-add-to-auto-mode-alist 'all)
|
|
(global-treesit-auto-mode))
|
|
|
|
;; Better undo/redo
|
|
(use-package undo-fu
|
|
:bind (("C-z" . undo-fu-only-undo)
|
|
("C-S-z" . undo-fu-only-redo))
|
|
:defer 3)
|
|
|
|
(use-package undo-fu-session
|
|
:after (undo-fu)
|
|
:config
|
|
(setopt undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'")
|
|
undo-fu-session-directory (concat xdg_cache_home "undo-fu-session/"))
|
|
(undo-fu-session-global-mode))
|
|
|
|
;; Mini-buffer completion UI
|
|
(use-package vertico
|
|
:config
|
|
(setopt vertico-cycle t
|
|
vertico-count 10
|
|
vertico-resize t
|
|
vertico-scroll-margin 1)
|
|
:init (vertico-mode))
|
|
|
|
;; Web and SSG
|
|
(define-derived-mode astro-mode web-mode "astro")
|
|
(use-package web-mode
|
|
:config
|
|
(setopt web-mode-attribute-indent-offset 2
|
|
web-mode-code-indent-offset 2
|
|
web-mode-css-indent-offset 2
|
|
web-mode-markup-indent-offset 2
|
|
web-mode-enable-front-matter-block t
|
|
web-mode-engines-alist '(("blade" . "\\.blade\\.")
|
|
("razor" . "\\.cshtml\\'")))
|
|
:mode
|
|
("\\.astro\\'" . astro-mode)
|
|
("\\.\\(cshtml\\|html?\\|razor\\)\\'" . web-mode))
|
|
|
|
;; Show keybind hints
|
|
(use-package which-key
|
|
:config
|
|
(setopt which-key-idle-delay 0.3
|
|
;; which-key-sort-order 'which-key-description-order
|
|
which-key-side-window-max-width 0.33)
|
|
(which-key-mode)
|
|
:defer 1)
|
|
|
|
;; Expand abbreviations to templates
|
|
(use-package yasnippet
|
|
:bind
|
|
(;; :map yas-minor-mode-map ; need to enable mode with something other than `:commands'
|
|
("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'
|
|
(yas-minor-mode))
|
|
|
|
(use-package yasnippet-snippets
|
|
:after (yasnippet))
|
|
|
|
(use-package consult-yasnippet
|
|
:after (consult yasnippet)
|
|
:bind
|
|
(:map yas-minor-mode-map
|
|
("C-c y c" . consult-yasnippet)))
|
|
|
|
;; YAML
|
|
(use-package yaml-pro
|
|
:hook (yaml-ts-mode . yaml-pro-ts-mode))
|
|
|
|
;; Zig
|
|
(use-package reformatter ; required for `zig-format' functions
|
|
:after (zig-mode))
|
|
(use-package zig-mode
|
|
:commands (zig-mode)
|
|
: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"))
|
|
(setopt fill-column 100
|
|
zig-format-on-save nil))
|
|
|
|
(add-to-list 'load-path "~/.config/emacs/lisp/")
|
|
(require 'init-org)
|
|
|
|
;;; init.el ends here
|