Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Trogon – An automatic TUI for command line apps (github.com/textualize)
248 points by willm on May 21, 2023 | hide | past | favorite | 70 comments
Hi HN,

Trogon is a project to generate a TUI for command line apps.

It presents the arguments, options, and switches as a form. Editing the form generates a command line, which you can then run with a keypress.

I'm a lover of the command line. But I can recall only a fraction of the switches for most commands I use. I would love it if there was a TUI available for most commands.

Trogon currently works with Python and the Click library, but I would like it to cover more of the Python ecosystem and also generate TUIs for apps not written in Python.

More information in the repository.

Let me know what you think...




I think the most important piece here is standardizing a schema format for command line programs.

Once you have that (and it’s actually adopted) there are many possibilities. TUI/GUI is just one of them. Think autocomplete, type checking, discoverability...


I believe something of this nature was proposed in the Oilshell under the name Shellac[0]. A shell-agnostic autocompletion format so that the world could finally move on from writing bespoke completion protocols for every new shell language.

[0] https://github.com/oilshell/oil/wiki/Shellac-Protocol-Propos...


I think so to! The schema has possibilities beyond just this tool.


Command-line interface description language http://docopt.org/


with, infamously, no spec.


> schema

I'm dreaming of a universal standard based on JSON Schema. Dynamicity is a challenge of course. I guess one needs to strike a balance between static data, say for each subcommand, and a full blown configuration language, say nix.


Ah I'm reminded of that one xkcd. https://xkcd.com/927/

I hate to be the LLM guy but they're really good at processing semi-structured data to structured data. You could go that route and have a universal autocomplete for the CLI. Kinda like Co-Pilot for Bash, or you could use it to do what the parent's doing and have a universal TUI program for building commands.


Is this what the Click library that Torgon uses provides?


This is really fun. I have an experimental branch of my sqlite-utils CLI tool (which has dozens of sub-commands) running with this now and it really did only take 6 lines of code - I'm treating Trogon as an optional dependency because people using my package as a Python library rather than a CLI tool may not want the extra installed components:

https://github.com/simonw/sqlite-utils/commit/ec12b780d5dcd6...

There's an animated GIF demo of the result here: https://github.com/simonw/sqlite-utils/issues/545#issuecomme...


I've now released this as `sqlite-utils` 3.32: https://sqlite-utils.datasette.io/en/stable/changelog.html#v...

To install:

    pipx install sqlite-utils
Then add the trogon dependency - this command ensures it gets added to the correct virtual environment:

    sqlite-utils install trogon
Then run this:

    sqlite-utils tui
Screenshot in the docs: https://sqlite-utils.datasette.io/en/stable/cli.html#cli-tui


why not

  pipx inject sqlite-utils trogon 
or really,

  pipx install 'sqlite-utils[tui]'
i believe you can expose sub-commands only if an extra is installed; i know this is true for separate entry points.


man i’m installing that this instant …


Significantly harder problem, but what would be of most interest for me is for a program to offer this interface to an unannotated program (which will always be the majority). `trogon ffmpeg` or what have you. Theoretically, command line help is structured in a way it should be possible to parse, but I have no doubt there are many many non-compliant implementations that exist. I suppose you could lean on man files when they exist.


That is a tricky problem indeed.

I’m thinking a lot could be extracted from help and man pages. But maybe for some apps we could just write it by hand, or partially by hand.

These schemas could be in a repo and downloaded on demand.


I hate to be the broken record here but I bet chatgpt could read the man pages for any commandline app and develop a schema in the given format for it.

In fact I’d love to try to do that


there is a large collection of annotations for autosuggestion of commandline arguments for fish and other shells that should be usable too.


This is exactly my current experiment on a personal project I'm working on, though I'm trying to create a Textual UI on a dynamic Python argparse CLI. Creating a Textual UI is non-trivial.

My tool uPlaybook[0] is kind of a CookieCutter [1] / Ansible [2] mashup, and the playbooks typically would have a number of "slots" you can configure to control the templating, like project name, license, if you want to "git init", that sort of thing.

It currently auto-generates a argparse interface, or it can interactively ask you those questions. But I've been working on a Textual UI as well. I chose argparse over Click largely because I want to work with minimal dependencies, and the Textual UI would be an optional dependency.

Going to have to check this guy out.

[0] https://github.com/linsomniac/uplaybook [1] https://cookiecutter.readthedocs.io/en/stable/ [2] https://www.ansible.com/


I would also[0] be interested in an argparse equivalent of this for my tool Library[1]

[0] https://github.com/Textualize/textual/discussions/228

[1] https://github.com/chapmanjacobd/library


> Command line apps reward repeated use, but they lack in discoverability.

The biggest thing preventing me from learning more CLI explained in one sentence, I'll definitely be looking into this.


I highly recommend:

cmd —help

man cmd

ls -la /usr/share/doc/cmd

While some of the language can be daunting, it is generally good reads. And these days we have ChatGPT etc that can help explain tricky words etc in more context, even if you native language is not English.

