commit edc69880480d09105208ff3cbb8713ccea65f6ed (patch)
parent fec9e6489e3669165a92a33675692409245cd0db
Author: Alex Karle <alex@alexkarle.com>
Date: Thu, 1 Sep 2022 00:34:40 -0400
blog: Add post on Acme Git GUI
I'd like to work on the formatting a bit of the demo, but this is
post-ready I think (and I need sleep!).
Diffstat:
2 files changed, 214 insertions(+), 0 deletions(-)
diff --git a/www/blog/index.txt b/www/blog/index.txt
@@ -12,6 +12,7 @@ For an up to date list of software/hardware I use, see
## 2022
+- 08/22 [Using the Plan 9 Plumber to Turn Acme into a Git GUI](/blog/plan9-acme-git-gui.html)
- 06/22 [Automating Multi-User WireGuard setup on OpenBSD](/blog/wireguard-management.html)
- 05/22 [Starting a Tilde Community for Fun and the Learnings](/blog/starting-a-tilde.html)
- 05/22 [Typesetting a Resume with `mandoc(1)`](/blog/mandoc-resume.html)
diff --git a/www/blog/plan9-acme-git-gui.txt b/www/blog/plan9-acme-git-gui.txt
@@ -0,0 +1,213 @@
+# Using the Plan 9 Plumber to Turn Acme into a Git GUI
+
+_Published: August 31, 2022_
+
+## Backstory
+
+I first gave Acme a [somewhat serious spin](/blog/exploring-plan9.html)
+~4 months ago and decided that the mouse-driven editor was a bit too
+unwieldy coming from my keyboard focused tool suite.
+
+
+However, a couple weeks ago I watched a snippet of the Lex Fridman podcast
+where he [interviewed John Carmack](https://www.youtube.com/watch?v=tzr7hRXcwkw)
+on IDEs (the tldr being that an IDE with a powerful debugger is crucial).
+Carmack advocating for a heavy IDE naturally inspired me to revisit one
+of the most spartan editors I've worked with: Acme.
+
+My previous post covered some of my first impressions and basics of what
+Acme is, so in this post I wanted to do a deep dive into one of my favorite
+features: the "look"/"plumb" behavior. To illustrate it, I'll walk through
+how I was able to use it to turn Acme into a Git GUI.
+
+## The Power of Button 3
+
+Button 3, or "right click", will "look" in Acme. More specifically, it
+will take either the selected text (via Button 1) or the word under the
+cursor and try to:
+
+1. Identify if it's a file/directory that exists, and open it in a buffer
+2. Send the snippet to the `plumber(4)`
+3. If all else fails, search for the word in the buffer
+
+Number (3) can be a great way to quickly click through usages of a
+variable in a function, and (1) is super helpful in exploring the
+filesystem and navigating to specific portions of files from tool
+output, but (2) is where the magic begins.
+
+
+The plumber gets its name from being a message bus between Plan 9
+programs. In a Plan 9 ecosystem, it appears (I haven't tested this)
+that individual servers for things like "web" or "mail" run and
+programs like Acme can interact with them by sending messages with
+`plumb(1)` through the plumber.
+
+In practice on a UNIX-like system, I'm running very few servers
+(just the plumber itself and `fontsrv(4)` for nicer fonts in Acme),
+so the plumbing rules usually have a fallback option of running a
+command (rather than passing it to a server).
+
+The plumber deciphers the messages from `plumb` by matching the
+data it receives (in this case the text under our click) against a
+series of patterns in a set of rules outlined in `plumb(7)`. By
+adding your own rules, you can configure button 3 to open any
+external program. Simple rules might match URLs and open a browser,
+but given that Acme itself exposes effectively an API through the
+filesystem, we can write little programs that in turn modify the
+contents of Acme.
+
+## Plumbing Rules for Git
+
+In Git, all objects (primarily commits, blobs, and trees) have a
+SHA, which is a hexidecimal string, making it easy to match on. Git
+likes to shorten them in tool output, so a primitive regex to match
+them might be:
+
+
+ [a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]+
+
+That's 6 or more hex digits in a row (an astute reader might warn
+that this would also match, say, CSS color codes, but for our
+purposes it'll work!).
+
+The full plumbing rule looks like so (in `~/lib/plumbing`):
+
+ type is text
+ data matches '[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]+'
+ plumb start rc -c 'git -C '$wdir' show '$0' >[2=1] | plumb -i -d edit -a ''action=showdata filename=/'$wdir'/'$0''''
+
+We tell the plumber that if the type of the message is text, and if
+it matches our pattern, that it should start the external program `rc(1)`
+(the plan9 shell) with the command:
+
+ git -C $wdir show $0 >[2=1]
+
+To run git in the working directory of the buffer the click was
+made on and run `git-show(1)` on the full text that was matched
+(with stderr duped to stdout).
+
+This command of course doesn't do much by itself--it will output
+to stdout. So to make use of the output, we send it back to
+`plumb(1)`, this time telling it to send to the `-d` (destination)
+`edit` (editor) with the action of showing data. This will open a
+new Acme buffer with the contents of the git object (whether it's
+a commit, the file for the blob, etc).
+
+
+## Going Full GUI
+
+At this point, we could run `git-log(1)` in a `win(1)` buffer (a
+shell session in Acme) and start clicking SHAs to see the diffs,
+but that's not super helpful.
+
+Looking at how I like to interact with Git in Vim, I commonly do
+the following:
+
+
+1. Look at the full git log, with ability to dive into commits
+2. View the short git log for a specific file to see when things changed at a high level
+3. View the `git-blame(1)` to see when things changed at a line-level
+
+The first can be solved by writing a small wrapper around git-log, `gl`:
+
+ #!/bin/sh
+ # git-log, but piped through plumb so that it:
+ # 1. doesn't scroll to the end
+ # 2. has the proper "filename" so that plumbing SHA's works
+ git log "$@" | plumb -i -d edit -a "action=showdata filename=/$(pwd)/git-log"
+
+For a shortened version (easier to browse), we can simply call this
+with `--oneline` (`glo`):
+
+
+ #!/bin/sh
+ exec gl --oneline "$@"
+
+The output on this repo looks like so:
+
+ [/path/to/alexkarle.com/git-log Del Snarf Redo | Look]
+ 28a5f1c blog: Edit typos and small rephrasings for wggen post
+ 85b54e2 blog: Add post on wggen tool to manage wg creds
+ 6c6d8e0 blog: Add post about garbash.com
+ da01dba blog: Add post about mandoc resume
+ ...
+
+Finally, we can get a per-file history by just filtering `glo` (`gv`):
+
+ #!/bin/sh
+ # gv -- imitation of :GV! vim plugin
+ file=${1:-$samfile}
+ glo -- "$file"
+
+Here we see a nice trick: `gv` takes in an argument (so that we can
+specify the file to log), but if it's empty it defaults to `$samfile`,
+which is set by Acme to be the current buffer being edited. So
+putting `gv` in the tag of the README and middle clicking to execute
+gives the same output as before, but filtered!
+
+
+Git blame uses the same concepts (`gbl`):
+
+ #!/bin/sh
+ # git blame, in acme!
+ file=${1:-$samfile}
+ git blame --date="short" "$file" | plumb -i -d edit -a "action=showdata filename=$file:BLAME"
+
+Calling `gbl` on the README pops up a new buffer with the following:
+
+ [/path/to/alexkarle.com/README.md:BLAME Del Snarf Redo | Look]
+ 5e9783a6 (Alex Karle 2020-06-18 1) alexkarle.com
+ 5e9783a6 (Alex Karle 2020-06-18 2) =============
+ 016a5d70 (Alex Karle 2020-07-14 3) My small corner of the internet.
+
+This may seem unhelpful, but remember that clicking any of those SHA's will
+open then in a new buffer with the full diff! Clicking 5e9783a6 gives:
+
+ [/path/to/alexkarle.com/5e9783a6 Del Snarf Redo | Look]
+ commit 5e9783a6ce559f76da83b2530059c9664f43306e
+ Author: Alex Karle <email @ domain>
+ Date: Thu Jun 18 00:18:48 2020 -0400
+ (snip)
+ diff \--git a/.gitignore b/.gitignore
+ new file mode 100644
+ index 0000000..84c048a
+ \--- /dev/null
+ +++ b/.gitignore
+ @@ -0,0 +1 @@
+ +/build/
+
+
+And what's this? More SHA's to click? 84c048a will give the full
+contents of .gitignore at this commit (if the diff doesn't show
+it).
+
+The most incredible bit is that Acme doesn't need to do much to
+support this use case--the flexibility of choosing an external (and
+extensible) program to match the text and the ability to spawn new
+buffers in Acme via any language externally enables this beautifully.
+Compare this to the [~500L of VimL in
+vim-fugitive](https://github.com/tpope/vim-fugitive/blob/9fcac5b/autoload/fugitive.vim#L6712)
+to convert the Vim sidebar into an interactive blame viewer. (No
+shade towards Tim Pope--if you're reading this, huge thanks for
+everything you've ever written, it's inspired me and shaped my
+career!).
+
+
+
+## Conclusion
+
+I'm really glad I chose to revisit Acme. While it's probably never
+going to replace Vim in my toolkit, it was such an incredible
+experience to be able to turn the tool into a pretty solid Git GUI
+(minus syntax highlighting of course) in just about an hour or so
+(including time to learn plumbing rules).
+
+The concept of a universal yet personally customizable plumber is
+beyond cool, and the fact that Acme has one of the 3 buttons reserved
+to plumb text allows for developers to easily hyperlink
+plaintext, which is awesome.
+
+If you'd like to give it a spin, all my scripts (including my starter
+script for Acme) are Open Source and live in my
+[dotfiles](https://sr.ht/~akarle/dotfiles).
+