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
add SerializeAddon #2298
add SerializeAddon #2298
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work 👏
…ist join instead and some code clean up
|
||
/** | ||
* Serializes terminal rows into a string that can be written back to the terminal | ||
* to restore the state. The cursor will also be positioned to the correct cell. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should add an explicit cursor move sequence (\x1b[y;xH
) if it's not where we expect it, otherwise this statement is false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as with my note above - absolute positioning of the cursor would have to be corrected later during restore, if the target terminal has other rows X rows width, thus serialize needs to export the viewport size to not lose this important bit of information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah great PR 👍. I am a bit unsure about the final goal of the addon, whether you want exact cell restoration later on or not. See my notes for further details.
|
||
for (let i = 0; i < length; i++) { | ||
const line = buffer.getLine(i); | ||
lines[i] = line ? line.translateToString() : ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the goal of the addon is to get the closest possible match to be replayed on other terminals it should also serialize/restore gaps in lines (empty cells up to trim border). Those can happen if the cursor jumped over cells (e.g. some cursor command or TAB). Note that translateToString
fills those with whitespaces to get a close string representation, that does not rely on terminal output (cannot use cursor commands for that).
To also grab those gaps imho its better to walk over all cells and check explicitly for content. If a real gap was found (watch out for empty cells after wide chars, those dont count here), the cursor should be moved forward. Doing this will ensure that the content is really the same after serialize/restore (beside the attrs that are not exported yet).
But as always, the devil is in the details. For this to work reliably, serialize would also have to export the viewport grid size, and a later restore action would have to take this into account.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My goal is to write a terminal session player which is the same as asciinema but with audio support. examples: https://asciinema.org/a/138296
But asciinema is written in ClosureScript that I believe rare people is familiar with. So I have to implement it in my own way.
To answer your question, Yes, I need to get the closest possible match to the original terminal session
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, then I think you cannot go with translateToString
directly and need a more advanced buffer scraping method instead. Also there is no simple replacement character to keep the null cells in the output (you cannot use NUL as it will be skipped by emulators as stream padding byte).
Hmm, do you want the data to be re-applicable to other targets (other emulators beside xterm.js)? If so, then the serializer would have to know about the features of that target. Note that there are dumb terminals, that cannot deal with cursor movements at all and would map CUF to whitespace (basically translateToString
assumes this dumb control char capabilities). Same with text attrs once you expose them - not all targets understand them.
So if you want to support those "other targets", imho serialize needs options to be eval'ed during export:
public serialize(rows?: number, opts?: ExportOptions): string {
...
if (!cell.hasContent) { // empty cell
for (let i = 0; i < cell.width; ++i) {
output += opts.CUF; // ' ' for dumb, '\x1b[C' for smart terminals
}
...
}
Not sure if we expose enough buffer state yet in API to let you do it this fine-grained.
Later on, this would look likewise for text attributes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edit: A different approach would be to serialize as much as possible information into a not directly applicable format, and do the features switch during restore. This has one advantage: you still have all the needed bits of information and can apply the same data to HTML, dumb, xterm.js (to be fed back). The major disadvantage is the fact, that this will need a restore component, while doing it during serialize would not.
Not sure where the tradeoff is, imho a directly applicable format is nicer to deal with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO xterm.js is enough for me and I don't need to support some special terminal emulator currently. All I want is to "copy" all the features that asciinema already have by Typescript.
Another thing is asciinema is based on VT terminal (see https://github.com/asciinema/vt), I believe it's the same as xterm.js
And I count this commit as a beginning, it doesn't need to cover all that cases for now. Continuously add features steps by steps is a good choice for me.
This commit based on the discussion of #2213 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah lets not over complicate things. If you only want to go with xterm.js compatibility, you can take any escape sequence in the final output thats listed in InputHandler. (We dont have a list of supported sequences yet.)
|
||
/** | ||
* Serializes terminal rows into a string that can be written back to the terminal | ||
* to restore the state. The cursor will also be positioned to the correct cell. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as with my note above - absolute positioning of the cursor would have to be corrected later during restore, if the target terminal has other rows X rows width, thus serialize needs to export the viewport size to not lose this important bit of information.
Can I merge to master now? |
Hi @JavaCS3, thanks for your contribution, we think your code quality is really good and we appreciate your effort! We've just had an internal discussion within the xterm.js maintainer team, and we came to the conclusion that this addon would be better off living in a separate repository outside the responsibility of our core maintainer team. We feel that at the current state, this addon is very specific to a certain use-case (extracting plain text from the buffer), and it won't benefit many users. I've got some ideas on how you can achieve #2213 with a different technique, so let's continue the discussion over there. |
@JavaCS3 we're still discussing, I think we do want this. Hold tight 😃 I suggest checking out @mofux's suggestion though in #2213 (comment) as that's probably a better solution to your problem in the end. |
Any update? |
if (!this._terminal) { | ||
throw new Error('Cannot use addon until it has been loaded'); | ||
} | ||
const terminalRows = this._terminal.rows; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to serialize whole buffer, but not only visible lines?
( const terminalRows = this._terminal.buffer.length;
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, It used to be like that.
But after I took @Tyriar 's suggestion into account, I changed to this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing the whole buffer could be pretty expensive so opting into more than the minimum is the thinking here.
@mofux @jerch where do you guys stand on this now? Some form of serialization is needed when we want to retain processes across reloads in VS Code (microsoft/vscode#20013). I think it's a fine compromise to only serialize the active single buffer. For serializing terminal modes we could add APIs down the track to do that, for example I don't really see how @JavaCS3 could seek backwards without such a feature. |
@Tyriar Well up to you, I still think that we dont need an addon in the repo base that does not yet add any real value. The PR still feels like a stub to me with much more things to come. The serializing idea is promising, if we could get more relevant data serialized. Thus I was hoping the discussion would go into this direction with API extensions and implementation here. Well we can do that in the future and add real value to this code later on. So again, up to you. |
Ok I've merged this into |
@Tyriar Thanks for your understanding. I almost want to give up. Is there any existing APIs can I use to capture buffers color? |
@JavaCS3 not yet, we just need to agree on the shape of them and add them though. |
Hey, thank you @JavaCS3 for your work on serialization plugin and Xterm.JS's team for addons feature. Fluent already started usage of buffer serialization to allow tabs drag and drop (new xterm.js instance should be created and restored to the state before user started tab drag). |
@Maxris We can progressively improve it! |
how to deserialize? |
@ZedYeung yes deserializing is just writing the serialized result to a new terminal. The idea was to leverage the existing data format and our optimized parser ( |
This PR is refer to #2213
Color and Wrap mode are NOT supported in
serialize
function. Will continue improve.Part of #595