Repository: microsoft/terminal (language: cpp)

Issue:
\n with ENABLE_PROCESSED_OUTPUT and without ENABLE_WRAP_AT_EOL_OUTPUT
### Windows Terminal version

1.22.2362

### Windows build number

10.0.19045

### Other Software

_No response_

### Steps to reproduce

Disable ENABLE_WRAP_AT_EOL_OUTPUT, keep ENABLE_PROCESSED_OUTPUT enabled, write to the end of line, then insert \n .  Traditionally the newline would operate as CRLF (processed output semantics) and start at the beginning of the following line.  Note this is Win32 semantics, VT semantics are different; in this sequence, VT support is not enabled.

In WT 1.22.x, this generates VT semantics.  Replacing \n with \r\n works as expected.

```
#include <windows.h>

int main(int argc, char * argv[])
{
    CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
    DWORD consoleWidth;
    DWORD charIndex;
    DWORD lineIndex;
    DWORD charsWritten;
    HANDLE consoleHandle;
    LPSTR buffer;

    consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(consoleHandle, &screenBufferInfo);
    consoleWidth = screenBufferInfo.dwSize.X;

    //
    //  Disable ENABLE_WRAP_AT_EOL_OUTPUT
    //
    SetConsoleMode(consoleHandle, ENABLE_PROCESSED_OUTPUT);
    buffer = malloc(consoleWidth + 1);

    for (lineIndex = 0; lineIndex < 3; lineIndex++) {
        for (charIndex = 0; charIndex < consoleWidth; charIndex++) {
            buffer[charIndex] = '1' + lineIndex;
        }
        WriteConsole(consoleHandle, buffer, consoleWidth, &charsWritten, NULL);
        WriteConsole(consoleHandle, "\n", 1, &charsWritten, NULL);
    }

    return 0;
}
```

### Expected Behavior

Behavior in WT 1.21, as well as Conhost, including OpenConsole from WT 1.22:

![Image](https://github.com/user-attachments/assets/77fcdf2e-5693-4294-965c-08c7f5e3a1f8)

### Actual Behavior

Behavior in WT 1.22:

![Image](https://github.com/user-attachments/assets/296a4a57-0c42-4c7b-bd65-6c165e28eb35)




Discussion / hints:
Whoa, thanks for catching this! Probably an issue in the new (as of 1.22) translation layer for console APIs to VT. :)

Fix patch:
diff --git a/src/host/_stream.cpp b/src/host/_stream.cpp
index 85cadb1cfef..30901515402 100644
--- a/src/host/_stream.cpp
+++ b/src/host/_stream.cpp
@@ -269,17 +269,26 @@ void WriteCharsLegacy(SCREEN_INFORMATION& screenInfo, const std::wstring_view& t
             case UNICODE_LINEFEED:
             {
                 auto pos = cursor.GetPosition();
-                if (WI_IsFlagClear(screenInfo.OutputMode, DISABLE_NEWLINE_AUTO_RETURN) && pos.x != 0)
+
+                // If DISABLE_NEWLINE_AUTO_RETURN is not set, any LF behaves like a CRLF.
+                if (WI_IsFlagClear(screenInfo.OutputMode, DISABLE_NEWLINE_AUTO_RETURN))
                 {
                     pos.x = 0;
-                    // This causes the current \n to be replaced with a \r\n in the ConPTY VT output.
-                    wch = 0;
-                    lastCharWrapped = true;
+
+                    // Setting wch=0 and lastCharWrapped=true will cause the code at the end
+                    // of the loop to emit a CRLF. However, we only do this if the preceding
+                    // character isn't already a CR. We don't want to emit CR CR LF after all.
+                    if (it == beg || it[-1] != '\r')
+                    {
+                        wch = 0;
+                        lastCharWrapped = true;
+                    }
                 }
 
                 textBuffer.GetMutableRowByOffset(pos.y).SetWrapForced(false);
                 pos.y = pos.y + 1;
                 AdjustCursorPosition(screenInfo, pos, psScrollY);
+
                 break;
             }
             case UNICODE_CARRIAGERETURN:


Test patch: