Compare commits
11 commits
main
...
dev/cazamo
Author | SHA1 | Date | |
---|---|---|---|
ad2678051f | |||
b7842624a0 | |||
30009eb0eb | |||
118d1cdc02 | |||
b13b8a7896 | |||
bf0cf5f0d2 | |||
724cd2c2ca | |||
8a646138f4 | |||
a0e4f2dd05 | |||
bcbf01e8cb | |||
428dec9702 |
|
@ -847,7 +847,7 @@
|
|||
}
|
||||
],
|
||||
"required": [ "actions" ]
|
||||
},
|
||||
},
|
||||
"CommandPaletteAction": {
|
||||
"description": "Arguments for a commandPalette action",
|
||||
"allOf": [
|
||||
|
|
|
@ -1430,12 +1430,13 @@ const til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<t
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update pos to be the end of the current glyph/character. This is used for accessibility
|
||||
// - Update pos to be the end of the current glyph/character.
|
||||
// Arguments:
|
||||
// - pos - a COORD on the word you are currently on
|
||||
// - accessibilityMode - this is being used for accessibility; make the end exclusive.
|
||||
// Return Value:
|
||||
// - pos - The COORD for the last cell of the current glyph (exclusive)
|
||||
const til::point TextBuffer::GetGlyphEnd(const til::point pos, std::optional<til::point> limitOptional) const
|
||||
const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
COORD resultPos = pos;
|
||||
const auto bufferSize = GetSize();
|
||||
|
@ -1453,7 +1454,10 @@ const til::point TextBuffer::GetGlyphEnd(const til::point pos, std::optional<til
|
|||
}
|
||||
|
||||
// increment one more time to become exclusive
|
||||
bufferSize.IncrementInBounds(resultPos, true);
|
||||
if (accessibilityMode)
|
||||
{
|
||||
bufferSize.IncrementInBounds(resultPos, true);
|
||||
}
|
||||
return resultPos;
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ public:
|
|||
bool MoveToPreviousWord(COORD& pos, const std::wstring_view wordDelimiters) const;
|
||||
|
||||
const til::point GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
const til::point GetGlyphEnd(const til::point pos, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
const til::point GetGlyphEnd(const til::point pos, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
bool MoveToNextGlyph(til::point& pos, bool allowBottomExclusive = false, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
bool MoveToPreviousGlyph(til::point& pos, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
|
||||
|
|
|
@ -549,11 +549,11 @@ try
|
|||
|
||||
if (multiClickMapper == 3)
|
||||
{
|
||||
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansionMode::Line);
|
||||
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Line);
|
||||
}
|
||||
else if (multiClickMapper == 2)
|
||||
{
|
||||
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansionMode::Word);
|
||||
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Word);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -359,28 +359,40 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
const ControlKeyStates modifiers,
|
||||
const bool keyDown)
|
||||
{
|
||||
// When there is a selection active, escape should clear it and NOT flow through
|
||||
// to the terminal. With any other keypress, it should clear the selection AND
|
||||
// flow through to the terminal.
|
||||
// Update the selection, if it's present
|
||||
// GH#6423 - don't dismiss selection if the key that was pressed was a
|
||||
// modifier key. We'll wait for a real keystroke to dismiss the
|
||||
// GH #7395 - don't dismiss selection when taking PrintScreen
|
||||
// selection.
|
||||
// GH#8522, GH#3758 - Only dismiss the selection on key _down_. If we
|
||||
// dismiss on key up, then there's chance that we'll immediately dismiss
|
||||
// GH#8522, GH#3758 - Only modify the selection on key _down_. If we
|
||||
// modify on key up, then there's chance that we'll immediately dismiss
|
||||
// a selection created by an action bound to a keydown.
|
||||
if (HasSelection() &&
|
||||
!KeyEvent::IsModifierKey(vkey) &&
|
||||
vkey != VK_SNAPSHOT &&
|
||||
keyDown)
|
||||
{
|
||||
// try to update the selection
|
||||
if (const auto updateSlnParams{ ::Terminal::ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) })
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second);
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(false));
|
||||
return true;
|
||||
}
|
||||
|
||||
// GH#8791 - don't dismiss selection if Windows key was also pressed as a key-combination.
|
||||
if (!modifiers.IsWinPressed())
|
||||
{
|
||||
_terminal->ClearSelection();
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
|
||||
// When there is a selection active, escape should clear it and NOT flow through
|
||||
// to the terminal. With any other keypress, it should clear the selection AND
|
||||
// flow through to the terminal.
|
||||
if (vkey == VK_ESCAPE)
|
||||
{
|
||||
return true;
|
||||
|
@ -899,6 +911,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_terminal->SetSelectionAnchor(position);
|
||||
}
|
||||
|
||||
Core::Point ControlCore::SelectionAnchor() const
|
||||
{
|
||||
auto lock = _terminal->LockForReading();
|
||||
return til::point{ _terminal->SelectionStartForRendering() };
|
||||
}
|
||||
|
||||
Core::Point ControlCore::SelectionEnd() const
|
||||
{
|
||||
auto lock = _terminal->LockForReading();
|
||||
return til::point{ _terminal->SelectionEndForRendering() };
|
||||
}
|
||||
|
||||
bool ControlCore::MovingStart() const
|
||||
{
|
||||
auto lock = _terminal->LockForReading();
|
||||
return _terminal->MovingStart();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets selection's end position to match supplied cursor position, e.g. while mouse dragging.
|
||||
// Arguments:
|
||||
|
@ -925,6 +955,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// save location (for rendering) + render
|
||||
_terminal->SetSelectionEnd(terminalPosition);
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
|
||||
// Called when the Terminal wants to set something to the clipboard, i.e.
|
||||
|
@ -985,6 +1016,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
{
|
||||
_terminal->ClearSelection();
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
|
||||
// send data up for clipboard
|
||||
|
@ -1276,6 +1308,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_terminal->SetBlockSelection(false);
|
||||
search.Select();
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1422,18 +1455,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// handle ALT key
|
||||
_terminal->SetBlockSelection(altEnabled);
|
||||
|
||||
::Terminal::SelectionExpansionMode mode = ::Terminal::SelectionExpansionMode::Cell;
|
||||
::Terminal::SelectionExpansion mode = ::Terminal::SelectionExpansion::Char;
|
||||
if (numberOfClicks == 1)
|
||||
{
|
||||
mode = ::Terminal::SelectionExpansionMode::Cell;
|
||||
mode = ::Terminal::SelectionExpansion::Char;
|
||||
}
|
||||
else if (numberOfClicks == 2)
|
||||
{
|
||||
mode = ::Terminal::SelectionExpansionMode::Word;
|
||||
mode = ::Terminal::SelectionExpansion::Word;
|
||||
}
|
||||
else if (numberOfClicks == 3)
|
||||
{
|
||||
mode = ::Terminal::SelectionExpansionMode::Line;
|
||||
mode = ::Terminal::SelectionExpansion::Line;
|
||||
}
|
||||
|
||||
// Update the selection appropriately
|
||||
|
@ -1458,7 +1491,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_terminal->SetSelectionEnd(terminalPosition, mode);
|
||||
selectionNeedsToBeCopied = true;
|
||||
}
|
||||
else if (mode != ::Terminal::SelectionExpansionMode::Cell || shiftEnabled)
|
||||
else if (mode != ::Terminal::SelectionExpansion::Char || shiftEnabled)
|
||||
{
|
||||
// If we are handling a double / triple-click or shift+single click
|
||||
// we establish selection using the selected mode
|
||||
|
@ -1468,6 +1501,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
}
|
||||
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
|
||||
void ControlCore::AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
|
||||
|
@ -1557,5 +1591,4 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
return hstring(ss.str());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -128,6 +128,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
bool HasSelection() const;
|
||||
bool CopyOnSelect() const;
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
|
||||
Core::Point SelectionAnchor() const;
|
||||
Core::Point SelectionEnd() const;
|
||||
bool MovingStart() const;
|
||||
void SetSelectionAnchor(til::point const& position);
|
||||
void SetEndSelectionPoint(til::point const& position);
|
||||
|
||||
|
@ -169,6 +172,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs);
|
||||
TYPED_EVENT(TransparencyChanged, IInspectable, Control::TransparencyChangedEventArgs);
|
||||
TYPED_EVENT(ReceivedOutput, IInspectable, IInspectable);
|
||||
TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
|
|
|
@ -80,6 +80,9 @@ namespace Microsoft.Terminal.Control
|
|||
|
||||
Boolean HasSelection { get; };
|
||||
IVector<String> SelectedText(Boolean trimTrailingWhitespace);
|
||||
Microsoft.Terminal.Core.Point SelectionAnchor { get; };
|
||||
Microsoft.Terminal.Core.Point SelectionEnd { get; };
|
||||
Boolean MovingStart { get; };
|
||||
|
||||
String HoveredUriText { get; };
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Core.Point> HoveredCell { get; };
|
||||
|
@ -110,6 +113,7 @@ namespace Microsoft.Terminal.Control
|
|||
event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
|
||||
event Windows.Foundation.TypedEventHandler<Object, TransparencyChangedEventArgs> TransparencyChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ReceivedOutput;
|
||||
event Windows.Foundation.TypedEventHandler<Object, UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,3 +11,4 @@
|
|||
#include "ScrollPositionChangedArgs.g.cpp"
|
||||
#include "RendererWarningArgs.g.cpp"
|
||||
#include "TransparencyChangedEventArgs.g.cpp"
|
||||
#include "UpdateSelectionMarkersEventArgs.g.cpp"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "ScrollPositionChangedArgs.g.h"
|
||||
#include "RendererWarningArgs.g.h"
|
||||
#include "TransparencyChangedEventArgs.g.h"
|
||||
#include "UpdateSelectionMarkersEventArgs.g.h"
|
||||
#include "cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
@ -131,4 +132,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
WINRT_PROPERTY(double, Opacity);
|
||||
};
|
||||
|
||||
struct UpdateSelectionMarkersEventArgs : public UpdateSelectionMarkersEventArgsT<UpdateSelectionMarkersEventArgs>
|
||||
{
|
||||
public:
|
||||
UpdateSelectionMarkersEventArgs(const bool clearMarkers) :
|
||||
_ClearMarkers(clearMarkers)
|
||||
{
|
||||
}
|
||||
|
||||
WINRT_PROPERTY(bool, ClearMarkers, false);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -67,4 +67,9 @@ namespace Microsoft.Terminal.Control
|
|||
{
|
||||
Double Opacity { get; };
|
||||
}
|
||||
|
||||
runtimeclass UpdateSelectionMarkersEventArgs
|
||||
{
|
||||
Boolean ClearMarkers { get; };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_core.TransparencyChanged({ this, &TermControl::_coreTransparencyChanged });
|
||||
_core.RaiseNotice({ this, &TermControl::_coreRaisedNotice });
|
||||
_core.HoveredHyperlinkChanged({ this, &TermControl::_hoveredHyperlinkChanged });
|
||||
_core.UpdateSelectionMarkers({ this, &TermControl::_updateSelectionMarkers });
|
||||
_interactivity.OpenHyperlink({ this, &TermControl::_HyperlinkHandler });
|
||||
_interactivity.ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
|
||||
|
||||
|
@ -333,6 +334,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
const auto bg = newAppearance.DefaultBackground();
|
||||
_changeBackgroundColor(bg);
|
||||
|
||||
// Update selection markers
|
||||
Windows::UI::Xaml::Media::SolidColorBrush selectionBackgroundBrush{ til::color{ newAppearance.SelectionBackground() } };
|
||||
SelectionStartIcon().Foreground(selectionBackgroundBrush);
|
||||
SelectionEndIcon().Foreground(selectionBackgroundBrush);
|
||||
|
||||
// Set TSF Foreground
|
||||
Media::SolidColorBrush foregroundBrush{};
|
||||
foregroundBrush.Color(static_cast<til::color>(newAppearance.DefaultForeground()));
|
||||
|
@ -1659,6 +1665,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
update.newValue = args.ViewTop();
|
||||
|
||||
_updateScrollBar->Run(update);
|
||||
_updatePatternLocations->Run();
|
||||
_updateSelectionMarkers(nullptr, winrt::make<UpdateSelectionMarkersEventArgs>(false));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -2464,8 +2472,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_core.ClearHoveredCell();
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TermControl::_hoveredHyperlinkChanged(IInspectable sender,
|
||||
IInspectable args)
|
||||
winrt::fire_and_forget TermControl::_hoveredHyperlinkChanged(IInspectable /*sender*/,
|
||||
IInspectable /*args*/)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
co_await resume_foreground(Dispatcher());
|
||||
|
@ -2488,12 +2496,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
HyperlinkTooltipBorder().BorderThickness(newThickness);
|
||||
|
||||
// Compute the location of the top left corner of the cell in DIPS
|
||||
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
|
||||
const til::point startPos{ lastHoveredCell.Value() };
|
||||
const til::size fontSize{ til::math::rounding, _core.FontSize() };
|
||||
const til::point posInPixels{ startPos * fontSize };
|
||||
const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() };
|
||||
const til::point locationInDIPs{ posInDIPs + marginsInDips };
|
||||
const til::point locationInDIPs{ _toPosInDips(lastHoveredCell.Value()) };
|
||||
|
||||
// Move the border to the top left corner of the cell
|
||||
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(),
|
||||
|
@ -2505,10 +2508,71 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
}
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TermControl::_updateSelectionMarkers(IInspectable /*sender*/, Control::UpdateSelectionMarkersEventArgs args)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
co_await resume_foreground(Dispatcher());
|
||||
if (weakThis.get() && args)
|
||||
{
|
||||
if (_core.HasSelection() && !args.ClearMarkers())
|
||||
{
|
||||
// show/update selection markers
|
||||
// figure out which endpoint to move, get it and the relevant icon (hide the other icon)
|
||||
const auto movingStart{ _core.MovingStart() };
|
||||
const auto selectionAnchor{ movingStart ? _core.SelectionAnchor() : _core.SelectionEnd() };
|
||||
const auto& icon{ movingStart ? SelectionStartIcon() : SelectionEndIcon() };
|
||||
const auto& otherIcon{ movingStart ? SelectionEndIcon() : SelectionStartIcon() };
|
||||
icon.Opacity(1);
|
||||
otherIcon.Opacity(0);
|
||||
|
||||
// Compute the location of the top left corner of the cell in DIPS
|
||||
const til::point locationInDIPs{ _toPosInDips(selectionAnchor) };
|
||||
|
||||
// Move the icon to the top left corner of the cell
|
||||
SelectionCanvas().SetLeft(icon,
|
||||
(locationInDIPs.x() - SwapChainPanel().ActualOffset().x));
|
||||
SelectionCanvas().SetTop(icon,
|
||||
(locationInDIPs.y() - SwapChainPanel().ActualOffset().y));
|
||||
}
|
||||
else
|
||||
{
|
||||
// hide selection markers
|
||||
SelectionStartIcon().Opacity(0);
|
||||
SelectionEndIcon().Opacity(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
til::point TermControl::_toPosInDips(const til::point terminalCellPos)
|
||||
{
|
||||
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
|
||||
const til::size fontSize{ til::math::rounding, _core.FontSize() };
|
||||
const til::point posInPixels{ terminalCellPos * fontSize };
|
||||
const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() };
|
||||
return posInDIPs + marginsInDips;
|
||||
}
|
||||
|
||||
void TermControl::_coreFontSizeChanged(const int fontWidth,
|
||||
const int fontHeight,
|
||||
const bool isInitialChange)
|
||||
{
|
||||
// scale the selection markers to be the size of a cell
|
||||
auto scaleIconMarker = [fontWidth, fontHeight](Windows::UI::Xaml::Controls::FontIcon icon) {
|
||||
const auto size{ icon.DesiredSize() };
|
||||
const auto scaleX = fontWidth / size.Width;
|
||||
const auto scaleY = fontHeight / size.Height;
|
||||
|
||||
Windows::UI::Xaml::Media::ScaleTransform transform{};
|
||||
transform.ScaleX(transform.ScaleX() * scaleX);
|
||||
transform.ScaleY(transform.ScaleY() * scaleY);
|
||||
icon.RenderTransform(transform);
|
||||
|
||||
// now hide the icon
|
||||
icon.Opacity(0);
|
||||
};
|
||||
scaleIconMarker(SelectionStartIcon());
|
||||
scaleIconMarker(SelectionEndIcon());
|
||||
|
||||
// Don't try to inspect the core here. The Core is raising this while
|
||||
// it's holding its write lock. If the handlers calls back to some
|
||||
// method on the TermControl on the same thread, and that _method_ calls
|
||||
|
|
|
@ -267,6 +267,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
void _FontInfoHandler(const IInspectable& sender, const FontInfoEventArgs& eventArgs);
|
||||
|
||||
winrt::fire_and_forget _hoveredHyperlinkChanged(IInspectable sender, IInspectable args);
|
||||
winrt::fire_and_forget _updateSelectionMarkers(IInspectable sender, Control::UpdateSelectionMarkersEventArgs args);
|
||||
|
||||
void _coreFontSizeChanged(const int fontWidth,
|
||||
const int fontHeight,
|
||||
|
@ -274,6 +275,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
winrt::fire_and_forget _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
|
||||
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
|
||||
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
|
||||
|
||||
til::point _toPosInDips(const til::point terminalCellPos);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,23 @@
|
|||
</ToolTipService.ToolTip>
|
||||
</Border>
|
||||
</Canvas>
|
||||
|
||||
<Canvas x:Name="SelectionCanvas"
|
||||
Visibility="Visible">
|
||||
<!-- LOAD BEARING Use Opacity instead of Visibility for these two FontIcons.
|
||||
Visibility::Collapsed prevents us from aquiring the desired size of the icons,
|
||||
resulting in an inability to scale them upon a FontSize change event -->
|
||||
<FontIcon x:Name="SelectionStartIcon"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
Opacity="0">
|
||||
</FontIcon>
|
||||
<FontIcon x:Name="SelectionEndIcon"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
Opacity="0">
|
||||
</FontIcon>
|
||||
</Canvas>
|
||||
</SwapChainPanel>
|
||||
|
||||
<!--
|
||||
|
|
|
@ -227,16 +227,33 @@ public:
|
|||
|
||||
#pragma region TextSelection
|
||||
// These methods are defined in TerminalSelection.cpp
|
||||
enum class SelectionExpansionMode
|
||||
enum class SelectionDirection
|
||||
{
|
||||
Cell,
|
||||
Word,
|
||||
Line
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down
|
||||
};
|
||||
void MultiClickSelection(const COORD viewportPos, SelectionExpansionMode expansionMode);
|
||||
|
||||
enum class SelectionExpansion
|
||||
{
|
||||
Char,
|
||||
Word,
|
||||
Line, // Mouse selection only!
|
||||
Viewport,
|
||||
Buffer
|
||||
};
|
||||
void MultiClickSelection(const COORD viewportPos, SelectionExpansion expansionMode);
|
||||
void SetSelectionAnchor(const COORD position);
|
||||
void SetSelectionEnd(const COORD position, std::optional<SelectionExpansionMode> newExpansionMode = std::nullopt);
|
||||
void SetSelectionEnd(const COORD position, std::optional<SelectionExpansion> newExpansionMode = std::nullopt);
|
||||
void SetBlockSelection(const bool isEnabled) noexcept;
|
||||
void UpdateSelection(SelectionDirection direction, SelectionExpansion mode);
|
||||
|
||||
using UpdateSelectionParams = std::optional<std::pair<SelectionDirection, SelectionExpansion>>;
|
||||
static UpdateSelectionParams ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey);
|
||||
bool MovingStart() const noexcept;
|
||||
til::point SelectionStartForRendering() const;
|
||||
til::point SelectionEndForRendering() const;
|
||||
|
||||
const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace);
|
||||
#pragma endregion
|
||||
|
@ -308,7 +325,7 @@ private:
|
|||
std::optional<SelectionAnchors> _selection;
|
||||
bool _blockSelection;
|
||||
std::wstring _wordDelimiters;
|
||||
SelectionExpansionMode _multiClickSelectionMode;
|
||||
SelectionExpansion _multiClickSelectionMode;
|
||||
#pragma endregion
|
||||
|
||||
// TODO: These members are not shared by an alt-buffer. They should be
|
||||
|
@ -375,6 +392,10 @@ private:
|
|||
std::pair<COORD, COORD> _PivotSelection(const COORD targetPos, bool& targetStart) const;
|
||||
std::pair<COORD, COORD> _ExpandSelectionAnchors(std::pair<COORD, COORD> anchors) const;
|
||||
COORD _ConvertToBufferCell(const COORD viewportPos) const;
|
||||
void _MoveByChar(SelectionDirection direction, COORD& pos);
|
||||
void _MoveByWord(SelectionDirection direction, COORD& pos);
|
||||
void _MoveByViewport(SelectionDirection direction, COORD& pos);
|
||||
void _MoveByBuffer(SelectionDirection direction, COORD& pos);
|
||||
#pragma endregion
|
||||
|
||||
Microsoft::Console::VirtualTerminal::SgrStack _sgrStack;
|
||||
|
|
|
@ -82,6 +82,24 @@ const COORD Terminal::GetSelectionEnd() const noexcept
|
|||
return _selection->end;
|
||||
}
|
||||
|
||||
til::point Terminal::SelectionStartForRendering() const
|
||||
{
|
||||
auto pos{ _selection->start };
|
||||
const auto bufferSize{ _buffer->GetSize() };
|
||||
bufferSize.DecrementInBounds(pos);
|
||||
pos.Y = std::clamp<short>(base::ClampSub(pos.Y, _VisibleStartIndex()), bufferSize.Top(), bufferSize.BottomInclusive());
|
||||
return pos;
|
||||
}
|
||||
|
||||
til::point Terminal::SelectionEndForRendering() const
|
||||
{
|
||||
auto pos{ _selection->end };
|
||||
const auto bufferSize{ _buffer->GetSize() };
|
||||
bufferSize.IncrementInBounds(pos);
|
||||
pos.Y = std::clamp<short>(base::ClampSub(pos.Y, _VisibleStartIndex()), bufferSize.Top(), bufferSize.BottomInclusive());
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Checks if selection is active
|
||||
// Return Value:
|
||||
|
@ -100,8 +118,8 @@ const bool Terminal::IsBlockSelection() const noexcept
|
|||
// - Perform a multi-click selection at viewportPos expanding according to the expansionMode
|
||||
// Arguments:
|
||||
// - viewportPos: the (x,y) coordinate on the visible viewport
|
||||
// - expansionMode: the SelectionExpansionMode to dictate the boundaries of the selection anchors
|
||||
void Terminal::MultiClickSelection(const COORD viewportPos, SelectionExpansionMode expansionMode)
|
||||
// - expansionMode: the SelectionExpansion to dictate the boundaries of the selection anchors
|
||||
void Terminal::MultiClickSelection(const COORD viewportPos, SelectionExpansion expansionMode)
|
||||
{
|
||||
// set the selection pivot to expand the selection using SetSelectionEnd()
|
||||
_selection = SelectionAnchors{};
|
||||
|
@ -124,7 +142,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos)
|
|||
_selection = SelectionAnchors{};
|
||||
_selection->pivot = _ConvertToBufferCell(viewportPos);
|
||||
|
||||
_multiClickSelectionMode = SelectionExpansionMode::Cell;
|
||||
_multiClickSelectionMode = SelectionExpansion::Char;
|
||||
SetSelectionEnd(viewportPos);
|
||||
|
||||
_selection->start = _selection->pivot;
|
||||
|
@ -136,7 +154,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos)
|
|||
// Arguments:
|
||||
// - viewportPos: the (x,y) coordinate on the visible viewport
|
||||
// - newExpansionMode: overwrites the _multiClickSelectionMode for this function call. Used for ShiftClick
|
||||
void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional<SelectionExpansionMode> newExpansionMode)
|
||||
void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional<SelectionExpansion> newExpansionMode)
|
||||
{
|
||||
if (!_selection.has_value())
|
||||
{
|
||||
|
@ -210,15 +228,15 @@ std::pair<COORD, COORD> Terminal::_ExpandSelectionAnchors(std::pair<COORD, COORD
|
|||
const auto bufferSize = _buffer->GetSize();
|
||||
switch (_multiClickSelectionMode)
|
||||
{
|
||||
case SelectionExpansionMode::Line:
|
||||
case SelectionExpansion::Line:
|
||||
start = { bufferSize.Left(), start.Y };
|
||||
end = { bufferSize.RightInclusive(), end.Y };
|
||||
break;
|
||||
case SelectionExpansionMode::Word:
|
||||
case SelectionExpansion::Word:
|
||||
start = _buffer->GetWordStart(start, _wordDelimiters);
|
||||
end = _buffer->GetWordEnd(end, _wordDelimiters);
|
||||
break;
|
||||
case SelectionExpansionMode::Cell:
|
||||
case SelectionExpansion::Char:
|
||||
default:
|
||||
// no expansion is necessary
|
||||
break;
|
||||
|
@ -235,6 +253,229 @@ void Terminal::SetBlockSelection(const bool isEnabled) noexcept
|
|||
_blockSelection = isEnabled;
|
||||
}
|
||||
|
||||
Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey)
|
||||
{
|
||||
if (mods.IsShiftPressed() && !mods.IsAltPressed())
|
||||
{
|
||||
if (mods.IsCtrlPressed())
|
||||
{
|
||||
// Ctrl + Shift + _
|
||||
switch (vkey)
|
||||
{
|
||||
case VK_LEFT:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Left, SelectionExpansion::Word };
|
||||
case VK_RIGHT:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Right, SelectionExpansion::Word };
|
||||
case VK_HOME:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Left, SelectionExpansion::Buffer };
|
||||
case VK_END:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Right, SelectionExpansion::Buffer };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shift + _
|
||||
switch (vkey)
|
||||
{
|
||||
case VK_HOME:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Left, SelectionExpansion::Viewport };
|
||||
case VK_END:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Right, SelectionExpansion::Viewport };
|
||||
case VK_PRIOR:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Up, SelectionExpansion::Viewport };
|
||||
case VK_NEXT:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Down, SelectionExpansion::Viewport };
|
||||
case VK_LEFT:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Left, SelectionExpansion::Char };
|
||||
case VK_RIGHT:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Right, SelectionExpansion::Char };
|
||||
case VK_UP:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Up, SelectionExpansion::Char };
|
||||
case VK_DOWN:
|
||||
return UpdateSelectionParams{ std::in_place, SelectionDirection::Down, SelectionExpansion::Char };
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode)
|
||||
{
|
||||
// 1. Figure out which endpoint to update
|
||||
// One of the endpoints is the pivot, signifying that the other endpoint is the one we want to move.
|
||||
const bool movingEnd{ _selection->start == _selection->pivot };
|
||||
auto targetPos{ movingEnd ? _selection->end : _selection->start };
|
||||
|
||||
// 2. Perform the movement
|
||||
switch (mode)
|
||||
{
|
||||
case SelectionExpansion::Char:
|
||||
_MoveByChar(direction, targetPos);
|
||||
break;
|
||||
case SelectionExpansion::Word:
|
||||
_MoveByWord(direction, targetPos);
|
||||
break;
|
||||
case SelectionExpansion::Viewport:
|
||||
_MoveByViewport(direction, targetPos);
|
||||
break;
|
||||
case SelectionExpansion::Buffer:
|
||||
_MoveByBuffer(direction, targetPos);
|
||||
break;
|
||||
}
|
||||
|
||||
// 3. Actually modify the selection
|
||||
// NOTE: targetStart doesn't matter here
|
||||
bool targetStart = false;
|
||||
std::tie(_selection->start, _selection->end) = _PivotSelection(targetPos, targetStart);
|
||||
|
||||
// 4. Scroll (if necessary)
|
||||
if (const auto viewport = _GetVisibleViewport(); !viewport.IsInBounds(targetPos))
|
||||
{
|
||||
if (const auto amtAboveView = viewport.Top() - targetPos.Y; amtAboveView > 0)
|
||||
{
|
||||
// anchor is above visible viewport, scroll by that amount
|
||||
_scrollOffset += amtAboveView;
|
||||
}
|
||||
else
|
||||
{
|
||||
// anchor is below visible viewport, scroll by that amount
|
||||
const auto amtBelowView = targetPos.Y - viewport.BottomInclusive();
|
||||
_scrollOffset -= amtBelowView;
|
||||
}
|
||||
_NotifyScrollEvent();
|
||||
_buffer->GetRenderTarget().TriggerScroll();
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::_MoveByChar(SelectionDirection direction, COORD& pos)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case SelectionDirection::Left:
|
||||
_buffer->GetSize().DecrementInBounds(pos);
|
||||
pos = _buffer->GetGlyphStart(pos);
|
||||
break;
|
||||
case SelectionDirection::Right:
|
||||
_buffer->GetSize().IncrementInBounds(pos);
|
||||
pos = _buffer->GetGlyphEnd(pos);
|
||||
break;
|
||||
case SelectionDirection::Up:
|
||||
{
|
||||
const auto bufferSize{ _buffer->GetSize() };
|
||||
pos = { pos.X, std::clamp(base::ClampSub<short, short>(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) };
|
||||
break;
|
||||
}
|
||||
case SelectionDirection::Down:
|
||||
{
|
||||
const auto bufferSize{ _buffer->GetSize() };
|
||||
pos = { pos.X, std::clamp(base::ClampAdd<short, short>(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case SelectionDirection::Left:
|
||||
const auto wordStartPos{ _buffer->GetWordStart(pos, _wordDelimiters) };
|
||||
if (_buffer->GetSize().CompareInBounds(_selection->pivot, pos) < 0)
|
||||
{
|
||||
// If we're moving towards the pivot, move one more cell
|
||||
pos = wordStartPos;
|
||||
_buffer->GetSize().DecrementInBounds(pos);
|
||||
}
|
||||
else if (wordStartPos == pos)
|
||||
{
|
||||
// already at the beginning of the current word,
|
||||
// move to the beginning of the previous word
|
||||
_buffer->GetSize().DecrementInBounds(pos);
|
||||
pos = _buffer->GetWordStart(pos, _wordDelimiters);
|
||||
}
|
||||
else
|
||||
{
|
||||
// move to the beginning of the current word
|
||||
pos = wordStartPos;
|
||||
}
|
||||
break;
|
||||
case SelectionDirection::Right:
|
||||
const auto wordEndPos{ _buffer->GetWordEnd(pos, _wordDelimiters) };
|
||||
if (_buffer->GetSize().CompareInBounds(pos, _selection->pivot) < 0)
|
||||
{
|
||||
// If we're moving towards the pivot, move one more cell
|
||||
pos = _buffer->GetWordEnd(pos, _wordDelimiters);
|
||||
_buffer->GetSize().IncrementInBounds(pos);
|
||||
}
|
||||
else if (wordEndPos == pos)
|
||||
{
|
||||
// already at the end of the current word,
|
||||
// move to the end of the next word
|
||||
_buffer->GetSize().IncrementInBounds(pos);
|
||||
pos = _buffer->GetWordEnd(pos, _wordDelimiters);
|
||||
}
|
||||
else
|
||||
{
|
||||
// move to the end of the current word
|
||||
pos = wordEndPos;
|
||||
}
|
||||
break;
|
||||
case SelectionDirection::Up:
|
||||
_MoveByChar(direction, pos);
|
||||
pos = _buffer->GetWordStart(pos, _wordDelimiters);
|
||||
break;
|
||||
case SelectionDirection::Down:
|
||||
_MoveByChar(direction, pos);
|
||||
pos = _buffer->GetWordEnd(pos, _wordDelimiters);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos)
|
||||
{
|
||||
const auto bufferSize{ _buffer->GetSize() };
|
||||
switch (direction)
|
||||
{
|
||||
case SelectionDirection::Left:
|
||||
pos = { bufferSize.Left(), pos.Y };
|
||||
break;
|
||||
case SelectionDirection::Right:
|
||||
pos = { bufferSize.RightInclusive(), pos.Y };
|
||||
break;
|
||||
case SelectionDirection::Up:
|
||||
{
|
||||
const auto viewportHeight{ _mutableViewport.Height() };
|
||||
const auto newY{ base::ClampSub<short, short>(pos.Y, viewportHeight) };
|
||||
pos = newY < bufferSize.Top() ? bufferSize.Origin() : COORD{ pos.X, newY };
|
||||
break;
|
||||
}
|
||||
case SelectionDirection::Down:
|
||||
{
|
||||
const auto viewportHeight{ _mutableViewport.Height() };
|
||||
const auto mutableBottom{ _mutableViewport.BottomInclusive() };
|
||||
const auto newY{ base::ClampAdd<short, short>(pos.Y, viewportHeight) };
|
||||
pos = newY > mutableBottom ? COORD{ bufferSize.RightInclusive(), mutableBottom } : COORD{ pos.X, newY };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos)
|
||||
{
|
||||
const auto bufferSize{ _buffer->GetSize() };
|
||||
switch (direction)
|
||||
{
|
||||
case SelectionDirection::Left:
|
||||
case SelectionDirection::Up:
|
||||
pos = bufferSize.Origin();
|
||||
break;
|
||||
case SelectionDirection::Right:
|
||||
case SelectionDirection::Down:
|
||||
pos = { bufferSize.RightInclusive(), _mutableViewport.BottomInclusive() };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - clear selection data and disable rendering it
|
||||
#pragma warning(disable : 26440) // changing this to noexcept would require a change to ConHost's selection model
|
||||
|
|
|
@ -206,7 +206,7 @@ void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd)
|
|||
realCoordEnd.Y -= gsl::narrow<short>(_VisibleStartIndex());
|
||||
|
||||
SetSelectionAnchor(realCoordStart);
|
||||
SetSelectionEnd(realCoordEnd, SelectionExpansionMode::Cell);
|
||||
SetSelectionEnd(realCoordEnd, SelectionExpansion::Char);
|
||||
}
|
||||
|
||||
const std::wstring_view Terminal::GetConsoleTitle() const noexcept
|
||||
|
|
|
@ -130,7 +130,7 @@ namespace TerminalCoreUnitTests
|
|||
DummyRenderTarget emptyRT;
|
||||
term.Create({ 10, 10 }, scrollback, emptyRT);
|
||||
|
||||
term.MultiClickSelection(maxCoord, Terminal::SelectionExpansionMode::Word);
|
||||
term.MultiClickSelection(maxCoord, Terminal::SelectionExpansion::Word);
|
||||
ValidateSingleRowSelection(term, expected);
|
||||
};
|
||||
|
||||
|
@ -142,7 +142,7 @@ namespace TerminalCoreUnitTests
|
|||
DummyRenderTarget emptyRT;
|
||||
term.Create({ 10, 10 }, scrollback, emptyRT);
|
||||
|
||||
term.MultiClickSelection(maxCoord, Terminal::SelectionExpansionMode::Line);
|
||||
term.MultiClickSelection(maxCoord, Terminal::SelectionExpansion::Line);
|
||||
ValidateSingleRowSelection(term, expected);
|
||||
};
|
||||
|
||||
|
@ -501,7 +501,7 @@ namespace TerminalCoreUnitTests
|
|||
|
||||
// Simulate double click at (x,y) = (5,10)
|
||||
auto clickPos = COORD{ 5, 10 };
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Word);
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Word);
|
||||
|
||||
// Validate selection area
|
||||
ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, (4 + gsl::narrow<SHORT>(text.size()) - 1), 10 }));
|
||||
|
@ -519,7 +519,7 @@ namespace TerminalCoreUnitTests
|
|||
|
||||
// Simulate click at (x,y) = (5,10)
|
||||
auto clickPos = COORD{ 5, 10 };
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Word);
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Word);
|
||||
|
||||
// Simulate renderer calling TriggerSelection and acquiring selection area
|
||||
auto selectionRects = term.GetSelectionRects();
|
||||
|
@ -546,7 +546,7 @@ namespace TerminalCoreUnitTests
|
|||
// Simulate click at (x,y) = (15,10)
|
||||
// this is over the '>' char
|
||||
auto clickPos = COORD{ 15, 10 };
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Word);
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Word);
|
||||
|
||||
// ---Validate selection area---
|
||||
// "Terminal" is in class 2
|
||||
|
@ -572,7 +572,7 @@ namespace TerminalCoreUnitTests
|
|||
term.Write(text);
|
||||
|
||||
// Simulate double click at (x,y) = (5,10)
|
||||
term.MultiClickSelection({ 5, 10 }, Terminal::SelectionExpansionMode::Word);
|
||||
term.MultiClickSelection({ 5, 10 }, Terminal::SelectionExpansion::Word);
|
||||
|
||||
// Simulate move to (x,y) = (21,10)
|
||||
//
|
||||
|
@ -601,7 +601,7 @@ namespace TerminalCoreUnitTests
|
|||
term.Write(text);
|
||||
|
||||
// Simulate double click at (x,y) = (21,10)
|
||||
term.MultiClickSelection({ 21, 10 }, Terminal::SelectionExpansionMode::Word);
|
||||
term.MultiClickSelection({ 21, 10 }, Terminal::SelectionExpansion::Word);
|
||||
|
||||
// Simulate move to (x,y) = (5,10)
|
||||
//
|
||||
|
@ -622,7 +622,7 @@ namespace TerminalCoreUnitTests
|
|||
|
||||
// Simulate click at (x,y) = (5,10)
|
||||
auto clickPos = COORD{ 5, 10 };
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Line);
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Line);
|
||||
|
||||
// Validate selection area
|
||||
ValidateSingleRowSelection(term, SMALL_RECT({ 0, 10, 99, 10 }));
|
||||
|
@ -636,7 +636,7 @@ namespace TerminalCoreUnitTests
|
|||
|
||||
// Simulate click at (x,y) = (5,10)
|
||||
auto clickPos = COORD{ 5, 10 };
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Line);
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Line);
|
||||
|
||||
// Simulate move to (x,y) = (7,10)
|
||||
term.SetSelectionEnd({ 7, 10 });
|
||||
|
@ -653,7 +653,7 @@ namespace TerminalCoreUnitTests
|
|||
|
||||
// Simulate click at (x,y) = (5,10)
|
||||
auto clickPos = COORD{ 5, 10 };
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansionMode::Line);
|
||||
term.MultiClickSelection(clickPos, Terminal::SelectionExpansion::Line);
|
||||
|
||||
// Simulate move to (x,y) = (5,11)
|
||||
term.SetSelectionEnd({ 5, 11 });
|
||||
|
@ -691,7 +691,7 @@ namespace TerminalCoreUnitTests
|
|||
// Step 1: Create a selection on "doubleClickMe"
|
||||
{
|
||||
// Simulate double click at (x,y) = (5,10)
|
||||
term.MultiClickSelection({ 5, 10 }, Terminal::SelectionExpansionMode::Word);
|
||||
term.MultiClickSelection({ 5, 10 }, Terminal::SelectionExpansion::Word);
|
||||
|
||||
// Validate selection area: "doubleClickMe" selected
|
||||
ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 16, 10 }));
|
||||
|
@ -704,7 +704,7 @@ namespace TerminalCoreUnitTests
|
|||
// buffer: doubleClickMe dragThroughHere
|
||||
// ^ ^
|
||||
// start finish
|
||||
term.SetSelectionEnd({ 21, 10 }, ::Terminal::SelectionExpansionMode::Cell);
|
||||
term.SetSelectionEnd({ 21, 10 }, Terminal::SelectionExpansion::Char);
|
||||
|
||||
// Validate selection area: "doubleClickMe drag" selected
|
||||
ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 21, 10 }));
|
||||
|
@ -717,7 +717,7 @@ namespace TerminalCoreUnitTests
|
|||
// buffer: doubleClickMe dragThroughHere
|
||||
// ^ ^ ^
|
||||
// start click finish
|
||||
term.SetSelectionEnd({ 21, 10 }, ::Terminal::SelectionExpansionMode::Word);
|
||||
term.SetSelectionEnd({ 21, 10 }, Terminal::SelectionExpansion::Word);
|
||||
|
||||
// Validate selection area: "doubleClickMe dragThroughHere" selected
|
||||
ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 32, 10 }));
|
||||
|
@ -730,7 +730,7 @@ namespace TerminalCoreUnitTests
|
|||
// buffer: doubleClickMe dragThroughHere |
|
||||
// ^ ^ ^
|
||||
// start click finish (boundary)
|
||||
term.SetSelectionEnd({ 21, 10 }, ::Terminal::SelectionExpansionMode::Line);
|
||||
term.SetSelectionEnd({ 21, 10 }, Terminal::SelectionExpansion::Line);
|
||||
|
||||
// Validate selection area: "doubleClickMe dragThroughHere..." selected
|
||||
ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 99, 10 }));
|
||||
|
@ -743,7 +743,7 @@ namespace TerminalCoreUnitTests
|
|||
// buffer: doubleClickMe dragThroughHere
|
||||
// ^ ^ ^
|
||||
// start click finish
|
||||
term.SetSelectionEnd({ 21, 10 }, ::Terminal::SelectionExpansionMode::Word);
|
||||
term.SetSelectionEnd({ 21, 10 }, Terminal::SelectionExpansion::Word);
|
||||
|
||||
// Validate selection area: "doubleClickMe dragThroughHere" selected
|
||||
ValidateSingleRowSelection(term, SMALL_RECT({ 4, 10, 32, 10 }));
|
||||
|
@ -825,7 +825,7 @@ namespace TerminalCoreUnitTests
|
|||
|
||||
// Step 4: Shift+Click at (5,10)
|
||||
{
|
||||
term.SetSelectionEnd({ 5, 10 }, ::Terminal::SelectionExpansionMode::Cell);
|
||||
term.SetSelectionEnd({ 5, 10 }, Terminal::SelectionExpansion::Char);
|
||||
|
||||
// Validate selection area
|
||||
// NOTE: Pivot should still be (10, 10)
|
||||
|
@ -834,7 +834,7 @@ namespace TerminalCoreUnitTests
|
|||
|
||||
// Step 5: Shift+Click back at (20,10)
|
||||
{
|
||||
term.SetSelectionEnd({ 20, 10 }, ::Terminal::SelectionExpansionMode::Cell);
|
||||
term.SetSelectionEnd({ 20, 10 }, Terminal::SelectionExpansion::Char);
|
||||
|
||||
// Validate selection area
|
||||
// NOTE: Pivot should still be (10, 10)
|
||||
|
|
|
@ -2253,7 +2253,7 @@ void TextBufferTests::GetGlyphBoundaries()
|
|||
_buffer->Write(iter, target);
|
||||
|
||||
auto start = _buffer->GetGlyphStart(target);
|
||||
auto end = _buffer->GetGlyphEnd(target);
|
||||
auto end = _buffer->GetGlyphEnd(target, true);
|
||||
|
||||
VERIFY_ARE_EQUAL(test.start, start);
|
||||
VERIFY_ARE_EQUAL(wideGlyph ? test.wideGlyphEnd : test.normalEnd, end);
|
||||
|
|
|
@ -493,6 +493,7 @@ void DxEngine::_ComputePixelShaderSettings() noexcept
|
|||
// actual failure from the API itself.
|
||||
[[nodiscard]] HRESULT DxEngine::_CreateSurfaceHandle() noexcept
|
||||
{
|
||||
#pragma warning(suppress : 26447)
|
||||
wil::unique_hmodule hDComp{ LoadLibraryEx(L"Dcomp.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) };
|
||||
RETURN_LAST_ERROR_IF(hDComp.get() == nullptr);
|
||||
|
||||
|
|
|
@ -295,7 +295,7 @@ void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit)
|
|||
if (unit == TextUnit_Character)
|
||||
{
|
||||
_start = buffer.GetGlyphStart(_start, documentEnd);
|
||||
_end = buffer.GetGlyphEnd(_start, documentEnd);
|
||||
_end = buffer.GetGlyphEnd(_start, true, documentEnd);
|
||||
}
|
||||
else if (unit <= TextUnit_Word)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue