There has been numerous quality of life improvements added to our terminal emulation liberated command-line environment, Lash, to the curses-like “libarcan-tui” it relies on, but particularly to its reference shell implementation, Cat9. These have mainly been subtle enough that there is little point in making the effort with longer dedicated write-ups on their various implications and overall splendour.
In general my criteria for any non-release write-up on this site is that the contents should, at the very least, highlight and counter some of the many deficiencies in the popular solutions, as well as fit into a grander story.
For the chapter on text-dominant shells there are quite a few candidates in the pipeline. Rather than building them up for an information overload like I did with the original release post, I decided to space them out with a focus on one or two of interest.
For this round I have selected ‘list‘ and ‘stash‘, as they interact and complement each other in a nice way, as well as showcase better integration with the outer desktop.
Before that, lets highlight a few conveniences first. In the following screenshot you see how the suggestion popup gained some width after I pressed F1 and how the borders of the popup itself defies the grid, as it is not using line drawing characters. Many commands now support descriptions of what they or any subcommands do.

They also give stronger validation feedback about the validation error and the affected offset.

As well as hint about what the current argument is expecting:

List supplants the well-known ‘ls’ (dating back to the very first AT&T UNIX). Although we still can fork and run ‘ls’ just like any old shell can with the generic improvement that we can reference its contents and context long after it is gone; repeat its execution later in-place and detect changes; slice out selected results and so on. Just as it is bland and boring, it is also problematic.
The file in the following screenshot does not exist, or at least isn’t called that and you can’t refer to it using the output of ls alone. If isatty() applies to stdout it behaves one way and you might get escaping that may or may not work for referencing it interactively depending on your libreadline implementation. It behaves in another when in a pipeline. All parsing of the output is ambiguous, we know that since long, don’t parse ls and all that. The data might be outdated the second it is produced and you wouldn’t know. Tab completion output presents it in yet another way.

Enter list. As shown in the following screenshot, as soon as I run the command some subtle things happen. One is that the number of ‘active’ jobs hinted at in the prompt does not go back to zero.

That is because list is still very much alive. If I create a new file in the folder, the list automatically updates and marks that an item is new. If I click on folders it navigates to them, and if I click on regular files some default open action will be triggered. I can change sorting order without re-execution. For the setup I have here, the default open action tells the outer window manager to swallow up until terminated, and hand over to a dedicated player or viewer and this composes over the network if run that way. The same naturally works if I hand input focus to the list job and navigate using the keyboard. The following clip demonstrates all that:
There are quite a few sneaky details to this. If I would, for instance, change my working directory and try to reference contents in the list, what would happen? In the following screenshot you can see the result of copy #0(2,4,5) and how the list resolves to its full path and the presentation metadata is stripped away. The crazy file is now gone after composing with /bin/rm by running rm #0(8) — no fragile escaping necessary.

This brings us to stash. Internally the mouse-2 binding for list was set to stash add #csel($crow) which means add to stash the currently selected row in the currently selected job. Stash is a singleton active job (only one running). It acts as a dynamic list of sorts, but there is, of course, more to it. Stash accumulates files on demand from other source, such as list, drag and drop actions and so on. The following clip shows that in action.
It also act as a generic staging area. A simple danger is that you “ls |grep pattern” and based on that information run a destructive command like “rm another_pattern”. The caveat being that infinitely many things might have happened between your ls and rm and innocent files are lost in the process. With stash I explicitly build my change set, then stash unlink yes to explicitly commit to only apply to this set.
As with list and others, we have deeper mouse and keyboard interaction as well as visual layout separated from the actual content because we are not a dot matrix printer. Resizing will prioritise content based on the space allotted. Presentation and content is separated. This screenshot shows a compact window having run ‘cat #stash’ to show composition with traditional cli tools.

Perhaps you can mimic some of this (not really, I am just being characteristically smug) via some of the recent trendy perversions of putting more logic into a terminal emulator clinging on to that riced PDP-11 experience as the default.
Another stash action is verify. This queues a checksum calculation for every file referenced in the stash. When that command is repeated, any entry where the checksum has changed gets highlighted. The following screenshot shows a stash of files where one was still being modified when the stash was re-verified.

This is useful to ensure that you are not operating on a stash that is currently being modified, or having preset tripwire protocol, mark the stash as part of the serialisable cat9 state set and move between machines to check that they match. It also goes well with the next item.
You should have noticed the arrows and that the name appears twice. This is for the last feature to demonstrate. If I run stash map <src> <new-dst> the arrow changes. This lets me give a name to the nameless, e.g. file descriptors being passed to the window. If I combine that with stash archive an archive (arc, tar, …) will be built using the mapping presented. The following screenshot shows such an archive built and extracted.

In the following clip I use the file-picker in my outer desktop (durden) to drag and drop two files into the shell window. As you can see these are automatically added to the stash. Note that they are not shown by their path, because I am actually running this remotely over our network protocol.
I then use resolve to ensure that the items (marked !) are resolved to locally readable files as tar is not capable of accepting sets of passed file descriptors and working from (so eventually needs replacement with something better). Lastly I archive them together.
It’s bold to decide to introduce a data structure to the command line workflow. A live updating list. Composition has traditionally stuck to untyped streams of “plain text”, so even as much as adding a list is radical.
Why did you choose to make stashes hold the list though, and not something deeper with keys and values and values (like JSON)?
Is because lists map directly into argument lists? (But then most programs use named options, so the key-value data structure could be a useful if that was the goal)
Also, I wasn’t able to infer by the post, are stashes just for holding files or are they too intended to store arbitrary strings?
Having a deeper structure to stash would make it harder to compose with all the other commands as those expect single lines.
Generally support for working with structured / parsed data is through ‘views’ where you attach a higher-level renderer for some specific format (JSON, markdown, …).
The stash only works with generic files or file-handles as a staging area for file operations.