From e760eac4dfac15d842f9b1d21edfcfa695dc5d8e Mon Sep 17 00:00:00 2001 From: Jessie Hildebrandt Date: Wed, 29 Nov 2023 03:57:08 -0500 Subject: [PATCH] Modernize config for Emacs 29.1 --- init.el | 1074 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 633 insertions(+), 441 deletions(-) diff --git a/init.el b/init.el index 527d96e..4b0e898 100644 --- a/init.el +++ b/init.el @@ -18,6 +18,7 @@ ;; ;; All configuration efforts here are organized around the use of wrapped ;; `use-package' macros. The keyword order for any config entry should be: +;; - preface ;; - if/when/unless ;; - demand ;; - after @@ -58,8 +59,6 @@ ;; ;; -------------------------------------------------------------------------- ;; -(defconst user/font "Fira Code 10" "Default font.") - (defconst user/init-file (locate-user-emacs-file "init.el") "Location of user init file.") (defconst user/early-init-file (locate-user-emacs-file "early-init.el") "Location of user early-init file.") @@ -75,43 +74,47 @@ ";;; Commentary:" ";; This file has been automatically generated by init.el." - ";; More relevant commentary is likely in init.el, not here." + ";; More relevant commentary is likely in init.el." ";;; Code:" - (defconst user/gc-cons-threshold (* 32 1024 1024) "Preferred garbage collection threshold value (32MB).") - (defconst user/gc-cons-percentage 0.1 "Preferred garbage collection percentage value (10%).") + (defconst user/default-gc-cons-threshold gc-cons-threshold) + (defconst user/default-gc-cons-percentage gc-cons-percentage) (defun user/defer-garbage-collection () "Defer garbage collection by maximizing the collection threshold." (setq gc-cons-threshold most-positive-fixnum gc-cons-percentage 1.0)) (defun user/restore-garbage-collection () - "Restore the garbage collection threshold parameters in a deferred fashion." - (setq gc-cons-threshold user/gc-cons-threshold - gc-cons-percentage user/gc-cons-percentage)) + "Restore the garbage collection threshold parameters to their default values." + (setq gc-cons-threshold user/default-gc-cons-threshold + gc-cons-percentage user/default-gc-cons-percentage)) ";; Defer garbage collection until after initialization" (user/defer-garbage-collection) (add-hook 'emacs-startup-hook #'user/restore-garbage-collection) ";; Clear `file-name-handler-alist' until after initialization" - (let ((default-file-name-handler-alist file-name-handler-alist)) + (let ((user/file-name-handler-alist file-name-handler-alist)) (setq file-name-handler-alist nil) - (add-hook 'emacs-startup-hook (lambda () (setq file-name-handler-alist default-file-name-handler-alist)))) + (add-hook 'emacs-startup-hook (lambda () (setq file-name-handler-alist user/file-name-handler-alist)))) ";; Configure GUI components before initial frame creation" - (setq inhibit-x-resources t + (setq font-use-system-font t + pgtk-wait-for-event-timeout 0 frame-inhibit-implied-resize t default-frame-alist '((width . 100) (height . 40) - (font . ,user/font) (menu-bar-lines . 0) (tool-bar-lines . 0) (vertical-scroll-bars . nil) (background-color . "gray15") (foreground-color . "gray85"))) + ";; Prevent system-provided configuration files from loading" + (setq site-run-file nil + inhibit-default-init t) + ";; package.el initialization is handled manually in init.el" (setq package-enable-at-startup nil) @@ -122,11 +125,10 @@ "Format and pretty-print list FORMS to FILE." (with-temp-file file (mapcar (lambda (form) - (insert (concat - (if (stringp form) - (prin1-to-string form :no-escape) - (pp-to-string form)) - "\n"))) + (insert (if (stringp form) + (prin1-to-string form :no-escape) + (pp-to-string form)) + "\n")) forms))) ;; Create (and load) early-init file if it does not yet exist, or if this file @@ -149,28 +151,24 @@ ;; To be evaluated at both compile time and run time (eval-and-compile - (setq package-user-dir (locate-user-emacs-file "package/") + (setq package-user-dir (locate-user-emacs-file "packages/") package-native-compile t package-check-signature nil - package-install-upgrade-built-in t use-package-hook-name-suffix nil - use-package-always-demand (daemonp))) + use-package-always-demand (daemonp) + native-comp-compiler-options "-march=native -flto")) ;; To be evaluated only at compile time (eval-when-compile ;; Initialize package.el (require 'package) + (require 'use-package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (unless (bound-and-true-p package--initialized) (package-initialize)) (package-refresh-contents) - ;; Install use-package - (unless (package-installed-p 'use-package) - (package-install 'use-package)) - (require 'use-package) - ;; After initialization, build quickstart file containing package autoload defs ;; and compile it alongside any other uncompiled Elisp files in installed packages (add-hook 'emacs-startup-hook (lambda () @@ -189,12 +187,12 @@ ;; -------------------------------------------------------------------------- ;; ;; -;; Custom interactive functions +;; User commands ;; ;; -------------------------------------------------------------------------- ;; (defun user/open-init-file () - "Opens the user init file in a new buffer." + "Open the user init file in a new buffer." (interactive) (find-file user/init-file)) @@ -205,23 +203,8 @@ (byte-compile-file user/init-file) (byte-compile-file user/early-init-file)) -(defun user/download-latest-init-file () - "Download the latest user init file from jessieh.net/emacs. - -The user init file will be automatically recompiled after downloading. - -If `user/init-file' points to a symlink, nothing will be downloaded." - (interactive) - (if (file-symlink-p user/init-file) - (message "%s is a symlink, operation aborted. Please update the init file manually." user/init-file) - (when (yes-or-no-p "Download latest init file from jessieh.net/emacs? ") - (message "Updating init file...") - (url-copy-file "https://jessieh.net/emacs" user/init-file :ok-if-already-exists) - (user/byte-compile-init-files)))) - (defun user/refresh-packages () "Refresh packages that have been configured for use in the user init file. - This is accomplished by deleting `package-user-dir' and recompiling the user init file, which initializes the package manager during compile time." (interactive) @@ -230,48 +213,6 @@ init file, which initializes the package manager during compile time." (delete-directory package-user-dir :recursive) (user/byte-compile-init-files))) -(defun user/indent-buffer () - "Call `indent-region' on the contents of the active buffer." - (interactive) - (indent-region (point-min) (point-max))) - -(defun user/select-minibuffer-window () - "Select the minibuffer window if it is active." - (interactive) - (when (active-minibuffer-window) - (select-window (active-minibuffer-window)))) - -(defun user/scratch-buffer () - "Open the scratch buffer, (re)creating it if not present." - (interactive) - (pop-to-buffer (get-scratch-buffer-create))) - -(defun user/scan-directory-for-projects () - "Prompt for a directory and then scan for any project roots within. - -Inaccessible directories and .git directories are skipped during searching. -When done searching, you will be shown a buffer of all discovered project -directories and will be prompted to index them. Choosing to index the project -directories will register them with Emacs' project management system." - (interactive) - (when-let* ((valid-root-p (lambda (path) - (and (file-accessible-directory-p path) - (not (string= (file-name-nondirectory path) ".git"))))) - (directory (read-directory-name "Look for projects in: ")) - (project-dir-list (mapcar #'file-name-directory - (directory-files-recursively directory "\\.git$" #'valid-root-p t))) - (num-projects-found (length project-dir-list)) - (temp-buffer-name (concat "*" (number-to-string num-projects-found) " Project Roots Found*"))) - (with-output-to-temp-buffer temp-buffer-name - (princ (mapconcat #'identity project-dir-list "\n"))) - (when (yes-or-no-p "Index all of these directories as projects? ") - (unless (fboundp 'project-remember-projects-under) - (require 'project)) - (mapc #'project-remember-projects-under project-dir-list) - (message "%d%s" num-projects-found " directories indexed as projects.")) - (with-current-buffer temp-buffer-name - (kill-buffer-and-window)))) - ;; -------------------------------------------------------------------------- ;; ;; ;; Internal/built-in packages @@ -280,7 +221,6 @@ directories will register them with Emacs' project management system." (defmacro editor-feature (name docstring &rest args) "Apply NAME and ARGS to `use-package' with `:ensure' defaulted to nil. - DOCSTRING is an optional form that is discarded upon expansion." (declare (doc-string 2) (indent defun)) @@ -291,26 +231,40 @@ DOCSTRING is an optional form that is discarded upon expansion." ;; emacs ;; ---------------------------------- ;; -(defun display-startup-echo-area-message () - "Display a blank message in the echo area on startup. - -This overrides the default `display-startup-echo-area-message' function." - (message "")) - -(defun user/ensure-region-active (func &rest args) - "Apply ARGS to FUNC only if `region-active-p' is non-nil." - (when (region-active-p) - (apply func args))) - (editor-feature emacs "Provides an extensible, customizable, self-documenting real-time display editor." + :preface + (defconst user/load-directory (locate-user-emacs-file "load/") "Location of extra user Lisp files.") + (defun user/indent-buffer () + "Call `indent-region' on the contents of the active buffer." + (interactive) + (indent-region (point-min) (point-max))) + (defun user/select-minibuffer-window () + "Select the minibuffer window if it is active." + (interactive) + (when (active-minibuffer-window) + (select-window (active-minibuffer-window)))) + (defun user/scratch-buffer () + "Open the scratch buffer, (re)creating it if not present." + (interactive) + (pop-to-buffer (get-scratch-buffer-create))) + (defun user/ensure-region-active (func &rest args) + "Apply ARGS to FUNC only if `region-active-p' is non-nil." + (when (region-active-p) + (apply func args))) + + :init + ;; Add user dir to `load-path' + (add-to-list 'load-path user/load-directory) + + ;; Use default system monospace and proportional fonts + (set-face-font 'fixed-pitch (font-get-system-font)) + (set-face-font 'variable-pitch (font-get-system-normal-font)) + :config - ;; Enable upcase/downcase region commands - (put 'upcase-region 'disabled nil) - (put 'downcase-region 'disabled nil) - (advice-add 'upcase-region :around 'user/ensure-region-active) - (advice-add 'downcase-region :around 'user/ensure-region-active) + ;; Override echo area greeting function + (defun display-startup-echo-area-message () (message "")) :custom ;; Default working directory @@ -321,15 +275,19 @@ This overrides the default `display-startup-echo-area-message' function." ;; General configuration (frame-title-format '("Emacs — %b") "Set frame title to buffer name") (truncate-lines t "Truncate lines instead of wrapping") - (kill-whole-line t "Include newline character when killing a line.") + (kill-whole-line t "Include newline character when killing a line") (context-menu-mode t "Enable global context menu support") (message-truncate-lines t "Truncate messages in the echo area") (cursor-in-non-selected-windows nil "Hide cursor in inactive windows") (ring-bell-function 'ignore "Disable terminal bell") + (line-spacing 0.20 "Add 20% extra space between lines") (fill-column 80 "Set default line-wrap column to column 80") + (help-window-select t "Focus help windows after summoning them") (max-mini-window-height 10 "Limit minibuffer height to 10 lines") + (tab-always-indent 'complete "Allow Tab key to indent current line or complete a symbol") (enable-recursive-minibuffers t "Allow minibuffer commands to be called in the minibuffer") - (x-gtk-use-system-tooltips nil "Disable use of system tooltips in favor of Emacs tooltips.") + (disabled-command-function nil "Enable invocation of all disabled interactive commands") + (use-system-tooltips t "Enable use of system tooltips in favor of Emacs tooltips") (load-prefer-newer t "Load from source files if they are newer than bytecode files") ;; Startup @@ -339,14 +297,14 @@ This overrides the default `display-startup-echo-area-message' function." (inhibit-default-init t "Do not attempt to load any OS-provided init files") ;; Default style rules - (sentence-end-double-space nil "Do not use double spacing between sentences in paragraphs.") - (require-final-newline t "Require a terminating newline at the end of every file.") + (sentence-end-double-space nil "Do not use double spacing between sentences in paragraphs") + (require-final-newline t "Require a terminating newline at the end of every file") (indent-tabs-mode nil "Use spaces for indentation") (tab-width 4 "Use 4 spaces for indentation") ;; Scrolling (mouse-wheel-progressive-speed nil "Disable mouse wheel acceleration during scrolling") - (scroll-preserve-screen-position 1 "Prevent the cursor from moving during scrolling") + (scroll-preserve-screen-position 'always "Prevent the cursor from moving during scrolling") (scroll-conservatively 101 "Scroll only one line at a time when cursor leaves view") (scroll-margin 5 "Maintain margin of 5 lines around cursor during scrolling") @@ -370,40 +328,34 @@ This overrides the default `display-startup-echo-area-message' function." unresolved docstrings)) - ;; Set default buffer display action priority: - ;; focus a window already displaying the buffer, else display buffer in current window - (display-buffer-base-action '((display-buffer-reuse-window display-buffer-same-window))) - - ;; Set default tooltip frame parameters - (tooltip-frame-parameters '((name . "tooltip") (border-width . 1) (internal-border-width . 10))) - ;; Filter out buffer-incompatible interactive commands by default (read-extended-command-predicate #'command-completion-default-include-p) :bind ;; General binds ("C-z" . undo) - ("C-h" . delete-backward-char) - ("C-?" . help-command) - ("C-c SPC" . tmm-menubar) - ("C-c DEL" . fixup-whitespace) - ("C-c d" . delete-pair) - ("C-c ." . emoji-search) - ("C-c q" . visual-line-mode) - ("C-c r" . revert-buffer-quick) - ("C-c f" . display-fill-column-indicator-mode) + ("C-x C-z" . nil) ("C-c \\" . user/indent-buffer) - ("C-c o" . user/select-minibuffer-window) - ("C-c s" . user/scratch-buffer) - ("C-c m" . (lambda () (interactive) (message "%s is in %s" (buffer-name) major-mode))) - ;; Navigation + ;; Cursor navigation ("M-n" . scroll-up-line) ("M-p" . scroll-down-line) ("C-M-n" . forward-paragraph) ("C-M-p" . backward-paragraph) :bind* + ;; General binds + ("C-c DEL" . fixup-whitespace) + ("C-c d" . delete-pair) + ("C-c ." . emoji-search) + ("C-c i" . overwrite-mode) + ("C-c v" . visual-line-mode) + ("C-c r" . revert-buffer-quick) + ("C-c f" . display-fill-column-indicator-mode) + ("C-c o" . user/select-minibuffer-window) + ("C-c s" . user/scratch-buffer) + ("C-c m" . (lambda () (interactive) (message "%s is in %s" (buffer-name) major-mode))) + ;; Window navigation ("C-c C-i" . windmove-up) ("C-c C-k" . windmove-down) @@ -411,8 +363,10 @@ This overrides the default `display-startup-echo-area-message' function." ("C-c C-l" . windmove-right) :hook - ;; Minibuffer line spacing setup - (minibuffer-setup-hook . (lambda () (setq-local line-spacing 0.15)))) + ;; Defer garbage collection while the minibuffer is active + ;; (Many interactive commands are memory-intensive and trigger many GC cycles) + (minibuffer-setup-hook . user/defer-garbage-collection) + (minibuffer-exit-hook . (lambda () (run-at-time 1 nil #'user/restore-garbage-collection)))) ;; ---------------------------------- ;; ;; autorevert @@ -423,6 +377,43 @@ This overrides the default `display-startup-echo-area-message' function." :config (global-auto-revert-mode)) +;; ---------------------------------- ;; +;; c-ts-mode +;; ---------------------------------- ;; + +(editor-feature c-ts-mode + "Major mode(s) for C and C++, using the Tree-sitter parsing library." + :preface + (defun user/c-ts-indent-style() + "Provide custom `c-ts-mode' indentation style." + `(;; Align function arguments to the start of the first one, offset if standalone + ((match nil "argument_list" nil 1 1) parent-bol c-ts-mode-indent-offset) + ((parent-is "argument_list") (nth-sibling 1) 0) + ;; Ditto for parameters + ((match nil "parameter_list" nil 1 1) parent-bol c-ts-mode-indent-offset) + ((parent-is "parameter_list") (nth-sibling 1) 0) + ;; Indent inside case blocks + ((parent-is "case_statement") standalone-parent c-ts-mode-indent-offset) + ;; Do not indent preprocessor statements or within namespaces + ((node-is "preproc") column-0 0) + ((n-p-gp nil nil "namespace_definition") grand-parent 0) + ;; Append to BSD style + ,@(alist-get 'bsd (c-ts-mode--indent-styles 'cpp)))) + :custom + (c-ts-mode-indent-offset 2 "Use 2 spaces for indenting C and C++ code") + (c-ts-mode-indent-style #'user/c-ts-indent-style "Use custom indentation rules for C and C++") + :mode + ("\\.cppm\\'" . c++-ts-mode)) + +;; ---------------------------------- ;; +;; compile +;; ---------------------------------- ;; + +(editor-feature compile + "Provides shortcuts for running and parsing compiler output." + :hook + (compilation-filter-hook . ansi-color-compilation-filter)) + ;; ---------------------------------- ;; ;; display-line-numbers ;; ---------------------------------- ;; @@ -448,9 +439,15 @@ This overrides the default `display-startup-echo-area-message' function." ;; Remove the mode-line segment that Eglot adds (setq mode-line-misc-info (assoc-delete-all 'eglot--managed-mode mode-line-misc-info)) :hook - (gdscript-mode . eglot-ensure) - (js-mode-hook . eglot-ensure) - (typescript-mode-hook . eglot-ensure)) + (c-ts-base-mode-hook . eglot-ensure) + (js-ts-mode-hook . eglot-ensure) + (typescript-mode-hook . eglot-ensure) + (gdscript-mode-hook . eglot-ensure) + :bind + (:map eglot-mode-map + ("C-c \\" . eglot-format-buffer) + ("C-c q" . eglot-code-action-quickfix) + ("C-c C-q" . eglot-code-actions))) ;; ---------------------------------- ;; ;; elec-pair @@ -465,61 +462,57 @@ This overrides the default `display-startup-echo-area-message' function." ;; eshell ;; ---------------------------------- ;; -(defun user/open-eshell (&optional force-new-session) - "Focus the last active `eshell' session, or start a new one if none available. - -When FORCE-NEW-SESSION is non-nil, a new session will be started even if there -is already an active session to bring into focus." - (interactive) - (let ((eshell-buffer (cl-find-if (lambda (buffer) - (eq (buffer-local-value 'major-mode buffer) - 'eshell-mode)) - (buffer-list)))) - (if eshell-buffer - (if force-new-session - (let ((current-buffer-directory default-directory)) - (pop-to-buffer eshell-buffer) - (let ((default-directory current-buffer-directory)) - (eshell :new-session))) - (pop-to-buffer eshell-buffer)) - (eshell)))) - -(defun user/auto-toggle-eshell-buffer-tabs () - "Enable `tab-line-mode' in all `eshell-mode' buffers if multiple are open. - -Also automatically disables `tab-line-mode' if all but one `eshell-mode' buffer -have been closed." - (let ((eshell-buffers (cl-remove-if-not (lambda (buffer) - (eq (buffer-local-value 'major-mode buffer) - 'eshell-mode)) - (buffer-list)))) - (mapc (lambda (buffer) - (with-current-buffer buffer - (tab-line-mode (and (length< eshell-buffers 2) -1)))) - eshell-buffers))) - -(defun user/prettify-eshell-pwd (path) - "Return PATH formatted and with all but the last directory name abbreviated." - (let* ((components (split-string (abbreviate-file-name path) "/")) - (str "")) - (while (cdr components) - (setq str (concat str - (cond ((= 0 (length (car components))) - "/") - ((= 1 (length (car components))) - (concat (car components) "/")) - (t - (if (string= "." (string (elt (car components) 0))) - (concat (substring (car components) 0 2) "/") - (string (elt (car components) 0) ?/))))) - components (cdr components))) - (concat (propertize str 'face 'font-lock-comment-face) - (propertize (cl-reduce (lambda (a b) (concat a "/" b)) - components) - 'face 'font-lock-doc-face)))) - (editor-feature eshell "Provides a shell-like interpreter that can process shell or Lisp commands." + :preface + (defun user/open-eshell (&optional force-new-session) + "Focus the last active `eshell' session, or start a new one if none available. +When FORCE-NEW-SESSION is non-nil, a new session will be started even if there +is already an active session to bring into focus." + (interactive) + (let ((eshell-buffer (cl-find-if (lambda (buffer) + (eq (buffer-local-value 'major-mode buffer) + 'eshell-mode)) + (buffer-list)))) + (if eshell-buffer + (if force-new-session + (let ((current-buffer-directory default-directory)) + (pop-to-buffer eshell-buffer) + (let ((default-directory current-buffer-directory)) + (eshell :new-session))) + (pop-to-buffer eshell-buffer)) + (eshell)))) + (defun user/auto-toggle-eshell-buffer-tabs () + "Enable `tab-line-mode' in all `eshell-mode' buffers if multiple are open. +Also automatically disables `tab-line-mode' if all but one `eshell-mode' buffer +have been closed." + (let ((eshell-buffers (cl-remove-if-not (lambda (buffer) + (eq (buffer-local-value 'major-mode buffer) + 'eshell-mode)) + (buffer-list)))) + (mapc (lambda (buffer) + (with-current-buffer buffer + (tab-line-mode (and (length< eshell-buffers 2) -1)))) + eshell-buffers))) + (defun user/prettify-eshell-pwd (path) + "Return PATH formatted and with all but the last directory name abbreviated." + (let* ((components (split-string (abbreviate-file-name path) "/")) + (str "")) + (while (cdr components) + (setq str (concat str + (cond ((= 0 (length (car components))) + "/") + ((= 1 (length (car components))) + (concat (car components) "/")) + (t + (if (string= "." (string (elt (car components) 0))) + (concat (substring (car components) 0 2) "/") + (string (elt (car components) 0) ?/))))) + components (cdr components))) + (concat (propertize str 'face 'font-lock-comment-face) + (propertize (cl-reduce (lambda (a b) (concat a "/" b)) + components) + 'face 'font-lock-doc-face)))) :custom (eshell-prompt-regexp "^[^#❱\n]* [#❱] ") (eshell-visual-commands '("fish" "bash" @@ -531,22 +524,14 @@ have been closed." (eshell-banner-message '(if (executable-find "fortune") (shell-command-to-string "fortune -s computers") "Hello, commander.")) - (eshell-prompt-function (lambda () - (concat "\n" - (user/prettify-eshell-pwd (eshell/pwd)) - (if (= (user-uid) 0) - " # " - " ❱ ")))) + (eshell-prompt-function (lambda () (concat "\n" (user/prettify-eshell-pwd (eshell/pwd)) + (if (= (user-uid) 0) " # " " ❱ ")))) :hook - (eshell-post-command-hook . (lambda () - (rename-buffer (concat eshell-buffer-name - " " - (user/prettify-eshell-pwd (eshell/pwd))) - :unique))) - (eshell-mode-hook . (lambda () - (setq-local line-spacing 0.15 - global-hl-line-mode nil - tab-line-tabs-function #'tab-line-tabs-mode-buffers))) + (eshell-post-command-hook . (lambda () (rename-buffer (concat eshell-buffer-name " " + (user/prettify-eshell-pwd (eshell/pwd))) + :unique))) + (eshell-mode-hook . (lambda () (setq-local global-hl-line-mode nil + tab-line-tabs-function #'tab-line-tabs-mode-buffers))) (buffer-list-update-hook . user/auto-toggle-eshell-buffer-tabs) :bind* ("C-c RET" . user/open-eshell) @@ -575,17 +560,16 @@ have been closed." ;; files ;; ---------------------------------- ;; -(defconst user/custom-file (locate-user-emacs-file "custom.el") "Location of user customizations file.") -(defconst user/backup-directory (locate-user-emacs-file "backups/") "Location of user backup directory.") -(defconst user/auto-save-directory (locate-user-emacs-file "auto-saves/") "Location of user auto save directory.") -(defconst user/lock-file-directory (locate-user-emacs-file "lock-files/") "Location of user lock file directory.") - -(make-directory user/backup-directory :parents) -(make-directory user/auto-save-directory :parents) -(make-directory user/lock-file-directory :parents) - (editor-feature files "Defines most of Emacs' file-handling functionality." + :preface + (defconst user/custom-file (locate-user-emacs-file "custom.el") "Location of user customizations file.") + (defconst user/backup-directory (locate-user-emacs-file "backups/") "Location of user backup directory.") + (defconst user/auto-save-directory (locate-user-emacs-file "auto-saves/") "Location of user auto save directory.") + (defconst user/lock-file-directory (locate-user-emacs-file "lock-files/") "Location of user lock file directory.") + (make-directory user/backup-directory :parents) + (make-directory user/auto-save-directory :parents) + (make-directory user/lock-file-directory :parents) :custom (version-control t "Use version numbers on backup files") (kept-new-versions 5 "Keep 5 recent backup files") @@ -605,29 +589,31 @@ have been closed." (editor-feature flymake "Provides universal on-the-fly syntax checking." + :config + (advice-add 'flymake-show-buffer-diagnostics :after (lambda () (pop-to-buffer (flymake--diagnostics-buffer-name)))) :hook (prog-mode-hook . flymake-mode) :bind - ("C-c C-e" . flymake-show-buffer-diagnostics)) + (:map flymake-mode-map + ("C-c C-e" . flymake-show-buffer-diagnostics))) ;; ---------------------------------- ;; ;; frame ;; ---------------------------------- ;; -(defvar user/initial-frame-created nil "Whether or not the first frame has been initialized by the server.") -(defvar user/after-daemon-make-initial-frame-functions nil "Run when the first frame is produced by the server in daemon mode.") - -(defun user/set-up-frame (frame) - "Set up newly-created frame FRAME." - (when (and (daemonp) - (display-graphic-p frame) - (not user/initial-frame-created)) - (with-selected-frame frame - (run-hooks 'user/after-daemon-make-initial-frame-functions) - (setq user/initial-frame-created t)))) - (editor-feature frame "Graphical frame configuration." + :preface + (defvar user/initial-frame-created nil "Whether or not the first frame has been initialized by the server.") + (defvar user/after-daemon-make-initial-frame-hook nil "Run when the first frame is produced by the server in daemon mode.") + (defun user/set-up-frame (frame) + "Set up newly-created frame FRAME." + (when (and (daemonp) + (display-graphic-p frame) + (not user/initial-frame-created)) + (with-selected-frame frame + (run-hooks 'user/after-daemon-make-initial-frame-hook) + (setq user/initial-frame-created t)))) :config (mapc #'user/set-up-frame (frame-list)) :hook @@ -665,7 +651,8 @@ have been closed." :config (show-paren-mode) :custom - (show-paren-delay 0.0 "Highlight matching delimiters instantly")) + (show-paren-delay 0.0 "Highlight matching delimiters instantly") + (show-paren-context-when-offscreen t "Show context of matching off-screen delimiters")) ;; ---------------------------------- ;; ;; pixel-scroll @@ -673,14 +660,38 @@ have been closed." (editor-feature pixel-scroll "Enables pixel-level animation of scrolling events." - :config - (pixel-scroll-precision-mode) + :when + (or (daemonp) + (display-graphic-p)) :custom - (pixel-scroll-precision-interpolate-page t "Enable pixel-level scrolling for page-wise scrolling events") - (pixel-wait 0.001 "Idle for a fraction of a second during each animation step for gentler animations") + (pixel-scroll-precision-interpolate-page t "Enable pixel-level scrolling for page-wise scroll events") + (pixel-scroll-precision-large-scroll-height 40.0 "Animate any scroll moving the view more than 40 pixels") + :hook + (server-after-make-frame-hook . pixel-scroll-precision-mode) + (emacs-startup-hook . pixel-scroll-precision-mode) :bind - (" " . pixel-scroll-interpolate-down) - (" " . pixel-scroll-interpolate-up)) + (:map pixel-scroll-precision-mode-map + ("M-v" . pixel-scroll-interpolate-up) + ("C-v" . pixel-scroll-interpolate-down))) + +;; ---------------------------------- ;; +;; project +;; ---------------------------------- ;; + +(editor-feature project + "Provides functionality for dealing with projects." + :preface + (defun user/index-projects (dir) + "Recursively scan for and index any project roots within DIR." + (interactive + (list (read-directory-name "Look for projects in: "))) + (when-let (project-roots (directory-files-recursively dir "\\.git$" #'project--find-in-directory t)) + (message "%d directories indexed as projects." + (seq-reduce '+ (mapcar #'project-remember-projects-under project-roots) 0)))) + :bind + (:map project-prefix-map + ("e" . flymake-show-project-diagnostics) + ("RET" . project-eshell))) ;; ---------------------------------- ;; ;; savehist @@ -689,7 +700,12 @@ have been closed." (editor-feature savehist "Persists minibuffer history between sessions." :config - (savehist-mode)) + ;; Save last 30 items from the kill ring between sessions + (add-to-list 'savehist-additional-variables '(kill-ring . 30)) + (savehist-mode) + :hook + ;; Remove text properties from `kill-ring' before saving it + (kill-emacs-hook . (lambda () (setq kill-ring (mapcar 'substring-no-properties kill-ring))))) ;; ---------------------------------- ;; ;; save-place @@ -757,6 +773,15 @@ have been closed." (tab-line-right-button nil "Disable the right scroll button") (tab-line-switch-cycling t "Enable wrap-around tab cycling")) +;; ---------------------------------- ;; +;; treesit +;; ---------------------------------- ;; + +(editor-feature treesit + "Integrates the Tree-sitter parsing library into Emacs." + :config + (add-to-list 'treesit-language-source-alist '(cpp "https://github.com/alfaix/tree-sitter-cpp/tree/alfaix/cpp-20-modules"))) + ;; ---------------------------------- ;; ;; uniquify ;; ---------------------------------- ;; @@ -768,6 +793,41 @@ have been closed." (uniquify-after-kill-buffer-p t "Update buffer names after killing") (uniquify-ignore-buffers-re "^\\*" "Avoid renaming special buffers")) +;; ---------------------------------- ;; +;; window +;; ---------------------------------- ;; + +(editor-feature window + "Provides commands for interacting with Emacs windows." + :preface + (defun user/buffer-special-p (buffer) + "Return non-nil if BUFFER is not visiting a file." + (and (not (buffer-file-name (get-buffer buffer))) + (not (string= (buffer-name (get-buffer buffer)) "*scratch*")) + (not (string-prefix-p " *" (buffer-name (get-buffer buffer)))))) + (defun user/window-special-p (window) + "Return non-nil if the current buffer of WINDOW is not visiting a file." + (and (not (window-dedicated-p window)) + (user/buffer-special-p (window-buffer window)))) + (defun user/display-buffer-reuse-special-window (buffer _alist) + "Return a window based on whether its displayed buffer is not visiting a file. +Display BUFFER in the returned window. Return nil if no usable window is found." + (let ((windows (seq-filter 'user/window-special-p (window-list nil :no-minibuf)))) + (cl-letf (((symbol-function 'window-list-1) (lambda (&rest _args) windows))) + (when-let ((window (get-lru-window))) + (set-window-buffer window buffer) + window)))) + :custom + ;; Set default buffer display action priority: + ;; focus window already displaying buffer, else display buffer in current window + (display-buffer-base-action '((display-buffer-reuse-window display-buffer-same-window))) + ;; Set special (non-file) buffer display action priority: + ;; focus window already displaying buffer, else reuse another special buffer's window, + ;; else attempt pop up new window with buffer + (display-buffer-alist `((user/buffer-special-p (display-buffer-reuse-window + user/display-buffer-reuse-special-window + display-buffer-pop-up-window))))) + ;; ---------------------------------- ;; ;; whitespace ;; ---------------------------------- ;; @@ -797,7 +857,7 @@ DOCSTRING is an optional form that is discarded upon expansion." `(use-package ,name :ensure t ,@args)) ;; ---------------------------------- ;; -;; Theme setup +;; Theme ;; ---------------------------------- ;; (external-package adwaita-dark-theme @@ -809,10 +869,15 @@ DOCSTRING is an optional form that is discarded upon expansion." (eval-after-load 'flymake #'adwaita-dark-theme-flymake-fringe-bmp-enable) (eval-after-load 'neotree #'adwaita-dark-theme-neotree-configuration-enable) :custom - (adwaita-dark-theme-bold-vertico-current t "Embolden the currently-selected candidate in vertico") + (adwaita-dark-theme-pad-tab-bar t "Enable visual padding for tab bars") + (adwaita-dark-theme-pad-tab-line t "Enable visual padding for tab lines") + (adwaita-dark-theme-pad-mode-line t "Enable visual padding for mode lines") + (adwaita-dark-theme-gray-outlines t "Use gray colors for outline-mode faces") (adwaita-dark-theme-gray-rainbow-delimiters t "Use a gray color for rainbow-delimiters faces") + (adwaita-dark-theme-bold-vertico-current t "Embolden the currently-selected candidate in vertico") + (adwaita-dark-theme-no-completions-first-difference t "Disable first difference highlight in completions") :hook - (user/after-daemon-make-initial-frame-functions . (lambda () (load-theme 'adwaita-dark :no-confirm)))) + (user/after-daemon-make-initial-frame-hook . (lambda () (load-theme 'adwaita-dark :no-confirm)))) ;; ---------------------------------- ;; ;; Simple language modes @@ -870,11 +935,6 @@ DOCSTRING is an optional form that is discarded upon expansion." ("\\.frag\\'" . glsl-mode) ("\\.vert\\'" . glsl-mode)) -(external-package json-mode - "Major mode for JSON files." - :mode - ("\\.json\\'" . json-mode)) - (external-package kotlin-mode "Major mode for Kotlin." :mode @@ -886,15 +946,10 @@ DOCSTRING is an optional form that is discarded upon expansion." (("\\.lua\\'" . lua-mode) ("\\.rockspec\\'" . lua-mode))) -(external-package rust-mode - "Major mode for Rust." +(external-package markdown-mode + "Major mode for Markdown files." :mode - ("\\.rs\\'" . rust-mode)) - -(external-package typescript-mode - "Major mode for TypeScript." - :mode - ("\\.tsx?\\'" . typescript-mode)) + (("\\.md\\'" . markdown-mode))) (external-package web-mode "Major mode for web templates." @@ -924,99 +979,104 @@ DOCSTRING is an optional form that is discarded upon expansion." (external-package bufler "Presents open buffers in a grouped and organized menu." - :config - ;; Set `line-spacing' to a custom value in bufler buffers for some - ;; added visual separation between UI elements - (add-hook 'bufler-list-mode-hook (lambda () (setq-local line-spacing 0.15))) :custom (bufler-columns '("Name" "Path")) (bufler-list-group-separators '((0 . "\n"))) (bufler-column-name-modified-buffer-sigil " ●") - (bufler-list-display-buffer '((display-buffer-reuse-window display-buffer-same-window))) - (bufler-groups (bufler-defgroups - (group - ;; Subgroup collecting all named workspaces. - (auto-workspace)) - (group - ;; Subgroup collecting all `help-mode' and `info-mode' buffers. - (group-or "Help/Info" - (mode-match "Help" (rx bos "help-")) - (mode-match "Info" (rx bos "info-")))) - (group - ;; Subgroup collecting all special buffers (i.e. ones that are not file-backed), - ;; except certain ones like Dired, Forge, or Magit buffers (which are allowed to - ;; fall through to other groups, so they end up grouped with their project buffers). - (group-not "Special" - (group-or "Special" - (mode-match "Eshell" (rx bos "eshell-")) - (mode-match "Magit" (rx bos "magit-")) - (mode-match "Forge" (rx bos "forge-")) - (mode-match "Dired" (rx bos "dired")) - (mode-match "Grep" (rx bos "grep-")) - (mode-match "Compilation" (rx bos "compilation-")) - (auto-file))) - (group - ;; Subgroup collecting these "special special" buffers - ;; separately for convenience. - (name-match "Emacs" - (rx bos "*" (or "Messages" "Warnings" "scratch" "Backtrace") "*"))) - (group - ;; Subgroup collecting all other Magit buffers, grouped by directory. - (mode-match "Magit" (rx bos "magit-")) - (auto-directory)) - ;; Remaining special buffers are grouped automatically by mode. - (auto-mode)) - (group - ;; Subgroup collecting buffers in a version-control project, - ;; grouping them by directory (using the parent project keeps, - ;; e.g. git worktrees with their parent repos). - (auto-parent-project) - (group-or "Files" - (auto-file)) - ;; Subgroup collecting special buffers so they are easily distinguished from file buffers. - (group-not "Special" - (auto-file))) - ;; Group remaining buffers by directory, then major mode. - (auto-directory) - (auto-mode))) + (bufler-list-display-buffer-action '((display-buffer-same-window))) + (bufler-groups + (bufler-defgroups + (group + ;; Subgroup collecting all named workspaces. + (auto-workspace)) + (group + ;; Subgroup collecting all `help-mode' and `info-mode' buffers. + (group-or "Help/Info" + (mode-match "Help" (rx bos "help-")) + (mode-match "Info" (rx bos "info-")))) + (group + ;; Subgroup collecting all special buffers (i.e. ones that are not file-backed), + ;; except certain ones like Dired, Forge, or Magit buffers (which are allowed to + ;; fall through to other groups, so they end up grouped with their project buffers). + (group-not "Special" + (group-or "Special" + (mode-match "Eshell" (rx bos "eshell-")) + (mode-match "Magit" (rx bos "magit-")) + (mode-match "Forge" (rx bos "forge-")) + (mode-match "Dired" (rx bos "dired")) + (mode-match "Grep" (rx bos "grep-")) + (mode-match "Compilation" (rx bos "compilation-")) + (auto-file))) + (group + ;; Subgroup collecting these "special special" buffers + ;; separately for convenience. + (name-match "Emacs" + (rx bos "*" (or "Messages" "Warnings" "scratch" "Backtrace") "*"))) + (group + ;; Subgroup collecting all other Magit buffers, grouped by directory. + (mode-match "Magit" (rx bos "magit-")) + (auto-directory)) + ;; Remaining special buffers are grouped automatically by mode. + (auto-mode)) + (group + ;; Subgroup collecting buffers in a version-control project, + ;; grouping them by directory (using the parent project keeps, + ;; e.g. git worktrees with their parent repos). + (auto-parent-project) + (group-or "Files" + (auto-file)) + ;; Subgroup collecting special buffers so they are easily distinguished from file buffers. + (group-not "Special" + (auto-file))) + ;; Group remaining buffers by directory, then major mode. + (auto-directory) + (auto-mode))) :bind ("C-x C-b" . bufler-list)) +;; ---------------------------------- ;; +;; cape +;; ---------------------------------- ;; + +(external-package cape + "Provides extensions for default Emacs completion facilities." + :config + ;; Wrap eglot's capf as noninterruptible to avoid desyncing with the language + ;; server during completion operations + (advice-add #'eglot-completion-at-point :around #'cape-wrap-noninterruptible)) + ;; ---------------------------------- ;; ;; cider ;; ---------------------------------- ;; -(defun user/cider-error-buffer () - "Switch to the CIDER error buffer, if it exists." - (interactive) - (if (get-buffer cider-error-buffer) - (pop-to-buffer cider-error-buffer) - (message "No active CIDER stacktrace buffer."))) - -(defun user/prettify-cider-namespace (namespace) - "Return NAMESPACE formatted and with all but the last name abbreviated." - (let* ((abbreviated-ns (cider-abbreviate-ns namespace)) - (names (reverse (split-string abbreviated-ns "\\."))) - (last-name (car names))) - (concat (mapconcat (lambda (name) - (propertize (concat name ".") - 'face 'font-lock-comment-face)) - (reverse (cdr names)) - "") - (propertize last-name - 'face 'font-lock-doc-face)))) - (external-package cider "Provides an interactive programming environment for Clojure." + :preface + (defun user/cider-error-buffer () + "Switch to the CIDER error buffer, if it exists." + (interactive) + (if (get-buffer cider-error-buffer) + (pop-to-buffer cider-error-buffer) + (message "No active CIDER stacktrace buffer."))) + (defun user/prettify-cider-namespace (namespace) + "Return NAMESPACE formatted and with all but the last name abbreviated." + (let* ((abbreviated-ns (cider-abbreviate-ns namespace)) + (names (reverse (split-string abbreviated-ns "\\."))) + (last-name (car names))) + (concat (mapconcat (lambda (name) (propertize (concat name ".") 'face 'font-lock-comment-face)) + (reverse (cdr names)) + "") + (propertize last-name + 'face 'font-lock-doc-face)))) :custom - (nrepl-hide-special-buffers t "Hide REPL communications buffers from buffer lists.") - (cider-show-error-buffer nil "Disable automatic display of the CIDER stacktrace info buffer.") - (cider-use-fringe-indicators nil "Disable evaluation indicators in the fringe of CIDER buffers.") - (cider-session-name-template "%j" "Label CIDER sessions with the short name of the current project.") - (cider-eval-spinner-type ["" "" "" "" "" ""] "Use an activity spinner that utilizes Fira Code glyphs.") - (cider-eval-spinner-delay 0.5 "Show the evaluation activity spinner after 0.5 seconds of activity.") - (cider-repl-display-help-banner nil "Disable initial infodump in CIDER REPL buffers.") - (cider-repl-prompt-function (lambda (namespace) (concat (user/prettify-cider-namespace namespace) " ❱ "))) + (nrepl-hide-special-buffers t "Hide REPL communications buffers from buffer lists") + (cider-show-error-buffer nil "Disable automatic display of the CIDER stacktrace info buffer") + (cider-use-fringe-indicators nil "Disable evaluation indicators in the fringe of CIDER buffers") + (cider-session-name-template "%j" "Label CIDER sessions with the short name of the current project") + (cider-eval-spinner-type ["" "" "" "" "" ""] "Use an activity spinner that utilizes Fira Code glyphs") + (cider-eval-spinner-delay 0.5 "Show the evaluation activity spinner after 0.5 seconds of activity") + (cider-repl-display-help-banner nil "Disable initial infodump in CIDER REPL buffers") + (cider-repl-prompt-function (lambda (ns) (concat (user/prettify-cider-namespace ns) " ❱ "))) :hook (clojure-mode-hook . cider-mode) (cider-repl-mode-hook . electric-pair-local-mode) @@ -1025,9 +1085,9 @@ DOCSTRING is an optional form that is discarded upon expansion." ("M-." . cider-find-var) ("M-," . cider-pop-back) ("C-c m" . cider-macroexpand-1) + ("C-c \\" . cider-format-buffer) ("C-c C-f" . cider-load-file) ("C-c C-b" . cider-load-buffer) - ("C-c C-\\" . cider-format-buffer) ("C-c M-e" . user/cider-error-buffer)) (:map cider-repl-mode-map ("C-c C-e" . end-of-buffer) @@ -1044,7 +1104,7 @@ DOCSTRING is an optional form that is discarded upon expansion." (external-package clj-refactor "Provides a suite of powerful refactoring functions for Clojure projects." :custom - (cljr-warn-on-eval nil "Disables warning prompts for refactor commands that build ASTs.") + (cljr-warn-on-eval nil "Disables warning prompts for refactor commands that build ASTs") :hook (cider-mode-hook . (lambda () (clj-refactor-mode) @@ -1064,6 +1124,13 @@ DOCSTRING is an optional form that is discarded upon expansion." :config ;; `eshell-mode-map' is not available until the `esh-mode' module is loaded (eval-after-load 'esh-mode (lambda () (bind-key "C-r" #'consult-history 'eshell-mode-map))) + ;; Override the default character range used for candidate line number annotations + ;; to use the Unicode PUA-B block (in favor of a character range outside of Unicode) + (setq consult--tofu-char #x100000 + consult--tofu-range #xFFFD) + ;; Have `xref' use consult for displaying definitions and references + (setq xref-show-xrefs-function #'consult-xref) + (setq xref-show-definitions-function #'consult-xref) :bind ("M-C-s" . (lambda () (interactive) (consult-line (thing-at-point 'symbol)))) ("M-s l" . consult-line) @@ -1087,26 +1154,23 @@ DOCSTRING is an optional form that is discarded upon expansion." :init (global-corfu-mode) :config + (add-to-list 'savehist-additional-variables 'corfu-history) (corfu-popupinfo-mode) (corfu-history-mode) - (add-to-list 'savehist-additional-variables 'corfu-history) - ;; Set `line-spacing' to a custom value in corfu buffers for some - ;; added visual separation between completion candidates - (advice-add 'corfu--make-buffer :around (lambda (orig-fun &rest args) - (let ((line-spacing 0.20)) - (apply orig-fun args)))) :custom - (corfu-auto t "Automatically display popups wherever available") + (corfu-auto t "Automatically display completion popups when available") + (corfu-auto-delay 0.0 "Display completion popups immediately when available") (corfu-min-width 20 "Ensure completion popups are at least 20 columns wide") (corfu-max-width 50 "Limit completion popup width to 50 columns") - (corfu-popupinfo-hide nil "Don't hide doc popups while scrolling between candidates") - (corfu-popupinfo-delay 0.1 "Wait 0.1 seconds before showing a doc popup for a candidate") + (corfu-preview-current nil "Disable inline preview of currently selected candidate") + (corfu-popupinfo-delay '(0.4 . 0.2) "Wait 0.4 seconds (0.2 subsequently) before showing a doc popup") (corfu-popupinfo-max-width 70 "Limit doc popup width to 70 columns") (corfu-popupinfo-min-height 4 "Ensure doc popups are at least 4 lines tall") (corfu-echo-documentation nil "Disable displaying documentation strings in the echo area") :hook - ;; Displaying popups aggressively (i.e. without summoning them with a key press) can - ;; cause the cursor to jump around in `eshell-mode' + ;; Displaying completion popups automatically (i.e. without summoning them explicitly) + ;; can cause performance issues in `eshell-mode' due to the high volume of completion + ;; candidates for certain commands (eshell-mode-hook . (lambda () (setq-local corfu-auto nil))) :bind (:map corfu-popupinfo-map @@ -1135,6 +1199,44 @@ DOCSTRING is an optional form that is discarded upon expansion." (global-diff-hl-mode) (diff-hl-flydiff-mode)) +;; ---------------------------------- ;; +;; eldoc-box +;; ---------------------------------- ;; + +(external-package eldoc-box + "Displays documentation from Eldoc in a floating popup." + :preface + (defun user/scroll-eldoc-box (count) + "Scrolls the `eldoc-box' window by COUNT lines if it visible." + (when (and (boundp 'eldoc-box--frame) + eldoc-box--frame + (frame-visible-p eldoc-box--frame)) + (with-selected-frame eldoc-box--frame + (scroll-up count)))) + :config + (dolist (parameter '((left-fringe . 12) (right-fringe . 12) (alpha-background . 90))) + (add-to-list 'eldoc-box-frame-parameters parameter)) + (add-hook 'eldoc-box-buffer-hook (lambda (&rest _args) + (goto-char (point-min)) + (insert (propertize "\n\s" 'face '(:height 0.2))) + (goto-char (point-max)) + (insert (propertize "\n\s" 'face '(:height 0.2))))) + (add-hook 'eldoc-box-frame-hook (lambda (&rest _args) + (setq-local line-spacing 0.25 + pixel-scroll-precision-mode nil + global-hl-line-mode nil))) + :custom + (eldoc-box-offset '(16 42 16) "Set a higher right offset for the popups to accomodate for the fringes") + (eldoc-documentation-strategy 'eldoc-documentation-compose "Combine results from all documentation sources") + (eldoc-box-max-pixel-width (lambda () (min 500 (/ (frame-outer-width) 4))) "Limit doc popup to 500 pixels wide") + (eldoc-box-max-pixel-height (lambda () (min 300 (/ (frame-outer-height) 4))) "Limit doc popup to 300 pixels tall") + (eldoc-box-doc-separator (propertize "\n\s\n" 'display '(space :width text) 'face '(:strike-through t))) + :hook + (eldoc-mode-hook . eldoc-box-hover-mode) + :bind + ("M-" . (lambda () (interactive) (user/scroll-eldoc-box -1))) + ("M-" . (lambda () (interactive) (user/scroll-eldoc-box 1)))) + ;; ---------------------------------- ;; ;; eshell-up ;; ---------------------------------- ;; @@ -1169,18 +1271,6 @@ DOCSTRING is an optional form that is discarded upon expansion." :hook (clojure-mode-hook . flymake-kondor-setup)) -;; ---------------------------------- ;; -;; fussy -;; ---------------------------------- ;; - -(external-package fussy - "Provides a flexible completion style that scores and sorts candidates." - :custom - (completion-ignore-case t "Ignore case in completion candidates") - (completion-category-defaults nil "Disable category-specific completion styles") - (completion-category-overrides nil "Disable category-specific completion styles") - (completion-styles '(substring fussy basic) "Set fussy as a fallback completion style")) - ;; ---------------------------------- ;; ;; hl-todo ;; ---------------------------------- ;; @@ -1196,18 +1286,41 @@ DOCSTRING is an optional form that is discarded upon expansion." :hook (prog-mode-hook . hl-todo-mode)) +;; ---------------------------------- ;; +;; hotfuzz +;; ---------------------------------- ;; + +(external-package hotfuzz + "Provides a native fuzzy completion style that scores and sorts candidates." + :preface + (defconst user/hotfuzz-directory (locate-user-emacs-file "hotfuzz/") "Location of dynamic Emacs module for hotfuzz") + (make-directory user/hotfuzz-directory :parents) + (add-to-list 'load-path user/hotfuzz-directory) + (eval-when-compile + (when (executable-find "clang") + (let ((source-url "https://raw.githubusercontent.com/axelf4/hotfuzz/master/hotfuzz-module.c") + (source-file (locate-user-emacs-file (concat user/hotfuzz-directory "hotfuzz-module.c"))) + (output-file (locate-user-emacs-file (concat user/hotfuzz-directory "hotfuzz-module.so")))) + (url-copy-file source-url source-file :ok-if-already-exists) + (shell-command (concat "clang -fPIC -O2 -march=native -shared " source-file " -o " output-file))))) + :custom + (hotfuzz-max-highlighted-completions most-positive-fixnum "Disable match candidate highlighting limits")) + ;; ---------------------------------- ;; ;; kind-icon ;; ---------------------------------- ;; (external-package kind-icon "Adds contextual icons in front of Corfu completion candidates." + :when + (or (daemonp) + (display-graphic-p)) + :after + (corfu) :config (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter) :custom - (kind-icon-use-icons nil "Use stylized text labels instead of graphical badges") - (kind-icon-blend-frac 0.25 "Brighten background colors with heavy blending from foreground colors") - (kind-icon-default-face 'corfu-default "Stylize characters using the same face as Corfu")) + (kind-icon-extra-space t "Insert extra blank space after the icon")) ;; ---------------------------------- ;; ;; ligature @@ -1216,66 +1329,60 @@ DOCSTRING is an optional form that is discarded upon expansion." (external-package ligature "Enables support for mapping characters to ligatures." :config - (ligature-set-ligatures 'prog-mode - '(;; This set of ligatures is for Fira Code, but - ;; should work for most any font with ligatures + (ligature-set-ligatures + 'prog-mode + '(;; This set of ligatures is for Fira Code, but + ;; should work for most any font with ligatures: + ;; && &&& + ;; ;; ;;; + ;; %% %%% + ;; ?? ??? ?: ?= ?. + ;; !! !!! !. !: !!. != !== !~ + (";" (rx (+ ";"))) + ("&" (rx (+ "&"))) + ("%" (rx (+ "%"))) + ("?" (rx (or ":" "=" "\." (+ "?")))) + ("!" (rx (+ (or "=" "!" "\." ":" "~")))) + ;; \\ \\\ \/ + ;; ++ +++ ++++ +> + ;; :: ::: :::: :> :< := :// ::= + ;; // /// //// /\ /* /> /===:===!=//===>>==>==/ + ;; == === ==== => =| =>>=>=|=>==>> ==< =/=//=// =~ =:= =!= + ("\\" (rx (or "/" (+ "\\")))) + ("+" (rx (or ">" (+ "+")))) + (":" (rx (or ">" "<" "=" "//" ":=" (+ ":")))) + ("/" (rx (+ (or ">" "<" "|" "/" "\\" "\*" ":" "!" "=")))) + ("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "=")))) + ;; |> ||> |||> ||||> |] |} || ||| |-> ||-|| + ;; |->>-||-<<-| |- |== ||=|| |==>>==<<==<=>==//==/=!==:===> + ("|" (rx (+ (or ">" "<" "|" "/" ":" "!" "}" "\]" "-" "=" )))) + ;; *> */ *) ** *** **** + ;; .. ... .... .= .- .? ..= ..< + ;; -- --- ---- -~ -> ->> -| -|->-->>->--<<-| + ;; #: #= #! #( #? #[ #{ #_ #_( ## ### ##### + ;; >: >- >>- >--|-> >>-|-> >= >== >>== >=|=:=>> >> >>> >>>> + ("*" (rx (or ">" "/" ")" (+ "*")))) + ("\." (rx (or "=" "-" "\?" "\.=" "\.<" (+ "\.")))) + ("-" (rx (+ (or ">" "<" "|" "~" "-")))) + ("#" (rx (or ":" "=" "!" "(" "\?" "\[" "{" "_(" "_" (+ "#")))) + (">" (rx (+ (or ">" "<" "|" "/" ":" "=" "-")))) - ;; && &&& - ;; ;; ;;; - ;; %% %%% - ;; ?? ??? ?: ?= ?. - ;; !! !!! !. !: !!. != !== !~ - (";" (rx (+ ";"))) - ("&" (rx (+ "&"))) - ("%" (rx (+ "%"))) - ("?" (rx (or ":" "=" "\." (+ "?")))) - ("!" (rx (+ (or "=" "!" "\." ":" "~")))) - - ;; \\ \\\ \/ - ;; ++ +++ ++++ +> - ;; :: ::: :::: :> :< := :// ::= - ;; // /// //// /\ /* /> /===:===!=//===>>==>==/ - ;; == === ==== => =| =>>=>=|=>==>> ==< =/=//=// =~ =:= =!= - ("\\" (rx (or "/" (+ "\\")))) - ("+" (rx (or ">" (+ "+")))) - (":" (rx (or ">" "<" "=" "//" ":=" (+ ":")))) - ("/" (rx (+ (or ">" "<" "|" "/" "\\" "\*" ":" "!" "=")))) - ("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "=")))) - - ;; |> ||> |||> ||||> |] |} || ||| |-> ||-|| - ;; |->>-||-<<-| |- |== ||=|| |==>>==<<==<=>==//==/=!==:===> - ("|" (rx (+ (or ">" "<" "|" "/" ":" "!" "}" "\]" "-" "=" )))) - - ;; *> */ *) ** *** **** - ;; .. ... .... .= .- .? ..= ..< - ;; -- --- ---- -~ -> ->> -| -|->-->>->--<<-| - ;; #: #= #! #( #? #[ #{ #_ #_( ## ### ##### - ;; >: >- >>- >--|-> >>-|-> >= >== >>== >=|=:=>> >> >>> >>>> - ("*" (rx (or ">" "/" ")" (+ "*")))) - ("\." (rx (or "=" "-" "\?" "\.=" "\.<" (+ "\.")))) - ("-" (rx (+ (or ">" "<" "|" "~" "-")))) - ("#" (rx (or ":" "=" "!" "(" "\?" "\[" "{" "_(" "_" (+ "#")))) - (">" (rx (+ (or ">" "<" "|" "/" ":" "=" "-")))) - - ;; <>