Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/non-te…
Browse files Browse the repository at this point in the history
…rminal-panes-2023
  • Loading branch information
zadjii-msft committed Nov 8, 2023
2 parents 4cec7e9 + 077d63e commit f622d80
Show file tree
Hide file tree
Showing 32 changed files with 178 additions and 966 deletions.
1 change: 0 additions & 1 deletion .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1590,7 +1590,6 @@ RIGHTALIGN
RIGHTBUTTON
riid
Rike
RIPMSG
RIS
roadmap
robomac
Expand Down
90 changes: 90 additions & 0 deletions doc/COOKED_READ_DATA.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# COOKED_READ_DATA, aka conhost's readline implementation

## Test instructions

All of the following ✅ marks must be fulfilled during manual testing:
* ASCII input
* Chinese input (中文維基百科) ❔
* Resizing the window properly wraps/unwraps wide glyphs ❌
Broken due to `TextBuffer::Reflow` bugs
* Surrogate pair input (🙂) ❔
* Resizing the window properly wraps/unwraps surrogate pairs ❌
Broken due to `TextBuffer::Reflow` bugs
* In cmd.exe
* Create 2 file: "a😊b.txt" and "a😟b.txt"
* Press tab: Autocomplete to "a😊b.txt" ✅
* Navigate the cursor right past the "a"
* Press tab twice: Autocomplete to "a😟b.txt" ✅
* Backspace deletes preceding glyphs ✅
* Ctrl+Backspace deletes preceding words ✅
* Escape clears input ✅
* Home navigates to start ✅
* Ctrl+Home deletes text between cursor and start ✅
* End navigates to end ✅
* Ctrl+End deletes text between cursor and end ✅
* Left navigates over previous code points ✅
* Ctrl+Left navigates to previous word-starts ✅
* Right and F1 navigate over next code points ✅
* Pressing right at the end of input copies characters
from the previous command ✅
* Ctrl+Right navigates to next word-ends ✅
* Insert toggles overwrite mode ✅
* Delete deletes next code point ✅
* Up and F5 cycle through history ✅
* Doesn't crash with no history ✅
* Stops at first entry ✅
* Down cycles through history ✅
* Doesn't crash with no history ✅
* Stops at last entry ✅
* PageUp retrieves the oldest command ✅
* PageDown retrieves the newest command ✅
* F2 starts "copy to char" prompt ✅
* Escape dismisses prompt ✅
* Typing a character copies text from the previous command up
until that character into the current buffer (acts identical
to F3, but with automatic character search) ✅
* F3 copies the previous command into the current buffer,
starting at the current cursor position,
for as many characters as possible ✅
* Doesn't erase trailing text if the current buffer
is longer than the previous command ✅
* Puts the cursor at the end of the copied text ✅
* F4 starts "copy from char" prompt ✅
* Escape dismisses prompt ✅
* Erases text between the current cursor position and the
first instance of a given char (but not including it) ✅
* F6 inserts Ctrl+Z ✅
* F7 without modifiers starts "command list" prompt ✅
* Escape dismisses prompt ✅
* Minimum size of 40x10 characters ✅
* Width expands to fit the widest history command ✅
* Height expands up to 20 rows with longer histories ✅
* F9 starts "command number" prompt ✅
* Left/Right paste replace the buffer with the given command ✅
* And put cursor at the end of the buffer ✅
* Up/Down navigate selection through history ✅
* Stops at start/end with <10 entries ✅
* Stops at start/end with >20 entries ✅
* Wide text rendering during pagination with >20 entries ✅
* Shift+Up/Down moves history items around ✅
* Home navigates to first entry ✅
* End navigates to last entry ✅
* PageUp navigates by 20 items at a time or to first ✅
* PageDown navigates by 20 items at a time or to last ✅
* Alt+F7 clears command history ✅
* F8 cycles through commands that start with the same text as
the current buffer up until the current cursor position ✅
* Doesn't crash with no history ✅
* F9 starts "command number" prompt ✅
* Escape dismisses prompt ✅
* Ignores non-ASCII-decimal characters ✅
* Allows entering between 1 and 5 digits ✅
* Pressing Enter fetches the given command from the history ✅
* Alt+F10 clears doskey aliases ✅
* In cmd.exe, with an empty prompt in an empty directory:
Pressing tab produces an audible bing and prints no text ✅
* When Narrator is enabled, in cmd.exe:
* Typing individual characters announces only
exactly each character that is being typed ✅
* Backspacing at the end of a prompt announces
only exactly each deleted character ✅
4 changes: 3 additions & 1 deletion src/cascadia/CascadiaPackage/Package-Can.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
xmlns:uap17="http://schemas.microsoft.com/appx/manifest/uap/windows10/17"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
IgnorableNamespaces="uap mp rescap uap3 uap17 desktop6 virtualization">

