Narrowing utilities are a wonderful way of increasing productivity. I have a few workflows using Emacs's Helm framework.
There are great productivity boosters like Alfred and Quicksilver for macOS, with batteries included.
If you're a tinkerer, you'd enjoy the powerful Hammerspoon. Like elisp gluing all things Emacs, Hammerspoon uses Lua to glue all things macOS. You can build your own narrowing utilities using chooser and a little Lua.
local chooser = hs.chooser.new(function(choice)
hs.alert.show(choice['text'])
end)
chooser:choices({
{
["text"] = "Alfred\n",
["subText"] = "macOS only\n",
},
{
["text"] = "Quicksilver\n",
["subText"] = "macOS only\n",
},
{
["text"] = "Hammerspoon\n",
["subText"] = "macOS only\n",
},
{
["text"] = "Emacs\n",
["subText"] = "is everywhere :)\n",
},
})
chooser:show()
Howard Abrams's post on Capturing Content for Emacs inspired me to look at gluing Emacs and macOS to launch my own cross-platform narrowing utilities.
I've also taken this opportunity to look at Oleh Krehel's wonderful completion package: Ivy. We can use it to build a macOS narrowing utility.
Ivy is remarkably easy to use. Turns out, ivy-read is all you need. A simple Emacs completion can be accomplished with little elisp.
(ivy-read "Hello ivy: "
'("One "
"Two "
"Three "
"Four "))
Pretty nifty. Let's make this completion more accessible from the rest of the OS. To do so, we create a separate Emacs frame and make it pretty. We also want it to interact with the OS. We'll use ivy-read's :action to invoke a tiny bit of AppleScript.
Oh and we'll also use some funny quotes to tease ourselves about our beloved editor.
(with-current-buffer (get-buffer-create "*modal-ivy*")
(let ((frame (make-frame '((auto-raise . t)
(background-color . "DeepSkyBlue3")
(cursor-color . "MediumPurple1")
(font . "Menlo 15")
(foreground-color . "#eeeeec")
(height . 20)
(internal-border-width . 20)
(left . 0.33)
(left-fringe . 0)
(line-spacing . 3)
(menu-bar-lines . 0)
(minibuffer . only)
(right-fringe . 0)
(tool-bar-lines . 0)
(top . 48)
(undecorated . t)
(unsplittable . t)
(vertical-scroll-bars . nil)
(width . 110)))))
(set-face-attribute 'ivy-minibuffer-match-face-1 frame
:background nil
:foreground nil)
(set-face-attribute 'ivy-minibuffer-match-face-2 frame
:background nil
:foreground "orange1")
(set-face-attribute 'ivy-minibuffer-match-face-3 frame
:background nil
:foreground "orange1")
(set-face-attribute 'ivy-minibuffer-match-face-4 frame
:background nil
:foreground "orange1")
(set-face-attribute 'ivy-current-match frame
:background "#ffc911"
:foreground "red")
(set-face-attribute 'minibuffer-prompt frame
:foreground "grey")
(let ((ivy-height 20)
(ivy-count-format ""))
(ivy-read "Emacs acronyms: "
'(" Emacs: Escape-Meta-Alt-Control-Shift "
" Emacs: Eight Megabytes And Constantly Swapping "
" Emacs: Even a Master of Arts Comes Simpler "
" Emacs: Each Manual's Audience is Completely Stupified "
" Emacs: Eventually Munches All Computer Storage "
" Emacs: Eradication of Memory Accomplished with Complete Simplicity "
" Emacs: Easily Maintained with the Assistance of Chemical Solutions "
" Emacs: Extended Macros Are Considered Superfluous "
" Emacs: Every Mode Accelerates Creation of Software "
" Emacs: Elsewhere Maybe All Commands are Simple "
" Emacs: Emacs Makes All Computing Simple "
" Emacs: Emacs Masquerades As Comfortable Shell "
" Emacs: Emacs My Alternative Computer Story "
" Emacs: Emacs Made Almost Completely Screwed "
" Emacs: Each Mail A Continued Surprise "
" Emacs: Eating Memory And Cycle-Sucking "
" Emacs: Elvis Masterminds All Computer Software "
" Emacs: Emacs Makes A Computer Slow" )
:action (lambda (funny-quote)
(async-shell-command (format "osascript -e 'tell app \"System Events\" to display dialog \"%s\" buttons {\"OK\"}'" funny-quote)))
:unwind (lambda ()
(shell-command "/Applications/Hammerspoon.app/Contents/Resources/extensions/hs/ipc/bin/hs -c 'backFromEmacs()'")
(delete-frame)
(other-window 1))))))
So where's all this going? I wrote a utility to extract all links from this page's org file and make them easily searchable from anywhere on macOS by invoking ⌥-W.
The keys are bound using Lua, Hammerspoon, and emacsclient. This works well on macOS, but there are alternatives for other operating systems.
hs.execute("emacsclient -ne \""..elisp.."\" -s /tmp/emacs*/server")
Here's the resulting utility in action:
These integrations look promising. They enable me to bring cross-platform Emacs utilities into areas I hadn't considered.