From 3047f2deb133c93044c96665cc3729047b095099 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Thu, 28 Nov 2024 12:41:56 -0500 Subject: [PATCH] Emacs: restructure and switch from org-roam to denote --- .../{early-init.el.tmpl => early-init.el} | 19 +- dot_config/emacs/init.el | 1085 ---------- dot_config/emacs/init.el.tmpl | 1759 +++++++++++++++++ dot_config/emacs/lisp/init-denote.el | 132 ++ dot_config/emacs/lisp/init-org-roam.el | 86 + dot_config/emacs/lisp/init-org.el | 889 +++++---- dot_config/emacs/lisp/init-org.old.el | 490 +++++ 7 files changed, 2945 insertions(+), 1515 deletions(-) rename dot_config/emacs/{early-init.el.tmpl => early-init.el} (89%) delete mode 100644 dot_config/emacs/init.el create mode 100644 dot_config/emacs/init.el.tmpl create mode 100644 dot_config/emacs/lisp/init-denote.el create mode 100644 dot_config/emacs/lisp/init-org-roam.el create mode 100644 dot_config/emacs/lisp/init-org.old.el diff --git a/dot_config/emacs/early-init.el.tmpl b/dot_config/emacs/early-init.el similarity index 89% rename from dot_config/emacs/early-init.el.tmpl rename to dot_config/emacs/early-init.el index 7466036..b69f826 100644 --- a/dot_config/emacs/early-init.el.tmpl +++ b/dot_config/emacs/early-init.el @@ -101,20 +101,13 @@ orig_fg)))) ;; Fonts -{{- if eq .chezmoi.hostname "helix" }} -(push '(font . "Hack-14") default-frame-alist) -(set-face-font 'default "Hack-14") -(set-face-font 'fixed-pitch "Hack-14") -(set-face-font 'variable-pitch "DejaVu Sans-14") -{{- else }} -(push '(font . "Hack-11") default-frame-alist) -(set-face-font 'default "Hack-11") -(set-face-font 'fixed-pitch "Hack-11") -(set-face-font 'variable-pitch "DejaVu Sans-11") -{{- end }} +;; (set-face-font 'default "Hack-14") +;; (set-face-font 'fixed-pitch "Hack-14") +;; (set-face-font 'variable-pitch "DejaVu Sans-14") -;; Some GUI options -(let ((options '((undecorated . t) +;; Some UI options +(let ((options '((font . "Hack-14") + (undecorated . t) (menu-bar-lines . 0) (tool-bar-lines . 0) (vertical-scroll-bars) diff --git a/dot_config/emacs/init.el b/dot_config/emacs/init.el deleted file mode 100644 index 23922eb..0000000 --- a/dot_config/emacs/init.el +++ /dev/null @@ -1,1085 +0,0 @@ -;;; init.el --- GNU Emacs Initialization File -*- lexical-binding: t; -*- - -;; Author: Andrew Scott -;; 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 - ("" . keyboard-escape-quit) - ;; Resizing buffers - ("S-C-" . shrink-window-horizontally) - ("S-C-" . enlarge-window-horizontally) - ("S-C-" . shrink-window) - ("S-C-" . 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) - ("" . 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 diff --git a/dot_config/emacs/init.el.tmpl b/dot_config/emacs/init.el.tmpl new file mode 100644 index 0000000..bdf5719 --- /dev/null +++ b/dot_config/emacs/init.el.tmpl @@ -0,0 +1,1759 @@ +;;; 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 diff --git a/dot_config/emacs/lisp/init-denote.el b/dot_config/emacs/lisp/init-denote.el new file mode 100644 index 0000000..847feeb --- /dev/null +++ b/dot_config/emacs/lisp/init-denote.el @@ -0,0 +1,132 @@ +;;; init-denote.el --- denote customizations -*- lexical-binding: t -*- + +;; Author: Andrew Scott +;; Keywords: denote, convenience, tools +;; URL: https://codeberg.org/andyscott/dotfiles + +;; This file is not part of GNU Emacs + +;; Copyright (c) 2024 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 denote customizations. + +;;; Code: + +;;;; Denote + +(use-package denote + :ensure + (denote :files (:defaults "denote.*el")) + :custom + (denote-directory (expand-file-name "notes" org-directory)) + (denote-known-keywords '("emacs" "projects") "Change default keywords") + ;; TODO: Make a decision about links + ;; (denote-org-store-link-to-heading 'context "Store denote links with headings") + (denote-prompts '(file-type title keywords) "Add `file-type'") + (denote-templates `((algo-practice . ,(concat "#+url:\n" + "#+difficulty:\n" + "#+topics:\n\n" + "* Tasks\n\n" + "* Input\n\n" + "* Notes\n\n" + "* Solution"))) "Add templates") + :bind + ;; (:map dired-mode-map + ;; ("" . denote-dired-rename-marked-files-using-front-matter) + ;; ("" . denote-dired-rename-marked-files-with-keywords) + ;; ("" . denote-dired-rename-files)) + ;; (:map org-mode-map + ;; ("" . denote-org-extras-backlinks-for-heading) + ;; ("" . denote-org-extras-dblock-insert-links) + ;; ("" . denote-org-extras-dblock-insert-backlinks) + ;; ("" . denote-org-extras-link-to-heading) ; Prompt for file/heading, add link at point + ;; ("" . denote-org-store-link-to-heading) ; Create CUSTOM_ID to heading and store link + ;; ) + (:prefix-map as/denote-prefix-map + :prefix "C-c d") + (:map as/denote-prefix-map + ;; Creating notes + ("n" . denote) + ("r" . denote-region) + ("t" . denote-template) + ;; Dired + ("d" . denote-sort-dired) + ;; Opening/creating + ("f" . denote-open-or-create) + ("F" . denote-open-or-create-with-command) + ;; Linking + ("a" . denote-add-links) ; Link to all notes matching a regex + ("b" . denote-backlinks) ; Create a buffer with backlinks + ("l" . denote-link) ; Insert a link to another note + ("L" . denote-link-or-create) ; Link to the target file, creating the file if needed + ("C-l" . denote-link-after-creating) ; Create a file in the background, then link to it in the current file + ("C-f" . denote-find-backlink) ; Use minibuffer completion to find backlinks + ;; Renaming + ("C" . denote-change-file-type-and-front-matter) + ("R" . denote-rename-file) + ;; Silos + ("s n" . denote-silo-extras-create-note) + ("s f" . denote-silo-extras-open-or-create) + ("s F" . denote-silo-extras-select-silo-then-command)) + :hook + (dired-mode . denote-dired-mode) + (text-mode . denote-fontify-links-mode-maybe) + :config + (denote-rename-buffer-mode)) + +;;;;; Consult Notes + +(use-package consult-notes + :custom + (consult-notes-file-dir-sources + `(("Org" ?o ,org-directory) + ("Projects" ?r ,(expand-file-name "projects" org-directory))) "Note locations w/ narrowing key") + ;; (consult-notes-org-headings-files '("~/path/to/file1.org" + ;; "~/path/to/file2.org") "Files for `consult-org-headings-mode'") + :bind + (:map as/denote-prefix-map + ("c" . consult-notes) + ("a" . consult-notes-search-in-all-notes)) + :config + ;; (consult-notes-org-headings-mode) + (consult-notes-denote-mode)) + + + +;;;;; Citar + Denote + +(use-package citar-denote + :if + (and (elpaca-installed-p 'denote) + (elpaca-installed-p 'citar)) + :custom + (citar-denote-keyword "bib") + (citar-denote-file-type 'org) + (citar-denote-title-format-authors 2) + :bind + (:map as/denote-prefix-map + ("C-c a" . citar-denote-add-citekey) + ("C-c d" . citar-denote-dwim) + ("C-c f" . citar-denote-open-note)) + :config + (citar-denote-mode)) + +(provide 'init-denote) +;;; init-denote.el ends here diff --git a/dot_config/emacs/lisp/init-org-roam.el b/dot_config/emacs/lisp/init-org-roam.el new file mode 100644 index 0000000..ed35c7f --- /dev/null +++ b/dot_config/emacs/lisp/init-org-roam.el @@ -0,0 +1,86 @@ +;;;;; Org Roam + +(use-package org-roam + :ensure + (org-roam :files (:defaults "extensions/*")) + :after + (org) + :custom + (org-roam-database-connector 'sqlite-builtin "Use built-in sqlite") + (org-roam-directory + (file-name-as-directory (expand-file-name "roam" org-directory)) "Set org-roam directory") + (org-roam-db-gc-threshold most-positive-fixnum "Limit GC during sync") + :bind + (:prefix-map as/org-roam-prefix-map + :prefix "C-c r") + (:map as/org-roam-prefix-map + ("a" . org-roam-alias-add) + ("A" . org-roam-alias-remove) + ("b" . org-roam-buffer-display-dedicated) + ("c" . org-roam-capture) + ("f" . org-roam-node-find) + ("i" . org-roam-node-insert) + ("s" . org-roam-db-sync)) + :config + (add-to-list 'display-buffer-alist + '("\\*org-roam\\*" + (display-buffer-in-direction) + (direction . right) + (window-width . 0.33) + (window-height . fit-window-to-buffer))) + (add-to-list 'org-roam-capture-templates + '("r" "reference" plain + "%?" + :target + (file+head "references/${citar-citekey}.org" + "#+title: ${note-title}\n") + :empty-lines 1 + :unnarrowed t + )) + (add-to-list 'org-roam-capture-templates + `("p" "project" plain (file ,(concat org-roam-directory + "/templates/projects.org")) + :target + (file+head "projects/%<%Y%m%d%H%M%S>-${slug}.org" + "#+title: ${title}\n#+filetags: :projects:") + :empty-lines 1 + :unnarrowed t)) + (add-to-list 'org-roam-capture-templates + `("j" "job" plain (file ,(concat org-roam-directory + "/templates/job_applications.org")) + :target + (file+head "projects/job_applications/%<%Y%m%d%H%M%S>-${slug}.org" + "#+title: ${title}\n#+filetags: :job_search:") + :empty-lines 1 + :unnarrowed t)) + (org-roam-db-autosync-mode)) + +;;;;;; Org Roam UI + +(use-package org-roam-ui + :if + (elpaca-installed-p 'org-roam) + :after + (org-roam) + :custom + (org-roam-ui-follow nil "Don't update UI when point moves") + :bind + (:map as/org-roam-prefix-map + ("u" . org-roam-ui-open))) + +;;;;;; Citar + Roam + +(use-package citar-org-roam + :if + (and (elpaca-installed-p 'citar) + (elpaca-installed-p 'org-roam)) + :after + (citar org-roam) + :custom + (citar-org-roam-capture-template-key "r" "Define which template to use") + (citar-org-roam-note-title-template "${title} by ${author}" "Default note title") + (citar-org-roam-subdir "references" "Default note directory") + :config + ;; NOTE: Trying `citar-denote' + ;; (citar-org-roam-mode) + ) diff --git a/dot_config/emacs/lisp/init-org.el b/dot_config/emacs/lisp/init-org.el index d787b90..d14ec1f 100644 --- a/dot_config/emacs/lisp/init-org.el +++ b/dot_config/emacs/lisp/init-org.el @@ -1,4 +1,4 @@ -;;; org-mode.el --- org-mode customizations -*- lexical-binding: t -*- +;;; init-org.el --- org-mode customizations -*- lexical-binding: t -*- ;; Author: Andrew Scott ;; Keywords: org, convenience, tools @@ -29,167 +29,259 @@ ;;; Code: -(use-package citar - :after (oc) - :config - (setopt citar-bibliography org-cite-global-bibliography - citar-library-paths '("~/Nextcloud/Library/")) - ;; (when (elpaca-installed-p 'citar-embark) - ;; (setopt citar-at-point-function 'embark-act)) - :hook (org-mode . citar-capf-setup)) +;;;; Org -(use-package citar-embark - :after (citar embark) - :config (citar-embark-mode)) +;;;;; Org Mode -(use-package citar-org-roam - :after (citar org-roam) - :config - (setopt citar-org-roam-capture-template-key "r" - citar-org-roam-note-title-template "${title} - ${author}" - citar-org-roam-subdir "references") - (citar-org-roam-mode)) +(use-feature org + :custom + ;;;;;; `org.el' + (org-directory (expand-file-name "~/Nextcloud/Documents/org")) + (org-adapt-indentation nil "No, see `org-indent-mode'") + (org-agenda-files (append + (directory-files org-directory t "\\`[^.].*\\.org\\'" t nil) + (directory-files (expand-file-name "projects" org-directory) t "\\`[^.].*\\.org\\'" t nil))) + (org-archive-location + (expand-file-name "archive/%s_archive::" org-directory) "Set location and format for archives") + (org-blank-before-new-entry '((heading . t) + (plain-list-item . auto)) "Heading: always, List: maybe") + (org-deadline-warning-days 5 "Decrease warning time") + (org-default-notes-file + (expand-file-name "inbox.org" org-directory) "Default file for `org-capture'") + ;; FIXME: `org-superstar' doesn't like this? + ;; (org-ellipsis " >> " "Until I can stop using ... myself...") + (org-enforce-todo-checkbox-dependencies t "Use checkboxes as blockers") + (org-hide-emphasis-markers t "Hide markers for italics/bold etm.") + (org-insert-heading-respect-content t "Add headlines to end of subtree") + (org-log-done 'time "Add timestamp when item completed") + (org-log-into-drawer t "Hide logs in a drawer") + (org-log-redeadline 'note "Require a note if deadline changes") + ;; (org-M-RET-may-split-line nil "Don't split when adding headings/items") + (org-pretty-entities t "Use UTF-8 for entities") + (org-pretty-entities-include-sub-superscripts nil "Don't mess with underscores") + (org-reverse-note-order t "Add/refile at the beginning") + (org-special-ctrl-a/e t "Once: Move point around headline text, Twice: move point normally") + ;; (org-special-ctrl-k t "Change behavior of `kill-line' depending on position") + (org-startup-folded 'show2levels "Show two headings only") + (org-startup-indented t "Turn on `org-indent-mode' automatically") + (org-startup-numerated t "Turn on `org-num-mode' automatically") + (org-tags-column 0 "Put tags right after headline") + ;; (org-tags-exclude-from-inheritance '("projects" + ;; "JobApplications" + ;; "Hybrid" + ;; "Remote" + ;; "InOffice") "Don't tag every headline") + (org-todo-keywords '((sequence "TODO(t)" + "NEXT(x)" + "PROG(p)" + "WAIT(w@/!)" + "|" + "DONE(d)" + "WONT(n@/!)") + (sequence "IDEA(i)" "|")) "Add NEXT, PROG, WAIT, WONT, IDEA") + (org-todo-repeat-to-state "TODO" "Reset to TODO regardless of previous state") -(use-package citeproc - :after (oc)) +;;;;;; `org-agenda.el' + (org-agenda-block-separator ?- "Use simple hyphens") + (org-agenda-skip-deadline-if-done t "Don't show deadline when already done") + ;; (org-agenda-skip-scheduled-if-deadline-is-shown nil "Show deadlines and schedules") + (org-agenda-skip-scheduled-if-done t "Don't show scheduled when already done") + (org-agenda-start-on-weekday nil "Start with today") + (org-agenda-start-with-log-mode '(clock closed state) "Show all logged items") + (org-agenda-tags-column 0 "Put tags right after headline") -(use-feature oc - :after (org) - :config - (setopt org-cite-export-processors '((latex biblatex) - (t csl)) - org-cite-global-bibliography '("~/Nextcloud/Library/bib/library.bib")) - (when (elpaca-installed-p 'citar) - (setopt org-cite-activate-processor 'citar - org-cite-follow-processor 'citar - org-cite-insert-processor 'citar))) + ;; REVIEW: Is this useful data to keep? + ;; :PROPERTIES: + ;; :CREATED: %U + ;; :END: -(use-feature oc-csl - :after (citeproc oc) - :config - (let ((zotero_styles (expand-file-name - "Zotero/styles/" (or (getenv "XDG_DATA_HOME") "~/.local/share/")))) - (if (file-directory-p zotero_styles) - (setopt org-cite-csl-styles-dir zotero_styles)))) +;;;;;; `org-capture.el' + (org-capture-templates + `(("i" "Inbox") + ("in" "Note" + entry (file+headline "inbox.org" "Notes") + "** %?" + :empty-lines 1) -(use-package org + ("it" "Task" entry (file+headline "inbox.org" "Tasks") + "** TODO [#B] %? +%i\n%a" + :empty-lines 1) + + ("d" "Denote" + plain (file denote-last-path) + #'denote-org-capture + :no-save t + :immediate-finish nil + :kill-buffer t + :jump-to-captured t) + + ("j" "Job Application" + entry (file+olp "projects/jobs.org" "Applications") + "*** TODO [#A] %^{Job Title} %^{Company} %?\nSCHEDULED: %t\n +**** Find Contacts at %\\2\nSCHEDULED: %t\n" + :clock-in t + :clock-keep t + :jump-to-captured t + :empty-lines 1))) + +;;;;;; `org-clock.el' + (org-clock-in-resume t "Resume if clock already started") + (org-clock-in-switch-to-state "PROG" "Switch items to In-Progress") + (org-clock-persist t "Save clock if Emacs is closed") + (org-clock-rounding-minutes 5 "Round to 5 minutes") + (org-clock-string-limit 30 "Don't crowd the mode line") + +;;;;;; `org-faces.el' - Custom Settings + (org-fontify-quote-and-verse-blocks t "Make #+begin_quote etm. look nicer") + (org-todo-keyword-faces '(("TODO" . (:inherit dired-mark :inverse-video t)) + ("PROG" . (:inherit match :inverse-video t)) + ("NEXT" . (:inherit dired-special :inverse-video t)) + ("WAIT" . (:inherit shadow :inverse-video t)) + ("WONT" . (:inherit org-done)) + ("DONE" . (:inherit org-done)) + ("IDEA" . (:inherit bold :inverse-video t)))) + (org-priority-faces '((?A . (:inherit error :weight semibold :inverse-video t)) + (?B . (:inherit warning :weight semibold :inverse-video t)) + (?C . (:inherit mode-line-inactive :weight semibold :inverse-video t)))) + +;;;;;; `org-fold.el' + (org-fold-catch-invisible-edits 'show-and-error "Abort edit, show point & throw error") + +;;;;;; `org-goto.el' + (org-goto-interface 'outline-path-completion "Use completion interface") + +;;;;;; `org-id.el' + (org-id-link-to-org-use-id 'create-if-interactive "Only if I say so") + (org-id-locations-file + (locate-user-emacs-file "org-id-locations") "Don't use a hidden file") + (org-id-method 'ts "Timestamps instead of UUID") + (org-id-ts-format "%Y%m%dT%H%M%S%z" "True ISO 8601 timestamp") + +;;;;;; `org-keys.el' + (org-mouse-1-follows-link 'double "Otherwise timestamps automatically open agenda") + (org-return-follows-link t "Follow links on RET") + (org-use-extra-keys t "Graphical users like useful keybinds too") + +;;;;;; `org-list.el' + (org-list-allow-alphabetical t "A. a. B. b. C. c. ...") + (org-list-demote-modify-bullet '(("+" . "-") + ("-" . "+") + ("*" . "+")) "Alternating bullets") + +;;;;;; `org-num.el' + (org-num-face 'org-level-6 "Use consistent face for num-mode") + +;;;;;; `org-refile.el' + (org-outline-path-complete-in-steps nil "Not needed with completion") + (org-refile-allow-creating-parent-nodes 'confirm "Ask before creating new nodes") + (org-refile-targets '((nil :maxlevel . 3) + (org-agenda-files :maxlevel . 2)) "Current file: 3 levels, Agenda files: 2 levels") + (org-refile-use-outline-path 'file "Include filename in path") + +;;;;;; `org-src.el' + (org-edit-src-content-indentation 0 "Don't indent after #+begin") + + :custom-face +;;;;;; `org-faces.el' - Custom Faces + ;; Headlines + (org-level-1 ((t (:inherit outline-1 :height 1.3)))) + (org-level-2 ((t (:inherit outline-2 :height 1.2)))) + (org-level-3 ((t (:inherit outline-3 :height 1.1)))) + ;; (org-level-4 ((t (:inherit outline-4 :height 1.2)))) + ;; (org-level-5 ((t (:inherit outline-5 :height 1.1)))) + ;; Ensure monospace Keywords/Tags/Blocks + (org-block ((t (:inherit fixed-pitch)))) ; inherited by `org-code' + (org-block-begin-line ((t (:inherit fixed-pitch)))) + (org-block-end-line ((t (:inherit (org-block-begin-line fixed-pitch))))) + (org-checkbox ((t (:inherit (org-todo fixed-pitch))))) + (org-checkbox-statistics-todo ((t (:inherit (org-todo fixed-pitch))))) + (org-date ((t (:inherit fixed-pitch)))) + (org-document-info-keyword ((t (:inherit (shadow fixed-pitch))))) + (org-drawer ((t (:inherit fixed-pitch)))) + (org-indent ((t (:inherit (org-hide fixed-pitch))))) + (org-link ((t (:foreground "dark cyan" :underline t)))) + (org-list-dt ((t (:inherit fixed-pitch)))) + (org-meta-line ((t (:inherit (fixed-pitch))))) + (org-property-value ((t (:inherit fixed-pitch)))) + (org-special-keyword ((t (:inherit fixed-pitch)))) + (org-table ((t (:inherit fixed-pitch)))) + (org-tag ((t (:inherit (fixed-pitch) :height 0.8)))) + (org-verbatim ((t (:inherit fixed-pitch)))) :bind - (:map global-map - ("C-c a" . org-agenda) - ("C-c c" . org-capture) - ("C-c l" . org-store-link)) + (:prefix-map as/org-prefix-map + :prefix "C-c o") + (:map as/org-prefix-map + ("a" . org-agenda) ; `org-agenda.el' + ("c" . org-capture) ; `org-capture.el' + ("g" . org-clock-goto) ; `org-clock.el' + ("H" . consult-org-agenda) ; `consult-org.el' + ("l" . org-store-link) ; `ol.el' + ("m" . org-tags-view)) ; `org-agenda.el' + (:map org-mode-map + ("C-c o c" . as/org-set-created-property) + ("C-c o d" . org-priority-down) + ("C-c o h" . consult-org-heading) ; `consult-org.el' + ("C-c o l" . embark-org-copy-link-target) ; `embark-org.el' + ("C-c o L" . org-toggle-link-display) ; `ol.el' + ("C-c o s" . org-insert-subheading) + ("C-c o u" . org-priority-up) + ("C-c o y" . org-todo-yesterday)) + :demand t + :hook + (org-mode . (lambda () + (setq-local fill-column 100) + (variable-pitch-mode) + (visual-line-fill-column-mode))) :config - ;; General options TODO: Comment various options more descriptively - (setopt org-agenda-block-separator nil - ;; org-agenda-files (list org-directory) - org-agenda-files (directory-files-recursively org-directory "org$") - org-agenda-skip-deadline-if-done nil - org-agenda-skip-scheduled-if-deadline-is-shown t - org-agenda-skip-scheduled-if-done nil - org-agenda-start-on-weekday nil - org-agenda-tags-column 0 - org-archive-location (expand-file-name "archive/%s_archive.org::" org-directory) - org-blank-before-new-entry '((heading . auto) - (plain-list-item . auto)) - org-deadline-warning-days 5 - org-enforce-todo-dependencies t - org-fold-catch-invisible-edits 'show-and-error - org-fontify-done-headline t - org-fontify-quote-and-verse-blocks t - org-fontify-todo-headline t - org-goto-interface 'outline-path-completion - org-hide-emphasis-markers t - org-insert-heading-respect-content t - org-log-done 'time - org-log-into-drawer t - org-log-redeadline 'time - org-log-refile 'note - org-log-reschedule 'time - org-outline-path-complete-in-steps nil - org-pretty-entities t - org-refile-allow-creating-parent-nodes 'confirm - org-refile-targets '((nil :maxlevel . 3) - (org-agenda-files :maxlevel . 2)) - org-refile-use-outline-path 'file - org-return-follows-link t - org-reverse-note-order t ; Add/refile notes at the beginning of an entry - org-special-ctrl-a/e t - org-src-preserve-indentation t - org-startup-folded 'fold - org-tags-column 0 - org-todo-keywords '((sequence "TODO(t)" - "NEXT(n)" - "PROG(p)" - "|" - "DONE(d!)" - "WONT(w@/!)") - (sequence "IDEA(i)" "|")) - org-todo-keyword-faces '(("TODO" . (dired-mark)) - ("PROG" . (success)) - ("NEXT" . (dired-special)) - ("WONT" . (org-done))) - org-todo-repeat-to-state "TODO") + (defun as/org-set-created-property () + "Add a CREATED property to org headlines with the current time" + (interactive) + (org-entry-put nil "CREATED" (format-time-string (org-time-stamp-format t t nil) (current-time))))) - (setq org-capture-templates - `( - ("i" "Inbox" entry (file "roam/inbox.org") - "* %?" - :empty-lines 1 - ) +;;;;; Appearance - ("j" "Log Entry" - entry (file+datetree "log.org") - "** %?" - :empty-lines 1) +;;;;;; Org Appear - ("n" "Note" - entry (file+headline "inbox.org" "Notes") - "** %? -:PROPERTIES: -:CREATED: %U -:END:" - :empty-lines 1) +(use-package org-appear + :custom + (org-appear-autoentities t "Toggle markers automatically") + (org-appear-autolinks 'just-brackets "Only show brackets, not target") + (org-appear-autosubmarkers t "Toggle sub/superscript markers automatically") + (org-appear-trigger 'on-change "Only auto-toggle if changed or selected") + :hook + (org-mode . org-appear-mode)) - ("t" "Todo" entry (file+headline "inbox.org" "Tasks") - "** TODO [#B] %? -:PROPERTIES: -:CREATED: %U -:END: -%i\n%a -Notes: " - :empty-lines 1) - ) - ) +;;;;;; Org Superstar - ;; Headline appearance - (custom-set-faces - '(org-level-1 ((t (:inherit outline-1 :height 1.5)))) - '(org-level-2 ((t (:inherit outline-2 :height 1.4)))) - '(org-level-3 ((t (:inherit outline-3 :height 1.3)))) - '(org-level-4 ((t (:inherit outline-4 :height 1.2)))) - '(org-level-5 ((t (:inherit outline-5 :height 1.1))))) - :hook (org-mode . org-indent-mode) - :init - (setopt org-directory "~/Nextcloud/Documents/org") - (bind-keys :prefix-map as/org-prefix-map - :prefix "C-c o" - ("n" . org-metadown) - ("p" . org-metaup) - ("f" . org-shiftmetaright) - ("b" . org-shiftmetaleft) - ("v" . org-tags-view) - ("y" . org-todo-yesterday) - ("l" . org-toggle-link-display) - ("C-n" . org-priority-down) - ("C-p" . org-priority-up))) +(use-package org-superstar + :custom + (org-superstar-headline-bullets-list '(?◉ ?🞛 ?○ ?▷ ?✸ ?✿) "Customize bullets") + (org-indent-mode-turns-on-hiding-stars nil "Required by `org-superstar-leading-bullet'") + (org-superstar-leading-bullet ?\s "Replace leading stars with 1 whitespace char") + (org-superstar-hide-leading-stars t "Enable hiding") + (org-superstar-special-todo-items t "Replace todo checkboxes") + (org-superstar-todo-bullet-alist '(("TODO" . ?☐) + ("NEXT" . ?☐) + ("PROG" . ?☐) + ("WAIT" . ?☐) + ("DONE" . ?☑) + ("WONT" . ?☑)) "Customize todo checkboxes") + :hook (org-mode . org-superstar-mode)) + +;;;;; Agenda + +;;;;;; Org Agenda (use-feature org-agenda - :after (org) + :after + (org) :bind (:map org-agenda-mode-map - ("C-c C-r" . as/org-agenda-reconcile-inbox-item)) - :config (setopt org-agenda-start-with-log-mode '(clock closed state)) - :init + ("C-c C-r" . as/org-agenda-reconcile-inbox-item) + ("C-c C-y" . org-agenda-todo-yesterday) + ("C-c o p" . org-pomodoro)) + :config (defun as/org-agenda-reconcile-inbox-item () "Process and refile an org-agenda item" (interactive) @@ -200,319 +292,282 @@ Notes: " (org-agenda-schedule nil nil)) (org-agenda-refile nil nil t)))) -(use-package org-appear - :config - (setopt org-appear-autoentities t - org-appear-autolinks nil - org-appear-autosubmarkers t - org-appear-trigger 'on-change) - :hook (org-mode . org-appear-mode)) - -(use-feature org-clock - :after (org) - :config - (setopt org-clock-in-resume t - org-clock-in-switch-to-state "PROG" - org-clock-persist t - org-clock-rounding-minutes 5)) - -(use-package org-edna - :config (setopt org-edna-finder-use-cache t) - :hook (org-mode . org-edna-mode)) - -(use-feature org-habit - :after (org) - ;; REVIEW: do I need to add to modules if it loads after org anyway? - :init (add-to-list 'org-modules 'org-habit t)) - -(use-feature org-id - :after (org) - :config - (setopt org-id-link-to-org-use-id t - org-id-locations-file (locate-user-emacs-file "org-id-locations") - org-id-method 'ts - org-id-ts-format "%Y%m%dT%H%M%S.%2N%z") - ;; REVIEW: do I need to add to modules if it loads after org anyway? - :init (add-to-list 'org-modules 'org-id t)) - -(use-package org-modern - :disabled t - :config - (setopt org-modern-block-name nil - org-modern-priority nil - org-modern-symbol "DejaVu Sans" - org-modern-todo nil - org-modern-tag nil - org-modern-timestamp nil) - :hook - (org-mode . org-modern-mode) - (org-agenda-finalize . org-modern-agenda)) - -(use-package org-noter - :after (org) - :config - (setopt org-noter-notes-search-path (list (concat org-directory "/roam"))) - (org-noter-enable-org-roam-integration)) - -(use-package org-pomodoro - :after (org-clock) - :commands (org-pomodoro) - :config - ;; (defun as/org-pomodoro-started-todo-update () - ;; "Update todo state when starting a pomodoro" - ;; (when (or (string= org-state "NEXT") - ;; (string= org-state "TODO")) - ;; (org-todo "PROG"))) - ;; (defun as/org-todo-state-maybe-update-pomodoro () - ;; "Update or start a pomodoro when changing todo state - - ;; REVIEW: This could be updated to always trigger a pomodoro change, like when - ;; changing state to PROG. This has the added benefit of making the above function - ;; redundent, as I could just use `org-todo' as a single start and end point for - ;; all pomodoros" - ;; (when (and (or (string= org-state "TODO") - ;; (string= org-state "DONE")) - ;; (org-pomodoro-active-p)) - ;; (org-pomodoro-kill))) - ;; (add-to-list 'org-after-todo-state-change-hook #'as/org-todo-state-change-maybe-kill-pomodoro) - ;; (add-to-list 'org-pomodoro-started-hook #'as/org-pomodoro-started-todo-update) - (setopt alert-user-configuration ; Send mesages to libnotify - '((((:category . "org-pomodoro")) libnotify nil)) - org-pomodoro-audio-player (executable-find "pw-cat") - org-pomodoro-keep-killed-pomodoro-time t - org-pomodoro-length 50 - org-pomodoro-short-break-length 10 - org-pomodoro-manual-break t) - :init - ;; (defun as/org-pomodoro-todo-state-trigger () - ;; "Starts or stops a pomodoro when todo state changes" - ;; (cond - ;; ((when (string= org-state "PROG") - ;; (if (org-pomodoro-active-p) - ;; ((org-pomodoro-kill) - ;; (org-pomodoro nil)) - ;; (org-pomodoro nil))) - ;; ((when (and (or (string= org-state "DONE") (string= org-state "TODO")) - ;; (org-pomodoro-active-p)) - ;; (org-pomodoro-kill)))))) - ;; (with-eval-after-load 'org-clock - ;; (add-to-list 'org-after-todo-state-change-hook #'as/org-pomodoro-todo-state-trigger)) - ) - -(use-package org-roam - :after (org) - :bind - (:map as/org-prefix-map - ("r i" . org-roam-node-insert) - ("r f" . org-roam-node-find) - ("r c" . org-roam-capture) - ;; REVIEW: Not sure if I really need these? - ;; ("r b" . org-roam-buffer-toggle) - ;; ("r d" . org-roam-buffer-display-dedicated) - ;; ("r a a" . org-roam-alias-add) - ;; ("r a r" . org-roam-alias-remove) - ;; ("r r a" . org-roam-ref-add) - ;; ("r r r" . org-roam-ref-remove) - ) - :config - (setopt org-roam-database-connector 'sqlite-builtin) - (setq org-roam-db-gc-threshold most-positive-fixnum) ; doesn't like the new `setopt' - (add-to-list 'display-buffer-alist - '("\\*org-roam\\*" - (display-buffer-in-direction) - (direction . right) - (window-width . 0.33) - (window-height . fit-window-to-buffer))) - (add-to-list 'org-roam-capture-templates - '("r" "reference" plain - "%?" - :target - (file+head "references/${citar-citekey}.org" - "#+title: Notes on: ${note-title}\n") - :empty-lines 1 - :unnarrowed t - )) - (add-to-list 'org-roam-capture-templates - `("p" "project" plain (file ,(concat org-roam-directory - "/templates/projects.org")) - :target - (file+head "projects/%<%Y%m%d%H%M%S>-${slug}.org" - "#+title: ${title}\n#+filetags: projects") - :empty-lines 1 - :unnarrowed t)) - (org-roam-db-autosync-mode) - :ensure (org-roam :files (:defaults "extensions/*")) - :init - (setopt org-roam-directory (file-name-as-directory (expand-file-name "roam" org-directory)))) +;;;;;; Org Super Agenda (use-package org-super-agenda - :hook (org-agenda-mode . org-super-agenda-mode) + :hook + (org-agenda-mode . org-super-agenda-mode) :init (setq org-agenda-custom-commands - '(("w" "Work agenda" + '(("u" "Super agenda" - ((agenda "" ((org-agenda-prefix-format " %?-12t %s") + ((agenda "" ((org-agenda-prefix-format " %-12t% s%?-6e") + ;;(org-agenda-prefix-format " %?-12t %s") (org-agenda-remove-tags t) (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo '("WONT"))) - (org-agenda-span 'day) - (org-habit-show-habits nil))) + (org-agenda-span 'day))) - (alltodo "" ((org-agenda-overriding-header "") - (org-agenda-prefix-format " %?-12t %s") + (alltodo "" ((org-agenda-overriding-header "\nI'M DOING IT...") + (org-agenda-prefix-format " %-20T") + ;; (org-agenda-prefix-format " %?-12t %s") (org-agenda-remove-tags t) (org-super-agenda-groups - '((:discard - (:deadline future - :scheduled future - :category ("house" "me" "notes"))) - - (:name "Done" - :log state + '( + (:name "Done Today" ; FIXME :todo "DONE" - :order 90) + :log t + :order 95) (:name "Overdue" :deadline past :scheduled past :order 1) - (:name "Inbox" - :category ("inbox" "phone_inbox") - :order 9) - - (:name "Important" - :priority "A" - :order 0) - - (:name "In-Progress" - :todo "PROG" - :order 2) - - (:name "Next" - :todo "NEXT" - :order 3) - - (:name "Today" - :deadline today - :scheduled today - :time-grid t - :order 4) - - (:name "Research" - :tag "research" - :order 7) - - (:name "Project Backlog" - :and (:todo "TODO" :tag "projects") - :order 5) - - (:name "General Backlog" - :and (:todo "TODO" :priority "B") - :order 8) - - (:name "Less Important" - :priority<= "C" + (:name "Waiting" + :todo "WAIT" :order 80) - )))))) - ("y" "My agenda" - - ((agenda "" ((org-agenda-prefix-format " %?-12t %s") - (org-agenda-remove-tags t) - (org-agenda-skip-function '(org-agenda-skip-entry-if - 'todo '("WONT") 'regexp '("job"))) - (org-agenda-span 3))) - - (alltodo "" ((org-agenda-overriding-header "") - (org-agenda-prefix-format " %?-12t %s") - (org-agenda-remove-tags t) - (org-super-agenda-groups - '((:discard - (:not - (:category ("house" "me" "notes")))) - - ;; (:discard - ;; (:deadline future :scheduled future)) - - (:name "Overdue" - :deadline past - :scheduled past - :order 1) (:name "Upcoming" :deadline future :scheduled future :order 99) - (:name "Inbox" - :category ("inbox" "phone_inbox") - :order 8) - - (:name "Done" - :todo "DONE" - :order 99) - - (:name "Important" + (:name "High Priority" :priority "A" - :order 0) - - (:name "In-Progress" - :todo "PROG" - :order 2) - - (:name "Next" - :todo "NEXT" - :order 3) - - (:name "Household" - :tag "chores" - :order 6) - - (:name "Routine" - :and (:habit t :not (:tag "chores")) :order 5) - (:name "Today" + (:name "Now" + :todo ("PROG" "NEXT") + :order 10) + + (:name "Today's Personal Tasks" + :and (:deadline today :tag "personal") + :and (:scheduled today :tag "personal") + :order 20) + + (:name "Today's Household Tasks" + :and (:deadline today :tag "household") + :and (:scheduled today :tag "household") + :order 30) + + (:name "Today's Projects" :deadline today :scheduled today - :time-grid t - :order 4) - - ;; (:name "Personal projects" - ;; :categery "me" - ;; :order 9) + :order 15) (:name "Research" :tag "research" - :order 7) + :order 45) - (:name "General Backlog" - :and (:todo "TODO" :priority "B") + (:name "Personal Backlog" + :and (:todo "TODO" :tag "personal") + :and (:todo "TODO" :tag "job_search") + :order 40) + + (:name "Household Backlog" + :and (:todo "TODO" :tag "household") :order 50) - (:name "Less Important" - :priority<= "C" - :order 85) - ))))))))) + (:name "Project Backlog" + :todo "TODO" + :order 35) -(use-package org-superstar - ;; :disabled t + (:name "Inbox" + :tag "inbox" + :order 90) + + + ))))) + ))) + ) + +;;;;; Contacts + +;; Last commit before requiring org 9.7: 048942e8063044accca7a5c42b81a1e27b7a0876 +(use-package org-contacts + :ensure + (org-contacts :repo "https://repo.or.cz/org-contacts.git" :ref "048942e8") + :custom + (org-contacts-files + `(,(expand-file-name "contacts.org" org-directory)) "Set single contacts file") + :commands + (org-contacts org-contacts-agenda)) + +;;;;; Navigation + +;;;;; Notes + +;;;;;; Org Noter + +(use-package org-noter + :custom + (org-noter-notes-search-path + `(,(expand-file-name "notes" org-directory)) "Note paths (non-recursive)") + :bind + ("C-c n n" . org-noter) + (:map dired-mode-map + ("C-c n n" . org-noter-start-from-dired)) + :hook + (dired-mode . org-noter-enable-update-renames)) + +;;;;;; Org Remark + +(use-package org-remark + :custom + (org-remark-line-ellipsis "---" "Default '...' is too similar to folded headlines") + (org-remark-notes-file-name + (expand-file-name "org-remark.org" org-directory) "Default too similar to `marginalia.el'") + :bind + ("C-c n m" . org-remark-mark) + ("C-c n l" . org-remark-mark-line) + (:map org-remark-mode-map + ("C-c n o" . org-remark-open) + ("C-c n ]" . org-remark-view-next) + ("C-c n [" . org-remark-view-prev) + ("C-c n r" . org-remark-remove) + ("C-c n d" . org-remark-delete)) + :init + (org-remark-global-tracking-mode) + :hook + (elpaca-after-init . org-remark-global-tracking-mode) + (nov-mode . org-remark-nov-mode)) + +;;;;; Org Citations + +;;;;;; Org Cite + +(use-feature oc + :custom + (org-cite-export-processors '((latex biblatex) + (t csl)) "Use biblatex for LaTeX, csl for everything else") + (org-cite-global-bibliography + `(,(expand-file-name "~/Nextcloud/Library/Bibliography/Library.bib")) "Set bib files") + :defer t :config - (setopt org-indent-mode-turns-on-hiding-stars nil - org-superstar-headline-bullets-list '("◉" "🞛" "○" "▷") - org-superstar-leading-bullet ?\s - org-superstar-special-todo-items t) - :hook (org-mode . org-superstar-mode)) + (when (elpaca-installed-p 'citar) + (setopt org-cite-activate-processor 'citar + org-cite-follow-processor 'citar + org-cite-insert-processor 'citar))) + +;;;;;; Org Cite CSL + +(use-feature oc-csl + :if + (elpaca-installed-p 'citeproc) + :after + (citeproc oc) + :config + (let ((zotero_styles (expand-file-name + "Zotero/styles/" (or (getenv "XDG_DATA_HOME") "~/.local/share/")))) + (if (file-directory-p zotero_styles) + (setopt org-cite-csl-styles-dir zotero_styles)))) + +;;;;;; Citar + +(use-package citar + :custom + (citar-bibliography + `(,(expand-file-name "~/Nextcloud/Library/Bibliography/Library.bib")) "Set bib files") + (citar-library-paths + `(,(expand-file-name "~/Nextcloud/Library/")) "Set paths to sources") + :bind + ("C-c n c" . citar-create-note) + :hook + (org-mode . citar-capf-setup) + :config + (when (elpaca-installed-p 'citar-embark) + (setopt citar-at-point-function 'embark-act))) + +;;;;;; Citar + Embark + +(use-package citar-embark + :if + (and (elpaca-installed-p 'citar) + (elpaca-installed-p 'embark)) + :after + (citar embark) + :config + (citar-embark-mode)) + +;;;;;; Citeproc + +;; Dependency for other packages +(use-package citeproc + :defer t) + +;;;;; Project Management + +;;;;;; Org Edna + +(use-package org-edna + :custom + (org-edna-finder-use-cache t "Improve performance with caching") + :bind + (:map org-mode-map + ("C-c o e" . org-edna-edit)) + :hook + (org-mode . org-edna-mode)) + +;;;;; Time Management + +;;;;;; Org Clock + +(use-feature org-clock + :after + (org) + :config + (defun as/save-after-org-clock-in (&rest r) + "Save org buffer after clocking in" + (with-current-buffer + (org-clocking-buffer) + (save-buffer))) + (defun as/save-after-org-clock-out (func &rest r) + "Save org buffer after clocking out of a task + +`:around' is used here in the event the current buffer is not the same as +`org-clocking-buffer'. Thanks to @mocompute for the idea: +" + (let ((buffer (org-clocking-buffer))) + (apply func r) + (when buffer (with-current-buffer buffer (save-buffer))))) + (advice-add #'org-clock-in :after #'as/save-after-org-clock-in) + (advice-add #'org-clock-out :around #'as/save-after-org-clock-out)) + +;;;;;; Org Pomodoro + +(use-package org-pomodoro + :after + (org-clock) + :custom + (alert-user-configuration + '((((:category . "org-pomodoro")) libnotify nil)) "Send alerts to libnotify") + (org-pomodoro-audio-player + (concat (executable-find "pw-cat") " -p --volume 0.25") "Use PipeWire & reduce volume") + (org-pomodoro-clock-breaks t "Include break time") + (org-pomodoro-format "%s" "Only display the timer") + (org-pomodoro-keep-killed-pomodoro-time t "Log manually ended clocks") + (org-pomodoro-length 50 "Increase pomodoro time") + (org-pomodoro-long-break-frequency 2 "Decrease long break frequency") + (org-pomodoro-manual-break t "Require manually clocking out") + (org-pomodoro-short-break-length 10 "Increase short break length") + :bind + (:map org-mode-map + ("C-c o p" . org-pomodoro)) + :commands + (org-pomodoro)) + +;;;;;; Org Timeblock (use-package org-timeblock + :custom + (org-timeblock-new-task-time 'pick "Ask me for new time") + (org-timeblock-show-future-repeats 'next "Only show next repeat") + (org-timeblock-scale-options (cons 7 20) "Start at 7:00, end at 20:00") + (org-timeblock-span 3 "Number of days to display") :bind (:map as/org-prefix-map - ("t" . org-timeblock)) - :config - (setopt org-timeblock-new-task-time 'pick - org-timeblock-show-future-repeats 'next - org-timeblock-scale-options (cons 7 20) - org-timeblock-span 3)) + ("b" . org-timeblock))) (provide 'init-org) -;;; org-mode.el ends here +;;; init-org.el ends here diff --git a/dot_config/emacs/lisp/init-org.old.el b/dot_config/emacs/lisp/init-org.old.el new file mode 100644 index 0000000..7157d12 --- /dev/null +++ b/dot_config/emacs/lisp/init-org.old.el @@ -0,0 +1,490 @@ +;;; org-mode.el --- org-mode customizations -*- lexical-binding: t -*- + +;; Author: Andrew Scott +;; Keywords: org, convenience, tools +;; URL: https://codeberg.org/andyscott/dotfiles + +;; This file is not part of GNU Emacs + +;; Copyright (c) 2024 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 org-mode customizations. + +;;; Code: + +(use-feature org + :bind + (:map as/org-prefix-map + ("a" . org-agenda) + ("c" . org-capture) + ("d" . org-priority-down) + ("h" . consult-org-heading) + ("l" . org-store-link) + ("s" . org-insert-subheading) + ("u" . org-priority-up) + ("y" . org-todo-yesterday) + ("C-h" . consult-org-agenda) + ("C-l" . embark-org-copy-link-target) ; `embark' + ("M-l" . org-toggle-link-display) ; `ol' + ("t" . org-tags-view)) ; `org-agenda' + (:map org-mode-map + ;; supposed to be set by `org-use-extra-keys' + ;; and still overwritten with `org-insert-drawer' when `org' is loaded + ("C-c C-x d" . org-metadown)) + :config + ;; General options TODO: Comment various options more descriptively + (setopt org-adapt-indentation nil + org-agenda-files (directory-files-recursively org-directory "org$") + org-archive-location (expand-file-name "archive/%s_archive.org::" org-directory) + org-blank-before-new-entry '((heading . t) + (plain-list-item . t)) + org-deadline-warning-days 5 + org-default-notes-file (expand-file-name "inbox.org" org-directory) + org-enforce-todo-checkbox-dependencies t + org-fontify-done-headline t + org-fontify-todo-headline nil + org-goto-interface 'outline-path-completion ; `org-goto' + org-hide-emphasis-markers t + org-insert-heading-respect-content t + org-log-done 'time + org-log-into-drawer t + org-log-redeadline 'time + org-M-RET-may-split-line nil + org-pretty-entities t + org-pretty-entities-include-sub-superscripts nil + org-reverse-note-order t ; Add/refile notes at the beginning of an entry + org-special-ctrl-a/e t + org-special-ctrl-k t + org-startup-folded 'content + org-tags-column 0 + org-todo-keywords '((sequence "TODO(t)" + "NEXT(x)" + "PROG(p)" + "WAIT(w@/!)" + "|" + "DONE(d!)" + "WONT(n@/!)") + (sequence "IDEA(i)" "|")) + org-todo-repeat-to-state "TODO") + :defer 3 + :hook + (org-mode . org-indent-mode) + (org-mode . variable-pitch-mode) + :init + (bind-keys :prefix-map as/org-prefix-map + :prefix "C-c o") + (setopt org-directory "~/Nextcloud/Documents/org" + org-use-extra-keys t)) + +;;; Built-in Packages: + +(use-feature oc + :after (org) + :config + (setopt org-cite-export-processors '((latex biblatex) + (t csl)) + org-cite-global-bibliography '("~/Nextcloud/Library/bib/library.bib")) + (when (elpaca-installed-p 'citar) + (setopt org-cite-activate-processor 'citar + org-cite-follow-processor 'citar + org-cite-insert-processor 'citar))) + +(use-feature oc-csl + :after (citeproc oc) + :config + (let ((zotero_styles (expand-file-name + "Zotero/styles/" (or (getenv "XDG_DATA_HOME") "~/.local/share/")))) + (if (file-directory-p zotero_styles) + (setopt org-cite-csl-styles-dir zotero_styles)))) + +(use-feature org-agenda + :after (org) + :bind + (:map org-agenda-mode-map + ("C-c C-r" . as/org-agenda-reconcile-inbox-item)) + :config + (setopt org-agenda-block-separator ?- + org-agenda-skip-deadline-if-done nil + org-agenda-skip-scheduled-if-deadline-is-shown nil + org-agenda-skip-scheduled-if-done nil + org-agenda-start-on-weekday nil + org-agenda-start-with-log-mode '(clock closed state) + org-agenda-tags-column 0) + (defun as/org-agenda-reconcile-inbox-item () + "Process and refile an org-agenda item" + (interactive) + (org-with-wide-buffer + (org-agenda-set-tags) + (org-agenda-priority) + (if (y-or-n-p "Schedule item?") + (org-agenda-schedule nil nil)) + (org-agenda-refile nil nil t)))) + +(use-feature org-capture + :after (org) + :config + (setq org-capture-templates ; `org-capture' + `( + ("i" "Inbox" + entry (file+headline "inbox.org" "Ideas") + "** IDEA %?" + :empty-lines 1 + ) + + ("j" "Log Entry" + entry (file+datetree "log.org") + "** %?" + :empty-lines 1) + + ("n" "Note" + entry (file+headline "inbox.org" "Notes") + "** %? +:PROPERTIES: +:CREATED: %U +:END:" + :empty-lines 1) + + ("t" "Todo" entry (file+headline "inbox.org" "Tasks") + "** TODO [#B] %? +:PROPERTIES: +:CREATED: %U +:END: +%i\n%a +Notes: " + :empty-lines 1) + ) + ) + ) + +(use-feature org-clock + :after (org) + :config + (setopt org-clock-in-resume t + org-clock-in-switch-to-state "PROG" + org-clock-persist t + org-clock-rounding-minutes 5 + org-clock-string-limit 20)) + +(use-feature org-faces + :after (org) + :config + (setopt org-fontify-quote-and-verse-blocks t + org-todo-keyword-faces '(("TODO" . (:inherit dired-mark :inverse-video t)) + ("PROG" . (:inherit match :inverse-video t)) + ("NEXT" . (:inherit dired-special :inverse-video t)) + ("WAIT" . (:inherit shadow :inverse-video t)) + ("WONT" . (:inherit org-done)) + ("DONE" . (:inherit org-done)) + ("IDEA" . (:inherit bold :inverse-video t))) + org-priority-faces '((?A . (:inherit error :weight semibold :inverse-video t)) + (?B . (:inherit warning :weight semibold :inverse-video t)) + (?C . (:inherit mode-line-inactive :weight semibold :inverse-video t)))) + :custom-face + ;; Headlines + (org-level-1 ((t (:inherit outline-1 :height 1.5)))) + (org-level-2 ((t (:inherit outline-2 :height 1.4)))) + (org-level-3 ((t (:inherit outline-3 :height 1.4)))) + (org-level-4 ((t (:inherit outline-4 :height 1.2)))) + (org-level-5 ((t (:inherit outline-5 :height 1.1)))) + ;; Ensure monospace Keywords/Tags/Blocks + (org-block ((t (:inherit fixed-pitch)))) ; inherited by `org-code' + (org-block-begin-line ((t (:inherit fixed-pitch)))) + (org-block-end-line ((t (:inherit (org-block-begin-line fixed-pitch))))) + (org-checkbox ((t (:inherit (org-todo fixed-pitch))))) + (org-checkbox-statistics-todo ((t (:inherit (org-todo fixed-pitch))))) + (org-date ((t (:inherit fixed-pitch)))) + (org-document-info-keyword ((t (:inherit (shadow fixed-pitch))))) + (org-drawer ((t (:inherit fixed-pitch)))) + (org-indent ((t (:inherit (org-hide fixed-pitch))))) + (org-link ((t (:foreground "dark cyan" :underline t)))) + (org-list-dt ((t (:inherit fixed-pitch)))) + (org-meta-line ((t (:inherit (fixed-pitch))))) + (org-property-value ((t (:inherit fixed-pitch)))) + (org-special-keyword ((t (:inherit fixed-pitch)))) + (org-table ((t (:inherit fixed-pitch)))) + (org-tag ((t (:inherit (fixed-pitch) :height 0.8)))) + (org-verbatim ((t (:inherit fixed-pitch))))) + +(use-feature org-fold + :after (org) + :config (setopt org-fold-catch-invisible-edits 'show-and-error)) + +(use-feature org-habit + :after (org)) + +(use-feature org-id + :after (org) + :config + (setopt org-id-link-to-org-use-id t + org-id-locations-file (locate-user-emacs-file "org-id-locations") + org-id-method 'ts + org-id-ts-format "%Y%m%dT%H%M%S.%2N%z")) + +(use-feature org-keys + :after (org) + :config + (setopt org-return-follows-link t)) + +(use-feature org-list + :after (org) + :config (setopt org-list-demote-modify-bullet '(("+" . "-") + ("-" . "+") + ("*" . "+")))) + +(use-feature org-refile + :after (org) + :config + (setopt org-log-refile 'note + org-outline-path-complete-in-steps nil + org-refile-allow-creating-parent-nodes 'confirm + org-refile-targets '((nil :maxlevel . 3) + (org-agenda-files :maxlevel . 2)) + org-refile-use-outline-path 'file)) + +(use-feature org-src + :after (org) + :config + (setopt org-edit-src-content-indentation 0 + org-src-preserve-indentation t + org-src-tab-acts-natively t)) + +;;; 3rd-party Packages: + +(use-package citar + :after (oc) + :config + (setopt citar-bibliography org-cite-global-bibliography + citar-library-paths '("~/Nextcloud/Library/")) + ;; (when (elpaca-installed-p 'citar-embark) + ;; (setopt citar-at-point-function 'embark-act)) + :hook (org-mode . citar-capf-setup)) + +(use-package citar-embark + :after (citar embark) + :config (citar-embark-mode)) + +(use-package citar-org-roam + :after (citar org-roam) + :config + (setopt citar-org-roam-capture-template-key "r" + citar-org-roam-note-title-template "${title} - ${author}" + citar-org-roam-subdir "references") + (citar-org-roam-mode)) + +(use-package citeproc + :defer t) + +(use-package org-appear + :bind + (:prefix-map as/org-appear + :prefix "C-c C-q") + :config + (setopt org-appear-autoentities t + org-appear-autolinks nil + org-appear-autosubmarkers t + org-appear-trigger 'on-change) + :hook (org-mode . org-appear-mode)) + +(use-package org-edna + :bind + (:map as/org-prefix-map + ("e" . org-edna-edit)) + :config (setopt org-edna-finder-use-cache t) + :hook (org-mode . org-edna-mode)) + +(use-package org-noter + :disabled t + :after (org) + :config + (setopt org-noter-notes-search-path (list (concat org-directory "/roam"))) + (org-noter-enable-org-roam-integration)) + +(use-package org-pomodoro + :after (org-clock) + :bind + (:map as/org-prefix-map + ("m" . org-pomodoro)) + :commands (org-pomodoro) + :config + (setopt alert-user-configuration ; Send messages to libnotify + '((((:category . "org-pomodoro")) libnotify nil)) + org-pomodoro-audio-player (concat (executable-find "pw-cat") " -p") + org-pomodoro-keep-killed-pomodoro-time t + org-pomodoro-length 50 + org-pomodoro-long-break-frequency 2 + org-pomodoro-manual-break t + org-pomodoro-short-break-length 10)) + +(use-package org-roam + ;; :after (org) + :bind + (:map as/org-roam-prefix-map + ("b" . org-roam-buffer-display-dedicated) + ("c" . org-roam-capture) + ("f" . org-roam-node-find) + ("i" . org-roam-node-insert)) + :config + (setopt org-roam-database-connector 'sqlite-builtin + org-roam-directory (file-name-as-directory (expand-file-name "roam" org-directory))) + (setq org-roam-db-gc-threshold most-positive-fixnum) ; doesn't like the new `setopt' + (add-to-list 'display-buffer-alist + '("\\*org-roam\\*" + (display-buffer-in-direction) + (direction . right) + (window-width . 0.33) + (window-height . fit-window-to-buffer))) + (add-to-list 'org-roam-capture-templates + '("r" "reference" plain + "%?" + :target + (file+head "references/${citar-citekey}.org" + "#+title: ${note-title}\n") + :empty-lines 1 + :unnarrowed t + )) + (add-to-list 'org-roam-capture-templates + `("p" "project" plain (file ,(concat org-roam-directory + "/templates/projects.org")) + :target + (file+head "projects/%<%Y%m%d%H%M%S>-${slug}.org" + "#+title: ${title}\n#+filetags: :projects:") + :empty-lines 1 + :unnarrowed t)) + (org-roam-db-autosync-mode) + :ensure (org-roam :files (:defaults "extensions/*")) + :init + (bind-keys :prefix-map as/org-roam-prefix-map + :prefix "C-c r")) + +(use-package org-super-agenda + :hook (org-agenda-mode . org-super-agenda-mode) + :init + (setq org-agenda-custom-commands + '(("u" "Super agenda" + + ((agenda "" ((org-agenda-prefix-format " %-12t% s%?-6e") + ;;(org-agenda-prefix-format " %?-12t %s") + (org-agenda-remove-tags t) + (org-agenda-skip-function '(org-agenda-skip-entry-if + 'todo '("WONT"))) + (org-agenda-span 'day))) + + (alltodo "" ((org-agenda-overriding-header "\nI'M DOING IT...") + (org-agenda-prefix-format " %-20T") + ;; (org-agenda-prefix-format " %?-12t %s") + (org-agenda-remove-tags t) + (org-super-agenda-groups + '( + (:name "Done Today" ; FIXME + :todo "DONE" + :log t + :order 95) + + (:name "Overdue" + :deadline past + :scheduled past + :order 1) + + (:name "Waiting" + :todo "WAIT" + :order 80) + + (:name "Upcoming" + :deadline future + :scheduled future + :order 99) + + (:name "High Priority" + :priority "A" + :order 5) + + (:name "Now" + :todo ("PROG" "NEXT") + :order 10) + + (:name "Personal" + :and (:deadline today :tag "personal") + :and (:scheduled today :tag "personal") + :order 30) + + (:name "Household" + :and (:deadline today :tag "household") + :and (:scheduled today :tag "household") + :order 35) + + (:name "Today" + :deadline today + :scheduled today + :order 15) + + (:name "Project Backlog" + :and (:todo "TODO" :tag "projects") + :order 20) + + (:name "Research" + :tag "research" + :order 40) + + (:name "Personal Backlog" + :and (:todo "TODO" :tag "personal") + :and (:todo "TODO" :tag "job_search") + :order 45) + + (:name "Household Backlog" + :and (:todo "TODO" :priority<= "B" :tag "household") + :order 50) + + (:name "Inbox" + :tag "inbox" + :order 90) + + + ))))) + )))) + +(use-package org-superstar + :config + (if org-odd-levels-only + (setopt org-superstar-headline-bullets-list '(?◉ ?- ?🞛 ?- ?○ ?- ?▷ ?- ?✸ ?- ?✿ ?-)) + (setopt org-superstar-headline-bullets-list '(?◉ ?🞛 ?○ ?▷ ?✸ ?✿))) + (setopt org-indent-mode-turns-on-hiding-stars nil ; needed for `org-superstar-leading-bullet' + org-superstar-leading-bullet ?\s + org-superstar-hide-leading-stars t + org-superstar-special-todo-items t + org-superstar-todo-bullet-alist '(("TODO" . ?☐) + ("NEXT" . ?☐) + ("PROG" . ?☐) + ("WAIT" . ?☐) + ("DONE" . ?☑) + ("WONT" . ?☑))) + :hook (org-mode . org-superstar-mode)) + +(use-package org-timeblock + :bind + (:map as/org-prefix-map + ("b" . org-timeblock)) + :config + (setopt org-timeblock-new-task-time 'pick + org-timeblock-show-future-repeats 'next + org-timeblock-scale-options (cons 7 20) + org-timeblock-span 3)) + +(provide 'init-org) +;;; org-mode.el ends here