diff --git a/init.el b/init.el index b32dfce..1a39f3c 100644 --- a/init.el +++ b/init.el @@ -38,11 +38,12 @@ "C-x o" (lambda () (interactive) (switch-to-buffer nil)) "C-x C-o" #'+open-paragraph "C-w" #'+kill-word-backward-or-region - "C-x C-1" #'delete-other-windows - "C-x 2" #'+split-window-below-then - "C-x C-2" #'+split-window-below-then - "C-x 3" #'+split-window-right-then - "C-x C-3" #'+split-window-right-then) + ;; "C-x C-1" #'delete-other-windows + ;; "C-x 2" #'+split-window-below-then + ;; "C-x C-2" #'+split-window-below-then + ;; "C-x 3" #'+split-window-right-then + ;; "C-x C-3" #'+split-window-right-then + ) ;; C-h deletes backward - see https://idiomdrottning.org/bad-emacs-defaults (global-set-key (kbd "C-h") 'delete-backward-char) (keyboard-translate ?\C-h ?\C-?) @@ -58,9 +59,6 @@ (:bind "C-c s" #'+init-sort-then-save) (:hook #'+init-add-setup-to-imenu)) -(setup (:require +lookup) - (+lookup-mode +1)) - (setup (:require auth-source) (:option auth-sources (list (private/ "authinfo")))) @@ -109,6 +107,9 @@ (:option pulse-flag nil pulse-delay 0.5 pulse-iterations 1) + (dolist (command '(+ace-window-or-switch-buffer + pop-mark pop-globl-mark)) + (add-to-list '+pulse-location-commands command)) (+ensure-after-init #'+pulse-location-mode)) (setup (:require reading) @@ -137,6 +138,15 @@ (:option browse-url-browser-function #'eww-browse-url +browse-url-browser-function browse-url-browser-function + browse-url-generic-program (seq-some #'executable-find + '("firefox" + "chromium" + "chrome")) + browse-url-generic-args (seq-some (lambda (e) + (when (equal (executable-find (car e)) + browse-url-generic-program) + (cdr e))) + '(("firefox" "--new-tab"))) browse-url-secondary-browser-function (if (executable-find "firefox") #'browse-url-firefox #'browse-url-default-browser) @@ -230,7 +240,7 @@ copy move hardlink symlink shell touch) dired-dwim-target t) - (:local-set truncate-lines nil) + (:local-set truncate-lines t) (:bind "" #'dired-up-directory "TAB" #'dired-subtree-cycle "i" #'dired-subtree-toggle @@ -475,13 +485,19 @@ (with-eval-after-load 'org (org-clock-persistence-insinuate) (org-link-set-parameters "tel" :follow #'+org-tel-open)) - ;; Fancy list bullets + ;; Extra keywords (font-lock-add-keywords 'org-mode - '(("^ *\\([-]\\) " + '(;; Fancy list bullets + ("^ *\\([-]\\) " (0 (compose-region (match-beginning 1) (match-end 1) "•"))) ("^ *\\([+]\\) " - (0 (compose-region (match-beginning 1) (match-end 1) "◦")))))) + (0 (compose-region (match-beginning 1) (match-end 1) "◦")))) + (with-eval-after-load 'form-feed + ;; Horizontal lines + (font-lock-add-keywords + 'org-mode + '(("^-----+" 0 'form-feed--font-lock-face t)))))) (setup org-agenda (:option org-agenda-skip-deadline-if-done t @@ -586,9 +602,6 @@ (executable-find "diff")) (:require apheleia +apheleia) - (setf (alist-get 'indent-region apheleia-formatters) #'+apheleia-indent-region - (alist-get 'emacs-lisp-mode apheleia-mode-alist) 'indent-region - (alist-get 'lisp-interaction-mode apheleia-mode-alist) 'indent-region) (apheleia-global-mode +1)) (setup (:straight avy) @@ -721,9 +734,15 @@ (advice-add #'circe-command-GQUIT :after #'+circe-gquit@kill-buffer) (:with-mode circe-chat-mode + (:local-set lui-input-function #'+lui-filter) (:hook #'enable-circe-color-nicks #'enable-circe-new-day-notifier - #'+circe-chat@set-prompt) + #'+circe-chat@set-prompt + ;; Filters + #'+circe-F/C-mode + ;; For some reason `+circe-shorten-url-mode' won't work right out of + ;; the gate. + (lambda () (run-with-idle-timer 0.25 nil #'+circe-shorten-url-mode))) (:bind "C-c C-s" #'circe-command-SLAP)) (:with-mode lui-mode @@ -889,8 +908,7 @@ See also `crux-reopen-as-root-mode'." (:option dictionary-use-single-buffer t) (autoload 'dictionary-search "dictionary" "Ask for a word and search it in all dictionaries" t) - (:hook #'reading-mode) - (define-key +lookup-mode-map "d" #'dictionary-search)) + (:hook #'reading-mode)) (setup (:straight (discord :host github @@ -918,12 +936,15 @@ See also `crux-reopen-as-root-mode'." elfeed-search-title-min-width 24 elfeed-search-title-max-width 78 elfeed-show-unique-buffers t - elfeed-db-directory (elfeed/ "db/" t)) - (:+key "C-x w" #'+elfeed) + elfeed-db-directory (elfeed/ "db/" t) + elfeed-log 'debug ; until I can figure out syncing... + ) + (:+key "C-x w" #'elfeed) (:with-mode elfeed-search-mode (:hook #'hl-line-mode) ;; https://old.reddit.com/r/emacs/comments/rlli0u/whats_your_favorite_defadvice/hphfh4e/ - (advice-add #'elfeed-search-update--force :after #'elfeed-db-save)) + (advice-add #'elfeed-search-update--force :after #'elfeed-db-save) + (advice-add #'elfeed :before #'elfeed-db-load)) (:with-mode elfeed-show-mode (:bind "SPC" #'+elfeed-scroll-up-command "S-SPC" #'+elfeed-scroll-down-command) @@ -945,14 +966,16 @@ See also `crux-reopen-as-root-mode'." (setup (:straight elpher)) (setup (:straight embark) - (:also-load +embark) + (:require embark + +embark) (:option prefix-help-command 'embark-prefix-help-command embark-keymap-prompter-key ";") (:+key "C-." #'embark-act "M-." #'embark-dwim " B" #'embark-bindings) (:with-map minibuffer-local-map - (:bind "C-." #'embark-act)) + (:bind "C-." #'embark-act + "M-." #'embark-dwim)) (:with-map embark-file-map (:bind "l" #'vlf))) @@ -1059,14 +1082,14 @@ See also `crux-reopen-as-root-mode'." (:file-match (rx ".rkt" eos) (rx ".scm" eos))) -(setup (:straight god-mode) - (setq god-mode-enable-function-key-translation nil) - (:require god-mode - +god-mode) - (:+key "C-M-g" #'god-mode-all) - (:with-mode god-local-mode - (:bind "i" #'+god-mode-insert - "a" nil))) +;; (setup (:straight god-mode) +;; (setq god-mode-enable-function-key-translation nil) +;; (:require god-mode +;; +god-mode) +;; (:+key "C-M-g" #'god-mode-all) +;; (:with-mode god-local-mode +;; (:bind "i" #'+god-mode-insert +;; "a" nil))) (setup (:straight helpful) (run-with-idle-timer 0.5 nil @@ -1132,17 +1155,9 @@ See also `crux-reopen-as-root-mode'." (setup (:straight (lin :host gitlab :repo "protesilaos/lin")) (require 'lin) - (:hook-into dired-mode - elfeed-search-mode - git-rebase-mode - ibuffer-mode - ledger-report-mode - log-view-mode - magit-log-mode - notmuch-search-mode - notmuch-tree-mode - org-agenda-mode - tabulated-list-mode)) + (dolist (hook lin-foreign-hooks) + (add-hook hook #'hl-line-mode) + (add-hook hook #'lin-mode))) (setup (:straight link-hint) (:require +link-hint) @@ -1155,6 +1170,11 @@ See also `crux-reopen-as-root-mode'." "m" #'link-hint-open-multiple-links "M-c" #'link-hint-copy-link "c" #'link-hint-copy-link))) +(setup (:straight macrostep) + (:require macrostep) + (:with-mode emacs-lisp-mode + (:bind "C-c e" #'macrostep-expand))) + (setup (:straight marginalia) (marginalia-mode +1)) @@ -1306,8 +1326,10 @@ See also `crux-reopen-as-root-mode'." :host github :repo "duckwork/titlecase.el" :files ("*"))) - (:with-map +casing-mode-map - (:bind "t" #'titlecase-dwim))) + (:require titlecase) + (:with-map +casing-map + (:bind "t" #'titlecase-dwim + "M-t" #'titlecase-dwim))) (setup (:straight topsy) (:hook-into ;;prog-mode @@ -1366,11 +1388,35 @@ See also `crux-reopen-as-root-mode'." (add-to-list 'native-comp-deferred-compilation-deny-list "vertico")) (vertico-mode +1) ;; Extensions - (:also-load vertico-directory) + (:also-load vertico-directory + vertico-mouse + vertico-unobtrusive + vertico-multiform) + (vertico-mouse-mode +1) + (vertico-multiform-mode +1) + (:option vertico-multiform-commands '((execute-extended-command flat) + (helpful-callable) + (helpful-variable)) + ;; This is applied /after/ the above, so default is at the end of + ;; this alist. + vertico-multiform-categories '((file buffer grid) + (t unobtrusive))) + (dolist (buf-cmd '(consult-find + consult-locate + consult-grep + consult-git-grep + consult-ripgrep + consult-line + consult-line-multi + consult-multi-occur + consult-keep-lines + consult-focus-lines)) + (setf (alist-get buf-cmd vertico-multiform-commands) '(buffer))) (:with-map vertico-map (:bind "RET" #'vertico-directory-enter "DEL" #'vertico-directory-delete-char - "M-DEL" #'vertico-directory-delete-word)) + "M-DEL" #'vertico-directory-delete-word + "TAB" #'+vertico-widen-or-complete)) (add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy)) (setup (:straight visual-fill-column) diff --git a/lisp/+apheleia.el b/lisp/+apheleia.el index f3b16e4..469232a 100644 --- a/lisp/+apheleia.el +++ b/lisp/+apheleia.el @@ -8,9 +8,8 @@ (setq-local indent-line-function (buffer-local-value 'indent-line-function orig)) (indent-region (point-min) -(point-max)) + (point-max)) (funcall callback))) (provide '+apheleia) ;;; +apheleia.el ends here - \ No newline at end of file diff --git a/lisp/+casing.el b/lisp/+casing.el index 5f39b2e..c8e9e4d 100644 --- a/lisp/+casing.el +++ b/lisp/+casing.el @@ -3,7 +3,6 @@ ;;; Code: (require 'thingatpt) -(require '+key) ;;;###autoload (defun +upcase-dwim (arg) @@ -61,21 +60,23 @@ Otherwise, it calls `capitalize-word' on the word at point (using ;; Later on, I'll add repeat maps and stuff in here... +(defvar +casing-map (let ((map (make-sparse-keymap))) + (define-key map "u" #'+upcase-dwim) + (define-key map (kbd "M-u") #'+upcase-dwim) + (define-key map "l" #'+downcase-dwim) + (define-key map (kbd "M-l") #'+downcase-dwim) + (define-key map "c" #'+capitalize-dwim) + (define-key map (kbd "M-c") #'+capitalize-dwim) + map) + "Keymap for case-related twiddling.") + (define-minor-mode +casing-mode "Enable easy case-twiddling commands." :lighter " cC" + :global t :keymap (let ((map (make-sparse-keymap))) - (define-key map "u" #'+upcase-dwim) - (define-key map (kbd "M-u") #'+upcase-dwim) - (define-key map "l" #'+downcase-dwim) - (define-key map (kbd "M-l") #'+downcase-dwim) - (define-key map "c" #'+capitalize-dwim) - (define-key map (kbd "M-c") #'+capitalize-dwim) - map) - (define-key +key-mode-map (kbd "M-c") (when +casing-mode - +casing-mode-map))) - -(defvaralias '+casing-map '+casing-mode-map) + (define-key map (kbd "M-c") +casing-map) + map)) (provide '+casing) ;;; +casing.el ends here diff --git a/lisp/+circe.el b/lisp/+circe.el index c29cea6..3d6ea60 100644 --- a/lisp/+circe.el +++ b/lisp/+circe.el @@ -101,9 +101,11 @@ For entry into `lui-formatting-list'." (defun +circe-kill-buffer (&rest _) "Kill a circe buffer without confirmation, and after a delay." - (let ((circe-channel-killed-confirmation nil) - (circe-server-killed-confirmation nil)) - (run-with-timer 0.25 nil 'kill-buffer))) + (let ((circe-channel-killed-confirmation) + (circe-server-killed-confirmation)) + (when (derived-mode-p 'lui-mode) ; don't spuriously kill + (ignore-errors + (kill-buffer))))) (defun +circe-quit@kill-buffer (&rest _) "ADVICE: kill all buffers of a server after `circe-command-QUIT'." @@ -115,9 +117,11 @@ For entry into `lui-formatting-list'." (defun +circe-gquit@kill-buffer (&rest _) "ADVICE: kill all Circe buffers after `circe-command-GQUIT'." - (dolist (buf (circe-server-buffers)) - (with-current-buffer buf - (+circe-quit@kill-buffer)))) + (let ((circe-channel-killed-confirmation) + (circe-server-killed-confirmation)) + (dolist (buf (circe-server-buffers)) + (with-current-buffer buf + (+circe-quit@kill-buffer))))) (defun +circe-quit-all@kill-emacs () "Quit all circe buffers when killing Emacs." @@ -165,28 +169,104 @@ See `circe-network-options' for a list of common options." (funcall +circe-server-buffer-action buffer)))) ;;; Chat commands -;; TODO: Actually ... write these~!?!?! - -(defun circe-command-SHORTEN (url) - "Shorten URL using `0x0-shorten-uri'.") (defun circe-command-SLAP (nick) - "Slap NICK around a bit with a large trout.") + "Slap NICK around a bit with a large trout." + (interactive (list (completing-read "Nick to slap: " + (circe-channel-nicks) + nil t nil))) + (circe-command-ME (format "slaps %s about a bit with a large trout" nick))) -(defun circe-command-POKE (nick) - "Poke NICK like in the old Facebook days.") +;;; Filtering functions +;; Set `lui-input-function' to `+lui-filter', then add the filters you want to +;; `circe-channel-mode-hook'. -;;; Pure idiocy +(require 'dash) -(define-minor-mode circe-cappy-hour-mode +(defvar +lui-filters nil + "Stack of input functions to apply. +This is an alist with cells of the structure (TAG . FN), so we +can easily remove elements.") +(make-variable-buffer-local '+lui-filters) + +(defun +lui-filter (text &optional fn-alist) + (let ((fs (nreverse (purecopy (or fn-alist +lui-filters))))) + (while fs + (setq text (funcall (cdr (pop fs)) text))) + (circe--input text))) + +(defmacro +circe-define-filter (name docstring &rest body) + "Define a filter for circe-inputted text." + (declare (doc-string 2) + (indent 1)) + (let (plist) + (while (keywordp (car-safe body)) + (push (pop body) plist) + (push (pop body) plist)) + ;; Return value + `(define-minor-mode ,name + ,docstring + ,@(nreverse plist) + (when (derived-mode-p 'circe-chat-mode) + (if ,name + (push '(,name . (lambda (it) ,@body)) +lui-filters) + (setq +lui-filters + (assoc-delete-all ',name +lui-filters))))))) + +;; CAPPY HOUR! (Pure idiocy) + +(+circe-define-filter +circe-cappy-hour-mode "ENABLE CAPPY HOUR IN CIRCE!" - :lighter "CAPPY HOUR" - (when (derived-mode-p 'circe-chat-mode) - (if circe-cappy-hour-mode - (setq-local lui-input-function - (lambda (input) (circe--input (upcase input)))) - ;; XXX: It'd be better if this were more general, but whatever. - (setq-local lui-input-function #'circe--input)))) + :lighter " CAPPY HOUR" + (upcase it)) + +;; URL Shortener + +(+circe-define-filter +circe-shorten-url-mode + "Shorten long urls when chatting." + :lighter " c0x0" + (+circe-0x0-shorten-urls it)) + +(defvar +circe-0x0-max-length 20 + "Maximum length of URLs before using a shortener.") + +(defun +circe-0x0-shorten-urls (text) + "Find urls in TEXT and shorten them using `0x0'." + (require '0x0) + (require 'browse-url) + (let ((case-fold-search t)) + (replace-regexp-in-string + browse-url-button-regexp + (lambda (match) + (if (> (length match) +circe-0x0-max-length) + (+with-message (format "Shortening URL: %s" match) + (0x0-shorten-uri (0x0--choose-server) + (substring-no-properties match))) + match)) + text))) + +;; Temperature conversion + +(+circe-define-filter +circe-F/C-mode + "Convert degF to degF/degC for international chats." + :lighter " F/C" + (str-F/C it)) + +(defun fahrenheit-to-celsius (degf) + "Convert DEGF to Celsius." + (round (* (/ 5.0 9.0) (- degf 32)))) + +(defun celsius-to-fahrenheit (degc) + "Convert DEGC to Fahrenheit." + (round (+ 32 (* (/ 9.0 5.0) degc)))) + +(defun str-F/C (text) + (replace-regexp-in-string "[0-9.]+[Ff]" + (lambda (match) + (format "%s/%dC" match + (fahrenheit-to-celsius + (string-to-number match)))) + text)) (provide '+circe) ;;; +circe.el ends here diff --git a/lisp/+elfeed.el b/lisp/+elfeed.el index c26bfab..4ee7581 100644 --- a/lisp/+elfeed.el +++ b/lisp/+elfeed.el @@ -21,12 +21,5 @@ (scroll-down-command arg) (error (elfeed-show-prev))))) -;; https://babbagefiles.blogspot.com/2017/03/take-elfeed-everywhere-mobile-rss.html -(defun +elfeed () - "Wrapper to load the elfeed db from disk before opening." - (interactive) - (elfeed-db-load) - (elfeed)) - (provide '+elfeed) ;;; +elfeed.el ends here diff --git a/lisp/+embark.el b/lisp/+embark.el index 3900492..e66d4b3 100644 --- a/lisp/+embark.el +++ b/lisp/+embark.el @@ -7,7 +7,6 @@ ;;; Code: (require 'embark) -(require 'marginalia) (embark-define-keymap embark-straight-map ("u" straight-visit-package-website) @@ -22,7 +21,8 @@ (add-to-list 'embark-keymap-alist '(straight . embark-straight-map)) -(add-to-list 'marginalia-prompt-categories '("recipe\\|package" . straight)) +(with-eval-after-load 'marginalia + (add-to-list 'marginalia-prompt-categories '("recipe\\|package" . straight))) (provide '+embark) ;;; +embark.el ends here diff --git a/lisp/+lookup.el b/lisp/+lookup.el deleted file mode 100644 index 755f84e..0000000 --- a/lisp/+lookup.el +++ /dev/null @@ -1,26 +0,0 @@ -;;; +lookup.el -*- lexical-binding: t; -*- - -;;; Commentary: - -;; I look up a lot of things in Emacs. Let's bind them all to an easy-to-use -;; keymap. - -;;; Code: - -(require '+key) - -(define-minor-mode +lookup-mode - "A mode for easily looking things up." - :lighter " l^" - :keymap (let ((map (make-sparse-keymap))) - (define-key map "f" #'find-function) - (define-key map "l" #'find-library) - (define-key map "v" #'find-variable) - map) - (define-key +key-mode-map (kbd "C-c l") (when +lookup-mode - +lookup-mode-map))) - -(defvaralias '+lookup-map '+lookup-mode-map) - -(provide '+lookup) -;;; +lookup.el ends here diff --git a/lisp/+org-capture.el b/lisp/+org-capture.el index ba036bd..6c59b98 100644 --- a/lisp/+org-capture.el +++ b/lisp/+org-capture.el @@ -85,5 +85,21 @@ properly process the variable." ;; Sort after, maybe (when sort-after (+org-capture-sort list)))) +(defun +org-template--ensure-path (keys &optional list) + "Ensure path of keys exists in `org-capture-templates'." + (unless list (setq list 'org-capture-templates)) + (when (> (length key) 1) + ;; Check for existence of groups. + (let ((expected (cl-loop for i from 1 to (1- (length key)) + collect (substring key 0 i) into keys + finally return keys))) + (cl-loop for ek in expected + if (not (+org-capture--get ek (symbol-value list))) do + (setf (+org-capture--get ek (symbol-value list)) + (list (format "(Group %s)" ek))))))) + +(defun +org-define-capture-template (keys title &rest args) + ) + (provide '+org-capture) ;;; +org-capture.el ends here diff --git a/lisp/+vertico.el b/lisp/+vertico.el index 4adde3d..d4fb3a3 100644 --- a/lisp/+vertico.el +++ b/lisp/+vertico.el @@ -12,5 +12,13 @@ (unless (eq 1 (abs (- beg-index vertico--index))) (ding)))) +(defun +vertico-widen-or-complete () + (interactive) + (if (or vertico-unobtrusive-mode + vertico-flat-mode) + (progn (vertico-unobtrusive-mode -1) + (vertico-flat-mode -1)) + (call-interactively #'vertico-insert))) + (provide '+vertico) ;;; +vertico.el ends here diff --git a/lisp/acdw.el b/lisp/acdw.el index 262c15e..603f46f 100644 --- a/lisp/acdw.el +++ b/lisp/acdw.el @@ -128,10 +128,12 @@ I keep forgetting how they differ." (defmacro +with-message (message &rest body) "Execute BODY, with MESSAGE. If body executes without errors, MESSAGE...Done will be displayed." - ;; ^ TODO - `(prog1 (progn (message ,(concat message "...")) - ,@body) - (message ,(concat message "...Done.")))) + (declare (indent 1)) + (let ((msg (gensym))) + `(let ((,msg ,message)) + (unwind-protect (progn (message "%s..." ,msg) + ,@body) + (message "%s... Done." ,msg))))) (defun +mapc-some-buffers (func &optional predicate) "Perform FUNC on all buffers satisfied by PREDICATE.