Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added CopyOnSelect as a Global Setting #2152

Merged
13 commits merged into from
Aug 20, 2019
1 change: 1 addition & 0 deletions doc/cascadia/SettingsSchema.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Properties listed below affect the entire window, regardless of the profile sett
| Property | Necessity | Type | Default | Description |
| -------- | --------- | ---- | ------- | ----------- |
| `alwaysShowTabs` | _Required_ | Boolean | `true` | When set to `true`, tabs are always displayed. When set to `false` and `showTabsInTitlebar` is set to `false`, tabs only appear after typing <kbd>Ctrl</kbd> + <kbd>T</kbd>. |
| `copyOnSelect` | Optional | Boolean | `false` | When set to `true`, a selection is immediately copied to your clipboard upon creation. When set to `false`, the selection persists and awaits further action. |
| `defaultProfile` | _Required_ | String | PowerShell guid | Sets the default profile. Opens by typing <kbd>Ctrl</kbd> + <kbd>T</kbd> or by clicking the '+' icon. The guid of the desired default profile is used as the value. |
| `initialCols` | _Required_ | Integer | `120` | The number of columns displayed in the window upon first load. |
| `initialRows` | _Required_ | Integer | `30` | The number of rows displayed in the window upon first load. |
Expand Down
21 changes: 20 additions & 1 deletion src/cascadia/TerminalApp/GlobalAppSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ static constexpr std::string_view ShowTitleInTitlebarKey{ "showTerminalTitleInTi
static constexpr std::string_view RequestedThemeKey{ "requestedTheme" };
static constexpr std::string_view ShowTabsInTitlebarKey{ "showTabsInTitlebar" };
static constexpr std::string_view WordDelimitersKey{ "wordDelimiters" };
static constexpr std::string_view CopyOnSelectKey{ "copyOnSelect" };

static constexpr std::wstring_view LightThemeValue{ L"light" };
static constexpr std::wstring_view DarkThemeValue{ L"dark" };
Expand All @@ -39,7 +40,8 @@ GlobalAppSettings::GlobalAppSettings() :
_showTitleInTitlebar{ true },
_showTabsInTitlebar{ true },
_requestedTheme{ ElementTheme::Default },
_wordDelimiters{ DEFAULT_WORD_DELIMITERS }
_wordDelimiters{ DEFAULT_WORD_DELIMITERS },
_copyOnSelect{ false }
{
}

Expand Down Expand Up @@ -117,6 +119,16 @@ void GlobalAppSettings::SetWordDelimiters(const std::wstring wordDelimiters) noe
_wordDelimiters = wordDelimiters;
}

bool GlobalAppSettings::GetCopyOnSelect() const noexcept
{
return _copyOnSelect;
}

void GlobalAppSettings::SetCopyOnSelect(const bool copyOnSelect) noexcept
{
_copyOnSelect = copyOnSelect;
}

#pragma region ExperimentalSettings
bool GlobalAppSettings::GetShowTabsInTitlebar() const noexcept
{
Expand All @@ -141,6 +153,7 @@ void GlobalAppSettings::ApplyToSettings(TerminalSettings& settings) const noexce
settings.InitialRows(_initialRows);
settings.InitialCols(_initialCols);
settings.WordDelimiters(_wordDelimiters);
settings.CopyOnSelect(_copyOnSelect);
}

// Method Description:
Expand All @@ -160,6 +173,7 @@ Json::Value GlobalAppSettings::ToJson() const
jsonObject[JsonKey(ShowTitleInTitlebarKey)] = _showTitleInTitlebar;
jsonObject[JsonKey(ShowTabsInTitlebarKey)] = _showTabsInTitlebar;
jsonObject[JsonKey(WordDelimitersKey)] = winrt::to_string(_wordDelimiters);
jsonObject[JsonKey(CopyOnSelectKey)] = _copyOnSelect;
jsonObject[JsonKey(RequestedThemeKey)] = winrt::to_string(_SerializeTheme(_requestedTheme));
jsonObject[JsonKey(KeybindingsKey)] = AppKeyBindingsSerialization::ToJson(_keybindings);

Expand Down Expand Up @@ -210,6 +224,11 @@ GlobalAppSettings GlobalAppSettings::FromJson(const Json::Value& json)
result._wordDelimiters = GetWstringFromJson(wordDelimiters);
}

if (auto copyOnSelect{ json[JsonKey(CopyOnSelectKey)] })
{
result._copyOnSelect = copyOnSelect.asBool();
}

