2

Warning: This may be a stupid/atypical question but I just don't know what to do. Any suggestion is welcome when it comes to change the existing behavior as long as the features are the same.

The behavior of the cli tool

I'm making a tmux session manager(yes another one). The goal was to have a way to pre-configure tmux sessions with some nice lang like rhai, and then to be able to switch between them in a fuzzy finder. But I also wanted to have the ability to create a configuration for the session based on repositories found on the system. The session would have the name of the repo and the root would be the path to the repositroy. Then a config can be created for it(I was thinking of optionally extending that to custom sessions).

The problem

I wanted the tool to be modular and configurable to users content hence I decided it would be a good idea if I just printed the found repo names(just the name of the top level directory of the path for readability reasons, there is an algo that disambiguates the names) to stdout and then this would be piped to a tool like fzf, then the picked session would be passed as an argument to my tool which would spawn an editor for that session. This would look something like:

session-manager new-session $(session-manager find-repos | fzf)

This design makes it so that the new-session subcommand doesn't have access to paths to those repostiories, which is needed. Because of this we have to store the previously found names of repos and their paths on the filesystem. This creates a problem where the user can run new-session after they created a new repo but if they haven't executed find-repos before that then we don't know where is the path of that repo, or if it's a repo at all. I don't know how to design the interface for it to be intuitive, modular and a the same time more resistant against putting the program in a bad state.

The potential solutions

  • Search for the repo when the user executes new-session with a session name that is not found. This has the downside of being slow, and is generally a weird solution because what to do when there are multiple repositories with the same top level name
  • Change the names of subcommands to make it clear that the search must be done just before a session is created
  • Change behaviour and somehow forcing the search to be done when creating a session. If someone wants to suggest this, please describe the behaviuor in detail.
  • Completly redesign the flow. I'm also open to such a suggestion.
  • Encapsulate searching with a higher level command that's defined in the config. This slightly reduces the freedom of the user to do whatever they want and I don't know if there could be security concerns. but it would make the interface intuitive

I'm mainly asking about how would you desigin such a cli application, how would the behaviour look how would the subcommands be named etc. I really tried to describe the behavior the best I could, but I realize that my description could have not been detailed enough in case of any questions, I'll be glad to clarify.

4
  • This does not seem to be about design. Just about tool usage. Commented Jul 1 at 19:30
  • I may have used the word in it's broader definition, but I think it's still appropriate. It's about designing the user experience in a solid way. Commented Jul 1 at 19:58
  • Nope, you have already designed UX. Now you are basically asking how to store a mapping from short names to full-path. Associative arrays are added to Bash 5. Does that help? Commented Jul 1 at 20:01
  • That's a possible solution, but I did not ask to for a techincal solution with the current placeholder design. I was asking if I could maybe design my tool to not have to find the path, or have a nice way to suggest to the user that they should run the find-repos command just before the selecting. Basically suggest one of possible solution that I mentioned or something new. As for you suggestion I would rather not depend directly on the users shell environment. The example with the pipe is a possible solution a user choose but they're free to do something else that fits their needs. Commented Jul 1 at 20:42

1 Answer 1

5

For your design goals of the system being modular, intuitive and fault-resistant you should avoid any temporal coupling between the sub-commands (temporal coupling = you need to run command A before command B to get reliable results).

To avoid temporal coupling between new-session and find-repos, you must make sure that the output of find-repos + any filtering/selection is good enough for new-session to get all the data it needs. That probably means that find-repos needs to output the full paths and not just the repo names.

Some options here are:

  • Just output the full paths from find-repos and let the user select from that. This would be easiest to implement, but probably a less convenient UX.
  • Output a list of space-separated pairs of repo name + path from find-repos. new-session will need to be adapted to accept such a pair as argument(s). In the filtering/selection, the user can focus more easily on the repo name, while the path information is also available for disambiguation if needed.
  • If you absolutely don't want to show the paths to the user, you can make the filtering/selection an integral part of find-repos. You can add an extra command-line option to specify the fitering/selection command to run from within find-repos. Then you can pass a list of only repo names to the filtering/selection command and use the output of that command to find the path that find-repos needs to return.
8
  • Thanks for responding! I discovered a potential solution, now I'm wondering which to use. Here's my idea: This doesn't solve temporal coupling, but rather makes it more explicit. I was thinking of spliting find-repos into cache-repos and list-repos then new-session would use the cache, I think this provides enough intuitiveness. A downside would be still reduced fault tolerance and a more complicated command but except for that it doesn't make any sacrifices. I'm thinking of choosing either the first or the third option suggested by you or mine. Let me know what you think! Commented Jul 2 at 12:45
  • The last point is the way to go (I would introduce a layer instead of an argument). If find-repos is internally cached, this would not event slow down UX. Commented Jul 2 at 12:45
  • @sentientbottleofwine if cache-repos is called internally and is not exposed, the command structure is not complicated. list-repos calls cache-repos, extracts short names, new-session calls cache-reposand uses results for lengthening of short names. Cache invalidation may be based on timeout. Commented Jul 2 at 12:47
  • @Basilevs I haven't really used done things in a way where you can specify a custom command that the program will depend on either in the config or as an argument. But to me it seems a little bit hacky, we depend on the stdout of the program internally and also the user might use shell expansions which wouldn't really work unless I would add that. I'm still considering this solution, but I'd rather choose the first solution proposed . Commented Jul 2 at 13:37
  • @Basilevs There may have been a misunderstanding. I meant for cache-repos to be accessible to the user, then the dependency is explicit. It's task would be to find and save the repos found on the filesystem, not to retrieve the data, because that can be done internally. If the user added a repo then they would know to execute cache-repos after. But cache-repos is not intened to be called standalone although it can be done, the intention is to do something like: cache-repos; list-repos | fzf, but I still can't decide what to choose in the end. Commented Jul 2 at 13:51

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.