selectel / pyte

Simple VTXXX-compatible linux terminal emulator
http://pyte.readthedocs.org/
GNU Lesser General Public License v3.0
649 stars 101 forks source link

Assigning to Screen.buffer to restore its state #155

Open abingham opened 2 years ago

abingham commented 2 years ago

I have a situation where I need to store the state of the terminal at some point and restore it later. For pyte's Screen, is it sufficient that I a) deep copy Screen.buffer at the point I want to save and b) assign to Screen.buffer when I want to restore it? Is this officially support behavior? Is there anything else I need to do? Thanks!

eldipa commented 2 years ago

Most of the state of Screen is on its buffer but not all. You need to backup the cursor too.

If the PR #160 is accepted, then copying Screen.buffer will not work. But if the PR is accepted and you still need the feature, we can think on a proper implementation for "backup and restore" the screen state.

Could you give details of why you need this "backup and restore" feature?

abingham commented 2 years ago

we can think on a proper implementation for "backup and restore" the screen state.

That’d be great. Any supported mechanism for doing this should meet my needs.

Could you give details of why you need this "backup and restore" feature?

A tool I’m developing does a form of terminal recording (similar in some ways to what’s mentioned in #160), and it includes support for adding ‘annotations’ and ‘highlights’ to what’s shown in the terminal. Before adding annotations (which can really be arbitrary modifications to the terminal contents) we store the terminal state; when removing them, we restore the state.

altoidbox commented 2 years ago

The control codes used for full screen applications such as tmux or vim make use of a 'normal' and 'alternate' screen buffer. Switching between these buffers feels like a similar operation to making a backup of the screen state and later restoring it.

Perhaps handling of those codes isn't something currently supported by pyte, but there may be those that have subclassed some of the pyte classes to implement it themselves.

eldipa commented 2 years ago

@abingham So the idea would be: you have a screen with data written by the terminal app, at some moment you stop feeding the streamer but update yourself the screen with some annotations. Because you want to remove the annotations before restarting the feeding, you store the screen's buffer before the annotations and restore it after.

In this sense the annotations or any "temporal" modification to the screen work more as a "stack": you start with a screen with a given buffer (0) and when you are about to do some temporal writing you push a new buffer state (1) which it's in principle, a copy of the former (0). Once you are done, you can restore the previous buffer doing a pop on the stack. In the browser analogy, it is like when you are seeing a page, you go to another page and then you go back.

What @altoidbox suggests I think it would not work. The alternate buffer is meant as a second independent buffer to switch back and forward with no content shared between. Think in an array of 2 different buffers. In the case of the stack you implicitly have that the content of the buffet at the top is a copy of the previous buffer. Note that "alternate buffer" concept is limited (AFAIK) to two buffer (the foreground and the alternate) but this is only because a practical design of old terminals, pyte could perfectly support N buffers (in similar fashion your browser supports multiple tabs)

Does this make sense?

@altoidbox do you know a program that requires alternate buffer?

altoidbox commented 2 years ago

@eldipa As far as applications that run in a terminal environment, the primary ones that come to mind are tmux, vim, and screen. Really any full screen terminal application that restores the original terminal state when they exit probably use the alternate screen buffer.

eldipa commented 2 years ago

Yes, I was thinking in screen too. For vim I think it does the same when it shows the output of a shell command. I guess for a PoC vim will be simpler to use.

I will give it a try to the restore buffer/alternate buffer things probably the next month. By the way, if you have some extra time to review and/or test the #160 it would be nice. It introduces some non-backward compatibility changes but I'm estimating that the changes required by the users will be small or none. And because #160 speeds up pyte in most of the benchmarks, having more "real" scenarios to validate that is important.

Thanks to both for the replies.

abingham commented 2 years ago

@eldipa Yes, the stack analogy is exactly correct; in fact ‘push’ and ‘pop’ are the verbs we use in our code for these operations. We need to be able to put any number of states on the stack and return to them.