Compare commits
1 commit
main
...
no-straigh
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8f2be92ff |
32 changed files with 457 additions and 1037 deletions
|
|
@ -8,15 +8,6 @@ A literate programming file for bootstraping my Emacs Configuration.
|
|||
#+begin_src emacs-lisp :exports none
|
||||
;;; bootstrap.el --- file for bootstraping my Emacs Configuration
|
||||
;;
|
||||
;; ██████████
|
||||
;; ░░███░░░░░█
|
||||
;; ░███ █ ░ █████████████ ██████ ██████ █████
|
||||
;; ░██████ ░░███░░███░░███ ░░░░░███ ███░░███ ███░░
|
||||
;; ░███░░█ ░███ ░███ ░███ ███████ ░███ ░░░ ░░█████
|
||||
;; ░███ ░ █ ░███ ░███ ░███ ███░░███ ░███ ███ ░░░░███
|
||||
;; ██████████ █████░███ █████░░████████░░██████ ██████
|
||||
;; ░░░░░░░░░░ ░░░░░ ░░░ ░░░░░ ░░░░░░░░ ░░░░░░ ░░░░░░
|
||||
|
||||
;; © 2021-2023 Howard X. Abrams
|
||||
;; Licensed under a Creative Commons Attribution 4.0 International License.
|
||||
;; See http://creativecommons.org/licenses/by/4.0/
|
||||
|
|
@ -36,8 +27,6 @@ A literate programming file for bootstraping my Emacs Configuration.
|
|||
* Introduction
|
||||
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]].
|
||||
|
||||
* Initial Settings
|
||||
|
|
@ -107,7 +96,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:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package cl-lib
|
||||
:straight (:type built-in)
|
||||
|
||||
:init (defun first (elt) (car elt))
|
||||
:commands (first))
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,11 @@ A literate programming file configuring critical applications.
|
|||
Can we call the following /applications/? I guess.
|
||||
* 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.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(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:
|
||||
:custom (with-editor-emacsclient-executable "emacsclient")
|
||||
|
||||
|
|
@ -87,7 +90,7 @@ Can not live without [[https://magit.vc/][Magit]], a Git porcelain for Emacs. I
|
|||
** 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.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(use-package diff-hl
|
||||
:custom
|
||||
(diff-hl-side 'right)
|
||||
|
|
@ -100,7 +103,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:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(use-package diff-hl
|
||||
:config
|
||||
(global-diff-hl-mode)
|
||||
|
|
@ -121,7 +124,7 @@ Turning on the mode, as well as binding some new /leader/ keys:
|
|||
|
||||
This project (and others) can use repeat mode, but
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(repeat-mode)
|
||||
#+END_SRC
|
||||
|
||||
|
|
@ -214,7 +217,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:
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(use-package compat
|
||||
:straight (:host github :repo "emacs-straight/compat"))
|
||||
;; :vc (:url "https://github.com/emacs-straight/compat"))
|
||||
|
||||
(use-package magit-section
|
||||
:commands magit-thing-at-point)
|
||||
|
|
@ -310,7 +313,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.
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(use-package gh
|
||||
:straight (:host github :repo "sigma/gh.el"))
|
||||
;; :vc (:url "https://github.com/sigma/gh.el"))
|
||||
#+end_src
|
||||
|
||||
** Forge
|
||||
|
|
@ -408,6 +411,7 @@ Web pages look pretty good with EWW, but I'm having difficulty getting it to ren
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package eww
|
||||
:after major-mode-hydra
|
||||
:init
|
||||
(setq browse-url-browser-function 'eww-browse-url
|
||||
browse-url-secondary-browser-function 'browse-url-default-browser
|
||||
|
|
@ -506,7 +510,8 @@ Make my EWW browsers /look/ like an Org file with the [[https://github.com/cheny
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package shrface
|
||||
:straight (:host github :repo "chenyanming/shrface")
|
||||
;; :vc (:url "https://github.com/chenyanming/shrface")
|
||||
:after major-mode-hydra
|
||||
:config
|
||||
(shrface-basic)
|
||||
;; (shrface-trial)
|
||||
|
|
@ -641,7 +646,7 @@ Instead I use Emacs' built-in directory lister (which accepts the standard, =dir
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package ls-lisp
|
||||
:straight (:type built-in)
|
||||
|
||||
:config
|
||||
(setq ls-lisp-use-insert-directory-program nil
|
||||
dired-listing-switches
|
||||
|
|
@ -652,7 +657,7 @@ And [[https://www.masteringemacs.org/article/dired-shell-commands-find-xargs-rep
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package dired-x
|
||||
:straight (:type built-in))
|
||||
)
|
||||
#+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 ~&~.
|
||||
|
|
@ -666,7 +671,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:
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(use-package dirvish
|
||||
:straight (:host github :repo "alexluigit/dirvish")
|
||||
;; :vc (:url "https://github.com/alexluigit/dirvish")
|
||||
:init (dirvish-override-dired-mode)
|
||||
|
||||
:custom
|
||||
|
|
@ -872,6 +877,8 @@ 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:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package org-noter
|
||||
:load-path "/User/howard.abrams/.emacs.d/repos/org-noter"
|
||||
:after major-mode-hydra
|
||||
:config
|
||||
(major-mode-hydra-define org-noter-doc-mode-map nil
|
||||
("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.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package mastodon
|
||||
:straight (:host codeberg :repo "martianh/mastodon.el")
|
||||
;; :vc (:url "https://codeberg.org/martianh/mastodon.el")
|
||||
:init
|
||||
(setq mastodon-instance-url "https://pdx.social"
|
||||
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
|
||||
(use-package mastodon
|
||||
:config
|
||||
(ha-leader "a m" `("mastodon" . ,(lambda () (interactive) (ha-tab-bar-new "mastodon" #'mastodon))))
|
||||
(ha-leader "a m" `("mastodon" . ,(ha-app-perspective "mastodon" #'mastodon)))
|
||||
|
||||
(defun ha-mastodon-scroll-or-more ()
|
||||
"Scroll a window, and at the end, get more entries in timeline."
|
||||
|
|
@ -53,35 +53,35 @@ I would like a dedicate perspective to Mastodon, and I would like a leader key s
|
|||
|
||||
(use-package major-mode-hydra
|
||||
:config
|
||||
(major-mode-hydra-define mastodon-mode (:quit-key "q")
|
||||
(major-mode-hydra-define mastodon-mode nil
|
||||
("Timelines"
|
||||
(("u" mastodon-tl-update "update")
|
||||
("F" mastodon-tl-get-federated-timeline "Federated")
|
||||
("H" mastodon-tl-get-home-timeline "Home")
|
||||
("L" mastodon-tl-get-local-timeline "Local")
|
||||
("T" mastodon-tl-get-tag-timeline "Hashtag"))
|
||||
(("u" mastodon-tl--update "update")
|
||||
("F" mastodon-tl--get-federated-timeline "Federated")
|
||||
("H" mastodon-tl--get-home-timeline "Home")
|
||||
("L" mastodon-tl--get-local-timeline "Local")
|
||||
("T" mastodon-tl--get-tag-timeline "Hashtag"))
|
||||
"Specials"
|
||||
(("M" mastodon-notifications--get-mentions "Mentions")
|
||||
("N" mastodon-notifications-get "Notifications")
|
||||
("A" mastodon-tl-followed-tags-timeline "All Tags")
|
||||
("S" mastodon-profile-view-bookmarks "Saved bookmarks")
|
||||
("O" mastodon-profile-my-profile "My Profile"))
|
||||
("A" mastodon-tl--followed-tags-timeline "All Tags")
|
||||
("S" mastodon-profile--view-bookmarks "Saved bookmarks")
|
||||
("O" mastodon-profile--my-profile "My Profile"))
|
||||
"Post"
|
||||
(("c" mastodon-toot "Compose toot")
|
||||
("e" mastodon-toot-edit-toot-at-point "Edit toot")
|
||||
("t" mastodon-tl-thread "Read thread")
|
||||
("r" mastodon-toot-reply "Reply")
|
||||
("m" mastodon-tl-dm-user "Direct Msg")
|
||||
("d" mastodon-toot-delete-toot "Delete"))
|
||||
("e" mastodon-toot--edit-toot-at-point "Edit toot")
|
||||
("t" mastodon-tl--thread "Read thread")
|
||||
("r" mastodon-toot--reply "Reply")
|
||||
("m" mastodon-tl--dm-user "Direct Msg")
|
||||
("d" mastodon-toot--delete-toot "Delete"))
|
||||
"Toot"
|
||||
(("f" mastodon-toot-toggle-favourite "Favorite")
|
||||
("b" mastodon-toot-toggle-boost "Boost")
|
||||
("s" mastodon-toot-toggle-bookmark "Save")
|
||||
("y" mastodon-toot-copy-toot-url "Copy URL")
|
||||
("Y" mastodon-toot-copy-toot-text "Copy text"))
|
||||
(("f" mastodon-toot--toggle-favourite "Favorite")
|
||||
("b" mastodon-toot--toggle-boost "Boost")
|
||||
("s" mastodon-toot--toggle-bookmark "Save")
|
||||
("y" mastodon-toot--copy-toot-url "Copy URL")
|
||||
("Y" mastodon-toot--copy-toot-text "Copy text"))
|
||||
"Navigation"
|
||||
(("n" mastodon-tl-next-tab-item "next" :color pink)
|
||||
("p" mastodon-tl-previous-tab-item "previous" :color pink)
|
||||
(("n" mastodon-tl--next-tab-item "next" :color pink)
|
||||
("p" mastodon-tl--previous-tab-item "previous" :color pink)
|
||||
("," ha-mastodon-scroll-or-more "...more" :color pink))))))
|
||||
#+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.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package ement
|
||||
:straight (:host github :repo "alphapapa/ement.el")
|
||||
;; :vc (:url "https://github.com/alphapapa/ement.el")
|
||||
:config
|
||||
(major-mode-hydra-define ement-room-mode (:quit-key "q")
|
||||
("Send"
|
||||
|
|
@ -175,7 +175,7 @@ I'm thinking the [[https://zevlg.github.io/telega.el/][Telega package]] would be
|
|||
(when (fboundp 'evil-insert-state)
|
||||
(add-hook 'telega-chat-mode-hook 'evil-insert-state))
|
||||
|
||||
(ha-leader "a t" `("telega" . ,(lambda () (interactive) (ha-tab-bar-new "telega" #'telega)))))
|
||||
(ha-leader "a t" `("telega" . ,(ha-app-perspective "telega" #'telega))))
|
||||
#+end_src
|
||||
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
|
||||
(when (f-directory? "~/src/emacs-rpgdm")
|
||||
(use-package rpgdm
|
||||
:straight (:local-repo "~/src/emacs-rpgdm")
|
||||
:load-path "~/src/emacs-rpgdm"
|
||||
:commands (rpgdm-mode rpgdm-tables-load)
|
||||
:init (setq rpgdm-base (expand-file-name "~/src/emacs-rpgdm"))
|
||||
: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
|
||||
(when (f-directory? "~/src/emacs-rpgtk")
|
||||
(use-package rpgtk
|
||||
:straight (:local-repo "~/src/emacs-rpgtk")
|
||||
:load-path "~/src/emacs-rpgtk"
|
||||
:after hydra
|
||||
;; :commands (rpgtk-mode rpgtk-tables-load rpgtk-dice rpgtk-message)
|
||||
:custom
|
||||
|
|
@ -217,7 +217,7 @@ And my [[https://gitlab.com/howardabrams/emacs-ironsworn][new Ironsworn project]
|
|||
(when (f-directory? "~/src/emacs-ironsworn")
|
||||
(use-package rpgdm-ironsworn
|
||||
:after rpgdm
|
||||
:straight (:local-repo "~/src/emacs-ironsworn")
|
||||
:load-path "~/src/emacs-ironsworn"
|
||||
:init
|
||||
(setq rpgdm-ironsworn-project (expand-file-name "~/src/emacs-ironsworn")
|
||||
;; 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?
|
||||
#+begin_src emacs-lisp
|
||||
(use-package empv
|
||||
:straight (:host github :repo "isamert/empv.el")
|
||||
;; :vc (:url "https://github.com/isamert/empv.el")
|
||||
:general (ha-leader
|
||||
"a p" '(empv-map :wk "play music")))
|
||||
#+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.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package org-mac-link
|
||||
:straight (:host gitlab :repo "aimebertrand/org-mac-link")
|
||||
;; :vc (:url "https://gitlab.com/aimebertrand/org-mac-link")
|
||||
:config
|
||||
(ha-leader "i" '("insert app info" . org-mac-link-get-link)))
|
||||
#+end_src
|
||||
|
|
|
|||
366
ha-config.org
366
ha-config.org
|
|
@ -146,7 +146,8 @@ After reading [[https://irreal.org/blog/?p=12139][Jon Sander’s essay]] as well
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package emacs-everywhere
|
||||
:straight (:host github :repo "tecosaur/emacs-everywhere"))
|
||||
;; :vc (:url "https://github.com/tecosaur/emacs-everywhere")
|
||||
)
|
||||
#+end_src
|
||||
|
||||
This package /called outside of Emacs/, so I bound a keybinding to iCanHazShortcut:
|
||||
|
|
@ -225,7 +226,6 @@ 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.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package recentf
|
||||
:straight (:type built-in)
|
||||
:config
|
||||
(setq recentf-auto-cleanup 'never) ;; disable before we start recentf!
|
||||
(recentf-mode 1))
|
||||
|
|
@ -336,10 +336,13 @@ The [[https://github.com/minad/vertico][vertico]] package puts the completing re
|
|||
(use-package vertico
|
||||
:config (vertico-mode))
|
||||
#+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:
|
||||
#+begin_src emacs-lisp
|
||||
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(use-package vertico-directory
|
||||
:straight (el-patch :files ("~/.emacs.d/straight/repos/vertico/extensions/vertico-directory.el"))
|
||||
:load-path "~/.emacs.d/repos/vertigo/extensions"
|
||||
;; :straight (:files ("~/.emacs.d/straight/repos/vertico/extensions/vertico-directory.el"))
|
||||
;; More convenient directory navigation commands
|
||||
:bind (:map vertico-map
|
||||
("RET" . vertico-directory-enter)
|
||||
|
|
@ -380,7 +383,7 @@ How does it compare? Once upon a time, I enjoyed typing ~plp~ for =package-list-
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package fussy
|
||||
;; :straight (:host github :repo "jojojames/fussy")
|
||||
;; ;; :vc (:url "https://github.com/jojojames/fussy")
|
||||
:config
|
||||
(push 'fussy completion-styles)
|
||||
(setq completion-category-defaults nil
|
||||
|
|
@ -571,7 +574,7 @@ The [[https://github.com/minad/cape][Cape project]] deliver particular [[help:co
|
|||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(use-package cape
|
||||
:straight (:host github :repo "minad/cape")
|
||||
;; :vc (:url "https://github.com/minad/cape")
|
||||
:init
|
||||
(setq completion-at-point-functions (list #'cape-emoji)))
|
||||
#+END_SRC
|
||||
|
|
@ -585,50 +588,20 @@ Each programming environment might need some particular love. For instance:
|
|||
#+END_SRC
|
||||
|
||||
|
||||
*** Company
|
||||
The [[http://company-mode.github.io/][company project]] for completion back-ends work well with LSP.
|
||||
|
||||
Do I want it to display whenever there is a pause in the conversation (set =company-minimum-prefix-length= to a large number, or set =company-idle-delay=), or do I want it to only show when I push the =TAB= or other key (see =company-indent-or-complete-common=).
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package company
|
||||
:custom
|
||||
(company-minimum-prefix-length 3) ; default
|
||||
(company-idle-delay 0.5)
|
||||
(company-tooltip-align-annotations t)
|
||||
(company-tooltip-limit 9)
|
||||
(company-tooltip-flip-when-above t)
|
||||
(company-show-quick-access 'left)
|
||||
|
||||
:bind (("M-/" . company-complete)
|
||||
:map company-mode-map
|
||||
("M-/" . company-other-backend))
|
||||
|
||||
:config
|
||||
(add-to-list 'company-backends 'company-yasnippet)
|
||||
|
||||
(set-face-attribute 'company-tooltip nil
|
||||
:family "Cascadia Code NF"
|
||||
:height 120)
|
||||
|
||||
:hook (after-init . global-company-mode))
|
||||
#+END_SRC
|
||||
|
||||
Another idea, is I can trigger the company with a M-/ but then view /other backends/ by re-hitting that keybinding.
|
||||
*** Corfu
|
||||
The default completion system either inserts the first option directly in the text (without cycling, so let’s hope it gets it right the first time), or presents choices in another buffer (who wants to hop to it to select an expansion).
|
||||
|
||||
After using [[http://company-mode.github.io/][company]] for my completion back-end, I switched to [[https://github.com/minad/corfu][corfu]] as it works with the variable-spaced font of my org files (also see [[https://takeonrules.com/2022/01/17/switching-from-company-to-corfu-for-emacs-completion/][this essay]] for my initial motivation).
|
||||
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
#+begin_src emacs-lisp
|
||||
(use-package corfu
|
||||
;; :vc (:url "https://github.com/minad/corfu")
|
||||
:custom
|
||||
(corfu-cycle t)
|
||||
(corfu-separator ?\s)
|
||||
:init
|
||||
:config
|
||||
(global-corfu-mode))
|
||||
#+end_src
|
||||
|
||||
*** Snippets
|
||||
Using [[https://github.com/joaotavora/yasnippet][yasnippet]] to expand templates into text:
|
||||
|
||||
|
|
@ -704,7 +677,7 @@ As I've mentioned [[http://www.howardism.org/Technical/Emacs/beep-for-emacs.html
|
|||
'libnotify)))
|
||||
|
||||
(use-package beep
|
||||
:straight (:local-repo "~/src/hamacs/elisp")
|
||||
:load-path "~/src/hamacs/elisp"
|
||||
:hook (after-init . ha-random-startup-message)
|
||||
:commands (beep-when-finished beep-when-run-too-long)
|
||||
:config
|
||||
|
|
@ -957,13 +930,14 @@ Since I wasn’t using all the features that [[https://github.com/bbatsov/projec
|
|||
(ha-leader
|
||||
"p" '(:ignore t :which-key "projects")
|
||||
"p W" '("initialize workspace" . ha-workspace-initialize)
|
||||
"p p" '("switch project" . ha-tab-bar-new-project)
|
||||
"p n" '("new project space" . ha-project-persp)
|
||||
|
||||
"p !" '("run cmd in project root" . project-shell-command)
|
||||
"p &" '("run cmd async" . project-async-shell-command)
|
||||
"p a" '("add new project" . project-remember-projects-under)
|
||||
"p d" '("dired" . project-dired)
|
||||
"p k" '("kill project buffers" . project-kill-buffers)
|
||||
"p p" '("switch project" . project-switch-project)
|
||||
"p x" '("remove known project" . project-forget-project)
|
||||
|
||||
"p f" '("find file" . project-find-file)
|
||||
|
|
@ -977,147 +951,204 @@ Since I wasn’t using all the features that [[https://github.com/bbatsov/projec
|
|||
"p s" '("project shell" . project-shell)))
|
||||
#+end_src
|
||||
** Workspaces
|
||||
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.
|
||||
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.
|
||||
|
||||
Couple notes:
|
||||
- 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.
|
||||
I build a Hydra to dynamically list the current projects as well as select the project.
|
||||
To do this, we need a way to generate a string of the perspectives in alphabetical order:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-tab-bar-new (name &optional bff)
|
||||
"Create a new tab with a NAME.
|
||||
With a non-nil IFF, call IFF as a function or switch
|
||||
to the IFF buffer or the files listed."
|
||||
(interactive "sWorkspace Name: ")
|
||||
(tab-bar-switch-to-tab name)
|
||||
(when bff
|
||||
(cond
|
||||
((listp bff) (find-file (car bff))
|
||||
(dolist (f (cdr bff))
|
||||
(split-window-right)
|
||||
(find-file f)))
|
||||
((fboundp bff) (call-interactively bff))
|
||||
((bufferp bff) (switch-to-buffer bff)))))
|
||||
(defun ha--persp-label (num names)
|
||||
"Return string of numbered elements.
|
||||
NUM is the starting number and NAMES is a list of strings."
|
||||
(when names
|
||||
(concat
|
||||
(format " %d: %s%s" ; Shame that the following doesn't work:
|
||||
num ; (propertize (number-to-string num) :foreground "#00a0")
|
||||
(car names) ; Nor does surrounding the number with underbars.
|
||||
|
||||
(if (equal (car names) (persp-name (persp-curr))) "*" ""))
|
||||
(ha--persp-label (1+ num) (cdr names)))))
|
||||
|
||||
(defun ha-persp-labels ()
|
||||
"Return a string of numbered elements from a list of names."
|
||||
(ha--persp-label 1 (sort (hash-table-keys (perspectives-hash)) 's-less?)))
|
||||
#+end_src
|
||||
|
||||
Create a new tab associated with a project:
|
||||
Build the hydra as well as configure the =perspective= project.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-tab-bar-new-project (project-dir)
|
||||
"Create a new tab/workspace based on a project.
|
||||
The project is defined by the PROJECT-DIR directory."
|
||||
(interactive (list (completing-read "Project: " (project-known-project-roots))))
|
||||
(let ((name (project-name (project-current nil project-dir)))
|
||||
(default-directory project-dir))
|
||||
(ha-tab-bar-new name)
|
||||
(project-switch-project project-dir)))
|
||||
(use-package perspective
|
||||
:custom
|
||||
(persp-modestring-short t)
|
||||
(persp-show-modestring t)
|
||||
|
||||
:config
|
||||
(setq persp-suppress-no-prefix-key-warning t)
|
||||
|
||||
(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
|
||||
|
||||
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:
|
||||
|
||||
Let’s give it a binding:
|
||||
#+begin_src emacs-lisp
|
||||
(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)))
|
||||
(ha-leader "TAB" '("workspaces" . hydra-workspace-leader/body))
|
||||
#+end_src
|
||||
|
||||
And some shortcut keys from the =general= project:
|
||||
When called, it /can/ look like:
|
||||
|
||||
#+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)
|
||||
"<tab> `" '("recent" . tab-bar-switch-to-recent-tab))
|
||||
[[file:screenshots/projects-hydra.png]]
|
||||
|
||||
(global-set-key (kbd "s-C-t") 'ha-tab-bar-new)
|
||||
(global-set-key (kbd "s-C-[") 'tab-bar-switch-to-prev-tab)
|
||||
(global-set-key (kbd "s-C-]") 'tab-bar-switch-to-next-tab)
|
||||
|
||||
(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."
|
||||
The /special/ perspective is a nice shortcut to the one I use the most:
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-switch-to-special ()
|
||||
"Change to the projects perspective."
|
||||
(interactive)
|
||||
;; Remove all previously created keybindings:
|
||||
(ignore-errors
|
||||
(dolist (indx (number-sequence 0 9))
|
||||
(general-nmap :prefix "SPC" (format "<tab> %d" indx) nil)))
|
||||
(persp-switch "projects"))
|
||||
#+end_src
|
||||
|
||||
;; Loop through the existing tabs, create keys for each:
|
||||
(seq-do-indexed 'ha-tab-bar-update-tab-keybinding (tab-bar-tabs)))
|
||||
I often want a workspace dedicated to an /application/, so this function:
|
||||
|
||||
(defun ha-tab-bar-update-tab-keybinding (tab-deets indx)
|
||||
"Create a keybinding to jump to tab described by TAB-DEETS.
|
||||
The key sequence, `SPC' `TAB' then INDX."
|
||||
(when (< indx 10)
|
||||
(let ((name (alist-get 'name tab-deets)))
|
||||
(general-nmap :prefix "SPC"
|
||||
;; As indx is starts with 0, we need to create keybindings to
|
||||
;; match the tab labels by incrementing it by one ... unless,
|
||||
;; we are at 10, where we use 0 instead:
|
||||
(format "<tab> %d" (if (= indx 9) 0 (1+ indx)))
|
||||
`(,name . (lambda () (interactive)
|
||||
"Switch to a tab-bar by number"
|
||||
(setq ha-tab-bar-previous
|
||||
(tab-bar-tab-name-current))
|
||||
(tab-bar-select-tab ,(1+ indx))))))))
|
||||
#+END_SRC
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-app-perspective (name func)
|
||||
"Generate new perspective NAME, automatically running FUNC."
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(let ((already-started? (seq-contains-p (persp-names) name 'equal)))
|
||||
(persp-switch name)
|
||||
(unless already-started?
|
||||
(call-interactively func)))))
|
||||
#+end_src
|
||||
|
||||
Any time I create or delete a new tab, we can call =ha-tab-bar-update-names=:
|
||||
And I can then use it like:
|
||||
#+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
|
||||
(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)
|
||||
#+begin_src emacs-lisp
|
||||
(defvar ha-workspace-projects-personal nil "List of default projects with a name.")
|
||||
|
||||
(add-hook desktop-after-read-hook #'ha-tab-bar-update-names)
|
||||
#+END_SRC
|
||||
(add-to-list 'ha-workspace-projects-personal
|
||||
'("projects" "~/projects" ("breathe.org" "tasks.org")))
|
||||
(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
|
||||
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]].
|
||||
|
|
@ -1135,7 +1166,6 @@ Also, as [[https://www.bytedude.com/gpg-in-emacs/][bytedude]] mentions, I need t
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package epa-file
|
||||
:straight (:type built-in)
|
||||
:custom
|
||||
(epg-debug t)
|
||||
(auth-source-debug t)
|
||||
|
|
@ -1145,18 +1175,22 @@ Also, as [[https://www.bytedude.com/gpg-in-emacs/][bytedude]] mentions, I need t
|
|||
;; Make sure we prompt in the minibuffer for the password:
|
||||
(epg-pinentry-mode 'loopback)
|
||||
;; 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
|
||||
(setenv "GPG_AGENT_INFO" nil)
|
||||
(ignore-error (epa-file-enable)))
|
||||
(epa-file-enable))
|
||||
#+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.
|
||||
|
||||
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 :tangle no
|
||||
#+begin_src emacs-lisp
|
||||
(use-package org
|
||||
:config
|
||||
(require 'org-crypt)
|
||||
|
|
|
|||
|
|
@ -145,10 +145,12 @@ The [[https://github.com/emacs-dashboard/emacs-dashboard][emacs-dashboard]] proj
|
|||
(string-replace "\n" "" smaller-version)))
|
||||
|
||||
(setq dashboard-startup-banner
|
||||
;; Choose a random image from my collection of startup images:
|
||||
(thread-first "~/src/hamacs/support/dashboard"
|
||||
(directory-files t (rx ".png"))
|
||||
(seq-random-elt)))
|
||||
(if (ha-emacs-for-work?)
|
||||
"~/src/hamacs/support/teal-sticker.png"
|
||||
;; Choose a random image from my collection of startup images:
|
||||
(thread-first "~/src/hamacs/support/dashboard"
|
||||
(directory-files t (rx ".png"))
|
||||
(seq-random-elt))))
|
||||
|
||||
(setq dashboard-banner-logo-title
|
||||
(format "Emacs %s — %s"
|
||||
|
|
@ -167,12 +169,12 @@ The [[https://github.com/emacs-dashboard/emacs-dashboard][emacs-dashboard]] proj
|
|||
dashboard-set-heading-icons t
|
||||
dashboard-footer-messages (list (ha--dad-joke)))
|
||||
|
||||
:config
|
||||
(dashboard-setup-startup-hook)
|
||||
|
||||
;; Real shame that :config is incompatible with :hook, otherwise:
|
||||
;; :hook (dashboard-after-initialize . ha-dashboard)
|
||||
|
||||
:config
|
||||
(tab-bar-switch-to-tab "main")
|
||||
(dashboard-setup-startup-hook))
|
||||
(add-hook 'dashboard-after-initialize-hook 'ha-dashboard))
|
||||
#+end_src
|
||||
|
||||
This dashboard project requires [[https://github.com/purcell/page-break-lines][page-break-lines]] (which is a nice project):
|
||||
|
|
@ -262,7 +264,6 @@ The =dashboard= project hooks to [[help:emacs-startup-hook][emacs-startup-hook]]
|
|||
(defun ha-dashboard ()
|
||||
"Shows the extra stuff with the dashboard."
|
||||
(interactive)
|
||||
(tab-bar-switch-to-tab "main")
|
||||
(switch-to-buffer "*dashboard*")
|
||||
(setq-local mode-line-format nil)
|
||||
(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
|
||||
(use-package demo-it
|
||||
:straight (:local-repo "~/src/demo-it")
|
||||
;; :straight (:host github :repo "howardabrams/demo-it")
|
||||
:load-path "~/src/demo-it"
|
||||
;; :vc (:url "https://github.com/howardabrams/demo-it")
|
||||
:commands (demo-it-create demo-it-start demo-it-hide-mode-line
|
||||
demo-it--presentation-display-set)
|
||||
: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
|
||||
(use-package dslide
|
||||
:straight (dslide :host github :repo "positron-solutions/dslide")
|
||||
;; :vc (:url "https://github.com/positron-solutions/dslide")
|
||||
:commands (dslide-deck-start dslide-deck-stop)
|
||||
:custom
|
||||
(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
|
||||
(use-package dslide
|
||||
:straight (dslide :host github :repo "positron-solutions/dslide")
|
||||
;; :vc (:url "https://github.com/positron-solutions/dslide")
|
||||
:commands (dslide-narrow-hook)
|
||||
:hook (dslide-narrow . 'ha-slide-notes-update))
|
||||
#+END_SRC
|
||||
|
|
@ -256,8 +256,7 @@ The [[https://github.com/positron-solutions/moc][Master of Ceremonies]] package
|
|||
(use-package default-text-scale)
|
||||
|
||||
(use-package moc
|
||||
:straight (:type git :host github
|
||||
:repo "positron-solutions/moc"))
|
||||
;; :vc (:url "https://github.com/positron-solutions/moc"))
|
||||
#+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.
|
||||
|
|
@ -272,7 +271,7 @@ The [[https://github.com/trevorpogue/topspace][topspace]] project can pad the to
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package topspace
|
||||
:straight (:type git :host github :repo "trevorpogue/topspace"))
|
||||
;; :vc (:url "https://github.com/trevorpogue/topspace"))
|
||||
#+END_SRC
|
||||
|
||||
*** Showing Something associated with a Headline
|
||||
|
|
@ -307,7 +306,7 @@ To do this, add =:DSLIDE_ACTIONS: dslide-action-highlight-paragraphs= to the pro
|
|||
|
||||
#+begin_src elisp emacs-lisp :tangle no
|
||||
(use-package dslide
|
||||
:straight (:host github :repo "positron-solutions/dslide")
|
||||
;; :vc (:url "https://github.com/positron-solutions/dslide")
|
||||
:config
|
||||
(defclass dslide-action-highlight-paragraphs (dslide-action)
|
||||
((overlays :initform nil))
|
||||
|
|
|
|||
|
|
@ -63,14 +63,19 @@ To make the active window /more noticeable/, we /dim/ the in-active windows with
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package dimmer
|
||||
:custom (dimmer-adjustment-mode :foreground)
|
||||
: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)
|
||||
:custom (dimmer-adjustment-mode :foreground))
|
||||
#+end_src
|
||||
|
||||
(dimmer-mode t))
|
||||
I get issues with Magic and Dimmer, so let’s turn off this feature in certain windows:
|
||||
|
||||
#+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
|
||||
|
||||
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.
|
||||
|
|
@ -81,11 +86,10 @@ either be "there or not" which resulted large jumps and large distractions.
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package ultra-scroll
|
||||
:straight (:type git :host github :repo "jdtsmith/ultra-scroll")
|
||||
;; :vc (:url "https://github.com/jdtsmith/ultra-scroll")
|
||||
:config
|
||||
(setq scroll-conservatively 101 ; important!
|
||||
pixel-scroll-precision-interpolate-page t
|
||||
scroll-margin 0)
|
||||
scroll-margin 0)
|
||||
(ultra-scroll-mode 1))
|
||||
#+END_SRC
|
||||
** Find the Bloody Cursor
|
||||
|
|
@ -93,7 +97,7 @@ Large screen, lots of windows, so where is the cursor? While I used to use =hl-l
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package pulsar
|
||||
:straight (:host github :repo "protesilaos/pulsar")
|
||||
;; :vc (:url "https://github.com/protesilaos/pulsar")
|
||||
:custom
|
||||
(pulsar-face 'pulsar-generic)
|
||||
(pulsar-delay 0.15)
|
||||
|
|
@ -155,7 +159,7 @@ Am I ever really ever satisfied with any font? I regularly change my font based
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package mixed-pitch
|
||||
;; :straight (:host github :repo "jabranham/mixed-pitch")
|
||||
;; ;; :vc (:url "https://github.com/jabranham/mixed-pitch")
|
||||
:config
|
||||
(add-to-list 'mixed-pitch-fixed-pitch-faces 'org-property-value)
|
||||
(add-to-list 'mixed-pitch-fixed-pitch-faces 'org-special-keyword)
|
||||
|
|
@ -385,7 +389,7 @@ This project replaces [[https://github.com/domtronn/all-the-icons.el][all-the-ic
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package nerd-icons
|
||||
:straight (nerd-icons :type git :host github :repo "rainstormstudio/nerd-icons.el")
|
||||
;; :vc (:url "https://github.com/rainstormstudio/nerd-icons.el")
|
||||
:custom
|
||||
;; The Nerd Font you want to use in GUI defaults to fixed-font:
|
||||
(nerd-icons-font-family ha-fixed-font))
|
||||
|
|
@ -634,7 +638,7 @@ In code, if you drop a specific /text/ labels, we can highlight them with [[http
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package hl-todo
|
||||
:straight (:host github :repo "tarsius/hl-todo")
|
||||
;; :vc (:url "https://github.com/tarsius/hl-todo")
|
||||
:config
|
||||
(setq hl-todo-keyword-faces
|
||||
`(("TODO" . ,(face-foreground 'warning))
|
||||
|
|
@ -650,16 +654,14 @@ Suggests to bind some keys to =hl-todo-next= in order to jump from tag to tag, b
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package consult-todo
|
||||
:straight (:host github :repo "liuyinz/consult-todo")
|
||||
;; :vc (:url "https://github.com/liuyinz/consult-todo")
|
||||
:init
|
||||
(defconst consult-todo--narrow
|
||||
'((?t . "TODO")
|
||||
(?f . "FIXME")
|
||||
(?n . "NOTE"))
|
||||
"Mapping of narrow and keywords.")
|
||||
;; :config
|
||||
;; (evil-define-key '(normal) 'global "g t" '("jump todos" . consult-todo))
|
||||
)
|
||||
:general (:states 'normal "g t" '("jump todos" . consult-todo)))
|
||||
#+end_src
|
||||
* 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).
|
||||
|
|
|
|||
|
|
@ -132,8 +132,8 @@ Also, let's do some basic configuration of Emacs' mail system:
|
|||
#+end_src
|
||||
|
||||
Create a special mail perspective:
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(ha-leader "a M" `("mail" . ,(ha-tab-bar-new "mail" #'notmuch)))
|
||||
#+begin_src emacs-lisp
|
||||
(ha-leader "a M" `("mail" . ,(ha-app-perspective "mail" #'notmuch)))
|
||||
#+end_src
|
||||
* Configuration
|
||||
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
|
||||
(use-package ol-notmuch
|
||||
:after org
|
||||
:straight (:type built-in)
|
||||
|
||||
:config (add-to-list 'org-modules 'ol-notmuch))
|
||||
#+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.
|
||||
|
|
|
|||
|
|
@ -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=:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package eshell
|
||||
:straight (:type built-in)
|
||||
|
||||
:hook (eshell-mode . ha-eshell-setup))
|
||||
#+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]].
|
||||
#+begin_src emacs-lisp
|
||||
(use-package pcre2el
|
||||
:straight (:host github :repo "joddie/pcre2el")
|
||||
;; :vc (:url "https://github.com/joddie/pcre2el")
|
||||
:config
|
||||
(defmacro prx (&rest expressions)
|
||||
"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
|
||||
(use-package eat
|
||||
:after eshell
|
||||
:straight (:repo "https://codeberg.org/akib/emacs-eat")
|
||||
;; :vc (:url "https://codeberg.org/akib/emacs-eat")
|
||||
:hook (eshell-load . eat-eshell-visual-command-mode))
|
||||
#+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=.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package eshell
|
||||
:straight (:type built-in)
|
||||
|
||||
:custom (eshell-banner-message '(ha-eshell-banner))
|
||||
:init
|
||||
(setq eshell-error-if-no-glob t
|
||||
|
|
|
|||
24
ha-evil.org
24
ha-evil.org
|
|
@ -193,29 +193,12 @@ I am not a long term VI user, and don’t have much need for any of its control
|
|||
;; I have better window control:
|
||||
(kbd "C-w") 'sp-kill-region))
|
||||
#+end_src
|
||||
|
||||
** Evil Escape
|
||||
I find that myself not noticing I’m in /insert/ mode, and start typing =j= repeatedly to go down a line, and end up typing something like: =jjjjjjjjjjjj=.
|
||||
|
||||
To remedy this, I’m using the [[https://www.emacswiki.org/emacs/KeyChord][KeyChord]] code:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(use-package key-chord
|
||||
:config
|
||||
(setq key-chord-two-keys-delay 0.1)
|
||||
|
||||
(key-chord-define evil-insert-state-map "jk" 'evil-normal-state)
|
||||
(key-chord-define evil-insert-state-map "jj" 'evil-normal-state)
|
||||
(key-chord-define evil-insert-state-map "kk" 'evil-normal-state)
|
||||
|
||||
(key-chord-mode 1))
|
||||
#+END_SRC
|
||||
** Evil Text Object Line
|
||||
Delete a line, ~d d~ is in basic VI. Since some commands use text objects, and the basic text object doesn’t include lines, the [[https://github.com/emacsorphanage/evil-textobj-line][evil-textobj-line]] project adds that:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package evil-textobj-line)
|
||||
#+end_src
|
||||
Now ~v i l~ selects the line without initial/trailing whitespace, and ~v a l~ selects the line with spaces, and ~S-v~ selects the line with the final carriage return. Is this much of an improvement? Well, wrapping a line in parenthesis, is just ~y s i l )~
|
||||
Now ~v i l~ and ~v a l~ works as you’d expect, but does this improve on ~S-v~?
|
||||
** Text Objects based on Indentation
|
||||
The [[https://github.com/TheBB/evil-indent-plus][evil-indent-plus]] project creates text objects based on the indentation level, similar to how the ~b~ works with “blocks” of code.
|
||||
#+begin_src emacs-lisp
|
||||
|
|
@ -419,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]]:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package align
|
||||
:straight (:type built-in)
|
||||
|
||||
:config
|
||||
(add-to-list 'align-rules-list
|
||||
`("lisp-assignments"
|
||||
|
|
@ -506,8 +489,9 @@ Notes:
|
|||
** 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.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(use-package better-jumper
|
||||
;; :vc (:url "https//github.com/gilbertw1/better-jumper")
|
||||
:config
|
||||
(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:
|
||||
#+begin_src emacs-lisp
|
||||
(ha-leader "a f" `("feed reader" . ,(ha-tab-bar-new "elfeed" #'elfeed)))
|
||||
(ha-leader "a f" `("feed reader" . ,(ha-app-perspective "elfeed" #'elfeed)))
|
||||
#+end_src
|
||||
* The Feeds :elfeed:
|
||||
The [[https://github.com/remyhonig/elfeed-org][elfeed-org]] project configures =elfeed= to read the RSS feeds from an Org file … like this one!
|
||||
|
|
|
|||
|
|
@ -335,8 +335,9 @@ And the collection of useful operations:
|
|||
"b O" '("other" . project-switch-buffer-to-other-window)
|
||||
"b i" '("ibuffer" . ibuffer)
|
||||
"b I" '("ibuffer" . ibuffer-other-window)
|
||||
"b k" '("persp remove" . persp-remove-buffer)
|
||||
"b N" '("new" . evil-buffer-new)
|
||||
"b d" '("delete" . kill-buffer)
|
||||
"b d" '("delete" . persp-kill-buffer*)
|
||||
"b r" '("revert" . revert-buffer)
|
||||
"b s" '("save" . save-buffer)
|
||||
"b S" '("save all" . evil-write-all)
|
||||
|
|
@ -520,7 +521,6 @@ The goal here is toggle switches and other miscellaneous settings.
|
|||
"t T" '("tramp mode" . tramp-mode)
|
||||
"t v" '("visual" . visual-line-mode)
|
||||
"t w" '("whitespace" . whitespace-mode)
|
||||
"t <tab>" '("tab-bar" . tab-bar-mode)
|
||||
|
||||
"t <escape>" '(keyboard-escape-quit :which-key t)
|
||||
"t C-g" '(keyboard-escape-quit :which-key t))
|
||||
|
|
@ -546,10 +546,13 @@ And put it on the toggle menu:
|
|||
(ha-leader "t n" '("narrow" . ha-narrow-dwim))
|
||||
#+end_src
|
||||
* Window Operations
|
||||
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.
|
||||
|
||||
While it comes with Emacs, I use [[https://www.emacswiki.org/emacs/WinnerMode][winner-mode]] to undo window-related changes:
|
||||
#+begin_src emacs-lisp
|
||||
(tab-bar-history-mode)
|
||||
(use-package winner
|
||||
:custom
|
||||
(winner-dont-bind-my-keys t)
|
||||
:config
|
||||
(winner-mode +1))
|
||||
#+end_src
|
||||
** Ace Window
|
||||
Use the [[https://github.com/abo-abo/ace-window][ace-window]] project to jump to any window you see.
|
||||
|
|
@ -877,7 +880,7 @@ Remember these keys in the *Help* buffer:
|
|||
Let's make Info behave a little more VI-like:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package info
|
||||
:straight (:type built-in)
|
||||
|
||||
:general
|
||||
(:states 'normal :keymaps 'Info-mode-map
|
||||
"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:
|
||||
#+begin_src emacs-lisp
|
||||
(ha-leader "a i" `("irc" . ,(ha-tab-bar-new "irc" #'ha-erc)))
|
||||
(ha-leader "a i" `("irc" . ,(ha-app-perspective "irc" #'ha-erc)))
|
||||
#+end_src
|
||||
|
||||
And a quick shortcuts to call it:
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#+author: Howard Abrams
|
||||
#+date: 2024-07-07
|
||||
#+filetags: emacs hamacs
|
||||
#+lastmod: [2025-02-20 Thu]
|
||||
#+lastmod: [2025-09-09 Tue]
|
||||
|
||||
A literate programming file for literate programming in Emacs Org Files.
|
||||
|
||||
|
|
@ -862,11 +862,13 @@ I would like to make the /filename/ more readable, I use the =s-match= again, to
|
|||
#+begin_src emacs-lisp
|
||||
(defun ha-hamacs-edit--file-title (file)
|
||||
"Return a more readable string from FILE."
|
||||
(s-with file
|
||||
(s-match ha-hamacs-edit-file-to-title)
|
||||
(second)
|
||||
(s-replace "-" " ")
|
||||
(s-titleize)))
|
||||
(if file
|
||||
(s-with file
|
||||
(s-match ha-hamacs-edit-file-to-title)
|
||||
(second)
|
||||
(s-replace "-" " ")
|
||||
(s-titleize))
|
||||
file))
|
||||
|
||||
(defvar ha-hamacs-edit-file-to-title
|
||||
(rx (optional (or "README-" "ha-"))
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ The RSS needs UUIDs:
|
|||
|
||||
#+BEGIN_SRC emacs-lisp results silent
|
||||
(use-package uuidgen
|
||||
:straight (:host github :repo "emacsmirror/uuidgen"))
|
||||
;; :vc (:url "https://github.com/emacsmirror/uuidgen"))
|
||||
|
||||
(defun org-icalendar-create-uid (&rest ignored)
|
||||
"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
|
||||
(use-package ox-rss
|
||||
:straight (:host github :repo "emacsmirror/ox-rss"))
|
||||
;; :vc (:url "https://github.com/emacsmirror/ox-rss"))
|
||||
|
||||
(use-package org
|
||||
:config
|
||||
|
|
@ -64,7 +64,7 @@ Render my code with my font colors:
|
|||
Also, we need Jack, and his HTML prowess:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package jack
|
||||
:straight (:host github :repo "tonyaldon/jack")
|
||||
;; :vc (:url "https://github.com/tonyaldon/jack")
|
||||
:commands (jack-html))
|
||||
#+end_src
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ A literate programming file for making Org file more readable.
|
|||
#+end_src
|
||||
* Introduction
|
||||
I like having org-mode files look more like a word processor than having it look like programming code. But that is me. The end results:
|
||||
|
||||
[[file:screenshots/org-as-word-processor.png]]
|
||||
* General Org Settings
|
||||
Since I use ellipsis in my writing… to /change/ how org renders a collapsed heading.
|
||||
|
|
@ -101,7 +102,7 @@ And hook this function to Org:
|
|||
The list of things to try:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq org-hide-leading-stars t) ; or t
|
||||
(setq org-hide-leading-stars nil) ; or t
|
||||
#+END_SRC
|
||||
|
||||
** Markup View
|
||||
|
|
@ -109,7 +110,7 @@ The variable, =org-hide-emphasis-markers=, is key to pretending that Emacs can b
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package org-appear
|
||||
:straight (:type git :host github :repo "awth13/org-appear")
|
||||
;; :vc (:url "https://github.com/awth13/org-appear")
|
||||
:init (setq org-appear-trigger 'manual)
|
||||
:hook
|
||||
((org-mode . (lambda ()
|
||||
|
|
@ -330,7 +331,7 @@ The [[https://github.com/minad/org-modern][org-modern]] project attempts to do a
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package org-modern
|
||||
:straight (:host github :repo "minad/org-modern")
|
||||
;; :vc (:url "https://github.com/minad/org-modern")
|
||||
:after org
|
||||
:hook ((org-mode . org-modern-mode)
|
||||
(org-agenda-finalize . org-modern-agenda))
|
||||
|
|
@ -366,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:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package org-padding
|
||||
:straight (:host github :repo "TonCherAmi/org-padding")
|
||||
;; :vc (:url "https://github.com/TonCherAmi/org-padding")
|
||||
:hook (org-mode . org-padding-mode)
|
||||
:config
|
||||
(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
|
||||
#+tags: emacs org
|
||||
#+startup: inlineimages
|
||||
#+lastmod: [2025-12-02 Tue]
|
||||
#+lastmod: [2025-09-08 Mon]
|
||||
|
||||
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
|
||||
(use-package org
|
||||
;; TODO: Using the latest org-mode
|
||||
;; :straight (:type built-in)
|
||||
;;
|
||||
:mode (("\\.org" . org-mode))
|
||||
:init
|
||||
<<variables>>
|
||||
|
|
@ -245,32 +245,6 @@ And I would like to have cute little icons for those states:
|
|||
("^ +\\([-*]\\) "
|
||||
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•")))))))
|
||||
#+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
|
||||
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.
|
||||
|
||||
|
|
@ -304,7 +278,7 @@ Came up with a great way to search a project for Org-specific files, and wrote [
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package org-find-file
|
||||
:straight nil
|
||||
|
||||
:config
|
||||
(ha-leader "f o" '("load org" . org-find-file)))
|
||||
#+end_src
|
||||
|
|
@ -515,8 +489,12 @@ 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:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package deflate
|
||||
:vc (:url "https://github.com/skuro/deflate.git"))
|
||||
|
||||
(use-package plantuml-mode
|
||||
:straight (:host github :repo "skuro/plantuml-mode")
|
||||
;; :vc (:url "https://github.com/skuro/plantuml-mode")
|
||||
:after deflate
|
||||
:init
|
||||
(setq org-plantuml-jar-path (expand-file-name "~/bin/plantuml.jar")))
|
||||
#+end_src
|
||||
|
|
@ -569,8 +547,7 @@ Of course, since we are dealing with Emacs, where we assimilate any good idea. J
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package pikchr-mode
|
||||
:straight (:local-repo "~/src/pikchr-mode")
|
||||
;; :straight (:host github :repo "kljohann/pikchr-mode")
|
||||
;; :vc (:url "https://github.com/kljohann/pikchr-mode")
|
||||
:custom
|
||||
(pikchr-executable "~/bin/pikchr"))
|
||||
#+end_src
|
||||
|
|
@ -758,7 +735,7 @@ I have a special version of tweaked [[file:elisp/ox-confluence.el][Confluence ex
|
|||
#+begin_src emacs-lisp
|
||||
(use-package ox-confluence
|
||||
:after org
|
||||
:straight nil ; Located in my "elisp" directory
|
||||
; Located in my "elisp" directory
|
||||
:config
|
||||
(ha-leader :keymaps 'org-mode-map
|
||||
"o E" '("to confluence" . ox-export-to-confluence)))
|
||||
|
|
@ -769,7 +746,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]]:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package jack
|
||||
:straight (:host github :repo "tonyaldon/jack")
|
||||
;; :vc (:url "https://github.com/tonyaldon/jack")
|
||||
:commands (jack-html))
|
||||
#+end_src
|
||||
|
||||
|
|
@ -826,7 +803,7 @@ I've been working on my own [[http://www.howardism.org/Technical/Emacs/focused-w
|
|||
(use-package async)
|
||||
|
||||
(use-package ha-focus
|
||||
:straight (:type built-in)
|
||||
|
||||
:config
|
||||
(ha-leader
|
||||
"o f" '("begin focus" . ha-focus-begin)
|
||||
|
|
@ -877,7 +854,7 @@ And the Emacs interface to that:
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package jinx
|
||||
:straight (:host github :repo "minad/jinx" :files (:defaults "jinx-mod.c" "emacs-module.h"))
|
||||
;; :vc (:url "https://github.com/minad/jinx" :files (:defaults "jinx-mod.c" "emacs-module.h"))
|
||||
:hook (emacs-startup . global-jinx-mode)
|
||||
:bind (("C-;" . jinx-correct-nearest)
|
||||
("s-;" . jinx-correct-nearest)
|
||||
|
|
@ -1276,7 +1253,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]]:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package logos
|
||||
:straight (:host gitlab :repo "protesilaos/logos")
|
||||
;; :vc (:url "https://gitlab.com/protesilaos/logos")
|
||||
:init
|
||||
(setq logos-outlines-are-pages t
|
||||
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
|
||||
(use-package spatial-navigate
|
||||
:straight (:repo "https://codeberg.org/ideasman42/emacs-spatial-navigate")
|
||||
;; :vc (:url "https://codeberg.org/ideasman42/emacs-spatial-navigate")
|
||||
:config
|
||||
(pretty-hydra-define spatial-navigate (:color amaranth :quit-key "q")
|
||||
("Box"
|
||||
|
|
@ -62,7 +62,7 @@ The [[https://github.com/antonj/Highlight-Indentation-for-Emacs][Highlight-Inden
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package highlight-indentation
|
||||
:straight (:host github :repo "antonj/Highlight-Indentation-for-Emacs")
|
||||
;; :vc (:url "https://github.com/antonj/Highlight-Indentation-for-Emacs")
|
||||
:hook ((yaml-mode . highlight-indentation-mode)
|
||||
(python-mode . highlight-indentation-mode)))
|
||||
#+end_src
|
||||
|
|
@ -119,7 +119,7 @@ Allow this mode in Org blocks:
|
|||
And we hook
|
||||
#+begin_src emacs-lisp
|
||||
(use-package yaml-pro
|
||||
:straight (:host github :repo "zkry/yaml-pro")
|
||||
;; :vc (:url "https://github.com/zkry/yaml-pro")
|
||||
:after yaml-mode
|
||||
:hook ((yaml-mode . yaml-pro-mode)))
|
||||
#+end_src
|
||||
|
|
@ -224,7 +224,7 @@ Do I consider all YAML files an Ansible file needing [[https://github.com/k1LoW/
|
|||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package ansible
|
||||
:straight (:host gitlab :repo "emacs-ansible/emacs-ansible")
|
||||
;; :vc (:url "https://gitlab.com/emacs-ansible/emacs-ansible")
|
||||
;; :mode ((rx (or "playbooks" "roles") (one-or-more any) ".y" (optional "a") "ml") . ansible-mode)
|
||||
:config
|
||||
(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
|
||||
(use-package poly-ansible
|
||||
:straight (:host github :repo "emacsmirror/poly-ansible")
|
||||
;; :vc (:url "https://github.com/emacsmirror/poly-ansible")
|
||||
:after ansible)
|
||||
#+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:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package ob-clojure
|
||||
:straight (:type built-in)
|
||||
|
||||
:custom
|
||||
(org-babel-clojure-backend 'cider)
|
||||
:config
|
||||
|
|
|
|||
|
|
@ -71,7 +71,11 @@ 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.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(use-package suggest)
|
||||
(use-package spinner
|
||||
:vc (:url "https://github.com/Malabarba/spinner.el"))
|
||||
|
||||
(use-package suggest
|
||||
:after spinner)
|
||||
#+end_src
|
||||
* Navigation
|
||||
** Goto Definitions
|
||||
|
|
@ -280,7 +284,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 …
|
||||
#+begin_src emacs-lisp
|
||||
(use-package emr
|
||||
;; :straight (:host github :repo "Wilfred/emacs-refactor")
|
||||
;; ;; :vc (:url "https://github.com/Wilfred/emacs-refactor")
|
||||
:config
|
||||
(pretty-hydra-define+ lisp-refactor nil
|
||||
("To 𝛌"
|
||||
|
|
@ -366,3 +370,4 @@ 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: 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
|
||||
exit
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ The [[https://github.com/mihaimaruseac/hindent][hindent package]] looks interest
|
|||
* Haskell and Org
|
||||
#+begin_src emacs-lisp
|
||||
(use-package ob-haskell
|
||||
:straight (:type built-in)
|
||||
|
||||
:config
|
||||
(add-to-list 'org-babel-load-languages '(haskell . t)))
|
||||
#+end_src
|
||||
|
|
|
|||
|
|
@ -136,14 +136,7 @@ Next, after reading David Vujic’s [[https://davidvujic.blogspot.com/2025/03/ar
|
|||
# c.InteractiveShellApp.exec_lines = ['%autoreload 2']
|
||||
#+END_SRC
|
||||
|
||||
** Isolated Python Environments
|
||||
While the Python community (and my work at my company) had difficulty transitioning from Python 2 to 3, I often run into issues needing a particular Python version and modules. After playing around with different approaches, I’m finding:
|
||||
* Docker environments are nicely isolated, but annoying to work from outside the container
|
||||
* The Builtin =venv= is works well for different library modules, but not for different versions
|
||||
* The =pyenv= deals with different Python versions, but is overkill for library isolation
|
||||
|
||||
While the [[https://github.com/marcwebbie/auto-virtualenv][auto-virtualenv]] project attempts to resolve this, I’m using the [[file:ha-programming.org::*Virtual Environments with direnv][direnv project]] abstraction for situations where I need project-specific isolation in more than just Python.
|
||||
*** Virtual Environments
|
||||
** Virtual Environment
|
||||
Use the built-in module, venv, to create isolated Python environments for specific projects, enabling you to manage dependencies separately.
|
||||
|
||||
Create a virtual environment, either in the project’s directory, or in a global spot:
|
||||
|
|
@ -167,8 +160,8 @@ Now, do what you need to do with this isolation:
|
|||
#+BEGIN_SRC sh :tangle no
|
||||
pip install -r test-requirements.txt
|
||||
#+END_SRC
|
||||
*** Managing Python Versions
|
||||
[[https://github.com/pyenv/pyenv][Pyenv]] is a tool for managing multiple versions of Python on your machine, allowing you to switch between them easily (see [[https://realpython.com/intro-to-pyenv/][this essay]]). On a Mac, installed it via Homebrew:
|
||||
** Virtual Environment with new Python Version
|
||||
Pyenv is a tool for managing multiple versions of Python on your machine, allowing you to switch between them easily. On a Mac, installed it via Homebrew:
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
brew install readline xz
|
||||
|
|
@ -220,55 +213,16 @@ Also, you need the following in your =~/.config/direnv/direnvrc= file (which I h
|
|||
fi
|
||||
}
|
||||
#+end_src
|
||||
|
||||
Tell Emacs about [[https://github.com/pythonic-emacs/pyenv-mode][pyenv-mode]]:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package pyenv-mode
|
||||
:config
|
||||
(defun setup-pyenv ()
|
||||
"Pyenv."
|
||||
(setenv "WORKON_HOME" "~/.pyenv/versions")
|
||||
(pyenv-mode +1)))
|
||||
#+END_SRC
|
||||
|
||||
Now specify the =pyenv= Python version by calling [[help:pyenv-mode-set][pyenv-mode-set]]:
|
||||
|
||||
#+begin_example
|
||||
M-x pyenv-mode-set
|
||||
#+end_example
|
||||
|
||||
When you run inferior Python processes (like =run-python=), the process will start inside the specified Python installation. You can unset the current version with:
|
||||
|
||||
#+begin_example
|
||||
M-x pyenv-mode-unset
|
||||
#+end_example
|
||||
|
||||
Or, we can do it automatically when we get into a project (if the project has a =.python-version= file):
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package pyenv-mode
|
||||
:config
|
||||
(defun project-pyenv-mode-set (&rest _)
|
||||
"Set pyenv version matching project name."
|
||||
(let* ((filename (thread-first
|
||||
(project-current)
|
||||
(project-root)
|
||||
(file-name-concat ".python-version")))
|
||||
(version (when (file-exists-p filename)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents filename)
|
||||
(buffer-string)))))
|
||||
(when version
|
||||
(pyenv-mode-set version)
|
||||
(pyenv-mode-unset))))
|
||||
|
||||
;; Either set/unset the pyenv version whenever changing tabs:
|
||||
(add-hook 'tab-bar-tab-post-select-functions 'project-pyenv-mode-set))
|
||||
#+END_SRC
|
||||
|
||||
*** Docker Environment
|
||||
Docker allows you to isolate your project's environment. The downside is that you are using Docker and probably a bloated container. On my work laptop, a Mac, this creates a behemoth virtual machine that immediately spins the fans like a wind tunnel.
|
||||
** Editing Python Code
|
||||
Let’s integrate this [[https://github.com/wbolster/evil-text-object-python][Python support for evil-text-object]] project:
|
||||
#+begin_src emacs-lisp
|
||||
(when (fboundp 'evil-define-text-object)
|
||||
(use-package evil-text-object-python
|
||||
:hook (python-mode . evil-text-object-python-add-bindings)))
|
||||
#+end_src
|
||||
This allows me to delete a Python “block” using ~dal~.
|
||||
** Docker Environment
|
||||
Docker really allows you to isolate your project's environment. The downside is that you are using Docker and probably a bloated container. On my work laptop, a Mac, this creates a behemoth virtual machine that immediately spins the fans like a wind tunnel.
|
||||
|
||||
But, but... think of the dependencies!
|
||||
|
||||
|
|
@ -282,14 +236,6 @@ Your project's =.envrc= file would contain something like:
|
|||
|
||||
container_layout
|
||||
#+end_src
|
||||
** Editing Python Code
|
||||
Let’s integrate this [[https://github.com/wbolster/evil-text-object-python][Python support for evil-text-object]] project:
|
||||
#+begin_src emacs-lisp
|
||||
(when (fboundp 'evil-define-text-object)
|
||||
(use-package evil-text-object-python
|
||||
:hook (python-mode . evil-text-object-python-add-bindings)))
|
||||
#+end_src
|
||||
This allows me to delete a Python “block” using ~dal~.
|
||||
** Unit Tests
|
||||
#+begin_src emacs-lisp
|
||||
(use-package python-pytest
|
||||
|
|
@ -321,22 +267,8 @@ The [[https://elpy.readthedocs.io/en/latest/introduction.html][Elpy Project]] ex
|
|||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package elpy
|
||||
:init
|
||||
(advice-add 'python-mode :before 'elpy-enable)
|
||||
:config
|
||||
;; (elpy-enable)
|
||||
(setq elpy-test-runner 'elpy-test-pytest-runner)
|
||||
(setq elpy-formatter 'black)
|
||||
(setq elpy-shell-echo-input nil)
|
||||
(setq elpy-modules (delq 'elpy-module-flymake elpy-modules)))
|
||||
#+END_SRC
|
||||
|
||||
After we’ve loaded the Company section, we can add jedi to the list of completions:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(use-package elpy
|
||||
:after company-mode
|
||||
:config (add-to-list 'company-backends 'company-jedi))
|
||||
(elpy-enable))
|
||||
#+END_SRC
|
||||
|
||||
Let’s expand our =major-mode-hydra= with some extras:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package ob-scheme
|
||||
:straight (:type built-in)
|
||||
|
||||
:config
|
||||
(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?
|
||||
#+begin_src emacs-lisp
|
||||
(use-package ob-racket
|
||||
:straight (:host github :repo "DEADB17/ob-racket")
|
||||
;; :vc (:url "https://github.com/DEADB17/ob-racket")
|
||||
:after org
|
||||
:config
|
||||
(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]]:
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
(use-package hide-show
|
||||
:straight (:type built-in)
|
||||
|
||||
:init
|
||||
(setq hs-hide-comments 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
|
||||
(use-package flycheck
|
||||
:straight (:host github :repo "flycheck/flycheck")
|
||||
;; :vc (:url "https://github.com/flycheck/flycheck")
|
||||
:init
|
||||
(setq next-error-message-highlight t)
|
||||
: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
|
||||
(when (treesit-available-p)
|
||||
(use-package treesit
|
||||
:straight (:type built-in)
|
||||
|
||||
:preface
|
||||
(setq treesit-language-source-alist
|
||||
'((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
|
||||
(when (treesit-available-p)
|
||||
(use-package combobulate
|
||||
:straight (:host github :repo "mickeynp/combobulate")
|
||||
;; :vc (:url "https://github.com/mickeynp/combobulate")
|
||||
:after treesit
|
||||
:hook ((yaml-ts-mode . combobulate-mode)
|
||||
;; (css-ts-mode . combobulate-mode)
|
||||
|
|
@ -670,26 +670,26 @@ Emacs has two LSP projects, and while I have used [[LSP Mode]], but since I don
|
|||
|
||||
:config
|
||||
(global-set-key (kbd "s-m") 'lsp)
|
||||
;; (ha-local-leader :keymaps 'prog-mode-map
|
||||
;; "w" '(:ignore t :which-key "lsp")
|
||||
;; "l" '(:ignore t :which-key "lsp")
|
||||
;; "ws" '("start" . lsp))
|
||||
(ha-local-leader :keymaps 'prog-mode-map
|
||||
"w" '(:ignore t :which-key "lsp")
|
||||
"l" '(:ignore t :which-key "lsp")
|
||||
"ws" '("start" . lsp))
|
||||
|
||||
;; ;; The following leader-like keys, are only available when I have
|
||||
;; ;; started LSP, and is an alternate to Command-m:
|
||||
;; :general
|
||||
;; (:states 'normal :keymaps 'lsp-mode-map
|
||||
;; ", w r" '("restart" . lsp-reconnect)
|
||||
;; ", w b" '("events" . lsp-events-buffer)
|
||||
;; ", w e" '("errors" . lsp-stderr-buffer)
|
||||
;; ", w q" '("quit" . lsp-shutdown)
|
||||
;; ", w Q" '("quit all" . lsp-shutdown-all)
|
||||
;; The following leader-like keys, are only available when I have
|
||||
;; started LSP, and is an alternate to Command-m:
|
||||
:general
|
||||
(:states 'normal :keymaps 'lsp-mode-map
|
||||
", w r" '("restart" . lsp-reconnect)
|
||||
", w b" '("events" . lsp-events-buffer)
|
||||
", w e" '("errors" . lsp-stderr-buffer)
|
||||
", w q" '("quit" . lsp-shutdown)
|
||||
", w Q" '("quit all" . lsp-shutdown-all)
|
||||
|
||||
;; ", l r" '("rename" . lsp-rename)
|
||||
;; ", l f" '("format" . lsp-format)
|
||||
;; ", l a" '("actions" . lsp-code-actions)
|
||||
;; ", l i" '("imports" . lsp-code-action-organize-imports)
|
||||
;; ", l d" '("doc" . lsp-lookup-documentation))
|
||||
", l r" '("rename" . lsp-rename)
|
||||
", l f" '("format" . lsp-format)
|
||||
", l a" '("actions" . lsp-code-actions)
|
||||
", l i" '("imports" . lsp-code-action-organize-imports)
|
||||
", l d" '("doc" . lsp-lookup-documentation))
|
||||
|
||||
:hook ((lsp-mode . lsp-enable-which-key-integration)))
|
||||
#+end_src
|
||||
|
|
@ -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
|
||||
(use-package lsp-ui-imenu
|
||||
:straight nil
|
||||
|
||||
:after lsp-ui
|
||||
:config
|
||||
(ha-local-leader :keymaps 'prog-mode-map
|
||||
|
|
@ -1089,7 +1089,7 @@ This means, that some data like:
|
|||
"data": {
|
||||
"name": "Create And Wait for Service Image",
|
||||
"description": "Creates a new Service Image using IMaaS",
|
||||
"long_description": "This job creates a new service image with name ... blah, blah, blah",
|
||||
"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",
|
||||
"job_id": "5e077245-0f4a-4dc9-b473-ce3ec0b811ba",
|
||||
"state": "success",
|
||||
"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:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package sh-mode
|
||||
:straight (:type built-in)
|
||||
|
||||
:mode (rx (or (seq ".sh" eol)
|
||||
"/bin/"))
|
||||
:init
|
||||
(setq sh-basic-offset 4
|
||||
sh-indentation 4)
|
||||
(setq sh-basic-offset 2
|
||||
sh-indentation 2)
|
||||
:config
|
||||
(ha-auto-insert-file (rx (or (seq ".sh" eol)
|
||||
"/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.
|
||||
#+begin_src emacs-lisp
|
||||
(use-package tramp
|
||||
:straight (:type built-in)
|
||||
|
||||
|
||||
:config
|
||||
;; 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:
|
||||
#+begin_src emacs-lisp
|
||||
(use-package tramp
|
||||
:straight (:type built-in)
|
||||
|
||||
:config
|
||||
(push '("docker" . ((tramp-login-program "docker")
|
||||
(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
|
||||
(use-package tramp-sh
|
||||
:after tramp
|
||||
:straight (:type built-in)
|
||||
|
||||
:custom (tramp-use-ssh-controlmaster-options nil))
|
||||
#+end_src
|
||||
* Remote Terminals
|
||||
|
|
@ -159,12 +159,13 @@ While not as fast as [[https://github.com/akermu/emacs-libvterm][vterm]], the [[
|
|||
|
||||
#+BEGIN_SRC emacs-lisp :tangle no
|
||||
(use-package eat
|
||||
:straight (:host codeberg :repo "akib/emacs-eat"
|
||||
:files ("*.el" ("term" "term/*.el") "*.texi"
|
||||
"*.ti" ("terminfo/e" "terminfo/efo/e/*")
|
||||
("terminfo/65" "terminfo/65/*")
|
||||
("integration" "integration/*")
|
||||
(:exclude ".dir-locals.el" "*-tests.el")))
|
||||
;; :straight (:host codeberg :repo "akib/emacs-eat"
|
||||
;; :files ("*.el" ("term" "term/*.el") "*.texi"
|
||||
;; "*.ti" ("terminfo/e" "terminfo/efo/e/*")
|
||||
;; ("terminfo/65" "terminfo/65/*")
|
||||
;; ("integration" "integration/*")
|
||||
;; (:exclude ".dir-locals.el" "*-tests.el")))
|
||||
;; :vc (:url "https://codeberg.org/akib/emacs-eat")
|
||||
:commands (eat eat-make eat-project)
|
||||
:bind (:map eat-semi-char-mode-map
|
||||
("C-c C-t" . ha-eat-narrow-to-shell-prompt-dwim))
|
||||
|
|
@ -214,6 +215,14 @@ 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.")
|
||||
#+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
|
||||
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]].
|
||||
|
|
@ -224,11 +233,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'.
|
||||
STARTFILE is the initial text given to the PROGRAM, and the
|
||||
SWITCHES are the command line options."
|
||||
(unless program (setq program ha-shell))
|
||||
(cond
|
||||
((fboundp 'vterm) (progn (vterm name)
|
||||
(when program
|
||||
(vterm-send-string (append program switches))
|
||||
(vterm-send-return))))
|
||||
(vterm-send-string (append program switches))
|
||||
(vterm-send-return)))
|
||||
((fboundp 'eat) (progn (switch-to-buffer
|
||||
(apply 'eat-make (append (list name program startfile)
|
||||
switches)))
|
||||
|
|
@ -292,7 +301,7 @@ For the sake of my demonstrations, I use =ha-shell= to start a terminal with a p
|
|||
default-directory)))
|
||||
(buf-name (format "*%s*" win-name)))
|
||||
(setq ha-latest-ssh-window-name buf-name)
|
||||
(ha-make-term win-name))) ; Lisp-2 FTW!?
|
||||
(ha-make-term win-name ha-shell))) ; Lisp-2 FTW!?
|
||||
#+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.
|
||||
|
|
@ -317,6 +326,8 @@ Now that Emacs can /host/ a Terminal shell, I would like to /programmatically/ s
|
|||
(t (progn
|
||||
(insert command)
|
||||
(term-send-input))))))
|
||||
|
||||
(ha-shell-send "exit")
|
||||
#+end_src
|
||||
|
||||
Let's have a quick way to bugger out of the terminal:
|
||||
|
|
|
|||
|
|
@ -323,6 +323,8 @@ Let’s make a /theme/:
|
|||
'hamacs
|
||||
`(default ((t (:foreground ,default-fg :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")))
|
||||
`(cursor ((t (:foreground ,gray-10 :background ,cursor))))
|
||||
`(region ((t (:background ,region))))
|
||||
|
|
@ -331,11 +333,6 @@ Let’s make a /theme/:
|
|||
`(mode-line-active ((t (:background ,active))))
|
||||
`(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-file ((t (:foreground "white" :weight bold))))
|
||||
`(doom-modeline-buffer-major-mode ((t (:foreground ,almond))))
|
||||
|
|
|
|||
277
hammerspoon.org
277
hammerspoon.org
|
|
@ -1,277 +0,0 @@
|
|||
#+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", function()
|
||||
spoon.Zoom:toggleMute()
|
||||
end)
|
||||
|
||||
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
|
||||
|
||||
Oh, and here is a helper for [[file:laptop_keyboard.kbd][kanata]] to put the display to sleep:
|
||||
|
||||
#+BEGIN_SRC lua
|
||||
hs.hotkey.bind({}, "F16", function()
|
||||
hs.execute("pmset displaysleepnow")
|
||||
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,15 +23,6 @@ gpg --homedir ~/.emacs.d/elpa/gnupg --receive-keys 066DAFCB81E42C40
|
|||
cat > "$HAMACS_DEST/early-init.el" <<EOF
|
||||
;;; early-init.el --- Hamacs Early Init -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; ▄████████ ▄▄▄▄███▄▄▄▄ ▄████████ ▄████████ ▄████████
|
||||
;; ███ ███ ▄██▀▀▀███▀▀▀██▄ ███ ███ ███ ███ ███ ███
|
||||
;; ███ █▀ ███ ███ ███ ███ ███ ███ █▀ ███ █▀
|
||||
;; ▄███▄▄▄ ███ ███ ███ ███ ███ ███ ███
|
||||
;; ▀▀███▀▀▀ ███ ███ ███▀███████████ ███ ▀███████████
|
||||
;; ███ █▄ ███ ███ ███ ███ ███ ███ █▄ ███
|
||||
;; ███ ███ ███ ███ ███ ███ ███ ███ ███ ▄█ ███
|
||||
;; ██████████ ▀█ ███ █▀ ███ █▀ ████████▀ ▄████████▀
|
||||
;;
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This is my early Emacs configuration file. See init.el for the real
|
||||
|
|
@ -78,14 +69,6 @@ echo "Created $HAMACS_DEST/early-init.el"
|
|||
cat > "$HAMACS_DEST/init.el" <<EOF
|
||||
;;; init.el --- Hamacs Init -*- lexical-binding: t; -*-
|
||||
;;
|
||||
;; :::::::::: :::: :::: ::: :::::::: ::::::::
|
||||
;; :+: +:+:+: :+:+:+ :+: :+: :+: :+: :+: :+:
|
||||
;; +:+ +:+ +:+:+ +:+ +:+ +:+ +:+ +:+
|
||||
;; +#++:++# +#+ +:+ +#+ +#++:++#++: +#+ +#++:++#++
|
||||
;; +#+ +#+ +#+ +#+ +#+ +#+ +#+
|
||||
;; #+# #+# #+# #+# #+# #+# #+# #+# #+#
|
||||
;; ########## ### ### ### ### ######## ########
|
||||
;;
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; This is my Emacs Bootloader. Simply put, I initialize the package
|
||||
|
|
@ -96,8 +79,23 @@ cat > "$HAMACS_DEST/init.el" <<EOF
|
|||
|
||||
(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):
|
||||
(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
|
||||
;; signature if possible:
|
||||
|
|
@ -115,29 +113,7 @@ cat > "$HAMACS_DEST/init.el" <<EOF
|
|||
(add-to-list 'package-archives
|
||||
'("elpa-dev" . "https://elpa.gnu.org/devel/"))
|
||||
|
||||
;; 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
|
||||
(setq use-package-always-ensure nil)
|
||||
|
||||
(use-package org
|
||||
;; TODO: Using the latest org-mode
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
;; -*- mode:lisp; -*-
|
||||
;; 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.
|
||||
;;
|
||||
;; Installation:
|
||||
;; brew install kanata
|
||||
;;
|
||||
;; Running:
|
||||
;; sudo kanata --cfg ~/src/hamacs/laptop_keyboard.kbd
|
||||
|
||||
(deflocalkeys-macos
|
||||
ì 13)
|
||||
|
||||
;; While this works on both my Macbook running MacOS and Linux, I have
|
||||
;; yet to figure out how to get the same file to work in both, as I
|
||||
;; have to modify the code in the `defcfg' section below.
|
||||
|
||||
(defcfg
|
||||
;; linux-dev-names-include ("Apple Internal Keyboard / Trackpad")
|
||||
macos-dev-names-include ("Apple Internal Keyboard / Trackpad"))
|
||||
|
||||
;; What keys are we re-defining? This is my Macbook Pro layouts, as
|
||||
;; both laptops are this hardware.
|
||||
;;
|
||||
;; Notice lmet/rmet = Apple's Command Key
|
||||
;; lalt/ralt = Option, or a real meta key
|
||||
|
||||
(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)
|
||||
|
||||
;; Also includes a symbol layer accessible while holding down either
|
||||
;; the `h' or `g' keys.
|
||||
|
||||
(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))
|
||||
|
||||
;; The base layer is fairly normal, except we all out aliases defined
|
||||
;; above, os the @a is both a `tap-hold' feature as well as a regular
|
||||
;; `a` key:
|
||||
|
||||
(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)
|
||||
|
||||
;; The other layer is our `symbols' which allows me to hold down the
|
||||
;; `g' key to invoke a magical VI-like h/j/k/l arrow keys:
|
||||
|
||||
(deflayer SYMBOLS
|
||||
esc 🔅 🔆 F3 F4 f5 f16 ◀◀ ▶⏸ ▶▶ 🔇 🔉 🔊
|
||||
_ 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 _
|
||||
_ _ _ _ _ _ _)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 449 KiB After Width: | Height: | Size: 308 KiB |
186
zshell.org
186
zshell.org
|
|
@ -21,7 +21,6 @@ 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:
|
||||
|
||||
- =~/.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
|
||||
- =~/.zlogin= :: Run for login shells … seems to run as often as =.zshrc=
|
||||
|
||||
|
|
@ -44,24 +43,8 @@ Let’s create the following files, and the configuration below will be injected
|
|||
* Path
|
||||
The all important =PATH= environment variable, needs my special =bin= directory.
|
||||
|
||||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||
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
|
||||
#+BEGIN_SRC zsh :export ~/.zshenv
|
||||
export PATH=$HOME/bin:/usr/local/bin:$PATH
|
||||
#+END_SRC
|
||||
|
||||
* Options
|
||||
|
|
@ -111,10 +94,7 @@ setopt MENU_COMPLETE
|
|||
When using Homebrew on a Mac, we need to add its =PATH=:
|
||||
|
||||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||
if [[ -d /opt/homebrew ]]
|
||||
then
|
||||
eval $(/opt/homebrew/bin/brew shellenv zsh)
|
||||
fi
|
||||
eval $(/opt/homebrew/bin/brew shellenv zsh)
|
||||
#+END_SRC
|
||||
|
||||
This adds the following environment variables, along with expanding the =PATH=.
|
||||
|
|
@ -218,28 +198,18 @@ 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
|
||||
#+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
|
||||
Anything special for particular languages.
|
||||
*** Python
|
||||
Not overly impressed, for to get =pyenv= to work, we need to add this code:
|
||||
|
||||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||
#+BEGIN_SRC zsh
|
||||
export PYENV_ROOT="$HOME/.pyenv"
|
||||
export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
|
||||
eval "$(pyenv init --path)"
|
||||
#+END_SRC
|
||||
|
||||
And call the =pyenv= to initialize it:
|
||||
|
||||
#+BEGIN_SRC zsh
|
||||
# eval "$(pyenv init --path)"
|
||||
#+END_SRC
|
||||
|
||||
** 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.
|
||||
|
|
@ -258,7 +228,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:
|
||||
|
||||
#+begin_SRC zsh
|
||||
plugins=(colorize direnv gnu-utils iterm2 macos virtualenv zbell zsh-syntax-highlighting)
|
||||
plugins=(colorize direnv gnu-utils iterm2 macos pyenv virtualenv zbell zsh-syntax-highlighting)
|
||||
#+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).
|
||||
|
|
@ -272,26 +242,6 @@ The trick is to install some base-level plugins, and then, on my work computer,
|
|||
fi
|
||||
#+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:
|
||||
|
||||
#+BEGIN_SRC zsh
|
||||
|
|
@ -324,80 +274,6 @@ Oh use the absolute /over-the-top/ bling associated with Oh My Zshell’s /theme
|
|||
#+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]].
|
||||
* 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
|
||||
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:
|
||||
|
||||
|
|
@ -416,25 +292,15 @@ Favorite feature is the [[https://iterm2.com/documentation-status-bar.html][Stat
|
|||
Currently, I show the currently defined Kube namespace.
|
||||
|
||||
#+BEGIN_SRC zsh
|
||||
function iterm2_python_version() {
|
||||
echo $(pyenv version-name):$(echo "$VIRTUAL_ENV" | sed "
|
||||
s|^$HOME|~|
|
||||
s|^~/src/wpc-gerrit.inday.io/||
|
||||
s|^~/work/||
|
||||
s|^~/.venv/||
|
||||
s|/\.venv$||
|
||||
s|\.venv$||")
|
||||
}
|
||||
|
||||
function iterm2_print_user_vars() {
|
||||
# iterm2_set_user_var kubecontext $($ yq '.users[0].name' ~/.kube/config):$(kubectl config view --minify --output 'jsonpath={..namespace}')
|
||||
# iterm2_set_user_var kubecontext $($ yq '.users[0].name' ~/.kube/config):$(kubectl config view --minify --output 'jsonpath={..namespace}')
|
||||
|
||||
# Correct version:
|
||||
# iterm2_set_user_var kubecontext $(kubectl config current-context):$(kubectl config view --minify --output 'jsonpath={..namespace}')
|
||||
# Faster version:
|
||||
iterm2_set_user_var kubecontext $(awk '/^current-context:/{print $2;exit;}' <~/.kube/config)
|
||||
# Correct version:
|
||||
# iterm2_set_user_var kubecontext $(kubectl config current-context):$(kubectl config view --minify --output 'jsonpath={..namespace}')
|
||||
# Faster version:
|
||||
iterm2_set_user_var kubecontext $(awk '/^current-context:/{print $2;exit;}' <~/.kube/config)
|
||||
|
||||
iterm2_set_user_var pycontext $(iterm2_python_version)
|
||||
iterm2_set_user_var pycontext "$(pyenv version-name):$(echo $VIRTUAL_ENV | sed 's/.*.venv\///')"
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
|
|
@ -458,12 +324,10 @@ While it /should/ figure out (as Emacs keybindings are the default), this is how
|
|||
bindkey -e
|
||||
#+END_SRC
|
||||
|
||||
Where be the =emacsclient=? It should, at this point, be in our path.
|
||||
|
||||
And how should we call it?
|
||||
Where be the =emacsclient=, and how should we call it?
|
||||
|
||||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||
export EMACS_SOCKET_NAME=personal
|
||||
export EMACS="emacsclient --socket-name personal"
|
||||
#+END_SRC
|
||||
|
||||
Which needs to be overwritten on my Work computer:
|
||||
|
|
@ -471,15 +335,15 @@ Which needs to be overwritten on my Work computer:
|
|||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||
if hostname | grep AL33 >/dev/null
|
||||
then
|
||||
export EMACS_SOCKET_NAME=work
|
||||
export EMACS="emacsclient --socket-name work"
|
||||
fi
|
||||
#+END_SRC
|
||||
|
||||
The =EDITOR= variable that some programs use to edit files from the command line:
|
||||
|
||||
#+BEGIN_SRC zsh :tangle ~/.zshenv
|
||||
export EDITOR="emacsclient --tty"
|
||||
export VISUAL="emacsclient --create-frame"
|
||||
export EDITOR="$EMACS --tty"
|
||||
export VISUAL="$EMACS --create-frame"
|
||||
#+END_SRC
|
||||
|
||||
With these variables defined, we can create simple aliases:
|
||||
|
|
@ -487,8 +351,8 @@ With these variables defined, we can create simple aliases:
|
|||
#+BEGIN_SRC zsh
|
||||
alias e="$EDITOR"
|
||||
alias te="$EDITOR"
|
||||
alias ee="emacsclient --create-frame"
|
||||
alias eee="emacsclient --create-frame --no-wait"
|
||||
alias ee="$EMACS --create-frame"
|
||||
alias eee="$EMACS --create-frame --no-wait"
|
||||
#+END_SRC
|
||||
|
||||
** Vterm
|
||||
|
|
@ -543,7 +407,7 @@ For instance:
|
|||
Assuming we’ve installed [[https://github.com/lsd-rs/lsd][lsd]], let’s make an alias for it:
|
||||
|
||||
#+BEGIN_SRC zsh
|
||||
if which lsd >/dev/null
|
||||
if whence lsd >/dev/null
|
||||
then
|
||||
alias ls=lsd
|
||||
fi
|
||||
|
|
@ -567,13 +431,6 @@ And an abstraction for transitory endpoints over SSH:
|
|||
alias ossh="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o loglevel=ERROR"
|
||||
#+END_SRC
|
||||
|
||||
And other ones that I use:
|
||||
|
||||
#+BEGIN_SRC zsh
|
||||
alias os=openstack
|
||||
alias k=kubectl
|
||||
#+END_SRC
|
||||
|
||||
* Final Message
|
||||
For sensitive work-related environment variables, store them elsewhere, and load them:
|
||||
|
||||
|
|
@ -589,7 +446,6 @@ To let us know we read the =~/.zshrc= file:
|
|||
|
||||
#+description: A literate programming file for configuring Zshell.
|
||||
#+property: header-args:zsh :tangle ~/.zshrc
|
||||
#+property: header-args:sh :tangle no
|
||||
#+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: skip:nil author:nil email:nil creator:nil timestamp:nil
|
||||
|
|
|
|||
Loading…
Reference in a new issue