<Identity
Name="Microsoft.WindowsTerminalCanary"
Expand All @@ -33,6 +34,7 @@
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
</virtualization:ExcludedKeys>
</virtualization:RegistryWriteVirtualization>
<uap17:UpdateWhileInUse>defer</uap17:UpdateWhileInUse>
</Properties>

<Dependencies>
Expand Down
4 changes: 3 additions & 1 deletion src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
xmlns:uap17="http://schemas.microsoft.com/appx/manifest/uap/windows10/17"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
IgnorableNamespaces="uap mp rescap uap3 uap17 desktop6 virtualization">

<Identity
Name="WindowsTerminalDev"
Expand All @@ -33,6 +34,7 @@
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
</virtualization:ExcludedKeys>
</virtualization:RegistryWriteVirtualization>
<uap17:UpdateWhileInUse>defer</uap17:UpdateWhileInUse>
</Properties>

<Dependencies>
Expand Down
4 changes: 3 additions & 1 deletion src/cascadia/CascadiaPackage/Package-Pre.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
xmlns:uap7="http://schemas.microsoft.com/appx/manifest/uap/windows10/7"
xmlns:uap17="http://schemas.microsoft.com/appx/manifest/uap/windows10/17"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
IgnorableNamespaces="uap mp rescap uap3 uap17 desktop6 virtualization">

<Identity
Name="Microsoft.WindowsTerminalPreview"
Expand All @@ -34,6 +35,7 @@
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
</virtualization:ExcludedKeys>
</virtualization:RegistryWriteVirtualization>
<uap17:UpdateWhileInUse>defer</uap17:UpdateWhileInUse>
</Properties>

<Dependencies>
Expand Down
4 changes: 3 additions & 1 deletion src/cascadia/CascadiaPackage/Package.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
xmlns:uap7="http://schemas.microsoft.com/appx/manifest/uap/windows10/7"
xmlns:uap17="http://schemas.microsoft.com/appx/manifest/uap/windows10/17"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:virtualization="http://schemas.microsoft.com/appx/manifest/virtualization/windows10"
IgnorableNamespaces="uap mp rescap uap3 desktop6 virtualization">
IgnorableNamespaces="uap mp rescap uap3 uap17 desktop6 virtualization">

<Identity
Name="Microsoft.WindowsTerminal"
Expand All @@ -34,6 +35,7 @@
<virtualization:ExcludedKey>HKEY_CURRENT_USER\Console\%%Startup</virtualization:ExcludedKey>
</virtualization:ExcludedKeys>
</virtualization:RegistryWriteVirtualization>
<uap17:UpdateWhileInUse>defer</uap17:UpdateWhileInUse>
</Properties>

<Dependencies>
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalSettingsModel/defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@
"foreground": "#383A42",
"background": "#FAFAFA",
"cursorColor": "#4F525D",
"selectionBackground": "#4F525D",
"black": "#383A42",
"red": "#E45649",
"green": "#50A14F",
Expand Down Expand Up @@ -218,6 +219,7 @@
"foreground": "#657B83",
"background": "#FDF6E3",
"cursorColor": "#002B36",
"selectionBackground": "#073642",
"black": "#002B36",
"red": "#DC322F",
"green": "#859900",
Expand Down Expand Up @@ -262,6 +264,7 @@
"foreground": "#555753",
"background": "#FFFFFF",
"cursorColor": "#000000",
"selectionBackground": "#555753",
"black": "#000000",
"red": "#CC0000",
"green": "#4E9A06",
Expand Down
8 changes: 5 additions & 3 deletions src/cascadia/WindowsTerminal/AppHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,8 @@ winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> AppHost::_GetWindowL
co_await wil::resume_foreground(_windowLogic.GetRoot().Dispatcher());

const auto strongThis = weakThis.lock();
if (!strongThis)
// GH #16235: If we don't have a window logic, we're already refrigerating, and won't have our _window either.
if (!strongThis || _windowLogic == nullptr)
{
co_return layoutJson;
}
Expand Down Expand Up @@ -1267,7 +1268,8 @@ winrt::fire_and_forget AppHost::_QuitRequested(const winrt::Windows::Foundation:
co_await wil::resume_foreground(_windowLogic.GetRoot().Dispatcher());

const auto strongThis = weakThis.lock();
if (!strongThis)
// GH #16235: If we don't have a window logic, we're already refrigerating, and won't have our _window either.
if (!strongThis || _windowLogic == nullptr)
{
co_return;
}
Expand Down Expand Up @@ -1431,7 +1433,7 @@ winrt::fire_and_forget AppHost::_WindowInitializedHandler(const winrt::Windows::

// If we're gone on the other side of this co_await, well, that's fine. Just bail.
const auto strongThis = weakThis.lock();
if (!strongThis)
if (!strongThis || _window == nullptr)
{
co_return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/host/consoleInformation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ ULONG CONSOLE_INFORMATION::GetCSRecursionCount() const noexcept
return STATUS_SUCCESS;
}

RIPMSG1(RIP_WARNING, "Console init failed with status 0x%x", Status);
LOG_NTSTATUS_MSG(Status, "Console init failed");

delete gci.ScreenBuffers;
gci.ScreenBuffers = nullptr;
Expand Down
1 change: 0 additions & 1 deletion src/host/directio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,6 @@ CATCH_RETURN();
_In_ PCD_CREATE_OBJECT_INFORMATION Information,
_In_ PCONSOLE_CREATESCREENBUFFER_MSG a)
{
Telemetry::Instance().LogApiCall(Telemetry::ApiCall::CreateConsoleScreenBuffer);
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();

// If any buffer type except the one we support is set, it's invalid.
Expand Down
1 change: 1 addition & 0 deletions src/host/exe/exemain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ int CALLBACK wWinMain(
_In_ PWSTR /*pwszCmdLine*/,
_In_ int /*nCmdShow*/)
{
wil::SetResultLoggingCallback(&Tracing::TraceFailure);
Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().hInstance = hInstance;

ConsoleCheckDebug();
Expand Down
1 change: 0 additions & 1 deletion src/host/getset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ void ApiRoutines::GetConsoleInputModeImpl(InputBuffer& context, ULONG& mode) noe
{
try
{
Telemetry::Instance().LogApiCall(Telemetry::ApiCall::GetConsoleMode);
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
Expand Down
2 changes: 1 addition & 1 deletion src/host/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void InitSideBySide()
// OpenConsole anyways, nothing happens and we get ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET.
if (ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET != error)
{
RIPMSG1(RIP_WARNING, "InitSideBySide failed create an activation context. Error: %d\r\n", error);
LOG_WIN32_MSG(error, "InitSideBySide failed create an activation context.");
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/host/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ void HandleMenuEvent(const DWORD wParam)
EventsWritten = gci.pInputBuffer->Write(SynthesizeMenuEvent(wParam));
if (EventsWritten != 1)
{
RIPMSG0(RIP_WARNING, "PutInputInBuffer: EventsWritten != 1, 1 expected");
LOG_HR_MSG(E_FAIL, "PutInputInBuffer: EventsWritten != 1, 1 expected");
}
}
catch (...)
Expand All @@ -230,7 +230,7 @@ void HandleCtrlEvent(const DWORD EventType)
gci.CtrlFlags |= CONSOLE_CTRL_CLOSE_FLAG;
break;
default:
RIPMSG1(RIP_ERROR, "Invalid EventType: 0x%x", EventType);
LOG_HR_MSG(E_INVALIDARG, "Invalid EventType: 0x%x", EventType);
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/host/readDataCooked.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,14 +436,17 @@ void COOKED_READ_DATA::_handleChar(wchar_t wch, const DWORD modifiers)

if (_ctrlWakeupMask != 0 && wch < L' ' && (_ctrlWakeupMask & (1 << wch)))
{
_flushBuffer();

// The old implementation (all the way since the 90s) overwrote the character at the current cursor position with the given wch.
// But simultaneously it incremented the buffer length, which would have only worked if it was written at the end of the buffer.
// Press tab past the "f" in the string "foo" and you'd get "f\to " (a trailing whitespace; the initial contents of the buffer back then).
// It's unclear whether the original intention was to write at the end of the buffer at all times or to implement an insert mode.
// I went with insert mode.
//
// It is important that we don't actually print that character out though, as it's only for the calling application to see.
// That's why we flush the contents before the insertion and then ensure that the _flushBuffer() call in Read() exits early.
_flushBuffer();
_buffer.Replace(_buffer.GetCursorPosition(), 0, &wch, 1);
_buffer.MarkAsClean();

_controlKeyState = modifiers;
_transitionState(State::DoneWithWakeupMask);
Expand Down
2 changes: 1 addition & 1 deletion src/host/screenInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1391,7 +1391,7 @@ try
{
if ((USHORT)coordNewScreenSize.width >= SHORT_MAX || (USHORT)coordNewScreenSize.height >= SHORT_MAX)
{
RIPMSG2(RIP_WARNING, "Invalid screen buffer size (0x%x, 0x%x)", coordNewScreenSize.width, coordNewScreenSize.height);
LOG_HR_MSG(E_INVALIDARG, "Invalid screen buffer size (0x%x, 0x%x)", coordNewScreenSize.width, coordNewScreenSize.height);
return STATUS_INVALID_PARAMETER;
}

Expand Down
6 changes: 0 additions & 6 deletions src/host/selectionInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ Selection::KeySelectionEventResult Selection::HandleKeySelectionEvent(const INPU
// C-c, C-Ins. C-S-c Is also handled by this case.
((ctrlPressed) && (wVirtualKeyCode == 'C' || wVirtualKeyCode == VK_INSERT)))
{
Telemetry::Instance().SetKeyboardTextEditingUsed();

// copy selection
return Selection::KeySelectionEventResult::CopyToClipboard;
}
Expand Down Expand Up @@ -291,8 +289,6 @@ bool Selection::HandleKeyboardLineSelectionEvent(const INPUT_KEY_INFO* const pIn
return false;
}

Telemetry::Instance().SetKeyboardTextSelectionUsed();

// if we're not currently selecting anything, start a new mouse selection
if (!IsInSelectingState())
{
Expand Down Expand Up @@ -704,8 +700,6 @@ bool Selection::_HandleColorSelection(const INPUT_KEY_INFO* const pInputKeyInfo)
// Clear the selection and call the search / mark function.
ClearSelection();

Telemetry::Instance().LogColorSelectionUsed();

const auto& textBuffer = gci.renderData.GetTextBuffer();
const auto hits = textBuffer.SearchText(str, true);
for (const auto& s : hits)
Expand Down
9 changes: 1 addition & 8 deletions src/host/srvinit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,11 +428,6 @@ HRESULT ConsoleCreateIoThread(_In_ HANDLE Server,
[[maybe_unused]] PCONSOLE_API_MSG connectMessage)
try
{
// Create a telemetry instance here - this singleton is responsible for
// setting up the g_hConhostV2EventTraceProvider, which is otherwise not
// initialized in the defterm handoff at this point.
(void)Telemetry::Instance();

#if !TIL_FEATURE_RECEIVEINCOMINGHANDOFF_ENABLED
TraceLoggingWrite(g_hConhostV2EventTraceProvider,
"SrvInit_ReceiveHandoff_Disabled",
Expand Down Expand Up @@ -865,8 +860,6 @@ PWSTR TranslateConsoleTitle(_In_ PCWSTR pwszConsoleTitle, const BOOL fUnexpand,
[[nodiscard]] NTSTATUS ConsoleAllocateConsole(PCONSOLE_API_CONNECTINFO p)
{
// AllocConsole is outside our codebase, but we should be able to mostly track the call here.
Telemetry::Instance().LogApiCall(Telemetry::ApiCall::AllocConsole);

auto& g = ServiceLocator::LocateGlobals();

auto& gci = g.getConsoleInformation();
Expand Down Expand Up @@ -1050,7 +1043,7 @@ DWORD WINAPI ConsoleIoThread(LPVOID lpParameter)
// This will not return. Terminate immediately when disconnected.
ServiceLocator::RundownAndExit(STATUS_SUCCESS);
}
RIPMSG1(RIP_WARNING, "DeviceIoControl failed with Result 0x%x", hr);
LOG_HR_MSG(hr, "DeviceIoControl failed");
ReplyMsg = nullptr;
continue;
}
Expand Down
Loading

0 comments on commit f622d80

Please sign in to comment.