if (auto requestedTheme{ json[JsonKey(RequestedThemeKey)] })
{
result._requestedTheme = _ParseTheme(GetWstringFromJson(requestedTheme));
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalApp/GlobalAppSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class TerminalApp::GlobalAppSettings final
std::wstring GetWordDelimiters() const noexcept;
void SetWordDelimiters(const std::wstring wordDelimiters) noexcept;

bool GetCopyOnSelect() const noexcept;
void SetCopyOnSelect(const bool copyOnSelect) noexcept;

winrt::Windows::UI::Xaml::ElementTheme GetRequestedTheme() const noexcept;

Json::Value ToJson() const;
Expand All @@ -72,6 +75,7 @@ class TerminalApp::GlobalAppSettings final

bool _showTabsInTitlebar;
std::wstring _wordDelimiters;
bool _copyOnSelect;
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;

static winrt::Windows::UI::Xaml::ElementTheme _ParseTheme(const std::wstring& themeString) noexcept;
Expand Down
29 changes: 26 additions & 3 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
else if (point.Properties().IsRightButtonPressed())
{
// copy selection, if one exists
if (_terminal->IsSelectionActive())
// copyOnSelect causes right-click to always paste
if (_terminal->IsSelectionActive() && !_terminal->IsCopyOnSelectActive())
{
CopySelectionToClipboard(!shiftEnabled);
}
Expand Down Expand Up @@ -843,7 +844,26 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation

const auto ptr = args.Pointer();

if (ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Touch)
if (ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Mouse)
{
const auto modifiers = static_cast<uint32_t>(args.KeyModifiers());
// static_cast to a uint32_t because we can't use the WI_IsFlagSet
// macro directly with a VirtualKeyModifiers
const auto shiftEnabled = WI_IsFlagSet(modifiers, static_cast<uint32_t>(VirtualKeyModifiers::Shift));

// copyOnSelect if there's an active selection...
if (_terminal->IsCopyOnSelectActive() && _terminal->IsSelectionActive())
{
// copy if not single cell selection...
// or if single cell copy allowed (drag off of single cell then back onto it)
if (!_terminal->IsSingleCellSelection() ||
(_terminal->IsSingleCellSelection() && _terminal->IsSingleCellCopyAllowed()))
{
CopySelectionToClipboard(!shiftEnabled);
}
}
}
else if (ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Touch)
{
_touchAnchor = std::nullopt;
}
Expand Down Expand Up @@ -1354,7 +1374,10 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// extract text from buffer
const auto copiedData = _terminal->RetrieveSelectedTextFromBuffer(trimTrailingWhitespace);

_terminal->ClearSelection();
if (!_terminal->IsCopyOnSelectActive())
{
_terminal->ClearSelection();
}

// send data up for clipboard
_clipboardCopyHandlers(copiedData);
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ Terminal::Terminal() :
_snapOnInput{ true },
_boxSelection{ false },
_selectionActive{ false },
_allowSingleCharSelection{ false },
_copyOnSelect{ false },
_selectionAnchor{ 0, 0 },
_endSelectionPosition{ 0, 0 }
{
Expand Down Expand Up @@ -135,6 +137,8 @@ void Terminal::UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSetting

_wordDelimiters = settings.WordDelimiters();

_copyOnSelect = settings.CopyOnSelect();

// TODO:MSFT:21327402 - if HistorySize has changed, resize the buffer so we
// have a smaller scrollback. We should do this carefully - if the new buffer
// size is smaller than where the mutable viewport currently is, we'll want
Expand Down
8 changes: 7 additions & 1 deletion src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ class Microsoft::Terminal::Core::Terminal final :

#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
const bool IsSingleCellSelection() const noexcept;
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
const bool IsSingleCellCopyAllowed() const noexcept;
const bool IsSelectionActive() const noexcept;
const bool IsCopyOnSelectActive() const noexcept;
void DoubleClickSelection(const COORD position);
void TripleClickSelection(const COORD position);
void SetSelectionAnchor(const COORD position);
Expand All @@ -160,14 +163,17 @@ class Microsoft::Terminal::Core::Terminal final :

bool _snapOnInput;

// Text Selection
#pragma region Text Selection
COORD _selectionAnchor;
COORD _endSelectionPosition;
bool _boxSelection;
bool _selectionActive;
bool _allowSingleCharSelection;
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
bool _copyOnSelect;
SHORT _selectionAnchor_YOffset;
SHORT _endSelectionPosition_YOffset;
std::wstring _wordDelimiters;
#pragma endregion

std::shared_mutex _readWriteLock;

Expand Down
46 changes: 45 additions & 1 deletion src/cascadia/TerminalCore/TerminalSelection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ std::vector<SMALL_RECT> Terminal::_GetSelectionRects() const
{
std::vector<SMALL_RECT> selectionArea;

if (!_selectionActive)
// copyOnSelect: don't render selection on single cell
// (unless specifically allowed by highlighting more than one cell then reducing it)
if (_copyOnSelect && !_allowSingleCharSelection && IsSingleCellSelection())
{
return selectionArea;
}

if (!IsSelectionActive())
{
return selectionArea;
}
Expand Down Expand Up @@ -121,6 +128,24 @@ const SHORT Terminal::_ExpandWideGlyphSelectionRight(const SHORT xPos, const SHO
return position.X;
}

// Method Description:
// - Checks if selection is on a single cell
// Return Value:
// - bool representing if selection is only a single cell. Used for copyOnSelect
const bool Terminal::IsSingleCellSelection() const noexcept
{
return (_selectionAnchor == _endSelectionPosition);
}

// Method Description:
// - Checks if selection on a single cell is allowed for rendering purposes
// Return Value:
// - bool representing if selection is only a single cell. Used for copyOnSelect
const bool Terminal::IsSingleCellCopyAllowed() const noexcept
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this and the above be folded into IsSelectionActive?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one can be deleted once the TermControl caller goes away

{
return _allowSingleCharSelection;
}

// Method Description:
// - Checks if selection is active
// Return Value:
Expand All @@ -130,6 +155,15 @@ const bool Terminal::IsSelectionActive() const noexcept
return _selectionActive;
}

// Method Description:
// - Checks if the CopyOnSelect setting is active
// Return Value:
// - true if feature is active, false otherwise.
const bool Terminal::IsCopyOnSelectActive() const noexcept
{
return _copyOnSelect;
}

// Method Description:
// - Select the sequence between delimiters defined in Settings
// Arguments:
Expand Down Expand Up @@ -180,6 +214,10 @@ void Terminal::SetSelectionAnchor(const COORD position)
_selectionAnchor_YOffset = gsl::narrow<SHORT>(_ViewStartIndex());

_selectionActive = true;
if (_copyOnSelect)
{
_allowSingleCharSelection = false;
}
SetEndSelectionPosition(position);
}

Expand All @@ -197,6 +235,11 @@ void Terminal::SetEndSelectionPosition(const COORD position)
// copy value of ViewStartIndex to support scrolling
// and update on new buffer output (used in _GetSelectionRects())
_endSelectionPosition_YOffset = gsl::narrow<SHORT>(_ViewStartIndex());

if (_copyOnSelect && !IsSingleCellSelection())
{
_allowSingleCharSelection = true;
}
}

// Method Description:
Expand All @@ -213,6 +256,7 @@ void Terminal::SetBoxSelection(const bool isEnabled) noexcept
void Terminal::ClearSelection()
{
_selectionActive = false;
_allowSingleCharSelection = false;
_selectionAnchor = { 0, 0 };
_endSelectionPosition = { 0, 0 };
_selectionAnchor_YOffset = 0;
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettings/ICoreSettings.idl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace Microsoft.Terminal.Settings
CursorStyle CursorShape;
UInt32 CursorHeight;
String WordDelimiters;
Boolean CopyOnSelect;
};

}
11 changes: 11 additions & 0 deletions src/cascadia/TerminalSettings/TerminalSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
_cursorShape{ CursorStyle::Vintage },
_cursorHeight{ DEFAULT_CURSOR_HEIGHT },
_wordDelimiters{ DEFAULT_WORD_DELIMITERS },
_copyOnSelect{ false },
_useAcrylic{ false },
_closeOnExit{ true },
_tintOpacity{ 0.5 },
Expand Down Expand Up @@ -148,6 +149,16 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
_wordDelimiters = value;
}

bool TerminalSettings::CopyOnSelect()
{
return _copyOnSelect;
}

void TerminalSettings::CopyOnSelect(bool value)
{
_copyOnSelect = value;
}

bool TerminalSettings::UseAcrylic()
{
return _useAcrylic;
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalSettings/terminalsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
void CursorHeight(uint32_t value);
hstring WordDelimiters();
void WordDelimiters(hstring const& value);
bool CopyOnSelect();
void CopyOnSelect(bool value);
// ------------------------ End of Core Settings -----------------------

bool UseAcrylic();
Expand Down Expand Up @@ -113,6 +115,7 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
winrt::Windows::UI::Xaml::Media::Stretch _backgroundImageStretchMode;
winrt::Windows::UI::Xaml::HorizontalAlignment _backgroundImageHorizontalAlignment;
winrt::Windows::UI::Xaml::VerticalAlignment _backgroundImageVerticalAlignment;
bool _copyOnSelect;
hstring _commandline;
hstring _startingDir;
hstring _envVars;
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/UnitTests_TerminalCore/ScreenSizeLimitsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ namespace TerminalCoreUnitTests
CursorStyle CursorShape() const noexcept { return CursorStyle::Vintage; }
uint32_t CursorHeight() { return 42UL; }
winrt::hstring WordDelimiters() { return winrt::to_hstring(DEFAULT_WORD_DELIMITERS.c_str()); }
bool CopyOnSelect() { return false; }

// other implemented methods
uint32_t GetColorTableEntry(int32_t) const { return 123; }
Expand All @@ -52,6 +53,7 @@ namespace TerminalCoreUnitTests
void CursorShape(CursorStyle const&) noexcept {}
void CursorHeight(uint32_t) {}
void WordDelimiters(winrt::hstring) {}
void CopyOnSelect(bool) {}

// other unimplemented methods
void SetColorTableEntry(int32_t /* index */, uint32_t /* value */) {}
Expand Down