Prevent the horizontal tab character wrapping at the end of a line #3197
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary of the Pull Request
When a horizontal tab ('\t') is output on the last column of the screen, the current implementation moves the cursor position to the start of the next line. However, the DEC STD 070 manual specifies that a horizontal tab shouldn't move past the last column of the active line (or the right margin, if we supported horizontal margins). This PR updates the forward tab implementation, to prevent it wrapping onto a new line when it reaches the end of a line.
PR Checklist
Detailed Description of the Pull Request / Additional comments
Originally the
SCREEN_INFORMATION::GetForwardTab
method had a condition which handled a tab at the end of the line as a special case, moving the cursor to the start of the next line. I've simply removed that condition, so an end-of-line tab is handled the same way as any other position (in this case it will just leaves the cursor where it is).While testing, though, I found that there were circumstances where you could have tab stops greater than the width of the screen, and when that happens, a tab can still end up wrapping onto the next line. To fix that I had to add an additional check to make sure the tab position was always clamped to the width of the buffer.
With these fixes in place, a tab control should now never move off the active line, so I realised that the
DoPrivateTabHelper
function could be optimized to calculate all of the tab movements in advance, and then only make a single call toAdjustCursorPosition
with the final coordinates. This change is not strictly necessary, though, so it can easily be reverted if there are any objections.Regarding backwards compatibility, note that the
GetForwardTab
method is only used in two places:WriteCharsLegacy
function, but this only applies in VT mode (see here).CHT
escape sequence in theDoPrivateTabHelper
function, and obviously an escape sequence would also only be applicable in VT mode.So this change should have no effect on legacy console applications, which wouldn't have VT mode activated.
Validation Steps Performed
I've added another step to the
TestGetForwardTab
test which makes sure that a horizontal tab won't wrap at the end of a line.I've also confirmed that this fixes the last remaining issue in the Test of autowrap in Vttest (pages 3 and 4 of the Test of cursor movements). Although I should note that this only works in conhost.