My new default advice actually for junior developers here in Sweden. Works for many other tech areas too, not just the terminal.


Ah, yes. In English we used to spell that R-T-F-M.


You should check out https://tldr.sh/ It gives you practical examples for common use cases.


Also https://github.com/chubin/cheat.sh (https://cht.sh). Actually using it quite often!


Lack in discoverability compared to what? GUI apps? Web browsers? LOL. Those are intentionally designed to make you use them inefficiently.


I love anything TUI related. I spent a lot of time last year making a TUI-over-the-wire protocol with a TUI browser.

It's somewhat related to this because it's generating a TUI dynamically based on an input schema coming over the wire via gRPC.

Would love any feedback http://uggly.bytester.net


My interest is piqued! You might want to join our Discord server to discuss TUI related things.


Cool project!

But, also, “What is old is new again”.

Back in the days of the mainframe and 3270 terminals, all of the commands were pretty much like this. There really was no command line. Rather, it was a screen of fields filled in by the operator and sent wholesale to the system.

Of course it did not end there. Most every Unix system had some kind of, effectively, “curses” based, full screen administration TUI. They were all pretty good for basic and intermediate tasks. I recall doing a lot of disk operations (partition, raid/striping, etc) just following prompts on these things.

Unix System V actually had a rather nice form and menu package you could use from scripts to do your own TUI just like the admin console they shipped.

Anyway, nice project. Just always interesting to watch stuff come around again.


How easy is it to get this to compose nicely with typer, which also sits on top of click? like, if i expose the command group to the decorator or something, will that work?



daaaang.

ok, we’re cooking with gas now!


Will you’re a legend. I’ve been loving all the work you and the team are doing on textualize. And thanks for doing a lot of dev in the open for us noobs to level up.


Cheers! Glad you like our stuff.


I don't understand why is it more effective than the manual lookup... If a certain cli tool has hundreds of arguments from which I need certain 2, I would rather open documentation and man pages in the `less` tool rather than scroll an infinite form. If a certain cli tool has just the arguments I need, then I know all of them already (or I can recall em in a few seconds from ctrl+r)


I haven't looked at the schema but it might do better when limiting you to certain choices.

For example, there might be a frequency option whose value can be either annual or monthly. If this was communicated correctly in a man page then it's still possible for someone to typo that as monttly.

They'd pick it up if the error reporting is good, but having the options in a tui should prevent such issues.


As others have mentioned, GPT is quite good at reading semi-structured data and producing a structured output. I find it is very effective to ask it to output in an already popular, domain specific format whenever possible. Let it use familiar idioms, instead of trying to coerce it to use a bespoke format.

So here's a simple attempt at taking the output of `black --help` and turning it into a python `argparse` script. You could feed the `--help` or man page for pretty much any command into GPT-4 with this sort of prompt and get an argparse script. It probably doesn't hurt that GPT-4 is already familiar with the argument syntax for all the popular cli tools.

You could then imagine executing the generated code against a faux-argparse library which instantiates the data structures you need to render a Trogon UI. Probably best to do this in an appropriate sandbox.

  $ black --help | aichat --model gpt-4 --prompt 'write a python program that uses argparse to *exactly* parse this tools command line'
  
  ```python
  import argparse
  import sys

  def main(args=None):
      parser = argparse.ArgumentParser(description="The uncompromising code formatter.")
      parser.add_argument("SRC", nargs="*", help="Source files to format")
      parser.add_argument("-c", "--code", type=str, help="Format the code passed in as a string.")
      parser.add_argument("-l", "--line-length", type=int, default=88, help="How many characters per line to allow. [default: 88]")
      parser.add_argument("-t", "--target-version", choices=["py33", "py34", "py35", "py36", "py37", "py38", "py39", "py310", "py311"], help="Python versions that should be supported by Black's output.")
      parser.add_argument("--pyi", action="store_true", help="Format all input files like typing stubs regardless of file extension (useful when piping source on standard input).")
      ...
      parser.add_argument("-h", "--help", action="help", help="Show this message and exit.")

      if args is None:
          args = sys.argv[1:]
      parsed_args = parser.parse_args(args)
      print(parsed_args)

  if __name__ == "__main__":
      main()
  ```
  This Python program uses argparse to parse the command line options for the Black code formatter. You can run this script and pass the command line arguments to see the parsed output.


That's funny because like Trogon, I also implemented some kind of introspection for Python's Click arguments structure. But to automatically derives a configuration file instead of a TUI: https://kdeldycke.github.io/click-extra/config.html


While we're building Swagger/OpenAPI for CLIs, could we also please create typed/type-safe CLIs? I want to invoke command line tools like I invoke functions in my favorite programming language.


Isn't this the main selling point of PowerShell?


that and “everything’s an object”


they are typed... I've yet to come across a cli that doesn't, at the very least pretend, like it's following posix. So all of it's parameters should be strings.


Saying that all parameters are strings isn't really saying much. In the same way one could say that any function is typed because each of its parameters is expected to be a byte string.

