Interacting with Acme
Posted on .
Interacting with Acme through the terminal is pretty rad. This is basically a poor rehash of acme(4) plus ideas for a Git integration.
Acme exposes all its innards through a file system structure. Running on a Linux system it’s supposedly possible to use FUSE to have the 9P file system directly available for reading and writing.
Without it, we can interact with Acme through the 9p command, which lets us
read and write files on a 9P server. Acme’s files are all found in the acme
folder. Each window that Acme has open is assigned a number, the window ID and
these are present as folders named by their window IDs. Aside from the window
folder, there are some special files and folders that we’ll talk about here.
The index file
The index file is a special file you can read to list all the windows currently open in Acme:
% 9p read acme/index
15 68 799 0 1 /home/tj/sources/zx50ef/site/interacme.md Del Snarf Undo Put | Look
2 105 112 1 0 /home/tj/sources/zx50ef/ Del Snarf Get | Look
12 51 348 1 1 /home/tj/sources/zx50ef/site/ Del Snarf Get | Look
13 62 11851 0 0 /home/tj/sources/zx50ef/+watch Del Snarf | Look Get Kill Quit
14 49 205 0 1 /home/tj/sources/zx50ef/+Errors Del Snarf | Look
Each line represents a window. For every line, the first number in given
is the window ID, so, as an example, we know there exists a folder called
acme/15
(in fact the very window in which this is currently being
typed!). The second and third numbers are character counts (in runes)
in the tag and body, respectively. So acme/15
has 68 characters in the
tag, and 799 characters in the body. The fourth number indicates if the
window represents a file (0) or folder (1). The last number indicates
if the window is modified (1 if true, 0 otherwise).
Window control
For each window, there are a number of ways to interact with them. We can read out the current tag and body, we can save the file, overwrite it, etc.
One could imagine an autosave feature that reads a given window corresponding to an open file, compares the last modified timestamp to the file and issues a Put if a significant amount of time has elapsed, like an autosave.
Creating a new window
We can open a new window like this:
% 9p read acme/new/ctl
26 18 0 0 0 807 /mnt/font/DroidSans/11a/font 32
Simply by reading the special acme/new/ctl
we get a new window created,
and a line including the new window ID back.
Clearing a window
If $winid gives the window id, and we want to clear it:
% echo -n , | 9p write acme/$winid/addr
% echo -n | 9p write acme/$winid/data
The first line selects the entire buffer (the equivalent of executing “Edit ,”). The second line then writes the empty string as the data, overwriting the selection.
Ideas for Git integration
Getting used to editing scrollback, then selecting and executing the edited texts takes a bit of time, but it’s not too bad. It works for the most part, but I have been considering some of the ways I use Git and if a tighter integrcation could be done. Putting together a new patch, including writing the commit message could be done with a kind of “Git” buffer.
Some of the commands I use most frequently when putting a new commit:
- “git add -p” - interactively select (and edit) hunks that go on the index
- “git commit -v” - shows me the staged changes going into the commit
I rarely use the “-m” flag for git commit to provide a single-line message. Most of the time, I want to look over the change so it’s at hand when I’m writing out the why of the change. It’s also common to include a reference to an issue or task in a “Fixes: “ commit trailer.
In the tag of an open file/folder (say /path/to/x/), I write “Git” and execute it. A new buffer is opened with the tag:
/path/to/x/+git | Status Diff Log Commit
Executing “Status” would clear the buffer’s text and fill in the output from “git status”
Executing “Diff” would clear the buffer, and fill in the output from “git diff”. “Diff” should accepts extra arguments and just pass them to “git diff”.
Executing “Log” would clear the buffer, and fill in the output from “git log”. To manage the amount of output, maybe an implicit “-10” should be specified. “Log” could also accept extra arguments and just pass them to “git log”.
Executing “Commit” presents a bit of a challenge. If “-m” isn’t used for “git commit”, the user’s $EDITOR is opened with a template, and they can fill in the commit message. Once the file is closed the commit is created (provided the message isn’t empty). Maybe it would be possible to have Git see the opened file in Acme and only finalize the commit when the file is closed? If not, then another approach might be needed where the Git-Acme integration takes more control over it.
Today, when I want to write a longer commit message I do:
% mktemp
/tmp/tmp.UB8KlFSjLp
Then open the file (right-clicking on the name), type in the commit message and finalize the commit by executing:
git commit -F /tmp/tmp.UB8KlFSjLp
Then I also try to remember to delete the temporary file.