Compare commits

..

No commits in common. "038ec85e0e554a45352cc7c16c0118e2cb3413ba" and "05e0fbae40095f235870c09ae7a7731ab089906b" have entirely different histories.

6 changed files with 21 additions and 329 deletions

View file

@ -1048,13 +1048,13 @@ And some shortcut keys from the =general= project:
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: 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 #+BEGIN_SRC emacs-lisp
(defun ha-tab-bar-update-names (&optional changed-tab) (defun ha-tab-bar-update-names ()
"Create normal-mode keybindings for the tab groupings. "Create normal-mode keybindings for the tab groupings.
This creates `SPC TAB 1' to jump to the first tab, etc." This creates `SPC TAB 1' to jump to the first tab, etc."
(interactive) (interactive)
;; Remove all previously created keybindings: ;; Remove all previously created keybindings:
(ignore-errors (ignore-errors
(dolist (indx (number-sequence 0 9)) (dolist (indx (number-sequence 1 9))
(general-nmap :prefix "SPC" (format "<tab> %d" indx) nil))) (general-nmap :prefix "SPC" (format "<tab> %d" indx) nil)))
;; Loop through the existing tabs, create keys for each: ;; Loop through the existing tabs, create keys for each:
@ -1063,14 +1063,11 @@ I want to quickly jump, by the number shown on the tab, to that grouping. The fo
(defun ha-tab-bar-update-tab-keybinding (tab-deets indx) (defun ha-tab-bar-update-tab-keybinding (tab-deets indx)
"Create a keybinding to jump to tab described by TAB-DEETS. "Create a keybinding to jump to tab described by TAB-DEETS.
The key sequence, `SPC' `TAB' then INDX." The key sequence, `SPC' `TAB' then INDX."
(when (< indx 10)
(let ((name (alist-get 'name tab-deets))) (let ((name (alist-get 'name tab-deets)))
(general-nmap :prefix "SPC" (general-nmap :prefix "SPC"
;; As indx is starts with 0, we need to create keybindings to (format "<tab> %d" (1+ indx))
;; match the tab labels by incrementing it by one ... unless, `(,name .
;; we are at 10, where we use 0 instead: (lambda () (interactive) (tab-bar-select-tab ,(1+ indx)))))))
(format "<tab> %d" (if (= indx 9) 0 (1+ indx)))
`(,name . (lambda () (interactive) (tab-bar-select-tab ,(1+ indx))))))))
#+END_SRC #+END_SRC
Any time I create or delete a new tab, we can call =ha-tab-bar-update-names=: Any time I create or delete a new tab, we can call =ha-tab-bar-update-names=:

View file

@ -3,7 +3,7 @@
#+date: 2020-09-18 #+date: 2020-09-18
#+tags: emacs org #+tags: emacs org
#+startup: inlineimages #+startup: inlineimages
#+lastmod: [2025-12-02 Tue] #+lastmod: [2025-07-01 Tue]
A literate programming file for configuring org-mode and those files. A literate programming file for configuring org-mode and those files.
@ -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) "•"))))))) (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•")))))))
#+end_src #+end_src
What was
#+BEGIN_SRC emacs-lisp
(defun display-latest-clocked-task ()
"Display the name of the latest task that was clocked in."
(interactive)
(let ((latest-task (car (org-clock-get-clock-string))))
(if latest-task
(message "Latest clocked task: %s" latest-task)
(message "No task is currently clocked in."))))
#+END_SRC
Need to be able to clock out of a task even if no /clock-in/ has occurred.
#+BEGIN_SRC emacs-lisp
(defun ha-clock-out ()
"Safely clock out of the current task.
This will not throw an error if not active clock exists."
(interactive)
(ignore-errors
(org-clock-out)
(message "Clocked out.")))
#+END_SRC
** Meetings ** Meetings
I've notice that while showing a screen while taking meeting notes, I don't always like showing other windows, so I created this function to remove distractions during a meeting. I've notice that while showing a screen while taking meeting notes, I don't always like showing other windows, so I created this function to remove distractions during a meeting.

View file

@ -292,7 +292,7 @@ For the sake of my demonstrations, I use =ha-shell= to start a terminal with a p
default-directory))) default-directory)))
(buf-name (format "*%s*" win-name))) (buf-name (format "*%s*" win-name)))
(setq ha-latest-ssh-window-name buf-name) (setq ha-latest-ssh-window-name buf-name)
(ha-make-term win-name))) ; Lisp-2 FTW!? (ha-make-term win-name ha-shell))) ; Lisp-2 FTW!?
#+end_src #+end_src
Now that Emacs can /host/ a Terminal shell, I would like to /programmatically/ send commands to the running terminal, e.g. =(ha-shell-send "ls *.py")= I would really like to be able to send and execute a command in a terminal from a script. Now that Emacs can /host/ a Terminal shell, I would like to /programmatically/ send commands to the running terminal, e.g. =(ha-shell-send "ls *.py")= I would really like to be able to send and execute a command in a terminal from a script.
@ -317,6 +317,8 @@ Now that Emacs can /host/ a Terminal shell, I would like to /programmatically/ s
(t (progn (t (progn
(insert command) (insert command)
(term-send-input)))))) (term-send-input))))))
(ha-shell-send "exit")
#+end_src #+end_src
Let's have a quick way to bugger out of the terminal: Let's have a quick way to bugger out of the terminal:

View file

@ -1,267 +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, Ive 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, Ive 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
Ive 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 Zooms menus, and with the latest version of Zoom, they changed the /case/ of the menu, meaning that I needed to create a pull request.
From this [[https://developer.okta.com/blog/2020/10/22/set-up-a-mute-indicator-light-for-zoom-with-hammerspoon][nice essay]], we create a menu bar item that shows the status, as well as allowing me to click it to toggle:
#+BEGIN_SRC lua
zoomStatusMenuBarItem = hs.menubar.new(true)
zoomStatusMenuBarItem:setClickCallback(function()
spoon.Zoom:toggleMute()
end)
updateZoomStatus = function(event)
hs.printf("updateZoomStatus(%s)", event)
if (event == "from-running-to-meeting") then
zoomStatusMenuBarItem:returnToMenuBar()
elseif (event == "muted") then
zoomStatusMenuBarItem:setTitle("🔴")
elseif (event == "unmuted") then
zoomStatusMenuBarItem:setTitle("🟢")
elseif (event == "from-meeting-to-running") then
zoomStatusMenuBarItem:removeFromMenuBar()
end
end
#+END_SRC
Now we can load, instantiate it, as well as create a callback loop to call =updateZoomStatus=:
#+BEGIN_SRC lua
hs.loadSpoon("Zoom")
spoon.Zoom:setStatusCallback(updateZoomStatus)
spoon.Zoom:start()
#+END_SRC
And bind a key to the mute ability that works good for both keyboards:
#+BEGIN_SRC lua
hs.hotkey.bind({"cmd", "alt", "ctrl", "shift"}, "M", spoon.Zoom:toggleMute)
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "M", function()
spoon.Zoom:toggleMute()
end)
#+END_SRC
Lovely bit of code and shows the true power of Hammerspoon to fix the various app issues.
* Automatically Adjust Volume
Leaving my home office and hopping on the train can be socially awkward when my laptop suddenly screams, so if I leave my home, I just readjust the volume and turn it off:
#+BEGIN_SRC lua
----------------------------------------------------------------------
-- When leaving house, turn off the volume:
wifiWatcher = nil
homeSSID = "Intertubes"
workSSID = "workdaysecure"
hotspotSSID = "Pixie Dust"
lastSSID = hs.wifi.currentNetwork()
function ssidChangedCallback()
newSSID = hs.wifi.currentNetwork()
if newSSID == homeSSID and lastSSID ~= homeSSID then
-- joined our home WiFi network
hs.audiodevice.defaultOutputDevice():setVolume(25)
elseif newSSID == workSSID and lastSSID ~= workSSID then
-- joined our work WiFi network
hs.audiodevice.defaultOutputDevice():setVolume(0)
elseif newSSID == hotspotSSID and lastSSID ~= hotspotSSID then
-- joined our hotspot WiFi network
hs.audiodevice.defaultOutputDevice():setVolume(0)
elseif newSSID ~= homeSSID and lastSSID == homeSSID then
-- departed our home WiFi network
hs.audiodevice.defaultOutputDevice():setVolume(0)
end
lastSSID = newSSID
end
hs.wifi.watcher.new(ssidChangedCallback):start()
#+END_SRC
Why yes, Im /looking for features/ to use Hammerspoon.
* Clocking out a Task
I want to use Orgs task clocking ability, but I often forget to /clock out/. This code allows me to clock out whenever my computer goes to sleep … which works well when closing the laptop lid:
#+BEGIN_SRC lua
function sleepWatch(eventType)
if (eventType == hs.caffeinate.watcher.systemWillSleep) then
if hs.application.find("Emacs") then
hs.execute("/opt/homebrew/bin/emacsclient --socket work --eval '(ha-clock-out)'")
end
end
end
hs.caffeinate.watcher.new(sleepWatch):start()
#+END_SRC
Not that we could also do something for Wake:
#+BEGIN_SRC lua :tangle no
if (eventType == hs.caffeinate.watcher.systemDidWake) then
...
end
#+END_SRC
* Monitors
My company gave me a nice monitor … maybe a little too nice, as I dont 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

View file

@ -3,10 +3,6 @@
;; modifier, so holding down `d` and hitting `p` results in `P` being ;; modifier, so holding down `d` and hitting `p` results in `P` being
;; entered. ;; entered.
(deflocalkeys-macos
ì 13
)
;; Also includes a symbol layer accessible while holding down either ;; Also includes a symbol layer accessible while holding down either
;; the `h' or `g' keys. ;; the `h' or `g' keys.
@ -17,12 +13,11 @@
;; ) ;; )
) )
(defsrc (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 ` 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ] \ tab q w e r t y u i o p [ ] \
caps a s d f g h j k l ; ' ret caps a s d f g h j k l ; ' ret
lsft z x c v b n m , . / rsft lsft z x c v b n m , . / rsft
fn lctl lalt lmet spc rmet ralt lctl lalt lmet spc rmet ralt
) )
(defvar (defvar
@ -45,19 +40,17 @@
) )
(deflayer base (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 ` 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ] \ tab q w e r t y u i o p [ ] \
@caps @a @s @d @f @g @h @j @k @l @; ' ret @caps @a @s @d @f @g @h @j @k @l @; ' ret
lsft z x c v b n m , . / rsft lsft z x c v b n m , . / rsft
@h lctl lalt lmet spc rmet ralt lctl lalt lmet spc rmet ralt
) )
(deflayer SYMBOLS (deflayer SYMBOLS
esc 🔅 🔆 F3 F4 f5 f6 ◀◀ ▶⏸ ▶▶ 🔇 🔉 🔊 _ F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 _ _ _
_ f11 f12 f13 f14 f15 f16 f17 f18 f19 f20 _ _ _
_ S-1 S-2 { } S-\ F16 F17 F18 F19 pgup _ _ _ _ S-1 S-2 { } S-\ F16 F17 F18 F19 pgup _ _ _
_ S-3 S-4 S-9 S-0 ` left down up right pgdn _ _ _ S-3 S-4 S-9 S-0 ` left down up right pgdn _ _
_ S-5 S-6 [ ] S-` F11 F12 F13 F14 F15 _ _ S-5 S-6 [ ] S-` F11 F12 F13 F14 F15 _
_ _ _ _ _ _ _ _ _ _ _ _ _
) )

