Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Idea: more generalization for ptys #54

Closed
mikehearn opened this issue Mar 9, 2022 · 4 comments
Closed

Idea: more generalization for ptys #54

mikehearn opened this issue Mar 9, 2022 · 4 comments

Comments

@mikehearn
Copy link
Contributor

I updated to latest Mordant today - looks good. I found the way stderr is handled a little odd. Why is it done as a sort of transformation of TerminalInterface/Terminal? It feels a bit like Terminal should just be a wrapper around an arbitrary byte stream and maybe a set of environment variables, rather than special cased for stderr/stdout, as that way you can easily connect it to things like a telnet or ssh session. Note that this would require modifying StdoutTerminalInterface.

@mikehearn
Copy link
Contributor Author

Another reason I'm a bit confused by this approach - if you have a program that writes to both stdout and stderr simultaneously e.g. because you're drawing a progress bar on stdout, and then you want to println to stderr, it won't work because they're two separate terminals entirely with their own interceptor lists and locks - even though in the typical case, they're both connected to the same terminal.

@ajalt
Copy link
Owner

ajalt commented May 30, 2022

@mikehearn thanks for the feedback. I changed forStdErr to share locks and interceptors in 92f4903.

I agree that forStdErr feels clunky. I'd love to hear your thoughts on a better API. Can you elaborate on the issue you are having using a mordant app over ssh?

Here are some of the design constraints that led me to the current solution:

  • Mordant has a lot of different functions that print text (print, println, info, warning, cursors, animations, etc.), so I don't want to add a flag like stderr=true to each one.
  • As you've mentioned, we do want to share themes and interceptors between stdout and stderr
  • Not every platform even has a concept of stderr (browsers, the minecraft dev console etc.)
  • There is no cross-platform concept of "an arbitrary byte stream" that we could wrap. I added TerminalInterface to abstract this, so someone could implement one to print to something other stdout.
  • For most platforms, which do have stdout and stderr, we need to detect whether they are interactive ttys or not. Each stream can be redirected separately, so one could be interactive while the other is not. This is why I wasn't originally sharing interceptors.

@mikehearn
Copy link
Contributor Author

Thanks. Those are good rationales. Probably, if they were described in the kdocs I'd have restricted the scope of the bug report to the lack of shared interceptors/locking.

Internally I've started abstracting Mordant a bit, because at some point I want to expose its capabilities via APIs in my own product and can't/don't want to be asking you to keep to a stable library ABI in future. I've played with a few alternatives but the current approach, which seems to be working, is an upgraded PrintStream that changes the behaviour of printing objects when certain types are detected. This is JVM specific of course but I don't need to run in browsers or using K/N, and anyway PrintStream isn't a very complicated API.

So for example there's a wrapper type for Markdown, and when you use System.out.println(MimeTypedString.markdown("*foo**")) then MimeTypedString is recognized by the print stream and it gets converted to Mordant widgets and printed. Likewise for List<Path> (which triggers a nice coloured ls style listing) and so on. This is less powerful than Mordant's widget and animation API because it's semantic rather than presentational, but the benefit is a much smaller API surface area, and there's also the possibility to transparently upgrade the presentation with new widgets later. It also solves the stderr issue.

I think for Mordant the forStdErr approach makes sense, now you explained it. It might be worth renaming Terminal to reflect that it's really a wrapper over a particular input/output stream pair and not a "terminal" in the hardware/app sense per se.

@ajalt
Copy link
Owner

ajalt commented May 31, 2022

Sounds good. I do have a lot of docs to write.

@ajalt ajalt closed this as completed May 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants