Add an action to search the web for selected text (#15539)
This PR adds a `searchWeb` command to search the selected text on the web. Arguments: - `queryUrl`: URL of the web page to launch (the selected text will be inserted where the first `%s` is found in the query string) To make the search text more "compact" and handle multi-line selections, I'm concatenating the selected lines and replacing consecutive whitespaces with a single space (we may change this with something more clever in case). ## Validation Steps Performed Manual testing with single, multi-line, block selections. Closes #10175 --------- Co-authored-by: Marco Pelagatti <marco.pelagatti@iongroup.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
This commit is contained in:
parent
2386abb8df
commit
40963c7b18
|
@ -421,6 +421,7 @@
|
|||
"scrollToMark",
|
||||
"clearMark",
|
||||
"clearAllMarks",
|
||||
"searchWeb",
|
||||
"experimental.colorSelection",
|
||||
"unbound"
|
||||
],
|
||||
|
@ -1709,6 +1710,29 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"SearchWebAction": {
|
||||
"description": "Search the web for selected text",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/$defs/ShortcutAction"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "searchWeb"
|
||||
},
|
||||
"queryUrl": {
|
||||
"type": "string",
|
||||
"description": "URL of the web page to launch, %s is replaced with the selected text"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [
|
||||
"queryUrl"
|
||||
]
|
||||
},
|
||||
"AdjustOpacityAction": {
|
||||
"description": "Changes the opacity of the active Terminal window. If `relative` is specified, then this action will increase/decrease relative to the current opacity.",
|
||||
"allOf": [
|
||||
|
@ -2004,6 +2028,9 @@
|
|||
{
|
||||
"$ref": "#/$defs/ColorSelectionAction"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/SearchWebAction"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
|
|
|
@ -1021,6 +1021,49 @@ namespace winrt::TerminalApp::implementation
|
|||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleSearchForText(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (const auto termControl{ _GetActiveControl() })
|
||||
{
|
||||
if (termControl.HasSelection())
|
||||
{
|
||||
const auto selections{ termControl.SelectedText(true) };
|
||||
|
||||
// concatenate the selection into a single line
|
||||
auto searchText = std::accumulate(selections.begin(), selections.end(), std::wstring());
|
||||
|
||||
// make it compact by replacing consecutive whitespaces with a single space
|
||||
searchText = std::regex_replace(searchText, std::wregex(LR"(\s+)"), L" ");
|
||||
|
||||
std::wstring queryUrl;
|
||||
if (args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<SearchForTextArgs>())
|
||||
{
|
||||
queryUrl = realArgs.QueryUrl().c_str();
|
||||
}
|
||||
}
|
||||
|
||||
// use global default if query URL is unspecified
|
||||
if (queryUrl.empty())
|
||||
{
|
||||
queryUrl = _settings.GlobalSettings().SearchWebDefaultQueryUrl().c_str();
|
||||
}
|
||||
|
||||
constexpr std::wstring_view queryToken{ L"%s" };
|
||||
if (const auto pos{ queryUrl.find(queryToken) }; pos != std::wstring_view::npos)
|
||||
{
|
||||
queryUrl.replace(pos, queryToken.length(), Windows::Foundation::Uri::EscapeComponent(searchText));
|
||||
}
|
||||
|
||||
winrt::Microsoft::Terminal::Control::OpenHyperlinkEventArgs shortcut{ queryUrl };
|
||||
_OpenHyperlinkHandler(termControl, shortcut);
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleGlobalSummon(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
|
|
|
@ -214,6 +214,9 @@
|
|||
<data name="SplitPaneText" xml:space="preserve">
|
||||
<value>Split Pane</value>
|
||||
</data>
|
||||
<data name="SearchWebText" xml:space="preserve">
|
||||
<value>Web Search</value>
|
||||
</data>
|
||||
<data name="TabColorChoose" xml:space="preserve">
|
||||
<value>Color...</value>
|
||||
</data>
|
||||
|
|
|
@ -4581,7 +4581,7 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
|
||||
void TerminalPage::_PopulateContextMenu(const IInspectable& sender,
|
||||
const bool /*withSelection*/)
|
||||
const bool withSelection)
|
||||
{
|
||||
// withSelection can be used to add actions that only appear if there's
|
||||
// selected text, like "search the web". In this initial draft, it's not
|
||||
|
@ -4638,6 +4638,11 @@ namespace winrt::TerminalApp::implementation
|
|||
makeItem(RS_(L"PaneClose"), L"\xE89F", ActionAndArgs{ ShortcutAction::ClosePane, nullptr });
|
||||
}
|
||||
|
||||
if (withSelection)
|
||||
{
|
||||
makeItem(RS_(L"SearchWebText"), L"\xF6FA", ActionAndArgs{ ShortcutAction::SearchForText, nullptr });
|
||||
}
|
||||
|
||||
makeItem(RS_(L"TabClose"), L"\xE711", ActionAndArgs{ ShortcutAction::CloseTab, CloseTabArgs{ _GetFocusedTabIndex().value() } });
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
int ViewHeight() const;
|
||||
int BufferHeight() const;
|
||||
|
||||
bool HasSelection() const;
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
|
||||
|
||||
bool BracketedPasteEnabled() const noexcept;
|
||||
|
||||
Windows::Foundation::Collections::IVector<Control::ScrollMark> ScrollMarks() const;
|
||||
|
@ -188,9 +191,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
bool ShouldSendAlternateScroll(const unsigned int uiButton, const int32_t delta) const;
|
||||
Core::Point CursorPosition() const;
|
||||
|
||||
bool HasSelection() const;
|
||||
bool CopyOnSelect() const;
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
|
||||
Control::SelectionData SelectionInfo() const;
|
||||
void SetSelectionAnchor(const til::point position);
|
||||
void SetEndSelectionPoint(const til::point position);
|
||||
|
|
|
@ -124,8 +124,6 @@ namespace Microsoft.Terminal.Control
|
|||
void Search(String text, Boolean goForward, Boolean caseSensitive);
|
||||
Microsoft.Terminal.Core.Color BackgroundColor { get; };
|
||||
|
||||
Boolean HasSelection { get; };
|
||||
IVector<String> SelectedText(Boolean trimTrailingWhitespace);
|
||||
SelectionData SelectionInfo { get; };
|
||||
SelectionInteractionMode SelectionMode();
|
||||
|
||||
|
|
|
@ -180,3 +180,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
WINRT_PROPERTY(bool, ClearMarkers, false);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(OpenHyperlinkEventArgs);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace Microsoft.Terminal.Control
|
|||
|
||||
runtimeclass OpenHyperlinkEventArgs
|
||||
{
|
||||
OpenHyperlinkEventArgs(String uri);
|
||||
String Uri { get; };
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@ namespace Microsoft.Terminal.Control
|
|||
Int32 ViewHeight { get; };
|
||||
Int32 BufferHeight { get; };
|
||||
|
||||
Boolean HasSelection { get; };
|
||||
IVector<String> SelectedText(Boolean trimTrailingWhitespace);
|
||||
|
||||
Boolean BracketedPasteEnabled { get; };
|
||||
|
||||
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
|
||||
|
|
|
@ -3335,6 +3335,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
return _core.Opacity();
|
||||
}
|
||||
|
||||
bool TermControl::HasSelection() const
|
||||
{
|
||||
return _core.HasSelection();
|
||||
}
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> TermControl::SelectedText(bool trimTrailingWhitespace) const
|
||||
{
|
||||
return _core.SelectedText(trimTrailingWhitespace);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when the core raises a FoundMatch event. That's done in response
|
||||
// to us starting a search query with ControlCore::Search.
|
||||
|
|
|
@ -69,6 +69,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
int ViewHeight() const;
|
||||
int BufferHeight() const;
|
||||
|
||||
bool HasSelection() const;
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
|
||||
|
||||
bool BracketedPasteEnabled() const noexcept;
|
||||
|
||||
double BackgroundOpacity() const;
|
||||
|
|
|
@ -72,6 +72,7 @@ static constexpr std::string_view IdentifyWindowKey{ "identifyWindow" };
|
|||
static constexpr std::string_view IdentifyWindowsKey{ "identifyWindows" };
|
||||
static constexpr std::string_view RenameWindowKey{ "renameWindow" };
|
||||
static constexpr std::string_view OpenWindowRenamerKey{ "openWindowRenamer" };
|
||||
static constexpr std::string_view SearchForTextKey{ "searchWeb" };
|
||||
static constexpr std::string_view GlobalSummonKey{ "globalSummon" };
|
||||
static constexpr std::string_view QuakeModeKey{ "quakeMode" };
|
||||
static constexpr std::string_view FocusPaneKey{ "focusPane" };
|
||||
|
@ -403,6 +404,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
{ ShortcutAction::RenameWindow, RS_(L"ResetWindowNameCommandKey") },
|
||||
{ ShortcutAction::OpenWindowRenamer, RS_(L"OpenWindowRenamerCommandKey") },
|
||||
{ ShortcutAction::GlobalSummon, MustGenerate },
|
||||
{ ShortcutAction::SearchForText, MustGenerate },
|
||||
{ ShortcutAction::QuakeMode, RS_(L"QuakeModeCommandKey") },
|
||||
{ ShortcutAction::FocusPane, MustGenerate },
|
||||
{ ShortcutAction::OpenSystemMenu, RS_(L"OpenSystemMenuCommandKey") },
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "PrevTabArgs.g.cpp"
|
||||
#include "NextTabArgs.g.cpp"
|
||||
#include "RenameWindowArgs.g.cpp"
|
||||
#include "SearchForTextArgs.g.cpp"
|
||||
#include "GlobalSummonArgs.g.cpp"
|
||||
#include "FocusPaneArgs.g.cpp"
|
||||
#include "ExportBufferArgs.g.cpp"
|
||||
|
@ -765,6 +766,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
return RS_(L"ResetWindowNameCommandKey");
|
||||
}
|
||||
|
||||
winrt::hstring SearchForTextArgs::GenerateName() const
|
||||
{
|
||||
return winrt::hstring{
|
||||
fmt::format(std::wstring_view(RS_(L"SearchForTextCommandKey")),
|
||||
Windows::Foundation::Uri(QueryUrl()).Domain().c_str())
|
||||
};
|
||||
}
|
||||
|
||||
winrt::hstring GlobalSummonArgs::GenerateName() const
|
||||
{
|
||||
// GH#10210 - Is this action literally the same thing as the `quakeMode`
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "PrevTabArgs.g.h"
|
||||
#include "NextTabArgs.g.h"
|
||||
#include "RenameWindowArgs.g.h"
|
||||
#include "SearchForTextArgs.g.h"
|
||||
#include "GlobalSummonArgs.g.h"
|
||||
#include "FocusPaneArgs.g.h"
|
||||
#include "ExportBufferArgs.g.h"
|
||||
|
@ -227,6 +228,10 @@ private: \
|
|||
#define RENAME_WINDOW_ARGS(X) \
|
||||
X(winrt::hstring, Name, "name", false, L"")
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SEARCH_FOR_TEXT_ARGS(X) \
|
||||
X(winrt::hstring, QueryUrl, "queryUrl", false, L"")
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define GLOBAL_SUMMON_ARGS(X) \
|
||||
X(winrt::hstring, Name, "name", false, L"") \
|
||||
|
@ -711,6 +716,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
ACTION_ARGS_STRUCT(RenameWindowArgs, RENAME_WINDOW_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(SearchForTextArgs, SEARCH_FOR_TEXT_ARGS);
|
||||
|
||||
struct GlobalSummonArgs : public GlobalSummonArgsT<GlobalSummonArgs>
|
||||
{
|
||||
ACTION_ARG_BODY(GlobalSummonArgs, GLOBAL_SUMMON_ARGS)
|
||||
|
|
|
@ -349,6 +349,11 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
String Name { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SearchForTextArgs : IActionArgs
|
||||
{
|
||||
String QueryUrl { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass GlobalSummonArgs : IActionArgs
|
||||
{
|
||||
String Name { get; };
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
ON_ALL_ACTIONS(IdentifyWindows) \
|
||||
ON_ALL_ACTIONS(RenameWindow) \
|
||||
ON_ALL_ACTIONS(OpenWindowRenamer) \
|
||||
ON_ALL_ACTIONS(SearchForText) \
|
||||
ON_ALL_ACTIONS(GlobalSummon) \
|
||||
ON_ALL_ACTIONS(QuakeMode) \
|
||||
ON_ALL_ACTIONS(FocusPane) \
|
||||
|
@ -115,6 +116,7 @@
|
|||
ON_ALL_ACTIONS_WITH_ARGS(CopyText) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(ExecuteCommandline) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(FindMatch) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(SearchForText) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(GlobalSummon) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(MoveFocus) \
|
||||
ON_ALL_ACTIONS_WITH_ARGS(MovePane) \
|
||||
|
|
|
@ -100,6 +100,7 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
INHERITABLE_SETTING(Boolean, EnableColorSelection);
|
||||
INHERITABLE_SETTING(Boolean, IsolatedMode);
|
||||
INHERITABLE_SETTING(Boolean, AllowHeadless);
|
||||
INHERITABLE_SETTING(String, SearchWebDefaultQueryUrl);
|
||||
|
||||
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
|
||||
void AddColorScheme(ColorScheme scheme);
|
||||
|
|
|
@ -65,7 +65,8 @@ Author(s):
|
|||
X(bool, EnableColorSelection, "experimental.enableColorSelection", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<Model::NewTabMenuEntry>, NewTabMenu, "newTabMenu", winrt::single_threaded_vector<Model::NewTabMenuEntry>({ Model::RemainingProfilesEntry{} })) \
|
||||
X(bool, AllowHeadless, "compatibility.allowHeadless", false) \
|
||||
X(bool, IsolatedMode, "compatibility.isolatedMode", false)
|
||||
X(bool, IsolatedMode, "compatibility.isolatedMode", false) \
|
||||
X(hstring, SearchWebDefaultQueryUrl, "searchWebDefaultQueryUrl", L"https://www.bing.com/search?q=%22%s%22")
|
||||
|
||||
#define MTSM_PROFILE_SETTINGS(X) \
|
||||
X(int32_t, HistorySize, "historySize", DEFAULT_HISTORY_SIZE) \
|
||||
|
|
|
@ -699,4 +699,12 @@
|
|||
<data name="SelectCommandPreviousCommandKey" xml:space="preserve">
|
||||
<value>Select previous command</value>
|
||||
</data>
|
||||
<data name="SearchForTextCommandKey" xml:space="preserve">
|
||||
<value>Search {0}</value>
|
||||
<comment>{0} will be replaced with a user-specified URL to a web page</comment>
|
||||
</data>
|
||||
<data name="SearchWebCommandKey" xml:space="preserve">
|
||||
<value>Search the web for selected text</value>
|
||||
<comment>This will open a web browser to search for some user-selected text</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -466,6 +466,9 @@
|
|||
{ "command": "expandSelectionToWord" },
|
||||
{ "command": "showContextMenu", "keys": "menu" },
|
||||
|
||||
// Web Search
|
||||
{ "command": { "action": "searchWeb" }, "name": { "key": "SearchWebCommandKey" } },
|
||||
|
||||
// Scrollback
|
||||
{ "command": "scrollDown", "keys": "ctrl+shift+down" },
|
||||
{ "command": "scrollDownPage", "keys": "ctrl+shift+pgdn" },
|
||||
|
|
Loading…
Reference in New Issue