2019-05-03 00:29:04 +02:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "Terminal.hpp"
|
|
|
|
#include "../../terminal/parser/OutputStateMachineEngine.hpp"
|
|
|
|
#include "TerminalDispatch.hpp"
|
|
|
|
#include "../../inc/unicode.hpp"
|
|
|
|
#include "../../inc/DefaultSettings.h"
|
|
|
|
#include "../../inc/argb.h"
|
|
|
|
#include "../../types/inc/utils.hpp"
|
|
|
|
|
|
|
|
#include "winrt/Microsoft.Terminal.Settings.h"
|
|
|
|
|
|
|
|
using namespace winrt::Microsoft::Terminal::Settings;
|
|
|
|
using namespace Microsoft::Terminal::Core;
|
2019-06-05 01:31:36 +02:00
|
|
|
using namespace Microsoft::Console;
|
2019-05-03 00:29:04 +02:00
|
|
|
using namespace Microsoft::Console::Render;
|
|
|
|
using namespace Microsoft::Console::Types;
|
|
|
|
using namespace Microsoft::Console::VirtualTerminal;
|
|
|
|
|
2019-05-18 05:57:34 +02:00
|
|
|
static std::wstring _KeyEventsToText(std::deque<std::unique_ptr<IInputEvent>>& inEventsToWrite)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
std::wstring wstr = L"";
|
2020-01-03 19:44:27 +01:00
|
|
|
for (const auto& ev : inEventsToWrite)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
if (ev->EventType() == InputEventType::KeyEvent)
|
|
|
|
{
|
2020-01-03 19:44:27 +01:00
|
|
|
const auto& k = static_cast<KeyEvent&>(*ev);
|
|
|
|
const auto wch = k.GetCharData();
|
2019-05-03 00:29:04 +02:00
|
|
|
wstr += wch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return wstr;
|
|
|
|
}
|
|
|
|
|
2020-01-03 19:44:27 +01:00
|
|
|
#pragma warning(suppress : 26455) // default constructor is throwing, too much effort to rearrange at this time.
|
2019-05-03 00:29:04 +02:00
|
|
|
Terminal::Terminal() :
|
2019-06-11 22:27:09 +02:00
|
|
|
_mutableViewport{ Viewport::Empty() },
|
2020-01-03 19:44:27 +01:00
|
|
|
_title{},
|
2019-05-03 00:29:04 +02:00
|
|
|
_colorTable{},
|
|
|
|
_defaultFg{ RGB(255, 255, 255) },
|
|
|
|
_defaultBg{ ARGB(0, 0, 0, 0) },
|
2020-07-09 13:25:30 +02:00
|
|
|
_screenReversed{ false },
|
2019-05-03 00:29:04 +02:00
|
|
|
_pfnWriteInput{ nullptr },
|
|
|
|
_scrollOffset{ 0 },
|
|
|
|
_snapOnInput{ true },
|
2020-06-19 00:09:45 +02:00
|
|
|
_altGrAliasing{ true },
|
2020-02-28 01:42:26 +01:00
|
|
|
_blockSelection{ false },
|
2020-03-25 22:09:49 +01:00
|
|
|
_selection{ std::nullopt }
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2019-12-19 23:12:53 +01:00
|
|
|
auto dispatch = std::make_unique<TerminalDispatch>(*this);
|
|
|
|
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
|
|
|
|
|
|
|
|
_stateMachine = std::make_unique<StateMachine>(std::move(engine));
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-06-11 22:27:09 +02:00
|
|
|
auto passAlongInput = [&](std::deque<std::unique_ptr<IInputEvent>>& inEventsToWrite) {
|
|
|
|
if (!_pfnWriteInput)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2019-05-03 00:29:04 +02:00
|
|
|
std::wstring wstr = _KeyEventsToText(inEventsToWrite);
|
|
|
|
_pfnWriteInput(wstr);
|
|
|
|
};
|
|
|
|
|
|
|
|
_terminalInput = std::make_unique<TerminalInput>(passAlongInput);
|
|
|
|
|
|
|
|
_InitializeColorTable();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Terminal::Create(COORD viewportSize, SHORT scrollbackLines, IRenderTarget& renderTarget)
|
|
|
|
{
|
2019-06-11 22:27:09 +02:00
|
|
|
_mutableViewport = Viewport::FromDimensions({ 0, 0 }, viewportSize);
|
2019-05-03 00:29:04 +02:00
|
|
|
_scrollbackLines = scrollbackLines;
|
2019-06-11 22:27:09 +02:00
|
|
|
const COORD bufferSize{ viewportSize.X,
|
|
|
|
Utils::ClampToShortMax(viewportSize.Y + scrollbackLines, 1) };
|
2019-05-18 05:57:34 +02:00
|
|
|
const TextAttribute attr{};
|
|
|
|
const UINT cursorSize = 12;
|
2019-05-03 00:29:04 +02:00
|
|
|
_buffer = std::make_unique<TextBuffer>(bufferSize, attr, cursorSize, renderTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
2019-05-28 18:53:03 +02:00
|
|
|
// - Initializes the Terminal from the given set of settings.
|
2019-05-03 00:29:04 +02:00
|
|
|
// Arguments:
|
|
|
|
// - settings: the set of CoreSettings we need to use to initialize the terminal
|
|
|
|
// - renderTarget: A render target the terminal can use for paint invalidation.
|
|
|
|
void Terminal::CreateFromSettings(winrt::Microsoft::Terminal::Settings::ICoreSettings settings,
|
2019-06-11 22:27:09 +02:00
|
|
|
Microsoft::Console::Render::IRenderTarget& renderTarget)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2019-06-05 01:31:36 +02:00
|
|
|
const COORD viewportSize{ Utils::ClampToShortMax(settings.InitialCols(), 1),
|
|
|
|
Utils::ClampToShortMax(settings.InitialRows(), 1) };
|
2019-12-04 23:57:44 +01:00
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
// TODO:MSFT:20642297 - Support infinite scrollback here, if HistorySize is -1
|
2019-06-05 01:31:36 +02:00
|
|
|
Create(viewportSize, Utils::ClampToShortMax(settings.HistorySize(), 0), renderTarget);
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
UpdateSettings(settings);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Update our internal properties to match the new values in the provided
|
|
|
|
// CoreSettings object.
|
|
|
|
// Arguments:
|
|
|
|
// - settings: an ICoreSettings with new settings values for us to use.
|
|
|
|
void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSettings settings)
|
|
|
|
{
|
|
|
|
_defaultFg = settings.DefaultForeground();
|
|
|
|
_defaultBg = settings.DefaultBackground();
|
|
|
|
|
|
|
|
CursorType cursorShape = CursorType::VerticalBar;
|
|
|
|
switch (settings.CursorShape())
|
|
|
|
{
|
2019-06-11 22:27:09 +02:00
|
|
|
case CursorStyle::Underscore:
|
|
|
|
cursorShape = CursorType::Underscore;
|
|
|
|
break;
|
|
|
|
case CursorStyle::FilledBox:
|
|
|
|
cursorShape = CursorType::FullBox;
|
|
|
|
break;
|
|
|
|
case CursorStyle::EmptyBox:
|
|
|
|
cursorShape = CursorType::EmptyBox;
|
|
|
|
break;
|
|
|
|
case CursorStyle::Vintage:
|
|
|
|
cursorShape = CursorType::Legacy;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case CursorStyle::Bar:
|
|
|
|
cursorShape = CursorType::VerticalBar;
|
|
|
|
break;
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
2020-06-09 23:47:13 +02:00
|
|
|
if (_buffer)
|
|
|
|
{
|
|
|
|
_buffer->GetCursor().SetStyle(settings.CursorHeight(),
|
|
|
|
settings.CursorColor(),
|
|
|
|
cursorShape);
|
|
|
|
}
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
{
|
2020-01-03 19:44:27 +01:00
|
|
|
_colorTable.at(i) = settings.GetColorTableEntry(i);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_snapOnInput = settings.SnapOnInput();
|
2020-06-05 18:11:41 +02:00
|
|
|
_altGrAliasing = settings.AltGrAliasing();
|
2019-07-12 01:06:18 +02:00
|
|
|
_wordDelimiters = settings.WordDelimiters();
|
2019-11-22 01:18:24 +01:00
|
|
|
_suppressApplicationTitle = settings.SuppressApplicationTitle();
|
|
|
|
_startingTitle = settings.StartingTitle();
|
|
|
|
|
2020-06-09 00:31:28 +02:00
|
|
|
_terminalInput->ForceDisableWin32InputMode(settings.ForceVTInput());
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
// TODO:MSFT:21327402 - if HistorySize has changed, resize the buffer so we
|
|
|
|
// have a smaller scrollback. We should do this carefully - if the new buffer
|
|
|
|
// size is smaller than where the mutable viewport currently is, we'll want
|
|
|
|
// to make sure to rotate the buffer contents upwards, so the mutable viewport
|
|
|
|
// remains at the bottom of the buffer.
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Resize the terminal as the result of some user interaction.
|
|
|
|
// Arguments:
|
|
|
|
// - viewportSize: the new size of the viewport, in chars
|
|
|
|
// Return Value:
|
|
|
|
// - S_OK if we successfully resized the terminal, S_FALSE if there was
|
|
|
|
// nothing to do (the viewportSize is the same as our current size), or an
|
|
|
|
// appropriate HRESULT for failing to resize.
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] HRESULT Terminal::UserResize(const COORD viewportSize) noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
const auto oldDimensions = _mutableViewport.Dimensions();
|
|
|
|
if (viewportSize == oldDimensions)
|
|
|
|
{
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
2020-03-18 23:22:26 +01:00
|
|
|
|
|
|
|
const auto dx = ::base::ClampSub(viewportSize.X, oldDimensions.X);
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
const auto oldTop = _mutableViewport.Top();
|
|
|
|
|
2020-03-18 23:22:26 +01:00
|
|
|
const short newBufferHeight = ::base::ClampAdd(viewportSize.Y, _scrollbackLines);
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
COORD bufferSize{ viewportSize.X, newBufferHeight };
|
|
|
|
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
// Save cursor's relative height versus the viewport
|
2020-03-18 23:22:26 +01:00
|
|
|
const short sCursorHeightInViewportBefore = ::base::ClampSub(_buffer->GetCursor().GetPosition().Y, _mutableViewport.Top());
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
|
|
|
|
// This will be used to determine where the viewport should be in the new buffer.
|
|
|
|
const short oldViewportTop = _mutableViewport.Top();
|
|
|
|
short newViewportTop = oldViewportTop;
|
2020-03-16 13:55:25 +01:00
|
|
|
short newVisibleTop = ::base::saturated_cast<short>(_VisibleStartIndex());
|
|
|
|
|
|
|
|
// If the original buffer had _no_ scroll offset, then we should be at the
|
|
|
|
// bottom in the new buffer as well. Track that case now.
|
|
|
|
const bool originalOffsetWasZero = _scrollOffset == 0;
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
|
Show a double width cursor for double width characters (#5319)
# Summary of the Pull Request
This PR will allow the cursor to be double width when on top of a double width character. This required changing `IsCursorDoubleWidth` to check whether the glyph the cursor's on top of is double width. This code is exactly the same as the original PR that addressed this issue in #2932. That one got reverted at some point due to the crashes related to it, but due to a combination of Terminal having come further since that PR and other changes to address use-after-frees, some of the crashes may/may not be relevant now. The ones that seemed to be relevant/repro-able, I attempt to address in this PR.
The `IsCursorDoubleWidth` check would fail during the `TextBuffer::Reflow` call inside of `Terminal::UserResize` occasionally, particularly when `newCursor.EndDeferDrawing()` is called. This is because when we tell the newCursor to `EndDefer`, the renderer will attempt to redraw the cursor. As part of this redraw, it'll ask if `IsCursorDoubleWidth`, and if the renderer managed to ask this before `UserResize` swapped out the old buffer with the new one from `Reflow`, the renderer will be asking the old buffer if its out-of-bounds cursor is double width. This was pretty easily repro'd using `cmatrix -u0` and resizing the window like a madman.
As a solution, I've moved the Start/End DeferDrawing calls out of `Reflow` and into `UserResize`. This way, I can "clamp" the portion of the code where the newBuffer is getting created and reflowed and swapped into the Terminal buffer, and only allow the renderer to draw once the swap is done. This also means that ConHost's `ResizeWithReflow` needed to change slightly.
In addition, I've added a WriteLock to `SetCursorOn`. It was mentioned as a fix for a crash in #2965 (although I can't repro), and I also figured it would be good to try to emulate where ConHost locks with regards to Cursor operations, and this seemed to be one that we were missing.
## PR Checklist
* [x] Closes #2713
* [x] CLA signed
* [x] Tests added/passed
## Validation Steps Performed
Manual validation that the cursor is indeed chonky, added a test case to check that we are correctly saying that the cursor is double width (not too sure if I put it in the right place). Also open to other test case ideas and thoughts on what else I should be careful for since I am quite nervous about what other crashes might occur.
2020-04-15 21:23:06 +02:00
|
|
|
// skip any drawing updates that might occur until we swap _buffer with the new buffer or if we exit early.
|
|
|
|
_buffer->GetCursor().StartDeferDrawing();
|
|
|
|
// we're capturing _buffer by reference here because when we exit, we want to EndDefer on the current active buffer.
|
|
|
|
auto endDefer = wil::scope_exit([&]() noexcept { _buffer->GetCursor().EndDeferDrawing(); });
|
|
|
|
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
// First allocate a new text buffer to take the place of the current one.
|
|
|
|
std::unique_ptr<TextBuffer> newTextBuffer;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
newTextBuffer = std::make_unique<TextBuffer>(bufferSize,
|
|
|
|
_buffer->GetCurrentAttributes(),
|
|
|
|
0, // temporarily set size to 0 so it won't render.
|
|
|
|
_buffer->GetRenderTarget());
|
|
|
|
|
Show a double width cursor for double width characters (#5319)
# Summary of the Pull Request
This PR will allow the cursor to be double width when on top of a double width character. This required changing `IsCursorDoubleWidth` to check whether the glyph the cursor's on top of is double width. This code is exactly the same as the original PR that addressed this issue in #2932. That one got reverted at some point due to the crashes related to it, but due to a combination of Terminal having come further since that PR and other changes to address use-after-frees, some of the crashes may/may not be relevant now. The ones that seemed to be relevant/repro-able, I attempt to address in this PR.
The `IsCursorDoubleWidth` check would fail during the `TextBuffer::Reflow` call inside of `Terminal::UserResize` occasionally, particularly when `newCursor.EndDeferDrawing()` is called. This is because when we tell the newCursor to `EndDefer`, the renderer will attempt to redraw the cursor. As part of this redraw, it'll ask if `IsCursorDoubleWidth`, and if the renderer managed to ask this before `UserResize` swapped out the old buffer with the new one from `Reflow`, the renderer will be asking the old buffer if its out-of-bounds cursor is double width. This was pretty easily repro'd using `cmatrix -u0` and resizing the window like a madman.
As a solution, I've moved the Start/End DeferDrawing calls out of `Reflow` and into `UserResize`. This way, I can "clamp" the portion of the code where the newBuffer is getting created and reflowed and swapped into the Terminal buffer, and only allow the renderer to draw once the swap is done. This also means that ConHost's `ResizeWithReflow` needed to change slightly.
In addition, I've added a WriteLock to `SetCursorOn`. It was mentioned as a fix for a crash in #2965 (although I can't repro), and I also figured it would be good to try to emulate where ConHost locks with regards to Cursor operations, and this seemed to be one that we were missing.
## PR Checklist
* [x] Closes #2713
* [x] CLA signed
* [x] Tests added/passed
## Validation Steps Performed
Manual validation that the cursor is indeed chonky, added a test case to check that we are correctly saying that the cursor is double width (not too sure if I put it in the right place). Also open to other test case ideas and thoughts on what else I should be careful for since I am quite nervous about what other crashes might occur.
2020-04-15 21:23:06 +02:00
|
|
|
newTextBuffer->GetCursor().StartDeferDrawing();
|
|
|
|
|
2020-03-16 13:55:25 +01:00
|
|
|
// Build a PositionInformation to track the position of both the top of
|
|
|
|
// the mutable viewport and the top of the visible viewport in the new
|
|
|
|
// buffer.
|
|
|
|
// * the new value of mutableViewportTop will be used to figure out
|
|
|
|
// where we should place the mutable viewport in the new buffer. This
|
|
|
|
// requires a bit of trickiness to remain consistent with conpty's
|
|
|
|
// buffer (as seen below).
|
|
|
|
// * the new value of visibleViewportTop will be used to calculate the
|
ci: run spell check in CI, fix remaining issues (#4799)
This commit introduces a github action to check our spelling and fixes
the following misspelled words so that we come up green.
It also renames TfEditSes to TfEditSession, because Ses is not a word.
currently, excerpt, fallthrough, identified, occurred, propagate,
provided, rendered, resetting, separate, succeeded, successfully,
terminal, transferred, adheres, breaks, combining, preceded,
architecture, populated, previous, setter, visible, window, within,
appxmanifest, hyphen, control, offset, powerpoint, suppress, parsing,
prioritized, aforementioned, check in, build, filling, indices, layout,
mapping, trying, scroll, terabyte, vetoes, viewport, whose
2020-03-25 19:02:53 +01:00
|
|
|
// new scrollOffset in the new buffer, so that the visible lines on
|
2020-03-16 13:55:25 +01:00
|
|
|
// the screen remain roughly the same.
|
|
|
|
TextBuffer::PositionInformation oldRows{ 0 };
|
|
|
|
oldRows.mutableViewportTop = oldViewportTop;
|
|
|
|
oldRows.visibleViewportTop = newVisibleTop;
|
|
|
|
|
|
|
|
const std::optional<short> oldViewStart{ oldViewportTop };
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
RETURN_IF_FAILED(TextBuffer::Reflow(*_buffer.get(),
|
|
|
|
*newTextBuffer.get(),
|
|
|
|
_mutableViewport,
|
2020-03-16 13:55:25 +01:00
|
|
|
{ oldRows }));
|
|
|
|
|
|
|
|
newViewportTop = oldRows.mutableViewportTop;
|
|
|
|
newVisibleTop = oldRows.visibleViewportTop;
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
}
|
|
|
|
CATCH_RETURN();
|
|
|
|
|
|
|
|
// Conpty resizes a little oddly - if the height decreased, and there were
|
|
|
|
// blank lines at the bottom, those lines will get trimmed. If there's not
|
|
|
|
// blank lines, then the top will get "shifted down", moving the top line
|
|
|
|
// into scrollback. See GH#3490 for more details.
|
|
|
|
//
|
|
|
|
// If the final position in the buffer is on the bottom row of the new
|
|
|
|
// viewport, then we're going to need to move the top down. Otherwise, move
|
|
|
|
// the bottom up.
|
|
|
|
//
|
|
|
|
// There are also important things to consider with line wrapping.
|
|
|
|
// * If a line in scrollback wrapped that didn't previously, we'll need to
|
|
|
|
// make sure to have the new viewport down another line. This will cause
|
|
|
|
// our top to move down.
|
|
|
|
// * If a line _in the viewport_ wrapped that didn't previously, then the
|
|
|
|
// conpty buffer will also have that wrapped line, and will move the
|
|
|
|
// cursor & text down a line in response. This causes our bottom to move
|
|
|
|
// down.
|
|
|
|
//
|
|
|
|
// We're going to use a combo of both these things to calculate where the
|
|
|
|
// new viewport should be. To keep in sync with conpty, we'll need to make
|
|
|
|
// sure that any lines that entered the scrollback _stay in scrollback_. We
|
|
|
|
// do that by taking the max of
|
|
|
|
// * Where the old top line in the viewport exists in the new buffer (as
|
|
|
|
// calculated by TextBuffer::Reflow)
|
|
|
|
// * Where the bottom of the text in the new buffer is (and using that to
|
|
|
|
// calculate another proposed top location).
|
|
|
|
|
|
|
|
const COORD newCursorPos = newTextBuffer->GetCursor().GetPosition();
|
|
|
|
#pragma warning(push)
|
|
|
|
#pragma warning(disable : 26496) // cpp core checks wants this const, but it's assigned immediately below...
|
|
|
|
COORD newLastChar = newCursorPos;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
newLastChar = newTextBuffer->GetLastNonSpaceCharacter();
|
|
|
|
}
|
|
|
|
CATCH_LOG();
|
|
|
|
#pragma warning(pop)
|
|
|
|
|
|
|
|
const auto maxRow = std::max(newLastChar.Y, newCursorPos.Y);
|
|
|
|
|
2020-03-18 23:22:26 +01:00
|
|
|
const short proposedTopFromLastLine = ::base::ClampAdd(::base::ClampSub(maxRow, viewportSize.Y), 1);
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
const short proposedTopFromScrollback = newViewportTop;
|
|
|
|
|
|
|
|
short proposedTop = std::max(proposedTopFromLastLine,
|
|
|
|
proposedTopFromScrollback);
|
|
|
|
|
|
|
|
// If we're using the new location of the old top line to place the
|
|
|
|
// viewport, we might need to make an adjustment to it.
|
|
|
|
//
|
|
|
|
// We're using the last cell of the line to calculate where the top line is
|
|
|
|
// in the new buffer. If that line wrapped, then all the lines below it
|
|
|
|
// shifted down in the buffer. If there's space for all those lines in the
|
|
|
|
// conpty buffer, then the originally unwrapped top line will _still_ be in
|
|
|
|
// the buffer. In that case, don't stick to the _end_ of the old top line,
|
|
|
|
// instead stick to the _start_, which is one line up.
|
|
|
|
//
|
|
|
|
// We can know if there's space in the conpty buffer by checking if the
|
|
|
|
// maxRow (the highest row we've written text to) is above the viewport from
|
|
|
|
// this proposed top position.
|
|
|
|
if (proposedTop == proposedTopFromScrollback)
|
|
|
|
{
|
|
|
|
const auto proposedViewFromTop = Viewport::FromDimensions({ 0, proposedTopFromScrollback }, viewportSize);
|
|
|
|
if (maxRow < proposedViewFromTop.BottomInclusive())
|
|
|
|
{
|
|
|
|
if (dx < 0 && proposedTop > 0)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2020-03-18 23:22:26 +01:00
|
|
|
auto row = newTextBuffer->GetRowByOffset(::base::ClampSub(proposedTop, 1));
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
if (row.GetCharRow().WasWrapForced())
|
|
|
|
{
|
|
|
|
proposedTop--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CATCH_LOG();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the new bottom would be higher than the last row of text, then we
|
|
|
|
// definitely want to use the last row of text to determine where the
|
|
|
|
// viewport should be.
|
|
|
|
const auto proposedViewFromTop = Viewport::FromDimensions({ 0, proposedTopFromScrollback }, viewportSize);
|
|
|
|
if (maxRow > proposedViewFromTop.BottomInclusive())
|
|
|
|
{
|
|
|
|
proposedTop = proposedTopFromLastLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure the proposed viewport is within the bounds of the buffer.
|
|
|
|
// First make sure the top is >=0
|
|
|
|
proposedTop = std::max(static_cast<short>(0), proposedTop);
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
// If the new bottom would be below the bottom of the buffer, then slide the
|
|
|
|
// top up so that we'll still fit within the buffer.
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
const auto newView = Viewport::FromDimensions({ 0, proposedTop }, viewportSize);
|
|
|
|
const auto proposedBottom = newView.BottomExclusive();
|
2019-05-03 00:29:04 +02:00
|
|
|
if (proposedBottom > bufferSize.Y)
|
|
|
|
{
|
2020-03-18 23:22:26 +01:00
|
|
|
proposedTop = ::base::ClampSub(proposedTop, ::base::ClampSub(proposedBottom, bufferSize.Y));
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_mutableViewport = Viewport::FromDimensions({ 0, proposedTop }, viewportSize);
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
|
|
|
|
_buffer.swap(newTextBuffer);
|
|
|
|
|
2020-03-16 13:55:25 +01:00
|
|
|
// GH#3494: Maintain scrollbar position during resize
|
|
|
|
// Make sure that we don't scroll past the mutableViewport at the bottom of the buffer
|
|
|
|
newVisibleTop = std::min(newVisibleTop, _mutableViewport.Top());
|
|
|
|
// Make sure we don't scroll past the top of the scrollback
|
|
|
|
newVisibleTop = std::max<short>(newVisibleTop, 0);
|
|
|
|
|
|
|
|
// If the old scrolloffset was 0, then we weren't scrolled back at all
|
|
|
|
// before, and shouldn't be now either.
|
2020-03-18 23:22:26 +01:00
|
|
|
_scrollOffset = originalOffsetWasZero ? 0 : ::base::ClampSub(_mutableViewport.Top(), newVisibleTop);
|
2020-03-21 00:50:59 +01:00
|
|
|
|
|
|
|
// GH#5029 - make sure to InvalidateAll here, so that we'll paint the entire visible viewport.
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_buffer->GetRenderTarget().TriggerRedrawAll();
|
|
|
|
}
|
|
|
|
CATCH_LOG();
|
2019-05-03 00:29:04 +02:00
|
|
|
_NotifyScrollEvent();
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Terminal::Write(std::wstring_view stringView)
|
|
|
|
{
|
|
|
|
auto lock = LockForWriting();
|
|
|
|
|
2019-12-19 23:12:53 +01:00
|
|
|
_stateMachine->ProcessString(stringView);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
2019-11-13 03:12:43 +01:00
|
|
|
// Method Description:
|
|
|
|
// - Attempts to snap to the bottom of the buffer, if SnapOnInput is true. Does
|
|
|
|
// nothing if SnapOnInput is set to false, or we're already at the bottom of
|
|
|
|
// the buffer.
|
|
|
|
// Arguments:
|
|
|
|
// - <none>
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void Terminal::TrySnapOnInput()
|
|
|
|
{
|
|
|
|
if (_snapOnInput && _scrollOffset != 0)
|
|
|
|
{
|
|
|
|
auto lock = LockForWriting();
|
|
|
|
_scrollOffset = 0;
|
|
|
|
_NotifyScrollEvent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-13 01:44:28 +01:00
|
|
|
// Routine Description:
|
|
|
|
// - Relays if we are tracking mouse input
|
|
|
|
// Parameters:
|
|
|
|
// - <none>
|
|
|
|
// Return value:
|
|
|
|
// - true, if we are tracking mouse input. False, otherwise
|
|
|
|
bool Terminal::IsTrackingMouseInput() const noexcept
|
|
|
|
{
|
|
|
|
return _terminalInput->IsTrackingMouseInput();
|
|
|
|
}
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
// Method Description:
|
2020-04-07 21:09:28 +02:00
|
|
|
// - Send this particular (non-character) key event to the terminal.
|
|
|
|
// - The terminal will translate the key and the modifiers pressed into the
|
|
|
|
// appropriate VT sequence for that key chord. If we do translate the key,
|
|
|
|
// we'll return true. In that case, the event should NOT be processed any further.
|
|
|
|
// - Character events (e.g. WM_CHAR) are generally the best way to properly receive
|
|
|
|
// keyboard input on Windows though, as the OS is suited best at handling the
|
|
|
|
// translation of the current keyboard layout, dead keys, etc.
|
|
|
|
// As a result of this false is returned for all key events that contain characters.
|
|
|
|
// SendCharEvent may then be called with the data obtained from a character event.
|
|
|
|
// - As a special case we'll always handle VK_TAB key events.
|
|
|
|
// This must be done due to TermControl::_KeyDownHandler (one of the callers)
|
|
|
|
// always marking tab key events as handled, causing no character event to be raised.
|
2019-05-03 00:29:04 +02:00
|
|
|
// Arguments:
|
2020-04-07 21:09:28 +02:00
|
|
|
// - vkey: The vkey of the last pressed key.
|
|
|
|
// - scanCode: The scan code of the last pressed key.
|
2019-07-16 20:09:29 +02:00
|
|
|
// - states: The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
|
2020-06-09 00:31:28 +02:00
|
|
|
// - keyDown: If true, the key was pressed, otherwise the key was released.
|
2019-05-03 00:29:04 +02:00
|
|
|
// Return Value:
|
|
|
|
// - true if we translated the key event, and it should not be processed any further.
|
|
|
|
// - false if we did not translate the key, and it should be processed into a character.
|
2020-06-09 00:31:28 +02:00
|
|
|
bool Terminal::SendKeyEvent(const WORD vkey,
|
|
|
|
const WORD scanCode,
|
|
|
|
const ControlKeyStates states,
|
|
|
|
const bool keyDown)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2020-06-09 23:49:39 +02:00
|
|
|
// GH#6423 - don't snap on this key if the key that was pressed was a
|
|
|
|
// modifier key. We'll wait for a real keystroke to snap to the bottom.
|
2020-06-15 21:55:20 +02:00
|
|
|
// GH#6481 - Additionally, make sure the key was actually pressed. This
|
|
|
|
// check will make sure we behave the same as before GH#6309
|
|
|
|
if (!KeyEvent::IsModifierKey(vkey) && keyDown)
|
2020-06-09 23:49:39 +02:00
|
|
|
{
|
|
|
|
TrySnapOnInput();
|
|
|
|
}
|
|
|
|
|
2020-04-07 21:09:28 +02:00
|
|
|
_StoreKeyEvent(vkey, scanCode);
|
|
|
|
|
|
|
|
const auto isAltOnlyPressed = states.IsAltPressed() && !states.IsCtrlPressed();
|
2020-06-05 18:11:41 +02:00
|
|
|
const auto isSuppressedAltGrAlias = !_altGrAliasing && states.IsAltPressed() && states.IsCtrlPressed();
|
2019-05-03 00:29:04 +02:00
|
|
|
|
|
|
|
// DON'T manually handle Alt+Space - the system will use this to bring up
|
2020-04-07 21:09:28 +02:00
|
|
|
// the system menu for restore, min/maximize, size, move, close.
|
|
|
|
// (This doesn't apply to Ctrl+Alt+Space.)
|
|
|
|
if (isAltOnlyPressed && vkey == VK_SPACE)
|
2019-06-15 00:00:46 +02:00
|
|
|
{
|
2020-04-07 21:09:28 +02:00
|
|
|
return false;
|
2019-06-15 00:00:46 +02:00
|
|
|
}
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2020-06-05 18:11:41 +02:00
|
|
|
// By default Windows treats Ctrl+Alt as an alias for AltGr.
|
|
|
|
// When the altGrAliasing setting is set to false, this behaviour should be disabled.
|
|
|
|
//
|
|
|
|
// Whenever possible _CharacterFromKeyEvent() will return a valid character.
|
|
|
|
// For instance both Ctrl+Alt+Q as well as AltGr+Q return @ on a German keyboard.
|
|
|
|
//
|
|
|
|
// We can achieve the altGrAliasing functionality by skipping the call to _CharacterFromKeyEvent,
|
|
|
|
// as TerminalInput::HandleKey will then fall back to using the vkey which
|
|
|
|
// is the underlying ASCII character (e.g. A-Z) on the keyboard in our case.
|
|
|
|
// See GH#5525/GH#6211 for more details
|
|
|
|
const auto ch = isSuppressedAltGrAlias ? UNICODE_NULL : _CharacterFromKeyEvent(vkey, scanCode, states);
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2020-04-07 21:09:28 +02:00
|
|
|
// Delegate it to the character event handler if this key event can be
|
|
|
|
// mapped to one (see method description above). For Alt+key combinations
|
|
|
|
// we'll not receive another character event for some reason though.
|
|
|
|
// -> Don't delegate the event if this is a Alt+key combination.
|
|
|
|
//
|
|
|
|
// As a special case we'll furthermore always handle VK_TAB
|
|
|
|
// key events here instead of in Terminal::SendCharEvent.
|
|
|
|
// See the method description for more information.
|
|
|
|
if (!isAltOnlyPressed && vkey != VK_TAB && ch != UNICODE_NULL)
|
2019-07-16 22:56:46 +02:00
|
|
|
{
|
2020-04-07 21:09:28 +02:00
|
|
|
return false;
|
2019-07-16 22:56:46 +02:00
|
|
|
}
|
|
|
|
|
2020-06-09 00:31:28 +02:00
|
|
|
KeyEvent keyEv{ keyDown, 1, vkey, scanCode, ch, states.Value() };
|
2020-04-07 21:09:28 +02:00
|
|
|
return _terminalInput->HandleKey(&keyEv);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
2020-03-13 01:44:28 +01:00
|
|
|
// Method Description:
|
|
|
|
// - Send this particular mouse event to the terminal. The terminal will translate
|
|
|
|
// the button and the modifiers pressed into the appropriate VT sequence for that
|
|
|
|
// mouse event. If we do translate the key, we'll return true. In that case, the
|
|
|
|
// event should NOT be processed any further. If we return false, the event
|
|
|
|
// was NOT translated, and we should instead use the event normally
|
|
|
|
// Arguments:
|
|
|
|
// - viewportPos: the position of the mouse event relative to the viewport origin.
|
|
|
|
// - uiButton: the WM mouse button event code
|
|
|
|
// - states: The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
|
|
|
|
// - wheelDelta: the amount that the scroll wheel changed (should be 0 unless button is a WM_MOUSE*WHEEL)
|
|
|
|
// Return Value:
|
|
|
|
// - true if we translated the key event, and it should not be processed any further.
|
|
|
|
// - false if we did not translate the key, and it should be processed into a character.
|
|
|
|
bool Terminal::SendMouseEvent(const COORD viewportPos, const unsigned int uiButton, const ControlKeyStates states, const short wheelDelta)
|
|
|
|
{
|
|
|
|
// viewportPos must be within the dimensions of the viewport
|
|
|
|
const auto viewportDimensions = _mutableViewport.Dimensions();
|
|
|
|
if (viewportPos.X < 0 || viewportPos.X >= viewportDimensions.X || viewportPos.Y < 0 || viewportPos.Y >= viewportDimensions.Y)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return _terminalInput->HandleMouse(viewportPos, uiButton, GET_KEYSTATE_WPARAM(states.Value()), wheelDelta);
|
|
|
|
}
|
|
|
|
|
2020-04-07 21:09:28 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Send this particular character to the terminal.
|
|
|
|
// - This method is the counterpart to SendKeyEvent and behaves almost identical.
|
|
|
|
// The difference is the focus on sending characters to the terminal,
|
|
|
|
// whereas SendKeyEvent handles the sending of keys like the arrow keys.
|
|
|
|
// Arguments:
|
|
|
|
// - ch: The UTF-16 code unit to be sent.
|
|
|
|
// - scanCode: The scan code of the last pressed key. Can be left 0.
|
|
|
|
// - states: The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
|
|
|
|
// Return Value:
|
|
|
|
// - true if we translated the character event, and it should not be processed any further.
|
|
|
|
// - false otherwise.
|
|
|
|
bool Terminal::SendCharEvent(const wchar_t ch, const WORD scanCode, const ControlKeyStates states)
|
2019-10-11 23:02:09 +02:00
|
|
|
{
|
2020-04-07 21:09:28 +02:00
|
|
|
// DON'T manually handle Alt+Space - the system will use this to bring up
|
|
|
|
// the system menu for restore, min/maximize, size, move, close.
|
|
|
|
if (ch == L' ' && states.IsAltPressed() && !states.IsCtrlPressed())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto vkey = _TakeVirtualKeyFromLastKeyEvent(scanCode);
|
|
|
|
if (vkey == 0 && scanCode != 0)
|
|
|
|
{
|
|
|
|
vkey = _VirtualKeyFromScanCode(scanCode);
|
|
|
|
}
|
|
|
|
if (vkey == 0)
|
|
|
|
{
|
|
|
|
vkey = _VirtualKeyFromCharacter(ch);
|
|
|
|
}
|
|
|
|
|
2020-06-09 00:31:28 +02:00
|
|
|
// Unfortunately, the UI doesn't give us both a character down and a
|
|
|
|
// character up event, only a character received event. So fake sending both
|
|
|
|
// to the terminal input translator. Unless it's in win32-input-mode, it'll
|
|
|
|
// ignore the keyup.
|
|
|
|
KeyEvent keyDown{ true, 1, vkey, scanCode, ch, states.Value() };
|
|
|
|
KeyEvent keyUp{ false, 1, vkey, scanCode, ch, states.Value() };
|
|
|
|
const auto handledDown = _terminalInput->HandleKey(&keyDown);
|
|
|
|
const auto handledUp = _terminalInput->HandleKey(&keyUp);
|
|
|
|
return handledDown || handledUp;
|
2019-10-11 23:02:09 +02:00
|
|
|
}
|
|
|
|
|
2019-10-01 18:15:30 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Returns the keyboard's scan code for the given virtual key code.
|
|
|
|
// Arguments:
|
|
|
|
// - vkey: The virtual key code.
|
|
|
|
// Return Value:
|
|
|
|
// - The keyboard's scan code.
|
|
|
|
WORD Terminal::_ScanCodeFromVirtualKey(const WORD vkey) noexcept
|
|
|
|
{
|
|
|
|
return LOWORD(MapVirtualKeyW(vkey, MAPVK_VK_TO_VSC));
|
|
|
|
}
|
|
|
|
|
2020-04-07 21:09:28 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Returns the virtual key code for the given keyboard's scan code.
|
|
|
|
// Arguments:
|
|
|
|
// - scanCode: The keyboard's scan code.
|
|
|
|
// Return Value:
|
|
|
|
// - The virtual key code. 0 if no mapping can be found.
|
|
|
|
WORD Terminal::_VirtualKeyFromScanCode(const WORD scanCode) noexcept
|
|
|
|
{
|
|
|
|
return LOWORD(MapVirtualKeyW(scanCode, MAPVK_VSC_TO_VK));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Returns any virtual key code that produces the given character.
|
|
|
|
// Arguments:
|
|
|
|
// - scanCode: The keyboard's scan code.
|
|
|
|
// Return Value:
|
|
|
|
// - The virtual key code. 0 if no mapping can be found.
|
|
|
|
WORD Terminal::_VirtualKeyFromCharacter(const wchar_t ch) noexcept
|
|
|
|
{
|
|
|
|
const auto vkey = LOWORD(VkKeyScanW(ch));
|
|
|
|
return vkey == -1 ? 0 : vkey;
|
|
|
|
}
|
|
|
|
|
2019-10-01 18:15:30 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Translates the specified virtual key code and keyboard state to the corresponding character.
|
|
|
|
// Arguments:
|
|
|
|
// - vkey: The virtual key code that initiated this keyboard event.
|
|
|
|
// - scanCode: The scan code that initiated this keyboard event.
|
|
|
|
// - states: The current keyboard state.
|
|
|
|
// Return Value:
|
|
|
|
// - The character that would result from this virtual key code and keyboard state.
|
|
|
|
wchar_t Terminal::_CharacterFromKeyEvent(const WORD vkey, const WORD scanCode, const ControlKeyStates states) noexcept
|
2020-01-03 19:44:27 +01:00
|
|
|
try
|
2019-10-01 18:15:30 +02:00
|
|
|
{
|
|
|
|
const auto sc = scanCode != 0 ? scanCode : _ScanCodeFromVirtualKey(vkey);
|
|
|
|
|
|
|
|
// We might want to use GetKeyboardState() instead of building our own keyState.
|
|
|
|
// The question is whether that's necessary though. For now it seems to work fine as it is.
|
2020-01-03 19:44:27 +01:00
|
|
|
std::array<BYTE, 256> keyState = {};
|
|
|
|
keyState.at(VK_SHIFT) = states.IsShiftPressed() ? 0x80 : 0;
|
|
|
|
keyState.at(VK_CONTROL) = states.IsCtrlPressed() ? 0x80 : 0;
|
|
|
|
keyState.at(VK_MENU) = states.IsAltPressed() ? 0x80 : 0;
|
2019-10-01 18:15:30 +02:00
|
|
|
|
2019-11-13 17:59:28 +01:00
|
|
|
// For the following use of ToUnicodeEx() please look here:
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-tounicodeex
|
|
|
|
|
2019-10-01 18:15:30 +02:00
|
|
|
// Technically ToUnicodeEx() can produce arbitrarily long sequences of diacritics etc.
|
|
|
|
// Since we only handle the case of a single UTF-16 code point, we can set the buffer size to 2 though.
|
2020-01-03 19:44:27 +01:00
|
|
|
std::array<wchar_t, 2> buffer;
|
2019-10-01 18:15:30 +02:00
|
|
|
|
2019-11-13 17:59:28 +01:00
|
|
|
// wFlags:
|
|
|
|
// * If bit 0 is set, a menu is active.
|
|
|
|
// If this flag is not specified ToUnicodeEx will send us character events on certain Alt+Key combinations (e.g. Alt+Arrow-Up).
|
|
|
|
// * If bit 2 is set, keyboard state is not changed (Windows 10, version 1607 and newer)
|
2020-01-03 19:44:27 +01:00
|
|
|
const auto result = ToUnicodeEx(vkey, sc, keyState.data(), buffer.data(), gsl::narrow_cast<int>(buffer.size()), 0b101, nullptr);
|
2019-10-01 18:15:30 +02:00
|
|
|
|
|
|
|
// TODO:GH#2853 We're only handling single UTF-16 code points right now, since that's the only thing KeyEvent supports.
|
2020-01-03 19:44:27 +01:00
|
|
|
return result == 1 || result == -1 ? buffer.at(0) : 0;
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
LOG_CAUGHT_EXCEPTION();
|
|
|
|
return UNICODE_INVALID;
|
2019-10-01 18:15:30 +02:00
|
|
|
}
|
|
|
|
|
2020-04-07 21:09:28 +02:00
|
|
|
// Method Description:
|
|
|
|
// - It's possible for a single scan code on a keyboard to
|
|
|
|
// produce different key codes depending on the keyboard state.
|
|
|
|
// MapVirtualKeyW(scanCode, MAPVK_VSC_TO_VK) will always chose one of the
|
|
|
|
// possibilities no matter what though and thus can't be used in SendCharEvent.
|
|
|
|
// - This method stores the key code from a key event (SendKeyEvent).
|
|
|
|
// If the key event contains character data, handling of the event will be
|
|
|
|
// denied, in order to delegate the work to the character event handler.
|
|
|
|
// - The character event handler (SendCharEvent) will now pick up
|
|
|
|
// the stored key code to restore the full key event data.
|
|
|
|
// Arguments:
|
|
|
|
// - vkey: The virtual key code.
|
|
|
|
// - scanCode: The scan code.
|
|
|
|
void Terminal::_StoreKeyEvent(const WORD vkey, const WORD scanCode)
|
|
|
|
{
|
|
|
|
_lastKeyEventCodes.emplace(KeyEventCodes{ vkey, scanCode });
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - This method acts as a counterpart to _StoreKeyEvent and extracts a stored
|
|
|
|
// key code. As a safety measure it'll ensure that the given scan code
|
|
|
|
// matches the stored scan code from the previous key event.
|
|
|
|
// - See _StoreKeyEvent for more information.
|
|
|
|
// Arguments:
|
|
|
|
// - scanCode: The scan code.
|
|
|
|
// Return Value:
|
|
|
|
// - The key code matching the given scan code. Otherwise 0.
|
|
|
|
WORD Terminal::_TakeVirtualKeyFromLastKeyEvent(const WORD scanCode) noexcept
|
|
|
|
{
|
|
|
|
const auto codes = _lastKeyEventCodes.value_or(KeyEventCodes{});
|
|
|
|
_lastKeyEventCodes.reset();
|
|
|
|
return codes.ScanCode == scanCode ? codes.VirtualKey : 0;
|
|
|
|
}
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
// Method Description:
|
2020-02-10 21:40:01 +01:00
|
|
|
// - Acquire a read lock on the terminal.
|
2019-05-03 00:29:04 +02:00
|
|
|
// Return Value:
|
|
|
|
// - a shared_lock which can be used to unlock the terminal. The shared_lock
|
|
|
|
// will release this lock when it's destructed.
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] std::shared_lock<std::shared_mutex> Terminal::LockForReading()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return std::shared_lock<std::shared_mutex>(_readWriteLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
2020-02-10 21:40:01 +01:00
|
|
|
// - Acquire a write lock on the terminal.
|
2019-05-03 00:29:04 +02:00
|
|
|
// Return Value:
|
|
|
|
// - a unique_lock which can be used to unlock the terminal. The unique_lock
|
|
|
|
// will release this lock when it's destructed.
|
2019-06-11 22:27:09 +02:00
|
|
|
[[nodiscard]] std::unique_lock<std::shared_mutex> Terminal::LockForWriting()
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return std::unique_lock<std::shared_mutex>(_readWriteLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
Viewport Terminal::_GetMutableViewport() const noexcept
|
|
|
|
{
|
|
|
|
return _mutableViewport;
|
|
|
|
}
|
|
|
|
|
|
|
|
short Terminal::GetBufferHeight() const noexcept
|
|
|
|
{
|
|
|
|
return _mutableViewport.BottomExclusive();
|
|
|
|
}
|
|
|
|
|
Search - add search box control and implement search experience (#3590)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
This is the PR for feature Search: #605
This PR includes the newly introduced SearchBoxControl in TermControl dir, which is the search bar for the search experience. And the codes that enable Search in Windows Terminal.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
The PR that migrates the Conhost search module: https://github.com/microsoft/terminal/pull/3279
Spec (still actively updating): https://github.com/microsoft/terminal/pull/3299
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #605
* [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) 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: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
These functionalities are included in the search experience.
1. Search in Terminal text buffer.
2. Automatic wrap-around.
3. Search up or down switch by clicking different buttons.
4. Search case sensitively/insensitively by clicking a button. S. Move the search box to the top/bottom by clicking a button.
6. Close by clicking 'X'.
7. Open search by ctrl + F.
When the searchbox is open, the user could still interact with the terminal by clicking the terminal input area.
While I already have the search functionalities, currently there are still some known to-do works and I will keep updating my PR:
1. Optimize the search box UI, this includes:
1) Theme adaptation. The search box background and font color
should change according to the theme,
2) Add background. Currently the elements in search box are all
transparent. However, we need a background.
3) Move button should be highlighted once clicked.
2. Accessibility: search process should be able to performed without mouse. Once the search box is focused, the user should be able to navigate between all interactive elements on the searchbox using keyboard.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
To test:
1. checkout this branch.
2. Build the project.
3. Start Windows Terminal and press Ctrl+F
4. The search box should appear on the top right corner.
2019-12-17 16:52:37 +01:00
|
|
|
// ViewStartIndex is also the length of the scrollback
|
|
|
|
int Terminal::ViewStartIndex() const noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return _mutableViewport.Top();
|
|
|
|
}
|
|
|
|
|
Search - add search box control and implement search experience (#3590)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
This is the PR for feature Search: #605
This PR includes the newly introduced SearchBoxControl in TermControl dir, which is the search bar for the search experience. And the codes that enable Search in Windows Terminal.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
The PR that migrates the Conhost search module: https://github.com/microsoft/terminal/pull/3279
Spec (still actively updating): https://github.com/microsoft/terminal/pull/3299
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #605
* [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) 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: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
These functionalities are included in the search experience.
1. Search in Terminal text buffer.
2. Automatic wrap-around.
3. Search up or down switch by clicking different buttons.
4. Search case sensitively/insensitively by clicking a button. S. Move the search box to the top/bottom by clicking a button.
6. Close by clicking 'X'.
7. Open search by ctrl + F.
When the searchbox is open, the user could still interact with the terminal by clicking the terminal input area.
While I already have the search functionalities, currently there are still some known to-do works and I will keep updating my PR:
1. Optimize the search box UI, this includes:
1) Theme adaptation. The search box background and font color
should change according to the theme,
2) Add background. Currently the elements in search box are all
transparent. However, we need a background.
3) Move button should be highlighted once clicked.
2. Accessibility: search process should be able to performed without mouse. Once the search box is focused, the user should be able to navigate between all interactive elements on the searchbox using keyboard.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
To test:
1. checkout this branch.
2. Build the project.
3. Start Windows Terminal and press Ctrl+F
4. The search box should appear on the top right corner.
2019-12-17 16:52:37 +01:00
|
|
|
int Terminal::ViewEndIndex() const noexcept
|
|
|
|
{
|
|
|
|
return _mutableViewport.BottomInclusive();
|
|
|
|
}
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
// _VisibleStartIndex is the first visible line of the buffer
|
|
|
|
int Terminal::_VisibleStartIndex() const noexcept
|
|
|
|
{
|
Search - add search box control and implement search experience (#3590)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
This is the PR for feature Search: #605
This PR includes the newly introduced SearchBoxControl in TermControl dir, which is the search bar for the search experience. And the codes that enable Search in Windows Terminal.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
The PR that migrates the Conhost search module: https://github.com/microsoft/terminal/pull/3279
Spec (still actively updating): https://github.com/microsoft/terminal/pull/3299
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #605
* [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) 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: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
These functionalities are included in the search experience.
1. Search in Terminal text buffer.
2. Automatic wrap-around.
3. Search up or down switch by clicking different buttons.
4. Search case sensitively/insensitively by clicking a button. S. Move the search box to the top/bottom by clicking a button.
6. Close by clicking 'X'.
7. Open search by ctrl + F.
When the searchbox is open, the user could still interact with the terminal by clicking the terminal input area.
While I already have the search functionalities, currently there are still some known to-do works and I will keep updating my PR:
1. Optimize the search box UI, this includes:
1) Theme adaptation. The search box background and font color
should change according to the theme,
2) Add background. Currently the elements in search box are all
transparent. However, we need a background.
3) Move button should be highlighted once clicked.
2. Accessibility: search process should be able to performed without mouse. Once the search box is focused, the user should be able to navigate between all interactive elements on the searchbox using keyboard.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
To test:
1. checkout this branch.
2. Build the project.
3. Start Windows Terminal and press Ctrl+F
4. The search box should appear on the top right corner.
2019-12-17 16:52:37 +01:00
|
|
|
return std::max(0, ViewStartIndex() - _scrollOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Terminal::_VisibleEndIndex() const noexcept
|
|
|
|
{
|
|
|
|
return std::max(0, ViewEndIndex() - _scrollOffset);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Viewport Terminal::_GetVisibleViewport() const noexcept
|
|
|
|
{
|
|
|
|
const COORD origin{ 0, gsl::narrow<short>(_VisibleStartIndex()) };
|
|
|
|
return Viewport::FromDimensions(origin,
|
|
|
|
_mutableViewport.Dimensions());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Writes a string of text to the buffer, then moves the cursor (and viewport)
|
|
|
|
// in accordance with the written text.
|
|
|
|
// This method is our proverbial `WriteCharsLegacy`, and great care should be made to
|
|
|
|
// keep it minimal and orderly, lest it become WriteCharsLegacy2ElectricBoogaloo
|
|
|
|
// TODO: MSFT 21006766
|
|
|
|
// This needs to become stream logic on the buffer itself sooner rather than later
|
|
|
|
// because it's otherwise impossible to avoid the Electric Boogaloo-ness here.
|
|
|
|
// I had to make a bunch of hacks to get Japanese and emoji to work-ish.
|
|
|
|
void Terminal::_WriteBuffer(const std::wstring_view& stringView)
|
|
|
|
{
|
|
|
|
auto& cursor = _buffer->GetCursor();
|
|
|
|
|
2019-10-15 06:44:52 +02:00
|
|
|
// Defer the cursor drawing while we are iterating the string, for a better performance.
|
|
|
|
// We can not waste time displaying a cursor event when we know more text is coming right behind it.
|
|
|
|
cursor.StartDeferDrawing();
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
for (size_t i = 0; i < stringView.size(); i++)
|
|
|
|
{
|
2020-01-03 19:44:27 +01:00
|
|
|
const auto wch = stringView.at(i);
|
2019-05-03 00:29:04 +02:00
|
|
|
const COORD cursorPosBefore = cursor.GetPosition();
|
|
|
|
COORD proposedCursorPosition = cursorPosBefore;
|
|
|
|
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
// TODO: MSFT 21006766
|
|
|
|
// This is not great but I need it demoable. Fix by making a buffer stream writer.
|
|
|
|
//
|
|
|
|
// If wch is a surrogate character we need to read 2 code units
|
|
|
|
// from the stringView to form a single code point.
|
|
|
|
const auto isSurrogate = wch >= 0xD800 && wch <= 0xDFFF;
|
|
|
|
const auto view = stringView.substr(i, isSurrogate ? 2 : 1);
|
|
|
|
const OutputCellIterator it{ view, _buffer->GetCurrentAttributes() };
|
|
|
|
const auto end = _buffer->Write(it);
|
|
|
|
const auto cellDistance = end.GetCellDistance(it);
|
|
|
|
const auto inputDistance = end.GetInputDistance(it);
|
|
|
|
|
|
|
|
if (inputDistance > 0)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
// If "wch" was a surrogate character, we just consumed 2 code units above.
|
|
|
|
// -> Increment "i" by 1 in that case and thus by 2 in total in this iteration.
|
|
|
|
proposedCursorPosition.X += gsl::narrow<SHORT>(cellDistance);
|
|
|
|
i += inputDistance - 1;
|
2019-07-25 22:31:41 +02:00
|
|
|
}
|
2019-05-03 00:29:04 +02:00
|
|
|
else
|
|
|
|
{
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
// If _WriteBuffer() is called with a consecutive string longer than the viewport/buffer width
|
|
|
|
// the call to _buffer->Write() will refuse to write anything on the current line.
|
|
|
|
// GetInputDistance() thus returns 0, which would in turn cause i to be
|
|
|
|
// decremented by 1 below and force the outer loop to loop forever.
|
|
|
|
// This if() basically behaves as if "\r\n" had been encountered above and retries the write.
|
|
|
|
// With well behaving shells during normal operation this safeguard should normally not be encountered.
|
|
|
|
proposedCursorPosition.X = 0;
|
|
|
|
proposedCursorPosition.Y++;
|
Make Conpty emit wrapped lines as actually wrapped lines (#4415)
## Summary of the Pull Request
Changes how conpty emits text to preserve line-wrap state, and additionally adds rudimentary support to the Windows Terminal for wrapped lines.
## References
* Does _not_ fix (!) #3088, but that might be lower down in conhost. This makes wt behave like conhost, so at least there's that
* Still needs a proper deferred EOL wrap implementation in #780, which is left as a todo
* #4200 is the mega bucket with all this work
* MSFT:16485846 was the first attempt at this task, which caused the regression MSFT:18123777 so we backed it out.
* #4403 - I made sure this worked with that PR before I even sent #4403
## PR Checklist
* [x] Closes #405
* [x] Closes #3367
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
## Detailed Description of the Pull Request / Additional comments
I started with the following implementation:
When conpty is about to write the last column, note that we wrapped this line here. If the next character the vt renderer is told to paint get is supposed to be at the start of the following line, then we know that the previous line had wrapped, so we _won't_ emit the usual `\r\n` here, and we'll just continue emitting text.
However, this isn't _exactly_ right - if someone fills the row _exactly_ with text, the information that's available to the vt renderer isn't enough to know for sure if this line broke or not. It is possible for the client to write a full line of text, with a `\n` at the end, to manually break the line. So, I had to also add the `lineWrapped` param to the `IRenderEngine` interface, which is about half the files in this changelist.
## Validation Steps Performed
* Ran tests
* Checked how the Windows Terminal behaves with these changes
* Made sure that conhost/inception and gnome-terminal both act as you'd expect with wrapped lines from conpty
2020-02-27 17:40:11 +01:00
|
|
|
|
|
|
|
// Try the character again.
|
|
|
|
i--;
|
|
|
|
|
Add support for "reflow"ing the Terminal buffer (#4741)
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them.
As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.
I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.
## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
this
* #4354 - we don't speak of this PR anymore
## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed
## EDIT: Changes to this PR on 5 March 2020
I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.
Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.
So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.
This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.
When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.
The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens:
* With the quirk disabled, conpty reprints the entire buffer. This is
60 lines that get printed. This ends up blowing away about 20 lines
of scrollback history, as the terminal app would have tried to keep
the text pinned to the bottom of the window. The term. app moved the
viewport up 20 lines, and then the 50 lines of conpty output (30
lines of text, and 20 blank lines at the bottom) overwrote the lines
from the scrollback. This is bad, but not immediately obvious, and
is **what currently happens**.
* With the quirk enabled, conpty doesn't emit any lines, but the
actual content of the window is still only in the top 30 lines.
However, the terminal app has still moved 20 lines down from the
scrollback back into the viewport. So the terminal's cursor is at
y=50 now, but conpty's is at 30. This means that the terminal and
conpty are out of sync, and there's not a good way of re-syncing
these. It's very possible (trivial in `powershell`) that the new
output will jump up to y=30 override the existing output in the
terminal buffer.
The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.
What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
2020-03-13 01:43:37 +01:00
|
|
|
// If we write the last cell of the row here, TextBuffer::Write will
|
|
|
|
// mark this line as wrapped for us. If the next character we
|
|
|
|
// process is a newline, the Terminal::CursorLineFeed will unmark
|
|
|
|
// this line as wrapped.
|
Make Conpty emit wrapped lines as actually wrapped lines (#4415)
## Summary of the Pull Request
Changes how conpty emits text to preserve line-wrap state, and additionally adds rudimentary support to the Windows Terminal for wrapped lines.
## References
* Does _not_ fix (!) #3088, but that might be lower down in conhost. This makes wt behave like conhost, so at least there's that
* Still needs a proper deferred EOL wrap implementation in #780, which is left as a todo
* #4200 is the mega bucket with all this work
* MSFT:16485846 was the first attempt at this task, which caused the regression MSFT:18123777 so we backed it out.
* #4403 - I made sure this worked with that PR before I even sent #4403
## PR Checklist
* [x] Closes #405
* [x] Closes #3367
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
## Detailed Description of the Pull Request / Additional comments
I started with the following implementation:
When conpty is about to write the last column, note that we wrapped this line here. If the next character the vt renderer is told to paint get is supposed to be at the start of the following line, then we know that the previous line had wrapped, so we _won't_ emit the usual `\r\n` here, and we'll just continue emitting text.
However, this isn't _exactly_ right - if someone fills the row _exactly_ with text, the information that's available to the vt renderer isn't enough to know for sure if this line broke or not. It is possible for the client to write a full line of text, with a `\n` at the end, to manually break the line. So, I had to also add the `lineWrapped` param to the `IRenderEngine` interface, which is about half the files in this changelist.
## Validation Steps Performed
* Ran tests
* Checked how the Windows Terminal behaves with these changes
* Made sure that conhost/inception and gnome-terminal both act as you'd expect with wrapped lines from conpty
2020-02-27 17:40:11 +01:00
|
|
|
|
|
|
|
// TODO: GH#780 - This should really be a _deferred_ newline. If
|
|
|
|
// the next character to come in is a newline or a cursor
|
|
|
|
// movement or anything, then we should _not_ wrap this line
|
|
|
|
// here.
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
_AdjustCursorPosition(proposedCursorPosition);
|
|
|
|
}
|
2019-05-03 00:29:04 +02:00
|
|
|
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
cursor.EndDeferDrawing();
|
|
|
|
}
|
2019-05-03 00:29:04 +02:00
|
|
|
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
|
|
|
|
{
|
|
|
|
#pragma warning(suppress : 26496) // cpp core checks wants this const but it's modified below.
|
|
|
|
auto proposedCursorPosition = proposedPosition;
|
|
|
|
auto& cursor = _buffer->GetCursor();
|
|
|
|
const Viewport bufferSize = _buffer->GetSize();
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2020-04-29 21:28:59 +02:00
|
|
|
// If we're about to scroll past the bottom of the buffer, instead cycle the
|
|
|
|
// buffer.
|
2020-06-12 21:51:37 +02:00
|
|
|
SHORT rowsPushedOffTopOfBuffer = 0;
|
2020-07-09 13:24:20 +02:00
|
|
|
const auto newRows = std::max(0, proposedCursorPosition.Y - bufferSize.Height() + 1);
|
2020-06-12 21:51:37 +02:00
|
|
|
if (proposedCursorPosition.Y >= bufferSize.Height())
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
{
|
|
|
|
for (auto dy = 0; dy < newRows; dy++)
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
_buffer->IncrementCircularBuffer();
|
|
|
|
proposedCursorPosition.Y--;
|
2020-06-12 21:51:37 +02:00
|
|
|
rowsPushedOffTopOfBuffer++;
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update Cursor Position
|
|
|
|
cursor.SetPosition(proposedCursorPosition);
|
2019-05-03 00:29:04 +02:00
|
|
|
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
// Move the viewport down if the cursor moved below the viewport.
|
2020-06-12 21:51:37 +02:00
|
|
|
bool updatedViewport = false;
|
2020-07-09 13:24:20 +02:00
|
|
|
const auto scrollAmount = std::max(0, proposedCursorPosition.Y - _mutableViewport.BottomInclusive());
|
|
|
|
if (scrollAmount > 0)
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
{
|
2020-06-12 21:51:37 +02:00
|
|
|
const auto newViewTop = std::max(0, proposedCursorPosition.Y - (_mutableViewport.Height() - 1));
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
if (newViewTop != _mutableViewport.Top())
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2020-04-29 21:28:59 +02:00
|
|
|
_mutableViewport = Viewport::FromDimensions({ 0, gsl::narrow<short>(newViewTop) },
|
|
|
|
_mutableViewport.Dimensions());
|
2020-06-12 21:51:37 +02:00
|
|
|
updatedViewport = true;
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
}
|
2019-10-15 06:44:52 +02:00
|
|
|
|
2020-06-12 21:51:37 +02:00
|
|
|
if (updatedViewport)
|
|
|
|
{
|
2020-07-09 13:24:20 +02:00
|
|
|
// scroll if...
|
|
|
|
// - no selection is active
|
|
|
|
// - viewport is already at the bottom
|
|
|
|
const bool scrollToOutput = !IsSelectionActive() && _scrollOffset == 0;
|
|
|
|
|
|
|
|
_scrollOffset = scrollToOutput ? 0 : _scrollOffset + scrollAmount + newRows;
|
|
|
|
|
2020-06-12 21:51:37 +02:00
|
|
|
_NotifyScrollEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rowsPushedOffTopOfBuffer != 0)
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
{
|
2020-04-13 22:09:02 +02:00
|
|
|
// We have to report the delta here because we might have circled the text buffer.
|
|
|
|
// That didn't change the viewport and therefore the TriggerScroll(void)
|
|
|
|
// method can't detect the delta on its own.
|
2020-06-12 21:51:37 +02:00
|
|
|
COORD delta{ 0, -rowsPushedOffTopOfBuffer };
|
2020-04-13 22:09:02 +02:00
|
|
|
_buffer->GetRenderTarget().TriggerScroll(&delta);
|
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request
This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.
## References
This is a followup to PR #4171
## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] 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: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435
## Detailed Description of the Pull Request / Additional comments
There are four changes to the `WriteCharsLegacy` implementation:
1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.
2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.
3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled.
4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.
Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.
Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.
## Validation Steps Performed
I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 20:18:46 +01:00
|
|
|
}
|
2020-03-31 01:21:47 +02:00
|
|
|
|
|
|
|
_NotifyTerminalCursorPositionChanged();
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Terminal::UserScrollViewport(const int viewTop)
|
|
|
|
{
|
2020-04-13 22:09:02 +02:00
|
|
|
// we're going to modify state here that the renderer could be reading.
|
|
|
|
auto lock = LockForWriting();
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
const auto clampedNewTop = std::max(0, viewTop);
|
Search - add search box control and implement search experience (#3590)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
This is the PR for feature Search: #605
This PR includes the newly introduced SearchBoxControl in TermControl dir, which is the search bar for the search experience. And the codes that enable Search in Windows Terminal.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
The PR that migrates the Conhost search module: https://github.com/microsoft/terminal/pull/3279
Spec (still actively updating): https://github.com/microsoft/terminal/pull/3299
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #605
* [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) 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: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
These functionalities are included in the search experience.
1. Search in Terminal text buffer.
2. Automatic wrap-around.
3. Search up or down switch by clicking different buttons.
4. Search case sensitively/insensitively by clicking a button. S. Move the search box to the top/bottom by clicking a button.
6. Close by clicking 'X'.
7. Open search by ctrl + F.
When the searchbox is open, the user could still interact with the terminal by clicking the terminal input area.
While I already have the search functionalities, currently there are still some known to-do works and I will keep updating my PR:
1. Optimize the search box UI, this includes:
1) Theme adaptation. The search box background and font color
should change according to the theme,
2) Add background. Currently the elements in search box are all
transparent. However, we need a background.
3) Move button should be highlighted once clicked.
2. Accessibility: search process should be able to performed without mouse. Once the search box is focused, the user should be able to navigate between all interactive elements on the searchbox using keyboard.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
To test:
1. checkout this branch.
2. Build the project.
3. Start Windows Terminal and press Ctrl+F
4. The search box should appear on the top right corner.
2019-12-17 16:52:37 +01:00
|
|
|
const auto realTop = ViewStartIndex();
|
2019-05-03 00:29:04 +02:00
|
|
|
const auto newDelta = realTop - clampedNewTop;
|
|
|
|
// if viewTop > realTop, we want the offset to be 0.
|
|
|
|
|
|
|
|
_scrollOffset = std::max(0, newDelta);
|
2020-04-13 22:09:02 +02:00
|
|
|
|
|
|
|
// We can use the void variant of TriggerScroll here because
|
|
|
|
// we adjusted the viewport so it can detect the difference
|
|
|
|
// from the previous frame drawn.
|
|
|
|
_buffer->GetRenderTarget().TriggerScroll();
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
2020-01-03 19:44:27 +01:00
|
|
|
int Terminal::GetScrollOffset() noexcept
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
return _VisibleStartIndex();
|
|
|
|
}
|
|
|
|
|
2020-01-03 19:44:27 +01:00
|
|
|
void Terminal::_NotifyScrollEvent() noexcept
|
|
|
|
try
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
|
|
|
if (_pfnScrollPositionChanged)
|
|
|
|
{
|
|
|
|
const auto visible = _GetVisibleViewport();
|
|
|
|
const auto top = visible.Top();
|
|
|
|
const auto height = visible.Height();
|
|
|
|
const auto bottom = this->GetBufferHeight();
|
|
|
|
_pfnScrollPositionChanged(top, height, bottom);
|
|
|
|
}
|
|
|
|
}
|
2020-01-03 19:44:27 +01:00
|
|
|
CATCH_LOG()
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2020-03-31 01:21:47 +02:00
|
|
|
void Terminal::_NotifyTerminalCursorPositionChanged() noexcept
|
|
|
|
{
|
|
|
|
if (_pfnCursorPositionChanged)
|
|
|
|
{
|
2020-04-17 03:10:29 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
_pfnCursorPositionChanged();
|
|
|
|
}
|
|
|
|
CATCH_LOG();
|
2020-03-31 01:21:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
void Terminal::SetWriteInputCallback(std::function<void(std::wstring&)> pfn) noexcept
|
|
|
|
{
|
2020-01-03 19:44:27 +01:00
|
|
|
_pfnWriteInput.swap(pfn);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Terminal::SetTitleChangedCallback(std::function<void(const std::wstring_view&)> pfn) noexcept
|
|
|
|
{
|
2020-01-03 19:44:27 +01:00
|
|
|
_pfnTitleChanged.swap(pfn);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
2020-06-30 03:55:40 +02:00
|
|
|
void Terminal::SetCopyToClipboardCallback(std::function<void(const std::wstring_view&)> pfn) noexcept
|
|
|
|
{
|
|
|
|
_pfnCopyToClipboard.swap(pfn);
|
|
|
|
}
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
void Terminal::SetScrollPositionChangedCallback(std::function<void(const int, const int, const int)> pfn) noexcept
|
|
|
|
{
|
2020-01-03 19:44:27 +01:00
|
|
|
_pfnScrollPositionChanged.swap(pfn);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
|
|
|
|
2020-03-31 01:21:47 +02:00
|
|
|
void Terminal::SetCursorPositionChangedCallback(std::function<void()> pfn) noexcept
|
|
|
|
{
|
|
|
|
_pfnCursorPositionChanged.swap(pfn);
|
|
|
|
}
|
|
|
|
|
2019-05-24 18:53:00 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Allows setting a callback for when the background color is changed
|
|
|
|
// Arguments:
|
|
|
|
// - pfn: a function callback that takes a uint32 (DWORD COLORREF) color in the format 0x00BBGGRR
|
2020-05-16 00:43:00 +02:00
|
|
|
void Terminal::SetBackgroundCallback(std::function<void(const COLORREF)> pfn) noexcept
|
2019-05-24 18:53:00 +02:00
|
|
|
{
|
2020-01-03 19:44:27 +01:00
|
|
|
_pfnBackgroundColorChanged.swap(pfn);
|
2019-05-24 18:53:00 +02:00
|
|
|
}
|
|
|
|
|
2019-05-03 00:29:04 +02:00
|
|
|
void Terminal::_InitializeColorTable()
|
2020-01-03 19:44:27 +01:00
|
|
|
try
|
2019-05-03 00:29:04 +02:00
|
|
|
{
|
2020-07-14 20:30:59 +02:00
|
|
|
const gsl::span<COLORREF> tableView = { _colorTable.data(), _colorTable.size() };
|
2019-05-03 00:29:04 +02:00
|
|
|
// First set up the basic 256 colors
|
2019-06-05 01:31:36 +02:00
|
|
|
Utils::Initialize256ColorTable(tableView);
|
2019-05-03 00:29:04 +02:00
|
|
|
// Then use fill the first 16 values with the Campbell scheme
|
2019-06-05 01:31:36 +02:00
|
|
|
Utils::InitializeCampbellColorTable(tableView);
|
2019-05-03 00:29:04 +02:00
|
|
|
// Then make sure all the values have an alpha of 255
|
2019-06-05 01:31:36 +02:00
|
|
|
Utils::SetColorTableAlpha(tableView, 0xff);
|
2019-05-03 00:29:04 +02:00
|
|
|
}
|
2020-01-03 19:44:27 +01:00
|
|
|
CATCH_LOG()
|
2019-05-03 00:29:04 +02:00
|
|
|
|
2019-05-14 03:25:54 +02:00
|
|
|
// Method Description:
|
2020-03-13 18:39:42 +01:00
|
|
|
// - Sets the cursor to be currently on. On/Off is tracked independently of
|
|
|
|
// cursor visibility (hidden/visible). On/off is controlled by the cursor
|
|
|
|
// blinker. Visibility is usually controlled by the client application. If the
|
|
|
|
// cursor is hidden, then the cursor will remain hidden. If the cursor is
|
|
|
|
// Visible, then it will immediately become visible.
|
2019-05-14 03:25:54 +02:00
|
|
|
// Arguments:
|
|
|
|
// - isVisible: whether the cursor should be visible
|
Show a double width cursor for double width characters (#5319)
# Summary of the Pull Request
This PR will allow the cursor to be double width when on top of a double width character. This required changing `IsCursorDoubleWidth` to check whether the glyph the cursor's on top of is double width. This code is exactly the same as the original PR that addressed this issue in #2932. That one got reverted at some point due to the crashes related to it, but due to a combination of Terminal having come further since that PR and other changes to address use-after-frees, some of the crashes may/may not be relevant now. The ones that seemed to be relevant/repro-able, I attempt to address in this PR.
The `IsCursorDoubleWidth` check would fail during the `TextBuffer::Reflow` call inside of `Terminal::UserResize` occasionally, particularly when `newCursor.EndDeferDrawing()` is called. This is because when we tell the newCursor to `EndDefer`, the renderer will attempt to redraw the cursor. As part of this redraw, it'll ask if `IsCursorDoubleWidth`, and if the renderer managed to ask this before `UserResize` swapped out the old buffer with the new one from `Reflow`, the renderer will be asking the old buffer if its out-of-bounds cursor is double width. This was pretty easily repro'd using `cmatrix -u0` and resizing the window like a madman.
As a solution, I've moved the Start/End DeferDrawing calls out of `Reflow` and into `UserResize`. This way, I can "clamp" the portion of the code where the newBuffer is getting created and reflowed and swapped into the Terminal buffer, and only allow the renderer to draw once the swap is done. This also means that ConHost's `ResizeWithReflow` needed to change slightly.
In addition, I've added a WriteLock to `SetCursorOn`. It was mentioned as a fix for a crash in #2965 (although I can't repro), and I also figured it would be good to try to emulate where ConHost locks with regards to Cursor operations, and this seemed to be one that we were missing.
## PR Checklist
* [x] Closes #2713
* [x] CLA signed
* [x] Tests added/passed
## Validation Steps Performed
Manual validation that the cursor is indeed chonky, added a test case to check that we are correctly saying that the cursor is double width (not too sure if I put it in the right place). Also open to other test case ideas and thoughts on what else I should be careful for since I am quite nervous about what other crashes might occur.
2020-04-15 21:23:06 +02:00
|
|
|
void Terminal::SetCursorOn(const bool isOn)
|
2019-05-14 03:25:54 +02:00
|
|
|
{
|
Show a double width cursor for double width characters (#5319)
# Summary of the Pull Request
This PR will allow the cursor to be double width when on top of a double width character. This required changing `IsCursorDoubleWidth` to check whether the glyph the cursor's on top of is double width. This code is exactly the same as the original PR that addressed this issue in #2932. That one got reverted at some point due to the crashes related to it, but due to a combination of Terminal having come further since that PR and other changes to address use-after-frees, some of the crashes may/may not be relevant now. The ones that seemed to be relevant/repro-able, I attempt to address in this PR.
The `IsCursorDoubleWidth` check would fail during the `TextBuffer::Reflow` call inside of `Terminal::UserResize` occasionally, particularly when `newCursor.EndDeferDrawing()` is called. This is because when we tell the newCursor to `EndDefer`, the renderer will attempt to redraw the cursor. As part of this redraw, it'll ask if `IsCursorDoubleWidth`, and if the renderer managed to ask this before `UserResize` swapped out the old buffer with the new one from `Reflow`, the renderer will be asking the old buffer if its out-of-bounds cursor is double width. This was pretty easily repro'd using `cmatrix -u0` and resizing the window like a madman.
As a solution, I've moved the Start/End DeferDrawing calls out of `Reflow` and into `UserResize`. This way, I can "clamp" the portion of the code where the newBuffer is getting created and reflowed and swapped into the Terminal buffer, and only allow the renderer to draw once the swap is done. This also means that ConHost's `ResizeWithReflow` needed to change slightly.
In addition, I've added a WriteLock to `SetCursorOn`. It was mentioned as a fix for a crash in #2965 (although I can't repro), and I also figured it would be good to try to emulate where ConHost locks with regards to Cursor operations, and this seemed to be one that we were missing.
## PR Checklist
* [x] Closes #2713
* [x] CLA signed
* [x] Tests added/passed
## Validation Steps Performed
Manual validation that the cursor is indeed chonky, added a test case to check that we are correctly saying that the cursor is double width (not too sure if I put it in the right place). Also open to other test case ideas and thoughts on what else I should be careful for since I am quite nervous about what other crashes might occur.
2020-04-15 21:23:06 +02:00
|
|
|
auto lock = LockForWriting();
|
2020-03-13 18:39:42 +01:00
|
|
|
_buffer->GetCursor().SetIsOn(isOn);
|
2019-05-14 03:25:54 +02:00
|
|
|
}
|
2019-05-23 19:44:27 +02:00
|
|
|
|
|
|
|
bool Terminal::IsCursorBlinkingAllowed() const noexcept
|
|
|
|
{
|
|
|
|
const auto& cursor = _buffer->GetCursor();
|
|
|
|
return cursor.IsBlinkingAllowed();
|
|
|
|
}
|