From 553d7f57f0aa8ed07094819dd8265d19ef331f10 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 26 Apr 2023 12:57:32 -0700 Subject: [PATCH 1/3] Support tooltip rendering in list view --- PSReadLine/Cmdlets.cs | 10 + PSReadLine/DynamicHelp.cs | 6 +- PSReadLine/KeyBindings.cs | 3 + PSReadLine/KeyBindings.vi.cs | 2 + PSReadLine/PSReadLine.format.ps1xml | 4 + PSReadLine/PSReadLineResources.Designer.cs | 11 ++ PSReadLine/PSReadLineResources.resx | 3 + PSReadLine/Prediction.Entry.cs | 6 +- PSReadLine/Prediction.Views.cs | 201 +++++++++++++++++++-- PSReadLine/Prediction.cs | 15 ++ PSReadLine/Render.Helper.cs | 25 +++ 11 files changed, 266 insertions(+), 20 deletions(-) diff --git a/PSReadLine/Cmdlets.cs b/PSReadLine/Cmdlets.cs index ee323db57..bc89cc1f9 100644 --- a/PSReadLine/Cmdlets.cs +++ b/PSReadLine/Cmdlets.cs @@ -101,6 +101,7 @@ public class PSConsoleReadLineOptions 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 @@ public object ListPredictionSelectedColor 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 @@ public object ListPredictionSelectedColor internal string _inlinePredictionColor; internal string _listPredictionColor; internal string _listPredictionSelectedColor; + internal string _listPredictionTooltipColor; internal void ResetColors() { @@ -532,6 +540,7 @@ internal void ResetColors() InlinePredictionColor = DefaultInlinePredictionColor; ListPredictionColor = DefaultListPredictionColor; ListPredictionSelectedColor = DefaultListPredictionSelectedColor; + ListPredictionTooltipColor = DefaultListPredictionTooltipColor; var bg = Console.BackgroundColor; if (fg == VTColorUtils.UnknownColor || bg == VTColorUtils.UnknownColor) @@ -571,6 +580,7 @@ internal void SetColor(string property, object value) {"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); diff --git a/PSReadLine/DynamicHelp.cs b/PSReadLine/DynamicHelp.cs index 6334c59b6..bbd6bf70e 100644 --- a/PSReadLine/DynamicHelp.cs +++ b/PSReadLine/DynamicHelp.cs @@ -19,6 +19,7 @@ public partial class PSConsoleReadLine [ExcludeFromCodeCoverage] void IPSConsoleReadLineMockableMethods.RenderFullHelp(string content, string regexPatternToScrollTo) { + _pager ??= new Pager(); _pager.Write(content, regexPatternToScrollTo); } @@ -142,11 +143,6 @@ private void WriteDynamicHelpContent(string commandName, string parameterName, b private void DynamicHelpImpl(bool isFullHelp) { - if (isFullHelp) - { - _pager ??= new Pager(); - } - int cursor = _singleton._current; string commandName = null; string parameterName = null; diff --git a/PSReadLine/KeyBindings.cs b/PSReadLine/KeyBindings.cs index 69daaa0c9..89564228d 100644 --- a/PSReadLine/KeyBindings.cs +++ b/PSReadLine/KeyBindings.cs @@ -235,6 +235,7 @@ void SetDefaultWindowsBindings() { 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 @@ void SetDefaultEmacsBindings() { 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 @@ public static KeyHandlerGroup GetDisplayGrouping(string function) case nameof(NextSuggestion): case nameof(PreviousSuggestion): case nameof(SwitchPredictionView): + case nameof(ShowFullPredictionTooltip): return KeyHandlerGroup.Prediction; case nameof(CaptureScreen): diff --git a/PSReadLine/KeyBindings.vi.cs b/PSReadLine/KeyBindings.vi.cs index e7498c166..9d051ec02 100644 --- a/PSReadLine/KeyBindings.vi.cs +++ b/PSReadLine/KeyBindings.vi.cs @@ -91,6 +91,8 @@ private void SetDefaultViBindings() { 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 diff --git a/PSReadLine/PSReadLine.format.ps1xml b/PSReadLine/PSReadLine.format.ps1xml index 3446753f2..5b20c58af 100644 --- a/PSReadLine/PSReadLine.format.ps1xml +++ b/PSReadLine/PSReadLine.format.ps1xml @@ -204,6 +204,10 @@ $d = [Microsoft.PowerShell.KeyHandler]::GetGroupingDescription($_.Group) [Microsoft.PowerShell.VTColorUtils]::FormatColor($_.ListPredictionSelectedColor) + + + [Microsoft.PowerShell.VTColorUtils]::FormatColor($_.ListPredictionTooltipColor) + [Microsoft.PowerShell.VTColorUtils]::FormatColor($_.MemberColor) diff --git a/PSReadLine/PSReadLineResources.Designer.cs b/PSReadLine/PSReadLineResources.Designer.cs index 35dd5a337..7d3435945 100644 --- a/PSReadLine/PSReadLineResources.Designer.cs +++ b/PSReadLine/PSReadLineResources.Designer.cs @@ -2192,6 +2192,17 @@ internal static string SwitchPredictionViewDescription } } + /// + /// Looks up a localized string similar to Show the full tooltip of the selected list-view item in the terminal's alternate screen buffer. + /// + internal static string ShowFullPredictionTooltipDescription + { + get + { + return ResourceManager.GetString("ShowFullPredictionTooltipDescription", resourceCulture); + } + } + /// /// Looks up a localized string similar to Make visual selection of the command arguments. /// diff --git a/PSReadLine/PSReadLineResources.resx b/PSReadLine/PSReadLineResources.resx index 28d6e5d4f..618ef22b9 100644 --- a/PSReadLine/PSReadLineResources.resx +++ b/PSReadLine/PSReadLineResources.resx @@ -837,6 +837,9 @@ Or not saving history with: Switch between the inline and list prediction views. + + Show the full tooltip of the selected list-view item in the terminal's alternate screen buffer. + 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}'. diff --git a/PSReadLine/Prediction.Entry.cs b/PSReadLine/Prediction.Entry.cs index f576f62a6..643afa5d3 100644 --- a/PSReadLine/Prediction.Entry.cs +++ b/PSReadLine/Prediction.Entry.cs @@ -47,6 +47,7 @@ private struct SuggestionEntry 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 @@ private struct SuggestionEntry 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; diff --git a/PSReadLine/Prediction.Views.cs b/PSReadLine/Prediction.Views.cs index 7ab89e65b..2f23f15ec 100644 --- a/PSReadLine/Prediction.Views.cs +++ b/PSReadLine/Prediction.Views.cs @@ -215,6 +215,7 @@ private class PredictionListView : PredictionViewBase // 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 @@ private class PredictionListView : PredictionViewBase 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 @@ internal string SelectedItemText } } + /// + /// The tooltip of the currently selected item. + /// + 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 @@ internal PredictionListView(PSConsoleReadLine singleton) /// /// Calculate the max width and height of the list view based on the current terminal size. /// - 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); } /// @@ -326,8 +349,9 @@ internal PredictionListView(PSConsoleReadLine singleton) /// 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 */; } /// @@ -364,7 +388,7 @@ internal override void GetSuggestion(string userInput) // 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 @@ private void AggregateSuggestions() } 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 @@ private void AggregateSuggestions() _listViewTop = 0; _listViewEnd = Math.Min(_listItems.Count, _maxViewHeight); _listViewHeight = _listViewEnd - _listViewTop; + _tooltipHeight = 0; } else { @@ -658,18 +683,25 @@ internal override void RenderSuggestion(List consoleBufferLines, } _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 @@ private int GetPesudoListHeightForWarningRendering() return pesudoListHeight; } + /// + /// Calculate the number of tooltip lines rendered in the list view. + /// + 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; + } + /// /// Generate the rendering text for the metadata line. /// @@ -865,6 +917,127 @@ static StringBuilder AppendColor(StringBuilder buffer, string colorToUse, ref st buffer.Insert(charPosition, " ", padding); } + /// + /// Generate the rendering text for the tooltip. + /// + private int RenderTooltip(string tooltip, List consoleBufferLines, ref int currentLogicalLine) + { + const int LengthOfLeadingPart = 6; + const string IndicatorSymbol = ">>"; + const string MsgForViewAll = "( to view all)"; + const string MoreTextIndicator1 = " \u2026 "; + const string MoreTextIndicator2 = "\u2026 "; + const string DimItalicStyle = "\x1b[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; + + do + { + int startIndex = newlineIndex + 1; + if (startIndex == tooltip.Length) + { + break; + } + + newlineIndex = tooltip.IndexOf('\n', startIndex); + (start, end) = TrimSubstringInPlace(tooltip, startIndex, newlineIndex is -1 ? tooltip.Length - 1 : newlineIndex); + + if (start is -1) + { + continue; + } + + if (linesLeft is 0) + { + // More non-empty logical lines, but no more space for rendering. + moreToCome = true; + break; + } + + linesLeft--; + buff = NextBufferLine(consoleBufferLines, ref currentLogicalLine); + + if (first) + { + first = false; + string tooltipStyle = _singleton._options._listPredictionTooltipColor; + if (tooltipStyle != PSConsoleReadLineOptions.DefaultInlinePredictionColor) + { + tooltipStyle += DimItalicStyle; + } + + buff.Append(tooltipStyle) + .Append(' ', 3) + .Append(IndicatorSymbol) + .Append(' '); + } + else + { + buff.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 logical string, but no more space for rendering. + moreToCome = true; + break; + } + + cellCount = charInCells; + } + + buff.Append(ch); + } + } + while (linesLeft >= 0 && newlineIndex >= 0); + + if (moreToCome) + { + // Append the "( to view all)" at the end of the last line + string highlightStyle = _singleton._options._listPredictionColor + DimItalicStyle; + + 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; + } + /// /// Trigger the feedback about a suggestion was accepted. /// @@ -899,7 +1072,7 @@ internal override void Clear(bool cursorAtEol) int listHeight = _warningPrinted ? GetPesudoListHeightForWarningRendering() - : _listViewHeight; + : _listViewHeight + _tooltipHeight; int top = cursorAtEol ? _singleton._console.CursorTop @@ -919,7 +1092,9 @@ internal override void Reset() _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; } diff --git a/PSReadLine/Prediction.cs b/PSReadLine/Prediction.cs index fc790f948..7ece2ed1b 100644 --- a/PSReadLine/Prediction.cs +++ b/PSReadLine/Prediction.cs @@ -180,6 +180,21 @@ public static void PreviousSuggestion(ConsoleKeyInfo? key = null, object arg = n UpdateListSelection(numericArg); } + /// + /// Show the tooltip of the currently selected list item in the full view. + /// + 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); + } + } + } + /// /// Implementation for updating the selected item in list view. /// diff --git a/PSReadLine/Render.Helper.cs b/PSReadLine/Render.Helper.cs index 8fe8de071..8fc56bea1 100644 --- a/PSReadLine/Render.Helper.cs +++ b/PSReadLine/Render.Helper.cs @@ -190,5 +190,30 @@ private static int SubstringLengthByCellsFromEnd(string text, int start, int cou 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); + } } } From 7f4fa1248e50ae7050c16638b27ffe4e108ec72f Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 27 Apr 2023 16:37:45 -0700 Subject: [PATCH 2/3] Add tests and a few fixes --- PSReadLine/Prediction.Views.cs | 39 ++- test/InlinePredictionTest.cs | 17 +- test/ListViewTooltipTest.cs | 484 +++++++++++++++++++++++++++++++++ 3 files changed, 529 insertions(+), 11 deletions(-) create mode 100644 test/ListViewTooltipTest.cs diff --git a/PSReadLine/Prediction.Views.cs b/PSReadLine/Prediction.Views.cs index 2f23f15ec..6e7cfdcf0 100644 --- a/PSReadLine/Prediction.Views.cs +++ b/PSReadLine/Prediction.Views.cs @@ -939,41 +939,59 @@ private int RenderTooltip(string tooltip, List consoleBufferLines int windowWidth = _singleton._console.BufferWidth; int linesLeft = _maxTooltipHeight; + string tooltipStyle = _singleton._options._listPredictionTooltipColor; + if (tooltipStyle != PSConsoleReadLineOptions.DefaultInlinePredictionColor) + { + tooltipStyle += DimItalicStyle; + } + 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 logical lines, but no more space for rendering. + // 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; - string tooltipStyle = _singleton._options._listPredictionTooltipColor; - if (tooltipStyle != PSConsoleReadLineOptions.DefaultInlinePredictionColor) - { - tooltipStyle += DimItalicStyle; - } - buff.Append(tooltipStyle) .Append(' ', 3) .Append(IndicatorSymbol) @@ -981,7 +999,8 @@ private int RenderTooltip(string tooltip, List consoleBufferLines } else { - buff.Append(' ', LengthOfLeadingPart); + buff.Append(tooltipStyle) + .Append(' ', LengthOfLeadingPart); } cellCount = LengthOfLeadingPart; @@ -996,8 +1015,9 @@ private int RenderTooltip(string tooltip, List consoleBufferLines linesLeft--; if (linesLeft is -1) { - // More text from the current logical string, but no more space for rendering. + // More text from the current substring line, but no more space for rendering. moreToCome = true; + cellCount -= charInCells; break; } @@ -1013,7 +1033,6 @@ private int RenderTooltip(string tooltip, List consoleBufferLines { // Append the "( to view all)" at the end of the last line string highlightStyle = _singleton._options._listPredictionColor + DimItalicStyle; - int remainingCells = windowWidth - cellCount; if (remainingCells >= MsgForViewAll.Length + MoreTextIndicator1.Length) diff --git a/test/InlinePredictionTest.cs b/test/InlinePredictionTest.cs index f67125581..d9729c675 100644 --- a/test/InlinePredictionTest.cs +++ b/test/InlinePredictionTest.cs @@ -395,6 +395,7 @@ public void ViDefect2408() } 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 @@ internal static List MockedPredictInput(Ast ast, Token[] token new[] { typeof(Guid), typeof(string), typeof(uint), typeof(List) }, 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 + { + 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)ctor.Invoke( + new object[] { predictorId_0, "Tooltip", MiniSessionId, suggestions_0 }), + }; + } var suggestions_1 = new List { diff --git a/test/ListViewTooltipTest.cs b/test/ListViewTooltipTest.cs new file mode 100644 index 000000000..624ec0c99 --- /dev/null +++ b/test/ListViewTooltipTest.cs @@ -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 ''. + 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.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 ''. + 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 ''. + 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, "( 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 ''. + 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 ''. + 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.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 ''. + 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, "( 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 ''. + 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 ''. + 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, "( 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 ''. + 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, "( 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)) + )); + } + } +} From 0bed11ebc9e1a6a69ba08d5d9207bc4db209bda2 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 27 Apr 2023 16:53:52 -0700 Subject: [PATCH 3/3] Adjust the tooltip colors a little bit --- PSReadLine/Prediction.Views.cs | 6 +++--- test/MockConsole.cs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/PSReadLine/Prediction.Views.cs b/PSReadLine/Prediction.Views.cs index 6e7cfdcf0..e4ad73024 100644 --- a/PSReadLine/Prediction.Views.cs +++ b/PSReadLine/Prediction.Views.cs @@ -927,7 +927,7 @@ private int RenderTooltip(string tooltip, List consoleBufferLines const string MsgForViewAll = "( to view all)"; const string MoreTextIndicator1 = " \u2026 "; const string MoreTextIndicator2 = "\u2026 "; - const string DimItalicStyle = "\x1b[2;3m"; + const string BoldDimItalicStyle = "\x1b[1;2;3m"; bool first = true; int newlineIndex = -1; @@ -942,7 +942,7 @@ private int RenderTooltip(string tooltip, List consoleBufferLines string tooltipStyle = _singleton._options._listPredictionTooltipColor; if (tooltipStyle != PSConsoleReadLineOptions.DefaultInlinePredictionColor) { - tooltipStyle += DimItalicStyle; + tooltipStyle += BoldDimItalicStyle; } do @@ -1032,7 +1032,7 @@ private int RenderTooltip(string tooltip, List consoleBufferLines if (moreToCome) { // Append the "( to view all)" at the end of the last line - string highlightStyle = _singleton._options._listPredictionColor + DimItalicStyle; + string highlightStyle = _singleton._options._listPredictionColor + BoldDimItalicStyle; int remainingCells = windowWidth - cellCount; if (remainingCells >= MsgForViewAll.Length + MoreTextIndicator1.Length) diff --git a/test/MockConsole.cs b/test/MockConsole.cs index f827d4691..ee0a7c363 100644 --- a/test/MockConsole.cs +++ b/test/MockConsole.cs @@ -235,9 +235,9 @@ public virtual void Write(string s) 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 @@ public override void Write(string s) 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; }