From 407771183e9d70b7e4b8ed9e2d773c9bc8e7af14 Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Thu, 29 Apr 2021 12:16:03 -0500 Subject: Massively refactor - Redefine as much as possible as `setup' forms - Reorganize into "Setup", "Basics", and "Packages" sections - Within each section, alphabetize sexps - Also (mostly) alphabetize acdw- files - (Not the ones that are almost completely others' code) - Sidebar: Why is this not a thing in elisp!? Should write a function - Break karthink's thing into another library `acdw-re' - Add a function to `acdw': `acdw/find-emacs-source' - Should refactor that to better find the source I think everything looks much more better now! --- init.el | 1406 ++++++++++++++++++++++++------------------------- lisp/acdw-modeline.el | 92 ++-- lisp/acdw-re.el | 66 +++ lisp/acdw.el | 129 +++-- 4 files changed, 877 insertions(+), 816 deletions(-) create mode 100644 lisp/acdw-re.el diff --git a/init.el b/init.el index fcbfd09..8f7363e 100644 --- a/init.el +++ b/init.el @@ -15,100 +15,235 @@ ;; - Make good choices. ;;; Code: - -;;; Necessary packages - -;;; `setup' -(progn - (straight-use-package '(setup :host nil - :repo "https://git.sr.ht/~zge/setup")) - (require 'setup)) - -(setup-define :straight - (lambda (recipe) - `(or (ignore-errors (straight-use-package ',recipe)) - (progn - (message "Straight error: %S" ',recipe) - (throw 'setup-exit nil)))) - :documentation "Install RECIPE with `straight-use-package'." - :repeatable t - :shorthand (lambda (sexp) - (let ((recipe (cadr sexp))) - (if (consp recipe) - (car recipe) - recipe)))) - -(setup-define :leader - (lambda (key command) - `(progn - (autoload #',command (symbol-name setup-name)) - (define-key acdw/leader - ,(if (stringp key) (kbd key) key) - #',command))) - :documentation "Bind KEY to COMMAND in `acdw/leader' (C-z) map." - :repeatable t) - -;;; `no-littering' +;;; Setup + +;;;; `setup' +(straight-use-package '(setup :host nil :repo "https://git.sr.ht/~zge/setup")) +(require 'setup) + +(setup setup + (setup-define :straight + (lambda (recipe) + `(or (ignore-errors (straight-use-package ',recipe)) + (progn + (message "Straight error: %S" ',recipe) + (throw 'setup-exit nil)))) + :documentation "Install RECIPE with `straight-use-package'." + :repeatable t + :shorthand (lambda (sexp) + (let ((recipe (cadr sexp))) + (if (consp recipe) + (car recipe) + recipe)))) + + (setup-define :leader + (lambda (key command) + `(progn + (autoload #',command (symbol-name setup-name)) + (define-key acdw/leader + ,(if (stringp key) (kbd key) key) + #',command))) + :documentation "Bind KEY to COMMAND in `acdw/leader' (C-z) map." + :repeatable t)) + +;;;; `no-littering' (setup (:straight no-littering) (:option no-littering-etc-directory (acdw/dir) no-littering-var-directory (acdw/dir)) (require 'no-littering)) -;;; My packages +;;;; My packages (when-let ((default-directory (expand-file-name-exists-p "pkg/" user-emacs-directory))) (normal-top-level-add-subdirs-to-load-path)) -;;; Good defaults +;;;; Utility functions and variables +;; see also: `acdw' and friends. Functions here aren't big enough, or they're +;; too tightly bound to stuff here, to be placed in `acdw'. -(defmacro setc (&rest args) - "Customize user options using ARGS like `setq'." - (declare (debug setq)) - `(setup (:option ,@args))) +;; Regular modes: `text-mode' and `prog-mode' +(defun acdw/fringe-setup () + (setq-local indicate-empty-lines t + indicate-buffer-boundaries '((top . right) + (bottom . right)))) -(setup emacs - ;; Me +;; Flash the mode line +(defun flash-mode-line () + "Flash the modeline as a bell." + (when (eq acdw/system :home) + (beep)) + (invert-face 'mode-line) + (run-with-timer 0.1 nil #'invert-face 'mode-line)) + +(defvar lispy-modes '(emacs-lisp-mode + eval-expression-minibuffer + ielm-mode + lisp-mode + lisp-interaction-mode + scheme-mode + slime-repl-mode) + "List of modes that are lisp-like enough to hook packages into.") + + +;;; Basics +;; NOTE that some of the names in `setup' forms are arbitrary. + +(setup acdw (:option user-full-name "Case Duckworth" user-mail-address "acdw@acdw.net" calendar-location-name "Baton Rouge, LA" calendar-latitude 30.4 - calendar-longitude -91.1) + calendar-longitude -91.1)) + +(setup autorevert + (global-auto-revert-mode +1)) + +(setup browse-url + (setq-default browse-url-browser-function 'eww-browse-url + browse-url-secondary-browser-function + (if (executable-find "firefox") + 'browse-url-firefox + 'browse-url-default-browser) + browse-url-new-window-flag t + browse-url-firefox-new-window-is-tab t) + (when (eq acdw/system :work) + (add-to-list 'exec-path "C:/Program Files/Mozilla Firefox"))) + +(setup buffers + (:global "C-x C-b" ibuffer + "C-x k" acdw/kill-a-buffer)) + +(setup completion + (:option completion-ignore-case t + read-buffer-completion-ignore-case t + icomplete-delay-completions-threshold 0 + icomplete-max-delay-chars 0 + icomplete-compute-delay 0 + icomplete-show-matches-on-no-input t + icomplete-with-buffer-completion-tables t + icomplete-in-buffer t + completion-styles '(partial-completion substring flex) + completion-category-defaults nil + completion-category-overrides + '((file (styles . (partial-completion))))) + + (:global "M-/" hippie-expand) - ;; Lines - (:option fill-column 79 - word-wrap t - truncate-lines nil) + (icomplete-mode +1)) - (global-display-fill-column-indicator-mode +1) - (global-so-long-mode +1) +(setup cursor + (:option cursor-type 'bar + cursor-in-non-selected-windows 'hollow + blink-cursor-blinks 1) + (blink-cursor-mode +1)) - (add-hook 'visual-line-mode-hook - (defun acdw/disable-fill-column-indicator () - (display-fill-column-indicator-mode - (if visual-line-mode -1 +1)))) +(setup cus-edit + (:option custom-file (acdw/dir "custom.el") + custom-magic-show nil + custom-magic-show-button t + custom-unlispify-tag-names nil + custom-variable-default-form 'edit)) - ;; Whitespace - (:option whitespace-style - '(empty indentation space-before-tab space-after-tab) - indent-tabs-mode nil - tab-width 4 - backward-delete-char-untabify-method 'hungry) +(setup debugger + (:hook visual-line-mode) + (:leader "d" toggle-debug-on-error)) + +(setup dired + (setq-default dired-recursive-copies 'always + dired-recursive-deletes 'always + delete-by-moving-to-trash t + dired-listing-switches "-Al" + ls-lisp-dirs-first t + dired-ls-F-marks-symlinks t + dired-no-confirm '(byte-compile + chgrp chmod chown copy + hardlink load move + shell touch symlink) + dired-dwim-target t) + + (:also-load dired-x) - (add-hook 'before-save-hook #'whitespace-cleanup) + (:hook dired-hide-details-mode + hl-line-mode) + + (:global "C-x C-j" dired-jump) - ;; Killing and yanking - (:option save-interprogram-paste-before-kill t - yank-pop-change-selection t - x-select-enable-clipboard t - x-select-enable-primary t - mouse-drag-copy-region t - kill-do-not-save-duplicates t) + (pcase acdw/system + (:work (:straight w32-browser) + (autoload 'dired-w32-browser "w32-browser") + (:bind "RET" dired-w32-browser)) + (:home (:straight dired-open) + (require 'dired-open) + (:bind "RET" dired-find-alternate-file) + (:option (prepend dired-open-functions) #'dired-open-xdg))) + + (:when-loaded + (:straight dired-subtree) + (:bind "i" dired-subtree-toggle + "TAB" dired-subtree-cycle) + + (:straight dired-collapse) + (:hook dired-collapse-mode) + + (:straight dired-git-info) + (:bind ")" dired-git-info-mode) + + (:straight trashed) + (:option trashed-action-confirmer #'y-or-n-p))) + +(setup ediff + (:option ediff-window-setup-function 'ediff-setup-windows-plain + ediff-split-window-function 'split-window-horizontally)) + +(setup eldoc + (:option eldoc-idle-delay 0.1 + eldoc-echo-area-use-multiline-p nil)) + +(setup elisp-mode + (:option eval-expression-print-length nil + eval-expression-print-level nil + lisp-indent-function #'lisp-indent-function) - (delete-selection-mode +1) + (defun acdw/enforce-lexical-binding () + (setq lexical-binding t)) + + (add-hook 'emacs-lisp-mode-hook #'acdw/enforce-lexical-binding) - ;; Encoding + (defun acdw/eval-region-or-buffer () + (interactive) + (if (region-active-p) + (let ((begin (region-beginning)) + (end (region-end))) + (with-message (format "Evaluating %S -> %S" begin end) + (eval-region begin end))) + (with-message "Evaluating buffer" + (eval-buffer)))) + + ;; Emulate slime's eval binds + (:with-map emacs-lisp-mode-map + (:bind "C-c C-c" eval-defun + "C-c C-k" acdw/eval-region-or-buffer + "C-c C-z" ielm)) + + (add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode) + (add-hook 'ielm-mode-hook 'turn-on-eldoc-mode) + + (setup (:straight macrostep) + (define-key emacs-lisp-mode-map (kbd "C-c e") #'macrostep-expand)) + + (setup (:straight eros) + (:hook-into emacs-lisp-mode)) + + ;; Add advice to pulse evaluated regions + (defun acdw/elisp-eval-region-advice (fn start end &rest args) + (pulse-momentary-highlight-region start end) + (apply fn start end args)) + + (advice-add 'eval-region :around #'acdw/elisp-eval-region-advice)) + +(setup encoding (:option locale-coding-system 'utf-8-unix coding-system-for-read 'utf-8-unix coding-system-for-write 'utf-8-unix @@ -131,51 +266,7 @@ (set-selection-coding-system 'utf-16-le)) (_ (set-selection-coding-system 'utf-8) (set-clipboard-coding-system 'utf-8))) - - ;; Cursor - (:option cursor-type 'bar - cursor-in-non-selected-windows 'hollow - blink-cursor-blinks 1) - (blink-cursor-mode +1) - - ;; Scrolling - (:option auto-window-vscroll nil - fast-but-imprecise-scrolling t - scroll-margin 0 - scroll-conservatively 101 - scroll-preserve-screen-position 1) - - ;; Minibuffer - (:option minibuffer-prompt-properties - '(read-only t cursor-intangible t face minibuffer-prompt) - enable-recursive-minibuffers t - file-name-shadow-properties '(invisible t intangible t) - read-answer-short t) - - (add-hook 'minibuffer-setup-hook #'acdw/gc-disable) - (add-hook 'minibuffer-exit-hook #'acdw/gc-enable) - - (minibuffer-depth-indicate-mode +1) - (file-name-shadow-mode +1) - (minibuffer-electric-default-mode +1) - (fset 'yes-or-no-p #'y-or-n-p) - - ;; Completion - (:option completion-ignore-case t - read-buffer-completion-ignore-case t - icomplete-delay-completions-threshold 0 - icomplete-max-delay-chars 0 - icomplete-compute-delay 0 - icomplete-show-matches-on-no-input t - icomplete-with-buffer-completion-tables t - icomplete-in-buffer t - completion-styles '(partial-completion substring flex) - completion-category-defaults nil - completion-category-overrides - '((file (styles . (partial-completion))))) - ;; (icomplete-mode +1) - ;; Emoji (let ((ffl (font-family-list))) (dolist (emoji-font '("Segoe UI Emoji" "Noto Color Emoji" @@ -183,82 +274,109 @@ "Symbola")) (when (member emoji-font ffl) (set-fontset-font t 'symbol - (font-spec :family emoji-font) nil 'append)))) + (font-spec :family emoji-font) nil 'append))))) + +(setup eshell + (:option eshell-directory-name (acdw/dir "eshell/" t) + eshell-aliases-file (acdw/dir "eshell/aliases" t)) + + (defun eshell-quit-or-delete-char (arg) + "Delete the character to the right, or quit eshell on an empty line." + (interactive "p") + (if (and (eolp) (looking-back eshell-prompt-regexp)) + (eshell-life-is-too-much) + (delete-forward-char arg))) + + (global-set-key (kbd "") #'eshell) - ;; Etc. - (:option inhibit-startup-screen t - initial-buffer-choice t - initial-scratch-message (concat ";; Howdy, " - (nth 0 (split-string - user-full-name)) - "! " - "Welcome to GNU Emacs.\n\n") - initial-major-mode 'emacs-lisp-mode - disabled-command-function nil - load-prefer-newer t - comp-async-report-warnings-errors nil - frame-title-format '((:eval (if-let ((bn buffer-file-name)) - (abbreviate-file-name bn) - "%b")) - " %+%* GNU Emacs" - (:eval (when (frame-parameter - nil 'client) - " Client"))) - tab-bar-show 1 - use-dialog-box nil - use-file-dialog nil - echo-keystrokes 0.01 - recenter-positions '(top middle bottom) - attempt-stack-overflow-recovery nil - attempt-orderly-shutdown-on-fatal-signal nil - window-resize-pixelwise t - find-function-C-source-directory - (pcase acdw/system - (:work (expand-file-name (concat "~/src/emacs-" - emacs-version - "/src"))) - (:home (expand-file-name - "~/src/pkg/emacs/src/emacs-git/src")) - (:other nil)) - w32-allow-system-shell t - w32-pass-lwindow-to-system nil - w32-lwindow-modifier 'super - w32-pass-rwindow-to-system nil - w32-rwindow-modifier 'super - w32-pass-apps-to-system nil - w32-apps-modifier 'hyper - visible-bell nil - ring-bell-function #'flash-mode-line - view-read-only t) + (hook-defun eshell-setup 'eshell-mode-hook + (define-key eshell-mode-map (kbd "") #'bury-buffer) + (define-key eshell-mode-map (kbd "C-d") #'eshell-quit-or-delete-char) + (when (boundp 'simple-modeline--mode-line) + (setq mode-line-format '(:eval simple-modeline--mode-line))))) + +(setup eww + (:hook acdw/reading-mode)) + +(setup files + (:option backup-directory-alist `((".*" . ,(acdw/dir "backup/" t))) + tramp-backup-directory-alist backup-directory-alist + auto-save-file-name-transforms `((".*" ,(acdw/dir "auto-save/" t) t)) + auto-save-list-file-prefix (acdw/dir "auto-save-list/.saves-" t) + backup-by-copying t + delete-old-versions t + version-control t + vc-make-backup-files t) + + (:global "C-c i" acdw/find-emacs-dotfiles) + + (auto-save-visited-mode +1) + + (when-unfocused save-some-buffers + (save-some-buffers t))) + +(setup flyspell + (setq-default ispell-program-name "hunspell" + ispell-dictionary "en_US" + ispell-personal-dictionary "~/.hunspell_personal") + (:needs ispell-program-name) ; don't proceed if not installed + + (unless (file-exists-p ispell-personal-dictionary) + (write-region "" nil ispell-personal-dictionary nil 0)) + + (defun flyspell-start () + "Start `flyspell-mode' or `flyspell-prog-mode', depending on current mode." + (interactive) + (cond ((derived-mode-p 'text-mode) + (flyspell-mode)) + ((derived-mode-p 'prog-mode) + (flyspell-prog-mode)) + (t (message "Non-text or -prog mode. Run `flyspell-mode'.")))) + (:leader "s" flyspell-start) - (defun flash-mode-line () - "Flash the modeline as a bell." - (when (eq acdw/system :home) - (beep)) - (invert-face 'mode-line) - (run-with-timer 0.1 nil #'invert-face 'mode-line)) + (:when-loaded + (setup (:straight flyspell-correct) + (define-key flyspell-mode-map (kbd "C-;") #'flyspell-correct-wrapper)))) +(setup frames + (:option frame-title-format '((:eval (if-let ((bn buffer-file-name)) + (abbreviate-file-name bn) + "%b")) + " %+%* GNU Emacs" + (:eval (when (frame-parameter + nil 'client) + " Client"))) + window-resize-pixelwise t) (when-unfocused garbage-collect - (garbage-collect)) + (garbage-collect))) - (tooltip-mode -1) - (winner-mode +1) +(setup gnus + (:option gnus-home-directory (expand-file-name "gnus" user-emacs-directory) + gnus-directory (expand-file-name "gnus/News" user-emacs-directory) + gnus-init-file (expand-file-name "gnus.el" user-emacs-directory)) + (when (not (file-exists-p gnus-directory)) + (make-directory gnus-directory :parents)) + (:leader "m" gnus)) + +(setup imenu + (:option imenu-auto-rescan t)) - (add-hook 'view-mode-hook (defun acdw/read-view-mode () - (acdw/reading-mode (if view-mode +1 -1)))) +(setup isearch + (:option search-default-mode t)) - ;;; Bindings - (:global "M-SPC" cycle-spacing - "M-/" hippie-expand - "M-=" count-words - "C-x C-b" ibuffer - "C-c i" acdw/find-emacs-dotfiles - "C-x k" acdw/kill-a-buffer) +(setup lines + (:option fill-column 79 + word-wrap t + truncate-lines nil) - (:leader "C-c" save-buffers-kill-emacs - "t" acdw/insert-iso-date) + (global-display-fill-column-indicator-mode +1) + (global-so-long-mode +1) + + (add-hook 'visual-line-mode-hook + (defun acdw/disable-fill-column-indicator () + (display-fill-column-indicator-mode + (if visual-line-mode -1 +1)))) - ;;; Advice ;; `acdw/kill-line-and-join-advice' cribs from `crux-kill-and-join-forward'. ;; I can't simply advise `kill-line' with an override from crux because crux ;; itself calls `kill-line', leading to a infinite nesting situation. @@ -269,15 +387,20 @@ (delete-indentation 1) (apply orig args))))) -;; Regular modes (`text-mode', `prog-mode', etc.) -(defun acdw/setup-regular-modes () - (setq-local indicate-empty-lines t - indicate-buffer-boundaries '((top . right) - (bottom . right)))) +(setup minibuffer + (:option minibuffer-prompt-properties + '(read-only t cursor-intangible t face minibuffer-prompt) + enable-recursive-minibuffers t + file-name-shadow-properties '(invisible t intangible t) + read-answer-short t) -(setup text - (:hook turn-on-auto-fill - acdw/setup-regular-modes)) + (add-hook 'minibuffer-setup-hook #'acdw/gc-disable) + (add-hook 'minibuffer-exit-hook #'acdw/gc-enable) + + (minibuffer-depth-indicate-mode +1) + (file-name-shadow-mode +1) + (minibuffer-electric-default-mode +1) + (fset 'yes-or-no-p #'y-or-n-p)) (setup prog (:option smie-indent-basic tab-width) @@ -293,46 +416,23 @@ (:hook show-paren-mode electric-pair-local-mode - acdw/setup-regular-modes) + acdw/fringe-setup) (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)) -(setup cus-edit - (:option custom-file (acdw/dir "custom.el") - custom-magic-show nil - custom-magic-show-button t - custom-unlispify-tag-names nil - custom-variable-default-form 'edit)) - -(setup uniquify - (:option uniquify-buffer-name-style 'forward - uniquify-separator path-separator - uniquify-after-kill-buffer-p t - uniquify-ignore-buffers-re "^\\*")) - -(setup files - (:option backup-directory-alist `((".*" . ,(acdw/dir "backup/" t))) - tramp-backup-directory-alist backup-directory-alist - auto-save-file-name-transforms `((".*" ,(acdw/dir "auto-save/" t) t)) - auto-save-list-file-prefix (acdw/dir "auto-save-list/.saves-" t) - backup-by-copying t - delete-old-versions t - version-control t - vc-make-backup-files t) - - (auto-save-visited-mode +1) - - (when-unfocused save-some-buffers - (save-some-buffers t))) +(setup re-builder + (require 'acdw-re) + (advice-add 're-builder :before #'acdw/re-builder-save-state) -(setup autorevert - (global-auto-revert-mode +1)) + (:global "C-M-%" re-builder) -(setup saveplace - (:option save-place-file (acdw/dir "places.el") - save-place-forget-unreadable-files (eq acdw/system :home)) - (save-place-mode +1)) + (dolist (map '(reb-mode-map reb-lisp-mode-map)) + (let ((setup-map map)) + (:bind "RET" reb-replace-regexp + "M-n" reb-next-match + "M-p" reb-prev-match + "M-q" reb-quit)))) (setup (:require recentf) (:option recentf-save-file (acdw/dir "recentf.el") @@ -343,317 +443,174 @@ (recentf-mode +1)) (setup (:require savehist) - (:option (append savehist-additional-variables) 'kill-ring - (append savehist-additional-variables) 'search-ring - (append savehist-additional-variables) 'regexp-search-ring - history-length t + (:option history-length t history-delete-duplicates t savehist-autosave-interval 6 savehist-file (acdw/dir "savehist.el")) - (savehist-mode +1)) - -(setup imenu - (:option imenu-auto-rescan t)) - -(setup isearch - (:option search-default-mode t)) - -(setup debugger - (:hook visual-line-mode) - (:leader "d" toggle-debug-on-error)) - -(setup eldoc - (:option eldoc-idle-delay 0.1 - eldoc-echo-area-use-multiline-p nil)) -(setup flyspell - (setq-default ispell-program-name "hunspell" - ispell-dictionary "en_US" - ispell-personal-dictionary "~/.hunspell_personal") - (:needs ispell-program-name) ; don't proceed if not installed + (dolist (var '(kill-ring + search-ring + regexp-search-ring)) + (:option (append savehist-additional-variables) var)) - (unless (file-exists-p ispell-personal-dictionary) - (write-region "" nil ispell-personal-dictionary nil 0)) + (savehist-mode +1)) - (defun flyspell-start () - "Start `flyspell-mode' or `flyspell-prog-mode', depending on current mode." - (interactive) - (cond ((derived-mode-p 'text-mode) - (flyspell-mode)) - ((derived-mode-p 'prog-mode) - (flyspell-prog-mode)) - (t (message "Non-text or -prog mode. Run `flyspell-mode'.")))) - (:leader "s" flyspell-start)) +(setup saveplace + (:option save-place-file (acdw/dir "places.el") + save-place-forget-unreadable-files (eq acdw/system :home)) + + (save-place-mode +1)) (setup scratch + (:option inhibit-startup-screen t + initial-buffer-choice t + initial-scratch-message (concat ";; Howdy, " + (nth 0 (split-string + user-full-name)) + "! " + "Welcome to GNU Emacs.\n\n") + initial-major-mode 'emacs-lisp-mode) + (hook-defun immortal-scratch kill-buffer-query-functions (if (eq (current-buffer) (get-buffer "*scratch*")) (progn (bury-buffer) nil) t))) -(setup re-builder - ;; https://karthinks.com/software/bridging-islands-in-emacs-1/ - - (defvar acdw/re-builder-positions nil - "Store point and region bounds before calling re-builder") - - (advice-add 're-builder - :before - (defun acdw/re-builder-save-state (&rest _) - "Save into `acdw/re-builder-positions' the point and region -positions before calling `re-builder'." - (setq acdw/re-builder-positions - (cons (point) - (when (region-active-p) - (list (region-beginning) - (region-end))))))) - - (defun reb-replace-regexp (&optional delimited) - "Run `query-replace-regexp' with the contents of re-builder. With -non-nil optional argument DELIMITED, only replace matches -surrounded by word boundaries." - (interactive "P") - (reb-update-regexp) - (let* ((re (reb-target-binding reb-regexp)) - (replacement (query-replace-read-to - re - (concat "Query replace" - (if current-prefix-arg - (if (eq current-prefix-arg '-) " backward" " word") - "") - " regexp" - (if (with-selected-window reb-target-window - (region-active-p)) " in region" "")) - t)) - (pnt (car acdw/re-builder-positions)) - (beg (cadr acdw/re-builder-positions)) - (end (caddr acdw/re-builder-positions))) - (with-selected-window reb-target-window - (goto-char pnt) ; replace with (goto-char (match-beginning 0)) if you want - ; to control where in the buffer the replacement starts - ; with re-builder - (setq acdw/re-builder-positions nil) - (reb-quit) - (query-replace-regexp re replacement delimited beg end)))) - - (:global "C-M-%" re-builder) - - (dolist (map '(reb-mode-map reb-lisp-mode-map)) - (let ((setup-map map)) - (:bind "RET" reb-replace-regexp - "M-n" reb-next-match - "M-p" reb-prev-match - "M-q" reb-quit)))) - - -;;; Applications - -(setup (:straight (org :host nil - :repo "https://code.orgmode.org/bzg/org-mode.git")) - (require 'acdw-org) ; so I don't clutter up init.el - (:option org-adapt-indentation nil - org-catch-invisible-edits 'smart - org-confirm-babel-evaluate nil - org-export-coding-system 'utf-8-unix - org-export-headline-levels 8 - org-export-with-section-numbers nil - org-export-with-smart-quotes t - org-export-with-sub-superscripts t - org-export-with-toc nil - org-fontify-done-headline t - org-fontify-quote-and-verse-blocks t - org-fontify-whole-heading-line t - org-hide-emphasis-markers t - org-html-coding-system 'utf-8-unix - org-imenu-depth 3 - org-pretty-entities t - org-special-ctrl-a/e t - org-special-ctrl-k t - org-src-fontify-natively t - org-src-tab-acts-natively t - org-src-window-setup 'current-window - org-startup-truncated nil - org-tags-column (- 0 fill-column -3) - org-directory "~/org") - (:bind "RET" acdw-org/return-dwim - "" acdw-org/org-table-copy-down) - (add-hook 'before-save-hook #'acdw-org/fix-blank-lines-in-buffer) - (advice-add 'org-delete-backward-char - :override #'acdw-org/delete-backward-char)) - -(setup eshell - (:option eshell-directory-name (acdw/dir "eshell/" t) - eshell-aliases-file (acdw/dir "eshell/aliases" t)) - - (defun eshell-quit-or-delete-char (arg) - "Delete the character to the right, or quit eshell on an empty line." - (interactive "p") - (if (and (eolp) (looking-back eshell-prompt-regexp)) - (eshell-life-is-too-much) - (delete-forward-char arg))) - - (global-set-key (kbd "") #'eshell) - - (hook-defun eshell-setup 'eshell-mode-hook - (define-key eshell-mode-map (kbd "") #'bury-buffer) - (define-key eshell-mode-map (kbd "C-d") #'eshell-quit-or-delete-char) - (when (boundp 'simple-modeline--mode-line) - (setq mode-line-format '(:eval simple-modeline--mode-line))))) - -(setup ediff - (:option ediff-window-setup-function 'ediff-setup-windows-plain - ediff-split-window-function 'split-window-horizontally)) - -(setup browse-url - (setq-default browse-url-browser-function 'eww-browse-url - browse-url-secondary-browser-function - (if (executable-find "firefox") - 'browse-url-firefox - 'browse-url-default-browser) - browse-url-new-window-flag t - browse-url-firefox-new-window-is-tab t) - (when (eq acdw/system :work) - (add-to-list 'exec-path "C:/Program Files/Mozilla Firefox"))) - -(setup shr - (:option shr-width fill-column - shr-max-width fill-column - shr-max-image-proportion 0.6 - shr-image-animate t - shr-discard-aria-hidden t)) - -(setup eww - (:hook acdw/reading-mode)) - -(setup (:straight (elpher :host nil - :repo "git://thelambdalab.xyz/elpher.git")) - (:option elpher-ipv4-always t - elpher-certificate-directory (acdw/dir "elpher/") - elpher-gemini-max-fill-width fill-column) - (:leader "e" elpher-bookmarks) - (:bind "n" elpher-next-link - "p" elpher-prev-link - "o" elpher-follow-current-link - "G" elpher-go-current) - (:hook acdw/reading-mode) - (autoload 'elpher-bookmarks "elpher" nil t) - (autoload 'elpher-go "elpher" nil t) - ;; Make `eww' gemini/gopher aware. From Emacswiki. - (advice-add 'eww-browse-url :around - (defun elpher:eww-browse-url (original url &optional new-window) - "Handle gemini and gopher links." - (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url) - (require 'elpher) - (elpher-go url)) - (t (funcall original url new-window)))))) +(setup scrolling + (:option auto-window-vscroll nil + fast-but-imprecise-scrolling t + scroll-margin 0 + scroll-conservatively 101 + scroll-preserve-screen-position 1)) -(setup (:straight (gemini-mode - :host nil - :repo "https://git.carcosa.net/jmcbray/gemini.el.git")) - (:file-match "\\.\\(gemini\\|gmi\\)\\'")) +(setup selection + (:option save-interprogram-paste-before-kill t + yank-pop-change-selection t + x-select-enable-clipboard t + x-select-enable-primary t + mouse-drag-copy-region t + kill-do-not-save-duplicates t) -(setup (:straight (gemini-write - :host nil - :repo "https://alexschroeder.ch/cgit/gemini-write" - :fork - (:repo "https://tildegit.org/acdw/gemini-write" - :branch "main"))) - (with-eval-after-load 'elpher - (require 'gemini-write))) + (delete-selection-mode +1)) -(setup dired - (setq-default dired-recursive-copies 'always - dired-recursive-deletes 'always - delete-by-moving-to-trash t - dired-listing-switches "-Al" - ls-lisp-dirs-first t - dired-ls-F-marks-symlinks t - dired-no-confirm '(byte-compile - chgrp chmod chown copy - hardlink load move - shell touch symlink) - dired-dwim-target t) - (:also-load dired-x) - (:hook dired-hide-details-mode - hl-line-mode) - (:global "C-x C-j" dired-jump) +(setup (:require server) + (unless (server-running-p) + (server-start))) - (pcase acdw/system - (:work (:straight w32-browser) - (autoload 'dired-w32-browser "w32-browser") - (:bind "RET" dired-w32-browser)) - (:home (:straight dired-open) - (require 'dired-open) - (:bind "RET" dired-find-alternate-file) - (:option (prepend dired-open-functions) #'dired-open-xdg))) +(setup sh-mode + (:option sh-basic-offset tab-width + sh-indent-after-case 0 + sh-indent-for-case-alt '+ + sh-indent-for-case-label 0) + + (:local-set indent-tabs-mode t) + + (when (executable-find "shfmt") + (with-eval-after-load 'apheleia + (:option (append apheleia-formatters) '(shfmt . ("shfmt")) + (append apheleia-mode-alist) '(sh-mode . shfmt)))) - (:straight dired-subtree) - (:bind "i" dired-subtree-toggle - "TAB" dired-subtree-cycle) + (when (executable-find "shellcheck") + (:straight flymake-shellcheck) + (:hook flymake-mode + flymake-shellcheck-load))) - (:straight dired-collapse) - (:hook dired-collapse-mode) +(setup shr + (:option shr-width fill-column + shr-max-width fill-column + shr-max-image-proportion 0.6 + shr-image-animate t + shr-discard-aria-hidden t)) - (:straight dired-git-info) - (:bind ")" dired-git-info-mode) +(setup text + (:hook turn-on-auto-fill + acdw/fringe-setup)) - (:straight trashed) - (:option trashed-action-confirmer #'y-or-n-p)) +(setup uniquify + (:option uniquify-buffer-name-style 'forward + uniquify-separator path-separator + uniquify-after-kill-buffer-p t + uniquify-ignore-buffers-re "^\\*")) -(setup (:straight magit) - (:leader "g" magit-status) +(setup view + (:option view-read-only t) + + (defun acdw/read-view-mode () + (acdw/reading-mode (if view-mode +1 -1))) + + (:hook acdw/read-view-mode)) - (defun magit-display-buffer-same-window (buffer) - "Display BUFFER in the selected window like God intended." - (display-buffer buffer '(display-buffer-same-window))) +(setup whitespace + (:option whitespace-style + '(empty indentation space-before-tab space-after-tab) + indent-tabs-mode nil + tab-width 4 + backward-delete-char-untabify-method 'hungry) + + (:global "M-SPC" cycle-spacing) - (:option magit-display-buffer-function #'magit-display-buffer-same-window - magit-popup-display-buffer-action '((display-buffer-same-window)) - magit-refresh-status-buffer nil)) + (add-hook 'before-save-hook #'whitespace-cleanup)) -(setup (:straight nov) - (:option nov-text-width fill-column) - (:file-match "\\.epub\\'")) +(setup windows + (:option use-dialog-box nil + use-file-dialog nil + tab-bar-show 1 + visible-bell nil + ring-bell-function #'flash-mode-line + recenter-positions '(top middle bottom)) + + (tooltip-mode -1) + (winner-mode +1)) -(setup gnus - (:option gnus-home-directory (expand-file-name "gnus" user-emacs-directory) - gnus-directory (expand-file-name "gnus/News" user-emacs-directory) - gnus-init-file (expand-file-name "gnus.el" user-emacs-directory)) - (when (not (file-exists-p gnus-directory)) - (make-directory gnus-directory :parents)) - (:leader "m" gnus)) +(setup w32 + (:option w32-allow-system-shell t + w32-pass-lwindow-to-system nil + w32-lwindow-modifier 'super + w32-pass-rwindow-to-system nil + w32-rwindow-modifier 'super + w32-pass-apps-to-system nil + w32-apps-modifier 'hyper)) -(when (eq acdw/system :home) - ;; Apparently the original repo is unmaintained, thus this fork. - (setup (:straight (pdf-tools - :host github - :repo "vedang/pdf-tools")) - (pdf-loader-install)) +;; "Et cetera" settings +(setup emacs + (:option disabled-command-function nil + load-prefer-newer t + comp-async-report-warnings-errors nil + echo-keystrokes 0.01 + attempt-stack-overflow-recovery nil + attempt-orderly-shutdown-on-fatal-signal nil + find-function-C-source-directory (acdw/find-emacs-source)) - (setup (:straight vterm))) + (:global "M-=" count-words) + + (:leader "C-c" save-buffers-kill-emacs + "t" acdw/insert-iso-date)) -;; Extra packages +;;; Packages -(setup (:straight (beginend - :fork (:repo "duckwork/beginend"))) - (beginend-global-mode +1)) +(setup (:straight (0x0 :host nil + :repo "https://git.sr.ht/~zge/nullpointer-emacs")) + (:option 0x0-default-host 'ttm)) -(setup (:straight mwim) - (:global "C-a" mwim-beginning - "C-e" mwim-end)) +(setup (:straight (apheleia :host github + :repo "raxod502/apheleia")) + + (apheleia-global-mode +1) -(setup (:straight expand-region) - (:global "C-=" er/expand-region)) + ;; Use a dumb formatter on modes that `apheleia' doesn't work for. + (hook-defun dumb-auto-format before-save-hook + (setq stupid-modes '(makefile-mode)) + ;; If there's no apheleia formatter for the mode, just indent the buffer. + (unless (or (apply #'derived-mode-p stupid-modes) + (and (fboundp 'apheleia--get-formatter-command) + (apheleia--get-formatter-command))) + (indent-region (point-min) (point-max))))) -(setup (:straight crux) - (:global "M-`" crux-other-window-or-switch-buffer - "C-o" crux-smart-open-line - "M-o" crux-smart-open-line-above - "C-M-\\" crux-cleanup-buffer-or-region - "C-x 4 t" crux-transpose-windows) - (crux-reopen-as-root-mode +1)) +(setup (:straight async) + (autoload 'dired-async-mode "dired-async.el" nil t) + (dired-async-mode +1)) (setup (:straight avy) (:global "C-:" avy-goto-char @@ -661,50 +618,13 @@ surrounded by word boundaries." "M-g f" avy-goto-line "M-g w" avy-goto-word-1 "C-c C-j" avy-resume) + (eval-after-load "isearch" '(define-key isearch-mode-map (kbd "C-'") #'avy-isearch))) -(setup (:straight zzz-to-char) - (defun acdw/zzz-up-to-char (prefix) - "Call `zzz-up-to-char', unless issued a PREFIX, in which case -call `zzz-to-char'." - (interactive "P") - (if prefix - (call-interactively #'zzz-to-char) - (call-interactively #'zzz-up-to-char))) - - (:global "M-z" acdw/zzz-up-to-char)) - -(setup (:straight async) - (autoload 'dired-async-mode "dired-async.el" nil t) - (dired-async-mode +1)) - -(setup (:straight undo-fu) - (:global "C-/" undo-fu-only-undo - "C-?" undo-fu-only-redo)) - -(setup (:straight undo-fu-session) - (:option undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" - "/git-rebase-todo\\'") - undo-fu-session-directory (acdw/dir "undo/" t) - undo-fu-session-compression (eq acdw/system :home)) - - (global-undo-fu-session-mode +1)) - -(setup (:straight (vertico - :host github - :repo "minad/vertico")) - (setq resize-mini-windows 'grow-only) - (if (boundp 'comp-deferred-compilation-deny-list) - (add-to-list 'comp-deferred-compilation-deny-list "vertico")) - (icomplete-mode -1) - (vertico-mode +1)) - -(setup (:straight (orderless - :host github - :repo "oantolin/orderless")) - (require 'orderless) - (:option (prepend completion-styles) 'orderless)) +(setup (:straight (beginend + :fork (:repo "duckwork/beginend"))) + (beginend-global-mode +1)) (setup (:straight (consult :host github @@ -788,6 +708,124 @@ if ripgrep is installed, otherwise `consult-grep'." completion-cycle-threshold 3 tab-always-indent 'complete)) +(setup (:straight crux) + + (:global "M-`" crux-other-window-or-switch-buffer + "C-o" crux-smart-open-line + "M-o" crux-smart-open-line-above + "C-M-\\" crux-cleanup-buffer-or-region + "C-x 4 t" crux-transpose-windows) + + (crux-reopen-as-root-mode +1)) + +(setup (:straight (electric-cursor + :host github + :repo "duckwork/electric-cursor")) + (electric-cursor-mode +1)) + +(setup (:straight (elpher :host nil + :repo "git://thelambdalab.xyz/elpher.git")) + (:option elpher-ipv4-always t + elpher-certificate-directory (acdw/dir "elpher/") + elpher-gemini-max-fill-width fill-column) + + (:leader "e" elpher-bookmarks) + + (:bind "n" elpher-next-link + "p" elpher-prev-link + "o" elpher-follow-current-link + "G" elpher-go-current) + + (:hook acdw/reading-mode) + + (autoload 'elpher-bookmarks "elpher" nil t) + (autoload 'elpher-go "elpher" nil t) + + ;; Make `eww' gemini/gopher aware. From Emacswiki. + (advice-add 'eww-browse-url :around + (defun elpher:eww-browse-url (original url &optional new-window) + "Handle gemini and gopher links." + (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url) + (require 'elpher) + (elpher-go url)) + (t (funcall original url new-window))))) + + (:when-loaded + (setup (:straight (gemini-write + :host nil + :repo "https://alexschroeder.ch/cgit/gemini-write" + :fork + (:repo "https://tildegit.org/acdw/gemini-write" + :branch "main"))) + (require 'gemini-write)))) + +(setup (:straight expand-region) + (:global "C-=" er/expand-region)) + +(setup (:straight fennel-mode) + (:needs "fennel") + (autoload 'fennel-repl "fennel-mode" nil t) + (:file-match "\\.fnl\\'")) + +(setup (:straight form-feed) + (global-form-feed-mode +1)) + +(setup (:straight geiser)) + +(setup (:straight slime) + (defvar acdw/lisp-bin (or (executable-find "sbcl") + (executable-find "clisp"))) + (:needs acdw/lisp-bin) + + (:also-load slime-autoloads) + + (:option inferior-lisp-program acdw/lisp-bin) + + (when-let ((slime-helper (or (expand-file-name-exists-p + "~/quicklisp/slime-helper.el") + (expand-file-name-exists-p + "~/var/quicklisp/slime-helper.el")))) + (load slime-helper)) + + (with-eval-after-load 'company + (setup (:straight slime-company) + (:option slime-company-completion 'fuzzy + slime-company-after-completion nil) + (slime-setup '(slime-fancy slime-company))))) + +(setup (:straight (gemini-mode + :host nil + :repo "https://git.carcosa.net/jmcbray/gemini.el.git")) + (:file-match "\\.\\(gemini\\|gmi\\)\\'")) + +(setup gforth + (when (locate-library "gforth") + (autoload 'forth-mode "gforth") + (add-to-list 'auto-mode-alist '("\\.fs\\'" . forth-mode)) + (autoload 'forth-block-mode "gforth") + (add-to-list 'auto-mode-alist '("\\.fb\\'" . forth-block-mode)))) + +(setup (:straight helpful) + (:global " f" helpful-callable + " v" helpful-variable + " k" helpful-key + " o" helpful-symbol + "C-c C-d" helpful-at-point)) + +(setup (:straight lua-mode) + (:file-match "\\.lua\\'")) + +(setup (:straight magit) + (:leader "g" magit-status) + + (defun magit-display-buffer-same-window (buffer) + "Display BUFFER in the selected window like God intended." + (display-buffer buffer '(display-buffer-same-window))) + + (:option magit-display-buffer-function #'magit-display-buffer-same-window + magit-popup-display-buffer-action '((display-buffer-same-window)) + magit-refresh-status-buffer nil)) + (setup (:straight marginalia) (:option marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light)) @@ -803,107 +841,76 @@ if ripgrep is installed, otherwise `consult-grep'." modus-themes-headings '((1 . section) (t . no-color)) modus-themes-mode-line nil) + (acdw/sunrise-sunset #'modus-themes-load-operandi #'modus-themes-load-vivendi)) -(setup (:straight simple-modeline) - (setup (:straight minions)) - (:option simple-modeline-segments - '((acdw-modeline/modified - acdw-modeline/buffer-name - acdw-modeline/vc-branch - simple-modeline-segment-position - simple-modeline-segment-word-count) - (simple-modeline-segment-misc-info - simple-modeline-segment-process - acdw-modeline/god-mode-indicator - acdw-modeline/minions - simple-modeline-segment-major-mode))) - (require 'acdw-modeline) - (simple-modeline-mode +1)) +(setup (:straight mwim) + (:global "C-a" mwim-beginning + "C-e" mwim-end)) + +(setup (:straight nov) + (:option nov-text-width fill-column) + (:file-match "\\.epub\\'")) (setup (:straight olivetti) (:option olivetti-body-width (+ fill-column 4) olivetti-minimum-body-width fill-column) + (add-hook 'olivetti-mode-hook (defun acdw/olivetti-mode-hook () (if olivetti-mode (setq-local indicate-empty-lines nil indicate-buffer-boundaries nil) - (acdw/setup-regular-modes))))) - -(setup (:straight form-feed) - (global-form-feed-mode +1)) - -(setup (:straight which-key) - (:option which-key-show-early-on-C-h t - which-key-idle-delay 10000 - which-key-idle-secondary-delay 0.05) - (which-key-setup-side-window-bottom) - (which-key-mode +1)) - -(setup (:straight helpful) - (:global " f" helpful-callable - " v" helpful-variable - " k" helpful-key - " o" helpful-symbol - "C-c C-d" helpful-at-point)) - -(setup (:straight (0x0 :host nil - :repo "https://git.sr.ht/~zge/nullpointer-emacs")) - (:option 0x0-default-host 'ttm)) - -(with-eval-after-load 'flyspell - (setup (:straight flyspell-correct) - (define-key flyspell-mode-map (kbd "C-;") #'flyspell-correct-wrapper))) + (acdw/fringe-setup))))) -(setup (:straight (electric-cursor +(setup (:straight (orderless :host github - :repo "duckwork/electric-cursor")) - (electric-cursor-mode +1)) - -(setup (:straight restart-emacs) - (defun upgrade-packages-and-restart () - "Upgrade all packages and restart Emacs." - (interactive) - (straight-pull-all) - (restart-emacs))) - - -;;; Programming - -;;; General tools -(setup (:straight (apheleia :host github - :repo "raxod502/apheleia")) - (apheleia-global-mode +1) - - ;; Use a dumb formatter on modes that `apheleia' doesn't work for. - (hook-defun dumb-auto-format before-save-hook - (setq stupid-modes '(makefile-mode)) - ;; If there's no apheleia formatter for the mode, just indent the buffer. - (unless (or (apply #'derived-mode-p stupid-modes) - (and (fboundp 'apheleia--get-formatter-command) - (apheleia--get-formatter-command))) - (indent-region (point-min) (point-max))))) - -;;; Lisps -(defvar lispy-modes '(emacs-lisp-mode - eval-expression-minibuffer - ielm-mode - lisp-mode - lisp-interaction-mode - scheme-mode - slime-repl-mode) - "List of modes that are lisp-like enough to hook packages into.") + :repo "oantolin/orderless")) + (require 'orderless) + (:option (prepend completion-styles) 'orderless)) -(setup (:straight paren-face) - (dolist (mode lispy-modes) - (add-hook (intern (concat (symbol-name mode) "-hook")) #'paren-face-mode))) +(setup (:straight (org :host nil + :repo "https://code.orgmode.org/bzg/org-mode.git")) + (require 'acdw-org) ; so I don't clutter up init.el + (:option org-adapt-indentation nil + org-catch-invisible-edits 'smart + org-confirm-babel-evaluate nil + org-export-coding-system 'utf-8-unix + org-export-headline-levels 8 + org-export-with-section-numbers nil + org-export-with-smart-quotes t + org-export-with-sub-superscripts t + org-export-with-toc nil + org-fontify-done-headline t + org-fontify-quote-and-verse-blocks t + org-fontify-whole-heading-line t + org-hide-emphasis-markers t + org-html-coding-system 'utf-8-unix + org-imenu-depth 3 + org-pretty-entities t + org-special-ctrl-a/e t + org-special-ctrl-k t + org-src-fontify-natively t + org-src-tab-acts-natively t + org-src-window-setup 'current-window + org-startup-truncated nil + org-tags-column (- 0 fill-column -3) + org-directory "~/org") + + (:bind "RET" acdw-org/return-dwim + "" acdw-org/org-table-copy-down) + + (add-hook 'before-save-hook #'acdw-org/fix-blank-lines-in-buffer) + + (advice-add 'org-delete-backward-char + :override #'acdw-org/delete-backward-char)) (setup (:straight paredit) ;; I don't use paredit-splice-sexp much, and it stomps on isearch. (:unbind "M-s") + (defun setup-paredit-mode () "Correct weirdnesses and set up paredit mode." (paredit-mode +1) @@ -916,92 +923,54 @@ if ripgrep is installed, otherwise `consult-grep'." (require 'eldoc) (eldoc-add-command 'paredit-backward-delete 'paredit-close-round)) -(setup elisp-mode - (:option eval-expression-print-length nil - eval-expression-print-level nil - lisp-indent-function #'lisp-indent-function) - - (defun acdw/enforce-lexical-binding () - (setq lexical-binding t)) - - (add-hook 'emacs-lisp-mode-hook #'acdw/enforce-lexical-binding) +(setup (:straight paren-face) + (dolist (mode lispy-modes) + (add-hook (intern (concat (symbol-name mode) "-hook")) #'paren-face-mode))) - (defun acdw/eval-region-or-buffer () +(setup (:straight restart-emacs) + (defun upgrade-packages-and-restart () + "Upgrade all packages and restart Emacs." (interactive) - (if (region-active-p) - (let ((begin (region-beginning)) - (end (region-end))) - (with-message (format "Evaluating %S -> %S" begin end) - (eval-region begin end))) - (with-message "Evaluating buffer" - (eval-buffer)))) - - ;; Emulate slime's eval binds - (:with-map emacs-lisp-mode-map - (:bind "C-c C-c" eval-defun - "C-c C-k" acdw/eval-region-or-buffer - "C-c C-z" ielm)) - - (add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode) - (add-hook 'ielm-mode-hook 'turn-on-eldoc-mode) - - (setup (:straight macrostep) - (define-key emacs-lisp-mode-map (kbd "C-c e") #'macrostep-expand)) - - (setup (:straight eros) - (:hook-into emacs-lisp-mode)) - - ;; Add advice to pulse evaluated regions - (defun acdw/elisp-eval-region-advice (fn start end &rest args) - (pulse-momentary-highlight-region start end) - (apply fn start end args)) - - (advice-add 'eval-region :around #'acdw/elisp-eval-region-advice)) - -(setup (:straight geiser)) + (straight-pull-all) + (restart-emacs))) -(when-let (lisp-bin (or (executable-find "sbcl") - (executable-find "clisp"))) - (setup (:straight slime) - (require 'slime-autoloads) - (:option inferior-lisp-program lisp-bin) - - (when-let ((slime-helper (or (expand-file-name-exists-p - "~/quicklisp/slime-helper.el") - (expand-file-name-exists-p - "~/var/quicklisp/slime-helper.el")))) - (load slime-helper)) - - (with-eval-after-load 'company - (setup (:straight slime-company) - (:option slime-company-completion 'fuzzy - slime-company-after-completion nil) - (slime-setup '(slime-fancy slime-company)))))) - -(when (executable-find "fennel") - (setup (:straight fennel-mode) - (autoload 'fennel-repl "fennel-mode" nil t) - (:file-match "\\.fnl\\'"))) +(setup (:straight simple-modeline) + (setup (:straight minions)) + (:option simple-modeline-segments + '((acdw-modeline/modified + acdw-modeline/buffer-name + acdw-modeline/vc-branch + simple-modeline-segment-position + simple-modeline-segment-word-count) + (simple-modeline-segment-misc-info + simple-modeline-segment-process + acdw-modeline/god-mode-indicator + acdw-modeline/minions + simple-modeline-segment-major-mode))) + + (require 'acdw-modeline) + (simple-modeline-mode +1)) -(setup (:straight lua-mode) - (:file-match "\\.lua\\'")) +(setup (:straight undo-fu) + (:global "C-/" undo-fu-only-undo + "C-?" undo-fu-only-redo)) -(setup sh-mode - (:option sh-basic-offset tab-width - sh-indent-after-case 0 - sh-indent-for-case-alt '+ - sh-indent-for-case-label 0) - (:local-set indent-tabs-mode t) +(setup (:straight undo-fu-session) + (:option undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" + "/git-rebase-todo\\'") + undo-fu-session-directory (acdw/dir "undo/" t) + undo-fu-session-compression (eq acdw/system :home)) - (when (executable-find "shfmt") - (with-eval-after-load 'apheleia - (:option (append apheleia-formatters) '(shfmt . ("shfmt")) - (append apheleia-mode-alist) '(sh-mode . shfmt)))) + (global-undo-fu-session-mode +1)) - (when (executable-find "shellcheck") - (straight-use-package 'flymake-shellcheck) - (:hook flymake-mode - flymake-shellcheck-load))) +(setup (:straight (vertico + :host github + :repo "minad/vertico")) + (setq resize-mini-windows 'grow-only) + (if (boundp 'comp-deferred-compilation-deny-list) + (add-to-list 'comp-deferred-compilation-deny-list "vertico")) + (icomplete-mode -1) + (vertico-mode +1)) (setup (:straight web-mode) (:option css-level-offset 2 @@ -1015,18 +984,35 @@ if ripgrep is installed, otherwise `consult-grep'." "\\.erb\\'" "\\.mustache\\'")) -(when (locate-library "gforth") - (autoload 'forth-mode "gforth") - (add-to-list 'auto-mode-alist '("\\.fs\\'" . forth-mode)) - (autoload 'forth-block-mode "gforth") - (add-to-list 'auto-mode-alist '("\\.fb\\'" . forth-block-mode))) +(setup (:straight which-key) + (:option which-key-show-early-on-C-h t + which-key-idle-delay 10000 + which-key-idle-secondary-delay 0.05) + (which-key-setup-side-window-bottom) + (which-key-mode +1)) -(when (eq acdw/system :home) - (setup (:straight pkgbuild-mode))) +(setup (:straight zzz-to-char) + (defun acdw/zzz-up-to-char (prefix) + "Call `zzz-up-to-char', unless issued a PREFIX, in which case +call `zzz-to-char'." + (interactive "P") + (if prefix + (call-interactively #'zzz-to-char) + (call-interactively #'zzz-up-to-char))) + + (:global "M-z" acdw/zzz-up-to-char)) -;;; Server +;;; System-dependent + +;;;; Home +(when (eq acdw/system :home) + + (setup (:straight pkgbuild-mode)) + + (setup (:straight (pdf-tools + :host github + :repo "vedang/pdf-tools")) + (pdf-loader-install)) -(require 'server) -(unless (server-running-p) - (server-start)) + (setup (:straight vterm))) diff --git a/lisp/acdw-modeline.el b/lisp/acdw-modeline.el index c7b904f..79249bb 100644 --- a/lisp/acdw-modeline.el +++ b/lisp/acdw-modeline.el @@ -22,64 +22,60 @@ (require 'simple-modeline) (require 'minions) -;; modified from `simple-modeline' -(defun acdw-modeline/modified () - "Displays a color-coded buffer modification/read-only +(defun acdw-modeline/buffer-name () ; gonsie + (propertize " %b " + 'face + (if (buffer-modified-p) + 'font-lock-warning-face + 'font-lock-type-face) + 'help-echo (buffer-file-name))) + +(defun acdw-modeline/god-mode-indicator () + (when (bound-and-true-p god-local-mode) + " God")) + +(defun acdw-modeline/modified () ; modified from `simple-modeline' + "Displays a color-coded buffer modification/read-only indicator in the mode-line." - (if (not (string-match-p "\\*.*\\*" (buffer-name))) - (let* ((read-only (and buffer-read-only (buffer-file-name))) + (if (not (string-match-p "\\*.*\\*" (buffer-name))) + (let* ((read-only (and buffer-read-only (buffer-file-name))) (modified (buffer-modified-p))) (propertize (if read-only " =" (if modified " +" " -")) 'help-echo (format - (concat "Buffer is %s and %smodified\n" - "mouse-1: Toggle read-only status.") - (if read-only "read-only" "writable") - (if modified "" "not ")) + (concat "Buffer is %s and %smodified\n" + "mouse-1: Toggle read-only status.") + (if read-only "read-only" "writable") + (if modified "" "not ")) 'local-map (purecopy (simple-modeline-make-mouse-map - 'mouse-1 - (lambda (event) - (interactive "e") - (with-selected-window - (posn-window (event-start event)) - (read-only-mode 'toggle))))) + 'mouse-1 + (lambda (event) + (interactive "e") + (with-selected-window + (posn-window (event-start event)) + (read-only-mode 'toggle))))) 'mouse-face 'mode-line-highlight)))) -;; all me, baby -(defun acdw-modeline/minions () - "Display a button for `minions-minor-modes-menu'." - (concat - " " - (propertize - "&" - 'help-echo (format - "Minor modes menu\nmouse-1: show menu.") - 'local-map (purecopy (simple-modeline-make-mouse-map - 'mouse-1 - (lambda (event) - (interactive "e") - (with-selected-window (posn-window - (event-start event)) - (minions-minor-modes-menu))))) - 'mouse-face 'mode-line-highlight))) +(defun acdw-modeline/minions () ; by me + "Display a button for `minions-minor-modes-menu'." + (concat + " " + (propertize + "&" + 'help-echo (format + "Minor modes menu\nmouse-1: show menu.") + 'local-map (purecopy (simple-modeline-make-mouse-map + 'mouse-1 + (lambda (event) + (interactive "e") + (with-selected-window (posn-window + (event-start event)) + (minions-minor-modes-menu))))) + 'mouse-face 'mode-line-highlight))) -;; from https://www.gonsie.com/blorg/modeline.html, from Doom (defun acdw-modeline/vc-branch () + ;; from https://www.gonsie.com/blorg/modeline.html, from Doom (if-let ((backend (vc-backend buffer-file-name))) - (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)))) - -;; from gonsie -(defun acdw-modeline/buffer-name () - (propertize " %b " - 'face - (if (buffer-modified-p) - 'font-lock-warning-face - 'font-lock-type-face) - 'help-echo (buffer-file-name))) - -;; god-mode indicator -(defun acdw-modeline/god-mode-indicator () - (when (bound-and-true-p god-local-mode) - " God")) + (substring vc-mode (+ (if (eq backend 'Hg) 2 3) 2)))) (provide 'acdw-modeline) diff --git a/lisp/acdw-re.el b/lisp/acdw-re.el new file mode 100644 index 0000000..ea1c42a --- /dev/null +++ b/lisp/acdw-re.el @@ -0,0 +1,66 @@ +;;; acdw-re.el -*- lexical-binding: t; coding: utf-8-unix -*- +;; Author: Case Duckworth +;; Created: 2021-04-29 +;; Keywords: configuration +;; URL: https://tildegit.org/acdw/emacs + +;; This file is NOT part of GNU Emacs. + +;;; License: +;; Everyone is permitted to do whatever with this software, without +;; limitation. This software comes without any warranty whatsoever, +;; but with two pieces of advice: +;; - Don't hurt yourself. +;; - Make good choices. + +;;; Commentary: +;; Pulled mostly from karthinks: +;; https://karthinks.com/software/bridging-islands-in-emacs-1/ + +;;; Code: + +(defvar acdw/re-builder-positions nil + "Store point and region bounds before calling re-builder") + +(defun acdw/re-builder-save-state (&rest _) + "Save into `acdw/re-builder-positions' the point and region +positions before calling `re-builder'." + (setq acdw/re-builder-positions + (cons (point) + (when (region-active-p) + (list (region-beginning) + (region-end)))))) + +(defun reb-replace-regexp (&optional delimited) + "Run `query-replace-regexp' with the contents of re-builder. With +non-nil optional argument DELIMITED, only replace matches +surrounded by word boundaries." + (interactive "P") + (reb-update-regexp) + (let* ((re (reb-target-binding reb-regexp)) + (replacement (query-replace-read-to + re + (concat "Query replace" + (if current-prefix-arg + (if (eq current-prefix-arg '-) + " backward" + " word") + "") + " regexp" + (if (with-selected-window reb-target-window + (region-active-p)) " in region" "")) + t)) + (pnt (car acdw/re-builder-positions)) + (beg (cadr acdw/re-builder-positions)) + (end (caddr acdw/re-builder-positions))) + (with-selected-window reb-target-window + ;; replace with (goto-char (match-beginning 0)) if you want to control + ;; where in the buffer the replacement starts with re-builder + (goto-char pnt) + (setq acdw/re-builder-positions nil) + (reb-quit) + (query-replace-regexp re replacement delimited beg end)))) + +(provide 'acdw-re) + +;;; acdw-re.el ends here diff --git a/lisp/acdw.el b/lisp/acdw.el index 54b139c..1093a8d 100644 --- a/lisp/acdw.el +++ b/lisp/acdw.el @@ -19,7 +19,7 @@ ;;; Code: -;; Utility constants +;;; Variables (defconst acdw/system (pcase system-type ('gnu/linux :home) @@ -28,19 +28,15 @@ "Which computer system is currently being used.") -;; Utility functions +;;; Utility functions -(defmacro when-unfocused (name &rest forms) - "Define a function NAME, executing FORMS, that fires when Emacs -is unfocused." - (declare (indent 1)) - (let ((func-name (intern (concat "when-unfocused-" (symbol-name name))))) - `(progn - (defun ,func-name () "Defined by `when-unfocused'." - (when (seq-every-p #'null - (mapcar #'frame-focus-state (frame-list))) - ,@forms)) - (add-function :after after-focus-change-function #',func-name)))) +(defun expand-file-name-exists-p (&rest expand-file-name-args) + "Call `expand-file-name' on EXPAND-FILE-NAME-ARGS, returning + its name if it exists, or NIL otherwise." + (let ((file (apply #'expand-file-name expand-file-name-args))) + (if (file-exists-p file) + file + nil))) (defmacro hook-defun (name hooks &rest forms) "Define a function NAME that executes FORMS, and add it to @@ -88,13 +84,17 @@ With a prefix argument, run git pull on the repo first." (when (file-exists-p file) (load-file file)))))) -(defun expand-file-name-exists-p (&rest expand-file-name-args) - "Call `expand-file-name' on EXPAND-FILE-NAME-ARGS, returning - its name if it exists, or NIL otherwise." - (let ((file (apply #'expand-file-name expand-file-name-args))) - (if (file-exists-p file) - file - nil))) +(defmacro when-unfocused (name &rest forms) + "Define a function NAME, executing FORMS, that fires when Emacs +is unfocused." + (declare (indent 1)) + (let ((func-name (intern (concat "when-unfocused-" (symbol-name name))))) + `(progn + (defun ,func-name () "Defined by `when-unfocused'." + (when (seq-every-p #'null + (mapcar #'frame-focus-state (frame-list))) + ,@forms)) + (add-function :after after-focus-change-function #',func-name)))) (defmacro with-message (message &rest body) "Execute BODY, messaging 'MESSAGE...' before and 'MESSAGE... Done.' after." @@ -105,6 +105,9 @@ With a prefix argument, run git pull on the repo first." ,@body) (message "%s... Done." ,message))) + +;;; Specialized functions + (defun acdw/dir (&optional file make-directory) "Place Emacs files in one place. @@ -122,37 +125,6 @@ if MAKE-DIRECTORY is non-nil." file-name) dir))) -(defun acdw/gc-enable () - "Enable the Garbage collector." - (setq gc-cons-threshold (* 800 1024 1024) - gc-cons-percentage 0.1)) - -(defun acdw/gc-disable () - "Functionally disable the Garbage collector." - (setq gc-cons-threshold most-positive-fixnum - gc-cons-percentage 0.8)) - -(defun acdw/sunrise-sunset (sunrise-command sunset-command) - "Run commands at sunrise and sunset." - (let* ((times-regex (rx (* nonl) - (: (any ?s ?S) "unrise") " " - (group (repeat 1 2 digit) ":" - (repeat 1 2 digit) - (: (any ?a ?A ?p ?P) (any ?m ?M))) - (* nonl) - (: (any ?s ?S) "unset") " " - (group (repeat 1 2 digit) ":" - (repeat 1 2 digit) - (: (any ?a ?A ?p ?P) (any ?m ?M))) - (* nonl))) - (ss (sunrise-sunset)) - (_m (string-match times-regex ss)) - (sunrise-time (match-string 1 ss)) - (sunset-time (match-string 2 ss))) - (run-at-time sunrise-time (* 60 60 24) sunrise-command) - (run-at-time sunset-time (* 60 60 24) sunset-command) - (run-at-time "12:00am" (* 60 60 24) sunset-command))) - (defun acdw/find-emacs-dotfiles () "Finds lisp files in `user-emacs-directory' and passes them to `completing-read'." @@ -161,6 +133,30 @@ if MAKE-DIRECTORY is non-nil." (directory-files-recursively user-emacs-directory "\.el$")))) +(defun acdw/find-emacs-source () + "Find where Emacs keeps its source tree." + (pcase acdw/system + (:work (expand-file-name + (concat "~/src/emacs-" emacs-version "/src"))) + (:home (expand-file-name "~/src/pkg/emacs/src/emacs-git/src")) + (:other nil))) + +(defun acdw/gc-disable () + "Functionally disable the Garbage collector." + (setq gc-cons-threshold most-positive-fixnum + gc-cons-percentage 0.8)) + +(defun acdw/gc-enable () + "Enable the Garbage collector." + (setq gc-cons-threshold (* 800 1024 1024) + gc-cons-percentage 0.1)) + +(defun acdw/insert-iso-date (with-time) + "Insert the ISO-8601-formatted date, with optional time." + (interactive "P") + (let ((format (if with-time "%FT%T%z" "%F"))) + (insert (format-time-string format (current-time))))) + (defun acdw/kill-a-buffer (&optional prefix) "Kill a buffer based on the following rules: @@ -179,14 +175,30 @@ Prompt only if there are unsaved changes." (16 (mapc 'kill-buffer (delq (current-buffer) (buffer-list))) (delete-other-windows)))) -(defun acdw/insert-iso-date (with-time) - "Insert the ISO-8601-formatted date, with optional time." - (interactive "P") - (let ((format (if with-time "%FT%T%z" "%F"))) - (insert (format-time-string format (current-time))))) +(defun acdw/sunrise-sunset (sunrise-command sunset-command) + "Run commands at sunrise and sunset." + (let* ((times-regex (rx (* nonl) + (: (any ?s ?S) "unrise") " " + (group (repeat 1 2 digit) ":" + (repeat 1 2 digit) + (: (any ?a ?A ?p ?P) (any ?m ?M))) + (* nonl) + (: (any ?s ?S) "unset") " " + (group (repeat 1 2 digit) ":" + (repeat 1 2 digit) + (: (any ?a ?A ?p ?P) (any ?m ?M))) + (* nonl))) + (ss (sunrise-sunset)) + (_m (string-match times-regex ss)) + (sunrise-time (match-string 1 ss)) + (sunset-time (match-string 2 ss))) + (run-at-time sunrise-time (* 60 60 24) sunrise-command) + (run-at-time sunset-time (* 60 60 24) sunset-command) + (run-at-time "12:00am" (* 60 60 24) sunset-command))) -;; Make `C-z' more useful +;;; Keymaps + (defvar acdw/leader (let ((map (make-sparse-keymap)) (c-z (global-key-binding "\C-z"))) @@ -195,7 +207,8 @@ Prompt only if there are unsaved changes." map)) -;; `acdw/reading-mode' +;;; Minor modes + (define-minor-mode acdw/reading-mode "A mode for reading." :init-value nil -- cgit 1.4.1-21-gabe81