ajalt / mordant

Multiplatform text styling for Kotlin command-line applications
https://ajalt.github.io/mordant/
Apache License 2.0
935 stars 33 forks source link

React to terminal size changes on JVM #152

Closed mikehearn closed 5 months ago

mikehearn commented 6 months ago

Currently, changing the size of the terminal window whilst a progress tracker runs will cause corrupt display, as the new size isn't taken into account. There's a sun.misc.Signal API I think, that would allow for reacting to the SIGWINCH on UNIX. On Windows it's harder, I don't think the JVM exposes anything for that, not even in private APIs. Perhaps jline has some code for it.

ajalt commented 6 months ago

I think this would require some JNA code.

In the meantime, you could potentially poll terminal.info.updateTerminalSize(). The reason I don't do that automatically is because, due to the JNA bug mentioned in #86, we still have to shell out to stty on macs, which is potentially slow. If that ever gets resolved, we could check for a new size before each frame.

mrbubble commented 6 months ago

updateTerminalSize correctly detects the size change, but doesn't address the garbling of the output when the screen shrinks. What seems to happen when using full width progress bars is that any reduction in the screen width causes the progress bar lines to wrap, so when the next animation frame comes the number of lines to clear is incorrect, and some of the lines become permanent above the animation.

ajalt commented 6 months ago

Oh, good point. That's a tougher problem. It seems like the solution would be to keep track of the terminal size between frames and calculate where we think the cursor is after wrapping so that we can move back to the original position.

mrbubble commented 6 months ago

Should be something like previousHeight * ceil(previousWitdh/newWidth), for the case where the animation width covers the entire terminal width, and the newWidth is smaller than the previous.

mikehearn commented 6 months ago

Would printing the right number of backspace characters be an alternate way to clear the animation?

ajalt commented 6 months ago

Backspace is a good idea, but unfortunately terminals handle it very differently. Some will ignore it entirely, some will only delete back to the start of the line etc.

ajalt commented 6 months ago

Ok, so I implemented this in #151.

If you're able to try out that branch and let me know what you think, I'd be appreciate it.

mikehearn commented 6 months ago

Thanks! I'll try and make time for it in the next few weeks.

We have our own multi-task progress bar implementation that uses Mordants rendering alongside its own, but it uses the animation APIs so it should work. Do you have any pictures of what the new multi-task tracker looks like? Perhaps we can migrate, although I do like our current look.

The JNA bug could be worked around by using Panama on modern JVMs. JNA isn't necessary anymore on those versions.

ajalt commented 6 months ago

The multi bar looks pretty much the same, but

image

Panama looks promising, but it's still in preview, so it will be quite a while before we can drop JNA.

JakeWharton commented 6 months ago

It's stable in JDK 22 releasing in two months. A multi-release jar would allow its use only when running on 22+.