terminal: Automatically triggered Replace mode using vim in OpenSSH on cmd / powershell though Windows Terminal

Replace input mode will triggered automatically when using vim though OpenSSH Client in cmd.

Environment

Windows build number: [Version 10.0.18362.175]
Windows Terminal version (if applicable): 0.2.1715.0

Remote Linux PC: Ubuntu LTS 1604

OpenSSH Client: Stock version in Windows 10 1903 Build 18362.175

Steps to reproduce

  1. Open Windows Terminal
  2. Open new tab running cmd / powershell / powershell 6
  3. ssh to a Ubuntu 1604 LTS PC
  4. Open any document using vim

Expected behavior

Not trigger any input mode, the status bar at the bottom displays the path of the file that vim opened.

Actual behavior

Triggered Replace input mode.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 42 (17 by maintainers)

Commits related to this issue

Most upvoted comments

Seems to be an issue with utf-8 ambiguous characters and Windows cmd console. Flag t_u7 is set by default and so vim will request cursor position and get a bad reply from the ssh client.

Workaround: Adding set t_u7= or set ambw=double to your vimrc should fix the problem. set t_u7= will disable requesting cursor position and ambw=double will set the ambiguous characters mode to double.

For more info see vim reference manual: https://vimhelp.org/term.txt.html

Credits: https://superuser.com/a/1525060

set ambw=double appears to have conflict with airline/powerline characters. I see extra spaces after the <| arrows. set t_u7= works though! – David Woods Jul 9 at 17:12

Okay, here’s what’s happening.

When we receive a DSR(CPR), the console host attempts to prepend the CPR to the input buffer here:

https://github.com/microsoft/terminal/blob/230b86c9905e0f91f07741664b0814cf43c3a483/src/terminal/adapter/adaptDispatch.cpp#L818-L819

https://github.com/microsoft/terminal/blob/230b86c9905e0f91f07741664b0814cf43c3a483/src/terminal/adapter/adaptDispatch.cpp#L857-L859

Because of the design of the input queue and how it has to remain compatible with ReadConsoleInput, the CPR is transformed into a series of KEY_EVENT_RECORDs – one down and one up each for the entire sequence. Just like a user had pressed each of those keys.

Now, this poses a problem for two CPRs being received back-to-back: the second CPR will cause the later position to be prepended to the input queue before the earlier position.

If an application has read input between the two CPRs – even a single keypress, it will certainly encounter this issue.

In my testing, I saw that the input queue at the time of the second prepend contained…

ESC up
[ DOWN
[ UP
2 DOWN
2 UP
...

indicating that only the first keypress (esc down) had been read and popped out of the queue.

The resultant sequence was…

^[ ^[  [  [  3  3  ;  ;  3  3  R  R ^[  [  [  2  2  ;  ;  2  2  R  R
DN UP DN UP DN UP DN UP DN UP DN UP UP DN UP DN UP DN UP DN UP DN UP
                                    ^^ frame-shifted start of prior event

Because VT input events are usually read on the keydown event, the first ESC has already been totally spooled into the application.

I’ll need to wait for my team to be back from vacation/leave to figure out why we went with a prepend, as that decision predates me. 😄

Reader’s notes:

Prepend seems like it was an intentional choice – we do it in a number of places (every DSR, DA, DA2, DA3, VT52 Identify, DSR-OS, CPR) – but I do not believe that it is ever correct.

It was introduced on 2017-10-17 in a pull request (!997738) that introduced support for window manipulation sequences over the pty, which we’ve never documented and quickly replaced with the signal channel. (This will be of particular interest to the folks having the purity discussion about sending an ED down the input handle 😁).

commit [REDACTED]
Author: @zadjii-msft
Date:   Thu Oct 12 13:03:30 2017 -0700

    We need seperate Append and Perpend WriteInputs

      The InteractDispatch wants to append to the buffer,
      but the adapter needs to prepend to the buffer.

      Tests still don't build.

This comment suggests that we had to add a separate prepend so that InteractDispatch could append. Because this pull request mainly dealt with InteractDispatch, the implication is that the “adapter” was already prepending and we needed to add Prepend…Buffer to disentangle the prepending behavior that “adapter” was using.

However, the code change is fairly obvious in the “adapter”. It explicitly goes from appending to prepending with this diff:

diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp
index xxxxxxxxx..yyyyyyyyy 100644
--- a/src/terminal/adapter/adaptDispatch.cpp
+++ b/src/terminal/adapter/adaptDispatch.cpp
@@ -932,7 +932,7 @@ bool AdaptDispatch::_WriteResponse(_In_reads_(cReply) PCWSTR pwszReply, _In_ siz
     if (cInputBuffer > 0)
     {
         DWORD dwWritten = 0;
-        fSuccess = !!_pConApi->WriteConsoleInputW(rgInput, (DWORD)cInputBuffer, &dwWritten);
+        fSuccess = !!_pConApi->PrivatePrependConsoleInput(rgInput, (DWORD)cInputBuffer, &dwWritten);
     }

Mike’s on paternity leave (yay!), so I can’t exactly ask 😄

Also having this bug with Windows Terminal since I updated to Version: 1.2.2381.0 on win10

(sorry, I flippantly gave you the preview link anyway ;P)

Just surprised this issue has reopened after a year ago. Since was told it was an issue in Win32-OpenSSH, then just ignored this issue when it happens. Hum.

Ah, Labor Day, that makes it. It must be a sound and good break without labor~~

Suppose God the savior himself take a same holiday, people across the world would get nobody to pray to. You guys are Savior to the WT-addicted die-hard fans. Hope God’s got no holidays and wish you be blessed Thor’s hammer 🔨 and hammer it hard 😁

As reported at https://github.com/vim/vim/issues/6365#issuecomment-652583382, conhost seems to return a broken response to two running CPR (cursor position report) requests.

executed command

$ echo -ne "\e[2J\e[2;2H\e[6n\e[3;3H"; echo -ne "\e[6n"; hd

expected result

  ^[[2;2R^[[3;3R
00000000  1b 5b 32 3b 32 52 1b 5b  33 3b 33 52 0a           |.[2;2R.[3;3R.|
0000000d

actual result

  ^[^[[3;3R[2;2R
00000000  1b 1b 5b 33 3b 33 52 5b  32 3b 32 52 0a           |..[3;3R[2;2R.|
0000000d