jdx / mise

dev tools, env vars, task runner
https://mise.jdx.dev
MIT License
9.35k stars 259 forks source link

cli ux bus #1951

Open jdx opened 5 months ago

jdx commented 5 months ago

Full disclosure, this is a complex issue that probably won't make much sense to anyone except me. I'm just writing down my thoughts to come back to this later as it keeps returning as a problem and I want to build a generic solution.

A ton of complexity in mise is related to displaying information to the user. mise will display logs and progress bars differently depending on how it's configured like if --verbose is passed or not.

Currently this is handled by passing around a bunch of "progress bar" structs which are sort of singletons for particular "tasks" of execution. There can be multiple running at once like when installing multiple tools in parallel.

Each of these "tasks" can output its own logs at different levels (error, warn, etc) and there is a lot of configuration around these to keep the output clean and relevant while also making it possible for the user to get more verbose output relatively easily by just passing --verbose or --debug.

So basically each task has a "progress bar" struct that needs to be passed to all subroutines so they have a place to output the right information. This works ok, but it does mean there are sometimes glitches because this step was skipped. Also, some parts of the code operate inside of some of this logic and some don't, meaning there may or may not be a progress bar to report information to. If there isn't, then we just operate like a traditional CLI and dump the logs out to stderr.

This is becoming more of an issue as of late because I'm modularizing some of the code in mise out to separate crates like xx, usage, demand, and vfox.rs. These libraries often also need a way to report status and progress.

What I want is some generic "bus" where libraries can emit this information to where the CLI calling the library has control over how that information gets rendered. I'd also like to remove the requirement that this needs to be explicitly passed as a struct down to all of the tasks and instead they had some kind of shared reference to get its current task.

My initial thought here was to use some kind of thread-local storage, but that has some problems since you may actually want to spawn multiple threads inside of a given task. I may need to look around a bit more for something like this to see if it's possible to have something like thread-local but also shared with some subset of threads—frankly I'm a bit new to multithreading code in general.

This seems to be a perennial problem in CLIs. Most CLIs just emit line-by-line whatever it is doing but that becomes quite hard to read once the CLI starts doing a lot of things. This is especially true when the CLI is doing things in parallel and emitting information about several things at once.

For that reason, I'd like for this to be a new crate for the explicit purpose of reporting CLI status. I know in node there is a tool which roughly does what I'm proposing here and it was driven by the observable pattern—though the name of the project escapes me right now. Once we have that in place, I would also like a way for plugins to be able to emit this somehow as well, like for example a plugin would be able to report the download progress back up to a progress bar in the UI so you could have multiple progress bars for different plugin tasks running in parallel.

Along with simply having a place to report this logic I would think this plugin would also have a set of built-in reporters, similar to what color_eyre does for error message reporting.

Anyhow the ultimate goal here is to make it possible for libraries to have a way to report progress but give mise (or whatever host CLI is running the library) the ability to customize how that information is presented to the user. This notably is strongly related to what logging libraries like log are already doing. However those don't have a way to report metadata like progress percentage of downloads.

jdx commented 4 months ago

some prior art: https://andrewkelley.me/post/zig-new-cli-progress-bar-explained.html#zig-progress-protocol-spec