8
8
#include < LibraryResources.h>
9
9
10
10
#include " SuggestionsControl.g.cpp"
11
+ #include " ../../types/inc/utils.hpp"
11
12
12
13
using namespace winrt ;
13
14
using namespace winrt ::TerminalApp;
@@ -19,6 +20,8 @@ using namespace winrt::Windows::Foundation;
19
20
using namespace winrt ::Windows::Foundation::Collections;
20
21
using namespace winrt ::Microsoft::Terminal::Settings::Model;
21
22
23
+ using namespace std ::chrono_literals;
24
+
22
25
namespace winrt ::TerminalApp::implementation
23
26
{
24
27
SuggestionsControl::SuggestionsControl ()
@@ -103,9 +106,7 @@ namespace winrt::TerminalApp::implementation
103
106
// stays "attached" to the cursor.
104
107
if (Visibility () == Visibility::Visible && _direction == TerminalApp::SuggestionsDirection::BottomUp)
105
108
{
106
- auto m = this ->Margin ();
107
- m.Top = (_anchor.Y - ActualHeight ());
108
- this ->Margin (m);
109
+ this ->_recalculateTopMargin ();
109
110
}
110
111
});
111
112
@@ -281,9 +282,78 @@ namespace winrt::TerminalApp::implementation
281
282
{
282
283
if (const auto actionPaletteItem{ filteredCommand.Item ().try_as <winrt::TerminalApp::ActionPaletteItem>() })
283
284
{
284
- PreviewAction.raise (*this , actionPaletteItem.Command ());
285
+ const auto & cmd = actionPaletteItem.Command ();
286
+ PreviewAction.raise (*this , cmd);
287
+
288
+ const auto description{ cmd.Description () };
289
+
290
+ if (const auto & selected{ SelectedItem () })
291
+ {
292
+ selected.SetValue (Automation::AutomationProperties::FullDescriptionProperty (), winrt::box_value (description));
293
+ }
294
+
295
+ if (!description.empty ())
296
+ {
297
+ _openTooltip (cmd);
298
+ }
299
+ else
300
+ {
301
+ // If there's no description, then just close the tooltip.
302
+ _descriptionsView ().Visibility (Visibility::Collapsed);
303
+ _descriptionsBackdrop ().Visibility (Visibility::Collapsed);
304
+ _recalculateTopMargin ();
305
+ }
306
+ }
307
+ }
308
+ }
309
+
310
+ void SuggestionsControl::_openTooltip (Command cmd)
311
+ {
312
+ const auto description{ cmd.Description () };
313
+ if (description.empty ())
314
+ {
315
+ return ;
316
+ }
317
+
318
+ // Build the contents of the "tooltip" based on the description
319
+ //
320
+ // First, the title. This is just the name of the command.
321
+ _descriptionTitle ().Inlines ().Clear ();
322
+ Documents::Run titleRun;
323
+ titleRun.Text (cmd.Name ());
324
+ _descriptionTitle ().Inlines ().Append (titleRun);
325
+
326
+ // Now fill up the "subtitle" part of the "tooltip" with the actual
327
+ // description itself.
328
+ const auto & inlines{ _descriptionComment ().Inlines () };
329
+ inlines.Clear ();
330
+
331
+ // Split the filtered description on '\n`
332
+ const auto lines = ::Microsoft::Console::Utils::SplitString (description, L' \n ' );
333
+ // build a Run + LineBreak, and add them to the text block
334
+ for (const auto & line : lines)
335
+ {
336
+ // Trim off any `\r`'s in the string. Pwsh completions will
337
+ // frequently have these embedded.
338
+ std::wstring trimmed{ line };
339
+ trimmed.erase (std::remove (trimmed.begin (), trimmed.end (), L' \r ' ), trimmed.end ());
340
+ if (trimmed.empty ())
341
+ {
342
+ continue ;
285
343
}
344
+
345
+ Documents::Run textRun;
346
+ textRun.Text (trimmed);
347
+ inlines.Append (textRun);
348
+ inlines.Append (Documents::LineBreak{});
286
349
}
350
+
351
+ // Now, make ourselves visible.
352
+ _descriptionsView ().Visibility (Visibility::Visible);
353
+ _descriptionsBackdrop ().Visibility (Visibility::Visible);
354
+ // and update the padding to account for our new contents.
355
+ _recalculateTopMargin ();
356
+ return ;
287
357
}
288
358
289
359
void SuggestionsControl::_previewKeyDownHandler (const IInspectable& /* sender*/ ,
@@ -1020,16 +1090,71 @@ namespace winrt::TerminalApp::implementation
1020
1090
void SuggestionsControl::_setDirection (TerminalApp::SuggestionsDirection direction)
1021
1091
{
1022
1092
_direction = direction;
1093
+
1094
+ // We need to move either the list of suggestions, or the tooltip, to
1095
+ // the top of the stack panel (depending on the layout).
1096
+ Grid controlToMoveToTop = nullptr ;
1097
+
1023
1098
if (_direction == TerminalApp::SuggestionsDirection::TopDown)
1024
1099
{
1025
1100
Controls::Grid::SetRow (_searchBox (), 0 );
1101
+ controlToMoveToTop = _backdrop ();
1026
1102
}
1027
1103
else // BottomUp
1028
1104
{
1029
1105
Controls::Grid::SetRow (_searchBox (), 4 );
1106
+ controlToMoveToTop = _descriptionsBackdrop ();
1107
+ }
1108
+
1109
+ assert (controlToMoveToTop);
1110
+ const auto & children{ _listAndDescriptionStack ().Children () };
1111
+ uint32_t index ;
1112
+ if (children.IndexOf (controlToMoveToTop, index ))
1113
+ {
1114
+ children.Move (index , 0 );
1030
1115
}
1031
1116
}
1032
1117
1118
+ void SuggestionsControl::_recalculateTopMargin ()
1119
+ {
1120
+ auto currentMargin = Margin ();
1121
+ // Call Measure() on the descriptions backdrop, so that it gets it's new
1122
+ // DesiredSize for this new description text.
1123
+ //
1124
+ // If you forget this, then we _probably_ weren't laid out since
1125
+ // updating that text, and the ActualHeight will be the _last_
1126
+ // description's height.
1127
+ _descriptionsBackdrop ().Measure ({
1128
+ static_cast <float >(ActualWidth ()),
1129
+ static_cast <float >(ActualHeight ()),
1130
+ });
1131
+
1132
+ // Now, position vertically.
1133
+ if (_direction == TerminalApp::SuggestionsDirection::TopDown)
1134
+ {
1135
+ // The control should open right below the cursor, with the list
1136
+ // extending below. This is easy, we can just use the cursor as the
1137
+ // origin (more or less)
1138
+ currentMargin.Top = (_anchor.Y );
1139
+ }
1140
+ else
1141
+ {
1142
+ // Bottom Up.
1143
+
1144
+ // This is wackier, because we need to calculate the offset upwards
1145
+ // from our anchor. So we need to get the size of our elements:
1146
+ const auto backdropHeight = _backdrop ().ActualHeight ();
1147
+ const auto descriptionDesiredHeight = _descriptionsBackdrop ().Visibility () == Visibility::Visible ?
1148
+ _descriptionsBackdrop ().DesiredSize ().Height :
1149
+ 0 ;
1150
+
1151
+ const auto marginTop = (_anchor.Y - backdropHeight - descriptionDesiredHeight);
1152
+
1153
+ currentMargin.Top = marginTop;
1154
+ }
1155
+ Margin (currentMargin);
1156
+ }
1157
+
1033
1158
void SuggestionsControl::Open (TerminalApp::SuggestionsMode mode,
1034
1159
const Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command>& commands,
1035
1160
winrt::hstring filter,
@@ -1047,9 +1172,8 @@ namespace winrt::TerminalApp::implementation
1047
1172
_anchor = anchor;
1048
1173
_space = space;
1049
1174
1050
- const til::size actualSize{ til::math::rounding, ActualWidth (), ActualHeight () };
1051
1175
// Is there space in the window below the cursor to open the menu downwards?
1052
- const bool canOpenDownwards = (_anchor.Y + characterHeight + actualSize. height ) < space.Height ;
1176
+ const bool canOpenDownwards = (_anchor.Y + characterHeight + ActualHeight () ) < space.Height ;
1053
1177
_setDirection (canOpenDownwards ? TerminalApp::SuggestionsDirection::TopDown :
1054
1178
TerminalApp::SuggestionsDirection::BottomUp);
1055
1179
// Set the anchor below by a character height
@@ -1063,26 +1187,13 @@ namespace winrt::TerminalApp::implementation
1063
1187
const auto proposedX = gsl::narrow_cast<int >(_anchor.X - 40 );
1064
1188
// If the control is too wide to fit in the window, clamp it fit inside
1065
1189
// the window.
1066
- const auto maxX = gsl::narrow_cast<int >(space.Width - actualSize. width );
1190
+ const auto maxX = gsl::narrow_cast<int >(space.Width - ActualWidth () );
1067
1191
const auto clampedX = std::clamp (proposedX, 0 , maxX);
1068
1192
1069
- // Create a thickness for the new margins
1070
- auto newMargin = Windows::UI::Xaml::ThicknessHelper::FromLengths (clampedX, 0 , 0 , 0 );
1071
- // Now, position vertically.
1072
- if (_direction == TerminalApp::SuggestionsDirection::TopDown)
1073
- {
1074
- // The control should open right below the cursor, with the list
1075
- // extending below. This is easy, we can just use the cursor as the
1076
- // origin (more or less)
1077
- newMargin.Top = (_anchor.Y );
1078
- }
1079
- else
1080
- {
1081
- // Position at the cursor. The suggestions UI itself will maintain
1082
- // its own offset such that it's always above its origin
1083
- newMargin.Top = (_anchor.Y - actualSize.height );
1084
- }
1085
- Margin (newMargin);
1193
+ // Create a thickness for the new margins. This will set the left, then
1194
+ // we'll go update the top separately
1195
+ Margin (Windows::UI::Xaml::ThicknessHelper::FromLengths (clampedX, 0 , 0 , 0 ));
1196
+ _recalculateTopMargin ();
1086
1197
1087
1198
_searchBox ().Text (filter);
1088
1199
@@ -1099,5 +1210,4 @@ namespace winrt::TerminalApp::implementation
1099
1210
// selection starting at the end of the string.
1100
1211
_searchBox ().Select (filter.size (), 0 );
1101
1212
}
1102
-
1103
1213
}
0 commit comments