Pangram verdict · v3.3
We believe that this document is fully human-written
AI likelihood · overall
HumanArticle text · 1,603 words · 5 segments analyzed
Table of Contents 1. About emacs completion 2. The Demonstration consult marginalia embark 3. Anatomy of spot structure modularity 4. Candidates as Shared Currency candidates 5. Consult: Defining the Search Surface consult async narrowing 6. Why the Cache? async ratelimits 7. Marginalia: Promoting Candidates into Informed Choices marginalia 8. Embark: The Action Layer embark composition 8.1. Composition: When an Action Opens Another Search composition chaining 9. The Integration Point: spot-mode modularity hooks 10. The Counterfactual: What spot Would Look Like Without VOMPECCC 11. What This Says About the Substrate substrate platform 12. Generalizing the Pattern Beyond Spotify generalization pattern 13. Conclusion 14. TLDR 1. About emacs completion This is the third post in a series on Emacs completion. The first post argued that Incremental Completing Read (ICR) is not merely a UI convenience but a structural property of an interface, and that Emacs is one of the few environments where completion is exposed as a programmable substrate rather than a sealed UI. The second post broke the substrate into eight packages (collectively VOMPECCC), each solving one of the six orthogonal concerns of a complete completion system. In this post, I show, concretely, what it looks like when you build with VOMPECCC, by walking through the code of spot, a Spotify client I implemented as a pure ICR application in Emacs. A word I'll use throughout this post to refer to the use of VOMPECCC in spot is shim, and it is worth qualifying that. The whole package is about 1,100 non-blank, non-comment lines of Lisp1. Roughly 635 of those is infrastructure any Spotify client would need regardless of its UI choices: OAuth with refresh, HTTP transport with error surfacing, a cached search layer, a currently-playing mode-line, a config surface, player-control commands, blah blah blah.
The shim is the rest: 493 lines across exactly three files (spot-consult.el, spot-marginalia.el, spot-embark.el) whose entire job is to feed candidates into Consult (source), annotate them with Marginalia (source), and attach actions to them through Embark (source). When I say spot is a shim, I mean those three files, and I'm emphasizing the fact that there is relatively little code. The rest of spot is plumbing that has nothing to do with the completion substrate. spot implements no custom UI. It has no tabulated-list buffer, no custom keymap for navigation, no rendering code. Every interaction surface; the search prompt, the candidate display, the annotations, and the action menu; is rented from the completion substrate by the 493-line shim. This post is about the code. Instead of cataloging spot's features (I'll do that when I publish the package to Melpa), I want to show how the code actually hangs together on top of VOMPECCC, with verbatim snippets mapped onto the interaction they produce. If the previous two posts were the why and the what, this one is the how, with a working application to ground the pattern. 2. The Demonstration consult marginalia embark Before any code, here is the concrete task the video is solving: I am trying to find a J Dilla song whose title I can't remember; all I recall is that the word don't is somewhere in the track name. The entire post revolves around this one video, so it is worth watching before reading on. Everything that follows is a line-by-line breakdown of the code that produces what you are about to see. In the upper right hand side of my emacs (in the tab-bar), you'll see the key-bindings and, more importantly, the commands I am invoking to drive spot. (To make this clip easier to digest, you can play, pause, scrub, view in full screen, or view as "Picture in Picture" use the video controls). Here is what happens in the clip: I invoke spot-consult-search and type j dilla. Each keystroke fires an async query against the Spotify Web API, and the result set is streamed into the minibuffer.
That is Consult. In my emacs config, Vertico2 renders the candidate set vertically so the per-row metadata is legible. I use Spotify's query parameters to widen the result set per type. Spotify's search endpoint caps results per content type, so I append parameter flags (--type=track --limit=50, etc.) to ask for a fatter haul across tracks, albums, and artists. The candidates are streamed back through Consult exactly as before, just more of them. I type ,, the consult-async-split-style character, to switch from remote search to local ICR. Everything before the comma continues to be the API query; everything after is a local narrowing pattern that matches against the candidate set already in hand. No further Spotify requests are issued, and each incremental keystroke only filters the rows Consult is already holding. I type dont (no apostrophe) looking for the song. The default matching is literal, so "dont" doesn't match "Don't". Zero candidates. The corpus contains the song; my pattern just doesn't. (You thought I did this by mistake didn't you 😜? It actually highlights why fuzzy matching is so important.) I backspace and prefix the query with ~, the Orderless3 dispatcher for fuzzy matching. ~dont now matches "Don't Cry" (and others) because fuzzy matching tolerates the missing apostrophe. The search set is unchanged; I swapped matching styles without re-querying Spotify. This may sound like a small feature, but consider how much a little fuzz widens the match space of your input strings. This is espacially important in an application like Spotify where entity names can be long and difficult to remember. I append @donuts, the Orderless dispatcher for matching against the Marginalia annotation column rather than the candidate name. That narrows the surviving candidates to tracks whose annotation mentions "donuts" (i.e., tracks on Dilla's Donuts album, my personal favourite), even though the word "donuts" never appears in any track title. The song I was looking for is right there. (note my orderless-component-separator is also ",") With the track selected, I invoke Embark (embark-act) and press P to play. The P binding dispatches to spot-action--generic-play-uri, which pulls the track's URI off the candidate's multi-data property and sends a PUT to the Spotify player.
The song starts playing; no further navigation required. Three VOMPECCC packages are doing the work: Consult (the async streaming + the split-character handoff to local ICR), Marginalia (the metadata column the @ dispatcher just narrowed against), and Embark (the action menu that allows you to play the track, list the album's other tracks, or add it to a playlist). The whole rest of this post is an argument that the code required to make this happen is pleasantly concise, because none of those capabilities (asynchronous search with narrowing, metadata annotation, annotation-aware fuzzy filtering, or contextual actions) needed to be built. They already exist in the VOMPECCC framework, and spot's only job is to feed them data. 3. Anatomy of spot structure modularity spot is organized so that each file corresponds to one concern. This is deliberate: the architecture mirrors the modularity of VOMPECCC itself, not because I was trying to be cute (I'm cute enough 👺), but because when your substrate is modular, consuming it modularly is the lowest-friction path. File Responsibility Substrate package LoC spot-auth.el OAuth2 authorization + automatic token refresh timer (none) 65 spot-generic-query.el HTTP request plumbing (sync + async, error surfacing) (none) 88 spot-search.el Cached search against the Spotify API (none) 100 spot-generic-action.el Player control commands (play/pause/next/previous) (none) 51 spot-mode-line.el Currently-playing display (none) 115 spot-var.el Configuration variables (endpoints, credentials, etc.) (none) 127 spot-util.el Alist/hash-table conversions, candidate propertize (the glue) 52 spot-consult.el Seven async Consult sources + consult--multi entry Consult 194 spot-marginalia.el Annotation functions per content type Marginalia 159 spot-embark.el Keymaps and actions per content type Embark 140 spot.el spot-mode: wires registries + timers in and out (integration) 37 Total 1128 The breakdown is the whole point of the shim framing.
The three substrate-facing files (194 + 159 + 140 = 493 lines) are the part that actually integrates with VOMPECCC. None of that is UI code; there is no UI code in spot. Every pixel the user sees comes from Consult, Marginalia, Embark, or whatever the user has slotted in below them. One caveat on the 194-line figure for spot-consult.el: roughly 105 of those lines are a 7-way parallel triplet (one source definition, one history variable, and one completion function per Spotify content type), varying only in the narrow key and the :category symbol. A small macro (spot-define-consult-source) would collapse the 105 lines into 7 invocations plus a ~25-line definition, for 30-35 lines total. The honest Consult-facing line count, with redundancy factored out, is closer to 115 than 194, and the whole shim closer to 420 than 493. The reason I didn't write this macro is because it would muddy the concrete depiction of the VOMPECCC APIs here, and honestly, I tend to avoid over-macroizing as it creates new and confusing APIs over well-established and intuitive APIs. 4. Candidates as Shared Currency candidates Before looking at any of the three VOMPECCC layers individually, there is one piece of code that makes the entire integration possible. It is a short function, and if you understand it, you understand how Consult, Marginalia, and Embark cooperate without knowing anything about each other. (defun spot--propertize-items (tables) "Propertize a list of hash TABLES for display in completion. Each table is expected to have `name' and `type' keys. Names are truncated for display per `spot-candidate-max-width'; the full name remains accessible via `multi-data'." (-map (lambda (table) (propertize (spot--truncate-name (ht-get table 'name)) 'category (intern (ht-get table 'type)) 'multi-data table)) tables)) Every candidate that spot hands to Consult is a string (the Spotify item's name) carrying two text properties: category is one of album, artist, track, playlist, show, episode, or audiobook.