Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the list view to be scrollable and auto-adjust the list view height #3583

Merged
merged 7 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions PSReadLine/KeyBindings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ public static void ShowKeyBindings(ConsoleKeyInfo? key = null, object arg = null
}

// Don't overwrite any of the line - so move to first line after the end of our buffer.
var point = _singleton.ConvertOffsetToPoint(_singleton._buffer.Length);
var point = _singleton.EndOfBufferPosition();
console.SetCursorPosition(point.X, point.Y);
console.Write("\n");

Expand Down Expand Up @@ -721,7 +721,7 @@ public static void WhatIsKey(ConsoleKeyInfo? key = null, object arg = null)

var console = _singleton._console;
// Don't overwrite any of the line - so move to first line after the end of our buffer.
var point = _singleton.ConvertOffsetToPoint(_singleton._buffer.Length);
var point = _singleton.EndOfBufferPosition();
console.SetCursorPosition(point.X, point.Y);
console.Write("\n");

Expand Down
11 changes: 11 additions & 0 deletions PSReadLine/PSReadLineResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions PSReadLine/PSReadLineResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,9 @@ Or not saving history with:
<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>
<data name="WindowSizeTooSmallWarning" xml:space="preserve">
<value>! terminal size too small to show the list view</value>
</data>
<data name="NeedsUpdateHelp" xml:space="preserve">
<value>No help content available. Please use Update-Help to download the latest help content.</value>
</data>
Expand Down
106 changes: 84 additions & 22 deletions PSReadLine/Prediction.Entry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,52 @@ namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
/// <summary>
/// Represents a prediction source.
/// </summary>
private readonly struct SourceInfo
{
internal readonly string SourceName;
internal readonly int EndIndex;
internal readonly int PrevSourceEndIndex;
internal readonly int ItemCount;

internal SourceInfo(string sourceName, int endIndex, int prevSourceEndIndex)
{
SourceName = sourceName;
int sourceWidth = LengthInBufferCells(SourceName);
if (sourceWidth > PredictionListView.SourceMaxWidth)
{
sourceWidth = PredictionListView.SourceMaxWidth - 1;
int sourceStrLen = SubstringLengthByCells(sourceName, sourceWidth);
SourceName = sourceName.Substring(0, sourceStrLen) + SuggestionEntry.Ellipsis;
}

EndIndex = endIndex;
PrevSourceEndIndex = prevSourceEndIndex;
ItemCount = EndIndex - PrevSourceEndIndex;
}
}

/// <summary>
/// This type represents an individual suggestion entry.
/// </summary>
private struct SuggestionEntry
{
internal const char Ellipsis = '\u2026';
internal const string HistorySource = "History";

internal readonly Guid PredictorId;
internal readonly uint? PredictorSession;
internal readonly string Source;
internal readonly string SuggestionText;
internal readonly int InputMatchIndex;

private string _listItemTextRegular;
private string _listItemTextSelected;

internal SuggestionEntry(string suggestion, int matchIndex)
: this(source: "History", predictorId: Guid.Empty, predictorSession: null, suggestion, matchIndex)
: this(source: HistorySource, predictorId: Guid.Empty, predictorSession: null, suggestion, matchIndex)
{
}

Expand All @@ -32,6 +65,8 @@ internal SuggestionEntry(string source, Guid predictorId, uint? predictorSession
PredictorSession = predictorSession;
SuggestionText = suggestion;
InputMatchIndex = matchIndex;

_listItemTextRegular = _listItemTextSelected = null;
}

/// <summary>
Expand All @@ -57,8 +92,19 @@ private static int DivideAndRoundUp(int dividend, int divisor)
/// <param name="selectionHighlighting">The highlighting sequences for a selected list item.</param>
internal string GetListItemText(int width, string input, string selectionHighlighting)
{
const string ellipsis = "...";
const int ellipsisLength = 3;
const int ellipsisLength = 1;

if (selectionHighlighting is null)
{
if (_listItemTextRegular is not null)
{
return _listItemTextRegular;
}
}
else if (_listItemTextSelected is not null)
{
return _listItemTextSelected;
}

// Calculate the 'SOURCE' portion to be rendered.
int sourceStrLen = Source.Length;
Expand Down Expand Up @@ -119,7 +165,7 @@ internal string GetListItemText(int width, string input, string selectionHighlig
// The suggestion text doesn't contain the user input.
int length = SubstringLengthByCells(SuggestionText, textWidth - ellipsisLength);
line.Append(SuggestionText, 0, length)
.Append(ellipsis);
.Append(Ellipsis);
break;
}

Expand All @@ -136,7 +182,7 @@ internal string GetListItemText(int width, string input, string selectionHighlig
.Append(SuggestionText, 0, input.Length)
.EndColorSection(selectionHighlighting)
.Append(SuggestionText, input.Length, length - input.Length)
.Append(ellipsis);
.Append(Ellipsis);
}
else
{
Expand All @@ -149,7 +195,7 @@ internal string GetListItemText(int width, string input, string selectionHighlig
int remainingLenInCells = textWidth - ellipsisLength - rightLenInCells;
int length = SubstringLengthByCellsFromEnd(SuggestionText, input.Length - 1, remainingLenInCells);
line.Append(_singleton._options.EmphasisColor)
.Append(ellipsis)
.Append(Ellipsis)
.Append(SuggestionText, input.Length - length, length)
.EndColorSection(selectionHighlighting)
.Append(SuggestionText, input.Length, SuggestionText.Length - input.Length);
Expand All @@ -162,11 +208,11 @@ internal string GetListItemText(int width, string input, string selectionHighlig
int startIndex = input.Length - leftStrLen;
int totalStrLen = SubstringLengthByCells(SuggestionText, startIndex, textWidth - ellipsisLength * 2);
line.Append(_singleton._options.EmphasisColor)
.Append(ellipsis)
.Append(Ellipsis)
.Append(SuggestionText, startIndex, leftStrLen)
.EndColorSection(selectionHighlighting)
.Append(SuggestionText, input.Length, totalStrLen - leftStrLen)
.Append(ellipsis);
.Append(Ellipsis);
}
}

Expand All @@ -192,7 +238,7 @@ internal string GetListItemText(int width, string input, string selectionHighlig
.Append(SuggestionText, InputMatchIndex, input.Length)
.EndColorSection(selectionHighlighting)
.Append(SuggestionText, rightStartindex, rightStrLen)
.Append(ellipsis);
.Append(Ellipsis);
break;
}

Expand All @@ -201,7 +247,7 @@ internal string GetListItemText(int width, string input, string selectionHighlig
{
// Otherwise, if the (mid+right) portions take up to 2/3 of the text width, we just truncate the suggestion text at the beginning.
int leftStrLen = SubstringLengthByCellsFromEnd(SuggestionText, InputMatchIndex - 1, textWidth - midRightLenInCells - ellipsisLength);
line.Append(ellipsis)
line.Append(Ellipsis)
.Append(SuggestionText, InputMatchIndex - leftStrLen, leftStrLen)
.Append(_singleton._options.EmphasisColor)
.Append(SuggestionText, InputMatchIndex, input.Length)
Expand All @@ -223,13 +269,13 @@ internal string GetListItemText(int width, string input, string selectionHighlig
int leftStrLen = SubstringLengthByCellsFromEnd(SuggestionText, InputMatchIndex - 1, leftCellLen - ellipsisLength);
int rightStrLen = SubstringLengthByCells(SuggestionText, rightStartindex, rigthCellLen - ellipsisLength);

line.Append(ellipsis)
line.Append(Ellipsis)
.Append(SuggestionText, InputMatchIndex - leftStrLen, leftStrLen)
.Append(_singleton._options.EmphasisColor)
.Append(SuggestionText, InputMatchIndex, input.Length)
.EndColorSection(selectionHighlighting)
.Append(SuggestionText, rightStartindex, rightStrLen)
.Append(ellipsis);
.Append(Ellipsis);
break;
}

Expand All @@ -249,7 +295,7 @@ internal string GetListItemText(int width, string input, string selectionHighlig
line.Append(SuggestionText, 0, InputMatchIndex)
.Append(_singleton._options.EmphasisColor)
.Append(SuggestionText, InputMatchIndex, midLeftStrLen)
.Append(ellipsis)
.Append(Ellipsis)
.Append(SuggestionText, rightStartindex - midRightStrLen, midRightStrLen)
.EndColorSection(selectionHighlighting)
.Append(SuggestionText, rightStartindex, SuggestionText.Length - rightStartindex);
Expand Down Expand Up @@ -277,11 +323,11 @@ internal string GetListItemText(int width, string input, string selectionHighlig
line.Append(SuggestionText, 0, InputMatchIndex)
.Append(_singleton._options.EmphasisColor)
.Append(SuggestionText, InputMatchIndex, midLeftStrLen)
.Append(ellipsis)
.Append(Ellipsis)
.Append(SuggestionText, rightStartindex - midRightStrLen, midRightStrLen)
.EndColorSection(selectionHighlighting)
.Append(SuggestionText, rightStartindex, rightStrLen)
.Append(ellipsis);
.Append(Ellipsis);
break;
}

Expand All @@ -298,11 +344,11 @@ internal string GetListItemText(int width, string input, string selectionHighlig
int midRightStrLen = SubstringLengthByCellsFromEnd(SuggestionText, rightStartindex - 1, midRightCellLen);
int leftStrLen = SubstringLengthByCellsFromEnd(SuggestionText, InputMatchIndex - 1, midRemainingLenInCells);

line.Append(ellipsis)
line.Append(Ellipsis)
.Append(SuggestionText, InputMatchIndex - leftStrLen, leftStrLen)
.Append(_singleton._options.EmphasisColor)
.Append(SuggestionText, InputMatchIndex, midLeftStrLen)
.Append(ellipsis)
.Append(Ellipsis)
.Append(SuggestionText, rightStartindex - midRightStrLen, midRightStrLen)
.EndColorSection(selectionHighlighting)
.Append(SuggestionText, rightStartindex, SuggestionText.Length - rightStartindex);
Expand All @@ -324,15 +370,15 @@ internal string GetListItemText(int width, string input, string selectionHighlig
int spacesNeeded = textWidth - midRemainingLenInCells * 3 - ellipsisLength * 3;
string spaces = spacesNeeded > 0 ? Spaces(spacesNeeded) : string.Empty;

line.Append(ellipsis)
line.Append(Ellipsis)
.Append(SuggestionText, InputMatchIndex - leftStrLen, leftStrLen)
.Append(_singleton._options.EmphasisColor)
.Append(SuggestionText, InputMatchIndex, midLeftStrLen)
.Append(ellipsis)
.Append(Ellipsis)
.Append(SuggestionText, rightStartindex - midRightStrLen, midRightStrLen)
.EndColorSection(selectionHighlighting)
.Append(SuggestionText, rightStartindex, rightStrLen)
.Append(ellipsis)
.Append(Ellipsis)
.Append(spaces);
break;
}
Expand All @@ -351,13 +397,29 @@ internal string GetListItemText(int width, string input, string selectionHighlig
else
{
line.Append(Source, 0, sourceStrLen)
.Append(ellipsis);
.Append(Ellipsis);
}

line.EndColorSection(selectionHighlighting)
.Append(']');

return line.ToString();
if (selectionHighlighting is not null)
{
// Need to reset at the end if the selection highlighting is being applied.
line.Append(VTColorUtils.AnsiReset);
}

string textForRendering = line.ToString();
if (selectionHighlighting is null)
{
_listItemTextRegular = textForRendering;
}
else
{
_listItemTextSelected = textForRendering;
}

return textForRendering;
}
}
}
Expand Down