-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement the rest of the FTCS marks #14341
Changes from 11 commits
58b5d99
63ffcc0
f1a96c4
a1b9dac
a3ede80
b3c523c
b02d222
43875fd
609e354
2317192
045ceaf
5c33a61
0e184f1
302c99e
0bcb6ed
ba9e1c0
887f16a
9257c1f
c70afe7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -804,11 +804,34 @@ bool Terminal::SendCharEvent(const wchar_t ch, const WORD scanCode, const Contro | |
// Then treat this line like it's a prompt mark. | ||
if (_autoMarkPrompts && vkey == VK_RETURN && !_inAltBuffer()) | ||
{ | ||
DispatchTypes::ScrollMark mark; | ||
mark.category = DispatchTypes::MarkCategory::Prompt; | ||
// Don't set the color - we'll automatically use the DEFAULT_FOREGROUND | ||
// color for any MarkCategory::Prompt marks without one set. | ||
AddMark(mark); | ||
// * If we have a _currentPrompt: | ||
// - Then we did know that the prompt started, (we may have also | ||
// already gotten a CommandStart sequence). The user has pressed | ||
// enter, and we're treating that like the prompt has now ended. | ||
// - Perform a FTCS_COMMAND_EXECUTED, so that we start marking this | ||
// as output. | ||
// - This enables CMD to have full FTCS support, even though there's | ||
// no point in CMD to insert a "preexec" hook | ||
// * Else: We don't have a prompt. We don't know anything else, but we | ||
// can set the whole line as the prompt, no command, and start the | ||
// command_executed now. | ||
|
||
if (_currentPrompt) | ||
{ | ||
OutputStart(); | ||
} | ||
else | ||
{ | ||
DispatchTypes::ScrollMark mark; | ||
mark.category = DispatchTypes::MarkCategory::Prompt; | ||
// Don't set the color - we'll automatically use the DEFAULT_FOREGROUND | ||
// color for any MarkCategory::Prompt marks without one set. | ||
|
||
AddMark(mark); // without parameters, this will act as if it came | ||
// from the connection itself, and set _currentPromptState accordingly | ||
|
||
OutputStart(); | ||
} | ||
} | ||
|
||
// Unfortunately, the UI doesn't give us both a character down and a | ||
|
@@ -1251,8 +1274,20 @@ void Terminal::_AdjustCursorPosition(const til::point proposedPosition) | |
{ | ||
for (auto& mark : _scrollMarks) | ||
{ | ||
// Move the mark up | ||
mark.start.y -= rowsPushedOffTopOfBuffer; | ||
|
||
// If the mark had sub-regions, then move those pointers too | ||
if (mark.commandEnd.has_value()) | ||
{ | ||
(*mark.commandEnd).y -= rowsPushedOffTopOfBuffer; | ||
} | ||
if (mark.outputEnd.has_value()) | ||
{ | ||
(*mark.outputEnd).y -= rowsPushedOffTopOfBuffer; | ||
} | ||
} | ||
|
||
_scrollMarks.erase(std::remove_if(_scrollMarks.begin(), | ||
_scrollMarks.end(), | ||
[](const VirtualTerminal::DispatchTypes::ScrollMark& m) { return m.start.y < 0; }), | ||
|
@@ -1542,9 +1577,11 @@ void Terminal::_updateUrlDetection() | |
} | ||
} | ||
|
||
// NOTE: This is the version of AddMark that comes from the UI. The VT api call into this too. | ||
void Terminal::AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark, | ||
zadjii-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const til::point& start, | ||
const til::point& end) | ||
const til::point& end, | ||
const bool fromUi) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe that using indices would be better than using |
||
{ | ||
if (_inAltBuffer()) | ||
{ | ||
|
@@ -1555,11 +1592,21 @@ void Terminal::AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes: | |
m.start = start; | ||
m.end = end; | ||
|
||
_scrollMarks.push_back(m); | ||
if (fromUi) | ||
{ | ||
_scrollMarks.insert(_scrollMarks.begin(), m); | ||
} | ||
else | ||
{ | ||
_scrollMarks.push_back(m); | ||
} | ||
|
||
// Tell the control that the scrollbar has somehow changed. Used as a | ||
// workaround to force the control to redraw any scrollbar marks | ||
_NotifyScrollEvent(); | ||
|
||
// DON'T set _currentPrompt. The VT impl will do that for you. We don't want | ||
// UI-driven marks to set that. | ||
} | ||
|
||
void Terminal::ClearMark() | ||
|
@@ -1576,13 +1623,19 @@ void Terminal::ClearMark() | |
start = til::point{ GetSelectionAnchor() }; | ||
end = til::point{ GetSelectionEnd() }; | ||
} | ||
auto inSelection = [&start, &end](const DispatchTypes::ScrollMark& m) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (I just realized that the two positions were for a selection!) |
||
return (m.start >= start && m.start <= end) || | ||
(m.end >= start && m.end <= end); | ||
}; | ||
|
||
if (_currentPrompt && inSelection(*_currentPrompt)) | ||
{ | ||
_currentPrompt = nullptr; | ||
} | ||
|
||
_scrollMarks.erase(std::remove_if(_scrollMarks.begin(), | ||
_scrollMarks.end(), | ||
[&start, &end](const auto& m) { | ||
return (m.start >= start && m.start <= end) || | ||
(m.end >= start && m.end <= end); | ||
}), | ||
inSelection), | ||
_scrollMarks.end()); | ||
|
||
// Tell the control that the scrollbar has somehow changed. Used as a | ||
|
@@ -1591,6 +1644,7 @@ void Terminal::ClearMark() | |
} | ||
void Terminal::ClearAllMarks() noexcept | ||
{ | ||
_currentPrompt = nullptr; | ||
_scrollMarks.clear(); | ||
// Tell the control that the scrollbar has somehow changed. Used as a | ||
// workaround to force the control to redraw any scrollbar marks | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2665,14 +2665,52 @@ bool AdaptDispatch::DoFinalTermAction(const std::wstring_view string) | |
} | ||
|
||
const auto action = til::at(parts, 0); | ||
|
||
if (action == L"A") // FTCS_PROMPT | ||
if (action.size() == 1) | ||
{ | ||
// Simply just mark this line as a prompt line. | ||
DispatchTypes::ScrollMark mark; | ||
mark.category = DispatchTypes::MarkCategory::Prompt; | ||
_api.AddMark(mark); | ||
return true; | ||
switch (action[0]) | ||
{ | ||
case L'A': // FTCS_PROMPT | ||
{ | ||
// Simply just mark this line as a prompt line. | ||
DispatchTypes::ScrollMark mark; | ||
mark.category = DispatchTypes::MarkCategory::Prompt; | ||
_api.AddMark(mark); | ||
return true; | ||
} | ||
case L'B': // FTCS_COMMAND_START | ||
{ | ||
_api.CommandStart(); | ||
zadjii-msft marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return true; | ||
} | ||
case L'C': // FTCS_COMMAND_EXECUTED | ||
{ | ||
_api.OutputStart(); | ||
return true; | ||
} | ||
case L'D': // FTCS_COMMAND_FINISHED | ||
{ | ||
std::optional<unsigned int> error = std::nullopt; | ||
if (parts.size() >= 2) | ||
{ | ||
const auto errorString = til::at(parts, 1); | ||
|
||
// If we fail to parse the code, then it was gibberish, or it might | ||
// have just started with "-". Either way, let's just treat it as an | ||
// error and move on. | ||
// | ||
// We know that "0" will be successfully parsed, and that's close enough. | ||
unsigned int parsedError = 0; | ||
error = Utils::StringToUint(errorString, parsedError) ? parsedError : | ||
static_cast<unsigned int>(-1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am moderately horrified about this actually -- why is this better than |
||
} | ||
_api.CommandFinished(error); | ||
return true; | ||
} | ||
default: | ||
{ | ||
return false; | ||
} | ||
} | ||
} | ||
|
||
// When we add the rest of the FTCS sequences (GH#11000), we should add a | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Both branches end up calling
OutputStart
at the end.