diff --git a/dot_config/emacs/early-init.el.tmpl b/dot_config/emacs/early-init.el.tmpl index 8f9e730..70506d6 100644 --- a/dot_config/emacs/early-init.el.tmpl +++ b/dot_config/emacs/early-init.el.tmpl @@ -31,7 +31,28 @@ ;;; Code: -;; Relocate emacs-user-directory to XDG_DATA_HOME +;; Disable `package.el' +(setq package-enable-at-startup nil) + +;; Ensure other defaults are loaded +(setq inhibit-default-init nil) + +;; Avoid `garbage-collect' during init +(setq gc-cons-percentage 1 + gc-cons-threshold most-positive-fixnum) + +;; Skip regexp checking by `find-file-name-handler' during init +(defvar default-file-name-handler-alist file-name-handler-alist) +(setq file-name-handler-alist nil) + +;; Restore `garbage-collect' and `file-name-handler-alist' settings +(add-hook 'emacs-startup-hook + (lambda () + (setq file-name-handler-alist default-file-name-handler-alist + gc-cons-percentage 0.1 + gc-cons-threshold (* 1024 1024 8)))) + +;; Relocate `emacs-user-directory' to XDG_DATA_HOME (setq user-emacs-directory (expand-file-name "emacs/" (or (getenv "XDG_DATA_HOME") "~/.local/share/"))) @@ -41,18 +62,12 @@ (unless (file-directory-p xdg_cache_home) (make-directory xdg_cache_home)) -;; Move eln-cache to XDG_CACHE_HOME +;; Move `eln-cache' to XDG_CACHE_HOME (when (fboundp 'startup-redirect-eln-cache) (if (< emacs-major-version 29) (push (expand-file-name "eln-cache/" xdg_cache_home) native-comp-eln-load-path) (startup-redirect-eln-cache (expand-file-name "eln-cache/" xdg_cache_home)))) -;; Disable package.el -(setq package-enable-at-startup nil) - -;; Ensure other default libs are loaded -(setq inhibit-default-init nil) - ;; Load newest byte code (setq load-prefer-newer t) @@ -61,19 +76,22 @@ (setq native-comp-deferred-compilation t native-comp-async-report-warnings-errors nil)) -;; Raise garbage collection threshold -(setq gc-cons-threshold 500000000 - gc-cons-percentage 0.1) - ;; Don't advertise instructions for frame exit (setq server-client-instructions nil) ;; Don't implicitly resize the frame (setq frame-inhibit-implied-resize t) +;; Allow frames to increase/decrease by one pixel +(setq frame-resize-pixelwise t) + ;; Disable startup screen (setq inhibit-startup-screen t) +;; Start in `fundamental-mode' instead of `lisp-interaction-mode' to avoid +;; loading unnecessary packages via hooks +(setq initial-major-mode 'fundamental-mode) + ;; Visible bell only (setq visible-bell t) @@ -94,6 +112,8 @@ (push '(menu-bar-lines . 0) default-frame-alist) (push '(tool-bar-lines . 0) default-frame-alist) (push '(vertical-scroll-bars) default-frame-alist) +(push '(background-color . "#282828") default-frame-alist) +(push '(foreground-color . "#C6C6C6") default-frame-alist) ;; Make lsp-mode use plists (setenv "LSP_USE_PLISTS" "true") diff --git a/dot_config/emacs/init.el b/dot_config/emacs/init.el index b9e1ab9..1759caa 100644 --- a/dot_config/emacs/init.el +++ b/dot_config/emacs/init.el @@ -1,18 +1,12 @@ -;; init.el --- GNU Emacs Initialization File -*- lexical-binding: t; -*- +;;; init.el --- GNU Emacs Initialization File -*- lexical-binding: t; -*- -;; Copyright (c) 2023 Andrew Scott - -;; Author: Andrew Scott +;; Author: Andrew Scott ;; Keywords: convenience, tools ;; URL: https://codeberg.org/andyscott/dotfiles ;; This file is not part of GNU Emacs. -;;; Commentary: - -;; My Emacs initialization file. - -;;; License: +;; Copyright (c) 2023 Andrew Scott ;; MIT No Attribution @@ -29,9 +23,14 @@ ;; 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 emacs startup +;; 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." @@ -40,14 +39,25 @@ (time-subtract (current-time) before-init-time))) gcs-done))) -;;; Initialize elpaca +;; 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 - :files (:defaults (:exclude "extensions")) + :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)) @@ -59,8 +69,10 @@ (when (< emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) - ((zerop (call-process "git" nil buffer t "clone" - (plist-get order :repo) repo))) + ((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)) @@ -78,49 +90,102 @@ (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca `(,@elpaca-order)) -;; Unload `seq' before build -;; 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)) +;; Configure `use-package' with `Elpaca' +(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)) -(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 (elpaca elpaca-use-package + (require 'elpaca-use-package) (elpaca-use-package-mode) - (setq elpaca-use-package-by-default t)) + (setopt use-package-always-ensure 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)) + +;; TODO - remove this when done profiling startup +(setopt use-package-compute-statistics t) + +;; Wait for `Elpaca' to process current queue (elpaca-wait) -;;; Built-in features -(use-package emacs - :ensure nil - :init - ;; Initial mode - (setq initial-major-mode 'fundamental-mode) +;;; Built-in Packages: - ;; Vertico - ;; Add prompt to `completing-read-multiple' - (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) +;; Revert a buffer if the file has changed +(use-feature autorevert + :config (global-auto-revert-mode t) + :defer 3 + :init (setopt auto-revert-interval 0.01)) - ;; Recursive minibuffers - (setq enable-recursive-minibuffers t) +;; Customize compilation & related buffers +(use-feature compile + :commands (compile recompile) + :config (setopt compilation-ask-about-save nil + compilation-scroll-output 'first-error)) - ;; Disable prompt in minibuffer - (setq minibuffer-prompt-properties - '(read-only t cursor-intangible t face minibuffer-prompt)) - (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) +;; Write external customizations to /dev/null +(use-feature cus-edit + :init (setopt custom-file null-device)) + +;; 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 c a" . eglot-code-actions) + ("C-c c o" . eglot-code-actions-organize-imports) + ("C-c c r" . eglot-rename) + ("C-c c f" . eglot-format)) + :config + (push '(astro-mode . ("astro-ls" "--stdio" + :initializationOptions + (:typescript (:tsdk "/usr/lib/node_modules/typescript/lib")))) eglot-server-programs) + (push '((rust-ts-mode rust-mode) . ("rustup" "run" "stable" "rust-analyzer" + :initializationOptions + (:check (:command "clippy")))) eglot-server-programs) + (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 + c-ts-mode + c++-ts-mode + rust-ts-mode + 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 @@ -133,334 +198,188 @@ ("S-C-" . shrink-window) ("S-C-" . enlarge-window)) :config - ;; General Options - ;; Better scrolling - (setq scroll-step 1 - scroll-conservatively 1000 - scroll-preserve-screen-position t) - (when (fboundp 'pixel-scroll-precision-mode) - (pixel-scroll-precision-mode)) + (setopt cursor-type 'bar + fill-column 80 + scroll-step 1 + scroll-conservatively 1000 + scroll-preserve-screen-position t) + :init + ;; 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) - ;; Cursor - (setq-default cursor-type 'bar - blink-cursor-delay 1.0) + (setopt enable-recursive-minibuffers t ; Recursive minibuffers + minibuffer-prompt-properties ; Disable prompt in minibuffer + '(read-only t cursor-intangible t face minibuffer-prompt)) + (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)) - ;; Tabs - (setq tab-always-indent 'complete) - (setq-default tab-width 4) - - ;; Prefer UTF-8 character coding - (prefer-coding-system 'utf-8) - (set-default-coding-systems 'utf-8) - (set-terminal-coding-system 'utf-8) - (set-keyboard-coding-system 'utf-8)) - -(use-package compile - :ensure nil - :commands (compile recompile) - :config (setq compilation-scroll-output t)) - -(use-package cus-edit - :ensure nil - :config (setq-default custom-file null-device)) - -(use-package display-fill-column-indicator - :ensure nil - :init (setq-default fill-column 100) - :hook ((conf-mode - markdown-mode - prog-mode) . display-fill-column-indicator-mode)) - -(use-package display-line-numbers - :ensure nil - :hook ((conf-mode prog-mode) . display-line-numbers-mode)) - -(use-package eglot - :ensure nil - :bind (:map - eglot-mode-map - ("C-c c a" . eglot-code-actions) - ("C-c c o" . eglot-code-actions-organize-imports) - ("C-c c r" . eglot-rename) - ("C-c c f" . eglot-format)) - :config - (push '(astro-mode . ("astro-ls" "--stdio" - :initializationOptions - (:typescript (:tsdk "/usr/lib/node_modules/typescript/lib")))) eglot-server-programs) - (setq 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" - )) - :hook ((astro-mode - c-ts-mode - c++-ts-mode - zig-mode) . eglot-ensure)) - -(use-package elec-pair - :ensure nil - :defer 3 - :config (electric-pair-mode)) - -(use-package files - :ensure nil +;; 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)) - (setq backup-directory-alist `((".*" . ,auto_save_directory)) - auto-save-file-name-transforms `((".*" ,auto_save_directory t)))) - (setq 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)) + (setopt backup-directory-alist `((".*" . ,auto_save_directory)) + 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)) -(use-package flymake - :ensure nil - :bind (:map flymake-mode-map - ("C-c ! d" . flymake-show-buffer-diagnostics) - ("C-c ! D" . flymake-show-project-diagnostics) - ("C-c ! n" . flymake-goto-next-error) - ("C-c ! p" . flymake-goto-prev-error)) - :config (flymake-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))) -(use-package flyspell - :ensure nil - :defer 3 +;; Customize spell checking +(use-feature flyspell :hook (((git-commit-mode - markdown-mode + org-mode text-mode) . flyspell-mode) (prog-mode . flyspell-prog-mode))) -(use-package mwheel - :ensure nil - :config - (setq mouse-wheel-follow-mouse t - mouse-wheel-progressive-speed nil - mouse-wheel-scroll-amount '(2 ((shift) . 1)))) +;; Customize frame behavior/cursor blinking +(use-feature frame + :config (setopt blink-cursor-delay 1.0 + blink-cursor-interval 0.75)) -(use-package paren - :ensure nil - :defer 3 - :config (show-paren-mode)) +;; Ensure UTF-8 terminal encoding +(use-feature mule + :config (unless (display-graphic-p) + (set-terminal-coding-system 'utf-8))) -(use-package recentf - :ensure nil +;; Customize mouse wheel +(use-feature mwheel :config - (setq recentf-auto-cleanup 'never - recentf-max-menu-items 15 - recentf-max-saved-items 100 - recentf-save-file (concat xdg_cache_home "recentf")) + (setopt mouse-wheel-follow-mouse t + mouse-wheel-progressive-speed nil + mouse-wheel-scroll-amount '(2 ((shift) . 1)))) + +;; 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))) + +(use-feature project + :config (setopt project-vc-extra-root-markers '("Cargo.toml"))) + +;; Customize handling of recent files +(use-feature recentf + :config + (setopt recentf-max-menu-items 100 + recentf-max-saved-items 1000 + recentf-save-file (concat xdg_cache_home "recentf")) (recentf-mode)) -(use-package savehist - :ensure nil - :defer 3 +;; Customize saving mini-buffer history +(use-feature savehist :config - (setq savehist-autosave-interval 60 - savehist-additional-variables '(search-ring regexp-search-ring) - savehist-file (concat xdg_cache_home "history")) + (setopt savehist-autosave-interval 120 + savehist-file (concat xdg_cache_home "history")) (savehist-mode)) -(use-package saveplace - :ensure nil - :defer 1 +;; Customize saving place in files +(use-feature saveplace :config - (setq save-place-file (concat xdg_cache_home "places")) + (setopt save-place-file (concat xdg_cache_home "places")) (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 - ;; Unload `seq' before `elpaca' starts building :ensure `(seq :build ,(+elpaca-seq-build-steps))) -(use-package simple - :ensure nil - :config (setq-default indent-tabs-mode nil) - :hook ((conf-mode prog-mode) . column-number-mode)) +;; "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))) -(use-package text-mode - :ensure nil - :config (setq-local fill-column 120 - whitespace-style '(face - whitespace-missing-newline-at-eof - space-after-tab - space-before-tab - trailing))) +;; Customize text buffers +(use-feature text-mode + :config (setq-local fill-column 120)) -(use-package treesit - :ensure nil +;; Customize tree-sitter parsing +(use-feature treesit :config (push '(c++-mode . c++-ts-mode) major-mode-remap-alist) - (setq treesit-font-lock-level 4)) + (setopt treesit-font-lock-level 4)) -(use-package whitespace - :ensure nil +;; Customize whitespace visualization & cleanup +(use-feature whitespace + :config + (add-hook 'before-save-hook #'whitespace-cleanup) + (setopt whitespace-line-column nil + whitespace-style '(face + lines-char + missing-newline-at-eof + space-after-tab + space-before-tab + tabs + trailing)) :hook ((conf-mode prog-mode - text-mode) . whitespace-mode) - :config - (add-hook 'before-save-hook #'whitespace-cleanup) - (setq whitespace-line-column nil - whitespace-style '(face - lines-char - missing-newline-at-eof - space-after-tab - space-before-tab - tabs - trailing))) + text-mode) . whitespace-mode)) -;;; Packages -;; Benchmark Emacs startup -(use-package esup - :defer t - :custom (esup-depth 0)) +;;; Packages: -;; Theme +;; Shows current/total matches in mode line +(use-package anzu + :config (global-anzu-mode) + :defer 3) + +;; Auto-format +(use-package apheleia + :defer t) + +;; Extensions for `completion-at-point' +(use-package cape + :bind ("M-p" . cape-prefix-map)) + +;; Catppuccin theme (use-package catppuccin-theme :config - (setq custom-safe-themes t - catppuccin-flavor 'macchiato) + (setopt custom-safe-themes t + catppuccin-flavor 'macchiato) (catppuccin-reload) (load-theme 'catppuccin t)) -(use-package everforest - :ensure (everforest :host sourcehut :repo "theorytoe/everforest-theme") - :config - ;; (setq custom-safe-themes t) - ;; (load-theme 'everforest-hard-dark t) - (let ((moody_line (face-attribute 'mode-line :foreground)) - (moody_inactive (face-attribute 'mode-line-inactive :background))) - (set-face-attribute 'mode-line nil :overline moody_line) - (set-face-attribute 'mode-line-inactive nil :overline moody_line) - (set-face-attribute 'mode-line-inactive nil :underline moody_inactive) - (set-face-attribute 'mode-line nil :box nil) - (set-face-attribute 'mode-line-inactive nil :box nil) - (set-face-attribute 'mode-line-inactive nil :background moody_inactive)) - :custom-face - (cursor ((t (:background "#7fbbb3")))) - (whitespace-big-indent ((t (:background "#9da9a0")))) - (whitespace-empty ((t (:background "#9da9a0")))) - (whitespace-hspace ((t (:background "#9da9a0")))) - (whitespace-indentation ((t (:background "#9da9a0")))) - (whitespace-line ((t (:background "#e67e80")))) - (whitespace-newline ((t (:background "#e67e80")))) - (whitespace-space ((t (:background "#9da9a0")))) - (whitespace-space-after-tab ((t (:background "#9da9a0")))) - (whitespace-space-before-tab ((t (:background "#9da9a0")))) - (whitespace-tab ((t (:background "#9da9a0")))) - (whitespace-trailing ((t (:background "#e67e80"))))) - -(elpaca-wait) - -;; Mode line -(use-package moody - :defer 1 - :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)) - -(use-package minions - :after (moody) - :config (minions-mode)) - -(use-package keycast - :defer t - :config (keycast-mode-line-insert-after 'moody-mode-line-buffer-identification)) - -;; Show keybind hints -(use-package which-key - :defer 3 - :config (which-key-mode) - :custom (which-key-idle-delay 0.3)) - -;; Flyspell corrections -(use-package flyspell-correct - :after (flyspell) - :bind (:map flyspell-mode-map ("C-M-." . flyspell-correct-wrapper))) - -;; Better annotations -(use-package marginalia - :defer 3 - :bind (:map minibuffer-local-map ("M-A" . marginalia-cycle)) - :config (marginalia-mode)) - -;; Better undo/redo -(use-package undo-tree - :defer 3 - :bind (:map undo-tree-map - ("C-z" . undo-tree-undo) - ("C-M-z" . undo-tree-redo)) - :config (global-undo-tree-mode) - :custom - (undo-tree-auto-save-history t) - (undo-tree-history-directory-alist `((".*" . ,(concat xdg_cache_home "undo-tree/"))))) - -;; Completion style -(use-package orderless - :defer 1 - :custom - (completion-styles '(orderless basic)) - (completion-category-overrides '((file (styles basic partial-completion))))) - -;; Completion UI -(use-package vertico - :init (vertico-mode) - :custom - (vertico-cycle t) - (vertico-count 10) - (vertico-resize t) - (vertico-scroll-margin 1) - (completion-ignore-case t) - (read-buffer-completion-ignore-case t) - (read-file-name-completion-ignore-case t)) - -;; Command menu for items around point -(use-package embark - :defer 3 - :init - (setq prefix-help-command #'embark-prefix-help-command) - ;; documentation from first source - (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target) - ;; documentation from multiple sources - ;; (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly) - :bind - (("C-." . embark-act) - ("C-;" . embark-dwim) - ("C-h B" . embark-bindings)) - :config - ;; Hide the Embark live/completions buffer mode line - (push '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" - nil - (window-parameters (mode-line-format . none))) display-buffer-alist)) - ;; Search and navigation (use-package consult - :init - ;; Register formatting - (setq 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 - (setq xref-show-xrefs-function #'consult-xref - xref-show-definitions-function #'consult-xref) - :custom - (consult-narrow-key "<") - (consult-preview-key 'any) - ;; Switch project root function - ;; (autoload 'projectile-project-root "projectile") :bind (;; C-c bindings in `mode-specific-map' ("C-c M-x" . consult-mode-command) ("C-c h" . consult-history) @@ -512,129 +431,190 @@ ;; Minibuffer history :map minibuffer-local-map ("M-s" . consult-history) ; orig. next-matching-history-element - ("M-r" . consult-history))) ; orig. previous-matching-history-element + ("M-r" . consult-history)) ; orig. previous-matching-history-element + :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)) -;; Consult-specific Embark actions -(use-package embark-consult - :after (embark consult) - :hook (embark-collect-mode . consult-preview-at-point-mode)) +;; UI for the workspace/symbols procedure calls +(use-package consult-eglot + :after (eglot) + :bind + (:map eglot-mode-map + ("C-c c s" . consult-eglot-symbols))) ;; In-buffer completion -(use-package corfu - :defer 3 - :ensure (corfu :files (:defaults "extensions/*")) - :bind (:map corfu-map ("M-SPC" . corfu-insert-separator)) +(use-package company + :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)) + +;; FIXME - I crash emacs +(use-package corfu + :disabled + :bind + (:map corfu-map + ("M-SPC" . corfu-insert-separator) + ("RET" . nil)) + :config + (setopt corfu-auto t + corfu-cycle t) (global-corfu-mode) (corfu-popupinfo-mode) - :custom - ;;(corfu-min-width 60) - ;;(corfu-max-width corfu-min-width) - (corfu-auto t) - ;;(corfu-auto-delay 0.3) - (corfu-cycle t) - ;;(corfu-popupinfo-delay 0.6) - (corfu-separator ?\s)) + :defer 3 + :ensure (corfu :files (:defaults "extensions/*"))) +;; 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 + (push '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" + nil + (window-parameters (mode-line-format . none))) display-buffer-alist) + :defer 3 + :init (setopt prefix-help-command #'embark-prefix-help-command)) + +(use-package embark-consult + :hook (embark-collect-mode . consult-preview-at-point-mode)) + +;; Correction functions for `flyspell' +(use-package flyspell-correct + :after (flyspell) + :bind + (:map flyspell-mode-map + ("C-M-." . flyspell-correct-wrapper))) + +;; Highlight keywords +(use-package hl-todo + :bind + (:map hl-todo-mode-map + ("C-c t p" . hl-todo-previous) + ("C-c t n" . hl-todo-next) + ("C-c t o" . hl-todo-occur) + ("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" highlight italic) + ("REVIEW" highlight italic) + ("TODO" bookmark-face bold))) + :ensure (hl-todo :depth nil) + :hook (prog-mode . hl-todo-mode)) + +;; Icons for `corfu' (use-package kind-icon + :disabled :after (corfu) - :config (push #'kind-icon-margin-formatter corfu-margin-formatters) - :custom - (kind-icon-default-face 'corfu-default) - (kind-icon-blend-background nil)) - -;; File manager -(use-package dir-treeview) + :config + (push #'kind-icon-margin-formatter corfu-margin-formatters) + (setopt kind-icon-default-face 'corfu-default)) ;; Git -(use-package transient) -(use-package magit - :after transient - :bind ("C-M-;" . magit-status) - :custom - (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1) - (transient-history-file (concat xdg_cache_home "transient-history"))) +(use-package transient ; Must declare before magit + :defer t) -(use-package git-timemachine - :bind ("C-M-'" . git-timemachine)) +(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 (concat xdg_cache_home "transient-history"))) + +(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 + :commands (markdown-mode) + :config (setq-local fill-column 120)) + +;; 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) + +(use-package minions + :after (moody) + :config (minions-mode)) + +;; Various nerd icon 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 (push #'nerd-icons-corfu-formatter corfu-margin-formatters)) + +(use-package nerd-icons-dired + :hook (dired-mode . nerd-icons-dired-mode)) + +(use-package nerd-icons-ibuffer + :hook (ibuffer-mode . nerd-icons-ibuffer-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) ;; Project Management (use-package projectile - :defer 1 + :disabled :bind ("C-c p" . projectile-command-map) :config + (setopt projectile-known-projects-file (concat xdg_cache_home "projectile-bookmarks") + projectile-project-search-path '(("~/Nextcloud/Projects/src/" . 2))) (push "*node_modules" projectile-globally-ignored-directories) - (projectile-mode) - :custom - (projectile-known-projects-file (concat xdg_cache_home "projectile-bookmarks"))) - -(use-package treemacs - :defer 1 - :bind - (:map global-map - ("M-0" . treemacs-select-window) - ("C-x t 1" . treemacs-delete-other-windows) - ("C-x t t" . treemacs) - ("C-x t B" . treemacs-bookmark) - ("C-x t C-t" . treemacs-find-file) - ("C-x t M-t" . treemacs-find-tag)) - :config - (treemacs-filewatch-mode) - (treemacs-git-commit-diff-mode) - :custom - (treemacs-git-mode 'deferred) - (treemacs-persist-file (concat xdg_cache_home "treemacs-persist"))) - -(use-package consult-projectile - :after (consult projectile)) - -(use-package treemacs-magit - :after (treemacs magit)) - -(use-package treemacs-projectile - :after (treemacs projectile)) - -;;; Language support -;; Auto-format -(use-package apheleia - :defer 3 - :config (apheleia-global-mode)) - -(use-package reformatter ; required for `zig fmt' - :after (zig-mode)) - -;; Templates -(use-package tempel - :init - ;; Completion at point - (defun tempel-setup-capf () - (setq-local completion-at-point-functions - (cons #'tempel-expand ; or `tempel-complete' w/ `tempel-trigger-prexfix' - completion-at-point-functions))) - ;; :custom (tempel-trigger-prefix "<") - :bind - (("M-+" . tempel-complete) ; or `tempel-expand' - ("M-*" . tempel-insert)) - :hook - ((conf-mode - lsp-mode - text-mode) . tempel-setup-capf)) - -(use-package tempel-collection - :after (tempel)) - -(use-package yasnippet - :bind - ("C-c y s" . yas-insert-snippet) - ("C-c y v" . yas-visit-snippet-file) - :config (yas-reload-all) - :hook (prog-mode . yas-minor-mode)) - -(use-package yasnippet-snippets - :after (yasnippet)) - -(use-package consult-yasnippet - :after (yasnippet consult)) + (projectile-mode)) ;; Visualize color names (use-package rainbow-mode @@ -642,11 +622,32 @@ prog-mode toml-ts-mode) . rainbow-mode)) -;; Syntax parsing/highlighting +;; `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)) + +;; Automatically download tree-sitter grammars (use-package treesit-auto :defer 1 :config - (setq my-cpp-tsauto-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 @@ -654,180 +655,86 @@ :url "https://github.com/tree-sitter/tree-sitter-cpp" :revision "v0.21.0" :ext "\\.cpp\\'")) - (add-to-list 'treesit-auto-recipe-list my-cpp-tsauto-config) + (push as/c-tsauto-config treesit-auto-recipe-list) + (push as/cpp-tsauto-config treesit-auto-recipe-list) + ;;(add-to-list 'treesit-auto-recipe-list as/cpp-tsauto-config) (treesit-auto-add-to-auto-mode-alist 'all) - (global-treesit-auto-mode) - :custom - (treesit-auto-install 'prompt)) + (global-treesit-auto-mode)) -;; Syntax checking -(use-package flycheck - :hook (lsp-mode . flycheck-mode) - :custom (flycheck-python-flake8-executable "flake8")) +;; Better undo/redo +(use-package undo-fu + :bind (("C-z" . undo-fu-only-undo) + ("C-M-z" . undo-fu-only-redo)) + :defer 1) -(use-package consult-flycheck - :after (consult flycheck)) - -;; LSP -(use-package consult-eglot - :after (consult eglot)) - -;; Use `emacs-lsp-booster' with `eglot' -(use-package eglot-booster - :ensure (eglot-booster :host github :repo "jdtsmith/eglot-booster") - :after eglot - :config (eglot-booster-mode)) - -(use-package lsp-mode - :hook - ((csharp-ts-mode - go-ts-mode - python-ts-mode) . lsp) - (lsp-mode . lsp-enable-which-key-integration) - :custom - (lsp-use-plists t) - (lsp-prefer-flymake nil) - (lsp-session-file (concat xdg_cache_home "lsp-session"))) - -(use-package lsp-ui - :hook (lsp-mode . lsp-ui-mode)) - -(use-package consult-lsp - :after (consult lsp-mode) - :bind - (:map lsp-mode-map - ([remap xref-find-apropos] . consult-lsp-symbols))) - -(use-package lsp-treemacs - :after (lsp-mode treemacs) - :config (lsp-treemacs-sync-mode)) - -;; Configure `emacs-lsp-booster' for `lsp-mode' -(defun lsp-booster--advice-json-parse (old-fn &rest args) - "Try to parse bytecode instead of json." - (or - (when (equal (following-char) ?#) - (let ((bytecode (read (current-buffer)))) - (when (byte-code-function-p bytecode) - (funcall bytecode)))) - (apply old-fn args))) -(advice-add (if (progn (require 'json) - (fboundp 'json-parse-buffer)) - 'json-parse-buffer - 'json-read) - :around - #'lsp-booster--advice-json-parse) - -(defun lsp-booster--advice-final-command (old-fn cmd &optional test?) - "Prepend emacs-lsp-booster command to lsp CMD." - (let ((orig-result (funcall old-fn cmd test?))) - (if (and (not test?) ; for check lsp-server-present? - (not (file-remote-p default-directory)) ; see lsp-resolve-final-command, it would add extra shell wrapper - lsp-use-plists - (not (functionp 'json-rpc-connection)) ; native json-rpc - (executable-find "emacs-lsp-booster")) - (progn - (message "Using emacs-lsp-booster for %s!" orig-result) - (cons "emacs-lsp-booster" orig-result)) - orig-result))) -(advice-add 'lsp-resolve-final-command :around #'lsp-booster--advice-final-command) - -;; Debugging -(use-package dap-mode - :after (lsp-mode) - :bind - (:map dap-mode-map - ("" . dap-debug) - ("" . dap-next) - ("" . dap-step-in) - ("S-" . dap-disconnect) - ("C-S-" . dap-debug-restart) - ("C-c d" . dap-debug-last)) +(use-package undo-fu-session + :after (undo-fu) :config - (eval-when-compile - (require 'cl-lib)) - (require 'dap-gdb-lldb) - (require 'dap-lldb) - (require 'dap-python) - :custom - (dap-auto-configure-features '(sessions locals tooltip)) - (dap-breakpoints-file (concat xdg_cache_home "dap-breakpoints")) - (dap-lldb-debug-program 'lldb-vscode) - (dap-utils-extension-path (concat user-emacs-directory "dap-extensions/")) - (dap-python-debugger 'debugpy) - ;; Templates - (dap-register-debug-template - "Rust :: LLDB Run Configuration" - (list :type "lldb" - :request "launch" - :name "LLDB::Run" - :gdbpath "rust-lldb"))) + (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)) -(use-package realgud - :defer t) +;; Mini-buffer completion UI +(use-package vertico + :config + (setopt vertico-cycle t + vertico-count 10 + vertico-resize t + vertico-scroll-margin 1 + completion-ignore-case t + read-buffer-completion-ignore-case t + read-file-name-completion-ignore-case t) + :init (vertico-mode)) -(use-package realgud-lldb - :defer t) - -;; C++ -(use-package modern-cpp-font-lock - :hook (c++-ts-mode . modern-c++-font-lock-mode)) - -;; Go -(use-package go-mode - :hook (go-ts-mode . go-mode) - :config (add-hook 'before-save-hook #'lsp-organize-imports)) - -;; JavaScript -(use-package js2-mode - :interpreter (("nodejs" . js2-mode) ("node" . js2-mode)) - :hook (js-ts-mode . js2-minor-mode) - :custom - (js-indent-level 2) - (js2-mode-show-strict-warnings t)) - -;; Python -(use-package lsp-pyright - :after (python) - :hook (python-ts-mode . (lambda () - (setq-local fill-column 80) - (require 'lsp-pyright) - (lsp)))) ; or `lsp-deferred' - -(use-package numpydoc - :after (python) - :bind (:map python-mode-map - ("C-c C-n" . numpydoc-generate)) - :custom (numpydoc-insert-examples-block nil)) - -(use-package conda - :after (python) - :init - (setq conda-anaconda-home (expand-file-name "/opt/miniconda3") - conda-env-home-directory (expand-file-name "~/.conda/envs")) - (conda-env-initialize-interactive-shells) - ;; (conda-env-autoactivate-mode) - :hook - ('find-file-hook . (lambda () - (when (bound-and-true-p conda-project-env-path) - (conda-env-activate-for-buffer))))) - -;; Web +;; Web and SSG (define-derived-mode astro-mode web-mode "astro") (use-package web-mode - :custom - (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\\'"))) + :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 + ("C-c y i" . yas-insert-snippet) + ("C-c y v" . yas-visit-snippet-file)) + :config (yas-reload-all) + :hook (prog-mode . yas-minor-mode)) + +(use-package yasnippet-snippets + :after (yasnippet)) + +(use-package consult-yasnippet + :after (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 @@ -835,13 +742,9 @@ (interactive) (save-buffer) (zig--run-cmd "build")) - (setq-local fill-column 100)) + (setq-local fill-column 100) + (setopt zig-format-on-save nil)) -;;; File format/markup support -(use-package markdown-mode - :commands (markdown-mode) - :config (setq-local fill-column 120)) - -(use-package yaml-pro - :hook (yaml-ts-mode . yaml-pro-ts-mode)) +(push "~/.config/emacs/lisp/" load-path) +(require 'init-org) ;;; init.el ends here diff --git a/dot_config/emacs/lisp/init-org.el b/dot_config/emacs/lisp/init-org.el new file mode 100644 index 0000000..b457714 --- /dev/null +++ b/dot_config/emacs/lisp/init-org.el @@ -0,0 +1,102 @@ +;;; 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-package org + :bind + (:map global-map + ("C-c a" . org-agenda) + ("C-c c" . org-capture) + ("C-c l" . org-store-link)) + :config + (setopt org-agenda-files (list (concat org-directory "/personal") + (concat org-directory "/projects") + (concat org-directory "/work")) + org-hide-emphasis-markers t + org-log-done 'time + org-return-follows-link t + org-todo-keywords '((sequence "TODO(t)" "IN-PROGRESS(i@/!)" "|" + "DONE(d!)" "BLOCKED(b@)" "WONT-DO(w@/!)" )) + org-todo-keyword-faces '(("TODO" . (icon-button)) + ("IN-PROGRESS" . (tool-bar)) + ("BLOCKED" . (match)) + ("WONT-DO" . (org-done)))) + (setopt org-capture-templates + `( + ("m" "Personal") + ("mj" "Log Entry" + entry (file+datetree ,(concat org-directory "/personal/log.org")) + "* %?" + :empty-lines 1) + + ("mn" "Note" + entry (file+headline ,(concat org-directory "/personal/notes.org") "Note to self...") + "* %?" + :empty-lines 1) + + ("mt" "Todo" + entry (file+headline ,(concat org-directory "/personal/todo.org") "Personal Tasks") + "* TODO [#B] %?\n:Created: %T\n " + :empty-lines 1) + + ("p" "Projects") + ("pn" "Note" + entry (file+headline ,(concat org-directory "/projects/notes.org") "Project Notes") + "** %?" + :empty-lines 1) + + ("pt" "Todo" + entry (file+headline ,(concat org-directory "/projects/todo.org") "Project Tasks") + "* TODO [#B] %?\n:Created: %T\n%i\n%a\nNotes: " + :empty-lines 0) + + ("w" "Work") + ("wn" "Note" + entry (file+headline "~/Nextcloud/Documents/org/work/notes.org" "Work notes") + "** %?" + :empty-lines 0) + + ("wt" "Todo" + entry (file+headline "~/Nextcloud/Documents/org/work/todo.org" "Work tasks") + "* TODO [#B] %?\n:Created: %T\n%i\n%a\nNotes: " + :empty-lines 0))) + :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" + ;; ("d" . org-priority-down) + ;; ("u" . org-priority-up) + ;; ("r" . org-shiftmetaright) + ;; ("l" . org-shiftmetaleft)) + ) + +(provide 'init-org) +;;; org-mode.el ends here