[PR #3271] Add support for all the line feed control sequences #25295

Open
opened 2026-01-31 09:08:35 +00:00 by claunia · 0 comments
Owner

Original Pull Request: https://github.com/microsoft/terminal/pull/3271

State: closed
Merged: Yes


Summary of the Pull Request

This adds support for the FF (form feed) and VT (vertical tab) control characters, as well as the NEL (Next Line) and IND (Index) escape sequences.

References

#976 discusses the conflict between VT100 Index sequence and the VT52 cursor back sequence.

PR Checklist

  • Closes Feature Request: Add a Copy Profile command (#3189)
  • CLA signed. If not, go over here and sign the CLA
  • Tests added/passed
  • Requires documentation to be updated
  • I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #3189

Detailed Description of the Pull Request / Additional comments

I've added a LineFeed method to the ITermDispatch interface, with an enum parameter specifying the required line feed type (i.e. with carriage return, without carriage return, or dependent on the LNM mode). The output state machine can then call that method to handle the various line feed control characters (parsed in the ActionExecute method), as well the NEL and IND escape sequences (parsed in the ActionEscDispatch method).

The AdaptDispatch implementation of LineFeed then forwards the call to a new PrivateLineFeed method in the ConGetSet interface, which simply takes a bool parameter specifying whether a carriage return is required or not. In the case of mode-dependent line feeds, the AdaptDispatch implementation determines whether the return is necessary or not, based on the existing AutoReturnOnNewLine setting (which I'm obtaining via another new PrivateGetLineFeedMode method).

Ultimately we'll want to support changing the mode via the LNM escape sequence, but there's no urgent need for that now. And using the existing AutoReturnOnNewLine setting as a substitute for the mode gives us backwards compatible behaviour, since that will be true for the Windows shells (which expect a linefeed to also generate a carriage return), and false in a WSL bash shell (which won't want the carriage return by default).

As for the actual PrivateLineFeed implementation, that is just a simplified version of how the line feed would previously have been executed in the WriteCharsLegacy function. This includes setting the cursor to "On" (with Cursor::SetIsOn), potentially clearing the wrap property of the line being left (with CharRow::SetWrapForced false), and then setting the new position using AdjustCursorPosition with the fKeepCursorVisible parameter set to false.

I'm unsure whether the SetIsOn call is really necessary, and I think the way the forced wrap is handled needs a rethink in general, but for now this should at least be compatible with the existing behaviour.

Finally, in order to make this all work in the Windows Terminal app, I also had to add a basic implementation of the ITermDispatch::LineFeed method in the TerminalDispatch class. There is currently no need to support mode-specific line feeds here, so this simply forwards a \n or \r\n to the Execute method, which is ultimately handled by the Terminal::_WriteBuffer implementation.

Validation Steps Performed

I've added output engine tests which confirm that the various control characters and escape sequences trigger the dispatch method correctly. Then I've added adapter tests which confirm the various dispatch options trigger the PrivateLineFeed API correctly. And finally I added some screen buffer tests that check the actual results of the NEL and IND sequences, which covers both forms of the PrivateLineFeed API (i.e. with and without a carriage return).

I've also run the Test of cursor movements in the Vttest utility, and confirmed that screens 1, 2, and 5 are now working correctly. The first two depend on NEL and IND being supported, and screen 5 requires the VT control character.

**Original Pull Request:** https://github.com/microsoft/terminal/pull/3271 **State:** closed **Merged:** Yes --- ## Summary of the Pull Request This adds support for the `FF` (form feed) and `VT` (vertical tab) [control characters](https://vt100.net/docs/vt510-rm/chapter4.html#T4-1), as well as the [`NEL` (Next Line)](https://vt100.net/docs/vt510-rm/NEL.html) and [`IND` (Index)](https://vt100.net/docs/vt510-rm/IND.html) escape sequences. ## References #976 discusses the conflict between VT100 Index sequence and the VT52 cursor back sequence. ## PR Checklist * [x] Closes #3189 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #3189 ## Detailed Description of the Pull Request / Additional comments I've added a `LineFeed` method to the `ITermDispatch` interface, with an enum parameter specifying the required line feed type (i.e. with carriage return, without carriage return, or dependent on the [`LNM` mode](https://vt100.net/docs/vt510-rm/LNM.html)). The output state machine can then call that method to handle the various line feed control characters (parsed in the `ActionExecute` method), as well the `NEL` and `IND` escape sequences (parsed in the `ActionEscDispatch` method). The `AdaptDispatch` implementation of `LineFeed` then forwards the call to a new `PrivateLineFeed` method in the `ConGetSet` interface, which simply takes a bool parameter specifying whether a carriage return is required or not. In the case of mode-dependent line feeds, the `AdaptDispatch` implementation determines whether the return is necessary or not, based on the existing _AutoReturnOnNewLine_ setting (which I'm obtaining via another new `PrivateGetLineFeedMode` method). Ultimately we'll want to support changing the mode via the [`LNM` escape sequence](https://vt100.net/docs/vt510-rm/LNM.html), but there's no urgent need for that now. And using the existing _AutoReturnOnNewLine_ setting as a substitute for the mode gives us backwards compatible behaviour, since that will be true for the Windows shells (which expect a linefeed to also generate a carriage return), and false in a WSL bash shell (which won't want the carriage return by default). As for the actual `PrivateLineFeed` implementation, that is just a simplified version of how the line feed would previously have been executed in the `WriteCharsLegacy` function. This includes setting the cursor to "On" (with `Cursor::SetIsOn`), potentially clearing the wrap property of the line being left (with `CharRow::SetWrapForced` false), and then setting the new position using `AdjustCursorPosition` with the _fKeepCursorVisible_ parameter set to false. I'm unsure whether the `SetIsOn` call is really necessary, and I think the way the forced wrap is handled needs a rethink in general, but for now this should at least be compatible with the existing behaviour. Finally, in order to make this all work in the _Windows Terminal_ app, I also had to add a basic implementation of the `ITermDispatch::LineFeed` method in the `TerminalDispatch` class. There is currently no need to support mode-specific line feeds here, so this simply forwards a `\n` or `\r\n` to the `Execute` method, which is ultimately handled by the `Terminal::_WriteBuffer` implementation. ## Validation Steps Performed I've added output engine tests which confirm that the various control characters and escape sequences trigger the dispatch method correctly. Then I've added adapter tests which confirm the various dispatch options trigger the `PrivateLineFeed` API correctly. And finally I added some screen buffer tests that check the actual results of the `NEL` and `IND` sequences, which covers both forms of the `PrivateLineFeed` API (i.e. with and without a carriage return). I've also run the _Test of cursor movements_ in the [Vttest](https://invisible-island.net/vttest/) utility, and confirmed that screens 1, 2, and 5 are now working correctly. The first two depend on `NEL` and `IND` being supported, and screen 5 requires the `VT` control character.
claunia added the pull-request label 2026-01-31 09:08:35 +00:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#25295