From b11adad984e8160e366d7e154d12c378a9545b9a Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Mon, 13 Dec 2021 10:29:50 -0600 Subject: Lots of changes, most interestingly browse-url stuff --- init.el | 133 ++++++++++++++++++++++++++++++++++++++++++---------- lisp/+browse-url.el | 117 +++++++++++++++++++++++++++++++++++++++++++++ lisp/+elfeed.el | 24 ++++++++++ lisp/+emacs.el | 1 - lisp/+key.el | 14 ++++-- lisp/+modeline.el | 8 ++++ lisp/+org.el | 55 ++++++++++++++++++++++ lisp/+util.el | 8 ++++ 8 files changed, 332 insertions(+), 28 deletions(-) create mode 100644 lisp/+browse-url.el create mode 100644 lisp/+elfeed.el diff --git a/init.el b/init.el index e0cf8ae..5d756cd 100644 --- a/init.el +++ b/init.el @@ -25,8 +25,7 @@ ;; necessary for good functioning. In this block, I add extra ;; things or more "experimental" ones that might not belong in a ;; separate file. - (:global "M-o" 'other-buffer - "C-x C-k" 'kill-this-buffer) + (:global "C-x C-k" 'kill-this-buffer) ;; 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-?)) @@ -39,7 +38,7 @@ (:hook '+init-add-setup-to-imenu)) (setup (:require +key) - (+key-global-mode +1)) + (+key-setup)) (setup (:require auth-source) (:option auth-sources (list (private/ "authinfo") @@ -51,7 +50,8 @@ (:also-load +pulse) (:option pulse-flag nil pulse-delay 0.5 - pulse-iterations 1) + pulse-iterations 1 + (append +pulse-location-commands) 'lui-track-jump-to-indicator) (+pulse-location-mode +1)) (setup calendar @@ -168,7 +168,7 @@ (setup (:straight anzu) (:option anzu-cons-mode-line-p nil) (:+key [remap query-replace] 'anzu-query-replace-regexp - [remap query-replace-regexp] 'anzu-query-replace-regexp) + [remap query-replace-regexp] 'anzu-query-replace-regexp) (global-anzu-mode +1) (:bind-into isearch [remap isearch-query-replace] @@ -206,8 +206,8 @@ (circadian-setup)) (setup (:straight circe) - (:require _circe) - (:require +circe) + (:require _circe + +circe) (autoload '+irc "+circe" "Connect to IRC." t) ;; Formatting options @@ -315,7 +315,7 @@ ("C-M-#" . consult-register) ;; Other custom bindings ("M-y" . consult-yank-pop) - (" a" . consult-apropos) + (" a" . consult-apropos) ;; M-g bindings (goto-map) ("M-g e" . consult-compile-error) ("M-g f" . consult-flymake) ; or consult-flycheck @@ -339,7 +339,7 @@ ("M-s u" . consult-focus-lines) ;; Isearch integration ("M-s e" . consult-isearch-history))) - (global-set-key (kbd (car binding)) (cdr binding))) + (define-key +key-mode-map (kbd (car binding)) (cdr binding))) (with-eval-after-load 'isearch-mode (dolist (binding '(("M-e" . consult-isearch-history) ("M-s e" . consult-isearch-history) @@ -370,8 +370,8 @@ (setup (:straight crux) (:+key "C-o" 'crux-smart-open-line - "M-o" 'crux-other-window-or-switch-buffer - "C-x 4 t" 'crux-transpose-windows) + "M-o" 'crux-other-window-or-switch-buffer + "C-x 4 t" 'crux-transpose-windows) (el-patch-feature crux) (with-eval-after-load 'crux @@ -419,8 +419,8 @@ See also `crux-reopen-as-root-mode'." (setup (:straight embark) (:option prefix-help-command 'embark-prefix-help-command) (:+key "C-." 'embark-act - "M-." 'embark-dwim - " B" 'embark-bindings)) + "M-." 'embark-dwim + " B" 'embark-bindings)) (setup (:straight embark-consult) (:load-after consult embark) @@ -461,10 +461,12 @@ See also `crux-reopen-as-root-mode'." (gcmh-mode +1)) (setup (:straight helpful) - (:+key " f" 'helpful-callable - " v" 'helpful-variable - " k" 'helpful-key - "C-c C-d" 'helpful-at-point)) + (run-with-idle-timer 0.5 nil + 'require 'helpful) + (:+key " f" 'helpful-callable + " v" 'helpful-variable + " k" 'helpful-key + "C-c C-d" 'helpful-at-point)) (setup (:straight (hippie-completing-read :host github @@ -531,7 +533,7 @@ See also `crux-reopen-as-root-mode'." (setup (:straight mwim) (:+key "C-a" #'mwim-beginning - "C-e" #'mwim-end)) + "C-e" #'mwim-end)) (setup (:straight orderless) (:option completion-styles '(orderless))) @@ -589,6 +591,7 @@ See also `crux-reopen-as-root-mode'." org-log-into-drawer t org-outline-path-complete-in-steps nil org-pretty-entities t + org-pretty-entities-include-sub-superscripts nil org-refile-use-outline-path 'file org-special-ctrl-a/e t org-special-ctrl-k t @@ -666,6 +669,7 @@ See also `crux-reopen-as-root-mode'." +modeline-vc simple-modeline-segment-misc-info simple-modeline-segment-process + +modeline-text-scale +modeline-narrowed +modeline-minions +modeline-major-mode))) @@ -719,7 +723,7 @@ See also `crux-reopen-as-root-mode'." (setup (:straight undo-fu) (:+key "C-/" #'undo-fu-only-undo - "C-?" #'undo-fu-only-redo)) + "C-?" #'undo-fu-only-redo)) (setup (:straight undo-fu-session) (:option undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" @@ -730,7 +734,8 @@ See also `crux-reopen-as-root-mode'." (setup (:straight (unfill :host github :repo "purcell/unfill" :fork (:host github :repo "duckwork/unfill"))) - (:+key "M-q" #'unfill-toggle)) + (:bind-into text-mode + "M-q" #'unfill-toggle)) (setup (:straight (vertico :host github @@ -765,7 +770,87 @@ See also `crux-reopen-as-root-mode'." (setup (:straight zzz-to-char) (:+key "M-z" (lambda (prefix) - "Call `zzz-to-char' or `zzz-up-to-char' with PREFIX arg." - (interactive "P") - (call-interactively - (if prefix #'zzz-up-to-char #'zzz-to-char))))) + "Call `zzz-to-char' or `zzz-up-to-char' with PREFIX arg." + (interactive "P") + (call-interactively + (if prefix #'zzz-up-to-char #'zzz-to-char))))) + +(setup (:straight elfeed) + (:also-load +elfeed) + (:option elfeed-use-curl t + elfeed-curl-extra-arguments '("--insecure") + elfeed-show-unique-buffers t + elfeed-db-directory (sync/ "elfeed/db/" t)) + (:with-mode elfeed-show-mode + (:bind "SPC" '+elfeed-scroll-up-command + "S-SPC" '+elfeed-scroll-down-command))) + +(setup (:straight elfeed-org) + (:option rmh-elfeed-org-files (list (sync/ "elfeed/elfeed.org" t))) + (elfeed-org)) + +(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)) + + +(setup browse-url + (:also-load +browse-url) + (:option browse-url-secondary-browser-function (if (executable-find "firefox") + 'browse-url-firefox + 'browse-url-default-browser) + browse-url-new-window-flag nil + browse-url-firefox-arguments '("--new-tab") + browse-url-firefox-new-window-is-tab t) + ;; Set up URL handlers. + (+browse-url-set-handlers + (list + (cons (rx ; images + "." (or "jpeg" "jpg" "png") eos) + (lambda (&rest args) + (apply + (cond ((executable-find "feh") '+browse-url-with-feh) + ((executable-find "mpv") '+browse-image-with-mpv) + (t 'eww-browse-url)) + args))) + (cons (rx ; videos + (or "youtube.com" "youtu.be" "yewtu.be" + (seq "." (or "mp4" "gif" "mov" "MOV") eos))) + (lambda (&rest args) + (apply (if (executable-find "mpv") + 'browse-url-mpv + browse-url-secondary-browser-function) + args))) + (cons (rx ; non-eww-friendly websites + (or + "github.com" + "gitlab.com" + "google.com" + "imgur.com" + "pixelfed" + "reddit.com" + "taskiq" + "twitter.com" + )) + browse-url-secondary-browser-function) + (cons "." ; everything else + 'eww-browse-url))) + ;; Transform URLs before passing to `browse-url' + (:option +browse-url-transformations `((,(rx "//" (or "youtube.com" + "youtu.be")) + . "//yewtu.be"))) + (+browse-url-transform-url-global-mode +1)) + +(setup (:straight-when pdf-tools + (eq system-type 'gnu/linux)) + (pdf-tools-install)) diff --git a/lisp/+browse-url.el b/lisp/+browse-url.el new file mode 100644 index 0000000..fad0826 --- /dev/null +++ b/lisp/+browse-url.el @@ -0,0 +1,117 @@ +;;; +browse-url.el -*- lexical-binding: t; -*- + +;;; Code: + +(require 'cl-lib) + +(defgroup +browse-url nil + "Group for my `browse-url' extras." + :group 'browse-url) + +;;; URL Handlers + +(defun +browse-url-set-handlers (handlers) + "Set handlers for `browse-url'. +Set `browse-url-handlers', if they exist; else +`browse-url-browser-function'. The reason for this switch is +that the latter is deprecated in Emacs 28+." + (set-default (if (boundp 'browse-url-handlers) + 'browse-url-handlers + 'browse-url-browser-function) + handlers)) + +(cl-defmacro +browse-url-make-external-viewer-handler + (viewer default-args &optional (prompt "URL: ") + &key + (custom-group '+browse-url) + (name (format "+browse-url-with-%s" viewer))) + "Create a `browse-url' handler function that calls VIEWER on the url. +Also create a `customize' setting in CUSTOM-GROUP for VIEWER's +arguments. DEFAULT-ARGS specifies the default arguments that +setting should have. PROMPT will be shown to user in the +function's `interactive' spec, as an argument to +`browse-url-interactive-arg'. The resulting function will be +named NAME, defaulting to \"+browse-url-with-VIEWER\", and the variable +\"NAME-args\"." + (declare (indent 1)) + `(progn + (defcustom ,(intern (format "%s-args" name)) + ,default-args + ,(format "Arguments to pass to %s in `%s'." viewer name) + :type '(repeat :tag "Command-line argument" string) + :group ',custom-group) + (defun ,(intern name) (url &optional _new-window) + ,(format "Open URL in %s." viewer) + (interactive (browse-url-interactive-arg ,prompt)) + (let* ((url (browse-url-encode-url url)) + (process-environment (browse-url-process-environment))) + (message ,(format "Opening %%s in %s..." viewer) url) + (apply #'start-process + (concat ,viewer " " url) nil + ,viewer + (append ,(intern (format "%s-args" name)) (list url))))))) + +;; Reference implementation: mpv +(+browse-url-make-external-viewer-handler "mpv" nil "Video URL: ") +;; And feh too +(+browse-url-make-external-viewer-handler "feh" '("--auto-zoom" + "--geometry" "800x600")) +;; And ... mpv, but for images +(+browse-url-make-external-viewer-handler "mpv" + '("--image-display-duration=inf") + "Image URL: " + :name "+browse-image-with-mpv") + +;;; URL Transformation Functions +;; There's a lot of bad websites out there. Luckily we can easily redirect +;; requests to more privacy-respecting, or just less javascript-ridden, sites +;; using some basic regex magic. Inspired by add-ons like +;; https://einaregilsson.com/redirector/. + +(defcustom +browse-url-transformations nil + "Transformation rules for various URLs. +This is an alist, the keys of which are regexen to match URLs +against, and the values are how to transform them. Match capture +data will be used in the transformations." + :type + '(alist :key-type (string :tag "URL regex match") + :value-type (string :tag "URL regex transformation")) + :group '+browse-url) + +(defun +browse-url-transform-advice (url &rest args) + "ADVICE to transform URL for later opening by `browse-url'. +ARGS are ignored here, but passed on for later processing." + ;; Basically, loop through `+browse-url-transformations' until finding a CAR + ;; that matches the URL. If one is found, transform it using `replace-match' + ;; with the CDR of that cell, or if one isn't, just pass the URL unchanged, + ;; along with the rest of the args, in a list to the original caller (probably + ;; `browse-url'.) + (apply 'list + (cl-loop with url = (substring-no-properties + (if (consp url) (car url) url)) + for (regex . transformation) in +browse-url-transformations + if (string-match regex url) + return (replace-match transformation nil nil url) + ;; else + finally return url) + args)) + +(define-minor-mode +browse-url-transform-url-mode + "Minor mode to transform a URL before passing it to `browse-url'. +This can be used to \"redirect\" URLs, for example from an +information silo to a more privacy-respecting one (e.g., +\"twitter.com\" -> \"nitter.com\"), by adding advice to `browse-url'. + +When using this mode, ensure that the transformed URL is also in +`browse-url-handlers', since that's what `browse-url' will see." + :lighter " Xurl" + :keymap nil + (if +browse-url-transform-url-mode + (advice-add 'browse-url :filter-args '+browse-url-transform-advice) + (advice-remove 'browse-url '+browse-url-transform-advice))) + +(define-global-minor-mode +browse-url-transform-url-global-mode + +browse-url-transform-url-mode +browse-url-transform-url-mode) + +(provide '+browse-url) +;;; +browse-url.el ends here diff --git a/lisp/+elfeed.el b/lisp/+elfeed.el new file mode 100644 index 0000000..823902b --- /dev/null +++ b/lisp/+elfeed.el @@ -0,0 +1,24 @@ +;;; +elfeed.el -*- lexical-binding: t; -*- + +;;; Code: + +(require 'elfeed) + +(defun +elfeed-scroll-up-command (&optional arg) + "Scroll up or go to next feed item in Elfeed" + (interactive "^P") + (let ((scroll-error-top-bottom nil)) + (condition-case-unless-debug nil + (scroll-up-command arg) + (error (elfeed-show-next))))) + +(defun +elfeed-scroll-down-command (&optional arg) + "Scroll up or go to next feed item in Elfeed" + (interactive "^P") + (let ((scroll-error-top-bottom nil)) + (condition-case-unless-debug nil + (scroll-down-command arg) + (error (elfeed-show-prev))))) + +(provide '+elfeed) +;;; +elfeed.el ends here diff --git a/lisp/+emacs.el b/lisp/+emacs.el index 147bb76..a858cf6 100644 --- a/lisp/+emacs.el +++ b/lisp/+emacs.el @@ -69,7 +69,6 @@ Do this only if the buffer is not visiting a file." kill-do-not-save-duplicates t kill-read-only-ok t kill-ring-max 500 - kill-whole-line t kmacro-ring-max 20 load-prefer-newer t major-mode '+set-major-mode-from-buffer-name diff --git a/lisp/+key.el b/lisp/+key.el index 5b4f467..7a51be1 100644 --- a/lisp/+key.el +++ b/lisp/+key.el @@ -14,6 +14,9 @@ ;;; Code: +(require 'easy-mmode) +(require 'setup nil t) + ;; I need to define this map before the proper mode map. (defvar +key-leader-map (let ((map (make-sparse-keymap)) (c-z (global-key-binding "\C-z"))) @@ -30,13 +33,18 @@ (define-minor-mode +key-mode "A minor mode with keybindings that will override every other mode." :init-value t - :lighter " +" - :keymap +key-mode-map) + :lighter " +") +(add-to-list 'emulation-mode-map-alists `((+key-mode . ,+key-mode-map))) ;;;###autoload (define-globalized-minor-mode +key-global-mode +key-mode +key-mode) -(add-to-list 'emulation-mode-map-alists `((+key-mode . ,+key-mode-map))) +;;;###autoload +(defun +key-setup () + "Setup `+key-mode' after everything else." + (if after-init-time + (+key-global-mode +1) + (add-hook 'after-init-hook '+key-global-mode))) (defun turn-off-+key-mode () "Turn off `+key-mode'." diff --git a/lisp/+modeline.el b/lisp/+modeline.el index 0dc34c7..7c74f76 100644 --- a/lisp/+modeline.el +++ b/lisp/+modeline.el @@ -153,5 +153,13 @@ The order of elements matters: whichever one matches first is applied." "Display `anzu--update-mode-line'." (concat " " (anzu--update-mode-line))) +(defun +modeline-text-scale () + "Display text scaling level." + ;; adapted from https://github.com/seagle0128/doom-modeline + (when (and (boundp 'text-scale-mode-amount) + (/= text-scale-mode-amount 0)) + (format (if (> text-scale-mode-amount 0) " (%+d)" " (%-d)") + text-scale-mode-amount))) + (provide '+modeline) ;;; +modeline.el ends here diff --git a/lisp/+org.el b/lisp/+org.el index a4ce230..9a91ef1 100644 --- a/lisp/+org.el +++ b/lisp/+org.el @@ -337,5 +337,60 @@ the deletion might narrow the column." (backward-delete-char-untabify N) (org-fix-tags-on-the-fly)))) +;;; Smarter {super,sub}scripts +;; https://old.reddit.com/r/emacs/comments/qzlzm0/what_are_your_top_key_bindings_rebindings_minor/hmwyhm3/ +;; I don't use this currently because I found out about +;; `org-pretty-entities-include-sub-superscripts', which really does exactly +;; what I wanted. + +(defface +org-script-markers '((t :inherit shadow)) + "Face to be used for sub/superscripts markers i.e., ^, _, {, }.") + +;; Hiding the super and subscript markers is extremely annoying +;; since any remotely complex equation becomes a chore. And leaving +;; it not raised is jarring to the eye. So this fontifies the +;; buffer just like how auctex does -- use a muted colour to +;; highlight the markup and raise the script. +(defun +org-raise-scripts (limit) + "Differences from `org-raise-scripts' are: + +- It doesn't actually hide the markup used for super and subscript. +- It uses a custom face to highlight the markup: +org-script-markers. +- It doesn't require `org-pretty-entities' to be t." + (when (and org-pretty-entities-include-sub-superscripts + (re-search-forward + (if (eq org-use-sub-superscripts t) + org-match-substring-regexp + org-match-substring-with-braces-regexp) + limit t)) + (let* ((pos (point)) table-p comment-p + (mpos (match-beginning 3)) + (emph-p (get-text-property mpos 'org-emphasis)) + (link-p (get-text-property mpos 'mouse-face)) + (keyw-p (eq 'org-special-keyword (get-text-property mpos 'face)))) + (goto-char (point-at-bol)) + (setq table-p (looking-at-p org-table-dataline-regexp) + comment-p (looking-at-p "^[ \t]*#[ +]")) + (goto-char pos) + ;; Handle a_b^c + (when (member (char-after) '(?_ ?^)) (goto-char (1- pos))) + (unless (or comment-p emph-p link-p keyw-p) + (put-text-property (match-beginning 3) (match-end 0) + 'display + (if (equal (char-after (match-beginning 2)) ?^) + ;; (nth (if table-p 3 1) org-script-display) + (nth 3 org-script-display) + ;; (nth (if table-p 2 0) org-script-display) + (nth 2 org-script-display))) + (put-text-property (match-beginning 2) (match-end 2) + 'face 'vz/org-script-markers) + (when (and (eq (char-after (match-beginning 3)) ?{) + (eq (char-before (match-end 3)) ?})) + (put-text-property (match-beginning 3) (1+ (match-beginning 3)) + 'face '+org-script-markers) + (put-text-property (1- (match-end 3)) (match-end 3) + 'face '+org-script-markers))) + t))) + (provide '+org) ;;; +org.el ends here diff --git a/lisp/+util.el b/lisp/+util.el index 0184a48..fb77278 100644 --- a/lisp/+util.el +++ b/lisp/+util.el @@ -79,6 +79,14 @@ ALIGNMENT can be one of these: ;;; COMMANDS +(defun +dos2unix (buffer) + "Replace \r\n with \n in BUFFER." + (interactive "*b") + (save-excursion + (with-current-buffer buffer + (goto-char (point-min)) + (while (search-forward (string ?\C-m ?\C-j) nil t) + (replace-match (string ?\C-j) nil t))))) (provide '+util) ;;; +util.el ends here -- cgit 1.4.1-21-gabe81