-
Notifications
You must be signed in to change notification settings - Fork 8.4k
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
Feature Request: implement XTPUSHSGR / XTPOPSGR #1796
Comments
Woah, I had no idea those existed. Did those get implemented recently? |
One open question: what to do if parameters are supplied to the XTPUSHSGR sequence? I summarized the command in the Issue; here is the full spec:
I don't think it is necessary to start out implementing support for the parameters, but if parameters are seen, what to do? Throw some sort of error? Or just ignore the entire sequence? I think the latter would be best. But note that to properly ignore it one would actually need to do an "empty" push, so that a subsequent XTPOPSGR sequence will have no effect (and not unbalance the stack). |
@zadjii-msft: yes; first introduced last August in patch #334, with aliases added more recently. |
This sounds great. I agree with the interim compromise of doing the empty push and ignoring the excess parameters we can't handle at that moment. I think it makes sense to get it going in phase 1 then add parameters in phase 2 to make implementation easier. I would just not like to see a long long time go by between the two phases. I think it's better to not support this at all than leave it in a half-baked state for a long time. |
This is not a polished PR that is ready to merge; it demonstrates a direction for which I need to get buy-off from the team before pursuing further. I'm currently working on implementing the XTPUSHSGR/XTPOPSGR control sequences (WIP PR [here](microsoft#1978), which requires saving a [stack of] text attributes, and not just the legacy attributes, but full RGB colors, etc. My first instinct was to implement the "business logic" (the stack) in the `AdaptDispatch` layer, but that will require getting the [full] text attributes from the underlying console API. This is not a *terribly* "invasive" change, but it is exposing new stuff at a layer boundary. Put another way, this means pound-including the "../buffer/out/TextAttribute.hpp" header in a few places outside of "buffer/out", and is that okay, or does that header need to be kept private and isolated? So there are a few ways this could go: 1. You folks might say "ugh, no!", and: 1. I could push (haha) the business logic of pushing and popping text attributes down another layer (so `AdaptDispatch` just forwards on the [PushGraphicsRendition](https://github.com/microsoft/terminal/blob/0af275b9cb68da14f38f05b2cdcbb35da99cb17c/src/terminal/adapter/adaptDispatchGraphics.cpp#L452) call to the lower layer, OR 2. You suggest a different, cleaner way of exposing the text attributes. OR 2. Maybe you think this general direction is fine, but maybe you have some particular requests that I do certain things differently (I totally understand being picky about stuff that cuts across API layers). What do you think? Related: PR microsoft#1978 Related: Issue microsoft#1796
The RawUI's LengthInBufferCells needs to treat VT control sequences as zero-width for the purpose of determining string length. Previously, it only handled SGR (Select Graphics Rendition) sequences (which do things like set fg color, bg color, etc.). I'm currently adding support for some new control sequences in the microsoft/terminal project: XTPUSHSGR and XTPOPSGR. Initial WIP PR [here](microsoft/terminal#1978). Summarized descriptions of XTPUSHSGR and XTPOPSGR from XTerm's [ctlseqs](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html) documentation: ``` CSI # { CSI Ps ; Ps # { Push video attributes onto stack (XTPUSHSGR), xterm. CSI # } Pop video attributes from stack (XTPOPSGR), xterm. Popping restores the video-attributes which were saved using XTPUSHSGR to their previous state. CSI # p CSI Ps ; Ps # p Push video attributes onto stack (XTPUSHSGR), xterm. This is an alias for CSI # {. CSI # q Pop video attributes from stack (XTPOPSGR), xterm. This is an alias for CSI # }. ``` The scenario enabled by these sequences is composability (see [Issue 1796](microsoft/terminal#1796)). I'd like to support these sequences in PowerShell, similarly to SGR sequences, to enable better SGR content composability.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
FYI, there's an ongoing discussion regarding these sequences in the xtermjs issue tracker (xtermjs/xterm.js#2570), and whether they're worth implementing as currently specified. |
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
This change adds a new pair of methods to ITermDispatch: PushGraphicsRendition and PopGraphicsRendition, and then plumbs the change through AdaptDispatch, TerminalDispatch, ITerminalApi and TerminalApi. The stack logic is encapsulated in the SgrStack class, to allow it to be reused between the two APIs (AdaptDispatch and TerminalDispatch). Like xterm, only ten levels of nesting are supported. Pushes beyond ten will remain balanced (an equal number of pops will take you back down to zero), up to 100 pushes. Beyond 100 pushes, pushes will become unbalanced (the internal counter will no longer be incremented). This bound gives the terminal a deterministic way to recover from garbage--do 101 pops and you know you've cleared the stack back down to zero. For partial pushes (see the description of XTPUSHSGR in Issue microsoft#1796), only attributes that are supported by terminal are saved; others are ignored (this change does not including adding general support for double underlines, for example). A partial push of unsupported parameters results in an "empty" push--the subsequent pop will not change the current text attributes.
Hey @jazzdelightsme, how should/does this interact with RIS hard reset? |
Implement the `XTPUSHSGR` and `XTPOPSGR` control sequences (see #1796). This change adds a new pair of methods to `ITermDispatch`: `PushGraphicsRendition` and `PopGraphicsRendition`, and then plumbs the change through `AdaptDispatch`, `TerminalDispatch`, `ITerminalApi` and `TerminalApi`. The stack logic is encapsulated in the `SgrStack` class, to allow it to be reused between the two APIs (`AdaptDispatch` and `TerminalDispatch`). Like xterm, only ten levels of nesting are supported. The stack is implemented as a "ring stack": if you push when the stack is full, the bottom of the stack will be dropped to make room. Partial pushes (see the description of `XTPUSHSGR` in Issue #1796) are implemented per xterm spec. ## Validation Steps Performed Tests added, plus manual verification of the feature. Closes #1796
@DHowett That's the beaty of the ring buffer implementation: nothing special needs to be done to "reset to initial state"; you just decide "okay, we're going to call where we are right now 'the beginning'". (More about this in the comment here.) It's true that if you had done some pushes, and then you executed a RIS, and then you did some pops, it would indeed restore the saved attributes. But I think the point of RIS (and actually I'm not an expert on that; I had to look it up) is that you want to "start over", in which case why would you immediately execute "negative" pops? So I don't think it's necessary to do anything special (like clear out the stack) in response to RIS. Just execute the RIS, and act as if you have 10 fresh, open sgrStack slots ahead of you (because you always do). |
@jazzdelightsme |
🎉This issue was addressed in #1978, which has now been successfully released as Handy links: |
Summary of the new feature/enhancement
I would like to add at least partial support for the control sequences "XTPUSHSGR" and "XTPOPSGR" (as well as their aliases). Summarized from xterm's ctlseqs doc:
XTPUSHSGR
XTPOPSGR
The problem this helps with is composability of content.
Suppose you have code that emits text that contains SGR control sequences to colorize it. You will find that your text is not easily composable--that is, you may have a format string like
"The name is: %s, the position is: %s"
, and then you want tosprintf
some inserts into that. Then that whole string you may want to insert into another, and so forth.The problem is that to have SGR sequences in that one has to have sort of a global awareness of content and associated coloring for that to work out.
With SGR push/pop, though, you can do things like:
And then you can
printf(line1, name, position)
, and have it all work out.Without a push/pop mechanism, composing strings like that cannot be done that way at all, unless you do your own custom rendering pass to handle the pushes and pops.
Xterm supports saving/restoring of individual attributes, but this most essential "composability" scenario only requires saving and restoring them all together, and should be simplest to implement.
Proposed technical implementation details (optional)
The "business logic" of these commands is not too complicated... it's just a stack.
Pull Request
PR is here: #1978
The text was updated successfully, but these errors were encountered: