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

Could TerminalDetection be made public? #171

Closed
mikehearn opened this issue May 21, 2024 · 6 comments
Closed

Could TerminalDetection be made public? #171

mikehearn opened this issue May 21, 2024 · 6 comments

Comments

@mikehearn
Copy link
Contributor

I have an app where for various reasons it's convenient to call println() from code that doesn't know about Mordant (and shouldn't). To make this work I can redirect stdout so System.out goes to a PrintStream that prints via Mordant, and Mordant prints via the original stdout stream. Unfortunately this is awkward in the current API, because Terminal requires TerminalInterface requires TerminalInfo, but the only public way to get this object is .... Terminal. So you have to create Terminal twice. If TerminalDetection were public, this could be avoided.

Alternatively, it'd be good if Mordant could do this interception itself.

@ajalt
Copy link
Owner

ajalt commented May 21, 2024

I'm not quite following the description, could you give a short code example of what you're trying to do?

@mikehearn
Copy link
Contributor Author

I'm trying to simplify the process of doing progress tracking (on the JVM for now, but possibly in future for KMP libraries too).

        fun get(): ProgressReport.Tracker {
            if (globalTracker != null)
                return globalTracker!!

            // Set up Mordant. We need to customize the interface to break the loop that would otherwise occur when we override stdout.
            // And we need to create Terminal twice, because TerminalDetection is internal.
            val tmp = Terminal()
            val redirectInterface = RedirectingTerminalInterface(System.out, System.err, tmp.info)
            val terminal = Terminal(terminalInterface = redirectInterface)

            // Ensure printing to stdout still works and pushes the messages _above_ the animation.
            System.setOut(PrintStreamWrapper(terminal, System.out))

The problem here is that to redirect stdout I need a Terminal with a custom TerminalInterface, but to implement TerminalInterface I need a TerminalInfo, but to get a TerminalInfo I need a Terminal. So there's a loop.

@ajalt
Copy link
Owner

ajalt commented May 25, 2024

I see, so your RedirectingTerminalInterface sends the terminal output to the original stdout, then your PrintStreamWrapper sends System.out to the terminal, and you do that so you can use System.out.println etc. while and animation is running.

The only thing the Terminal constructor does is call TerminalDetection, so there isn't actually any problem with creating two terminals like you're doing, but I agree that it looks odd and that I should add a batter way to do that.

@ajalt
Copy link
Owner

ajalt commented Sep 8, 2024

It's public in the latest release.

@ajalt ajalt closed this as completed Sep 8, 2024
@mikehearn
Copy link
Contributor Author

Thanks!

@mikehearn
Copy link
Contributor Author

I'm trying to port to Mordant 3 and it seems I still need to create a Terminal object twice, because the only way to implement what I want (System.out redirection into Mordant) requires me to wrap the TerminalInterface with an override that delegates to the real interface. But the only way to get the real interface is to create a Terminal because STANDARD_TERM_INTERFACE is marked internal.

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