Even though CLI parameters are passed to the application as strings, in reality they are often expected to be (and converted to) numbers, enums, lists, file descriptors, … And don't forget that some parameters are optional and/or can be repeated.

In short, there is ample opportunity for proper type annotations.


> In short, there is ample opportunity for proper type annotations.

So you want the parameters to be annotated for their valid values?

Have you not heard of man pages?

I honestly have no idea what else you could mean by type annotations for cli parameters. Do you have an example?


Of course I've heard of man pages. But IDEs haven't. If I write a Bash script, or a Gitlab pipeline, or a Dockerfile, I get little to no feedback at all from my IDE whether I've misspelled a parameter, pass an incorrect value etc.


oh, that's not really type annotations; that's just... cli linting? no idea what to call it but something that will both highlight errors in commands before they fail, and suggest intelligent tab completes.

I want that too, I've already started building it https://github.com/GrayHatter/hsh give me a few months :)


> oh, that's not really type annotations; that's just... cli linting?

I think it sort of is, depending on one's point of view. I mean, at the end of the day, a CLI encantation in a Bash script or Dockerfile is not really different from a function call in your Python/Java/whatever code, only that your interface is not an API but an ABI wrapped inside a POSIX CLI. So the CLI takes on the role of the function signature.

The only problem is that a CLI is typically a very soft and error-prone interface. It might forgive errors, it might be inconsistent etc. etc. This is certainly fine when you can iterate quickly on the command line. But for real programming? Not so much. For such purposes, proper (and properly typed) function signatures were invented. Whether or not you call matching/verifying function calls against function signatures type checking or linting is certainly up to you. :)

As for your project: Cool that you're working on this, and that you're using Zig! I'll visit again in a few months. :)


I want to use terminal, but everytime I type something I get presented with an adjacent form I can alternatively use. A cli command builder gui. Best of both worlds. Also should be web-based. And all output should be a searchable, sortable, groupable datagrid. Terminals really fall down in this department. I can't believe there isn't a terminal that does this yet. Like a Python notebook I guess.


Have you seen PowerShell ISE? Its not exactly what you want, and its UX definitely could be improved but lot of the functionality is there. See this screenshot for example https://ibb.co/T4pDJnw


This is great. I'm relatively comfortable with command lines, but I think people who reflexively respond with "RTFM" are completely wrong. There are few other parts of my life where reading a manual are necessary to start using a product. Being apathetic to users' needs (or deliberately hostile towards users) is frowned upon in almost every field.


This looks interesting, I love Textual so I tried this with one of the apps I wrote:

https://gitlab.com/stavros/parachute

Unfortunately, it doesn't seem to work, failing to find the `cli.command()` function (a group function) after I decorate `cli()` with @tui...


Try @tui() instead of @tui - that might fix it.


Thanks Simon, I can't believe I looked twice to make sure I wasn't calling it wrong, and still didn't see it.

That did, indeed, fix it!


Is there a similar tool with GUI that would obviate the need to typecheck argument values and make selection an easy toggle from a structured list with help/tooltips right where you need them instead of in an inconvenient separate --help document?


For various reasons, I use the stdlib argparse library. Will this work with that?


Can it generate bash completion scripts? eg:

    $ . <(fab --print-completion-script zsh)
to enable autocomplete for fab in zsh shell.


No idea about Trogon but Typer[0], which is based on the Click library that Trogon leverages, does provide autocompletion.

[0]: https://typer.tiangolo.com/


This inspired be to look into how Click handles this without Typer, and it turns out it's a supported feature there too: https://click.palletsprojects.com/en/8.1.x/shell-completion/

I got it working for my sqlite-utils tool in zsh by running this:

    eval "$(_SQLITE_UTILS_COMPLETE=zsh_source sqlite-utils)"


What's with the AI generated bird? If you're going to name it Trogon, it should at least look like one.


Also the bird is gigantic (relative to the laptop)!


I've used the python library gooey which seems to do the same thing. I like the ux of trogon


I worked on a web version of this (I was going to call 'Wooey' for 'Web-GUI'). I ended up abandoning it and I can't quite remember why


Does anyone know what terminal is being used in the demo? It looks really clean.


ITerm2 on MacOS


Looks very nice! Does it also support default "apps" like, e.g., ls?


Not currently, but I think it will in the future.


That would be so useful! Thanks for replying!


Awesome work, thank you Will. And that picture of Trogan... beautiful!


if man pages and `--help` output were more formal definitions of CLIs, we could make a tool that creates a browsable version of every CLI command that has man pages and/or `--help` text.


In the terminal, you can browse man pages and --help text of every CLI command... Who on earth needs another tool to do it?


my IDE gives me help as I type, allowing me to quickly refer to method lists, near-match methods, docs of such methods

what I envisioned is a similar experience for the CLI tools we've come to know and love

not sure anyone neeeeeeds that, but no-one neeeeded an IDE at first too


This makes perfect sense and the “why” is spot on.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: