Experimental: add support for scrollbar marks (#12948)
Adds support for marks in the scrollbar. These marks can be added in 3 ways: * Via the iterm2 `OSC 1337 ; SetMark` sequence * Via the `addMark` action * Automatically when the `experimental.autoMarkPrompts` per-profile setting is enabled. #11000 has more tracking for the big-picture for this feature, as well as additional follow-ups. This set of functionality seemed complete enough to send a review for now. That issue describes these how I wish these actions to look in the fullness of time. This is simply the v0.1 from the hackathon last month. #### Actions * `addMark`: add a mark to the buffer. If there's a selection, use place the mark covering at the selection. Otherwise, place the mark on the cursor row. - `color`: a color for the scrollbar mark. This is optional - defaults to the `foreground` color of the current scheme if omitted. * `scrollToMark` - `direction`: `["first", "previous", "next", "last"]` * `clearMark`: Clears marks at the current postition (either the selection if there is one, or the cursor position. * `clearAllMarks`: Don't think this needs explanation. #### Per-profile settings * `experimental.autoMarkPrompts`: `bool`, default `false`. * `experimental.showMarksOnScrollbar`: `bool` ## PR Checklist * [x] Closes #1527 * [x] Closes #6232 ## Detailed Description of the Pull Request / Additional comments This is basically hackathon code. It's experimental! That's okay! We'll figure the rest of the design in post. Theoretically, I should make these actions `experimental.` as well, but it seemed like since the only way to see these guys was via the `experimental.showMarksOnScrollbar` setting, you've already broken yourself into experimental jail, and you know what you're doing. Things that won't work as expected: * resizing, ESPECIALLY reflowing * Clearing the buffer with ED sequences / Clear Buffer I could theoretically add velocity around this in the `TermControl` layer. Always prevent marks from being visible, ignore all the actions. Marks could still be set by VT and automark, but they'd be useless. Next up priorities: * Making this work with the FinalTerm sequences * properly speccing * adding support for `showMarksOnScrollbar: flags(categories)`, so you can only display errors on the scrollbar * adding the `category` flag to the `addMark` action ## Validation Steps Performed I like using it quite a bit. The marks can get noisy if you have them emitted on every prompt and the buffer has 9000 lines. But that's the beautiful thing, the actions work even if the marks aren't visible, so you can still scroll between prompts. <details> <summary>Settings blob</summary> ```jsonc // actions { "keys": "ctrl+up", "command": { "action": "scrollToMark", "direction": "previous" }, "name": "Previous mark" }, { "keys": "ctrl+down", "command": { "action": "scrollToMark", "direction": "next" }, "name": "Next mark" }, { "keys": "ctrl+pgup", "command": { "action": "scrollToMark", "direction": "first" }, "name": "First mark" }, { "keys": "ctrl+pgdn", "command": { "action": "scrollToMark", "direction": "last" }, "name": "Last mark" }, { "command": { "action": "addMark" } }, { "command": { "action": "addMark", "color": "#ff00ff" } }, { "command": { "action": "addMark", "color": "#0000ff" } }, { "command": { "action": "clearAllMarks" } }, // profiles.defaults "experimental.autoMarkPrompts": true, "experimental.showMarksOnScrollbar": true, ``` </details>
This commit is contained in:
parent
730eb5fafd
commit
799b5d4add
|
@ -278,6 +278,55 @@ namespace winrt::TerminalApp::implementation
|
|||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleScrollToMark(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<ScrollToMarkArgs>())
|
||||
{
|
||||
_ApplyToActiveControls([&realArgs](auto& control) {
|
||||
control.ScrollToMark(realArgs.Direction());
|
||||
});
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
void TerminalPage::_HandleAddMark(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<AddMarkArgs>())
|
||||
{
|
||||
_ApplyToActiveControls([realArgs](auto& control) {
|
||||
Control::ScrollMark mark;
|
||||
if (realArgs.Color())
|
||||
{
|
||||
mark.Color.Color = realArgs.Color().Value();
|
||||
mark.Color.HasValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mark.Color.HasValue = false;
|
||||
}
|
||||
control.AddMark(mark);
|
||||
});
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
void TerminalPage::_HandleClearMark(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_ApplyToActiveControls([](auto& control) {
|
||||
control.ClearMark();
|
||||
});
|
||||
args.Handled(true);
|
||||
}
|
||||
void TerminalPage::_HandleClearAllMarks(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_ApplyToActiveControls([](auto& control) {
|
||||
control.ClearAllMarks();
|
||||
});
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleFindMatch(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
|
|
|
@ -37,6 +37,28 @@ constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(
|
|||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
static winrt::Microsoft::Terminal::Core::OptionalColor OptionalFromColor(const til::color& c)
|
||||
{
|
||||
Core::OptionalColor result;
|
||||
result.Color = c;
|
||||
result.HasValue = true;
|
||||
return result;
|
||||
}
|
||||
static winrt::Microsoft::Terminal::Core::OptionalColor OptionalFromColor(const std::optional<til::color>& c)
|
||||
{
|
||||
Core::OptionalColor result;
|
||||
if (c.has_value())
|
||||
{
|
||||
result.Color = *c;
|
||||
result.HasValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.HasValue = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper static function to ensure that all ambiguous-width glyphs are reported as narrow.
|
||||
// See microsoft/terminal#2066 for more info.
|
||||
static bool _IsGlyphWideForceNarrowFallback(const std::wstring_view /* glyph */)
|
||||
|
@ -1196,6 +1218,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
const int viewHeight,
|
||||
const int bufferSize)
|
||||
{
|
||||
if (!_initializedTerminal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Clear the regex pattern tree so the renderer does not try to render them while scrolling
|
||||
// We're **NOT** taking the lock here unlike _scrollbarChangeHandler because
|
||||
// we are already under lock (since this usually happens as a result of writing).
|
||||
|
@ -1854,4 +1880,140 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// transparency, or our acrylic, or our image.
|
||||
return Opacity() < 1.0f || UseAcrylic() || !_settings->BackgroundImage().empty() || _settings->UseBackgroundImageForWindow();
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IVector<Control::ScrollMark> ControlCore::ScrollMarks() const
|
||||
{
|
||||
auto internalMarks{ _terminal->GetScrollMarks() };
|
||||
auto v = winrt::single_threaded_observable_vector<Control::ScrollMark>();
|
||||
for (const auto& mark : internalMarks)
|
||||
{
|
||||
Control::ScrollMark m{};
|
||||
|
||||
// sneaky: always evaluate the color of the mark to a real value
|
||||
// before shoving it into the optional. If the mark doesn't have a
|
||||
// specific color set, we'll use the value from the color table
|
||||
// that's appropriate for this category of mark. If we do have a
|
||||
// color set, then great we'll use that. The TermControl can then
|
||||
// always use the value in the Mark regardless if it was actually
|
||||
// set or not.
|
||||
m.Color = OptionalFromColor(_terminal->GetColorForMark(mark));
|
||||
m.Start = mark.start.to_core_point();
|
||||
m.End = mark.end.to_core_point();
|
||||
|
||||
v.Append(m);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void ControlCore::AddMark(const Control::ScrollMark& mark)
|
||||
{
|
||||
::Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark m{};
|
||||
|
||||
if (mark.Color.HasValue)
|
||||
{
|
||||
m.color = til::color{ mark.Color.Color };
|
||||
}
|
||||
|
||||
if (HasSelection())
|
||||
{
|
||||
m.start = til::point{ _terminal->GetSelectionAnchor() };
|
||||
m.end = til::point{ _terminal->GetSelectionEnd() };
|
||||
}
|
||||
else
|
||||
{
|
||||
m.start = m.end = til::point{ _terminal->GetTextBuffer().GetCursor().GetPosition() };
|
||||
}
|
||||
|
||||
// The version of this that only accepts a ScrollMark will automatically
|
||||
// set the start & end to the cursor position.
|
||||
_terminal->AddMark(m, m.start, m.end);
|
||||
}
|
||||
void ControlCore::ClearMark() { _terminal->ClearMark(); }
|
||||
void ControlCore::ClearAllMarks() { _terminal->ClearAllMarks(); }
|
||||
|
||||
void ControlCore::ScrollToMark(const Control::ScrollToMarkDirection& direction)
|
||||
{
|
||||
const auto currentOffset = ScrollOffset();
|
||||
const auto& marks{ _terminal->GetScrollMarks() };
|
||||
|
||||
std::optional<DispatchTypes::ScrollMark> tgt;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case ScrollToMarkDirection::Last:
|
||||
{
|
||||
int highest = currentOffset;
|
||||
for (const auto& mark : marks)
|
||||
{
|
||||
const auto newY = mark.start.y;
|
||||
if (newY > highest)
|
||||
{
|
||||
tgt = mark;
|
||||
highest = newY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ScrollToMarkDirection::First:
|
||||
{
|
||||
int lowest = currentOffset;
|
||||
for (const auto& mark : marks)
|
||||
{
|
||||
const auto newY = mark.start.y;
|
||||
if (newY < lowest)
|
||||
{
|
||||
tgt = mark;
|
||||
lowest = newY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ScrollToMarkDirection::Next:
|
||||
{
|
||||
int minDistance = INT_MAX;
|
||||
for (const auto& mark : marks)
|
||||
{
|
||||
const auto delta = mark.start.y - currentOffset;
|
||||
if (delta > 0 && delta < minDistance)
|
||||
{
|
||||
tgt = mark;
|
||||
minDistance = delta;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ScrollToMarkDirection::Previous:
|
||||
default:
|
||||
{
|
||||
int minDistance = INT_MAX;
|
||||
for (const auto& mark : marks)
|
||||
{
|
||||
const auto delta = currentOffset - mark.start.y;
|
||||
if (delta > 0 && delta < minDistance)
|
||||
{
|
||||
tgt = mark;
|
||||
minDistance = delta;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tgt.has_value())
|
||||
{
|
||||
UserScrollViewport(tgt->start.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (direction == ScrollToMarkDirection::Last || direction == ScrollToMarkDirection::Next)
|
||||
{
|
||||
UserScrollViewport(BufferHeight());
|
||||
}
|
||||
else if (direction == ScrollToMarkDirection::First || direction == ScrollToMarkDirection::Previous)
|
||||
{
|
||||
UserScrollViewport(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,6 +119,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
int BufferHeight() const;
|
||||
|
||||
bool BracketedPasteEnabled() const noexcept;
|
||||
|
||||
Windows::Foundation::Collections::IVector<Control::ScrollMark> ScrollMarks() const;
|
||||
void AddMark(const Control::ScrollMark& mark);
|
||||
void ClearMark();
|
||||
void ClearAllMarks();
|
||||
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ITerminalInput
|
||||
|
|
|
@ -22,7 +22,6 @@ namespace Microsoft.Terminal.Control
|
|||
IsRightButtonDown = 0x4
|
||||
};
|
||||
|
||||
|
||||
enum ClearBufferType
|
||||
{
|
||||
Screen,
|
||||
|
|
|
@ -56,6 +56,7 @@ namespace Microsoft.Terminal.Control
|
|||
// Experimental Settings
|
||||
Boolean ForceFullRepaintRendering { get; };
|
||||
Boolean SoftwareRendering { get; };
|
||||
Boolean ShowMarks { get; };
|
||||
Boolean UseBackgroundImageForWindow { get; };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,6 +3,32 @@
|
|||
|
||||
namespace Microsoft.Terminal.Control
|
||||
{
|
||||
enum MarkCategory
|
||||
{
|
||||
Prompt = 0,
|
||||
Error = 1,
|
||||
Warning = 2,
|
||||
Info = 3
|
||||
};
|
||||
|
||||
struct ScrollMark
|
||||
{
|
||||
// There are other members of DispatchTypes::ScrollMark, but these are
|
||||
// all we need to expose up and set downwards currently. Additional
|
||||
// members can be bubbled as necessary.
|
||||
Microsoft.Terminal.Core.Point Start;
|
||||
Microsoft.Terminal.Core.Point End; // exclusive
|
||||
Microsoft.Terminal.Core.OptionalColor Color;
|
||||
};
|
||||
|
||||
enum ScrollToMarkDirection
|
||||
{
|
||||
Previous,
|
||||
Next,
|
||||
First,
|
||||
Last
|
||||
};
|
||||
|
||||
// These are properties of the TerminalCore that should be queryable by the
|
||||
// rest of the app.
|
||||
interface ICoreState
|
||||
|
@ -27,5 +53,11 @@ namespace Microsoft.Terminal.Control
|
|||
|
||||
UInt64 OwningHwnd;
|
||||
|
||||
void AddMark(ScrollMark mark);
|
||||
void ClearMark();
|
||||
void ClearAllMarks();
|
||||
void ScrollToMark(ScrollToMarkDirection direction);
|
||||
IVector<ScrollMark> ScrollMarks { get; };
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -124,9 +124,26 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
[weakThis = get_weak()](const auto& update) {
|
||||
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||
{
|
||||
control->_isInternalScrollBarUpdate = true;
|
||||
control->_throttledUpdateScrollbar(update);
|
||||
}
|
||||
});
|
||||
|
||||
auto scrollBar = control->ScrollBar();
|
||||
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
|
||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||
_autoScrollTimer.Tick({ this, &TermControl::_UpdateAutoScroll });
|
||||
|
||||
_ApplyUISettings();
|
||||
}
|
||||
|
||||
void TermControl::_throttledUpdateScrollbar(const ScrollBarUpdate& update)
|
||||
{
|
||||
// Assumptions:
|
||||
// * we're already not closing
|
||||
// * caller already checked weak ptr to make sure we're still alive
|
||||
|
||||
_isInternalScrollBarUpdate = true;
|
||||
|
||||
auto scrollBar = ScrollBar();
|
||||
if (update.newValue)
|
||||
{
|
||||
scrollBar.Value(*update.newValue);
|
||||
|
@ -137,15 +154,36 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// scroll one full screen worth at a time when the scroll bar is clicked
|
||||
scrollBar.LargeChange(std::max(update.newViewportSize - 1, 0.));
|
||||
|
||||
control->_isInternalScrollBarUpdate = false;
|
||||
_isInternalScrollBarUpdate = false;
|
||||
|
||||
if (_showMarksInScrollbar)
|
||||
{
|
||||
// Update scrollbar marks
|
||||
ScrollBarCanvas().Children().Clear();
|
||||
const auto marks{ _core.ScrollMarks() };
|
||||
const auto fullHeight{ ScrollBarCanvas().ActualHeight() };
|
||||
const auto totalBufferRows{ update.newMaximum + update.newViewportSize };
|
||||
|
||||
for (const auto m : marks)
|
||||
{
|
||||
Windows::UI::Xaml::Shapes::Rectangle r;
|
||||
Media::SolidColorBrush brush{};
|
||||
// Sneaky: technically, a mark doesn't need to have a color set,
|
||||
// it might want to just use the color from the palette for that
|
||||
// kind of mark. Fortunately, ControlCore is kind enough to
|
||||
// pre-evaluate that for us, and shove the real value into the
|
||||
// Color member, regardless if the mark has a literal value set.
|
||||
brush.Color(static_cast<til::color>(m.Color.Color));
|
||||
r.Fill(brush);
|
||||
r.Width(16.0f / 3.0f); // pip width - 1/3rd of the scrollbar width.
|
||||
r.Height(2);
|
||||
const auto markRow = m.Start.Y;
|
||||
const auto fractionalHeight = markRow / totalBufferRows;
|
||||
const auto relativePos = fractionalHeight * fullHeight;
|
||||
ScrollBarCanvas().Children().Append(r);
|
||||
Windows::UI::Xaml::Controls::Canvas::SetTop(r, relativePos);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
|
||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||
_autoScrollTimer.Tick({ this, &TermControl::_UpdateAutoScroll });
|
||||
|
||||
_ApplyUISettings();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -404,6 +442,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
newMargin.Right,
|
||||
newMargin.Bottom });
|
||||
}
|
||||
|
||||
_showMarksInScrollbar = settings.ShowMarks();
|
||||
// Clear out all the current marks
|
||||
ScrollBarCanvas().Children().Clear();
|
||||
// When we hot reload the settings, the core will send us a scrollbar
|
||||
// update. If we enabled scrollbar marks, then great, when we handle
|
||||
// that message, we'll redraw them.
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -2863,4 +2908,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
return _core.OwningHwnd();
|
||||
}
|
||||
|
||||
void TermControl::AddMark(const Control::ScrollMark& mark)
|
||||
{
|
||||
_core.AddMark(mark);
|
||||
}
|
||||
void TermControl::ClearMark() { _core.ClearMark(); }
|
||||
void TermControl::ClearAllMarks() { _core.ClearAllMarks(); }
|
||||
void TermControl::ScrollToMark(const Control::ScrollToMarkDirection& direction) { _core.ScrollToMark(direction); }
|
||||
|
||||
Windows::Foundation::Collections::IVector<Control::ScrollMark> TermControl::ScrollMarks() const
|
||||
{
|
||||
return _core.ScrollMarks();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -67,6 +67,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
uint64_t OwningHwnd();
|
||||
void OwningHwnd(uint64_t owner);
|
||||
|
||||
Windows::Foundation::Collections::IVector<Control::ScrollMark> ScrollMarks() const;
|
||||
void AddMark(const Control::ScrollMark& mark);
|
||||
void ClearMark();
|
||||
void ClearAllMarks();
|
||||
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void ScrollViewport(int viewTop);
|
||||
|
@ -195,6 +202,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
std::optional<Windows::UI::Xaml::DispatcherTimer> _blinkTimer;
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
bool _showMarksInScrollbar{ false };
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
|
@ -287,6 +295,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
|
||||
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
|
||||
void _coreFoundMatch(const IInspectable& sender, const Control::FoundResultsArgs& args);
|
||||
void _throttledUpdateScrollbar(const ScrollBarUpdate& update);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1243,6 +1243,30 @@
|
|||
Style="{StaticResource ForkedScrollbarTemplate}"
|
||||
ValueChanged="_ScrollbarChangeHandler"
|
||||
ViewportSize="10" />
|
||||
|
||||
<Grid x:Name="ScrollMarksGrid"
|
||||
Grid.Column="1"
|
||||
Width="{StaticResource ScrollBarSize}"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Height="{StaticResource ScrollBarSize}" />
|
||||
<Canvas x:Name="ScrollBarCanvas"
|
||||
Grid.Row="1"
|
||||
Width="{StaticResource ScrollBarSize}"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch" />
|
||||
<Border Grid.Row="2"
|
||||
Height="{StaticResource ScrollBarSize}" />
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
<local:TSFInputControl x:Name="TSFInputControl"
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <winrt/Windows.UI.Xaml.Input.h>
|
||||
#include <winrt/Windows.UI.Xaml.Interop.h>
|
||||
#include <winrt/Windows.ui.xaml.markup.h>
|
||||
#include <winrt/Windows.ui.xaml.shapes.h>
|
||||
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
|
||||
|
|
|
@ -24,6 +24,15 @@ namespace Microsoft.Terminal.Core
|
|||
UInt8 A;
|
||||
};
|
||||
|
||||
// Yes, this is also just an IReference<Color>. However, IReference has some
|
||||
// weird ownership semantics that just make it a pain for something as
|
||||
// simple as "maybe this color doesn't have a value set".
|
||||
struct OptionalColor
|
||||
{
|
||||
Boolean HasValue;
|
||||
Microsoft.Terminal.Core.Color Color;
|
||||
};
|
||||
|
||||
// TerminalCore declares its own Color struct to avoid depending on
|
||||
// Windows.UI. Windows.Foundation.Point also exists, but it's composed of
|
||||
// floating-point coordinates, when we almost always need integer coordinates.
|
||||
|
|
|
@ -26,6 +26,9 @@ namespace Microsoft.Terminal.Core
|
|||
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Core.Color> TabColor;
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Core.Color> StartingTabColor;
|
||||
|
||||
Boolean AutoMarkPrompts;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,8 @@ Terminal::Terminal() :
|
|||
_selection{ std::nullopt },
|
||||
_taskbarState{ 0 },
|
||||
_taskbarProgress{ 0 },
|
||||
_trimBlockSelection{ false }
|
||||
_trimBlockSelection{ false },
|
||||
_autoMarkPrompts{ false }
|
||||
{
|
||||
auto passAlongInput = [&](std::deque<std::unique_ptr<IInputEvent>>& inEventsToWrite) {
|
||||
if (!_pfnWriteInput)
|
||||
|
@ -121,6 +122,7 @@ void Terminal::UpdateSettings(ICoreSettings settings)
|
|||
_suppressApplicationTitle = settings.SuppressApplicationTitle();
|
||||
_startingTitle = settings.StartingTitle();
|
||||
_trimBlockSelection = settings.TrimBlockSelection();
|
||||
_autoMarkPrompts = settings.AutoMarkPrompts();
|
||||
|
||||
_terminalInput->ForceDisableWin32InputMode(settings.ForceVTInput());
|
||||
|
||||
|
@ -211,6 +213,11 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
|
|||
}
|
||||
|
||||
_defaultCursorShape = cursorShape;
|
||||
|
||||
// Tell the control that the scrollbar has somehow changed. Used as a
|
||||
// workaround to force the control to redraw any scrollbar marks whose color
|
||||
// may have changed.
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
|
||||
void Terminal::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle)
|
||||
|
@ -750,6 +757,22 @@ bool Terminal::SendCharEvent(const wchar_t ch, const WORD scanCode, const Contro
|
|||
vkey = _VirtualKeyFromCharacter(ch);
|
||||
}
|
||||
|
||||
// GH#1527: When the user has auto mark prompts enabled, we're going to try
|
||||
// and heuristically detect if this was the line the prompt was on.
|
||||
// * If the key was an Enter keypress (Terminal.app also marks ^C keypresses
|
||||
// as prompts. That's omitted for now.)
|
||||
// * AND we're not in the alt buffer
|
||||
//
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -1198,6 +1221,17 @@ void Terminal::_AdjustCursorPosition(const til::point proposedPosition)
|
|||
|
||||
if (rowsPushedOffTopOfBuffer != 0)
|
||||
{
|
||||
if (_scrollMarks.size() > 0)
|
||||
{
|
||||
for (auto& mark : _scrollMarks)
|
||||
{
|
||||
mark.start.y -= rowsPushedOffTopOfBuffer;
|
||||
}
|
||||
_scrollMarks.erase(std::remove_if(_scrollMarks.begin(),
|
||||
_scrollMarks.end(),
|
||||
[](const VirtualTerminal::DispatchTypes::ScrollMark& m) { return m.start.y < 0; }),
|
||||
_scrollMarks.end());
|
||||
}
|
||||
// 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.
|
||||
|
@ -1450,6 +1484,11 @@ void Terminal::ApplyScheme(const Scheme& colorScheme)
|
|||
_renderSettings.SetColorTableEntry(TextColor::CURSOR_COLOR, til::color{ colorScheme.CursorColor });
|
||||
|
||||
_renderSettings.MakeAdjustedColorArray();
|
||||
|
||||
// Tell the control that the scrollbar has somehow changed. Used as a
|
||||
// workaround to force the control to redraw any scrollbar marks whose color
|
||||
// may have changed.
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
|
||||
bool Terminal::_inAltBuffer() const noexcept
|
||||
|
@ -1476,3 +1515,101 @@ void Terminal::_updateUrlDetection()
|
|||
ClearPatternTree();
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark,
|
||||
const til::point& start,
|
||||
const til::point& end)
|
||||
{
|
||||
if (_inAltBuffer())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchTypes::ScrollMark m = mark;
|
||||
m.start = start;
|
||||
m.end = end;
|
||||
|
||||
_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();
|
||||
}
|
||||
|
||||
void Terminal::ClearMark()
|
||||
{
|
||||
// Look for one where the cursor is, or where the selection is if we have
|
||||
// one. Any mark that intersects the cursor/selection, on either side
|
||||
// (inclusive), will get cleared.
|
||||
const til::point cursor{ _activeBuffer().GetCursor().GetPosition() };
|
||||
til::point start{ cursor };
|
||||
til::point end{ cursor };
|
||||
|
||||
if (IsSelectionActive())
|
||||
{
|
||||
start = til::point{ GetSelectionAnchor() };
|
||||
end = til::point{ GetSelectionEnd() };
|
||||
}
|
||||
|
||||
_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);
|
||||
}),
|
||||
_scrollMarks.end());
|
||||
|
||||
// Tell the control that the scrollbar has somehow changed. Used as a
|
||||
// workaround to force the control to redraw any scrollbar marks
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
void Terminal::ClearAllMarks()
|
||||
{
|
||||
_scrollMarks.clear();
|
||||
// Tell the control that the scrollbar has somehow changed. Used as a
|
||||
// workaround to force the control to redraw any scrollbar marks
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
|
||||
const std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark>& Terminal::GetScrollMarks() const
|
||||
{
|
||||
// TODO: GH#11000 - when the marks are stored per-buffer, get rid of this.
|
||||
// We want to return _no_ marks when we're in the alt buffer, to effectively
|
||||
// hide them. We need to return a reference, so we can't just ctor an empty
|
||||
// list here just for when we're in the alt buffer.
|
||||
static std::vector<DispatchTypes::ScrollMark> _altBufferMarks{};
|
||||
return _inAltBuffer() ? _altBufferMarks : _scrollMarks;
|
||||
}
|
||||
|
||||
til::color Terminal::GetColorForMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark) const
|
||||
{
|
||||
if (mark.color.has_value())
|
||||
{
|
||||
return *mark.color;
|
||||
}
|
||||
|
||||
switch (mark.category)
|
||||
{
|
||||
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Prompt:
|
||||
{
|
||||
return _renderSettings.GetColorAlias(ColorAlias::DefaultForeground);
|
||||
}
|
||||
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Error:
|
||||
{
|
||||
return _renderSettings.GetColorTableEntry(TextColor::BRIGHT_RED);
|
||||
}
|
||||
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Warning:
|
||||
{
|
||||
return _renderSettings.GetColorTableEntry(TextColor::BRIGHT_YELLOW);
|
||||
}
|
||||
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Success:
|
||||
{
|
||||
return _renderSettings.GetColorTableEntry(TextColor::BRIGHT_GREEN);
|
||||
}
|
||||
default:
|
||||
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Info:
|
||||
{
|
||||
return _renderSettings.GetColorAlias(ColorAlias::DefaultForeground);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,6 +102,11 @@ public:
|
|||
RenderSettings& GetRenderSettings() noexcept { return _renderSettings; };
|
||||
const RenderSettings& GetRenderSettings() const noexcept { return _renderSettings; };
|
||||
|
||||
const std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark>& GetScrollMarks() const;
|
||||
void AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark,
|
||||
const til::point& start,
|
||||
const til::point& end);
|
||||
|
||||
#pragma region ITerminalApi
|
||||
// These methods are defined in TerminalApi.cpp
|
||||
void PrintString(const std::wstring_view string) override;
|
||||
|
@ -129,11 +134,18 @@ public:
|
|||
void ShowWindow(bool showOrHide) override;
|
||||
void UseAlternateScreenBuffer() override;
|
||||
void UseMainScreenBuffer() override;
|
||||
|
||||
void AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark) override;
|
||||
|
||||
bool IsConsolePty() const override;
|
||||
bool IsVtInputEnabled() const override;
|
||||
void NotifyAccessibilityChange(const til::rect& changedRect) override;
|
||||
#pragma endregion
|
||||
|
||||
void ClearMark();
|
||||
void ClearAllMarks();
|
||||
til::color GetColorForMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark) const;
|
||||
|
||||
#pragma region ITerminalInput
|
||||
// These methods are defined in Terminal.cpp
|
||||
bool SendKeyEvent(const WORD vkey, const WORD scanCode, const Microsoft::Terminal::Core::ControlKeyStates states, const bool keyDown) override;
|
||||
|
@ -290,6 +302,7 @@ private:
|
|||
bool _suppressApplicationTitle;
|
||||
bool _bracketedPasteMode;
|
||||
bool _trimBlockSelection;
|
||||
bool _autoMarkPrompts;
|
||||
|
||||
size_t _taskbarState;
|
||||
size_t _taskbarProgress;
|
||||
|
@ -356,6 +369,8 @@ private:
|
|||
};
|
||||
std::optional<KeyEventCodes> _lastKeyEventCodes;
|
||||
|
||||
std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark> _scrollMarks;
|
||||
|
||||
static WORD _ScanCodeFromVirtualKey(const WORD vkey) noexcept;
|
||||
static WORD _VirtualKeyFromScanCode(const WORD scanCode) noexcept;
|
||||
static WORD _VirtualKeyFromCharacter(const wchar_t ch) noexcept;
|
||||
|
|
|
@ -298,6 +298,12 @@ void Terminal::UseMainScreenBuffer()
|
|||
CATCH_LOG();
|
||||
}
|
||||
|
||||
void Terminal::AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark)
|
||||
{
|
||||
const til::point cursorPos{ _activeBuffer().GetCursor().GetPosition() };
|
||||
AddMark(mark, cursorPos, cursorPos);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Reacts to a client asking us to show or hide the window.
|
||||
// Arguments:
|
||||
|
|
|
@ -39,6 +39,10 @@ static constexpr std::string_view ScrollUpKey{ "scrollUp" };
|
|||
static constexpr std::string_view ScrollUpPageKey{ "scrollUpPage" };
|
||||
static constexpr std::string_view ScrollToTopKey{ "scrollToTop" };
|
||||
static constexpr std::string_view ScrollToBottomKey{ "scrollToBottom" };
|
||||
static constexpr std::string_view ScrollToMarkKey{ "scrollToMark" };
|
||||
static constexpr std::string_view AddMarkKey{ "addMark" };
|
||||
static constexpr std::string_view ClearMarkKey{ "clearMark" };
|
||||
static constexpr std::string_view ClearAllMarksKey{ "clearAllMarks" };
|
||||
static constexpr std::string_view SendInputKey{ "sendInput" };
|
||||
static constexpr std::string_view SetColorSchemeKey{ "setColorScheme" };
|
||||
static constexpr std::string_view SetTabColorKey{ "setTabColor" };
|
||||
|
@ -354,6 +358,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
{ ShortcutAction::ScrollUpPage, RS_(L"ScrollUpPageCommandKey") },
|
||||
{ ShortcutAction::ScrollToTop, RS_(L"ScrollToTopCommandKey") },
|
||||
{ ShortcutAction::ScrollToBottom, RS_(L"ScrollToBottomCommandKey") },
|
||||
{ ShortcutAction::ScrollToMark, RS_(L"ScrollToPreviousMarkCommandKey") },
|
||||
{ ShortcutAction::AddMark, RS_(L"AddMarkCommandKey") },
|
||||
{ ShortcutAction::ClearMark, RS_(L"ClearMarkCommandKey") },
|
||||
{ ShortcutAction::ClearAllMarks, RS_(L"ClearAllMarksCommandKey") },
|
||||
{ ShortcutAction::SendInput, L"" },
|
||||
{ ShortcutAction::SetColorScheme, L"" },
|
||||
{ ShortcutAction::SetTabColor, RS_(L"ResetTabColorCommandKey") },
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "CloseTabsAfterArgs.g.cpp"
|
||||
#include "CloseTabArgs.g.cpp"
|
||||
#include "MoveTabArgs.g.cpp"
|
||||
#include "ScrollToMarkArgs.g.cpp"
|
||||
#include "AddMarkArgs.g.cpp"
|
||||
#include "FindMatchArgs.g.cpp"
|
||||
#include "ToggleCommandPaletteArgs.g.cpp"
|
||||
#include "NewWindowArgs.g.cpp"
|
||||
|
@ -611,6 +613,38 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
return RS_(L"ScrollDownCommandKey");
|
||||
}
|
||||
|
||||
winrt::hstring ScrollToMarkArgs::GenerateName() const
|
||||
{
|
||||
switch (Direction())
|
||||
{
|
||||
case Microsoft::Terminal::Control::ScrollToMarkDirection::Last:
|
||||
return winrt::hstring{ RS_(L"ScrollToLastMarkCommandKey") };
|
||||
case Microsoft::Terminal::Control::ScrollToMarkDirection::First:
|
||||
return winrt::hstring{ RS_(L"ScrollToFirstMarkCommandKey") };
|
||||
case Microsoft::Terminal::Control::ScrollToMarkDirection::Next:
|
||||
return winrt::hstring{ RS_(L"ScrollToNextMarkCommandKey") };
|
||||
case Microsoft::Terminal::Control::ScrollToMarkDirection::Previous:
|
||||
default:
|
||||
return winrt::hstring{ RS_(L"ScrollToPreviousMarkCommandKey") };
|
||||
}
|
||||
return winrt::hstring{ RS_(L"ScrollToPreviousMarkCommandKey") };
|
||||
}
|
||||
|
||||
winrt::hstring AddMarkArgs::GenerateName() const
|
||||
{
|
||||
if (Color())
|
||||
{
|
||||
return winrt::hstring{
|
||||
fmt::format(std::wstring_view(RS_(L"AddMarkWithColorCommandKey")),
|
||||
til::color{ Color().Value() }.ToHexString(true))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return RS_(L"AddMarkCommandKey");
|
||||
}
|
||||
}
|
||||
|
||||
winrt::hstring MoveTabArgs::GenerateName() const
|
||||
{
|
||||
winrt::hstring directionString;
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "CloseTabArgs.g.h"
|
||||
#include "ScrollUpArgs.g.h"
|
||||
#include "ScrollDownArgs.g.h"
|
||||
#include "ScrollToMarkArgs.g.h"
|
||||
#include "AddMarkArgs.g.h"
|
||||
#include "MoveTabArgs.g.h"
|
||||
#include "ToggleCommandPaletteArgs.g.h"
|
||||
#include "FindMatchArgs.g.h"
|
||||
|
@ -180,6 +182,14 @@ private:
|
|||
#define SCROLL_DOWN_ARGS(X) \
|
||||
X(Windows::Foundation::IReference<uint32_t>, RowsToScroll, "rowsToScroll", false, nullptr)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SCROLL_TO_MARK_ARGS(X) \
|
||||
X(Microsoft::Terminal::Control::ScrollToMarkDirection, Direction, "direction", false, Microsoft::Terminal::Control::ScrollToMarkDirection::Previous)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define ADD_MARK_ARGS(X) \
|
||||
X(Windows::Foundation::IReference<Microsoft::Terminal::Core::Color>, Color, "color", false, nullptr)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define TOGGLE_COMMAND_PALETTE_ARGS(X) \
|
||||
X(CommandPaletteLaunchMode, LaunchMode, "launchMode", false, CommandPaletteLaunchMode::Action)
|
||||
|
@ -612,6 +622,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
ACTION_ARGS_STRUCT(ScrollDownArgs, SCROLL_DOWN_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(ScrollToMarkArgs, SCROLL_TO_MARK_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(AddMarkArgs, ADD_MARK_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(ToggleCommandPaletteArgs, TOGGLE_COMMAND_PALETTE_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(FindMatchArgs, FIND_MATCH_ARGS);
|
||||
|
|
|
@ -290,6 +290,17 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
Windows.Foundation.IReference<UInt32> RowsToScroll { get; };
|
||||
};
|
||||
|
||||
|
||||
[default_interface] runtimeclass ScrollToMarkArgs : IActionArgs
|
||||
{
|
||||
Microsoft.Terminal.Control.ScrollToMarkDirection Direction { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass AddMarkArgs : IActionArgs
|
||||
{
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Core.Color> Color { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass ToggleCommandPaletteArgs : IActionArgs
|
||||
{
|
||||
CommandPaletteLaunchMode LaunchMode { get; };
|
||||
|
|
|
@ -47,6 +47,10 @@
|
|||
ON_ALL_ACTIONS(ScrollDownPage) \
|
||||
ON_ALL_ACTIONS(ScrollToTop) \
|
||||
ON_ALL_ACTIONS(ScrollToBottom) \
|
||||
ON_ALL_ACTIONS(ScrollToMark) \
|
||||
ON_ALL_ACTIONS(AddMark) \
|
||||
ON_ALL_ACTIONS(ClearMark) \
|
||||
ON_ALL_ACTIONS(ClearAllMarks) \
|
||||
ON_ALL_ACTIONS(ResizePane) \
|
||||
ON_ALL_ACTIONS(MoveFocus) \
|
||||
ON_ALL_ACTIONS(MovePane) \
|
||||
|
@ -119,6 +123,8 @@
|
|||
ON_ALL_ACTIONS_WITH_ARGS(ResizePane) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(ScrollDown) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(ScrollUp) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(ScrollToMark) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(AddMark) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(SendInput) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(SetColorScheme) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(SetTabColor) \
|
||||
|
|
|
@ -78,7 +78,9 @@ Author(s):
|
|||
X(bool, UseAtlasEngine, "experimental.useAtlasEngine", false) \
|
||||
X(Windows::Foundation::Collections::IVector<winrt::hstring>, BellSound, "bellSound", nullptr) \
|
||||
X(bool, Elevate, "elevate", false) \
|
||||
X(bool, VtPassthrough, "experimental.connection.passthroughMode", false)
|
||||
X(bool, VtPassthrough, "experimental.connection.passthroughMode", false) \
|
||||
X(bool, AutoMarkPrompts, "experimental.autoMarkPrompts", false) \
|
||||
X(bool, ShowMarks, "experimental.showMarksOnScrollbar", false)
|
||||
|
||||
// Intentionally omitted Profile settings:
|
||||
// * Name
|
||||
|
|
|
@ -84,5 +84,7 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
INHERITABLE_PROFILE_SETTING(Windows.Foundation.Collections.IVector<String>, BellSound);
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, Elevate);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AutoMarkPrompts);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, ShowMarks);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -368,6 +368,31 @@
|
|||
<data name="ScrollToBottomCommandKey" xml:space="preserve">
|
||||
<value>Scroll to the bottom of history</value>
|
||||
</data>
|
||||
<data name="ScrollToPreviousMarkCommandKey" xml:space="preserve">
|
||||
<value>Scroll to the the previous mark</value>
|
||||
</data>
|
||||
<data name="ScrollToNextMarkCommandKey" xml:space="preserve">
|
||||
<value>Scroll to the next mark</value>
|
||||
</data>
|
||||
<data name="ScrollToFirstMarkCommandKey" xml:space="preserve">
|
||||
<value>Scroll to the first mark</value>
|
||||
</data>
|
||||
<data name="ScrollToLastMarkCommandKey" xml:space="preserve">
|
||||
<value>Scroll to the last mark</value>
|
||||
</data>
|
||||
<data name="AddMarkCommandKey" xml:space="preserve">
|
||||
<value>Add a scroll mark</value>
|
||||
</data>
|
||||
<data name="AddMarkWithColorCommandKey" xml:space="preserve">
|
||||
<value>Add a scroll mark, color:{0}</value>
|
||||
<comment>{Locked="color"}. "color" is a literal parameter name that shouldn't be translated. {0} will be replaced with a color in hexadecimal format, like `#123456`</comment>
|
||||
</data>
|
||||
<data name="ClearMarkCommandKey" xml:space="preserve">
|
||||
<value>Clear mark</value>
|
||||
</data>
|
||||
<data name="ClearAllMarksCommandKey" xml:space="preserve">
|
||||
<value>Clear all marks</value>
|
||||
</data>
|
||||
<data name="SendInputCommandKey" xml:space="preserve">
|
||||
<value>Send Input: "{0}"</value>
|
||||
<comment>{0} will be replaced with a string of input as defined by the user</comment>
|
||||
|
|
|
@ -281,6 +281,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
}
|
||||
|
||||
_Elevate = profile.Elevate();
|
||||
_AutoMarkPrompts = Feature_ScrollbarMarks::IsEnabled() && profile.AutoMarkPrompts();
|
||||
_ShowMarks = Feature_ScrollbarMarks::IsEnabled() && profile.ShowMarks();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -158,6 +158,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, Elevate, false);
|
||||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, AutoMarkPrompts, false);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, ShowMarks, false);
|
||||
|
||||
private:
|
||||
std::optional<std::array<Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE>> _ColorTable;
|
||||
gsl::span<Microsoft::Terminal::Core::Color> _getColorTableImpl();
|
||||
|
|
|
@ -546,3 +546,14 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage)
|
|||
pair_type{ "setAsDefault", ValueType::SetAsDefault },
|
||||
};
|
||||
};
|
||||
|
||||
// Possible ScrollToMarkDirection values
|
||||
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Control::ScrollToMarkDirection)
|
||||
{
|
||||
JSON_MAPPINGS(4) = {
|
||||
pair_type{ "previous", ValueType::Previous },
|
||||
pair_type{ "next", ValueType::Next },
|
||||
pair_type{ "first", ValueType::First },
|
||||
pair_type{ "last", ValueType::Last },
|
||||
};
|
||||
};
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
X(bool, ForceVTInput, false) \
|
||||
X(winrt::hstring, StartingTitle) \
|
||||
X(bool, DetectURLs, true) \
|
||||
X(bool, VtPassthrough, false)
|
||||
X(bool, VtPassthrough, false) \
|
||||
X(bool, AutoMarkPrompts)
|
||||
|
||||
// --------------------------- Control Settings ---------------------------
|
||||
// All of these settings are defined in IControlSettings.
|
||||
|
@ -68,5 +69,6 @@
|
|||
X(winrt::Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale) \
|
||||
X(bool, ForceFullRepaintRendering, false) \
|
||||
X(bool, SoftwareRendering, false) \
|
||||
X(bool, UseAtlasEngine, false) \
|
||||
X(bool, UseBackgroundImageForWindow, false) \
|
||||
X(bool, UseAtlasEngine, false)
|
||||
X(bool, ShowMarks, false)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
<heapType xmlns="http://schemas.microsoft.com/SMI/2020/WindowsSettings">SegmentHeap</heapType>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
|
|
|
@ -116,4 +116,16 @@
|
|||
<brandingToken>Preview</brandingToken>
|
||||
</alwaysDisabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_ScrollbarMarks</name>
|
||||
<description>Enables the experimental scrollbar marks feature.</description>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<!-- Did it this way instead of "release tokens" to ensure it won't go into Windows Inbox either... -->
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>Dev</brandingToken>
|
||||
<brandingToken>Preview</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
</featureStaging>
|
||||
|
|
|
@ -481,3 +481,8 @@ void ConhostInternalGetSet::NotifyAccessibilityChange(const til::rect& changedRe
|
|||
changedRect.bottom - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ConhostInternalGetSet::AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& /*mark*/)
|
||||
{
|
||||
// Not implemented for conhost.
|
||||
}
|
||||
|
|
|
@ -74,6 +74,8 @@ public:
|
|||
|
||||
void NotifyAccessibilityChange(const til::rect& changedRect) override;
|
||||
|
||||
void AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark) override;
|
||||
|
||||
private:
|
||||
Microsoft::Console::IIoProvider& _io;
|
||||
};
|
||||
|
|
|
@ -496,4 +496,22 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes
|
|||
constexpr VTInt s_sDECCOLMSetColumns = 132;
|
||||
constexpr VTInt s_sDECCOLMResetColumns = 80;
|
||||
|
||||
enum class MarkCategory : size_t
|
||||
{
|
||||
Prompt = 0,
|
||||
Error = 1,
|
||||
Warning = 2,
|
||||
Success = 3,
|
||||
Info = 4
|
||||
};
|
||||
|
||||
struct ScrollMark
|
||||
{
|
||||
std::optional<til::color> color;
|
||||
til::point start;
|
||||
til::point end; // exclusive
|
||||
MarkCategory category{ MarkCategory::Info };
|
||||
// Other things we may want to think about in the future are listed in
|
||||
// GH#11000
|
||||
};
|
||||
}
|
||||
|
|
|
@ -135,6 +135,8 @@ public:
|
|||
|
||||
virtual bool DoConEmuAction(const std::wstring_view string) = 0;
|
||||
|
||||
virtual bool DoITerm2Action(const std::wstring_view string) = 0;
|
||||
|
||||
virtual StringHandler DownloadDRCS(const VTInt fontNumber,
|
||||
const VTParameter startChar,
|
||||
const DispatchTypes::DrcsEraseControl eraseControl,
|
||||
|
|
|
@ -76,5 +76,7 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
virtual bool IsConsolePty() const = 0;
|
||||
|
||||
virtual void NotifyAccessibilityChange(const til::rect& changedRect) = 0;
|
||||
|
||||
virtual void AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark) = 0;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2465,6 +2465,50 @@ bool AdaptDispatch::DoConEmuAction(const std::wstring_view string)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Performs a iTerm2 action
|
||||
// - Ascribes to the ITermDispatch interface
|
||||
// - Currently, the actions we support are:
|
||||
// * `OSC1337;SetMark`: mark a line as a prompt line
|
||||
// - Not actually used in conhost
|
||||
// Arguments:
|
||||
// - string: contains the parameters that define which action we do
|
||||
// Return Value:
|
||||
// - false in conhost, true for the SetMark action, otherwise false.
|
||||
bool AdaptDispatch::DoITerm2Action(const std::wstring_view string)
|
||||
{
|
||||
// This is not implemented in conhost.
|
||||
if (_api.IsConsolePty())
|
||||
{
|
||||
// Flush the frame manually, to make sure marks end up on the right line, like the alt buffer sequence.
|
||||
_renderer.TriggerFlush(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if constexpr (!Feature_ScrollbarMarks::IsEnabled())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto parts = Utils::SplitString(string, L';');
|
||||
|
||||
if (parts.size() < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto action = til::at(parts, 0);
|
||||
|
||||
if (action == L"SetMark")
|
||||
{
|
||||
DispatchTypes::ScrollMark mark;
|
||||
mark.category = DispatchTypes::MarkCategory::Prompt;
|
||||
_api.AddMark(mark);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - DECDLD - Downloads one or more characters of a dynamically redefinable
|
||||
// character set (DRCS) with a specified pixel pattern. The pixel array is
|
||||
|
|
|
@ -130,6 +130,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
bool DoConEmuAction(const std::wstring_view string) override;
|
||||
|
||||
bool DoITerm2Action(const std::wstring_view string) override;
|
||||
|
||||
StringHandler DownloadDRCS(const VTInt fontNumber,
|
||||
const VTParameter startChar,
|
||||
const DispatchTypes::DrcsEraseControl eraseControl,
|
||||
|
|
|
@ -128,6 +128,8 @@ public:
|
|||
|
||||
bool DoConEmuAction(const std::wstring_view /*string*/) override { return false; }
|
||||
|
||||
bool DoITerm2Action(const std::wstring_view /*string*/) override { return false; }
|
||||
|
||||
StringHandler DownloadDRCS(const VTInt /*fontNumber*/,
|
||||
const VTParameter /*startChar*/,
|
||||
const DispatchTypes::DrcsEraseControl /*eraseControl*/,
|
||||
|
|
|
@ -237,6 +237,11 @@ public:
|
|||
Log::Comment(L"NotifyAccessibilityChange MOCK called...");
|
||||
}
|
||||
|
||||
void AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& /*mark*/) override
|
||||
{
|
||||
Log::Comment(L"AddMark MOCK called...");
|
||||
}
|
||||
|
||||
void PrepData()
|
||||
{
|
||||
PrepData(CursorDirection::UP); // if called like this, the cursor direction doesn't matter.
|
||||
|
|
|
@ -837,6 +837,11 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
|
|||
success = _dispatch->DoConEmuAction(string);
|
||||
break;
|
||||
}
|
||||
case OscActionCodes::ITerm2Action:
|
||||
{
|
||||
success = _dispatch->DoITerm2Action(string);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// If no functions to call, overall dispatch was a failure.
|
||||
success = false;
|
||||
|
|
|
@ -187,7 +187,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
SetClipboard = 52,
|
||||
ResetForegroundColor = 110, // Not implemented
|
||||
ResetBackgroundColor = 111, // Not implemented
|
||||
ResetCursorColor = 112
|
||||
ResetCursorColor = 112,
|
||||
ITerm2Action = 1337,
|
||||
};
|
||||
|
||||
bool _GetOscTitle(const std::wstring_view string,
|
||||
|
|
Loading…
Reference in New Issue