ajalt/mordant

Could TerminalDetection be made public?

Closed this issue · 6 comments

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.

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

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.

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.

It's public in the latest release.

Thanks!

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.