View file

@ -218,13 +218,6 @@ The [[https://github.com/zsh-users/zsh-syntax-highlighting][ZShell Syntax Highli
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
#+END_SRC #+END_SRC
Using the =colorize= plugin (see [[Plugins][plugins section below]]), we customize with this variable setting:
#+BEGIN_SRC zsh
export ZSH_COLORIZE_STYLE="coffee"
#+END_SRC
** Language Support ** Language Support
Anything special for particular languages. Anything special for particular languages.
*** Python *** Python
@ -453,7 +446,7 @@ Where be the =emacsclient=? It should, at this point, be in our path.
And how should we call it? And how should we call it?
#+BEGIN_SRC zsh :tangle ~/.zshenv #+BEGIN_SRC zsh :tangle ~/.zshenv
export EMACS_SOCKET_NAME=personal export EMACS="emacsclient --socket-name personal"
#+END_SRC #+END_SRC
Which needs to be overwritten on my Work computer: Which needs to be overwritten on my Work computer:
@ -461,15 +454,15 @@ Which needs to be overwritten on my Work computer:
#+BEGIN_SRC zsh :tangle ~/.zshenv #+BEGIN_SRC zsh :tangle ~/.zshenv
if hostname | grep AL33 >/dev/null if hostname | grep AL33 >/dev/null
then then
export EMACS_SOCKET_NAME=work export EMACS="emacsclient --socket-name work"
fi fi
#+END_SRC #+END_SRC
The =EDITOR= variable that some programs use to edit files from the command line: The =EDITOR= variable that some programs use to edit files from the command line:
#+BEGIN_SRC zsh :tangle ~/.zshenv #+BEGIN_SRC zsh :tangle ~/.zshenv
export EDITOR="emacsclient --tty" export EDITOR="$EMACS --tty"
export VISUAL="emacsclient --create-frame" export VISUAL="$EMACS --create-frame"
#+END_SRC #+END_SRC
With these variables defined, we can create simple aliases: With these variables defined, we can create simple aliases:
@ -477,8 +470,8 @@ With these variables defined, we can create simple aliases:
#+BEGIN_SRC zsh #+BEGIN_SRC zsh
alias e="$EDITOR" alias e="$EDITOR"
alias te="$EDITOR" alias te="$EDITOR"
alias ee="emacsclient --create-frame" alias ee="$EMACS --create-frame"
alias eee="emacsclient --create-frame --no-wait" alias eee="$EMACS --create-frame --no-wait"
#+END_SRC #+END_SRC
** Vterm ** Vterm