mirror of
https://github.com/PowerShell/PSReadLine
synced 2026-06-08 12:12:13 +00:00
Support tooltip rendering in the prediction list view (#3667)
This commit is contained in:
@@ -101,6 +101,7 @@ namespace Microsoft.PowerShell
|
||||
public const string DefaultInlinePredictionColor = "\x1b[97;2;3m";
|
||||
public const string DefaultListPredictionColor = "\x1b[33m";
|
||||
public const string DefaultListPredictionSelectedColor = "\x1b[48;5;238m";
|
||||
public const string DefaultListPredictionTooltipColor = "\x1b[97;2;3m";
|
||||
|
||||
public static EditMode DefaultEditMode = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
? EditMode.Windows
|
||||
@@ -495,6 +496,12 @@ namespace Microsoft.PowerShell
|
||||
set => _listPredictionSelectedColor = VTColorUtils.AsEscapeSequence(value);
|
||||
}
|
||||
|
||||
public object ListPredictionTooltipColor
|
||||
{
|
||||
get => _listPredictionTooltipColor;
|
||||
set => _listPredictionTooltipColor = VTColorUtils.AsEscapeSequence(value);
|
||||
}
|
||||
|
||||
internal string _defaultTokenColor;
|
||||
internal string _commentColor;
|
||||
internal string _keywordColor;
|
||||
@@ -512,6 +519,7 @@ namespace Microsoft.PowerShell
|
||||
internal string _inlinePredictionColor;
|
||||
internal string _listPredictionColor;
|
||||
internal string _listPredictionSelectedColor;
|
||||
internal string _listPredictionTooltipColor;
|
||||
|
||||
internal void ResetColors()
|
||||
{
|
||||
@@ -532,6 +540,7 @@ namespace Microsoft.PowerShell
|
||||
InlinePredictionColor = DefaultInlinePredictionColor;
|
||||
ListPredictionColor = DefaultListPredictionColor;
|
||||
ListPredictionSelectedColor = DefaultListPredictionSelectedColor;
|
||||
ListPredictionTooltipColor = DefaultListPredictionTooltipColor;
|
||||
|
||||
var bg = Console.BackgroundColor;
|
||||
if (fg == VTColorUtils.UnknownColor || bg == VTColorUtils.UnknownColor)
|
||||
@@ -571,6 +580,7 @@ namespace Microsoft.PowerShell
|
||||
{"InlinePrediction", (o, v) => o.InlinePredictionColor = v},
|
||||
{"ListPrediction", (o, v) => o.ListPredictionColor = v},
|
||||
{"ListPredictionSelected", (o, v) => o.ListPredictionSelectedColor = v},
|
||||
{"ListPredictionTooltip", (o, v) => o.ListPredictionTooltipColor = v},
|
||||
};
|
||||
|
||||
Interlocked.CompareExchange(ref ColorSetters, setters, null);
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace Microsoft.PowerShell
|
||||
[ExcludeFromCodeCoverage]
|
||||
void IPSConsoleReadLineMockableMethods.RenderFullHelp(string content, string regexPatternToScrollTo)
|
||||
{
|
||||
_pager ??= new Pager();
|
||||
_pager.Write(content, regexPatternToScrollTo);
|
||||
}
|
||||
|
||||
@@ -142,11 +143,6 @@ namespace Microsoft.PowerShell
|
||||
|
||||
private void DynamicHelpImpl(bool isFullHelp)
|
||||
{
|
||||
if (isFullHelp)
|
||||
{
|
||||
_pager ??= new Pager();
|
||||
}
|
||||
|
||||
int cursor = _singleton._current;
|
||||
string commandName = null;
|
||||
string parameterName = null;
|
||||
|
||||
@@ -235,6 +235,7 @@ namespace Microsoft.PowerShell
|
||||
{ Keys.F2, MakeKeyHandler(SwitchPredictionView, "SwitchPredictionView") },
|
||||
{ Keys.F3, MakeKeyHandler(CharacterSearch, "CharacterSearch") },
|
||||
{ Keys.ShiftF3, MakeKeyHandler(CharacterSearchBackward, "CharacterSearchBackward") },
|
||||
{ Keys.F4, MakeKeyHandler(ShowFullPredictionTooltip, "ShowFullPredictionTooltip") },
|
||||
{ Keys.F8, MakeKeyHandler(HistorySearchBackward, "HistorySearchBackward") },
|
||||
{ Keys.ShiftF8, MakeKeyHandler(HistorySearchForward, "HistorySearchForward") },
|
||||
// Added for xtermjs-based terminals that send different key combinations.
|
||||
@@ -339,6 +340,7 @@ namespace Microsoft.PowerShell
|
||||
{ Keys.AltH, MakeKeyHandler(ShowParameterHelp, "ShowParameterHelp") },
|
||||
{ Keys.F1, MakeKeyHandler(ShowCommandHelp, "ShowCommandHelp") },
|
||||
{ Keys.F2, MakeKeyHandler(SwitchPredictionView, "SwitchPredictionView") },
|
||||
{ Keys.F4, MakeKeyHandler(ShowFullPredictionTooltip, "ShowFullPredictionTooltip") },
|
||||
{ Keys.AltU, MakeKeyHandler(UpcaseWord, "UpcaseWord") },
|
||||
{ Keys.AltL, MakeKeyHandler(DowncaseWord, "DowncaseWord") },
|
||||
{ Keys.AltC, MakeKeyHandler(CapitalizeWord, "CapitalizeWord") },
|
||||
@@ -566,6 +568,7 @@ namespace Microsoft.PowerShell
|
||||
case nameof(NextSuggestion):
|
||||
case nameof(PreviousSuggestion):
|
||||
case nameof(SwitchPredictionView):
|
||||
case nameof(ShowFullPredictionTooltip):
|
||||
return KeyHandlerGroup.Prediction;
|
||||
|
||||
case nameof(CaptureScreen):
|
||||
|
||||
@@ -91,6 +91,8 @@ namespace Microsoft.PowerShell
|
||||
{ Keys.CtrlG, MakeKeyHandler(Abort, "Abort") },
|
||||
{ Keys.AltH, MakeKeyHandler(ShowParameterHelp, "ShowParameterHelp") },
|
||||
{ Keys.F1, MakeKeyHandler(ShowCommandHelp, "ShowCommandHelp") },
|
||||
{ Keys.F2, MakeKeyHandler(SwitchPredictionView, "SwitchPredictionView") },
|
||||
{ Keys.F4, MakeKeyHandler(ShowFullPredictionTooltip, "ShowFullPredictionTooltip") },
|
||||
};
|
||||
|
||||
// Some bindings are not available on certain platforms
|
||||
|
||||
@@ -204,6 +204,10 @@ $d = [Microsoft.PowerShell.KeyHandler]::GetGroupingDescription($_.Group)
|
||||
<Label>ListPredictionSelectedColor</Label>
|
||||
<ScriptBlock>[Microsoft.PowerShell.VTColorUtils]::FormatColor($_.ListPredictionSelectedColor)</ScriptBlock>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Label>ListPredictionTooltipColor</Label>
|
||||
<ScriptBlock>[Microsoft.PowerShell.VTColorUtils]::FormatColor($_.ListPredictionTooltipColor)</ScriptBlock>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Label>MemberColor</Label>
|
||||
<ScriptBlock>[Microsoft.PowerShell.VTColorUtils]::FormatColor($_.MemberColor)</ScriptBlock>
|
||||
|
||||
+11
@@ -2192,6 +2192,17 @@ namespace Microsoft.PowerShell.PSReadLine {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Show the full tooltip of the selected list-view item in the terminal's alternate screen buffer.
|
||||
/// </summary>
|
||||
internal static string ShowFullPredictionTooltipDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
return ResourceManager.GetString("ShowFullPredictionTooltipDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Make visual selection of the command arguments.
|
||||
/// </summary>
|
||||
|
||||
@@ -837,6 +837,9 @@ Or not saving history with:
|
||||
<data name="SwitchPredictionViewDescription" xml:space="preserve">
|
||||
<value>Switch between the inline and list prediction views.</value>
|
||||
</data>
|
||||
<data name="ShowFullPredictionTooltipDescription" xml:space="preserve">
|
||||
<value>Show the full tooltip of the selected list-view item in the terminal's alternate screen buffer.</value>
|
||||
</data>
|
||||
<data name="WindowSizeTooSmallForListView" xml:space="preserve">
|
||||
<value>The prediction 'ListView' is temporarily disabled because the current window size of the console is too small. To use the 'ListView', please make sure the 'WindowWidth' is not less than '{0}' and the 'WindowHeight' is not less than '{1}'.</value>
|
||||
</data>
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace Microsoft.PowerShell
|
||||
internal readonly Guid PredictorId;
|
||||
internal readonly uint? PredictorSession;
|
||||
internal readonly string Source;
|
||||
internal readonly string ToolTip;
|
||||
internal readonly string SuggestionText;
|
||||
internal readonly int InputMatchIndex;
|
||||
|
||||
@@ -54,16 +55,17 @@ namespace Microsoft.PowerShell
|
||||
private string _listItemTextSelected;
|
||||
|
||||
internal SuggestionEntry(string suggestion, int matchIndex)
|
||||
: this(source: HistorySource, predictorId: Guid.Empty, predictorSession: null, suggestion, matchIndex)
|
||||
: this(source: HistorySource, predictorId: Guid.Empty, predictorSession: null, suggestion, tooltip: null, matchIndex)
|
||||
{
|
||||
}
|
||||
|
||||
internal SuggestionEntry(string source, Guid predictorId, uint? predictorSession, string suggestion, int matchIndex)
|
||||
internal SuggestionEntry(string source, Guid predictorId, uint? predictorSession, string suggestion, string tooltip, int matchIndex)
|
||||
{
|
||||
Source = source;
|
||||
PredictorId = predictorId;
|
||||
PredictorSession = predictorSession;
|
||||
SuggestionText = suggestion;
|
||||
ToolTip = tooltip;
|
||||
InputMatchIndex = matchIndex;
|
||||
|
||||
_listItemTextRegular = _listItemTextSelected = null;
|
||||
|
||||
+207
-13
@@ -215,6 +215,7 @@ namespace Microsoft.PowerShell
|
||||
// List view constants.
|
||||
internal const int ListViewMaxHeight = 10;
|
||||
internal const int ListViewMaxWidth = 100;
|
||||
internal const int TooltipMaxHeight = 4;
|
||||
internal const int SourceMaxWidth = 15;
|
||||
|
||||
// Minimal window size.
|
||||
@@ -236,6 +237,11 @@ namespace Microsoft.PowerShell
|
||||
private int _maxViewHeight;
|
||||
// The actual height of the list view that is currently rendered.
|
||||
private int _listViewHeight;
|
||||
// The max number of physical lines for rendering tooltip.
|
||||
private int _maxTooltipHeight;
|
||||
// The actual number of lines used for rendering the tooltip.
|
||||
private int _tooltipHeight;
|
||||
|
||||
// The actual width of the list view that is currently rendered.
|
||||
private int _listViewWidth;
|
||||
// An index pointing to the item that is shown in the first slot of the list view.
|
||||
@@ -294,6 +300,23 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The tooltip of the currently selected item.
|
||||
/// </summary>
|
||||
internal string SelectedItemTooltip
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_listItems == null || _selectedIndex == -1)
|
||||
return null;
|
||||
|
||||
if (_selectedIndex >= 0)
|
||||
return _listItems[_selectedIndex].ToolTip;
|
||||
|
||||
throw new InvalidOperationException("Unexpected '_selectedIndex' value: " + _selectedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
internal PredictionListView(PSConsoleReadLine singleton)
|
||||
: base(singleton)
|
||||
{
|
||||
@@ -306,19 +329,19 @@ namespace Microsoft.PowerShell
|
||||
/// <summary>
|
||||
/// Calculate the max width and height of the list view based on the current terminal size.
|
||||
/// </summary>
|
||||
private (int maxWidth, int maxHeight, bool checkOnHeight) RefreshMaxViewSize()
|
||||
private (int, int, int, bool) RefreshMaxViewSize()
|
||||
{
|
||||
var console = _singleton._console;
|
||||
int maxWidth = Math.Min(console.BufferWidth, ListViewMaxWidth);
|
||||
int maxListWidth = Math.Min(console.BufferWidth, ListViewMaxWidth);
|
||||
|
||||
(int maxHeight, bool moreCheck) = console.BufferHeight switch
|
||||
(int maxListHeight, int maxTooltipHeigth, bool moreCheck) = console.BufferHeight switch
|
||||
{
|
||||
> ListViewMaxHeight * 2 => (ListViewMaxHeight, false),
|
||||
> ListViewMaxHeight => (ListViewMaxHeight / 2, false),
|
||||
_ => (ListViewMaxHeight / 3, true)
|
||||
> ListViewMaxHeight * 2 => (ListViewMaxHeight, TooltipMaxHeight, false),
|
||||
> ListViewMaxHeight => (ListViewMaxHeight / 2, TooltipMaxHeight / 2, false),
|
||||
_ => (ListViewMaxHeight / 3, TooltipMaxHeight / 3, true)
|
||||
};
|
||||
|
||||
return (maxWidth, maxHeight, moreCheck);
|
||||
return (maxListWidth, maxListHeight, maxTooltipHeigth, moreCheck);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -326,8 +349,9 @@ namespace Microsoft.PowerShell
|
||||
/// </summary>
|
||||
private bool HeightIsTooSmall()
|
||||
{
|
||||
int tooltipLineCount = GetToolTipLineCountForHeightCheck();
|
||||
int physicalLineCountForBuffer = _singleton.EndOfBufferPosition().Y - _singleton._initialY + 1;
|
||||
return _singleton._console.BufferHeight < physicalLineCountForBuffer + _maxViewHeight + 1 /* one metadata line */;
|
||||
return _singleton._console.BufferHeight < physicalLineCountForBuffer + _maxViewHeight + tooltipLineCount + 1 /* one metadata line */;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -364,7 +388,7 @@ namespace Microsoft.PowerShell
|
||||
// Reset the list item selection.
|
||||
_selectedIndex = -1;
|
||||
// Refresh the list view width and height in case the terminal was resized.
|
||||
(_listViewWidth, _maxViewHeight, _checkOnHeight) = RefreshMaxViewSize();
|
||||
(_listViewWidth, _maxViewHeight, _maxTooltipHeight, _checkOnHeight) = RefreshMaxViewSize();
|
||||
|
||||
if (inputUnchanged)
|
||||
{
|
||||
@@ -533,7 +557,7 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
|
||||
int matchIndex = sugText.IndexOf(_inputText, comparison);
|
||||
_listItems.Add(new SuggestionEntry(item.Name, item.Id, item.Session, sugText, matchIndex));
|
||||
_listItems.Add(new SuggestionEntry(item.Name, item.Id, item.Session, sugText, suggestion.ToolTip, matchIndex));
|
||||
|
||||
if (--num == 0)
|
||||
{
|
||||
@@ -586,6 +610,7 @@ namespace Microsoft.PowerShell
|
||||
_listViewTop = 0;
|
||||
_listViewEnd = Math.Min(_listItems.Count, _maxViewHeight);
|
||||
_listViewHeight = _listViewEnd - _listViewTop;
|
||||
_tooltipHeight = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -658,18 +683,25 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
|
||||
_listViewHeight = _listViewEnd - _listViewTop;
|
||||
_tooltipHeight = 0;
|
||||
}
|
||||
|
||||
for (int i = _listViewTop; i < _listViewEnd; i++)
|
||||
{
|
||||
bool itemSelected = i == _selectedIndex;
|
||||
string selectionColor = itemSelected ? _singleton._options._listPredictionSelectedColor : null;
|
||||
SuggestionEntry entry = _listItems[i];
|
||||
|
||||
NextBufferLine(consoleBufferLines, ref currentLogicalLine)
|
||||
.Append(_listItems[i].GetListItemText(
|
||||
.Append(entry.GetListItemText(
|
||||
_listViewWidth,
|
||||
_inputText,
|
||||
selectionColor));
|
||||
|
||||
if (_singleton._options.ShowToolTips && itemSelected && !string.IsNullOrWhiteSpace(entry.ToolTip))
|
||||
{
|
||||
_tooltipHeight = RenderTooltip(entry.ToolTip, consoleBufferLines, ref currentLogicalLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,6 +735,26 @@ namespace Microsoft.PowerShell
|
||||
return pesudoListHeight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the number of tooltip lines rendered in the list view.
|
||||
/// </summary>
|
||||
private int GetToolTipLineCountForHeightCheck()
|
||||
{
|
||||
int tooltipLineCount = 0;
|
||||
if (_singleton._options.ShowToolTips && _selectedIndex >= 0)
|
||||
{
|
||||
// When '_selectedIndex >= 0', this is an update to the list view triggered by navigation
|
||||
// within the list, and thus '_listItems' is guaranteed to be not null.
|
||||
string tooltip = _listItems[_selectedIndex].ToolTip;
|
||||
if (!string.IsNullOrWhiteSpace(tooltip))
|
||||
{
|
||||
tooltipLineCount = _maxTooltipHeight;
|
||||
}
|
||||
}
|
||||
|
||||
return tooltipLineCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the rendering text for the metadata line.
|
||||
/// </summary>
|
||||
@@ -865,6 +917,146 @@ namespace Microsoft.PowerShell
|
||||
buffer.Insert(charPosition, " ", padding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the rendering text for the tooltip.
|
||||
/// </summary>
|
||||
private int RenderTooltip(string tooltip, List<StringBuilder> consoleBufferLines, ref int currentLogicalLine)
|
||||
{
|
||||
const int LengthOfLeadingPart = 6;
|
||||
const string IndicatorSymbol = ">>";
|
||||
const string MsgForViewAll = "(<F4> to view all)";
|
||||
const string MoreTextIndicator1 = " \u2026 ";
|
||||
const string MoreTextIndicator2 = "\u2026 ";
|
||||
const string BoldDimItalicStyle = "\x1b[1;2;3m";
|
||||
|
||||
bool first = true;
|
||||
int newlineIndex = -1;
|
||||
int cellCount = 0;
|
||||
int start, end;
|
||||
|
||||
StringBuilder buff = null;
|
||||
bool moreToCome = false;
|
||||
int windowWidth = _singleton._console.BufferWidth;
|
||||
int linesLeft = _maxTooltipHeight;
|
||||
|
||||
string tooltipStyle = _singleton._options._listPredictionTooltipColor;
|
||||
if (tooltipStyle != PSConsoleReadLineOptions.DefaultInlinePredictionColor)
|
||||
{
|
||||
tooltipStyle += BoldDimItalicStyle;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
int startIndex = newlineIndex + 1;
|
||||
|
||||
// This may happen when the tooltip ends with a newline character.
|
||||
if (startIndex == tooltip.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the range of the current non-whitespace substring line.
|
||||
newlineIndex = tooltip.IndexOf('\n', startIndex);
|
||||
(start, end) = TrimSubstringInPlace(tooltip, startIndex, newlineIndex is -1 ? tooltip.Length - 1 : newlineIndex);
|
||||
|
||||
// This may happen when the current substring contains whitespace characters only.
|
||||
if (start is -1)
|
||||
{
|
||||
if (newlineIndex is -1)
|
||||
{
|
||||
// If we have reached the end, then we are done.
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, we need to continue processing the next substring line.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (linesLeft is 0)
|
||||
{
|
||||
// More non-empty substring lines, but no more space for rendering.
|
||||
moreToCome = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (buff is not null)
|
||||
{
|
||||
// Append reset for the previous substring line.
|
||||
buff.Append(VTColorUtils.AnsiReset);
|
||||
}
|
||||
|
||||
// Create a new buffer line for the current substring line.
|
||||
linesLeft--;
|
||||
buff = NextBufferLine(consoleBufferLines, ref currentLogicalLine);
|
||||
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
buff.Append(tooltipStyle)
|
||||
.Append(' ', 3)
|
||||
.Append(IndicatorSymbol)
|
||||
.Append(' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
buff.Append(tooltipStyle)
|
||||
.Append(' ', LengthOfLeadingPart);
|
||||
}
|
||||
|
||||
cellCount = LengthOfLeadingPart;
|
||||
for (; start <= end; start++)
|
||||
{
|
||||
char ch = tooltip[start];
|
||||
int charInCells = LengthInBufferCells(ch);
|
||||
|
||||
cellCount += charInCells;
|
||||
if (cellCount > windowWidth)
|
||||
{
|
||||
linesLeft--;
|
||||
if (linesLeft is -1)
|
||||
{
|
||||
// More text from the current substring line, but no more space for rendering.
|
||||
moreToCome = true;
|
||||
cellCount -= charInCells;
|
||||
break;
|
||||
}
|
||||
|
||||
cellCount = charInCells;
|
||||
}
|
||||
|
||||
buff.Append(ch);
|
||||
}
|
||||
}
|
||||
while (linesLeft >= 0 && newlineIndex >= 0);
|
||||
|
||||
if (moreToCome)
|
||||
{
|
||||
// Append the "(<F4> to view all)" at the end of the last line
|
||||
string highlightStyle = _singleton._options._listPredictionColor + BoldDimItalicStyle;
|
||||
int remainingCells = windowWidth - cellCount;
|
||||
|
||||
if (remainingCells >= MsgForViewAll.Length + MoreTextIndicator1.Length)
|
||||
{
|
||||
buff.Append(MoreTextIndicator1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int length = MsgForViewAll.Length + MoreTextIndicator2.Length - remainingCells;
|
||||
int buffIndex = buff.Length - length;
|
||||
|
||||
buff.Remove(buffIndex, length);
|
||||
buff.Append(MoreTextIndicator2);
|
||||
}
|
||||
|
||||
buff.Append(VTColorUtils.AnsiReset)
|
||||
.Append(highlightStyle)
|
||||
.Append(MsgForViewAll);
|
||||
}
|
||||
|
||||
buff.Append(VTColorUtils.AnsiReset);
|
||||
return _maxTooltipHeight - linesLeft > 0 ? linesLeft : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trigger the feedback about a suggestion was accepted.
|
||||
/// </summary>
|
||||
@@ -899,7 +1091,7 @@ namespace Microsoft.PowerShell
|
||||
|
||||
int listHeight = _warningPrinted
|
||||
? GetPesudoListHeightForWarningRendering()
|
||||
: _listViewHeight;
|
||||
: _listViewHeight + _tooltipHeight;
|
||||
|
||||
int top = cursorAtEol
|
||||
? _singleton._console.CursorTop
|
||||
@@ -919,7 +1111,9 @@ namespace Microsoft.PowerShell
|
||||
|
||||
_sources = null;
|
||||
_listItems = null;
|
||||
_maxViewHeight = _listViewTop = _listViewEnd = _listViewWidth = _listViewHeight = _selectedIndex = -1;
|
||||
_maxViewHeight = _maxTooltipHeight = -1;
|
||||
_listViewWidth = _listViewHeight = _tooltipHeight = -1;
|
||||
_listViewTop = _listViewEnd = _selectedIndex = -1;
|
||||
_warnAboutSize = _checkOnHeight = _updatePending = _renderFromSelected = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +180,21 @@ namespace Microsoft.PowerShell
|
||||
UpdateListSelection(numericArg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the tooltip of the currently selected list item in the full view.
|
||||
/// </summary>
|
||||
public static void ShowFullPredictionTooltip(ConsoleKeyInfo? key = null, object arg = null)
|
||||
{
|
||||
if (_singleton._prediction.ActiveView is PredictionListView listView && listView.HasActiveSuggestion)
|
||||
{
|
||||
string tooltip = listView.SelectedItemTooltip;
|
||||
if (!string.IsNullOrWhiteSpace(tooltip))
|
||||
{
|
||||
_singleton._mockableMethods.RenderFullHelp(tooltip, regexPatternToScrollTo: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation for updating the selected item in list view.
|
||||
/// </summary>
|
||||
|
||||
@@ -190,5 +190,30 @@ namespace Microsoft.PowerShell
|
||||
|
||||
return charLength;
|
||||
}
|
||||
|
||||
private static (int newStart, int newEnd) TrimSubstringInPlace(string text, int start, int end)
|
||||
{
|
||||
int newStart = start;
|
||||
int newEnd = end;
|
||||
|
||||
for (; newStart <= end; newStart++)
|
||||
{
|
||||
if (!char.IsWhiteSpace(text[newStart]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; newEnd > newStart; newEnd--)
|
||||
{
|
||||
if (!char.IsWhiteSpace(text[newEnd]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the new start/end after triming, or (-1, -1) if the substring only consists of whitespaces.
|
||||
return newStart > newEnd ? (-1, -1) : (newStart, newEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,6 +395,7 @@ namespace Test
|
||||
}
|
||||
|
||||
private const uint MiniSessionId = 56;
|
||||
private static readonly Guid predictorId_0 = Guid.Parse("c69fa9fc-6157-4877-8cf4-a9c83a0128af");
|
||||
private static readonly Guid predictorId_1 = Guid.Parse("b45b5fbe-90fa-486c-9c87-e7940fdd6273");
|
||||
private static readonly Guid predictorId_2 = Guid.Parse("74a86463-033b-44a3-b386-41ee191c94be");
|
||||
private static readonly Guid predictorId_3 = Guid.Parse("19e98622-99e0-41f7-9ee0-a8bed92cde51");
|
||||
@@ -409,10 +410,24 @@ namespace Test
|
||||
new[] { typeof(Guid), typeof(string), typeof(uint), typeof(List<PredictiveSuggestion>) }, null);
|
||||
|
||||
var input = ast.Extent.Text;
|
||||
if (input == "netsh")
|
||||
if (input is "netsh")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (input is "tooltip")
|
||||
{
|
||||
var suggestions_0 = new List<PredictiveSuggestion>
|
||||
{
|
||||
new PredictiveSuggestion("tooltip NO1", "Hello\nBinary\nWorld\nPowerShell is a task automation and configuration management program from Microsoft"),
|
||||
new PredictiveSuggestion("tooltip NO2", "Hello\nWorld"),
|
||||
};
|
||||
|
||||
return new List<PredictionResult>
|
||||
{
|
||||
(PredictionResult)ctor.Invoke(
|
||||
new object[] { predictorId_0, "Tooltip", MiniSessionId, suggestions_0 }),
|
||||
};
|
||||
}
|
||||
|
||||
var suggestions_1 = new List<PredictiveSuggestion>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,484 @@
|
||||
using System;
|
||||
using Microsoft.PowerShell;
|
||||
using Xunit;
|
||||
|
||||
namespace Test
|
||||
{
|
||||
public partial class ReadLine
|
||||
{
|
||||
[SkippableFact]
|
||||
public void List_Item_Tooltip_4_Lines()
|
||||
{
|
||||
// Set the terminal height to 22 and width to 60, so the metadata line will be fully rendered
|
||||
// and maximum 4 lines can be used for tooltip for a selected list item.
|
||||
int listWidth = 60;
|
||||
TestSetup(new TestConsole(keyboardLayout: _, width: listWidth, height: 22), KeyMode.Cmd);
|
||||
|
||||
// The font effect sequences of 'dim' and 'italic' used in list view metadata line
|
||||
// are ignored in the mock console, so only the white color will be left.
|
||||
var dimmedColors = Tuple.Create(ConsoleColor.White, _console.BackgroundColor);
|
||||
var emphasisColors = Tuple.Create(PSConsoleReadLineOptions.DefaultEmphasisColor, _console.BackgroundColor);
|
||||
using var disp = SetPrediction(PredictionSource.HistoryAndPlugin, PredictionViewStyle.ListView);
|
||||
_mockedMethods.ClearPredictionFields();
|
||||
|
||||
SetHistory("tooltip -history");
|
||||
Test("tooltip NO2", Keys(
|
||||
"tooltip", CheckThat(() => AssertScreenIs(6,
|
||||
TokenClassification.Command, "tooltip",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, "<-/3>",
|
||||
TokenClassification.None, new string(' ', listWidth - 28), // 28 is the length of '<-/3>' plus '<History(1) Tooltip(2)>'.
|
||||
dimmedColors, "<History(1) Tooltip(2)>",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " -history",
|
||||
TokenClassification.None, new string(' ', listWidth - 27), // 27 is the length of '> tooltip -history' plus '[History]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "History",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO1",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO1' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO2' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
// List view is done, no more list item following.
|
||||
NextLine,
|
||||
NextLine
|
||||
)),
|
||||
_.DownArrow,
|
||||
CheckThat(() => AssertScreenIs(6,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, ' ',
|
||||
TokenClassification.Parameter, "-history",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, "<1/3>",
|
||||
TokenClassification.None, new string(' ', listWidth - 30), // 30 is the length of '<1/3>' plus '<History(1/1) Tooltip(2)>'.
|
||||
dimmedColors, '<',
|
||||
TokenClassification.ListPrediction, "History(1/1) ",
|
||||
dimmedColors, "Tooltip(2)>",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.ListPredictionSelected, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.ListPredictionSelected, " -history",
|
||||
TokenClassification.ListPredictionSelected, new string(' ', listWidth - 27), // 27 is the length of '> tooltip -history' plus '[History]'.
|
||||
TokenClassification.ListPredictionSelected, '[',
|
||||
TokenClassification.ListPrediction, "History",
|
||||
TokenClassification.ListPredictionSelected, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO1",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO1' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO2' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
// List view is done, no more list item following.
|
||||
NextLine,
|
||||
NextLine
|
||||
)),
|
||||
_.DownArrow,
|
||||
CheckThat(() => AssertScreenIs(10,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, " NO1",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, "<2/3>",
|
||||
TokenClassification.None, new string(' ', listWidth - 30), // 30 is the length of '<2/3>' plus '<History(1) Tooltip(1/2)>'.
|
||||
dimmedColors, "<History(1) ",
|
||||
TokenClassification.ListPrediction, "Tooltip(1/2)",
|
||||
dimmedColors, '>',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " -history",
|
||||
TokenClassification.None, new string(' ', listWidth - 27), // 27 is the length of '> tooltip -history' plus '[History]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "History",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.ListPredictionSelected, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.ListPredictionSelected, " NO1",
|
||||
TokenClassification.ListPredictionSelected, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO1' plus '[Tooltip]'.
|
||||
TokenClassification.ListPredictionSelected, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.ListPredictionSelected, ']',
|
||||
NextLine,
|
||||
dimmedColors, " >> Hello", NextLine,
|
||||
dimmedColors, " Binary", NextLine,
|
||||
dimmedColors, " World", NextLine,
|
||||
dimmedColors, " PowerShell is a task automation an… ",
|
||||
TokenClassification.ListPrediction, "(<F4> to view all)",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO2' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
// List view is done, no more list item following.
|
||||
NextLine,
|
||||
NextLine
|
||||
)),
|
||||
_.DownArrow,
|
||||
CheckThat(() => AssertScreenIs(8,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, "<3/3>",
|
||||
TokenClassification.None, new string(' ', listWidth - 30), // 30 is the length of '<3/3>' plus '<History(1) Tooltip(2/2)>'.
|
||||
dimmedColors, "<History(1) ",
|
||||
TokenClassification.ListPrediction, "Tooltip(2/2)",
|
||||
dimmedColors, '>',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " -history",
|
||||
TokenClassification.None, new string(' ', listWidth - 27), // 27 is the length of '> tooltip -history' plus '[History]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "History",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO1",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO1' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.ListPredictionSelected, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.ListPredictionSelected, " NO2",
|
||||
TokenClassification.ListPredictionSelected, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO2' plus '[Tooltip]'.
|
||||
TokenClassification.ListPredictionSelected, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.ListPredictionSelected, ']',
|
||||
NextLine,
|
||||
dimmedColors, " >> Hello", NextLine,
|
||||
dimmedColors, " World",
|
||||
// List view is done, no more list item following.
|
||||
NextLine,
|
||||
NextLine
|
||||
)),
|
||||
|
||||
// Once accepted, the list should be cleared.
|
||||
_.Enter, CheckThat(() => AssertScreenIs(2,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
NextLine,
|
||||
NextLine))
|
||||
));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void List_Item_Tooltip_2_Lines()
|
||||
{
|
||||
// Set the terminal height to 15 and width to 60, so the metadata line will be fully rendered
|
||||
// and maximum 2 lines can be used for tooltip for a selected list item.
|
||||
int listWidth = 60;
|
||||
TestSetup(new TestConsole(keyboardLayout: _, width: listWidth, height: 15), KeyMode.Cmd);
|
||||
|
||||
// The font effect sequences of 'dim' and 'italic' used in list view metadata line
|
||||
// are ignored in the mock console, so only the white color will be left.
|
||||
var dimmedColors = Tuple.Create(ConsoleColor.White, _console.BackgroundColor);
|
||||
var emphasisColors = Tuple.Create(PSConsoleReadLineOptions.DefaultEmphasisColor, _console.BackgroundColor);
|
||||
using var disp = SetPrediction(PredictionSource.HistoryAndPlugin, PredictionViewStyle.ListView);
|
||||
_mockedMethods.ClearPredictionFields();
|
||||
|
||||
SetHistory("tooltip -history");
|
||||
Test("tooltip NO2", Keys(
|
||||
"tooltip", CheckThat(() => AssertScreenIs(6,
|
||||
TokenClassification.Command, "tooltip",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, "<-/3>",
|
||||
TokenClassification.None, new string(' ', listWidth - 28), // 28 is the length of '<-/3>' plus '<History(1) Tooltip(2)>'.
|
||||
dimmedColors, "<History(1) Tooltip(2)>",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " -history",
|
||||
TokenClassification.None, new string(' ', listWidth - 27), // 27 is the length of '> tooltip -history' plus '[History]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "History",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO1",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO1' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO2' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
// List view is done, no more list item following.
|
||||
NextLine,
|
||||
NextLine
|
||||
)),
|
||||
_.DownArrow, _.DownArrow,
|
||||
CheckThat(() => AssertScreenIs(8,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, " NO1",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, "<2/3>",
|
||||
TokenClassification.None, new string(' ', listWidth - 30), // 30 is the length of '<2/3>' plus '<History(1) Tooltip(1/2)>'.
|
||||
dimmedColors, "<History(1) ",
|
||||
TokenClassification.ListPrediction, "Tooltip(1/2)",
|
||||
dimmedColors, '>',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " -history",
|
||||
TokenClassification.None, new string(' ', listWidth - 27), // 27 is the length of '> tooltip -history' plus '[History]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "History",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.ListPredictionSelected, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.ListPredictionSelected, " NO1",
|
||||
TokenClassification.ListPredictionSelected, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO1' plus '[Tooltip]'.
|
||||
TokenClassification.ListPredictionSelected, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.ListPredictionSelected, ']',
|
||||
NextLine,
|
||||
dimmedColors, " >> Hello", NextLine,
|
||||
dimmedColors, " Binary … ",
|
||||
TokenClassification.ListPrediction, "(<F4> to view all)",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO2' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
// List view is done, no more list item following.
|
||||
NextLine,
|
||||
NextLine
|
||||
)),
|
||||
_.F4,
|
||||
CheckThat(() => Assert.Equal(
|
||||
"Hello\nBinary\nWorld\nPowerShell is a task automation and configuration management program from Microsoft",
|
||||
_mockedMethods.helpContentRendered)),
|
||||
_.DownArrow,
|
||||
CheckThat(() => AssertScreenIs(8,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, "<3/3>",
|
||||
TokenClassification.None, new string(' ', listWidth - 30), // 30 is the length of '<3/3>' plus '<History(1) Tooltip(2/2)>'.
|
||||
dimmedColors, "<History(1) ",
|
||||
TokenClassification.ListPrediction, "Tooltip(2/2)",
|
||||
dimmedColors, '>',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " -history",
|
||||
TokenClassification.None, new string(' ', listWidth - 27), // 27 is the length of '> tooltip -history' plus '[History]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "History",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO1",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO1' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.ListPredictionSelected, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.ListPredictionSelected, " NO2",
|
||||
TokenClassification.ListPredictionSelected, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO2' plus '[Tooltip]'.
|
||||
TokenClassification.ListPredictionSelected, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.ListPredictionSelected, ']',
|
||||
NextLine,
|
||||
dimmedColors, " >> Hello", NextLine,
|
||||
dimmedColors, " World",
|
||||
// List view is done, no more list item following.
|
||||
NextLine,
|
||||
NextLine
|
||||
)),
|
||||
|
||||
// Once accepted, the list should be cleared.
|
||||
_.Enter, CheckThat(() => AssertScreenIs(2,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
NextLine,
|
||||
NextLine))
|
||||
));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void List_Item_Tooltip_1_Line()
|
||||
{
|
||||
// Set the terminal height to 6 and width to 60, so the metadata line will be fully rendered
|
||||
// and maximum 2 lines can be used for tooltip for a selected list item.
|
||||
int listWidth = 60;
|
||||
TestSetup(new TestConsole(keyboardLayout: _, width: listWidth, height: 6), KeyMode.Cmd);
|
||||
|
||||
// The font effect sequences of 'dim' and 'italic' used in list view metadata line
|
||||
// are ignored in the mock console, so only the white color will be left.
|
||||
var dimmedColors = Tuple.Create(ConsoleColor.White, _console.BackgroundColor);
|
||||
var emphasisColors = Tuple.Create(PSConsoleReadLineOptions.DefaultEmphasisColor, _console.BackgroundColor);
|
||||
using var disp = SetPrediction(PredictionSource.HistoryAndPlugin, PredictionViewStyle.ListView);
|
||||
_mockedMethods.ClearPredictionFields();
|
||||
|
||||
SetHistory("tooltip -history");
|
||||
Test("tooltip NO2", Keys(
|
||||
"tooltip", _.DownArrow, _.DownArrow,
|
||||
CheckThat(() => AssertScreenIs(6,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, " NO1",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, "<2/3>",
|
||||
TokenClassification.None, new string(' ', listWidth - 30), // 30 is the length of '<2/3>' plus '<History(1) Tooltip(1/2)>'.
|
||||
dimmedColors, "<History(1) ",
|
||||
TokenClassification.ListPrediction, "Tooltip(1/2)",
|
||||
dimmedColors, '>',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " -history",
|
||||
TokenClassification.None, new string(' ', listWidth - 27), // 27 is the length of '> tooltip -history' plus '[History]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "History",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.ListPredictionSelected, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.ListPredictionSelected, " NO1",
|
||||
TokenClassification.ListPredictionSelected, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO1' plus '[Tooltip]'.
|
||||
TokenClassification.ListPredictionSelected, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.ListPredictionSelected, ']',
|
||||
NextLine,
|
||||
dimmedColors, " >> Hello … ",
|
||||
TokenClassification.ListPrediction, "(<F4> to view all)",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO2' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
// List view is done, no more list item following.
|
||||
NextLine
|
||||
)),
|
||||
_.F4,
|
||||
CheckThat(() => Assert.Equal(
|
||||
"Hello\nBinary\nWorld\nPowerShell is a task automation and configuration management program from Microsoft",
|
||||
_mockedMethods.helpContentRendered)),
|
||||
_.DownArrow,
|
||||
CheckThat(() => AssertScreenIs(6,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, "<3/3>",
|
||||
TokenClassification.None, new string(' ', listWidth - 30), // 30 is the length of '<3/3>' plus '<History(1) Tooltip(2/2)>'.
|
||||
dimmedColors, "<History(1) ",
|
||||
TokenClassification.ListPrediction, "Tooltip(2/2)",
|
||||
dimmedColors, '>',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " -history",
|
||||
TokenClassification.None, new string(' ', listWidth - 27), // 27 is the length of '> tooltip -history' plus '[History]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "History",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.None, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.None, " NO1",
|
||||
TokenClassification.None, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO1' plus '[Tooltip]'.
|
||||
TokenClassification.None, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.None, ']',
|
||||
NextLine,
|
||||
TokenClassification.ListPrediction, '>',
|
||||
TokenClassification.ListPredictionSelected, ' ',
|
||||
emphasisColors, "tooltip",
|
||||
TokenClassification.ListPredictionSelected, " NO2",
|
||||
TokenClassification.ListPredictionSelected, new string(' ', listWidth - 22), // 22 is the length of '> tooltip NO2' plus '[Tooltip]'.
|
||||
TokenClassification.ListPredictionSelected, '[',
|
||||
TokenClassification.ListPrediction, "Tooltip",
|
||||
TokenClassification.ListPredictionSelected, ']',
|
||||
NextLine,
|
||||
dimmedColors, " >> Hello … ",
|
||||
TokenClassification.ListPrediction, "(<F4> to view all)",
|
||||
// List view is done, no more list item following.
|
||||
NextLine
|
||||
)),
|
||||
_.F4,
|
||||
CheckThat(() => Assert.Equal(
|
||||
"Hello\nWorld",
|
||||
_mockedMethods.helpContentRendered)),
|
||||
|
||||
// Once accepted, the list should be cleared.
|
||||
_.Enter, CheckThat(() => AssertScreenIs(2,
|
||||
TokenClassification.Command, "tooltip",
|
||||
TokenClassification.None, " NO2",
|
||||
NextLine,
|
||||
NextLine))
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -235,9 +235,9 @@ namespace Test
|
||||
var escapeSequence = s.Substring(i + 2, len);
|
||||
foreach (var subsequence in escapeSequence.Split(';'))
|
||||
{
|
||||
if (subsequence is "2" or "3")
|
||||
if (subsequence is "1" or "2" or "3")
|
||||
{
|
||||
// Ignore the font effect sequence: 2 - dimmed color; 3 - italics
|
||||
// Ignore the font effect sequence: 1 - bold; 2 - dimmed color; 3 - italics
|
||||
// They are used in the metadata line of the list view.
|
||||
continue;
|
||||
}
|
||||
@@ -451,9 +451,9 @@ namespace Test
|
||||
var escapeSequence = s.Substring(i + 2, len);
|
||||
foreach (var subsequence in escapeSequence.Split(';'))
|
||||
{
|
||||
if (subsequence is "2" or "3")
|
||||
if (subsequence is "1" or "2" or "3")
|
||||
{
|
||||
// Ignore the font effect sequence: 2 - dimmed color; 3 - italics
|
||||
// Ignore the font effect sequence: 1 - bold; 2 - dimmed color; 3 - italics
|
||||
// They are used in the metadata line of the list view.
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user