ratatui / ratatui

A Rust crate for cooking up terminal user interfaces (TUIs) 👨‍🍳🐀 https://ratatui.rs
https://ratatui.rs
MIT License
10.3k stars 309 forks source link

Allow the Inline ViewPort to be resized #984

Open PitiBouchon opened 7 months ago

PitiBouchon commented 7 months ago

I would like to use the Viewport::Inline(height) and modify the height of it

I'm looking for :

insert_before already works to print a line before the viewport but isn't modifiable

joshka commented 3 months ago

This seems like a reasonable feature to add. Would you mind putting some thoughts down on how the library might change to accommodate this (i.e. what methods will be added to the relevant types)? I wonder what would break if this was implemented.

PitiBouchon commented 3 months ago

I currently don't have much free time, but I'll look into it in the future

joshka commented 3 months ago

I currently don't have much free time, but I'll look into it in the future

No problem. Take as much time as you need.

nfachan commented 2 months ago

This is something that we would like to use for our Maelstrom project. As such, I have a few thoughts on it. Unfortunately, there seem to be a lot of details to conside#

Terminal Capabilities

The terminfo manpage has some interesting content in the " Insert/delete line and vertical motions" section that is relevant to this discussion.

I think if done right, and on a modern terminal, it would be possible to do viewport resizing without much redrawing, and thus without a lot of flickering. Unfortunately, this complicates the API because we'd need to give some hints to Ratatui so that it would scroll/insert/delete in the right place to minimize redrawing.

Growing the Inline Viewport

When growing the inline viewport, there are a few different issues to consider. The first is whether or not the viewport currently sits at the bottom of the screen or not. If it does, then it will obviously have to grow upwards. But if it doesn't, then, in theory, it could grow upwards or downwards. I think having the inline viewport grow upwards when it's not sitting on the bottom is kind of weird behavior, so I would disallow it and just mandate that the viewport will always grow down unless it's sitting at the bottom of the screen, in which case it will always grow up.

When growing by multiple lines, the viewport may need to first grow down, and then grow up. For the purposes of this comment, I'll assume that such a request is split into two.

If the viewport grows up, then there is another question of what to do with the lines currently above the viewport. Should we overwrite them, or should we scroll them up?

Finally, in order to minimize redrawing, we want to know where in the viewport the new line is going to appear: top, bottom, or middle.

With all of that, you get something like (in addition to updating the viewport_area):

On Bottom? Up or Down Scroll or Overwrite Where in Viewport Operation
Yes Up Scroll Anywhere Create a scroll region from top of screen to desired line and scroll up or use terminal's insert line.
Yes Up Overwrite Top Clear the line just added to the viewport.
Yes Up Overwrite Not Top Either create a scroll region inside of the viewport to scroll up the currently-written contents, or accept redrawing the top part of the viewport.
No Down N/A Bottom Clear the line just added to the viewport.
No Down N/A Not Bottom Either create a scroll region inside of the viewport to scroll down the currently-written contents, or accept redrawing the bottom part of the viewport.

I think you could give three parameters to the grow_viewport function: the number of lines to grow by, whether or not to overwrite or scroll when growing the viewport upwards, and where in the viewport the new lines should appear. The decision to grow up or down would be made by Ratatui based on where the viewport was.

Shrinking the Viewport

There is one big question that I see when shrinking the viewport: whether to shrink from the top or from the bottom.

Shrinking the viewport from the top would involve giving Ratatui a function to draw to the lines that are released out of the viewport. In other words, this is like an insert_before where the viewport size also shrinks. This is something we want in Maelstrom. This wouldn't require any extra terminal capabilities. However, you could also tell Ratatui which line from the viewport to remove and it could use the scrolling or delete capabilities to make the change more efficiently.

Shrinking the viewport from the bottom would involve clearing the lines now left below the viewport. Again, this wouldn't require any extra terminal capabilities, but specifying which lines you wanted to remove would allow Ratatui to use extra terminal capabilities to make the change more efficiently.

joshka commented 2 months ago

I'd recommend experimenting how each of these works outside of ratatui (I.e using plain crossterm), with some sample code and then mapping the ideas onto ratatui. Note how resizing the double buffer interacts here. Most of the time we're just redrawing the entire buffer when there's a resize, as accurately determining the diff is difficult (this seems like an example of the sort of difficulty to do that). Also check how this interacts with a few terminal emulators if you have a way to do so (Mac: iterm2 / terminal.app, windows: ?, Linux: ?, cross platform: alacrity, kitty, wezterm).

It would be easy to end up writing this in an unmaintainable mess of special cases, but simple, clean and obvious would make me happy to see this. With an understanding of what happens when terminal support is lacking would be nice to have too.

Also, maelstrom looks pretty neat. Looking forward to trying it sometime. I'd love for this to be more than tests and encompass all the preflight things in some sort of continuous manner like clippy, coverage, formatting, etc. it would be pretty wild to know prior to submitting a PR that none of the CI steps will fail (in a performant automatic manner). Bringing more things into the developer inner loop safely without any downsides would be amazing. I recall using ncrunch as a .Net dev ages ago, and the ability to automatically show broken tests on save was a killer productivity feature. Hopefully maelstrom reaches that level of usefulness.