Compare commits
17 commits
no-straigh
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
038ec85e0e | ||
|
|
3a639902a0 | ||
|
|
82ecae035c | ||
|
|
4de1b825f7 | ||
|
|
a3c3458140 | ||
|
|
468f74086c | ||
|
|
40555ea625 | ||
|
|
05e0fbae40 | ||
|
|
fe720dfddf | ||
|
|
f386570dc1 | ||
|
|
3f3febddf3 | ||
|
|
43fd32499e | ||
|
|
c1dd2a133a | ||
|
|
bc1b7a1c35 | ||
|
|
0cbcc59c27 | ||
|
|
4456224988 | ||
|
|
9a67d92054 |
31 changed files with 839 additions and 414 deletions
|
|
@ -8,6 +8,15 @@ A literate programming file for bootstraping my Emacs Configuration.
|
||||||
#+begin_src emacs-lisp :exports none
|
#+begin_src emacs-lisp :exports none
|
||||||
;;; bootstrap.el --- file for bootstraping my Emacs Configuration
|
;;; bootstrap.el --- file for bootstraping my Emacs Configuration
|
||||||
;;
|
;;
|
||||||
|
;; ██████████
|
||||||
|
;; ░░███░░░░░█
|
||||||
|
;; ░███ █ ░ █████████████ ██████ ██████ █████
|
||||||
|
;; ░██████ ░░███░░███░░███ ░░░░░███ ███░░███ ███░░
|
||||||
|
;; ░███░░█ ░███ ░███ ░███ ███████ ░███ ░░░ ░░█████
|
||||||
|
;; ░███ ░ █ ░███ ░███ ░███ ███░░███ ░███ ███ ░░░░███
|
||||||
|
;; ██████████ █████░███ █████░░████████░░██████ ██████
|
||||||
|
;; ░░░░░░░░░░ ░░░░░ ░░░ ░░░░░ ░░░░░░░░ ░░░░░░ ░░░░░░
|
||||||
|
|
||||||
;; © 2021-2023 Howard X. Abrams
|
;; © 2021-2023 Howard X. Abrams
|
||||||
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||||
;; See http://creativecommons.org/licenses/by/4.0/
|
;; See http://creativecommons.org/licenses/by/4.0/
|
||||||
|
|
@ -27,6 +36,8 @@ A literate programming file for bootstraping my Emacs Configuration.
|
||||||
* Introduction
|
* Introduction
|
||||||
This file contains all the variable definitions and library loading for the other files in my project.
|
This file contains all the variable definitions and library loading for the other files in my project.
|
||||||
|
|
||||||
|
I'm installing everything using the [[https://github.com/raxod502/straight.el#getting-started][straight.el]] for package installation and management. This is initialization code configured in [[file:initialize][initialize]], and calls to =use-package= now accepts a =:straight= parameter that allows me to retrieve special versions of some packages.
|
||||||
|
|
||||||
See the details in [[https://dev.to/jkreeftmeijer/emacs-package-management-with-straight-el-and-use-package-3oc8][this essay]].
|
See the details in [[https://dev.to/jkreeftmeijer/emacs-package-management-with-straight-el-and-use-package-3oc8][this essay]].
|
||||||
|
|
||||||
* Initial Settings
|
* Initial Settings
|
||||||
|
|
@ -96,7 +107,7 @@ Getting tired off all the packages that I load spewing a bunch of warnings that
|
||||||
The following packages come with Emacs, but seems like they still need loading:
|
The following packages come with Emacs, but seems like they still need loading:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package cl-lib
|
(use-package cl-lib
|
||||||
|
:straight (:type built-in)
|
||||||
:init (defun first (elt) (car elt))
|
:init (defun first (elt) (car elt))
|
||||||
:commands (first))
|
:commands (first))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,8 @@ A literate programming file configuring critical applications.
|
||||||
Can we call the following /applications/? I guess.
|
Can we call the following /applications/? I guess.
|
||||||
* Git and Magit
|
* Git and Magit
|
||||||
Can not live without [[https://magit.vc/][Magit]], a Git porcelain for Emacs. I stole the bulk of this work from Doom Emacs.
|
Can not live without [[https://magit.vc/][Magit]], a Git porcelain for Emacs. I stole the bulk of this work from Doom Emacs.
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package magit)
|
|
||||||
(use-package magit
|
(use-package magit
|
||||||
:load-path "~/.emacs.d/repos/magit"
|
|
||||||
;; See https://github.com/magit/magit/wiki/Emacsclient for why we need to set:
|
;; See https://github.com/magit/magit/wiki/Emacsclient for why we need to set:
|
||||||
:custom (with-editor-emacsclient-executable "emacsclient")
|
:custom (with-editor-emacsclient-executable "emacsclient")
|
||||||
|
|
||||||
|
|
@ -90,7 +87,7 @@ Can not live without [[https://magit.vc/][Magit]], a Git porcelain for Emacs. I
|
||||||
** VC Diff Highlight
|
** VC Diff Highlight
|
||||||
The [[https://github.com/dgutov/diff-hl][diff-hl project]], while more active, has more features than the [[https://github.com/syohex/emacs-git-gutter-fringe][git-gutter-fringe]] project.
|
The [[https://github.com/dgutov/diff-hl][diff-hl project]], while more active, has more features than the [[https://github.com/syohex/emacs-git-gutter-fringe][git-gutter-fringe]] project.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package diff-hl
|
(use-package diff-hl
|
||||||
:custom
|
:custom
|
||||||
(diff-hl-side 'right)
|
(diff-hl-side 'right)
|
||||||
|
|
@ -103,7 +100,7 @@ The [[https://github.com/dgutov/diff-hl][diff-hl project]], while more active, h
|
||||||
|
|
||||||
Turning on the mode, as well as binding some new /leader/ keys:
|
Turning on the mode, as well as binding some new /leader/ keys:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package diff-hl
|
(use-package diff-hl
|
||||||
:config
|
:config
|
||||||
(global-diff-hl-mode)
|
(global-diff-hl-mode)
|
||||||
|
|
@ -124,7 +121,7 @@ Turning on the mode, as well as binding some new /leader/ keys:
|
||||||
|
|
||||||
This project (and others) can use repeat mode, but
|
This project (and others) can use repeat mode, but
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+BEGIN_SRC emacs-lisp
|
||||||
(repeat-mode)
|
(repeat-mode)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
|
@ -217,7 +214,7 @@ The crucial parts of this helper function are that we "wash" the result using =a
|
||||||
The functions below depend on [[help:magit-thing-at-point][magit-thing-at-point]], and this depends on the [[https://sr.ht/~pkal/compat/][compat]] library, so let’s grab that stuff:
|
The functions below depend on [[help:magit-thing-at-point][magit-thing-at-point]], and this depends on the [[https://sr.ht/~pkal/compat/][compat]] library, so let’s grab that stuff:
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package compat
|
(use-package compat
|
||||||
;; :vc (:url "https://github.com/emacs-straight/compat"))
|
:straight (:host github :repo "emacs-straight/compat"))
|
||||||
|
|
||||||
(use-package magit-section
|
(use-package magit-section
|
||||||
:commands magit-thing-at-point)
|
:commands magit-thing-at-point)
|
||||||
|
|
@ -313,7 +310,7 @@ Using the [[https://github.com/emacsmirror/gist][gist package]] to write code sn
|
||||||
The gist project depends on the [[https://github.com/sigma/gh.el][gh library]]. There seems to be a problem with it.
|
The gist project depends on the [[https://github.com/sigma/gh.el][gh library]]. There seems to be a problem with it.
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package gh
|
(use-package gh
|
||||||
;; :vc (:url "https://github.com/sigma/gh.el"))
|
:straight (:host github :repo "sigma/gh.el"))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** Forge
|
** Forge
|
||||||
|
|
@ -411,7 +408,6 @@ Web pages look pretty good with EWW, but I'm having difficulty getting it to ren
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package eww
|
(use-package eww
|
||||||
:after major-mode-hydra
|
|
||||||
:init
|
:init
|
||||||
(setq browse-url-browser-function 'eww-browse-url
|
(setq browse-url-browser-function 'eww-browse-url
|
||||||
browse-url-secondary-browser-function 'browse-url-default-browser
|
browse-url-secondary-browser-function 'browse-url-default-browser
|
||||||
|
|
@ -510,8 +506,7 @@ Make my EWW browsers /look/ like an Org file with the [[https://github.com/cheny
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package shrface
|
(use-package shrface
|
||||||
;; :vc (:url "https://github.com/chenyanming/shrface")
|
:straight (:host github :repo "chenyanming/shrface")
|
||||||
:after major-mode-hydra
|
|
||||||
:config
|
:config
|
||||||
(shrface-basic)
|
(shrface-basic)
|
||||||
;; (shrface-trial)
|
;; (shrface-trial)
|
||||||
|
|
@ -646,7 +641,7 @@ Instead I use Emacs' built-in directory lister (which accepts the standard, =dir
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ls-lisp
|
(use-package ls-lisp
|
||||||
|
:straight (:type built-in)
|
||||||
:config
|
:config
|
||||||
(setq ls-lisp-use-insert-directory-program nil
|
(setq ls-lisp-use-insert-directory-program nil
|
||||||
dired-listing-switches
|
dired-listing-switches
|
||||||
|
|
@ -657,7 +652,7 @@ And [[https://www.masteringemacs.org/article/dired-shell-commands-find-xargs-rep
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package dired-x
|
(use-package dired-x
|
||||||
)
|
:straight (:type built-in))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
The advantage of =dired-x= is the ability to have [[https://www.emacswiki.org/emacs/DiredExtra#Dired_X][shell command guessing]] when selecting one or more files, and running a shell command on them with ~!~ or ~&~.
|
The advantage of =dired-x= is the ability to have [[https://www.emacswiki.org/emacs/DiredExtra#Dired_X][shell command guessing]] when selecting one or more files, and running a shell command on them with ~!~ or ~&~.
|
||||||
|
|
@ -671,7 +666,7 @@ The [[https://github.com/alexluigit/dirvish][dirvish]] project aims to make a pr
|
||||||
I’m beginning with dirvish to use the [[https://github.com/alexluigit/dirvish/blob/main/docs/CUSTOMIZING.org][sample configuration]] and change it:
|
I’m beginning with dirvish to use the [[https://github.com/alexluigit/dirvish/blob/main/docs/CUSTOMIZING.org][sample configuration]] and change it:
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package dirvish
|
(use-package dirvish
|
||||||
;; :vc (:url "https://github.com/alexluigit/dirvish")
|
:straight (:host github :repo "alexluigit/dirvish")
|
||||||
:init (dirvish-override-dired-mode)
|
:init (dirvish-override-dired-mode)
|
||||||
|
|
||||||
:custom
|
:custom
|
||||||
|
|
@ -877,8 +872,6 @@ The [[Evil Collection][evil-collection]] package adds the following keybindings:
|
||||||
I’d like write notes in org files that link to the PDFs (and maybe visa versa), using the [[https://github.com/weirdNox/org-noter][org-noter]] package:
|
I’d like write notes in org files that link to the PDFs (and maybe visa versa), using the [[https://github.com/weirdNox/org-noter][org-noter]] package:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-noter
|
(use-package org-noter
|
||||||
:load-path "/User/howard.abrams/.emacs.d/repos/org-noter"
|
|
||||||
:after major-mode-hydra
|
|
||||||
:config
|
:config
|
||||||
(major-mode-hydra-define org-noter-doc-mode-map nil
|
(major-mode-hydra-define org-noter-doc-mode-map nil
|
||||||
("Notes"
|
("Notes"
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ The following applications are not needed. I alternate between trying to /stay i
|
||||||
Glad to see the 2FA feature is working on the [[https://codeberg.org/martianh/mastodon.el][mastodon.el]] project, and even more glad to see the great birdland diaspora arrive in the land of the toots.
|
Glad to see the 2FA feature is working on the [[https://codeberg.org/martianh/mastodon.el][mastodon.el]] project, and even more glad to see the great birdland diaspora arrive in the land of the toots.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package mastodon
|
(use-package mastodon
|
||||||
;; :vc (:url "https://codeberg.org/martianh/mastodon.el")
|
:straight (:host codeberg :repo "martianh/mastodon.el")
|
||||||
:init
|
:init
|
||||||
(setq mastodon-instance-url "https://pdx.social"
|
(setq mastodon-instance-url "https://pdx.social"
|
||||||
mastodon-active-user "howard"))
|
mastodon-active-user "howard"))
|
||||||
|
|
@ -41,7 +41,7 @@ I would like a dedicate perspective to Mastodon, and I would like a leader key s
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package mastodon
|
(use-package mastodon
|
||||||
:config
|
:config
|
||||||
(ha-leader "a m" `("mastodon" . ,(ha-app-perspective "mastodon" #'mastodon)))
|
(ha-leader "a m" `("mastodon" . ,(lambda () (interactive) (ha-tab-bar-new "mastodon" #'mastodon))))
|
||||||
|
|
||||||
(defun ha-mastodon-scroll-or-more ()
|
(defun ha-mastodon-scroll-or-more ()
|
||||||
"Scroll a window, and at the end, get more entries in timeline."
|
"Scroll a window, and at the end, get more entries in timeline."
|
||||||
|
|
@ -55,33 +55,33 @@ I would like a dedicate perspective to Mastodon, and I would like a leader key s
|
||||||
:config
|
:config
|
||||||
(major-mode-hydra-define mastodon-mode nil
|
(major-mode-hydra-define mastodon-mode nil
|
||||||
("Timelines"
|
("Timelines"
|
||||||
(("u" mastodon-tl--update "update")
|
(("u" mastodon-tl-update "update")
|
||||||
("F" mastodon-tl--get-federated-timeline "Federated")
|
("F" mastodon-tl-get-federated-timeline "Federated")
|
||||||
("H" mastodon-tl--get-home-timeline "Home")
|
("H" mastodon-tl-get-home-timeline "Home")
|
||||||
("L" mastodon-tl--get-local-timeline "Local")
|
("L" mastodon-tl-get-local-timeline "Local")
|
||||||
("T" mastodon-tl--get-tag-timeline "Hashtag"))
|
("T" mastodon-tl-get-tag-timeline "Hashtag"))
|
||||||
"Specials"
|
"Specials"
|
||||||
(("M" mastodon-notifications--get-mentions "Mentions")
|
(("M" mastodon-notifications--get-mentions "Mentions")
|
||||||
("N" mastodon-notifications-get "Notifications")
|
("N" mastodon-notifications-get "Notifications")
|
||||||
("A" mastodon-tl--followed-tags-timeline "All Tags")
|
("A" mastodon-tl-followed-tags-timeline "All Tags")
|
||||||
("S" mastodon-profile--view-bookmarks "Saved bookmarks")
|
("S" mastodon-profile-view-bookmarks "Saved bookmarks")
|
||||||
("O" mastodon-profile--my-profile "My Profile"))
|
("O" mastodon-profile-my-profile "My Profile"))
|
||||||
"Post"
|
"Post"
|
||||||
(("c" mastodon-toot "Compose toot")
|
(("c" mastodon-toot "Compose toot")
|
||||||
("e" mastodon-toot--edit-toot-at-point "Edit toot")
|
("e" mastodon-toot-edit-toot-at-point "Edit toot")
|
||||||
("t" mastodon-tl--thread "Read thread")
|
("t" mastodon-tl-thread "Read thread")
|
||||||
("r" mastodon-toot--reply "Reply")
|
("r" mastodon-toot-reply "Reply")
|
||||||
("m" mastodon-tl--dm-user "Direct Msg")
|
("m" mastodon-tl-dm-user "Direct Msg")
|
||||||
("d" mastodon-toot--delete-toot "Delete"))
|
("d" mastodon-toot-delete-toot "Delete"))
|
||||||
"Toot"
|
"Toot"
|
||||||
(("f" mastodon-toot--toggle-favourite "Favorite")
|
(("f" mastodon-toot-toggle-favourite "Favorite")
|
||||||
("b" mastodon-toot--toggle-boost "Boost")
|
("b" mastodon-toot-toggle-boost "Boost")
|
||||||
("s" mastodon-toot--toggle-bookmark "Save")
|
("s" mastodon-toot-toggle-bookmark "Save")
|
||||||
("y" mastodon-toot--copy-toot-url "Copy URL")
|
("y" mastodon-toot-copy-toot-url "Copy URL")
|
||||||
("Y" mastodon-toot--copy-toot-text "Copy text"))
|
("Y" mastodon-toot-copy-toot-text "Copy text"))
|
||||||
"Navigation"
|
"Navigation"
|
||||||
(("n" mastodon-tl--next-tab-item "next" :color pink)
|
(("n" mastodon-tl-next-tab-item "next" :color pink)
|
||||||
("p" mastodon-tl--previous-tab-item "previous" :color pink)
|
("p" mastodon-tl-previous-tab-item "previous" :color pink)
|
||||||
("," ha-mastodon-scroll-or-more "...more" :color pink))))))
|
("," ha-mastodon-scroll-or-more "...more" :color pink))))))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ Let’s turn on non-fixed-width fonts to make everything easier to read:
|
||||||
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.com/alphapapa/ement.el][ement]] project.
|
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.com/alphapapa/ement.el][ement]] project.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ement
|
(use-package ement
|
||||||
;; :vc (:url "https://github.com/alphapapa/ement.el")
|
:straight (:host github :repo "alphapapa/ement.el")
|
||||||
:config
|
:config
|
||||||
(major-mode-hydra-define ement-room-mode (:quit-key "q")
|
(major-mode-hydra-define ement-room-mode (:quit-key "q")
|
||||||
("Send"
|
("Send"
|
||||||
|
|
@ -175,7 +175,7 @@ I'm thinking the [[https://zevlg.github.io/telega.el/][Telega package]] would be
|
||||||
(when (fboundp 'evil-insert-state)
|
(when (fboundp 'evil-insert-state)
|
||||||
(add-hook 'telega-chat-mode-hook 'evil-insert-state))
|
(add-hook 'telega-chat-mode-hook 'evil-insert-state))
|
||||||
|
|
||||||
(ha-leader "a t" `("telega" . ,(ha-app-perspective "telega" #'telega))))
|
(ha-leader "a t" `("telega" . ,(lambda () (interactive) (ha-tab-bar-new "telega" #'telega)))))
|
||||||
#+end_src
|
#+end_src
|
||||||
For some reason, you need [[https://github.com/Fanael/rainbow-identifiers][rainbow-identifiers]] to work, oh, I guess the docs state this.
|
For some reason, you need [[https://github.com/Fanael/rainbow-identifiers][rainbow-identifiers]] to work, oh, I guess the docs state this.
|
||||||
|
|
||||||
|
|
@ -189,7 +189,7 @@ Been working on my [[https://gitlab.com/howardabrams/emacs-rpgdm][RPG DM project
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when (f-directory? "~/src/emacs-rpgdm")
|
(when (f-directory? "~/src/emacs-rpgdm")
|
||||||
(use-package rpgdm
|
(use-package rpgdm
|
||||||
:load-path "~/src/emacs-rpgdm"
|
:straight (:local-repo "~/src/emacs-rpgdm")
|
||||||
:commands (rpgdm-mode rpgdm-tables-load)
|
:commands (rpgdm-mode rpgdm-tables-load)
|
||||||
:init (setq rpgdm-base (expand-file-name "~/src/emacs-rpgdm"))
|
:init (setq rpgdm-base (expand-file-name "~/src/emacs-rpgdm"))
|
||||||
:config (ha-leader "t D" '("rpg dm" . rpgdm-mode))))
|
:config (ha-leader "t D" '("rpg dm" . rpgdm-mode))))
|
||||||
|
|
@ -199,7 +199,7 @@ Working on my new replacement of my DM code:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when (f-directory? "~/src/emacs-rpgtk")
|
(when (f-directory? "~/src/emacs-rpgtk")
|
||||||
(use-package rpgtk
|
(use-package rpgtk
|
||||||
:load-path "~/src/emacs-rpgtk"
|
:straight (:local-repo "~/src/emacs-rpgtk")
|
||||||
:after hydra
|
:after hydra
|
||||||
;; :commands (rpgtk-mode rpgtk-tables-load rpgtk-dice rpgtk-message)
|
;; :commands (rpgtk-mode rpgtk-tables-load rpgtk-dice rpgtk-message)
|
||||||
:custom
|
:custom
|
||||||
|
|
@ -217,7 +217,7 @@ And my [[https://gitlab.com/howardabrams/emacs-ironsworn][new Ironsworn project]
|
||||||
(when (f-directory? "~/src/emacs-ironsworn")
|
(when (f-directory? "~/src/emacs-ironsworn")
|
||||||
(use-package rpgdm-ironsworn
|
(use-package rpgdm-ironsworn
|
||||||
:after rpgdm
|
:after rpgdm
|
||||||
:load-path "~/src/emacs-ironsworn"
|
:straight (:local-repo "~/src/emacs-ironsworn")
|
||||||
:init
|
:init
|
||||||
(setq rpgdm-ironsworn-project (expand-file-name "~/src/emacs-ironsworn")
|
(setq rpgdm-ironsworn-project (expand-file-name "~/src/emacs-ironsworn")
|
||||||
;; Ignore org links that call my RPG functions:
|
;; Ignore org links that call my RPG functions:
|
||||||
|
|
@ -234,7 +234,7 @@ Why not? Let’s see if the [[https://github.com/isamert/empv.el][empv]] project
|
||||||
What else?
|
What else?
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package empv
|
(use-package empv
|
||||||
;; :vc (:url "https://github.com/isamert/empv.el")
|
:straight (:host github :repo "isamert/empv.el")
|
||||||
:general (ha-leader
|
:general (ha-leader
|
||||||
"a p" '(empv-map :wk "play music")))
|
"a p" '(empv-map :wk "play music")))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ And for even quicker work, we can have special scripts tied to special keybindin
|
||||||
The [[https://gitlab.com/aimebertrand/org-mac-link][org-mac-link]] project makes it easy to tell Emacs to retrieve information from other apps, e.g. the URL of the opened tab in Firefox.
|
The [[https://gitlab.com/aimebertrand/org-mac-link][org-mac-link]] project makes it easy to tell Emacs to retrieve information from other apps, e.g. the URL of the opened tab in Firefox.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-mac-link
|
(use-package org-mac-link
|
||||||
;; :vc (:url "https://gitlab.com/aimebertrand/org-mac-link")
|
:straight (:host gitlab :repo "aimebertrand/org-mac-link")
|
||||||
:config
|
:config
|
||||||
(ha-leader "i" '("insert app info" . org-mac-link-get-link)))
|
(ha-leader "i" '("insert app info" . org-mac-link-get-link)))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
|
||||||
328
ha-config.org
328
ha-config.org
|
|
@ -146,8 +146,7 @@ After reading [[https://irreal.org/blog/?p=12139][Jon Sander’s essay]] as well
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package emacs-everywhere
|
(use-package emacs-everywhere
|
||||||
;; :vc (:url "https://github.com/tecosaur/emacs-everywhere")
|
:straight (:host github :repo "tecosaur/emacs-everywhere"))
|
||||||
)
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
This package /called outside of Emacs/, so I bound a keybinding to iCanHazShortcut:
|
This package /called outside of Emacs/, so I bound a keybinding to iCanHazShortcut:
|
||||||
|
|
@ -226,6 +225,7 @@ When I push changes to my files to Gerrit and other code review, I don’t want
|
||||||
The [[https://www.emacswiki.org/emacs/RecentFiles][recentf]] feature has been in Emacs for a long time, but it has a problem with Tramp, as we need to turn off the cleanup feature that attempts to =stat= all the files and remove them from the =recent= accessed list if they are readable. The requires recentf to open up a remote files which blocks Emacs at the most inopportune times… like when trying to reboot the machine.
|
The [[https://www.emacswiki.org/emacs/RecentFiles][recentf]] feature has been in Emacs for a long time, but it has a problem with Tramp, as we need to turn off the cleanup feature that attempts to =stat= all the files and remove them from the =recent= accessed list if they are readable. The requires recentf to open up a remote files which blocks Emacs at the most inopportune times… like when trying to reboot the machine.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package recentf
|
(use-package recentf
|
||||||
|
:straight (:type built-in)
|
||||||
:config
|
:config
|
||||||
(setq recentf-auto-cleanup 'never) ;; disable before we start recentf!
|
(setq recentf-auto-cleanup 'never) ;; disable before we start recentf!
|
||||||
(recentf-mode 1))
|
(recentf-mode 1))
|
||||||
|
|
@ -336,13 +336,10 @@ The [[https://github.com/minad/vertico][vertico]] package puts the completing re
|
||||||
(use-package vertico
|
(use-package vertico
|
||||||
:config (vertico-mode))
|
:config (vertico-mode))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
My issue with Vertico is when calling =find-file=, the Return key opens =dired=, instead of inserting the directory at point. This package addresses this:
|
My issue with Vertico is when calling =find-file=, the Return key opens =dired=, instead of inserting the directory at point. This package addresses this:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
#+begin_src emacs-lisp :tangle no
|
|
||||||
(use-package vertico-directory
|
(use-package vertico-directory
|
||||||
:load-path "~/.emacs.d/repos/vertigo/extensions"
|
:straight (el-patch :files ("~/.emacs.d/straight/repos/vertico/extensions/vertico-directory.el"))
|
||||||
;; :straight (:files ("~/.emacs.d/straight/repos/vertico/extensions/vertico-directory.el"))
|
|
||||||
;; More convenient directory navigation commands
|
;; More convenient directory navigation commands
|
||||||
:bind (:map vertico-map
|
:bind (:map vertico-map
|
||||||
("RET" . vertico-directory-enter)
|
("RET" . vertico-directory-enter)
|
||||||
|
|
@ -383,7 +380,7 @@ How does it compare? Once upon a time, I enjoyed typing ~plp~ for =package-list-
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package fussy
|
(use-package fussy
|
||||||
;; ;; :vc (:url "https://github.com/jojojames/fussy")
|
;; :straight (:host github :repo "jojojames/fussy")
|
||||||
:config
|
:config
|
||||||
(push 'fussy completion-styles)
|
(push 'fussy completion-styles)
|
||||||
(setq completion-category-defaults nil
|
(setq completion-category-defaults nil
|
||||||
|
|
@ -574,7 +571,7 @@ The [[https://github.com/minad/cape][Cape project]] deliver particular [[help:co
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+BEGIN_SRC emacs-lisp :tangle no
|
||||||
(use-package cape
|
(use-package cape
|
||||||
;; :vc (:url "https://github.com/minad/cape")
|
:straight (:host github :repo "minad/cape")
|
||||||
:init
|
:init
|
||||||
(setq completion-at-point-functions (list #'cape-emoji)))
|
(setq completion-at-point-functions (list #'cape-emoji)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
@ -595,11 +592,10 @@ After using [[http://company-mode.github.io/][company]] for my completion back-
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package corfu
|
(use-package corfu
|
||||||
;; :vc (:url "https://github.com/minad/corfu")
|
|
||||||
:custom
|
:custom
|
||||||
(corfu-cycle t)
|
(corfu-cycle t)
|
||||||
(corfu-separator ?\s)
|
(corfu-separator ?\s)
|
||||||
:config
|
:init
|
||||||
(global-corfu-mode))
|
(global-corfu-mode))
|
||||||
#+end_src
|
#+end_src
|
||||||
*** Snippets
|
*** Snippets
|
||||||
|
|
@ -677,7 +673,7 @@ As I've mentioned [[http://www.howardism.org/Technical/Emacs/beep-for-emacs.html
|
||||||
'libnotify)))
|
'libnotify)))
|
||||||
|
|
||||||
(use-package beep
|
(use-package beep
|
||||||
:load-path "~/src/hamacs/elisp"
|
:straight (:local-repo "~/src/hamacs/elisp")
|
||||||
:hook (after-init . ha-random-startup-message)
|
:hook (after-init . ha-random-startup-message)
|
||||||
:commands (beep-when-finished beep-when-run-too-long)
|
:commands (beep-when-finished beep-when-run-too-long)
|
||||||
:config
|
:config
|
||||||
|
|
@ -930,14 +926,13 @@ Since I wasn’t using all the features that [[https://github.com/bbatsov/projec
|
||||||
(ha-leader
|
(ha-leader
|
||||||
"p" '(:ignore t :which-key "projects")
|
"p" '(:ignore t :which-key "projects")
|
||||||
"p W" '("initialize workspace" . ha-workspace-initialize)
|
"p W" '("initialize workspace" . ha-workspace-initialize)
|
||||||
"p n" '("new project space" . ha-project-persp)
|
"p p" '("switch project" . ha-tab-bar-new-project)
|
||||||
|
|
||||||
"p !" '("run cmd in project root" . project-shell-command)
|
"p !" '("run cmd in project root" . project-shell-command)
|
||||||
"p &" '("run cmd async" . project-async-shell-command)
|
"p &" '("run cmd async" . project-async-shell-command)
|
||||||
"p a" '("add new project" . project-remember-projects-under)
|
"p a" '("add new project" . project-remember-projects-under)
|
||||||
"p d" '("dired" . project-dired)
|
"p d" '("dired" . project-dired)
|
||||||
"p k" '("kill project buffers" . project-kill-buffers)
|
"p k" '("kill project buffers" . project-kill-buffers)
|
||||||
"p p" '("switch project" . project-switch-project)
|
|
||||||
"p x" '("remove known project" . project-forget-project)
|
"p x" '("remove known project" . project-forget-project)
|
||||||
|
|
||||||
"p f" '("find file" . project-find-file)
|
"p f" '("find file" . project-find-file)
|
||||||
|
|
@ -951,204 +946,142 @@ Since I wasn’t using all the features that [[https://github.com/bbatsov/projec
|
||||||
"p s" '("project shell" . project-shell)))
|
"p s" '("project shell" . project-shell)))
|
||||||
#+end_src
|
#+end_src
|
||||||
** Workspaces
|
** Workspaces
|
||||||
A /workspace/ (at least to me) requires a quick jump to a collection of buffer windows organized around a project or task. For this, I'm basing my work on the [[https://github.com/nex3/perspective-el][perspective.el]] project.
|
A /workspace/ (at least to me) requires a quick jump to a collection of buffer windows organized around a project or task. Later versions of Emacs use [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Tab-Bars.html][Tab Bars]] which group windows and buffers in a perspective. The code that follows is a Poor Person’s Workspace package. Also let’s dive into the end section of [[https://www.masteringemacs.org/article/demystifying-emacs-window-manager][Mickey Petersen's essay]] on the subject.
|
||||||
|
|
||||||
I build a Hydra to dynamically list the current projects as well as select the project.
|
Couple notes:
|
||||||
To do this, we need a way to generate a string of the perspectives in alphabetical order:
|
- Function, =tab-bar-switch-to-tab=, switches or /creates/ a tab. We will always use this.
|
||||||
|
- We can switch to a tab by number with =tab-bar-select-tab=
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(setq tab-bar-show 1 ; hide bar if <= 1 tabs open
|
||||||
|
tab-bar-close-button-show nil ; hide tab close / X button
|
||||||
|
tab-bar-new-tab-choice "*dashboard*" ; buffer to show in new tabs
|
||||||
|
tab-bar-tab-hints t ; show tab numbers
|
||||||
|
|
||||||
|
tab-bar-button-relief 0
|
||||||
|
tab-bar-button-margin '(40 . 1)
|
||||||
|
|
||||||
|
;; Jump to a tab by numbers (see the keybindings set later):
|
||||||
|
tab-bar-select-tab-modifiers '(super control))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
I’ve struggled to /programmatically/ create sane workspaces, so let’s just save them off:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(desktop-save-mode 1)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
New workspace is a tab with a specific name that opens up a specific buffer or application. My motive for such a complicated function allows me to pre-create tabs with already running applications or files.
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha--persp-label (num names)
|
(defun ha-tab-bar-new (name &optional bff)
|
||||||
"Return string of numbered elements.
|
"Create a new tab with a NAME.
|
||||||
NUM is the starting number and NAMES is a list of strings."
|
With a non-nil IFF, call IFF as a function or switch
|
||||||
(when names
|
to the IFF buffer or the files listed."
|
||||||
(concat
|
(interactive "sWorkspace Name: ")
|
||||||
(format " %d: %s%s" ; Shame that the following doesn't work:
|
(tab-bar-switch-to-tab name)
|
||||||
num ; (propertize (number-to-string num) :foreground "#00a0")
|
(when bff
|
||||||
(car names) ; Nor does surrounding the number with underbars.
|
(cond
|
||||||
|
((listp bff) (find-file (car bff))
|
||||||
(if (equal (car names) (persp-name (persp-curr))) "*" ""))
|
(dolist (f (cdr bff))
|
||||||
(ha--persp-label (1+ num) (cdr names)))))
|
(split-window-right)
|
||||||
|
(find-file f)))
|
||||||
(defun ha-persp-labels ()
|
((fboundp bff) (call-interactively bff))
|
||||||
"Return a string of numbered elements from a list of names."
|
((bufferp bff) (switch-to-buffer bff)))))
|
||||||
(ha--persp-label 1 (sort (hash-table-keys (perspectives-hash)) 's-less?)))
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Build the hydra as well as configure the =perspective= project.
|
Create a new tab associated with a project:
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package perspective
|
(defun ha-tab-bar-new-project (project-dir)
|
||||||
:custom
|
"Create a new tab/workspace based on a project.
|
||||||
(persp-modestring-short t)
|
The project is defined by the PROJECT-DIR directory."
|
||||||
(persp-show-modestring t)
|
(interactive (list (completing-read "Project: " (project-known-project-roots))))
|
||||||
|
(let ((name (project-name (project-current nil project-dir)))
|
||||||
:config
|
(default-directory project-dir))
|
||||||
(setq persp-suppress-no-prefix-key-warning t)
|
(ha-tab-bar-new name)
|
||||||
|
(project-switch-project project-dir)))
|
||||||
(persp-mode)
|
|
||||||
|
|
||||||
(defhydra hydra-workspace-leader (:color blue :hint nil) "
|
|
||||||
Workspaces- %s(ha-persp-labels)
|
|
||||||
_n_: new project _r_: rename _a_: add buffer _l_: load worksp
|
|
||||||
_]_: next worksp _d_: delete _b_: goto buffer _s_: save worksp
|
|
||||||
_[_: previous _W_: init all _k_: remove buffer _`_: to last worksp "
|
|
||||||
("TAB" persp-switch-quick)
|
|
||||||
("RET" persp-switch)
|
|
||||||
("`" persp-switch-last)
|
|
||||||
("1" (persp-switch-by-number 1))
|
|
||||||
("2" (persp-switch-by-number 2))
|
|
||||||
("3" (persp-switch-by-number 3))
|
|
||||||
("4" (persp-switch-by-number 4))
|
|
||||||
("5" (persp-switch-by-number 5))
|
|
||||||
("6" (persp-switch-by-number 6))
|
|
||||||
("7" (persp-switch-by-number 7))
|
|
||||||
("8" (persp-switch-by-number 8))
|
|
||||||
("9" (persp-switch-by-number 9))
|
|
||||||
("0" (persp-switch-by-number 0))
|
|
||||||
("n" ha-project-persp)
|
|
||||||
("N" persp-switch)
|
|
||||||
("]" persp-next :color pink)
|
|
||||||
("[" persp-prev :color pink)
|
|
||||||
("d" persp-kill)
|
|
||||||
("W" ha-workspace-initialize)
|
|
||||||
("a" persp-add-buffer)
|
|
||||||
("b" persp-switch-to-buffer)
|
|
||||||
("k" persp-remove-buffer)
|
|
||||||
("K" persp-kill-buffer)
|
|
||||||
("m" persp-merge)
|
|
||||||
("u" persp-unmerge)
|
|
||||||
("i" persp-import)
|
|
||||||
("r" persp-rename)
|
|
||||||
("s" persp-state-save)
|
|
||||||
("l" persp-state-load)
|
|
||||||
("w" ha-switch-to-special) ; The most special perspective
|
|
||||||
("q" nil)
|
|
||||||
("C-g" nil)))
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Let’s give it a binding:
|
If we close a tab that is a project, we want to close all the buffers associated with it. I wouldn’t do this if it wasn’t so easy to re-create them:
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader "TAB" '("workspaces" . hydra-workspace-leader/body))
|
(defun ha-tab-bar-delete (tab-name)
|
||||||
|
"Delete a tab, TAB-NAME, and all buffers associated with it."
|
||||||
|
(interactive
|
||||||
|
(list (completing-read "Close tab by name: "
|
||||||
|
(mapcar (lambda (tab)
|
||||||
|
(alist-get 'name tab))
|
||||||
|
(funcall tab-bar-tabs-function)))))
|
||||||
|
(dolist (buf (ha-tab-bar-buffers tab-name))
|
||||||
|
(kill-buffer buf))
|
||||||
|
(tab-bar-close-tab-by-name tab-name))
|
||||||
|
|
||||||
|
(defun ha-tab-bar-buffers (tab-name)
|
||||||
|
"Return list of buffers associated with TAB-NAME."
|
||||||
|
(seq-filter (lambda (b)
|
||||||
|
(thread-last b
|
||||||
|
(tab-bar-get-buffer-tab)
|
||||||
|
(alist-get 'name)
|
||||||
|
(string-equal tab-name)))
|
||||||
|
(buffer-list)))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
When called, it /can/ look like:
|
And some shortcut keys from the =general= project:
|
||||||
|
|
||||||
[[file:screenshots/projects-hydra.png]]
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(general-nmap :prefix "SPC"
|
||||||
|
"<tab>" '(:ignore t :which-key "workspaces")
|
||||||
|
"<tab> <tab>" '("switch" . tab-switch)
|
||||||
|
"<tab> p" '("new project" . ha-tab-bar-new-project)
|
||||||
|
"<tab> n" '("new space" . ha-tab-bar-new)
|
||||||
|
"<tab> u" '("update names" . ha-tab-bar-update-names)
|
||||||
|
"<tab> d" '("delete space" . ha-tab-bar-delete))
|
||||||
|
|
||||||
The /special/ perspective is a nice shortcut to the one I use the most:
|
(global-set-key (kbd "s-C-t") 'ha-tab-bar-new)
|
||||||
#+begin_src emacs-lisp
|
(global-set-key (kbd "s-C-[") 'tab-bar-switch-to-prev-tab)
|
||||||
(defun ha-switch-to-special ()
|
(global-set-key (kbd "s-C-]") 'tab-bar-switch-to-next-tab)
|
||||||
"Change to the projects perspective."
|
|
||||||
|
(tab-bar-mode 1)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
I want to quickly jump, by the number shown on the tab, to that grouping. The following two functions create leader sequences with the name of the tab group:
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun ha-tab-bar-update-names (&optional changed-tab)
|
||||||
|
"Create normal-mode keybindings for the tab groupings.
|
||||||
|
This creates `SPC TAB 1' to jump to the first tab, etc."
|
||||||
(interactive)
|
(interactive)
|
||||||
(persp-switch "projects"))
|
;; Remove all previously created keybindings:
|
||||||
#+end_src
|
(ignore-errors
|
||||||
|
(dolist (indx (number-sequence 0 9))
|
||||||
|
(general-nmap :prefix "SPC" (format "<tab> %d" indx) nil)))
|
||||||
|
|
||||||
I often want a workspace dedicated to an /application/, so this function:
|
;; Loop through the existing tabs, create keys for each:
|
||||||
|
(seq-do-indexed 'ha-tab-bar-update-tab-keybinding (tab-bar-tabs)))
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
(defun ha-tab-bar-update-tab-keybinding (tab-deets indx)
|
||||||
(defun ha-app-perspective (name func)
|
"Create a keybinding to jump to tab described by TAB-DEETS.
|
||||||
"Generate new perspective NAME, automatically running FUNC."
|
The key sequence, `SPC' `TAB' then INDX."
|
||||||
(lambda ()
|
(when (< indx 10)
|
||||||
(interactive)
|
(let ((name (alist-get 'name tab-deets)))
|
||||||
(let ((already-started? (seq-contains-p (persp-names) name 'equal)))
|
(general-nmap :prefix "SPC"
|
||||||
(persp-switch name)
|
;; As indx is starts with 0, we need to create keybindings to
|
||||||
(unless already-started?
|
;; match the tab labels by incrementing it by one ... unless,
|
||||||
(call-interactively func)))))
|
;; we are at 10, where we use 0 instead:
|
||||||
#+end_src
|
(format "<tab> %d" (if (= indx 9) 0 (1+ indx)))
|
||||||
|
`(,name . (lambda () (interactive) (tab-bar-select-tab ,(1+ indx))))))))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
And I can then use it like:
|
Any time I create or delete a new tab, we can call =ha-tab-bar-update-names=:
|
||||||
#+begin_src emacs-lisp :tangle no
|
|
||||||
(ha-leader "a x" `("to foobar" . ,(ha-app-perspective "foobar" #'foobar)))
|
|
||||||
#+end_src
|
|
||||||
*** Predefined Workspaces
|
|
||||||
Let's describe a list of startup project workspaces. This way, I don't need the clutter of the recent state, but also get back to a state of mental normality.
|
|
||||||
Granted, this list is essentially a list of projects that I'm currently developing, so I expect this to change often.
|
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defvar ha-workspace-projects-personal nil "List of default projects with a name.")
|
(advice-add #'tab-bar-new-tab :after #'ha-tab-bar-update-names)
|
||||||
|
(advice-add #'tab-bar-close-tab :after #'ha-tab-bar-update-names)
|
||||||
|
(advice-add #'tab-bar-close-other-tabs :after #'ha-tab-bar-update-names)
|
||||||
|
|
||||||
(add-to-list 'ha-workspace-projects-personal
|
(add-hook desktop-after-read-hook #'ha-tab-bar-update-names)
|
||||||
'("projects" "~/projects" ("breathe.org" "tasks.org")))
|
#+END_SRC
|
||||||
(add-to-list 'ha-workspace-projects-personal
|
|
||||||
'("personal" "~/personal" ("general.org")))
|
|
||||||
(add-to-list 'ha-workspace-projects-personal
|
|
||||||
'("technical" "~/technical" ("ansible.org")))
|
|
||||||
(add-to-list 'ha-workspace-projects-personal
|
|
||||||
'("hamacs" "~/src/hamacs" ("README.org" "ha-config.org")))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
Given a list of information about project-workspaces, can we create them all?
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(defun ha-persp-exists? (name)
|
|
||||||
"Return non-nill if a perspective of NAME exists."
|
|
||||||
(when (fboundp 'perspectives-hash)
|
|
||||||
(seq-contains (hash-table-keys (perspectives-hash)) name)))
|
|
||||||
|
|
||||||
(defun ha-workspace-initialize (&optional projects)
|
|
||||||
"Precreate workspace projects from a PROJECTS list.
|
|
||||||
Each entry in the list is a list containing:
|
|
||||||
- name (as a string)
|
|
||||||
- project root directory
|
|
||||||
- a optional list of files to display"
|
|
||||||
(interactive)
|
|
||||||
(unless projects
|
|
||||||
(setq projects ha-workspace-projects-personal))
|
|
||||||
|
|
||||||
(dolist (project projects)
|
|
||||||
(seq-let (name root files) project
|
|
||||||
(unless (ha-persp-exists? name)
|
|
||||||
(message "Creating workspace: %s (from %s)" name root)
|
|
||||||
(ha-project-persp root name files))))
|
|
||||||
(persp-switch "main"))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
Often, but not always, I want a perspective based on an actual Git repository, e.g. a project. Emacs calls these transients.
|
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(defun ha-project-persp (project &optional name files)
|
|
||||||
"Create a new perspective, and then switch to the PROJECT.
|
|
||||||
If NAME is not given, then figure it out based on the name of the
|
|
||||||
PROJECT. If FILES aren't specified, then see if there is a
|
|
||||||
README. Otherwise, pull up Dired."
|
|
||||||
(interactive (list (completing-read "Project: "
|
|
||||||
(project-known-project-roots))))
|
|
||||||
(when (f-directory-p project)
|
|
||||||
(unless name
|
|
||||||
(setq name (f-filename project)))
|
|
||||||
(persp-switch name)
|
|
||||||
|
|
||||||
(let ((recent-files (thread-last recentf-list
|
|
||||||
(--filter (s-starts-with? project it))
|
|
||||||
(-take 3)))
|
|
||||||
(readme-org (f-join project "README.org"))
|
|
||||||
(readme-md (f-join project "README.md"))
|
|
||||||
(readme-rst (f-join project "README.rst")))
|
|
||||||
(cond
|
|
||||||
(files (ha--project-show-files project files))
|
|
||||||
(recent-files (ha--project-show-files project recent-files))
|
|
||||||
((f-exists? readme-org) (find-file readme-org))
|
|
||||||
((f-exists? readme-md) (find-file readme-md))
|
|
||||||
((f-exists? readme-rst) (find-file readme-rst))
|
|
||||||
(t (dired project))))))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
When starting a new perspective, and I specify more than one file, this function splits the window horizontally for each file.
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(defun ha--project-show-files (root files)
|
|
||||||
"Display a list of FILES in a project ROOT directory.
|
|
||||||
Each file gets its own window (so don't make the list of files
|
|
||||||
long)."
|
|
||||||
(when files
|
|
||||||
(let ((default-directory root)
|
|
||||||
(file (car files))
|
|
||||||
(more (cdr files)))
|
|
||||||
(message "Loading files from %s ... %s and %s" root file more)
|
|
||||||
(when (f-exists? file)
|
|
||||||
(find-file file))
|
|
||||||
(when more
|
|
||||||
(split-window-horizontally)
|
|
||||||
(ha--project-show-files root more)))))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
* Pretty Good Encryption
|
* Pretty Good Encryption
|
||||||
For details on using GnuPG in Emacs, see Mickey Petersen’s [[https://www.masteringemacs.org/article/keeping-secrets-in-emacs-gnupg-auth-sources][GnuPG Essay]].
|
For details on using GnuPG in Emacs, see Mickey Petersen’s [[https://www.masteringemacs.org/article/keeping-secrets-in-emacs-gnupg-auth-sources][GnuPG Essay]].
|
||||||
|
|
@ -1166,6 +1099,7 @@ Also, as [[https://www.bytedude.com/gpg-in-emacs/][bytedude]] mentions, I need t
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package epa-file
|
(use-package epa-file
|
||||||
|
:straight (:type built-in)
|
||||||
:custom
|
:custom
|
||||||
(epg-debug t)
|
(epg-debug t)
|
||||||
(auth-source-debug t)
|
(auth-source-debug t)
|
||||||
|
|
@ -1175,22 +1109,18 @@ Also, as [[https://www.bytedude.com/gpg-in-emacs/][bytedude]] mentions, I need t
|
||||||
;; Make sure we prompt in the minibuffer for the password:
|
;; Make sure we prompt in the minibuffer for the password:
|
||||||
(epg-pinentry-mode 'loopback)
|
(epg-pinentry-mode 'loopback)
|
||||||
;; I trust my Emacs session, so I don't bother expiring my pass:
|
;; I trust my Emacs session, so I don't bother expiring my pass:
|
||||||
(auth-source-cache-expiry nil))
|
(auth-source-cache-expiry nil)
|
||||||
#+end_src
|
|
||||||
|
|
||||||
Need to make sure that Emacs will handle the prompts, and turn it on:
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(use-package epa-file
|
|
||||||
:config
|
:config
|
||||||
(setenv "GPG_AGENT_INFO" nil)
|
(setenv "GPG_AGENT_INFO" nil)
|
||||||
(epa-file-enable))
|
(ignore-error (epa-file-enable)))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Since I already (at this point in my file) have Org installed and running, the following code configures the encryption of certain header sections (see [[https://orgmode.org/worg/org-tutorials/encrypting-files.html][this tutorial]]). Headers with a =:crypt:tag (see =org-crypt-tag-matcher= to change it) will be encrypted.
|
Since I already (at this point in my file) have Org installed and running, the following code configures the encryption of certain header sections (see [[https://orgmode.org/worg/org-tutorials/encrypting-files.html][this tutorial]]). Headers with a =:crypt:tag (see =org-crypt-tag-matcher= to change it) will be encrypted.
|
||||||
|
|
||||||
To temporarily read an encrypted part, and call =M-x org-decrypt-entry= when the cursor is inside that section. Saving the file, will re-encrypt it.
|
To temporarily read an encrypted part, and call =M-x org-decrypt-entry= when the cursor is inside that section. Saving the file, will re-encrypt it.
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package org
|
(use-package org
|
||||||
:config
|
:config
|
||||||
(require 'org-crypt)
|
(require 'org-crypt)
|
||||||
|
|
|
||||||
|
|
@ -145,12 +145,10 @@ The [[https://github.com/emacs-dashboard/emacs-dashboard][emacs-dashboard]] proj
|
||||||
(string-replace "\n" "" smaller-version)))
|
(string-replace "\n" "" smaller-version)))
|
||||||
|
|
||||||
(setq dashboard-startup-banner
|
(setq dashboard-startup-banner
|
||||||
(if (ha-emacs-for-work?)
|
;; Choose a random image from my collection of startup images:
|
||||||
"~/src/hamacs/support/teal-sticker.png"
|
(thread-first "~/src/hamacs/support/dashboard"
|
||||||
;; Choose a random image from my collection of startup images:
|
(directory-files t (rx ".png"))
|
||||||
(thread-first "~/src/hamacs/support/dashboard"
|
(seq-random-elt)))
|
||||||
(directory-files t (rx ".png"))
|
|
||||||
(seq-random-elt))))
|
|
||||||
|
|
||||||
(setq dashboard-banner-logo-title
|
(setq dashboard-banner-logo-title
|
||||||
(format "Emacs %s — %s"
|
(format "Emacs %s — %s"
|
||||||
|
|
@ -169,12 +167,12 @@ The [[https://github.com/emacs-dashboard/emacs-dashboard][emacs-dashboard]] proj
|
||||||
dashboard-set-heading-icons t
|
dashboard-set-heading-icons t
|
||||||
dashboard-footer-messages (list (ha--dad-joke)))
|
dashboard-footer-messages (list (ha--dad-joke)))
|
||||||
|
|
||||||
:config
|
|
||||||
(dashboard-setup-startup-hook)
|
|
||||||
|
|
||||||
;; Real shame that :config is incompatible with :hook, otherwise:
|
;; Real shame that :config is incompatible with :hook, otherwise:
|
||||||
;; :hook (dashboard-after-initialize . ha-dashboard)
|
;; :hook (dashboard-after-initialize . ha-dashboard)
|
||||||
(add-hook 'dashboard-after-initialize-hook 'ha-dashboard))
|
|
||||||
|
:config
|
||||||
|
(tab-bar-switch-to-tab "main")
|
||||||
|
(dashboard-setup-startup-hook))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
This dashboard project requires [[https://github.com/purcell/page-break-lines][page-break-lines]] (which is a nice project):
|
This dashboard project requires [[https://github.com/purcell/page-break-lines][page-break-lines]] (which is a nice project):
|
||||||
|
|
@ -264,6 +262,7 @@ The =dashboard= project hooks to [[help:emacs-startup-hook][emacs-startup-hook]]
|
||||||
(defun ha-dashboard ()
|
(defun ha-dashboard ()
|
||||||
"Shows the extra stuff with the dashboard."
|
"Shows the extra stuff with the dashboard."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
(tab-bar-switch-to-tab "main")
|
||||||
(switch-to-buffer "*dashboard*")
|
(switch-to-buffer "*dashboard*")
|
||||||
(setq-local mode-line-format nil)
|
(setq-local mode-line-format nil)
|
||||||
(delete-other-windows)
|
(delete-other-windows)
|
||||||
|
|
|
||||||
15
ha-demos.org
15
ha-demos.org
|
|
@ -44,8 +44,8 @@ Once I made demonstrations /within/ Emacs with my [[https://github.com/howardabr
|
||||||
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package demo-it
|
(use-package demo-it
|
||||||
:load-path "~/src/demo-it"
|
:straight (:local-repo "~/src/demo-it")
|
||||||
;; :vc (:url "https://github.com/howardabrams/demo-it")
|
;; :straight (:host github :repo "howardabrams/demo-it")
|
||||||
:commands (demo-it-create demo-it-start demo-it-hide-mode-line
|
:commands (demo-it-create demo-it-start demo-it-hide-mode-line
|
||||||
demo-it--presentation-display-set)
|
demo-it--presentation-display-set)
|
||||||
:custom (demo-it--insert-test-speed :faster))
|
:custom (demo-it--insert-test-speed :faster))
|
||||||
|
|
@ -194,7 +194,7 @@ With some a startup bug that I haven’t been able to resolve, I’m not using i
|
||||||
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package dslide
|
(use-package dslide
|
||||||
;; :vc (:url "https://github.com/positron-solutions/dslide")
|
:straight (dslide :host github :repo "positron-solutions/dslide")
|
||||||
:commands (dslide-deck-start dslide-deck-stop)
|
:commands (dslide-deck-start dslide-deck-stop)
|
||||||
:custom
|
:custom
|
||||||
(dslide-start-from 'point)
|
(dslide-start-from 'point)
|
||||||
|
|
@ -244,7 +244,7 @@ Call the =ha-slide-notes-update= function automatically after updating a slide.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+BEGIN_SRC emacs-lisp :tangle no
|
||||||
(use-package dslide
|
(use-package dslide
|
||||||
;; :vc (:url "https://github.com/positron-solutions/dslide")
|
:straight (dslide :host github :repo "positron-solutions/dslide")
|
||||||
:commands (dslide-narrow-hook)
|
:commands (dslide-narrow-hook)
|
||||||
:hook (dslide-narrow . 'ha-slide-notes-update))
|
:hook (dslide-narrow . 'ha-slide-notes-update))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
@ -256,7 +256,8 @@ The [[https://github.com/positron-solutions/moc][Master of Ceremonies]] package
|
||||||
(use-package default-text-scale)
|
(use-package default-text-scale)
|
||||||
|
|
||||||
(use-package moc
|
(use-package moc
|
||||||
;; :vc (:url "https://github.com/positron-solutions/moc"))
|
:straight (:type git :host github
|
||||||
|
:repo "positron-solutions/moc"))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Select text, and call =moc-focus= (call =moc-focus-quit= to stop). Highlight more text, and call =moc-focus-highlight= to brighten it, or =moc-focus-obscure= to hide it.
|
Select text, and call =moc-focus= (call =moc-focus-quit= to stop). Highlight more text, and call =moc-focus-highlight= to brighten it, or =moc-focus-obscure= to hide it.
|
||||||
|
|
@ -271,7 +272,7 @@ The [[https://github.com/trevorpogue/topspace][topspace]] project can pad the to
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package topspace
|
(use-package topspace
|
||||||
;; :vc (:url "https://github.com/trevorpogue/topspace"))
|
:straight (:type git :host github :repo "trevorpogue/topspace"))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
*** Showing Something associated with a Headline
|
*** Showing Something associated with a Headline
|
||||||
|
|
@ -306,7 +307,7 @@ To do this, add =:DSLIDE_ACTIONS: dslide-action-highlight-paragraphs= to the pro
|
||||||
|
|
||||||
#+begin_src elisp emacs-lisp :tangle no
|
#+begin_src elisp emacs-lisp :tangle no
|
||||||
(use-package dslide
|
(use-package dslide
|
||||||
;; :vc (:url "https://github.com/positron-solutions/dslide")
|
:straight (:host github :repo "positron-solutions/dslide")
|
||||||
:config
|
:config
|
||||||
(defclass dslide-action-highlight-paragraphs (dslide-action)
|
(defclass dslide-action-highlight-paragraphs (dslide-action)
|
||||||
((overlays :initform nil))
|
((overlays :initform nil))
|
||||||
|
|
|
||||||
|
|
@ -63,19 +63,14 @@ To make the active window /more noticeable/, we /dim/ the in-active windows with
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package dimmer
|
(use-package dimmer
|
||||||
:custom (dimmer-adjustment-mode :foreground))
|
:custom (dimmer-adjustment-mode :foreground)
|
||||||
#+end_src
|
:config
|
||||||
|
;; I get issues with Magit and Dimmer, so let’s turn off this feature in certain windows:
|
||||||
|
(dimmer-configure-which-key) ; Do not dim these special windows
|
||||||
|
(dimmer-configure-hydra)
|
||||||
|
(dimmer-configure-magit)
|
||||||
|
|
||||||
I get issues with Magic and Dimmer, so let’s turn off this feature in certain windows:
|
(dimmer-mode t))
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(use-package dimmer
|
|
||||||
:config
|
|
||||||
(dimmer-configure-which-key) ; Do not dim these special windows
|
|
||||||
(dimmer-configure-hydra)
|
|
||||||
(dimmer-configure-magit)
|
|
||||||
|
|
||||||
(dimmer-mode t))
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
As an interesting alternative, check out the [[https://www.emacs.dyerdwelling.family/emacs/20240208164549-emacs-selected-window-accent-mode-now-on-melpa/][selected-window-accent]] project.
|
As an interesting alternative, check out the [[https://www.emacs.dyerdwelling.family/emacs/20240208164549-emacs-selected-window-accent-mode-now-on-melpa/][selected-window-accent]] project.
|
||||||
|
|
@ -86,10 +81,11 @@ either be "there or not" which resulted large jumps and large distractions.
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package ultra-scroll
|
(use-package ultra-scroll
|
||||||
;; :vc (:url "https://github.com/jdtsmith/ultra-scroll")
|
:straight (:type git :host github :repo "jdtsmith/ultra-scroll")
|
||||||
:config
|
:config
|
||||||
(setq scroll-conservatively 101 ; important!
|
(setq scroll-conservatively 101 ; important!
|
||||||
scroll-margin 0)
|
pixel-scroll-precision-interpolate-page t
|
||||||
|
scroll-margin 0)
|
||||||
(ultra-scroll-mode 1))
|
(ultra-scroll-mode 1))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
** Find the Bloody Cursor
|
** Find the Bloody Cursor
|
||||||
|
|
@ -97,7 +93,7 @@ Large screen, lots of windows, so where is the cursor? While I used to use =hl-l
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package pulsar
|
(use-package pulsar
|
||||||
;; :vc (:url "https://github.com/protesilaos/pulsar")
|
:straight (:host github :repo "protesilaos/pulsar")
|
||||||
:custom
|
:custom
|
||||||
(pulsar-face 'pulsar-generic)
|
(pulsar-face 'pulsar-generic)
|
||||||
(pulsar-delay 0.15)
|
(pulsar-delay 0.15)
|
||||||
|
|
@ -159,7 +155,7 @@ Am I ever really ever satisfied with any font? I regularly change my font based
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package mixed-pitch
|
(use-package mixed-pitch
|
||||||
;; ;; :vc (:url "https://github.com/jabranham/mixed-pitch")
|
;; :straight (:host github :repo "jabranham/mixed-pitch")
|
||||||
:config
|
:config
|
||||||
(add-to-list 'mixed-pitch-fixed-pitch-faces 'org-property-value)
|
(add-to-list 'mixed-pitch-fixed-pitch-faces 'org-property-value)
|
||||||
(add-to-list 'mixed-pitch-fixed-pitch-faces 'org-special-keyword)
|
(add-to-list 'mixed-pitch-fixed-pitch-faces 'org-special-keyword)
|
||||||
|
|
@ -389,7 +385,7 @@ This project replaces [[https://github.com/domtronn/all-the-icons.el][all-the-ic
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package nerd-icons
|
(use-package nerd-icons
|
||||||
;; :vc (:url "https://github.com/rainstormstudio/nerd-icons.el")
|
:straight (nerd-icons :type git :host github :repo "rainstormstudio/nerd-icons.el")
|
||||||
:custom
|
:custom
|
||||||
;; The Nerd Font you want to use in GUI defaults to fixed-font:
|
;; The Nerd Font you want to use in GUI defaults to fixed-font:
|
||||||
(nerd-icons-font-family ha-fixed-font))
|
(nerd-icons-font-family ha-fixed-font))
|
||||||
|
|
@ -638,7 +634,7 @@ In code, if you drop a specific /text/ labels, we can highlight them with [[http
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package hl-todo
|
(use-package hl-todo
|
||||||
;; :vc (:url "https://github.com/tarsius/hl-todo")
|
:straight (:host github :repo "tarsius/hl-todo")
|
||||||
:config
|
:config
|
||||||
(setq hl-todo-keyword-faces
|
(setq hl-todo-keyword-faces
|
||||||
`(("TODO" . ,(face-foreground 'warning))
|
`(("TODO" . ,(face-foreground 'warning))
|
||||||
|
|
@ -654,14 +650,16 @@ Suggests to bind some keys to =hl-todo-next= in order to jump from tag to tag, b
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package consult-todo
|
(use-package consult-todo
|
||||||
;; :vc (:url "https://github.com/liuyinz/consult-todo")
|
:straight (:host github :repo "liuyinz/consult-todo")
|
||||||
:init
|
:init
|
||||||
(defconst consult-todo--narrow
|
(defconst consult-todo--narrow
|
||||||
'((?t . "TODO")
|
'((?t . "TODO")
|
||||||
(?f . "FIXME")
|
(?f . "FIXME")
|
||||||
(?n . "NOTE"))
|
(?n . "NOTE"))
|
||||||
"Mapping of narrow and keywords.")
|
"Mapping of narrow and keywords.")
|
||||||
:general (:states 'normal "g t" '("jump todos" . consult-todo)))
|
;; :config
|
||||||
|
;; (evil-define-key '(normal) 'global "g t" '("jump todos" . consult-todo))
|
||||||
|
)
|
||||||
#+end_src
|
#+end_src
|
||||||
* Full Size Frame
|
* Full Size Frame
|
||||||
Taken from [[https://emacsredux.com/blog/2020/12/04/maximize-the-emacs-frame-on-startup/][this essay]], I figured I would start the initial frame automatically in fullscreen, but not any subsequent frames (as this could be part of the capturing system).
|
Taken from [[https://emacsredux.com/blog/2020/12/04/maximize-the-emacs-frame-on-startup/][this essay]], I figured I would start the initial frame automatically in fullscreen, but not any subsequent frames (as this could be part of the capturing system).
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ Also, let's do some basic configuration of Emacs' mail system:
|
||||||
|
|
||||||
Create a special mail perspective:
|
Create a special mail perspective:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader "a M" `("mail" . ,(ha-app-perspective "mail" #'notmuch)))
|
(ha-leader "a M" `("mail" . ,(ha-tab-bar-new "mail" #'notmuch)))
|
||||||
#+end_src
|
#+end_src
|
||||||
* Configuration
|
* Configuration
|
||||||
Do I want to sign messages by default? Nope.
|
Do I want to sign messages by default? Nope.
|
||||||
|
|
@ -737,7 +737,7 @@ The idea of linking org documents to email could be nice, however, the =ol-notmu
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package ol-notmuch
|
(use-package ol-notmuch
|
||||||
:after org
|
:after org
|
||||||
|
:straight (:type built-in)
|
||||||
:config (add-to-list 'org-modules 'ol-notmuch))
|
:config (add-to-list 'org-modules 'ol-notmuch))
|
||||||
#+end_src
|
#+end_src
|
||||||
To use, read a message and save a link to it with ~SPC o l~. Next, in an org document, create a link with ~, l~. Now, you can return to the message from that document with ~, o~. Regardless, I may need to store a local copy when I upgrade Org.
|
To use, read a message and save a link to it with ~SPC o l~. Next, in an org document, create a link with ~, l~. Now, you can return to the message from that document with ~, o~. Regardless, I may need to store a local copy when I upgrade Org.
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ If you find the documentation lacking, I [[http://www.howardism.org/Technical/Em
|
||||||
Tell straight to use the built-in =eshell=:
|
Tell straight to use the built-in =eshell=:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package eshell
|
(use-package eshell
|
||||||
|
:straight (:type built-in)
|
||||||
:hook (eshell-mode . ha-eshell-setup))
|
:hook (eshell-mode . ha-eshell-setup))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
@ -976,7 +976,7 @@ The problem with this trick is that =rx= outputs an Emacs-compatible regular exp
|
||||||
The [[https://github.com/joddie/pcre2el][pcre2el]] project can convert from a Lisp regular expression to a [[http://www.pcre.org/][PCRE]] (Perl Compatible Regular Expression), acceptable by [[https://github.com/BurntSushi/ripgrep][ripgrep]].
|
The [[https://github.com/joddie/pcre2el][pcre2el]] project can convert from a Lisp regular expression to a [[http://www.pcre.org/][PCRE]] (Perl Compatible Regular Expression), acceptable by [[https://github.com/BurntSushi/ripgrep][ripgrep]].
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package pcre2el
|
(use-package pcre2el
|
||||||
;; :vc (:url "https://github.com/joddie/pcre2el")
|
:straight (:host github :repo "joddie/pcre2el")
|
||||||
:config
|
:config
|
||||||
(defmacro prx (&rest expressions)
|
(defmacro prx (&rest expressions)
|
||||||
"Convert the rx-compatible regular EXPRESSIONS to PCRE.
|
"Convert the rx-compatible regular EXPRESSIONS to PCRE.
|
||||||
|
|
@ -1378,7 +1378,7 @@ The [[https://codeberg.org/akib/emacs-eat][Emulate a Terminal]] project provides
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package eat
|
(use-package eat
|
||||||
:after eshell
|
:after eshell
|
||||||
;; :vc (:url "https://codeberg.org/akib/emacs-eat")
|
:straight (:repo "https://codeberg.org/akib/emacs-eat")
|
||||||
:hook (eshell-load . eat-eshell-visual-command-mode))
|
:hook (eshell-load . eat-eshell-visual-command-mode))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
@ -1787,7 +1787,7 @@ Sometimes you need to change something about the current file you are editing...
|
||||||
Here is where we associate all the functions and their hooks with =eshell=, through the magic of =use-package=.
|
Here is where we associate all the functions and their hooks with =eshell=, through the magic of =use-package=.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package eshell
|
(use-package eshell
|
||||||
|
:straight (:type built-in)
|
||||||
:custom (eshell-banner-message '(ha-eshell-banner))
|
:custom (eshell-banner-message '(ha-eshell-banner))
|
||||||
:init
|
:init
|
||||||
(setq eshell-error-if-no-glob t
|
(setq eshell-error-if-no-glob t
|
||||||
|
|
|
||||||
|
|
@ -402,7 +402,7 @@ Where I like to align, is on variable assignments, e.g.
|
||||||
If you press ~RETURN~ for the /character/ to align, =evil-lion= package simply calls the built-in [[help:align][align]] function. This function chooses a regular expression based on a list of /rules/, and aligning Lisp variables requires a complicated regular expression. Extend [[elisp:(describe-variable 'align-rules-list)][align-rules-list]]:
|
If you press ~RETURN~ for the /character/ to align, =evil-lion= package simply calls the built-in [[help:align][align]] function. This function chooses a regular expression based on a list of /rules/, and aligning Lisp variables requires a complicated regular expression. Extend [[elisp:(describe-variable 'align-rules-list)][align-rules-list]]:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package align
|
(use-package align
|
||||||
|
:straight (:type built-in)
|
||||||
:config
|
:config
|
||||||
(add-to-list 'align-rules-list
|
(add-to-list 'align-rules-list
|
||||||
`("lisp-assignments"
|
`("lisp-assignments"
|
||||||
|
|
@ -489,9 +489,8 @@ Notes:
|
||||||
** Evil Jump, er Better Jump
|
** Evil Jump, er Better Jump
|
||||||
The [[https//github.com/gilbertw1/better-jumper][better-jumper project]] replaces the [[https://github.com/bling/evil-jumper][evil-jumper project]], essentially allowing you jump back to various movements. While I already use ~g ;~ to jump to the last change, this jumps /to the jumps/ … kinda. I’m having a difficult time determining /what jumps/ are remembered.
|
The [[https//github.com/gilbertw1/better-jumper][better-jumper project]] replaces the [[https://github.com/bling/evil-jumper][evil-jumper project]], essentially allowing you jump back to various movements. While I already use ~g ;~ to jump to the last change, this jumps /to the jumps/ … kinda. I’m having a difficult time determining /what jumps/ are remembered.
|
||||||
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp
|
||||||
(use-package better-jumper
|
(use-package better-jumper
|
||||||
;; :vc (:url "https//github.com/gilbertw1/better-jumper")
|
|
||||||
:config
|
:config
|
||||||
(better-jumper-mode +1)
|
(better-jumper-mode +1)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ According to Ben Maughan and [[http://pragmaticemacs.com/emacs/to-eww-or-not-to-
|
||||||
|
|
||||||
And some global keys to display them in the =apps= menu:
|
And some global keys to display them in the =apps= menu:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader "a f" `("feed reader" . ,(ha-app-perspective "elfeed" #'elfeed)))
|
(ha-leader "a f" `("feed reader" . ,(ha-tab-bar-new "elfeed" #'elfeed)))
|
||||||
#+end_src
|
#+end_src
|
||||||
* The Feeds :elfeed:
|
* 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!
|
The [[https://github.com/remyhonig/elfeed-org][elfeed-org]] project configures =elfeed= to read the RSS feeds from an Org file … like this one!
|
||||||
|
|
|
||||||
|
|
@ -335,9 +335,8 @@ And the collection of useful operations:
|
||||||
"b O" '("other" . project-switch-buffer-to-other-window)
|
"b O" '("other" . project-switch-buffer-to-other-window)
|
||||||
"b i" '("ibuffer" . ibuffer)
|
"b i" '("ibuffer" . ibuffer)
|
||||||
"b I" '("ibuffer" . ibuffer-other-window)
|
"b I" '("ibuffer" . ibuffer-other-window)
|
||||||
"b k" '("persp remove" . persp-remove-buffer)
|
|
||||||
"b N" '("new" . evil-buffer-new)
|
"b N" '("new" . evil-buffer-new)
|
||||||
"b d" '("delete" . persp-kill-buffer*)
|
"b d" '("delete" . kill-buffer)
|
||||||
"b r" '("revert" . revert-buffer)
|
"b r" '("revert" . revert-buffer)
|
||||||
"b s" '("save" . save-buffer)
|
"b s" '("save" . save-buffer)
|
||||||
"b S" '("save all" . evil-write-all)
|
"b S" '("save all" . evil-write-all)
|
||||||
|
|
@ -521,6 +520,7 @@ The goal here is toggle switches and other miscellaneous settings.
|
||||||
"t T" '("tramp mode" . tramp-mode)
|
"t T" '("tramp mode" . tramp-mode)
|
||||||
"t v" '("visual" . visual-line-mode)
|
"t v" '("visual" . visual-line-mode)
|
||||||
"t w" '("whitespace" . whitespace-mode)
|
"t w" '("whitespace" . whitespace-mode)
|
||||||
|
"t <tab>" '("tab-bar" . tab-bar-mode)
|
||||||
|
|
||||||
"t <escape>" '(keyboard-escape-quit :which-key t)
|
"t <escape>" '(keyboard-escape-quit :which-key t)
|
||||||
"t C-g" '(keyboard-escape-quit :which-key t))
|
"t C-g" '(keyboard-escape-quit :which-key t))
|
||||||
|
|
@ -546,13 +546,10 @@ And put it on the toggle menu:
|
||||||
(ha-leader "t n" '("narrow" . ha-narrow-dwim))
|
(ha-leader "t n" '("narrow" . ha-narrow-dwim))
|
||||||
#+end_src
|
#+end_src
|
||||||
* Window Operations
|
* Window Operations
|
||||||
While it comes with Emacs, I use [[https://www.emacswiki.org/emacs/WinnerMode][winner-mode]] to undo window-related changes:
|
While it comes with Emacs, the =tab-bar= feature keeps track of all window configurations within a tab, allowing me to revert situations where I accidentally delete all the windows.
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package winner
|
(tab-bar-history-mode)
|
||||||
:custom
|
|
||||||
(winner-dont-bind-my-keys t)
|
|
||||||
:config
|
|
||||||
(winner-mode +1))
|
|
||||||
#+end_src
|
#+end_src
|
||||||
** Ace Window
|
** Ace Window
|
||||||
Use the [[https://github.com/abo-abo/ace-window][ace-window]] project to jump to any window you see.
|
Use the [[https://github.com/abo-abo/ace-window][ace-window]] project to jump to any window you see.
|
||||||
|
|
@ -880,7 +877,7 @@ Remember these keys in the *Help* buffer:
|
||||||
Let's make Info behave a little more VI-like:
|
Let's make Info behave a little more VI-like:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package info
|
(use-package info
|
||||||
|
:straight (:type built-in)
|
||||||
:general
|
:general
|
||||||
(:states 'normal :keymaps 'Info-mode-map
|
(:states 'normal :keymaps 'Info-mode-map
|
||||||
"B" 'Info-bookmark-jump
|
"B" 'Info-bookmark-jump
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ Quick way to start and jump to my IRC world.
|
||||||
|
|
||||||
And some global keys to display them:
|
And some global keys to display them:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(ha-leader "a i" `("irc" . ,(ha-app-perspective "irc" #'ha-erc)))
|
(ha-leader "a i" `("irc" . ,(ha-tab-bar-new "irc" #'ha-erc)))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
And a quick shortcuts to call it:
|
And a quick shortcuts to call it:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#+author: Howard Abrams
|
#+author: Howard Abrams
|
||||||
#+date: 2024-07-07
|
#+date: 2024-07-07
|
||||||
#+filetags: emacs hamacs
|
#+filetags: emacs hamacs
|
||||||
#+lastmod: [2025-09-09 Tue]
|
#+lastmod: [2025-02-20 Thu]
|
||||||
|
|
||||||
A literate programming file for literate programming in Emacs Org Files.
|
A literate programming file for literate programming in Emacs Org Files.
|
||||||
|
|
||||||
|
|
@ -862,13 +862,11 @@ I would like to make the /filename/ more readable, I use the =s-match= again, to
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(defun ha-hamacs-edit--file-title (file)
|
(defun ha-hamacs-edit--file-title (file)
|
||||||
"Return a more readable string from FILE."
|
"Return a more readable string from FILE."
|
||||||
(if file
|
(s-with file
|
||||||
(s-with file
|
(s-match ha-hamacs-edit-file-to-title)
|
||||||
(s-match ha-hamacs-edit-file-to-title)
|
(second)
|
||||||
(second)
|
(s-replace "-" " ")
|
||||||
(s-replace "-" " ")
|
(s-titleize)))
|
||||||
(s-titleize))
|
|
||||||
file))
|
|
||||||
|
|
||||||
(defvar ha-hamacs-edit-file-to-title
|
(defvar ha-hamacs-edit-file-to-title
|
||||||
(rx (optional (or "README-" "ha-"))
|
(rx (optional (or "README-" "ha-"))
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ The RSS needs UUIDs:
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp results silent
|
#+BEGIN_SRC emacs-lisp results silent
|
||||||
(use-package uuidgen
|
(use-package uuidgen
|
||||||
;; :vc (:url "https://github.com/emacsmirror/uuidgen"))
|
:straight (:host github :repo "emacsmirror/uuidgen"))
|
||||||
|
|
||||||
(defun org-icalendar-create-uid (&rest ignored)
|
(defun org-icalendar-create-uid (&rest ignored)
|
||||||
"Returns a UUID."
|
"Returns a UUID."
|
||||||
|
|
@ -42,7 +42,7 @@ While the following packages come with Emacs, they aren't necessarily loaded:
|
||||||
|
|
||||||
#+begin_src emacs-lisp :results silent
|
#+begin_src emacs-lisp :results silent
|
||||||
(use-package ox-rss
|
(use-package ox-rss
|
||||||
;; :vc (:url "https://github.com/emacsmirror/ox-rss"))
|
:straight (:host github :repo "emacsmirror/ox-rss"))
|
||||||
|
|
||||||
(use-package org
|
(use-package org
|
||||||
:config
|
:config
|
||||||
|
|
@ -64,7 +64,7 @@ Render my code with my font colors:
|
||||||
Also, we need Jack, and his HTML prowess:
|
Also, we need Jack, and his HTML prowess:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package jack
|
(use-package jack
|
||||||
;; :vc (:url "https://github.com/tonyaldon/jack")
|
:straight (:host github :repo "tonyaldon/jack")
|
||||||
:commands (jack-html))
|
:commands (jack-html))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ The variable, =org-hide-emphasis-markers=, is key to pretending that Emacs can b
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-appear
|
(use-package org-appear
|
||||||
;; :vc (:url "https://github.com/awth13/org-appear")
|
:straight (:type git :host github :repo "awth13/org-appear")
|
||||||
:init (setq org-appear-trigger 'manual)
|
:init (setq org-appear-trigger 'manual)
|
||||||
:hook
|
:hook
|
||||||
((org-mode . (lambda ()
|
((org-mode . (lambda ()
|
||||||
|
|
@ -331,7 +331,7 @@ The [[https://github.com/minad/org-modern][org-modern]] project attempts to do a
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-modern
|
(use-package org-modern
|
||||||
;; :vc (:url "https://github.com/minad/org-modern")
|
:straight (:host github :repo "minad/org-modern")
|
||||||
:after org
|
:after org
|
||||||
:hook ((org-mode . org-modern-mode)
|
:hook ((org-mode . org-modern-mode)
|
||||||
(org-agenda-finalize . org-modern-agenda))
|
(org-agenda-finalize . org-modern-agenda))
|
||||||
|
|
@ -367,7 +367,7 @@ According to an idea by [[https://jft.home.blog/2019/07/17/use-unicode-symbol-to
|
||||||
The [[https://github.com/TonCherAmi/org-padding][org-padding]] project looks places extra space before and after headers and blocks (essentially leading), to create a more word-processor-y experience. Great idea, however, I have spent a lot of extra time entering blank lines before and after my headers and blocks:
|
The [[https://github.com/TonCherAmi/org-padding][org-padding]] project looks places extra space before and after headers and blocks (essentially leading), to create a more word-processor-y experience. Great idea, however, I have spent a lot of extra time entering blank lines before and after my headers and blocks:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-padding
|
(use-package org-padding
|
||||||
;; :vc (:url "https://github.com/TonCherAmi/org-padding")
|
:straight (:host github :repo "TonCherAmi/org-padding")
|
||||||
:hook (org-mode . org-padding-mode)
|
:hook (org-mode . org-padding-mode)
|
||||||
:config
|
:config
|
||||||
(setq org-padding-block-begin-line-padding '(0.5 . 0.3)
|
(setq org-padding-block-begin-line-padding '(0.5 . 0.3)
|
||||||
|
|
|
||||||
51
ha-org.org
51
ha-org.org
|
|
@ -3,7 +3,7 @@
|
||||||
#+date: 2020-09-18
|
#+date: 2020-09-18
|
||||||
#+tags: emacs org
|
#+tags: emacs org
|
||||||
#+startup: inlineimages
|
#+startup: inlineimages
|
||||||
#+lastmod: [2025-09-08 Mon]
|
#+lastmod: [2025-12-02 Tue]
|
||||||
|
|
||||||
A literate programming file for configuring org-mode and those files.
|
A literate programming file for configuring org-mode and those files.
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ Org is a /large/ complex beast with a gazillion settings, so I discuss these lat
|
||||||
#+begin_src emacs-lisp :noweb yes
|
#+begin_src emacs-lisp :noweb yes
|
||||||
(use-package org
|
(use-package org
|
||||||
;; TODO: Using the latest org-mode
|
;; TODO: Using the latest org-mode
|
||||||
;;
|
;; :straight (:type built-in)
|
||||||
:mode (("\\.org" . org-mode))
|
:mode (("\\.org" . org-mode))
|
||||||
:init
|
:init
|
||||||
<<variables>>
|
<<variables>>
|
||||||
|
|
@ -245,6 +245,32 @@ And I would like to have cute little icons for those states:
|
||||||
("^ +\\([-*]\\) "
|
("^ +\\([-*]\\) "
|
||||||
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•")))))))
|
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•")))))))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
What was
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun display-latest-clocked-task ()
|
||||||
|
"Display the name of the latest task that was clocked in."
|
||||||
|
(interactive)
|
||||||
|
(let ((latest-task (car (org-clock-get-clock-string))))
|
||||||
|
(if latest-task
|
||||||
|
(message "Latest clocked task: %s" latest-task)
|
||||||
|
(message "No task is currently clocked in."))))
|
||||||
|
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Need to be able to clock out of a task even if no /clock-in/ has occurred.
|
||||||
|
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun ha-clock-out ()
|
||||||
|
"Safely clock out of the current task.
|
||||||
|
This will not throw an error if not active clock exists."
|
||||||
|
(interactive)
|
||||||
|
(ignore-errors
|
||||||
|
(org-clock-out)
|
||||||
|
(message "Clocked out.")))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
** Meetings
|
** Meetings
|
||||||
I've notice that while showing a screen while taking meeting notes, I don't always like showing other windows, so I created this function to remove distractions during a meeting.
|
I've notice that while showing a screen while taking meeting notes, I don't always like showing other windows, so I created this function to remove distractions during a meeting.
|
||||||
|
|
||||||
|
|
@ -278,7 +304,7 @@ Came up with a great way to search a project for Org-specific files, and wrote [
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package org-find-file
|
(use-package org-find-file
|
||||||
|
:straight nil
|
||||||
:config
|
:config
|
||||||
(ha-leader "f o" '("load org" . org-find-file)))
|
(ha-leader "f o" '("load org" . org-find-file)))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
@ -489,12 +515,8 @@ Need to install and configure Emacs to work with [[https://plantuml.com/][PlantU
|
||||||
|
|
||||||
After installing the [[https://github.com/skuro/plantuml-mode][plantuml-mode]], we need to reference the location:
|
After installing the [[https://github.com/skuro/plantuml-mode][plantuml-mode]], we need to reference the location:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package deflate
|
|
||||||
:vc (:url "https://github.com/skuro/deflate.git"))
|
|
||||||
|
|
||||||
(use-package plantuml-mode
|
(use-package plantuml-mode
|
||||||
;; :vc (:url "https://github.com/skuro/plantuml-mode")
|
:straight (:host github :repo "skuro/plantuml-mode")
|
||||||
:after deflate
|
|
||||||
:init
|
:init
|
||||||
(setq org-plantuml-jar-path (expand-file-name "~/bin/plantuml.jar")))
|
(setq org-plantuml-jar-path (expand-file-name "~/bin/plantuml.jar")))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
@ -547,7 +569,8 @@ Of course, since we are dealing with Emacs, where we assimilate any good idea. J
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package pikchr-mode
|
(use-package pikchr-mode
|
||||||
;; :vc (:url "https://github.com/kljohann/pikchr-mode")
|
:straight (:local-repo "~/src/pikchr-mode")
|
||||||
|
;; :straight (:host github :repo "kljohann/pikchr-mode")
|
||||||
:custom
|
:custom
|
||||||
(pikchr-executable "~/bin/pikchr"))
|
(pikchr-executable "~/bin/pikchr"))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
@ -735,7 +758,7 @@ I have a special version of tweaked [[file:elisp/ox-confluence.el][Confluence ex
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ox-confluence
|
(use-package ox-confluence
|
||||||
:after org
|
:after org
|
||||||
; Located in my "elisp" directory
|
:straight nil ; Located in my "elisp" directory
|
||||||
:config
|
:config
|
||||||
(ha-leader :keymaps 'org-mode-map
|
(ha-leader :keymaps 'org-mode-map
|
||||||
"o E" '("to confluence" . ox-export-to-confluence)))
|
"o E" '("to confluence" . ox-export-to-confluence)))
|
||||||
|
|
@ -746,7 +769,7 @@ I have a special version of tweaked [[file:elisp/ox-confluence.el][Confluence ex
|
||||||
I’m not afraid of HTML, but I like the idea of doing my HTML work in a Lisp-like way using the [[https://github.com/tonyaldon/jack][jack-html project]]:
|
I’m not afraid of HTML, but I like the idea of doing my HTML work in a Lisp-like way using the [[https://github.com/tonyaldon/jack][jack-html project]]:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package jack
|
(use-package jack
|
||||||
;; :vc (:url "https://github.com/tonyaldon/jack")
|
:straight (:host github :repo "tonyaldon/jack")
|
||||||
:commands (jack-html))
|
:commands (jack-html))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
@ -803,7 +826,7 @@ I've been working on my own [[http://www.howardism.org/Technical/Emacs/focused-w
|
||||||
(use-package async)
|
(use-package async)
|
||||||
|
|
||||||
(use-package ha-focus
|
(use-package ha-focus
|
||||||
|
:straight (:type built-in)
|
||||||
:config
|
:config
|
||||||
(ha-leader
|
(ha-leader
|
||||||
"o f" '("begin focus" . ha-focus-begin)
|
"o f" '("begin focus" . ha-focus-begin)
|
||||||
|
|
@ -854,7 +877,7 @@ And the Emacs interface to that:
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package jinx
|
(use-package jinx
|
||||||
;; :vc (:url "https://github.com/minad/jinx" :files (:defaults "jinx-mod.c" "emacs-module.h"))
|
:straight (:host github :repo "minad/jinx" :files (:defaults "jinx-mod.c" "emacs-module.h"))
|
||||||
:hook (emacs-startup . global-jinx-mode)
|
:hook (emacs-startup . global-jinx-mode)
|
||||||
:bind (("C-;" . jinx-correct-nearest)
|
:bind (("C-;" . jinx-correct-nearest)
|
||||||
("s-;" . jinx-correct-nearest)
|
("s-;" . jinx-correct-nearest)
|
||||||
|
|
@ -1253,7 +1276,7 @@ The [[https://github.com/rnkn/olivetti][olivetti project]] sets wide margins and
|
||||||
Trying out [[https://protesilaos.com/][Protesilaos Stavrou]]’s [[https://protesilaos.com/emacs/logos][logos project]] as a replacement for [[https://github.com/joostkremers/writeroom-mode][Writeroom-mode]]:
|
Trying out [[https://protesilaos.com/][Protesilaos Stavrou]]’s [[https://protesilaos.com/emacs/logos][logos project]] as a replacement for [[https://github.com/joostkremers/writeroom-mode][Writeroom-mode]]:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package logos
|
(use-package logos
|
||||||
;; :vc (:url "https://gitlab.com/protesilaos/logos")
|
:straight (:host gitlab :repo "protesilaos/logos")
|
||||||
:init
|
:init
|
||||||
(setq logos-outlines-are-pages t
|
(setq logos-outlines-are-pages t
|
||||||
logos-outline-regexp-alist
|
logos-outline-regexp-alist
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ The obvious keybindings are ~M-h/j/k/l~ … but that is used … well, somewhat.
|
||||||
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package spatial-navigate
|
(use-package spatial-navigate
|
||||||
;; :vc (:url "https://codeberg.org/ideasman42/emacs-spatial-navigate")
|
:straight (:repo "https://codeberg.org/ideasman42/emacs-spatial-navigate")
|
||||||
:config
|
:config
|
||||||
(pretty-hydra-define spatial-navigate (:color amaranth :quit-key "q")
|
(pretty-hydra-define spatial-navigate (:color amaranth :quit-key "q")
|
||||||
("Box"
|
("Box"
|
||||||
|
|
@ -62,7 +62,7 @@ The [[https://github.com/antonj/Highlight-Indentation-for-Emacs][Highlight-Inden
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package highlight-indentation
|
(use-package highlight-indentation
|
||||||
;; :vc (:url "https://github.com/antonj/Highlight-Indentation-for-Emacs")
|
:straight (:host github :repo "antonj/Highlight-Indentation-for-Emacs")
|
||||||
:hook ((yaml-mode . highlight-indentation-mode)
|
:hook ((yaml-mode . highlight-indentation-mode)
|
||||||
(python-mode . highlight-indentation-mode)))
|
(python-mode . highlight-indentation-mode)))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
@ -119,7 +119,7 @@ Allow this mode in Org blocks:
|
||||||
And we hook
|
And we hook
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package yaml-pro
|
(use-package yaml-pro
|
||||||
;; :vc (:url "https://github.com/zkry/yaml-pro")
|
:straight (:host github :repo "zkry/yaml-pro")
|
||||||
:after yaml-mode
|
:after yaml-mode
|
||||||
:hook ((yaml-mode . yaml-pro-mode)))
|
:hook ((yaml-mode . yaml-pro-mode)))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
@ -224,7 +224,7 @@ Do I consider all YAML files an Ansible file needing [[https://github.com/k1LoW/
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ansible
|
(use-package ansible
|
||||||
;; :vc (:url "https://gitlab.com/emacs-ansible/emacs-ansible")
|
:straight (:host gitlab :repo "emacs-ansible/emacs-ansible")
|
||||||
;; :mode ((rx (or "playbooks" "roles") (one-or-more any) ".y" (optional "a") "ml") . ansible-mode)
|
;; :mode ((rx (or "playbooks" "roles") (one-or-more any) ".y" (optional "a") "ml") . ansible-mode)
|
||||||
:config
|
:config
|
||||||
(setq ansible-vault-password-file "~/.ansible-vault-passfile")
|
(setq ansible-vault-password-file "~/.ansible-vault-passfile")
|
||||||
|
|
@ -242,7 +242,7 @@ Since most Ansible files are a combination of YAML and Jinja, the [[https://gith
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package poly-ansible
|
(use-package poly-ansible
|
||||||
;; :vc (:url "https://github.com/emacsmirror/poly-ansible")
|
:straight (:host github :repo "emacsmirror/poly-ansible")
|
||||||
:after ansible)
|
:after ansible)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ The /real problem/ is trying to remember all the [[https://github.com/clojure-em
|
||||||
And of course, we want to put this with org blocks:
|
And of course, we want to put this with org blocks:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ob-clojure
|
(use-package ob-clojure
|
||||||
|
:straight (:type built-in)
|
||||||
:custom
|
:custom
|
||||||
(org-babel-clojure-backend 'cider)
|
(org-babel-clojure-backend 'cider)
|
||||||
:config
|
:config
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,7 @@ And we should extend it with the [[https://github.com/xuchunyang/elisp-demos][el
|
||||||
Wilfred’s [[https://github.com/Wilfred/suggest.el][suggest]] function helps you find the right function. Basically, you type in the parameters of a function, and then the desired output, and it will write the function call.
|
Wilfred’s [[https://github.com/Wilfred/suggest.el][suggest]] function helps you find the right function. Basically, you type in the parameters of a function, and then the desired output, and it will write the function call.
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package spinner
|
(use-package suggest)
|
||||||
:vc (:url "https://github.com/Malabarba/spinner.el"))
|
|
||||||
|
|
||||||
(use-package suggest
|
|
||||||
:after spinner)
|
|
||||||
#+end_src
|
#+end_src
|
||||||
* Navigation
|
* Navigation
|
||||||
** Goto Definitions
|
** Goto Definitions
|
||||||
|
|
@ -284,7 +280,7 @@ These are all good, but the primary keys I need to figure out, are the s-express
|
||||||
Wilfred’s [[https://github.com/Wilfred/emacs-refactor/tree/master#elisp][emacs-refactor]] package can be helpful if you turn on =context-menu-mode= and …
|
Wilfred’s [[https://github.com/Wilfred/emacs-refactor/tree/master#elisp][emacs-refactor]] package can be helpful if you turn on =context-menu-mode= and …
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package emr
|
(use-package emr
|
||||||
;; ;; :vc (:url "https://github.com/Wilfred/emacs-refactor")
|
;; :straight (:host github :repo "Wilfred/emacs-refactor")
|
||||||
:config
|
:config
|
||||||
(pretty-hydra-define+ lisp-refactor nil
|
(pretty-hydra-define+ lisp-refactor nil
|
||||||
("To 𝛌"
|
("To 𝛌"
|
||||||
|
|
@ -370,4 +366,3 @@ Let's =provide= a name so we can =require= this file:
|
||||||
#+options: num:nil toc:t todo:nil tasks:nil tags:nil date:nil
|
#+options: num:nil toc:t todo:nil tasks:nil tags:nil date:nil
|
||||||
#+options: skip:nil author:nil email:nil creator:nil timestamp:nil
|
#+options: skip:nil author:nil email:nil creator:nil timestamp:nil
|
||||||
#+infojs_opt: view:nil toc:t ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
#+infojs_opt: view:nil toc:t ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
||||||
exit
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ The [[https://github.com/mihaimaruseac/hindent][hindent package]] looks interest
|
||||||
* Haskell and Org
|
* Haskell and Org
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ob-haskell
|
(use-package ob-haskell
|
||||||
|
:straight (:type built-in)
|
||||||
:config
|
:config
|
||||||
(add-to-list 'org-babel-load-languages '(haskell . t)))
|
(add-to-list 'org-babel-load-languages '(haskell . t)))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,8 @@ The [[https://elpy.readthedocs.io/en/latest/introduction.html][Elpy Project]] ex
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package elpy
|
(use-package elpy
|
||||||
:config
|
:ensure t
|
||||||
|
:init
|
||||||
(elpy-enable))
|
(elpy-enable))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ The [[https://www.nongnu.org/geiser/][geiser project]] attempts to be the interf
|
||||||
Do we need a Scheme work for Org Babel? According to [[https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-scheme.html][this document]], we just need to make sure we add the =:session= variable to start the REPL.
|
Do we need a Scheme work for Org Babel? According to [[https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-scheme.html][this document]], we just need to make sure we add the =:session= variable to start the REPL.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ob-scheme
|
(use-package ob-scheme
|
||||||
|
:straight (:type built-in)
|
||||||
:config
|
:config
|
||||||
(add-to-list 'org-babel-load-languages '(scheme . t)))
|
(add-to-list 'org-babel-load-languages '(scheme . t)))
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ While Racket, as a Scheme, should work with Geiser (below), let’s also get [[h
|
||||||
Can we get Racket working with Org?
|
Can we get Racket working with Org?
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package ob-racket
|
(use-package ob-racket
|
||||||
;; :vc (:url "https://github.com/DEADB17/ob-racket")
|
:straight (:host github :repo "DEADB17/ob-racket")
|
||||||
:after org
|
:after org
|
||||||
:config
|
:config
|
||||||
(add-to-list 'org-babel-load-languages '(racket . t)))
|
(add-to-list 'org-babel-load-languages '(racket . t)))
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ For all programming languages, I would like to now default to absolute line numb
|
||||||
While Emacs has options for viewing and moving around code, sometimes, we could /collapse/ all functions, and then start to expand them one at a time. For this, we could enable the built-in [[https://www.emacswiki.org/emacs/HideShow][hide-show feature]]:
|
While Emacs has options for viewing and moving around code, sometimes, we could /collapse/ all functions, and then start to expand them one at a time. For this, we could enable the built-in [[https://www.emacswiki.org/emacs/HideShow][hide-show feature]]:
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package hide-show
|
(use-package hide-show
|
||||||
|
:straight (:type built-in)
|
||||||
:init
|
:init
|
||||||
(setq hs-hide-comments t
|
(setq hs-hide-comments t
|
||||||
hs-hide-initial-comment-block t
|
hs-hide-initial-comment-block t
|
||||||
|
|
@ -212,7 +212,7 @@ Why use [[https://www.flycheck.org/][flycheck]] over the built-in =flymake=? Spe
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package flycheck
|
(use-package flycheck
|
||||||
;; :vc (:url "https://github.com/flycheck/flycheck")
|
:straight (:host github :repo "flycheck/flycheck")
|
||||||
:init
|
:init
|
||||||
(setq next-error-message-highlight t)
|
(setq next-error-message-highlight t)
|
||||||
:bind (:map flycheck-error-list-mode-map
|
:bind (:map flycheck-error-list-mode-map
|
||||||
|
|
@ -400,7 +400,7 @@ However, Emacs already has the ability to download and install grammars, so foll
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when (treesit-available-p)
|
(when (treesit-available-p)
|
||||||
(use-package treesit
|
(use-package treesit
|
||||||
|
:straight (:type built-in)
|
||||||
:preface
|
:preface
|
||||||
(setq treesit-language-source-alist
|
(setq treesit-language-source-alist
|
||||||
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
|
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
|
||||||
|
|
@ -480,7 +480,7 @@ I like [[file:ha-programming-elisp.org::*Clever Parenthesis][Clever Parenthesis]
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(when (treesit-available-p)
|
(when (treesit-available-p)
|
||||||
(use-package combobulate
|
(use-package combobulate
|
||||||
;; :vc (:url "https://github.com/mickeynp/combobulate")
|
:straight (:host github :repo "mickeynp/combobulate")
|
||||||
:after treesit
|
:after treesit
|
||||||
:hook ((yaml-ts-mode . combobulate-mode)
|
:hook ((yaml-ts-mode . combobulate-mode)
|
||||||
;; (css-ts-mode . combobulate-mode)
|
;; (css-ts-mode . combobulate-mode)
|
||||||
|
|
@ -730,7 +730,7 @@ The [[https://github.com/emacs-lsp/lsp-ui/blob/master/lsp-ui-imenu.el][lsp-imenu
|
||||||
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
#+begin_src emacs-lisp :tangle no
|
||||||
(use-package lsp-ui-imenu
|
(use-package lsp-ui-imenu
|
||||||
|
:straight nil
|
||||||
:after lsp-ui
|
:after lsp-ui
|
||||||
:config
|
:config
|
||||||
(ha-local-leader :keymaps 'prog-mode-map
|
(ha-local-leader :keymaps 'prog-mode-map
|
||||||
|
|
@ -1089,7 +1089,7 @@ This means, that some data like:
|
||||||
"data": {
|
"data": {
|
||||||
"name": "Create And Wait for Service Image",
|
"name": "Create And Wait for Service Image",
|
||||||
"description": "Creates a new Service Image using IMaaS",
|
"description": "Creates a new Service Image using IMaaS",
|
||||||
"long_description": "This job creates a new yawxway service image with name yawxway-howard.abrams-test and docker-dev-artifactory.workday.com/dev/yawxway-service:latest docker url in development folder",
|
"long_description": "This job creates a new service image with name ... blah, blah, blah",
|
||||||
"job_id": "5e077245-0f4a-4dc9-b473-ce3ec0b811ba",
|
"job_id": "5e077245-0f4a-4dc9-b473-ce3ec0b811ba",
|
||||||
"state": "success",
|
"state": "success",
|
||||||
"progress": "100",
|
"progress": "100",
|
||||||
|
|
@ -1296,12 +1296,12 @@ While I don't like writing them, I can't get away from them. Check out the goodi
|
||||||
While filename extensions work fine most of the time, I don't like to pre-pend =.sh= to the shell scripts I write, and instead, would like to associate =shell-mode= with all files in a =bin= directory:
|
While filename extensions work fine most of the time, I don't like to pre-pend =.sh= to the shell scripts I write, and instead, would like to associate =shell-mode= with all files in a =bin= directory:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package sh-mode
|
(use-package sh-mode
|
||||||
|
:straight (:type built-in)
|
||||||
:mode (rx (or (seq ".sh" eol)
|
:mode (rx (or (seq ".sh" eol)
|
||||||
"/bin/"))
|
"/bin/"))
|
||||||
:init
|
:init
|
||||||
(setq sh-basic-offset 2
|
(setq sh-basic-offset 4
|
||||||
sh-indentation 2)
|
sh-indentation 4)
|
||||||
:config
|
:config
|
||||||
(ha-auto-insert-file (rx (or (seq ".sh" eol)
|
(ha-auto-insert-file (rx (or (seq ".sh" eol)
|
||||||
"/bin/"))
|
"/bin/"))
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ A literate configuration for accessing remote systems.
|
||||||
[[https://www.emacswiki.org/emacs/TrampMode][Tramp]] allows almost all Emacs features to execute on a remote system.
|
[[https://www.emacswiki.org/emacs/TrampMode][Tramp]] allows almost all Emacs features to execute on a remote system.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package tramp
|
(use-package tramp
|
||||||
|
:straight (:type built-in)
|
||||||
|
|
||||||
:config
|
:config
|
||||||
;; Use remote PATH on tramp (handy for eshell).
|
;; Use remote PATH on tramp (handy for eshell).
|
||||||
|
|
@ -42,7 +42,7 @@ A literate configuration for accessing remote systems.
|
||||||
Will Schenk has [[https://willschenk.com/articles/2020/tramp_tricks/][a simple extension]] to allow editing of files /inside/ a Docker container:
|
Will Schenk has [[https://willschenk.com/articles/2020/tramp_tricks/][a simple extension]] to allow editing of files /inside/ a Docker container:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package tramp
|
(use-package tramp
|
||||||
|
:straight (:type built-in)
|
||||||
:config
|
:config
|
||||||
(push '("docker" . ((tramp-login-program "docker")
|
(push '("docker" . ((tramp-login-program "docker")
|
||||||
(tramp-login-args (("exec" "-it") ("%h") ("/bin/sh")))
|
(tramp-login-args (("exec" "-it") ("%h") ("/bin/sh")))
|
||||||
|
|
@ -72,7 +72,7 @@ Which means, I need to put it as a link in an org file.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package tramp-sh
|
(use-package tramp-sh
|
||||||
:after tramp
|
:after tramp
|
||||||
|
:straight (:type built-in)
|
||||||
:custom (tramp-use-ssh-controlmaster-options nil))
|
:custom (tramp-use-ssh-controlmaster-options nil))
|
||||||
#+end_src
|
#+end_src
|
||||||
* Remote Terminals
|
* Remote Terminals
|
||||||
|
|
@ -159,13 +159,12 @@ While not as fast as [[https://github.com/akermu/emacs-libvterm][vterm]], the [[
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp :tangle no
|
#+BEGIN_SRC emacs-lisp :tangle no
|
||||||
(use-package eat
|
(use-package eat
|
||||||
;; :straight (:host codeberg :repo "akib/emacs-eat"
|
:straight (:host codeberg :repo "akib/emacs-eat"
|
||||||
;; :files ("*.el" ("term" "term/*.el") "*.texi"
|
:files ("*.el" ("term" "term/*.el") "*.texi"
|
||||||
;; "*.ti" ("terminfo/e" "terminfo/efo/e/*")
|
"*.ti" ("terminfo/e" "terminfo/efo/e/*")
|
||||||
;; ("terminfo/65" "terminfo/65/*")
|
("terminfo/65" "terminfo/65/*")
|
||||||
;; ("integration" "integration/*")
|
("integration" "integration/*")
|
||||||
;; (:exclude ".dir-locals.el" "*-tests.el")))
|
(:exclude ".dir-locals.el" "*-tests.el")))
|
||||||
;; :vc (:url "https://codeberg.org/akib/emacs-eat")
|
|
||||||
:commands (eat eat-make eat-project)
|
:commands (eat eat-make eat-project)
|
||||||
:bind (:map eat-semi-char-mode-map
|
:bind (:map eat-semi-char-mode-map
|
||||||
("C-c C-t" . ha-eat-narrow-to-shell-prompt-dwim))
|
("C-c C-t" . ha-eat-narrow-to-shell-prompt-dwim))
|
||||||
|
|
@ -215,14 +214,6 @@ Let's begin by defining some variables used for communication between the functi
|
||||||
See =ha-ssh-add-favorite-host= for easily adding to this list.")
|
See =ha-ssh-add-favorite-host= for easily adding to this list.")
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Also, let's make it easy for me to change my default shell:
|
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
|
||||||
(defvar ha-shell "bash" ;; Eat works better with Bash/Zsh
|
|
||||||
;; (string-trim (shell-command-to-string "type -p fish"))
|
|
||||||
"The executable to the shell I want to use locally.")
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
** Terminal Abstractions
|
** Terminal Abstractions
|
||||||
Could I abstract the different ways I start terminals in Emacs? The =ha-ssh-term= starts either a [[VTerm]]
|
Could I abstract the different ways I start terminals in Emacs? The =ha-ssh-term= starts either a [[VTerm]]
|
||||||
or [[Eat]] terminals, depending on what is available. This replaces (wraps) the default [[help:make-term][make-term]].
|
or [[Eat]] terminals, depending on what is available. This replaces (wraps) the default [[help:make-term][make-term]].
|
||||||
|
|
@ -233,11 +224,11 @@ or [[Eat]] terminals, depending on what is available. This replaces (wraps) the
|
||||||
The PROGRAM, if non-nil, is executed, otherwise, this is `ha-shell'.
|
The PROGRAM, if non-nil, is executed, otherwise, this is `ha-shell'.
|
||||||
STARTFILE is the initial text given to the PROGRAM, and the
|
STARTFILE is the initial text given to the PROGRAM, and the
|
||||||
SWITCHES are the command line options."
|
SWITCHES are the command line options."
|
||||||
(unless program (setq program ha-shell))
|
|
||||||
(cond
|
(cond
|
||||||
((fboundp 'vterm) (progn (vterm name)
|
((fboundp 'vterm) (progn (vterm name)
|
||||||
(vterm-send-string (append program switches))
|
(when program
|
||||||
(vterm-send-return)))
|
(vterm-send-string (append program switches))
|
||||||
|
(vterm-send-return))))
|
||||||
((fboundp 'eat) (progn (switch-to-buffer
|
((fboundp 'eat) (progn (switch-to-buffer
|
||||||
(apply 'eat-make (append (list name program startfile)
|
(apply 'eat-make (append (list name program startfile)
|
||||||
switches)))
|
switches)))
|
||||||
|
|
@ -301,7 +292,7 @@ For the sake of my demonstrations, I use =ha-shell= to start a terminal with a p
|
||||||
default-directory)))
|
default-directory)))
|
||||||
(buf-name (format "*%s*" win-name)))
|
(buf-name (format "*%s*" win-name)))
|
||||||
(setq ha-latest-ssh-window-name buf-name)
|
(setq ha-latest-ssh-window-name buf-name)
|
||||||
(ha-make-term win-name ha-shell))) ; Lisp-2 FTW!?
|
(ha-make-term win-name))) ; Lisp-2 FTW!?
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Now that Emacs can /host/ a Terminal shell, I would like to /programmatically/ send commands to the running terminal, e.g. =(ha-shell-send "ls *.py")= I would really like to be able to send and execute a command in a terminal from a script.
|
Now that Emacs can /host/ a Terminal shell, I would like to /programmatically/ send commands to the running terminal, e.g. =(ha-shell-send "ls *.py")= I would really like to be able to send and execute a command in a terminal from a script.
|
||||||
|
|
@ -326,8 +317,6 @@ Now that Emacs can /host/ a Terminal shell, I would like to /programmatically/ s
|
||||||
(t (progn
|
(t (progn
|
||||||
(insert command)
|
(insert command)
|
||||||
(term-send-input))))))
|
(term-send-input))))))
|
||||||
|
|
||||||
(ha-shell-send "exit")
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Let's have a quick way to bugger out of the terminal:
|
Let's have a quick way to bugger out of the terminal:
|
||||||
|
|
|
||||||
|
|
@ -323,8 +323,6 @@ Let’s make a /theme/:
|
||||||
'hamacs
|
'hamacs
|
||||||
`(default ((t (:foreground ,default-fg :background ,default-bg))))
|
`(default ((t (:foreground ,default-fg :background ,default-bg))))
|
||||||
`(fringe ((t :background ,default-bg)))
|
`(fringe ((t :background ,default-bg)))
|
||||||
`(tab-bar ((t :foreground ,default-fg :background ,default-bg)))
|
|
||||||
`(tab-line ((t :foreground ,default-fg :background ,default-bg)))
|
|
||||||
`(window-divider ((t :foreground "black")))
|
`(window-divider ((t :foreground "black")))
|
||||||
`(cursor ((t (:foreground ,gray-10 :background ,cursor))))
|
`(cursor ((t (:foreground ,gray-10 :background ,cursor))))
|
||||||
`(region ((t (:background ,region))))
|
`(region ((t (:background ,region))))
|
||||||
|
|
@ -333,6 +331,11 @@ Let’s make a /theme/:
|
||||||
`(mode-line-active ((t (:background ,active))))
|
`(mode-line-active ((t (:background ,active))))
|
||||||
`(mode-line-inactive ((t (:background ,inactive))))
|
`(mode-line-inactive ((t (:background ,inactive))))
|
||||||
|
|
||||||
|
`(tab-bar ((t :foreground ,default-fg :background ,default-bg)))
|
||||||
|
`(tab-line ((t :foreground ,default-fg :background ,default-bg)))
|
||||||
|
`(tab-bar-tab ((t (:inherit variable-pitch :background ,active))))
|
||||||
|
`(tab-bar-tab-inactive ((t (:inherit variable-pitch :background ,inactive))))
|
||||||
|
|
||||||
`(doom-modeline-buffer-path ((t (:foreground ,almond))))
|
`(doom-modeline-buffer-path ((t (:foreground ,almond))))
|
||||||
`(doom-modeline-buffer-file ((t (:foreground "white" :weight bold))))
|
`(doom-modeline-buffer-file ((t (:foreground "white" :weight bold))))
|
||||||
`(doom-modeline-buffer-major-mode ((t (:foreground ,almond))))
|
`(doom-modeline-buffer-major-mode ((t (:foreground ,almond))))
|
||||||
|
|
|
||||||
267
hammerspoon.org
Normal file
267
hammerspoon.org
Normal file
|
|
@ -0,0 +1,267 @@
|
||||||
|
#+title: Hammerspoon Configuration
|
||||||
|
#+author: Howard X. Abrams
|
||||||
|
#+date: 2025-11-24
|
||||||
|
#+filetags: emacs hamacs
|
||||||
|
#+lastmod: [2025-12-02 Tue]
|
||||||
|
|
||||||
|
A literate programming file for configuring Hammerspoon.
|
||||||
|
|
||||||
|
* Introduction
|
||||||
|
Ever since I got a Mac, I’ve used various tools to /script/ it. With my limited number of applications, my UI needs are simple (I mean, what more do you need once Emacs is in full screen). That said, I’ve been using [[https://hammerspoon.org][Hammerspoon]] for those few needs. While I refer to the [[https://www.hammerspoon.org/docs/index.html][standard documentation]], I often steal snippets of code from others.
|
||||||
|
|
||||||
|
Simple to use. Use =hs.execute= to run a script, =ha.alert.show= to print a small message on the screen, and for something longer:
|
||||||
|
#+BEGIN_SRC lua :tangle no
|
||||||
|
hs.notify.new({title="Hammerspoon", informativeText="Hello World"}):send()
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Shortcut Keybindings
|
||||||
|
I’ve created left and right ~Meh~ keys on my Moonlanders:
|
||||||
|
- Left Meh Key: ~C-M-S-s~ (Control Option/Meta Command Shift)
|
||||||
|
- Right Meh Key: ~C-M-S~ (Control Option/Meta Shift)
|
||||||
|
|
||||||
|
To create special key bindings, I can:
|
||||||
|
#+BEGIN_SRC lua
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- Launcher replaces iCanHazShortcuts
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "T", function()
|
||||||
|
hs.application.launchOrFocus("iTerm")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "S", function()
|
||||||
|
hs.application.launchOrFocus("Slack")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "W", function()
|
||||||
|
hs.application.launchOrFocus("Spotify")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "F", function()
|
||||||
|
hs.application.launchOrFocus("Firefox")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "C", function()
|
||||||
|
-- hs.osascript.applescriptFromFile("~/bin/chrome.scr")
|
||||||
|
hs.execute("~/bin/chrome.scr")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "B", function()
|
||||||
|
hs.application.launchOrFocus("Microsoft Outlook")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "Z", function()
|
||||||
|
hs.application.launchOrFocus("zoom.us")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "A", function()
|
||||||
|
hs.application.launchOrFocus("Cursor")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "Q", function()
|
||||||
|
hs.application.launchOrFocus("KeepassXC")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "E", function()
|
||||||
|
hs.execute("FOR_WORK=yes open -a /Applications/Emacs.app")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Special Emacs Guys
|
||||||
|
-- Right Meh key:
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "X", function()
|
||||||
|
hs.execute("~/bin/emacs-capture")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Left Meh key:
|
||||||
|
hs.hotkey.bind({"cmd", "alt", "ctrl", "shift"}, "X", function()
|
||||||
|
hs.execute("~/bin/emacs-capture-clock")
|
||||||
|
end)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"alt", "ctrl", "shift"}, "M", function()
|
||||||
|
hs.execute("~/bin/emacs-capture-meeting")
|
||||||
|
end)
|
||||||
|
#+END_SRC
|
||||||
|
* Zoom
|
||||||
|
Library extensions to Hammerspoon are called /spoons/, and most of these are a simple Lua script, =init.lua= stored in the =Spoons= subdirectory. We grab these with a =git clone=, typically. To use the Zoom spoon, clone it:
|
||||||
|
|
||||||
|
#+BEGIN_SRC sh :dir ~/.hammerspoon/Spoons :tangle no :results silent
|
||||||
|
git clone https://github.com/jpf/Zoom.spoon.git
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
I noticed that it does its works by calling Zoom’s menus, and with the latest version of Zoom, they changed the /case/ of the menu, meaning that I needed to create a pull request.
|
||||||
|
|
||||||
|
From this [[https://developer.okta.com/blog/2020/10/22/set-up-a-mute-indicator-light-for-zoom-with-hammerspoon][nice essay]], we create a menu bar item that shows the status, as well as allowing me to click it to toggle:
|
||||||
|
|
||||||
|
#+BEGIN_SRC lua
|
||||||
|
zoomStatusMenuBarItem = hs.menubar.new(true)
|
||||||
|
zoomStatusMenuBarItem:setClickCallback(function()
|
||||||
|
spoon.Zoom:toggleMute()
|
||||||
|
end)
|
||||||
|
|
||||||
|
updateZoomStatus = function(event)
|
||||||
|
hs.printf("updateZoomStatus(%s)", event)
|
||||||
|
if (event == "from-running-to-meeting") then
|
||||||
|
zoomStatusMenuBarItem:returnToMenuBar()
|
||||||
|
elseif (event == "muted") then
|
||||||
|
zoomStatusMenuBarItem:setTitle("🔴")
|
||||||
|
elseif (event == "unmuted") then
|
||||||
|
zoomStatusMenuBarItem:setTitle("🟢")
|
||||||
|
elseif (event == "from-meeting-to-running") then
|
||||||
|
zoomStatusMenuBarItem:removeFromMenuBar()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Now we can load, instantiate it, as well as create a callback loop to call =updateZoomStatus=:
|
||||||
|
|
||||||
|
#+BEGIN_SRC lua
|
||||||
|
hs.loadSpoon("Zoom")
|
||||||
|
spoon.Zoom:setStatusCallback(updateZoomStatus)
|
||||||
|
spoon.Zoom:start()
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
And bind a key to the mute ability that works good for both keyboards:
|
||||||
|
|
||||||
|
#+BEGIN_SRC lua
|
||||||
|
hs.hotkey.bind({"cmd", "alt", "ctrl", "shift"}, "M", spoon.Zoom:toggleMute)
|
||||||
|
|
||||||
|
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "M", function()
|
||||||
|
spoon.Zoom:toggleMute()
|
||||||
|
end)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Lovely bit of code and shows the true power of Hammerspoon to fix the various app issues.
|
||||||
|
* Automatically Adjust Volume
|
||||||
|
Leaving my home office and hopping on the train can be socially awkward when my laptop suddenly screams, so if I leave my home, I just readjust the volume and turn it off:
|
||||||
|
|
||||||
|
#+BEGIN_SRC lua
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- When leaving house, turn off the volume:
|
||||||
|
|
||||||
|
wifiWatcher = nil
|
||||||
|
homeSSID = "Intertubes"
|
||||||
|
workSSID = "workdaysecure"
|
||||||
|
hotspotSSID = "Pixie Dust"
|
||||||
|
lastSSID = hs.wifi.currentNetwork()
|
||||||
|
|
||||||
|
function ssidChangedCallback()
|
||||||
|
newSSID = hs.wifi.currentNetwork()
|
||||||
|
|
||||||
|
if newSSID == homeSSID and lastSSID ~= homeSSID then
|
||||||
|
-- joined our home WiFi network
|
||||||
|
hs.audiodevice.defaultOutputDevice():setVolume(25)
|
||||||
|
elseif newSSID == workSSID and lastSSID ~= workSSID then
|
||||||
|
-- joined our work WiFi network
|
||||||
|
hs.audiodevice.defaultOutputDevice():setVolume(0)
|
||||||
|
elseif newSSID == hotspotSSID and lastSSID ~= hotspotSSID then
|
||||||
|
-- joined our hotspot WiFi network
|
||||||
|
hs.audiodevice.defaultOutputDevice():setVolume(0)
|
||||||
|
elseif newSSID ~= homeSSID and lastSSID == homeSSID then
|
||||||
|
-- departed our home WiFi network
|
||||||
|
hs.audiodevice.defaultOutputDevice():setVolume(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
lastSSID = newSSID
|
||||||
|
end
|
||||||
|
|
||||||
|
hs.wifi.watcher.new(ssidChangedCallback):start()
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Why yes, I’m /looking for features/ to use Hammerspoon.
|
||||||
|
* Clocking out a Task
|
||||||
|
I want to use Org’s task clocking ability, but I often forget to /clock out/. This code allows me to clock out whenever my computer goes to sleep … which works well when closing the laptop lid:
|
||||||
|
|
||||||
|
#+BEGIN_SRC lua
|
||||||
|
function sleepWatch(eventType)
|
||||||
|
if (eventType == hs.caffeinate.watcher.systemWillSleep) then
|
||||||
|
if hs.application.find("Emacs") then
|
||||||
|
hs.execute("/opt/homebrew/bin/emacsclient --socket work --eval '(ha-clock-out)'")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hs.caffeinate.watcher.new(sleepWatch):start()
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Not that we could also do something for Wake:
|
||||||
|
|
||||||
|
#+BEGIN_SRC lua :tangle no
|
||||||
|
if (eventType == hs.caffeinate.watcher.systemDidWake) then
|
||||||
|
...
|
||||||
|
end
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Monitors
|
||||||
|
My company gave me a nice monitor … maybe a little too nice, as I don’t care to shift my neck to the extreme sides (serious first-world problem), so here I can /center/ a window Keeping it my field of view:
|
||||||
|
|
||||||
|
#+BEGIN_SRC lua
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- Centering a window on the large monitors at Work:
|
||||||
|
|
||||||
|
function centerWindow()
|
||||||
|
local win = hs.window.focusedWindow()
|
||||||
|
local app = win:application()
|
||||||
|
local f = win:frame()
|
||||||
|
|
||||||
|
-- Magic numbers figured out by trial and error:
|
||||||
|
f.x = 600
|
||||||
|
f.y = 30
|
||||||
|
f.w = 2200
|
||||||
|
f.h = 1470
|
||||||
|
|
||||||
|
if app then
|
||||||
|
local name = app:name()
|
||||||
|
-- If the application is Slack, adjust the height
|
||||||
|
if name == "Slack" or name == "iTerm2" then
|
||||||
|
f.h = 1200
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
win:setFrame(f)
|
||||||
|
hs.alert.show("Centered Window")
|
||||||
|
end
|
||||||
|
|
||||||
|
hs.hotkey.bind({"cmd", "alt", "ctrl", "shift"}, "Y", centerWindow)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Auto Reload Configuration
|
||||||
|
Whenever my configuration file is altered (or with a ~Meh-R~ key), I reload the configuration:
|
||||||
|
|
||||||
|
#+BEGIN_SRC lua
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- Automatically reload the Hammerspoon configuration
|
||||||
|
|
||||||
|
hs.hotkey.bind({"cmd", "alt", "ctrl", "shift"}, "R", function()
|
||||||
|
hs.reload()
|
||||||
|
hs.alert.show("Reloaded Hammerspoon Config")
|
||||||
|
end)
|
||||||
|
|
||||||
|
function reloadConfig(files)
|
||||||
|
doReload = false
|
||||||
|
for _,file in pairs(files) do
|
||||||
|
if file:sub(-4) == ".lua" then
|
||||||
|
doReload = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if doReload then
|
||||||
|
hs.reload()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", reloadConfig):start()
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Technical Artifacts :noexport:
|
||||||
|
#+BEGIN_SRC lua
|
||||||
|
hs.alert.show("Hammerspoon Configuration")
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
|
||||||
|
#+DESCRIPTION: Literate Hammerspoon configuration
|
||||||
|
|
||||||
|
#+PROPERTY: header-args:sh :tangle no
|
||||||
|
#+PROPERTY: header-args:lua :tangle ~/.hammerspoon/init.lua
|
||||||
|
#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes
|
||||||
|
|
||||||
|
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil
|
||||||
|
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
|
||||||
|
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
||||||
58
initialize
58
initialize
|
|
@ -23,6 +23,15 @@ gpg --homedir ~/.emacs.d/elpa/gnupg --receive-keys 066DAFCB81E42C40
|
||||||
cat > "$HAMACS_DEST/early-init.el" <<EOF
|
cat > "$HAMACS_DEST/early-init.el" <<EOF
|
||||||
;;; early-init.el --- Hamacs Early Init -*- lexical-binding: t; -*-
|
;;; early-init.el --- Hamacs Early Init -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
|
;; ▄████████ ▄▄▄▄███▄▄▄▄ ▄████████ ▄████████ ▄████████
|
||||||
|
;; ███ ███ ▄██▀▀▀███▀▀▀██▄ ███ ███ ███ ███ ███ ███
|
||||||
|
;; ███ █▀ ███ ███ ███ ███ ███ ███ █▀ ███ █▀
|
||||||
|
;; ▄███▄▄▄ ███ ███ ███ ███ ███ ███ ███
|
||||||
|
;; ▀▀███▀▀▀ ███ ███ ███▀███████████ ███ ▀███████████
|
||||||
|
;; ███ █▄ ███ ███ ███ ███ ███ ███ █▄ ███
|
||||||
|
;; ███ ███ ███ ███ ███ ███ ███ ███ ███ ▄█ ███
|
||||||
|
;; ██████████ ▀█ ███ █▀ ███ █▀ ████████▀ ▄████████▀
|
||||||
|
;;
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;
|
;;
|
||||||
;; This is my early Emacs configuration file. See init.el for the real
|
;; This is my early Emacs configuration file. See init.el for the real
|
||||||
|
|
@ -69,6 +78,14 @@ echo "Created $HAMACS_DEST/early-init.el"
|
||||||
cat > "$HAMACS_DEST/init.el" <<EOF
|
cat > "$HAMACS_DEST/init.el" <<EOF
|
||||||
;;; init.el --- Hamacs Init -*- lexical-binding: t; -*-
|
;;; init.el --- Hamacs Init -*- lexical-binding: t; -*-
|
||||||
;;
|
;;
|
||||||
|
;; :::::::::: :::: :::: ::: :::::::: ::::::::
|
||||||
|
;; :+: +:+:+: :+:+:+ :+: :+: :+: :+: :+: :+:
|
||||||
|
;; +:+ +:+ +:+:+ +:+ +:+ +:+ +:+ +:+
|
||||||
|
;; +#++:++# +#+ +:+ +#+ +#++:++#++: +#+ +#++:++#++
|
||||||
|
;; +#+ +#+ +#+ +#+ +#+ +#+ +#+
|
||||||
|
;; #+# #+# #+# #+# #+# #+# #+# #+# #+#
|
||||||
|
;; ########## ### ### ### ### ######## ########
|
||||||
|
;;
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;
|
;;
|
||||||
;; This is my Emacs Bootloader. Simply put, I initialize the package
|
;; This is my Emacs Bootloader. Simply put, I initialize the package
|
||||||
|
|
@ -79,23 +96,8 @@ cat > "$HAMACS_DEST/init.el" <<EOF
|
||||||
|
|
||||||
(defvar hamacs-source-dir "$HAMACS_DIR" "Where we be.")
|
(defvar hamacs-source-dir "$HAMACS_DIR" "Where we be.")
|
||||||
|
|
||||||
(defvar hamacs-package-repos
|
|
||||||
(file-name-concat user-emacs-directory "repos")
|
|
||||||
"Repository location for all packages.")
|
|
||||||
|
|
||||||
(defun load-path-repo (repo)
|
|
||||||
(expand-file-name repo hamacs-package-repos))
|
|
||||||
|
|
||||||
(defun hamacs-package-repos-update-load-path ()
|
|
||||||
"Update the \`load-path' with clone repositories."
|
|
||||||
(interactive)
|
|
||||||
(dolist (repo (directory-files hamacs-package-repos 'full "[A-z].*"))
|
|
||||||
(add-to-list 'load-path repo nil 'string-equal)))
|
|
||||||
|
|
||||||
(hamacs-package-repos-update-load-path)
|
|
||||||
|
|
||||||
;; Bug fixes for ORG (there always seems to be something):
|
;; Bug fixes for ORG (there always seems to be something):
|
||||||
;; (defvar native-comp-deferred-compilation-deny-list nil)
|
(defvar native-comp-deferred-compilation-deny-list nil)
|
||||||
|
|
||||||
;; Allow the installation of unsigned packages, but verify the
|
;; Allow the installation of unsigned packages, but verify the
|
||||||
;; signature if possible:
|
;; signature if possible:
|
||||||
|
|
@ -113,7 +115,29 @@ cat > "$HAMACS_DEST/init.el" <<EOF
|
||||||
(add-to-list 'package-archives
|
(add-to-list 'package-archives
|
||||||
'("elpa-dev" . "https://elpa.gnu.org/devel/"))
|
'("elpa-dev" . "https://elpa.gnu.org/devel/"))
|
||||||
|
|
||||||
(setq use-package-always-ensure nil)
|
;; Configure straight https://github.com/raxod502/straight.el#getting-started
|
||||||
|
|
||||||
|
(defvar bootstrap-version)
|
||||||
|
(let ((bootstrap-file
|
||||||
|
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
|
||||||
|
(bootstrap-version 6))
|
||||||
|
(unless (file-exists-p bootstrap-file)
|
||||||
|
(with-current-buffer
|
||||||
|
(url-retrieve-synchronously
|
||||||
|
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
|
||||||
|
'silent 'inhibit-cookies)
|
||||||
|
(goto-char (point-max))
|
||||||
|
(eval-print-last-sexp)))
|
||||||
|
(load bootstrap-file nil 'nomessage))
|
||||||
|
|
||||||
|
(straight-use-package 'use-package)
|
||||||
|
|
||||||
|
;; While that enables the :straight t extension to use-package, let's just have that be the default:
|
||||||
|
(use-package straight
|
||||||
|
:custom (straight-use-package-by-default t
|
||||||
|
straight-default-vc 'git))
|
||||||
|
|
||||||
|
;; See the details in https://dev.to/jkreeftmeijer/emacs-package-management-with-straight-el-and-use-package-3oc8
|
||||||
|
|
||||||
(use-package org
|
(use-package org
|
||||||
;; TODO: Using the latest org-mode
|
;; TODO: Using the latest org-mode
|
||||||
|
|
|
||||||
63
laptop_keyboard.kbd
Normal file
63
laptop_keyboard.kbd
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
;; Here is a keyboard setup for an Apple Macbook keyboard to work with
|
||||||
|
;; "home row mods" where holding down keys on the home row can act like a
|
||||||
|
;; modifier, so holding down `d` and hitting `p` results in `P` being
|
||||||
|
;; entered.
|
||||||
|
|
||||||
|
(deflocalkeys-macos
|
||||||
|
ì 13
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Also includes a symbol layer accessible while holding down either
|
||||||
|
;; the `h' or `g' keys.
|
||||||
|
|
||||||
|
(defcfg
|
||||||
|
macos-dev-names-include ("Apple Internal Keyboard / Trackpad")
|
||||||
|
;; linux-dev-names-include (
|
||||||
|
;; "Microsoft Surface 045E:091C Keyboard"
|
||||||
|
;; )
|
||||||
|
)
|
||||||
|
(defsrc
|
||||||
|
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
|
||||||
|
` 1 2 3 4 5 6 7 8 9 0 - = bspc
|
||||||
|
tab q w e r t y u i o p [ ] \
|
||||||
|
caps a s d f g h j k l ; ' ret
|
||||||
|
lsft z x c v b n m , . / rsft
|
||||||
|
fn lctl lalt lmet spc rmet ralt
|
||||||
|
)
|
||||||
|
|
||||||
|
(defvar
|
||||||
|
tap-time 200
|
||||||
|
hold-time 200
|
||||||
|
)
|
||||||
|
|
||||||
|
(defalias
|
||||||
|
a (tap-hold $tap-time $hold-time a lmet)
|
||||||
|
s (tap-hold $tap-time $hold-time s lctl)
|
||||||
|
d (tap-hold $tap-time $hold-time d lsft)
|
||||||
|
f (tap-hold $tap-time $hold-time f lalt)
|
||||||
|
g (tap-hold $tap-time $hold-time g (layer-while-held SYMBOLS))
|
||||||
|
h (tap-hold $tap-time $hold-time h (layer-while-held SYMBOLS))
|
||||||
|
j (tap-hold $tap-time $hold-time j ralt)
|
||||||
|
k (tap-hold $tap-time $hold-time k rsft)
|
||||||
|
l (tap-hold $tap-time $hold-time l rctl)
|
||||||
|
; (tap-hold $tap-time $hold-time ; rmet)
|
||||||
|
caps (tap-hold $tap-time $hold-time esc lctl)
|
||||||
|
)
|
||||||
|
|
||||||
|
(deflayer base
|
||||||
|
esc F1 F2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
|
||||||
|
` 1 2 3 4 5 6 7 8 9 0 - = bspc
|
||||||
|
tab q w e r t y u i o p [ ] \
|
||||||
|
@caps @a @s @d @f @g @h @j @k @l @; ' ret
|
||||||
|
lsft z x c v b n m , . / rsft
|
||||||
|
@h lctl lalt lmet spc rmet ralt
|
||||||
|
)
|
||||||
|
|
||||||
|
(deflayer SYMBOLS
|
||||||
|
esc 🔅 🔆 F3 F4 f5 f6 ◀◀ ▶⏸ ▶▶ 🔇 🔉 🔊
|
||||||
|
_ f11 f12 f13 f14 f15 f16 f17 f18 f19 f20 _ _ _
|
||||||
|
_ S-1 S-2 { } S-\ F16 F17 F18 F19 pgup _ _ _
|
||||||
|
_ S-3 S-4 S-9 S-0 ` left down up right pgdn _ _
|
||||||
|
_ S-5 S-6 [ ] S-` F11 F12 F13 F14 F15 _
|
||||||
|
_ _ _ _ _ _ _
|
||||||
|
)
|
||||||
164
zshell.org
164
zshell.org
|
|
@ -21,6 +21,7 @@ Regardless, I keep my shell configuration conspicuously light.
|
||||||
Let’s create the following files, and the configuration below will be injected into one of them:
|
Let’s create the following files, and the configuration below will be injected into one of them:
|
||||||
|
|
||||||
- =~/.zshenv= :: Usually run for every zsh
|
- =~/.zshenv= :: Usually run for every zsh
|
||||||
|
- =~/.zprofile= :: Usually run for login shells (this includes the system-wide =/etc/zprofile=)
|
||||||
- =~/.zshrc= :: Run for interactive shells … default file when tangling
|
- =~/.zshrc= :: Run for interactive shells … default file when tangling
|
||||||
- =~/.zlogin= :: Run for login shells … seems to run as often as =.zshrc=
|
- =~/.zlogin= :: Run for login shells … seems to run as often as =.zshrc=
|
||||||
|
|
||||||
|
|
@ -43,8 +44,24 @@ Let’s create the following files, and the configuration below will be injected
|
||||||
* Path
|
* Path
|
||||||
The all important =PATH= environment variable, needs my special =bin= directory.
|
The all important =PATH= environment variable, needs my special =bin= directory.
|
||||||
|
|
||||||
#+BEGIN_SRC zsh :export ~/.zshenv
|
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||||
export PATH=$HOME/bin:/usr/local/bin:$PATH
|
export PATH=$HOME/bin:$HOME/.local/bin:$PATH
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
My Apple Macbook screws up my =PATH= by having =/etc/profile= (that runs after my =~/.zshenv=) /pre-pend/ system directories like =/bin= and =/usr/bin= /after/ I’ve set up my =PATH= environment variable. So, in my own =.zprofile= (which runs afterwards), I reverse it using the lovely =tac= program:
|
||||||
|
|
||||||
|
#+BEGIN_SRC sh :tangle ~/.zprofile :shebang #!/bin/zsh
|
||||||
|
if [[ -f /etc/zprofile ]]
|
||||||
|
then
|
||||||
|
# Reverse the PATH variable
|
||||||
|
reversed_path=$(echo $PATH | tr ':' '\n' | tac | tr '\n' ':')
|
||||||
|
|
||||||
|
# Reset the path after removing the trailing colon:
|
||||||
|
export PATH=${reversed_path%:}
|
||||||
|
|
||||||
|
# Output the reversed PATH
|
||||||
|
# echo "Reversed PATH: $reversed_path"
|
||||||
|
fi
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
* Options
|
* Options
|
||||||
|
|
@ -94,7 +111,10 @@ setopt MENU_COMPLETE
|
||||||
When using Homebrew on a Mac, we need to add its =PATH=:
|
When using Homebrew on a Mac, we need to add its =PATH=:
|
||||||
|
|
||||||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||||
eval $(/opt/homebrew/bin/brew shellenv zsh)
|
if [[ -d /opt/homebrew ]]
|
||||||
|
then
|
||||||
|
eval $(/opt/homebrew/bin/brew shellenv zsh)
|
||||||
|
fi
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
This adds the following environment variables, along with expanding the =PATH=.
|
This adds the following environment variables, along with expanding the =PATH=.
|
||||||
|
|
@ -198,18 +218,28 @@ The [[https://github.com/zsh-users/zsh-syntax-highlighting][ZShell Syntax Highli
|
||||||
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
|
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
Using the =colorize= plugin (see [[Plugins][plugins section below]]), we customize with this variable setting:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh
|
||||||
|
export ZSH_COLORIZE_STYLE="coffee"
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
|
||||||
** Language Support
|
** Language Support
|
||||||
Anything special for particular languages.
|
Anything special for particular languages.
|
||||||
*** Python
|
*** Python
|
||||||
Not overly impressed, for to get =pyenv= to work, we need to add this code:
|
Not overly impressed, for to get =pyenv= to work, we need to add this code:
|
||||||
|
|
||||||
#+BEGIN_SRC zsh
|
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||||
export PYENV_ROOT="$HOME/.pyenv"
|
export PYENV_ROOT="$HOME/.pyenv"
|
||||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||||
|
|
||||||
eval "$(pyenv init --path)"
|
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
And call the =pyenv= to initialize it:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh
|
||||||
|
# eval "$(pyenv init --path)"
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
** Plugins
|
** Plugins
|
||||||
Configure the plugins, making sure to not use =git=, as the aliases are a pain to remember when I already have a superior Git interface in Emacs.
|
Configure the plugins, making sure to not use =git=, as the aliases are a pain to remember when I already have a superior Git interface in Emacs.
|
||||||
|
|
@ -228,7 +258,7 @@ Configure the plugins, making sure to not use =git=, as the aliases are a pain t
|
||||||
To have a plugin /install/, add its name to the =plugins= array variable /before/ we =source= the OMZ script:
|
To have a plugin /install/, add its name to the =plugins= array variable /before/ we =source= the OMZ script:
|
||||||
|
|
||||||
#+begin_SRC zsh
|
#+begin_SRC zsh
|
||||||
plugins=(colorize direnv gnu-utils iterm2 macos pyenv virtualenv zbell zsh-syntax-highlighting)
|
plugins=(colorize direnv gnu-utils iterm2 macos virtualenv zbell zsh-syntax-highlighting)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Notice the =iterm2= plugin as well as the =macos= plugins that would be nice to figure out how to make them optionally added (although I believe they check themselves).
|
Notice the =iterm2= plugin as well as the =macos= plugins that would be nice to figure out how to make them optionally added (although I believe they check themselves).
|
||||||
|
|
@ -242,6 +272,26 @@ The trick is to install some base-level plugins, and then, on my work computer,
|
||||||
fi
|
fi
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
I would like to have a history /per project/, so that when I start a session for a project, my history has where I left off /for that project/ and not everything. I guess I’m not the only one who [[https://github.com/ivan-cukic/zsh-per-project-history][thought of this idea]]. We first need to add his plugin to the list of supplied plugins, so do this once:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh :tangle no
|
||||||
|
git clone https://github.com/ivan-cukic/zsh-per-project-history ~/.oh-my-zsh/plugins/per-project-history
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
His idea is to have a variable array, =PER_PROJECT_HISTORY_TAGS= that lists files that should identify the start of a project, and while his default seems sufficient, I am not found of the spammy message, so:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh
|
||||||
|
declare -a PER_PROJECT_HISTORY_TAGS
|
||||||
|
export PER_PROJECT_HISTORY_TAGS=(.envrc .git)
|
||||||
|
declare -r PER_PROJECT_HISTORY_TAGS
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
we just need to add =per-history= to the list of plugins:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh
|
||||||
|
plugins+=(per-project-history)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
Now that I’ve filled in the =plugins= variable, load OMZ and the plugins:
|
Now that I’ve filled in the =plugins= variable, load OMZ and the plugins:
|
||||||
|
|
||||||
#+BEGIN_SRC zsh
|
#+BEGIN_SRC zsh
|
||||||
|
|
@ -274,6 +324,80 @@ Oh use the absolute /over-the-top/ bling associated with Oh My Zshell’s /theme
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
I keep the prompt simple since all of the /gunk/ we typically put in a prompt is better placed in [[https://iterm2.com/documentation-status-bar.html][iTerm2's Status Bar]].
|
I keep the prompt simple since all of the /gunk/ we typically put in a prompt is better placed in [[https://iterm2.com/documentation-status-bar.html][iTerm2's Status Bar]].
|
||||||
|
* Homebrew
|
||||||
|
When using Homebrew on a Mac, we need to add its =PATH= and environment variables. This is typically done by running the command:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh :tangle no
|
||||||
|
eval $(brew shellenv zsh)
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
We want to add the path and environment variables into the =~/.zshenv= file, but this file should not contain any logic or code. So, let’s run the command /from Emacs/, and store the results in the file.
|
||||||
|
|
||||||
|
The full script to run is:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh :tangle no :results file :file ~/.zshenv_brew
|
||||||
|
echo '# -*- mode:sh; -*-'
|
||||||
|
if which brew >/dev/null
|
||||||
|
then
|
||||||
|
if [[ -d /opt/homebrew ]]
|
||||||
|
then
|
||||||
|
/opt/homebrew/bin/brew shellenv zsh
|
||||||
|
else
|
||||||
|
brew shellenv zsh
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Seems that if I want the GNU versions (instead of the old ones supplied by Apple), I have to do it myself:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh :tangle no :results file :file ~/.zshenv_gnu
|
||||||
|
echo '# -*- mode:sh; -*-'
|
||||||
|
if which brew >/dev/null
|
||||||
|
then
|
||||||
|
for PKG in binutils gettext unzip openssl texinfo mysql-client openjdk
|
||||||
|
do
|
||||||
|
if PKG_INSTALL=$(brew --prefix $PKG)
|
||||||
|
then
|
||||||
|
echo export PATH=$PKG_INSTALL/bin:'$PATH'
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for PKG in coreutils ed findutils gnu-indent gnu-sed gnu-tar grep make
|
||||||
|
do
|
||||||
|
if PKG_INSTALL=$(brew --prefix $PKG)
|
||||||
|
then
|
||||||
|
echo export PATH=$PKG_INSTALL/libexec/gnubin:'$PATH'
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
And linking all the GNU libraries:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh :tangle no :results file :file ~/.zshenv_lib
|
||||||
|
echo '# -*- mode:sh; -*-'
|
||||||
|
|
||||||
|
if which brew >/dev/null
|
||||||
|
then
|
||||||
|
for PKG in readline openssl xz binutils ctags libgccjit imagemagick
|
||||||
|
do
|
||||||
|
if PKG_INSTALL=$(brew --prefix $PKG)
|
||||||
|
echo export LDFLAGS=\"-L$PKG_INSTALL/lib '$LDFLAGS'\"
|
||||||
|
echo export CPPFLAGS=\"-I$PKG_INSTALL/include '$CPPFLAGS'\"
|
||||||
|
done
|
||||||
|
echo export LDFLAGS=\"'$LDFLAGS' -L$(brew --prefix)/lib\"
|
||||||
|
echo export CPPFLAGS=\"'$CPPFLAGS' -I$(brew --prefix)/include\"
|
||||||
|
fi
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
And pull in all the results into the =~/.zshenv= file (why yes, this could be inlined):
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||||
|
[[ -f $HOME/.zshenv_brew ]] && source $HOME/.zshenv_brew
|
||||||
|
[[ -f $HOME/.zshenv_gnu ]] && source $HOME/.zshenv_gnu
|
||||||
|
[[ -f $HOME/.zshenv_lib ]] && source $HOME/.zshenv_lib
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
* iTerm2
|
* iTerm2
|
||||||
On Mac systems, I like the [[https://www.iterm2.com/][iTerm2 application]], and we can enable [[https://iterm2.com/documentation-shell-integration.html][shell integration]], either via the old school way, or just rely on [[https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/iterm2][the /plugin/ ]]above:
|
On Mac systems, I like the [[https://www.iterm2.com/][iTerm2 application]], and we can enable [[https://iterm2.com/documentation-shell-integration.html][shell integration]], either via the old school way, or just rely on [[https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/iterm2][the /plugin/ ]]above:
|
||||||
|
|
||||||
|
|
@ -324,10 +448,12 @@ While it /should/ figure out (as Emacs keybindings are the default), this is how
|
||||||
bindkey -e
|
bindkey -e
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Where be the =emacsclient=, and how should we call it?
|
Where be the =emacsclient=? It should, at this point, be in our path.
|
||||||
|
|
||||||
|
And how should we call it?
|
||||||
|
|
||||||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||||
export EMACS="emacsclient --socket-name personal"
|
export EMACS_SOCKET_NAME=personal
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Which needs to be overwritten on my Work computer:
|
Which needs to be overwritten on my Work computer:
|
||||||
|
|
@ -335,15 +461,15 @@ Which needs to be overwritten on my Work computer:
|
||||||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||||
if hostname | grep AL33 >/dev/null
|
if hostname | grep AL33 >/dev/null
|
||||||
then
|
then
|
||||||
export EMACS="emacsclient --socket-name work"
|
export EMACS_SOCKET_NAME=work
|
||||||
fi
|
fi
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
The =EDITOR= variable that some programs use to edit files from the command line:
|
The =EDITOR= variable that some programs use to edit files from the command line:
|
||||||
|
|
||||||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||||
export EDITOR="$EMACS --tty"
|
export EDITOR="emacsclient --tty"
|
||||||
export VISUAL="$EMACS --create-frame"
|
export VISUAL="emacsclient --create-frame"
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
With these variables defined, we can create simple aliases:
|
With these variables defined, we can create simple aliases:
|
||||||
|
|
@ -351,8 +477,8 @@ With these variables defined, we can create simple aliases:
|
||||||
#+BEGIN_SRC zsh
|
#+BEGIN_SRC zsh
|
||||||
alias e="$EDITOR"
|
alias e="$EDITOR"
|
||||||
alias te="$EDITOR"
|
alias te="$EDITOR"
|
||||||
alias ee="$EMACS --create-frame"
|
alias ee="emacsclient --create-frame"
|
||||||
alias eee="$EMACS --create-frame --no-wait"
|
alias eee="emacsclient --create-frame --no-wait"
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
** Vterm
|
** Vterm
|
||||||
|
|
@ -407,7 +533,7 @@ For instance:
|
||||||
Assuming we’ve installed [[https://github.com/lsd-rs/lsd][lsd]], let’s make an alias for it:
|
Assuming we’ve installed [[https://github.com/lsd-rs/lsd][lsd]], let’s make an alias for it:
|
||||||
|
|
||||||
#+BEGIN_SRC zsh
|
#+BEGIN_SRC zsh
|
||||||
if whence lsd >/dev/null
|
if which lsd >/dev/null
|
||||||
then
|
then
|
||||||
alias ls=lsd
|
alias ls=lsd
|
||||||
fi
|
fi
|
||||||
|
|
@ -431,6 +557,13 @@ And an abstraction for transitory endpoints over SSH:
|
||||||
alias ossh="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o loglevel=ERROR"
|
alias ossh="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o loglevel=ERROR"
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
And other ones that I use:
|
||||||
|
|
||||||
|
#+BEGIN_SRC zsh
|
||||||
|
alias os=openstack
|
||||||
|
alias k=kubectl
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
* Final Message
|
* Final Message
|
||||||
For sensitive work-related environment variables, store them elsewhere, and load them:
|
For sensitive work-related environment variables, store them elsewhere, and load them:
|
||||||
|
|
||||||
|
|
@ -446,6 +579,7 @@ To let us know we read the =~/.zshrc= file:
|
||||||
|
|
||||||
#+description: A literate programming file for configuring Zshell.
|
#+description: A literate programming file for configuring Zshell.
|
||||||
#+property: header-args:zsh :tangle ~/.zshrc
|
#+property: header-args:zsh :tangle ~/.zshrc
|
||||||
|
#+property: header-args:sh :tangle no
|
||||||
#+property: header-args :results none :eval no-export :comments no mkdirp yes
|
#+property: header-args :results none :eval no-export :comments no mkdirp yes
|
||||||
#+options: num:nil toc:t todo:nil tasks:nil tags:nil date:nil
|
#+options: num:nil toc:t todo:nil tasks:nil tags:nil date:nil
|
||||||
#+options: skip:nil author:nil email:nil creator:nil timestamp:nil
|
#+options: skip:nil author:nil email:nil creator:nil timestamp:nil
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue