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

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

📋 Pull Request Information

Original PR: https://github.com/microsoft/terminal/pull/3271
Author: @j4james
Created: 10/21/2019
Status: Merged
Merged: 1/15/2020
Merged by: @undefined

Base: masterHead: feature-linefeed-controls


📝 Commits (10+)

  • 1bde1a5 Add LineFeed method to the ITermDispatch interface that can handle the different linefeed/newline variants required by VT mode.
  • 05158e1 Add support for the NEL escape sequence.
  • 829c59d Add support for LF, FF, and VT control characters.
  • 67152af Add support for the IND escape sequence.
  • 06d6f83 Add output engine tests for the various linefeed operations.
  • ad36c89 Add a private API for executing linefeeds without having to go through the WriteCharsLegacy function.
  • ef087de Use the AutoReturnOnNewline setting as a proxy for the Line Feed/New Line mode.
  • 99c8741 Add a minimal implementation of the LineFeed method in the TerminalDispatch class.
  • 1414198 Add adapter tests for the various linefeed types.
  • b08fd85 Add screen buffer tests for the IND and NEL escape sequences.

📊 Changes

19 files changed (+340 additions, -6 deletions)

View changed files

📝 src/cascadia/TerminalCore/TerminalDispatch.cpp (+21 -0)
📝 src/cascadia/TerminalCore/TerminalDispatch.hpp (+2 -0)
📝 src/host/getset.cpp (+29 -0)
📝 src/host/getset.h (+1 -0)
📝 src/host/outputStream.cpp (+25 -0)
📝 src/host/outputStream.hpp (+2 -0)
📝 src/host/ut_host/ScreenBufferTests.cpp (+89 -0)
📝 src/terminal/adapter/DispatchTypes.hpp (+7 -0)
📝 src/terminal/adapter/ITermDispatch.hpp (+1 -0)
📝 src/terminal/adapter/adaptDispatch.cpp (+22 -0)
📝 src/terminal/adapter/adaptDispatch.hpp (+1 -0)
📝 src/terminal/adapter/conGetSet.hpp (+2 -0)
📝 src/terminal/adapter/termDispatch.hpp (+1 -0)
📝 src/terminal/adapter/ut_adapter/adapterTest.cpp (+47 -0)
📝 src/terminal/parser/OutputStateMachineEngine.cpp (+23 -6)
📝 src/terminal/parser/OutputStateMachineEngine.hpp (+2 -0)
📝 src/terminal/parser/telemetry.cpp (+2 -0)
📝 src/terminal/parser/telemetry.hpp (+2 -0)
📝 src/terminal/parser/ut_parser/OutputEngineTest.cpp (+61 -0)

📄 Description

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.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/microsoft/terminal/pull/3271 **Author:** [@j4james](https://github.com/j4james) **Created:** 10/21/2019 **Status:** ✅ Merged **Merged:** 1/15/2020 **Merged by:** [@undefined](undefined) **Base:** `master` ← **Head:** `feature-linefeed-controls` --- ### 📝 Commits (10+) - [`1bde1a5`](https://github.com/microsoft/terminal/commit/1bde1a51169a6bd26e643061bae23b3ff71a7602) Add LineFeed method to the ITermDispatch interface that can handle the different linefeed/newline variants required by VT mode. - [`05158e1`](https://github.com/microsoft/terminal/commit/05158e1aa3974bcf8dd36107169e99185530ff71) Add support for the NEL escape sequence. - [`829c59d`](https://github.com/microsoft/terminal/commit/829c59dbaba08469ca389f75da8bb47ca8826b2b) Add support for LF, FF, and VT control characters. - [`67152af`](https://github.com/microsoft/terminal/commit/67152affec3e92d47d591d61381f81639594185a) Add support for the IND escape sequence. - [`06d6f83`](https://github.com/microsoft/terminal/commit/06d6f83237f940fb56c289617c51be4cce832cfd) Add output engine tests for the various linefeed operations. - [`ad36c89`](https://github.com/microsoft/terminal/commit/ad36c89460c584e21248d91a46c80d60a0ce7ee4) Add a private API for executing linefeeds without having to go through the WriteCharsLegacy function. - [`ef087de`](https://github.com/microsoft/terminal/commit/ef087de39d8e419931d38b8927ec967867ae63b4) Use the AutoReturnOnNewline setting as a proxy for the Line Feed/New Line mode. - [`99c8741`](https://github.com/microsoft/terminal/commit/99c87415d7d5a148259279aee9ec9f7d23406587) Add a minimal implementation of the LineFeed method in the TerminalDispatch class. - [`1414198`](https://github.com/microsoft/terminal/commit/1414198b078f0b7f8b83ab8581abed58850d0227) Add adapter tests for the various linefeed types. - [`b08fd85`](https://github.com/microsoft/terminal/commit/b08fd85962446e92349afa11f2f6403d32bebf76) Add screen buffer tests for the IND and NEL escape sequences. ### 📊 Changes **19 files changed** (+340 additions, -6 deletions) <details> <summary>View changed files</summary> 📝 `src/cascadia/TerminalCore/TerminalDispatch.cpp` (+21 -0) 📝 `src/cascadia/TerminalCore/TerminalDispatch.hpp` (+2 -0) 📝 `src/host/getset.cpp` (+29 -0) 📝 `src/host/getset.h` (+1 -0) 📝 `src/host/outputStream.cpp` (+25 -0) 📝 `src/host/outputStream.hpp` (+2 -0) 📝 `src/host/ut_host/ScreenBufferTests.cpp` (+89 -0) 📝 `src/terminal/adapter/DispatchTypes.hpp` (+7 -0) 📝 `src/terminal/adapter/ITermDispatch.hpp` (+1 -0) 📝 `src/terminal/adapter/adaptDispatch.cpp` (+22 -0) 📝 `src/terminal/adapter/adaptDispatch.hpp` (+1 -0) 📝 `src/terminal/adapter/conGetSet.hpp` (+2 -0) 📝 `src/terminal/adapter/termDispatch.hpp` (+1 -0) 📝 `src/terminal/adapter/ut_adapter/adapterTest.cpp` (+47 -0) 📝 `src/terminal/parser/OutputStateMachineEngine.cpp` (+23 -6) 📝 `src/terminal/parser/OutputStateMachineEngine.hpp` (+2 -0) 📝 `src/terminal/parser/telemetry.cpp` (+2 -0) 📝 `src/terminal/parser/telemetry.hpp` (+2 -0) 📝 `src/terminal/parser/ut_parser/OutputEngineTest.cpp` (+61 -0) </details> ### 📄 Description ## 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. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
claunia added the pull-request label 2026-01-31 09:08:33 +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#25290