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)
-		     ("<help> a" . consult-apropos)
+		     ("<f1> 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
-	   "<help> B" 'embark-bindings))
+	 "M-." 'embark-dwim
+	 "<f1> 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 "<help> f" 'helpful-callable
-           "<help> v" 'helpful-variable
-           "<help> k" 'helpful-key
-           "C-c C-d" 'helpful-at-point))
+  (run-with-idle-timer 0.5 nil
+                       'require 'helpful)
+  (:+key "<f1> f" 'helpful-callable
+         "<f1> v" 'helpful-variable
+         "<f1> 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