Woke with a rather obvious idea for something that can really make
Bonzai into a shell that has just not yet been made. The idea is
consistent with composition, the main basis for the Bonzai design. It’s
simple, create a Hook
type to go with Cmd
and Completer
and
Configurer
. A hook is just an importable package that hooks into the
execution of each Cmd.Run, Cmd.Call, or Exec. A Hook
would get all the
arguments passed to each as well as the output from each. A Hook
could
alter the inputs before they are passed on, or the output before it is
displayed. I hesitate to allow modification of input/output, though,
because knowing what Hook
messed with the input or output could get
messy. Hooks are how I would implement history. Any number of different
types of history could be created, even combined. Hooks could also allow
the dynamic writing of macro/scripts. A command like z macro start
could trigger a hook to start writing each subsequent z
call to a
macro file. This all needs caching to really be solid. I have to put
some more thought into that.
Caching is the key to getting off of complex single commands with tons
of arguments. It provides a consistent, safe way to preserve state
between simpler command line execution. Setting variables in shell is a
way to preserve that state between command line executions, but what if
we took that one step further, at the cost of a slight bit of
performance. What if we maintained the cache as a Protobuf binary, the
fastest possible thing to load and persist to disk. What would be the
cost in performance? I think it would be negligible. So say we add z
cache foo everything else is the value
and z cache foo
fetches the
value from the cache. I really think the delay in reading from the cache
would be really minimal considering it is an interactive session. But
even plans for “macros” or “scripts” would be fine, and more
importantly, have all their variables persisted effectively by using z
cache
for it.
The obvious next step is to add the |
operator (and only the pipe
operator) allowing z
to run in interactive/shell mode where it detects
if the session is interactive and prompts and stuff, and if not, assumes
the standard input is, indeed, a number of z <command> ...
lines. In
which case something like this becomes a Bonzai script:
set foo something here
set bar another value here
somecmd with args | set something
get foo bar | set combined
get combined
I think that like Configurer
we need to provide a Cacher
that
provides Get(name string)
and Set(name, value string)
and
Clear(name string)
as well as ReqCache bool
so people creating
commands can ensure those composing their own trees pick a Cacher
for
their z
command. Say someone wants to cache to a Reddis database, or
SQLite, or the cloud someplace since they don’t even have a filesystem.
All would work. The Protobuf file in os.UserCacheDir
is just the first
one I would implement.
The really cool thing about that is that by combining hooks and the
ability to process lines macro/script, that users can easily recreate
any natural combination of steps and then edit those steps directly.
This is something the script
command never actually got quite right.
It always produces files that themselves cannot be run. z script start
would, I figure, activate the hook that records every z
command
thereafter, which its arguments, to a file, text or protobuf, and then
z script stop
would stop. z script edit
would open that file with
the z config editor
and z script save <name>
would store it in the
os.UserConfigDir
or someplace similar. z script run <name>
would
obviously just run that script. And we already have support for aliases
if that is too much to type. But even better, z script gogen <name>
could generate Go code that could be plopped rather easily into a Cmd
definition in my monolith, so there aren’t a bunch of scripts around in
different files and such. I don’t know if we should call it a “macro” or
a “script”. I feel like “script” is better though, specifically
BonzaiScript which you can learn in five minutes. “It has ‘|’”. The end.
That is all there is to learn. Everything else is something you can
already do with your z
monolith, whatever those things are. The
“syntax” of the language depends entirely on what you put into your
Bonzai tree.
So the next step is going to be the bonzai.Cacher
interface and the
first reference implementation using Protobuf stored in
os.UserCacheDir
. Then we’ll probably need a bonzai.Shell
interface,
or perhaps just bonzai.Hook
. I don’t want this project to get out of
control, but those are the essentials that I’ve known it would always
need. And I think they cover the bases for all “replace my shell script”
efforts.