Update our DECSC/DECRC implementation to match the latest DEC algorithm #19588

Closed
opened 2026-01-31 06:48:07 +00:00 by claunia · 3 comments
Owner

Originally created by @j4james on GitHub (Mar 26, 2023).

Description of the new feature/enhancement

When origin mode (DECOM) is enabled, the cursor is supposed to be constrained within the boundaries of the scrolling margins (DECSTBM). But consider what happens when you save the cursor position (with DECSC), and then update the margins so that saved position would now be out of bounds.

For example, say the top margin is row 1, the cursor position is row 5. After saving the cursor position, we then update the top margin to row 10. On what row would you expect the cursor to restore?

On the early DEC terminals, the cursor would be restored to its original position (row 5), which is now 5 rows above the top margin. This is not a legal position when origin mode is enabled, and if you requested the coordinates with a DSR-CPR query, you'd get a nonsense result with random characters representing the negative coordinates.

Up to now we've avoided this bug by clamping the coordinates within the margin boundaries, but the way DEC ultimately addressed the issue was by using relative coordinates. So in the example above, the start row of 5 is offset 4 from the top margin, and thus the restored row becomes 14 (offset 4 from the new margin of 10).

So I would like to propose we update our implementation to match this later DEC algorithm, since that seems to be the most correct. You can see a demonstration of how this was handled on a range of different DEC terminals in issue https://github.com/microsoft/terminal/issues/14876#issuecomment-1459325217.

Proposed technical implementation details (optional)

This would actually be somewhat simpler than our current implementation. There's an extra step when saving the cursor to subtract the offset of the top margin (assuming the origin mode is set). But then when restoring the cursor, we can just pass the coordinates straight to the CursorPosition method without any additional adjustments (which are required in the current implementation).

Originally created by @j4james on GitHub (Mar 26, 2023). # Description of the new feature/enhancement When origin mode (`DECOM`) is enabled, the cursor is supposed to be constrained within the boundaries of the scrolling margins (`DECSTBM`). But consider what happens when you save the cursor position (with `DECSC`), and then update the margins so that saved position would now be out of bounds. For example, say the top margin is row 1, the cursor position is row 5. After saving the cursor position, we then update the top margin to row 10. On what row would you expect the cursor to restore? On the early DEC terminals, the cursor would be restored to its original position (row 5), which is now 5 rows above the top margin. This is not a legal position when origin mode is enabled, and if you requested the coordinates with a `DSR-CPR` query, you'd get a nonsense result with random characters representing the negative coordinates. Up to now we've avoided this bug by clamping the coordinates within the margin boundaries, but the way DEC ultimately addressed the issue was by using relative coordinates. So in the example above, the start row of 5 is offset 4 from the top margin, and thus the restored row becomes 14 (offset 4 from the new margin of 10). So I would like to propose we update our implementation to match this later DEC algorithm, since that seems to be the most correct. You can see a demonstration of how this was handled on a range of different DEC terminals in issue https://github.com/microsoft/terminal/issues/14876#issuecomment-1459325217. # Proposed technical implementation details (optional) This would actually be somewhat simpler than our current implementation. There's an extra step when saving the cursor to subtract the offset of the top margin (assuming the origin mode is set). But then when restoring the cursor, we can just pass the coordinates straight to the `CursorPosition` method without any additional adjustments (which are required in the current implementation).
claunia added the Product-ConhostIssue-BugIssue-TaskIn-PRArea-VTNeeds-Tag-Fix labels 2026-01-31 06:48:07 +00:00
Author
Owner

@DHowett commented on GitHub (Mar 27, 2023):

Sounds good to me! Are there any compatibility concerns?

@DHowett commented on GitHub (Mar 27, 2023): Sounds good to me! Are there any compatibility concerns?
Author
Owner

@j4james commented on GitHub (Mar 27, 2023):

I've done a bit of testing to see how other terminals handle this, and so far I've discovered 16 different approaches! That's out of 35 terminals.

To be fair, though, most of that variation is in how they handle the case where the restored cursor position is out of range. If it is in range, they mostly match the original DEC algorithm (i.e. using absolute coordinates). But there are a couple that are closer to the newer DEC algorithm, and also some that don't match any known terminal (I'm assuming a bug and not intentional).

Given those results, I think it's unlikely anyone is relying on a particular behavior here. And changing margins between saving and restoring the cursor is probably not a typical use case. But there's still a non-zero chance that this could be a breaking change for someone. I'd personally be willing to take that risk, but I can understand if you'd prefer to leave it as it is. This is not an essential change.

@j4james commented on GitHub (Mar 27, 2023): I've done a bit of testing to see how other terminals handle this, and so far I've discovered 16 different approaches! That's out of 35 terminals. To be fair, though, most of that variation is in how they handle the case where the restored cursor position is out of range. If it _is_ in range, they mostly match the original DEC algorithm (i.e. using absolute coordinates). But there are a couple that are closer to the newer DEC algorithm, and also some that don't match any known terminal (I'm assuming a bug and not intentional). Given those results, I think it's unlikely anyone is relying on a particular behavior here. And changing margins between saving and restoring the cursor is probably not a typical use case. But there's still a non-zero chance that this could be a breaking change for someone. I'd personally be willing to take that risk, but I can understand if you'd prefer to leave it as it is. This is not an essential change.
Author
Owner

@DHowett commented on GitHub (Mar 27, 2023):

I'm willing to take the risk too, with that justification. Thanks!

@DHowett commented on GitHub (Mar 27, 2023): I'm willing to take the risk too, with that justification. Thanks!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#19588