Álvaro Ramírez
Emacs utilities for your OS
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.