From ca4799e52463271168f7ffda16f9da7918c1c314 Mon Sep 17 00:00:00 2001 From: Howard Abrams Date: Fri, 1 Mar 2024 19:30:31 -0800 Subject: [PATCH] Migrating my local leader key to major-mode-hydra Seems that the leader has a bug when it comes to local mode maps, and the major-mode hydra is an attractive alternative. Granted, I do feel the need to group things for the tabular view, but that isn't a bad thing. Need to take a pass at my more-complex code in my programming stuff. --- ha-applications.org | 59 ++++++++++++++++++++++---------- ha-aux-apps.org | 56 +++++++++++++++++++------------ ha-config.org | 12 +++++-- ha-email.org | 63 ++++++++++++++++++---------------- ha-evil.org | 4 +++ ha-feed-reader.org | 82 +++++++++++++++++++++++++-------------------- ha-general.org | 4 +-- ha-irc.org | 12 ++++--- 8 files changed, 176 insertions(+), 116 deletions(-) diff --git a/ha-applications.org b/ha-applications.org index 343df39..1eafed7 100644 --- a/ha-applications.org +++ b/ha-applications.org @@ -385,15 +385,43 @@ Web pages look pretty good with EWW, but I'm having difficulty getting it to ren :config (ha-leader "a b" '("eww browser" . eww)) + (defun ha-eww-save-off-window (name) + (interactive (list (read-string "Name: " (plist-get eww-data :title)))) + (rename-buffer (format "*eww: %s*" name) t)) + + (major-mode-hydra-define eww-mode nil + ("Browser" + (("G" eww-browse "Browse") + ("B" eww-list-bookmarks "Bookmarks") + ("q" bury-buffer "Quit")) + "History" + (("l" eww-back-url "Back" :color pink) + ("r" eww-forward-url "Forward" :color pink) + ("H" eww-list-histories "History")) + "Current Page" + (("b" eww-add-bookmark "Bookmark") + ("g" link-hint-open-link "Jump Link") + ("d" eww-download "Download")) + "Render Page" + (("e" eww-browse-with-external-browser "Open in Firefox") + ("R" eww-readable "Reader Mode") + ("y" eww-copy-page-url "Copy URL")) + "Navigation" + (("u" eww-top-url "Site Top") + ("n" eww-next-url "Next Page") + ("p" eww-previous-url "Previous")) + "Toggles" + (("c" eww-toggle-colors "Colors") + ("i" eww-toggle-images "Images") + ("f" eww-toggle-fonts "Fonts")) + "Misc" + (("s" ha-eww-save-off-window "Rename") + ("S" eww-switch-to-buffer "Switch to") + ("-" eww-write-bookmarks "Save Bookmarks") + ("M" eww-read-bookmarks "Load Bookmarks")))) + :general (:states 'normal :keymaps 'eww-mode-map - "B" 'eww-list-bookmarks - "Y" 'eww-copy-page-url - "H" 'eww-back-url - "L" 'eww-forward-url - "u" 'eww-top-url - "p" 'eww-previous-url - "n" 'eww-next-url "q" 'bury-buffer) (:states 'normal :keymaps 'eww-buffers-mode-map "q" 'bury-buffer)) @@ -662,17 +690,12 @@ I’d like write notes in org files that link to the PDFs (and maybe visa versa) #+begin_src emacs-lisp (use-package org-noter :config - (ha-leader "o N" '("pdf notes" . org-noter)) - (ha-local-leader - :keymaps 'org-noter-doc-mode-map - "n" '("pdf notes" . org-noter) - - ;; This means that I can stay in normal mode: - :keymaps 'org-noter-notes-mode-map - "i" '("insert note" . org-noter-insert-note) - "s" '("sync note" . org-noter-sync-current-note) - "n" '("next note" . org-noter-sync-next-note) - "p" '("previous note" . org-noter-sync-prev-note))) + (major-mode-hydra-define org-noter-doc-mode-map nil + ("Notes" + (("i" org-noter-insert-note "insert note") + ("s" org-noter-sync-current-note "sync note") + ("n" org-noter-sync-next-note "next note" :color pink) + ("p" org-noter-sync-prev-note "previous note" :color pink))))) #+end_src To use, open a header in an org doc, and run =M-x org-noter= (~SPC o N~) and select the PDF. The =org-noter= function can be called in the PDF doc as well. In Emacs state, type ~i~ to insert a note /as a header/, or in Normal state, type ~, i~. diff --git a/ha-aux-apps.org b/ha-aux-apps.org index e5ca580..b9dae03 100644 --- a/ha-aux-apps.org +++ b/ha-aux-apps.org @@ -47,20 +47,42 @@ I would like a dedicate perspective to Mastodon, and I would like a leader key s (persp-names) "mastodon" 'equal))) (persp-switch "mastodon") (unless already-tooted? - (ha-local-leader :keymaps 'mastodon-mode-map - ;; "," '("thread" . mastodon-tl--thread) - "t" '("toot" . mastodon-toot) - "u" '("update" . mastodon-tl--update) - "f" '("favorite" . mastodon-toot--toggle-favourite) - "b" '("boost" . mastodon-toot--toggle-boost) - "r" '("reply" . mastodon-toot--reply) - "s" '("share" . mastodon-toot--copy-toot-url) - "y" '("copy text" . mastodon-toot--copy-toot-text) - "d" '("discover" . mastodon-discover)) - (my-mastodon-start)))) + (mastodon)))) (ha-leader - "a m" '("mastodon" . mastodon-perspective))) + "a m" '("mastodon" . mastodon-perspective)) + + (use-package major-mode-hydra + :config + (major-mode-hydra-define mastodon-mode nil + ("Timelines" + (("u" mastodon-tl--update "update") + ("F" mastodon-tl--get-federated-timeline "Federated") + ("H" mastodon-tl--get-home-timeline "Home") + ("L" mastodon-tl--get-local-timeline "Local") + ("T" mastodon-tl--get-tag-timeline "Hashtag")) + "Specials" + (("M" mastodon-notifications--get-mentions "Mentions") + ("N" mastodon-notifications-get "Notifications") + ("A" mastodon-tl--followed-tags-timeline "All Tags") + ("S" mastodon-profile--view-bookmarks "Saved bookmarks") + ("O" mastodon-profile--my-profile "My Profile")) + "Post" + (("c" mastodon-toot "Compose toot") + ("e" mastodon-toot--edit-toot-at-point "Edit toot") + ("t" mastodon-tl--thread "Read thread") + ("r" mastodon-toot--reply "Reply") + ("m" mastodon-tl--dm-user "Direct Msg") + ("d" mastodon-toot--delete-toot "Delete")) + "Toot" + (("f" mastodon-toot--toggle-favourite "Favorite") + ("b" mastodon-toot--toggle-boost "Boost") + ("s" mastodon-toot--toggle-bookmark "Save") + ("y" mastodon-toot--copy-toot-url "Copy URL") + ("Y" mastodon-toot--copy-toot-text "Copy text")) + "Navigation" + (("n" mastodon-tl--next-tab-item "next" :color pink) + ("p" mastodon-tl--previous-tab-item "previous" :color pink)))))) #+end_src Let’s turn on non-fixed-width fonts to make everything easier to read: @@ -68,16 +90,6 @@ Let’s turn on non-fixed-width fonts to make everything easier to read: (use-package mastodon :hook (mastodon-mode . mixed-pitch-mode)) #+end_src -Starting the =mastodon= perspective, I set some initial windows: -#+begin_src emacs-lisp - (defun my-mastodon-start () - "Configure the window placement for a Mastodon Instance." - (let ((default-directory (getenv "HOME"))) - (mastodon) - (switch-to-buffer "*mastodon-home*") - (split-window-right) - (mastodon-tl--get-local-timeline) - (switch-to-buffer "*mastodon-local*"))) #+end_src ** Matrix/Element Yet another encrypted chat/VoIP client-server, but unlike Signal and Telegram, [[matrix.org][Matrix]] is act ually open source. In other words, a project for nerds. We’ll be using Alphapapa’s latest [[https://github.c om/alphapapa/ement.el][ement]] project. diff --git a/ha-config.org b/ha-config.org index e2d3a2b..58e5d82 100644 --- a/ha-config.org +++ b/ha-config.org @@ -298,9 +298,15 @@ Pressing the ~SPACE~ can activate a /leader key sequence/ I define in my [[file: #+begin_src emacs-lisp (ha-hamacs-load "ha-general.org") #+end_src -*Note:* This code extends the =use-package= to include a =:general= keybinding section, that I use elsewhere, so I need to pull it in now. -** Text Completion Packages -*** Auto Completion +This extends the =use-package= to include a =:general= keybinding section. + +Since I seldom remember keybindings, or even function names, for major-modes, I pull them all together into a nice table using the [[https://github.com/jerrypnz/major-mode-hydra.el][Major Mode Hydra]] project: +#+begin_src emacs-lisp + (use-package major-mode-hydra + :config + (global-set-key (kbd "s-,") #'major-mode-hydra)) +#+end_src +** Additional Global Packages The following defines my use of the Emacs completion system. I’ve decided my /rules/ will be: - Nothing should automatically appear; that is annoying and distracting. - Spelling in org files (abbrev or hippie expander) and code completion are separate, but I’m not sure if I can split them diff --git a/ha-email.org b/ha-email.org index b790961..f99c55e 100644 --- a/ha-email.org +++ b/ha-email.org @@ -102,15 +102,17 @@ And some leader-based keybindings: (use-package notmuch :config (ha-leader ; Should I put these under an "m" heading? - "a n" '("new mail" . notmuch-retrieve-messages) + "a e" '("new mail" . notmuch-retrieve-messages) "a m" '("read mail" . notmuch) "a c" '("compose mail" . compose-mail)) - (ha-local-leader :keymaps 'notmuch-hello-mode-map - "u" '("new mail" . notmuch-retrieve-messages) - "m" '("read mail" . notmuch) - "c" '("compose" . notmuch-mua-new-mail) - "C" '("reply-later" . hey-notmuch-reply-later)) + (major-mode-hydra-define notmuch-hello-mode nil + ("Mail" + (("u" notmuch-retrieve-messages "new mail") + ("m" notmuch "read mail")) + "Messages" + (("c" notmuch-mua-new-mail "compose") + ("C" hey-notmuch-reply-later "reply-later")))) <> <>) @@ -643,9 +645,10 @@ This means: A series of keybindings to quickly send messages to one of the pre-defined buckets. #+NAME: hey-show-keybindings #+begin_src emacs-lisp :tangle no - (ha-local-leader :keymaps 'notmuch-show-mode-map - "c" '("compose" . notmuch-mua-new-mail) - "C" '("reply-later" . hey-notmuch-reply-later)) + (major-mode-hydra-define notmuch-show-mode nil + ("Messages" + (("c" notmuch-mua-new-mail "compose") + ("C" hey-notmuch-reply-later "reply-later")))) (define-key notmuch-show-mode-map (kbd "C") 'hey-notmuch-reply-later) #+end_src @@ -654,23 +657,26 @@ The bindings in =notmuch-search-mode= are available when looking at a list of me #+NAME: hey-search-keybindings #+begin_src emacs-lisp :tangle no - (ha-local-leader :keymaps 'notmuch-search-mode-map - "r" '("reply" . notmuch-search-reply-to-thread) - "R" '("reply-all" . notmuch-search-reply-to-thread-sender) - "/" '("search" . notmuch-search-filter) - "A" '("archive all" . hey-notmuch-archive-all) - "D" '("delete all" . hey-notmuch-delete-all) - "L" '("filter by from" . hey-notmuch-filter-by-from) - ";" '("search by from" . hey-notmuch-search-by-from) - "d" '("delete thread" . hey-notmuch-search-delete-and-archive-thread) - - "s" '("send to spam" . hey-notmuch-move-sender-to-spam) - "i" '("send to screened" . hey-notmuch-move-sender-to-screened) - "p" '("send to papertrail" . hey-notmuch-move-sender-to-papertrail) - "f" '("send to feed" . hey-notmuch-move-sender-to-thefeed) - "C" '("reply" . hey-notmuch-reply-later) - "c" '("compose" . notmuch-mua-new-mail)) + (major-mode-hydra-define notmuch-search-mode nil + ("Mail" + (("r" notmuch-search-reply-to-thread "reply") + ("R" notmuch-search-reply-to-thread-sender "reply-all") + ("A" hey-notmuch-archive-all "archive all") + ("D" hey-notmuch-delete-all "delete all") + ("d" hey-notmuch-search-delete-and-archive-thread "delete thread")) + "Search" + (("/" notmuch-search-filter "search") + ("L" hey-notmuch-filter-by-from "filter by from") + (";" hey-notmuch-search-by-from "search by from")) + "Messages" + (("s" hey-notmuch-move-sender-to-spam "send to spam") + ("i" hey-notmuch-move-sender-to-screened "send to screened") + ("p" hey-notmuch-move-sender-to-papertrail "send to papertrail") + ("f" hey-notmuch-move-sender-to-thefeed "send to feed") + ("C" hey-notmuch-reply-later "reply") + ("c" notmuch-mua-new-mail) "compose"))) + ;; And if I can remember the keybindings... (define-key notmuch-search-mode-map (kbd "r") 'notmuch-search-reply-to-thread) (define-key notmuch-search-mode-map (kbd "R") 'notmuch-search-reply-to-thread-sender) (define-key notmuch-search-mode-map (kbd "/") 'notmuch-search-filter) @@ -691,9 +697,10 @@ The gods ordained that Mail and Org should dance together, so step one is compos #+begin_src emacs-lisp (use-package org-mime :config - (ha-local-leader :keymaps 'notmuch-message-mode-map - "s" '("send" . notmuch-mua-send-and-exit) - "m" '("mime it" . org-mime-htmlize))) + (major-mode-hydra-define notmuch-message-mode nil + ("Messages" + (("s" notmuch-mua-send-and-exit "send") + ("m" org-mime-htmlize "mime it"))))) #+end_src A new option is to use [[https://github.com/jeremy-compostella/org-msg][org-msg]], so let's try it: #+begin_src emacs-lisp :noweb yes diff --git a/ha-evil.org b/ha-evil.org index dfa16ec..360b85f 100644 --- a/ha-evil.org +++ b/ha-evil.org @@ -75,6 +75,10 @@ The Escape key act like ~C-g~ and always go back to normal mode? (use-package evil :config (global-set-key (kbd "") 'keyboard-escape-quit) + + ;; Let's connect my major-mode-hydra to a global keybinding: + (evil-define-key 'normal 'global "," 'major-mode-hydra) + (evil-mode)) #+end_src diff --git a/ha-feed-reader.org b/ha-feed-reader.org index 36abc05..7497291 100644 --- a/ha-feed-reader.org +++ b/ha-feed-reader.org @@ -29,28 +29,46 @@ Let's get our feeds from a collection of org mode files. By default, Doom config #+begin_src emacs-lisp (use-package elfeed - :init + :config ;; While I would like to share the /status/ of my reads, so ... (setq elfeed-db-directory "~/dropbox/.elfeed/") + ;; Let's limit what is initially displayed, and then expand it: + (setq elfeed-search-filter "@6-months-ago +unread -science -funny") + ;; While not an elfeed-specific variable, this make reading articles ;; with images easier: (setq pixel-scroll-precision-mode t) - :general - (:states 'normal :keymaps 'elfeed-show-mode-map - "b" 'elfeed-show-visit - "n" 'elfeed-show-next - "p" 'elfeed-show-prev - "y" 'elfeed-show-yank - "q" 'kill-buffer - "o" 'link-hint-open-link ; This is why this package depends on link-hint: - "Q" 'delete-window) - (:states 'normal :keymaps 'elfeed-search-mode-map - "r" 'ha-elfeed-tag-unread - "R" 'elfeed-search-update--force - "u" 'elfeed-update - "U" 'elfeed-unjam)) + (defvar ha-elfeeds-title + (concat (all-the-icons-faicon "rss") " Feed Reader")) + + (major-mode-hydra-define elfeed-search-mode + (:title ha-elfeeds-title) + ("Feeds" + (("U" (elfeed-search-fetch 4) "Refresh Feeds") + ("u" elfeed-update "Update Screen") + ("f" elfeed-search-live-filter "Filter") + ("F" elfeed-search-clear-filter "Clear Filter") + ("X" elfeed-unjam "Unjam")) + "Entry" + (("r" elfeed-search-untag-all-unread "Mark read" :color pink) + ("R" ha-elfeed-tag-unread "Mark read/refresh") + ("y" elfeed-search-yank "Copy URL")))) + + (major-mode-hydra-define elfeed-show-mode + (:title ha-elfeeds-title) + ("Entry" + (("n" elfeed-show-next "Next Entry" :color pink) + ("p" elfeed-show-prev "Previous Entry" :color pink)) + "Read" + (("b" elfeed-show-visit "Show in EWW") + ("B" elfeed-show-visit-gui "Show in Browser") + ("y" elfeed-show-yank "Copy URL")) + "Navigation" + (("o" link-hint-open-link "Open Link") + ("q" bury-buffer "Close") + ("Q" delete-window "Close Window"))))) (defun ha-elfeed-tag-unread () (interactive) @@ -61,38 +79,28 @@ Let's get our feeds from a collection of org mode files. By default, Doom config According to Ben Maughan and [[http://pragmaticemacs.com/emacs/to-eww-or-not-to-eww/][this Pragmatic Emacs essay]], we could easily browse an article in the GUI browser instead of EWW with capital B: #+begin_src emacs-lisp - (use-package elfeed - :config - (defun elfeed-show-visit-gui () - "Wrapper for elfeed-show-visit to use gui browser instead of eww" - (interactive) - (let ((browse-url-generic-program "/usr/bin/open")) - (elfeed-show-visit t))) - - :bind (:map elfeed-show-mode-map - ("B" . elfeed-show-visit-gui))) + (defun elfeed-show-visit-gui () + "Wrapper for elfeed-show-visit to use gui browser instead of eww" + (interactive) + (let ((browse-url-generic-program "/usr/bin/open")) + (elfeed-show-visit t))) #+end_src Quick way to start and jump to my world of feeds. #+begin_src emacs-lisp - (defun ha-elfeed-persp-start () + (defun ha-elfeed-persp () "Create an ELFEED workspace and start my ELFEED client." (interactive) - (persp-switch "feeds") - (elfeed)) - - (defun ha-elfeed-persp-switch () - "Switch to the ELFEED workspace and load the next buffer." - (interactive) - (persp-switch "feeds")) + (let ((already-reading? (seq-contains-p + (persp-names) "feeds" 'equal))) + (persp-switch "feeds") + (unless already-reading? + (elfeed)))) #+end_src And some global keys to display them in the =apps= menu: - #+begin_src emacs-lisp -(ha-leader - "a f" '("elfeed switch" . ha-elfeed-persp-switch) - "a F" '("elfeed start" . ha-elfeed-persp-start)) + (ha-leader "a f" '("elfeed switch" . ha-elfeed-persp)) #+end_src * The Feeds :elfeed: The [[https://github.com/remyhonig/elfeed-org][elfeed-org]] project configures =elfeed= to read the RSS feeds from an Org file … like this one! diff --git a/ha-general.org b/ha-general.org index 09a23ef..087415c 100644 --- a/ha-general.org +++ b/ha-general.org @@ -46,9 +46,7 @@ I'm not trying an experiment where specially-placed function keys on my fancy er (general-create-definer ha-local-leader :states '(normal visual motion) - :prefix "," - :global-prefix "" - :non-normal-prefix "S-SPC") + :global-prefix "") (general-nmap "SPC m" (general-simulate-key "," :which-key "major mode"))) #+end_src diff --git a/ha-irc.org b/ha-irc.org index 588f8f6..5accab3 100644 --- a/ha-irc.org +++ b/ha-irc.org @@ -121,11 +121,13 @@ And some global keys to display them: And a quick shortcuts to call it: #+begin_src emacs-lisp - (ha-local-leader :keymaps '(erc-mode-map) - "o" '("next channel" . erc-track-switch-buffer) - "w" '("resize text" . ha-erc-resize-text) - "r" '("reconnect" . ha-erc-connect-irc) - "p" '("send password" . ha-erc-reconnect-password)) + (major-mode-hydra-define erc-mode nil + ("Server" + (("r" ha-erc-connect-irc "reconnect") + ("p" ha-erc-reconnect-password) "send password") + "Channel" + (("o" erc-track-switch-buffer "next channel") + ("w" ha-erc-resize-text "resize text")))) #+end_src * Display Configuration Using the [[https://github.com/seagle0128/doom-modeline][Doom Modeline]] to add notifications: