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

Add tooltips to the Suggestions Control #14939

Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
06874ee
dirty, but now with tooltips
zadjii-msft Feb 24, 2023
c839bfa
Cleanup for... review?
zadjii-msft Feb 24, 2023
e09379c
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Mar 1, 2023
dcdb145
Dismiss tooltip on close
zadjii-msft Mar 1, 2023
de56d9e
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Mar 1, 2023
110bb7d
surprisingly load bearing
zadjii-msft Mar 1, 2023
059fa07
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Mar 20, 2023
a010e23
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Mar 24, 2023
c49f765
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Apr 5, 2023
56cc44d
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft May 31, 2023
39c5b63
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Jul 5, 2023
faa6665
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Aug 2, 2023
f33a35b
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Aug 2, 2023
6368a6d
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Aug 8, 2023
6ee0d9f
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Aug 9, 2023
53281b8
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Aug 9, 2023
33197c5
Merge branch 'dev/migrie/fhl-2023/pwsh-autocomplete-demo' into dev/mi…
zadjii-msft Aug 9, 2023
a1043ba
a bunch of notes before I abandon this
zadjii-msft Aug 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 73 additions & 3 deletions src/cascadia/TerminalApp/SuggestionsControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <LibraryResources.h>

#include "SuggestionsControl.g.cpp"
#include "../../types/inc/utils.hpp"

using namespace winrt;
using namespace winrt::TerminalApp;
Expand All @@ -19,6 +20,8 @@ using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;

using namespace std::chrono_literals;

namespace winrt::TerminalApp::implementation
{
SuggestionsControl::SuggestionsControl()
Expand Down Expand Up @@ -262,8 +265,8 @@ namespace winrt::TerminalApp::implementation
// - <unused>
// Return Value:
// - <none>
void SuggestionsControl::_selectedCommandChanged(const IInspectable& /*sender*/,
const Windows::UI::Xaml::RoutedEventArgs& /*args*/)
winrt::fire_and_forget SuggestionsControl::_selectedCommandChanged(const IInspectable& /*sender*/,
const Windows::UI::Xaml::RoutedEventArgs& /*args*/)
{
const auto selectedCommand = _filteredActionsView().SelectedItem();
const auto filteredCommand{ selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>() };
Expand All @@ -281,9 +284,75 @@ namespace winrt::TerminalApp::implementation
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
{
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto& cmd = actionPaletteItem.Command();
PreviewAction.raise(*this, cmd);

const auto description{ cmd.Description() };
if (!description.empty())
{
// If it's already open, then just re-target it and update the content immediately.
if (DescriptionTip().IsOpen())
{
_openTooltip(cmd);
}
else
{
// Otherwise, wait a bit before opening it.
co_await winrt::resume_after(200ms);
co_await wil::resume_foreground(Dispatcher());
_openTooltip(cmd);
DescriptionTip().IsOpen(true);
}
}
else
{
// If there's no description, then just close the tooltip.
DescriptionTip().IsOpen(false);
}
}
}
}

winrt::fire_and_forget SuggestionsControl::_openTooltip(Command cmd)
{
const auto description{ cmd.Description() };

if (!cmd.Description().empty())
{
DescriptionTip().Target(SelectedItem());
DescriptionTip().Title(cmd.Name());

// If you try to put a newline in the Subtitle, it'll _immediately
// close the tooltip_. Instead, we'll need to build up the text as a
// series of runs, and put them in the content.

_toolTipContent().Inlines().Clear();

// First, replace all "\r\n" with "\n"
std::wstring filtered = description.c_str();

// replace all "\r\n" with "\n" in `filtered`
std::wstring::size_type pos = 0;
while ((pos = filtered.find(L"\r\n", pos)) != std::wstring::npos)
{
filtered.erase(pos, 1);
}

// Split the filtered description on '\n`
const auto lines = ::Microsoft::Console::Utils::SplitString(filtered.c_str(), L'\n');
// For each line, build a Run + LineBreak, and add them to the text
// block
for (const auto& line : lines)
{
if (line.empty())
continue;
Documents::Run textRun;
textRun.Text(winrt::hstring{ line });
_toolTipContent().Inlines().Append(textRun);
_toolTipContent().Inlines().Append(Documents::LineBreak{});
}
}
co_return;
}

void SuggestionsControl::_previewKeyDownHandler(const IInspectable& /*sender*/,
Expand Down Expand Up @@ -946,6 +1015,7 @@ namespace winrt::TerminalApp::implementation
void SuggestionsControl::_close()
{
Visibility(Visibility::Collapsed);
DescriptionTip().IsOpen(false);

// Clear the text box each time we close the dialog. This is consistent with VsCode.
_searchBox().Text(L"");
Expand Down
6 changes: 5 additions & 1 deletion src/cascadia/TerminalApp/SuggestionsControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ namespace winrt::TerminalApp::implementation

void _listItemClicked(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::ItemClickEventArgs& e);
void _listItemSelectionChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& e);
void _selectedCommandChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);

winrt::fire_and_forget _selectedCommandChanged(const Windows::Foundation::IInspectable& sender,
const Windows::UI::Xaml::RoutedEventArgs& args);

winrt::fire_and_forget _openTooltip(Microsoft::Terminal::Settings::Model::Command cmd);

void _moveBackButtonClicked(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs&);
void _updateCurrentNestedCommands(const winrt::Microsoft::Terminal::Settings::Model::Command& parentCommand);
Expand Down
11 changes: 11 additions & 0 deletions src/cascadia/TerminalApp/SuggestionsControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,17 @@
ItemsSource="{x:Bind FilteredActions}"
SelectionChanged="_listItemSelectionChanged"
SelectionMode="Single" />
<mux:TeachingTip x:Name="DescriptionTip"
Title=""
IsOpen="False"
PreferredPlacement="Right"
ShouldConstrainToRootBounds="False"
Subtitle="">
Copy link
Member

Choose a reason for hiding this comment

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

Is "Subtitle" necessary? Why?

Copy link
Member

Choose a reason for hiding this comment

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

Same with Title?

Also, looks like the WinUI docs don't say the default value (grr). So, mind checking each of these to make sure they're necessary?

<ScrollViewer HorizontalScrollBarVisibility="Hidden"
HorizontalScrollMode="Enabled">
<TextBlock x:Name="_toolTipContent" />
</ScrollViewer>
</mux:TeachingTip>

</Grid>

Expand Down
10 changes: 8 additions & 2 deletions src/cascadia/TerminalSettingsModel/Command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static constexpr std::string_view ArgsKey{ "args" };
static constexpr std::string_view IterateOnKey{ "iterateOn" };
static constexpr std::string_view CommandsKey{ "commands" };
static constexpr std::string_view KeysKey{ "keys" };
static constexpr std::string_view DescriptionKey{ "description" };

static constexpr std::string_view ProfileNameToken{ "${profile.name}" };
static constexpr std::string_view ProfileIconToken{ "${profile.icon}" };
Expand All @@ -40,6 +41,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
auto command{ winrt::make_self<Command>() };
command->_name = _name;
command->_Description = _Description;
command->_ActionAndArgs = *get_self<implementation::ActionAndArgs>(_ActionAndArgs)->Copy();
command->_keyMappings = _keyMappings;
command->_iconPath = _iconPath;
Expand Down Expand Up @@ -254,7 +256,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation

auto nested = false;
JsonUtils::GetValueForKey(json, IterateOnKey, result->_IterateOn);

JsonUtils::GetValueForKey(json, DescriptionKey, result->_Description);
// For iterable commands, we'll make another pass at parsing them once
// the json is patched. So ignore parsing sub-commands for now. Commands
// will only be marked iterable on the first pass.
Expand Down Expand Up @@ -406,7 +408,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Json::Value cmdJson{ Json::ValueType::objectValue };
JsonUtils::SetValueForKey(cmdJson, IconKey, _iconPath);
JsonUtils::SetValueForKey(cmdJson, NameKey, _name);

JsonUtils::SetValueForKey(cmdJson, DescriptionKey, _Description);
if (_ActionAndArgs)
{
cmdJson[JsonKey(ActionKey)] = ActionAndArgs::ToJson(_ActionAndArgs);
Expand All @@ -426,6 +428,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// First iteration also writes icon and name
JsonUtils::SetValueForKey(cmdJson, IconKey, _iconPath);
JsonUtils::SetValueForKey(cmdJson, NameKey, _name);
JsonUtils::SetValueForKey(cmdJson, DescriptionKey, _Description);
}

if (_ActionAndArgs)
Expand Down Expand Up @@ -654,8 +657,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
const auto parseElement = [&](const auto& element) {
winrt::hstring completionText;
winrt::hstring listText;
winrt::hstring tooltipText;
JsonUtils::GetValueForKey(element, "CompletionText", completionText);
JsonUtils::GetValueForKey(element, "ListItemText", listText);
JsonUtils::GetValueForKey(element, "ToolTip", tooltipText);

auto args = winrt::make_self<SendInputArgs>(
winrt::hstring{ fmt::format(FMT_COMPILE(L"{:\x7f^{}}{}"),
Expand All @@ -668,6 +673,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
auto c = winrt::make_self<Command>();
c->_name = listText;
c->_ActionAndArgs = actionAndArgs;
c->_Description = tooltipText;

// Try to assign a sensible icon based on the result type. These are
// roughly chosen to align with the icons in
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettingsModel/Command.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation

WINRT_PROPERTY(ExpandCommandType, IterateOn, ExpandCommandType::None);
WINRT_PROPERTY(Model::ActionAndArgs, ActionAndArgs);
WINRT_PROPERTY(winrt::hstring, Description, L"");

private:
Json::Value _originalJson;
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalSettingsModel/Command.idl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ namespace Microsoft.Terminal.Settings.Model
Command();

String Name { get; };
String Description { get; };

ActionAndArgs ActionAndArgs { get; };
Microsoft.Terminal.Control.KeyChord Keys { get; };
void RegisterKey(Microsoft.Terminal.Control.KeyChord keys);
Expand Down