Skip to content

Commit 53c3690

Browse files
authored
Replace command-error suggestion with new implementation based on subsystem plugin (PowerShell#18252)
1 parent 1d129c9 commit 53c3690

File tree

19 files changed

+835
-121
lines changed

19 files changed

+835
-121
lines changed

experimental-feature-linux.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"PSCustomTableHeaderLabelDecoration",
44
"PSLoadAssemblyFromNativeCode",
55
"PSNativeCommandErrorActionPreference",
6-
"PSSubsystemPluginModel"
6+
"PSSubsystemPluginModel",
7+
"PSFeedbackProvider"
78
]

experimental-feature-windows.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"PSCustomTableHeaderLabelDecoration",
44
"PSLoadAssemblyFromNativeCode",
55
"PSNativeCommandErrorActionPreference",
6-
"PSSubsystemPluginModel"
6+
"PSSubsystemPluginModel",
7+
"PSFeedbackProvider"
78
]

src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
#pragma warning disable 1634, 1691
5-
64
using System;
75
using System.Collections.Generic;
86
using System.Collections.ObjectModel;
@@ -18,6 +16,7 @@
1816
using System.Management.Automation.Remoting;
1917
using System.Management.Automation.Remoting.Server;
2018
using System.Management.Automation.Runspaces;
19+
using System.Management.Automation.Subsystem.Feedback;
2120
using System.Management.Automation.Tracing;
2221
using System.Reflection;
2322
using System.Runtime;
@@ -2489,7 +2488,6 @@ internal void Run(bool inputLoopIsNested)
24892488
if (inBlockMode)
24902489
{
24912490
// use a special prompt that denotes block mode
2492-
24932491
prompt = ">> ";
24942492
}
24952493
else
@@ -2502,7 +2500,14 @@ internal void Run(bool inputLoopIsNested)
25022500
// Evaluate any suggestions
25032501
if (previousResponseWasEmpty == false)
25042502
{
2505-
EvaluateSuggestions(ui);
2503+
if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSFeedbackProvider))
2504+
{
2505+
EvaluateFeedbacks(ui);
2506+
}
2507+
else
2508+
{
2509+
EvaluateSuggestions(ui);
2510+
}
25062511
}
25072512

25082513
// Then output the prompt
@@ -2805,6 +2810,77 @@ private static bool IsIncompleteParseException(Exception e)
28052810
return remoteException.ErrorRecord.CategoryInfo.Reason == nameof(IncompleteParseException);
28062811
}
28072812

2813+
private void EvaluateFeedbacks(ConsoleHostUserInterface ui)
2814+
{
2815+
// Output any training suggestions
2816+
try
2817+
{
2818+
List<FeedbackEntry> feedbacks = FeedbackHub.GetFeedback(_parent.Runspace);
2819+
if (feedbacks is null || feedbacks.Count == 0)
2820+
{
2821+
return;
2822+
}
2823+
2824+
// Feedback section starts with a new line.
2825+
ui.WriteLine();
2826+
2827+
const string Indentation = " ";
2828+
string nameStyle = PSStyle.Instance.Formatting.FeedbackProvider;
2829+
string textStyle = PSStyle.Instance.Formatting.FeedbackText;
2830+
string ansiReset = PSStyle.Instance.Reset;
2831+
2832+
if (!ui.SupportsVirtualTerminal)
2833+
{
2834+
nameStyle = string.Empty;
2835+
textStyle = string.Empty;
2836+
ansiReset = string.Empty;
2837+
}
2838+
2839+
int count = 0;
2840+
var output = new StringBuilder();
2841+
2842+
foreach (FeedbackEntry entry in feedbacks)
2843+
{
2844+
if (count > 0)
2845+
{
2846+
output.AppendLine();
2847+
}
2848+
2849+
output.Append("Suggestion [")
2850+
.Append(nameStyle)
2851+
.Append(entry.Name)
2852+
.Append(ansiReset)
2853+
.AppendLine("]:")
2854+
.Append(textStyle);
2855+
2856+
string[] lines = entry.Text.Split('\n', StringSplitOptions.RemoveEmptyEntries);
2857+
foreach (string line in lines)
2858+
{
2859+
output.Append(Indentation)
2860+
.Append(line.AsSpan().TrimEnd())
2861+
.AppendLine();
2862+
}
2863+
2864+
output.Append(ansiReset);
2865+
ui.Write(output.ToString());
2866+
2867+
count++;
2868+
output.Clear();
2869+
}
2870+
2871+
// Feedback section ends with a new line.
2872+
ui.WriteLine();
2873+
}
2874+
catch (Exception e)
2875+
{
2876+
// Catch-all OK. This is a third-party call-out.
2877+
ui.WriteErrorLine(e.Message);
2878+
2879+
LocalRunspace localRunspace = (LocalRunspace)_parent.Runspace;
2880+
localRunspace.GetExecutionContext.AppendDollarError(e);
2881+
}
2882+
}
2883+
28082884
private void EvaluateSuggestions(ConsoleHostUserInterface ui)
28092885
{
28102886
// Output any training suggestions

src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,12 +2030,15 @@ private static IEnumerable<FormatViewDefinition> ViewsOf_System_Management_Autom
20302030
.AddItemScriptBlock(@"""$($_.Strikethrough)$($_.Strikethrough.Replace(""""`e"""",'`e'))$($_.Reset)""", label: "Strikethrough")
20312031
.AddItemProperty(@"OutputRendering")
20322032
.AddItemScriptBlock(@"""$($_.Formatting.FormatAccent)$($_.Formatting.FormatAccent.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.FormatAccent")
2033-
.AddItemScriptBlock(@"""$($_.Formatting.TableHeader)$($_.Formatting.TableHeader.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.TableHeader")
20342033
.AddItemScriptBlock(@"""$($_.Formatting.ErrorAccent)$($_.Formatting.ErrorAccent.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.ErrorAccent")
20352034
.AddItemScriptBlock(@"""$($_.Formatting.Error)$($_.Formatting.Error.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.Error")
20362035
.AddItemScriptBlock(@"""$($_.Formatting.Warning)$($_.Formatting.Warning.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.Warning")
20372036
.AddItemScriptBlock(@"""$($_.Formatting.Verbose)$($_.Formatting.Verbose.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.Verbose")
20382037
.AddItemScriptBlock(@"""$($_.Formatting.Debug)$($_.Formatting.Debug.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.Debug")
2038+
.AddItemScriptBlock(@"""$($_.Formatting.TableHeader)$($_.Formatting.TableHeader.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.TableHeader")
2039+
.AddItemScriptBlock(@"""$($_.Formatting.CustomTableHeaderLabel)$($_.Formatting.CustomTableHeaderLabel.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.CustomTableHeaderLabel")
2040+
.AddItemScriptBlock(@"""$($_.Formatting.FeedbackProvider)$($_.Formatting.FeedbackProvider.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.FeedbackProvider")
2041+
.AddItemScriptBlock(@"""$($_.Formatting.FeedbackText)$($_.Formatting.FeedbackText.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.FeedbackText")
20392042
.AddItemScriptBlock(@"""$($_.Progress.Style)$($_.Progress.Style.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Progress.Style")
20402043
.AddItemScriptBlock(@"""$($_.Progress.MaxWidth)""", label: "Progress.MaxWidth")
20412044
.AddItemScriptBlock(@"""$($_.Progress.View)""", label: "Progress.View")
@@ -2086,12 +2089,15 @@ private static IEnumerable<FormatViewDefinition> ViewsOf_System_Management_Autom
20862089
ListControl.Create()
20872090
.StartEntry()
20882091
.AddItemScriptBlock(@"""$($_.FormatAccent)$($_.FormatAccent.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "FormatAccent")
2089-
.AddItemScriptBlock(@"""$($_.TableHeader)$($_.TableHeader.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "TableHeader")
20902092
.AddItemScriptBlock(@"""$($_.ErrorAccent)$($_.ErrorAccent.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "ErrorAccent")
20912093
.AddItemScriptBlock(@"""$($_.Error)$($_.Error.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Error")
20922094
.AddItemScriptBlock(@"""$($_.Warning)$($_.Warning.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Warning")
20932095
.AddItemScriptBlock(@"""$($_.Verbose)$($_.Verbose.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Verbose")
20942096
.AddItemScriptBlock(@"""$($_.Debug)$($_.Debug.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Debug")
2097+
.AddItemScriptBlock(@"""$($_.TableHeader)$($_.TableHeader.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "TableHeader")
2098+
.AddItemScriptBlock(@"""$($_.CustomTableHeaderLabel)$($_.CustomTableHeaderLabel.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "CustomTableHeaderLabel")
2099+
.AddItemScriptBlock(@"""$($_.FeedbackProvider)$($_.FeedbackProvider.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "FeedbackProvider")
2100+
.AddItemScriptBlock(@"""$($_.FeedbackText)$($_.FeedbackText.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "FeedbackText")
20952101
.EndEntry()
20962102
.EndList());
20972103
}

src/System.Management.Automation/FormatAndOutput/common/PSStyle.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,28 @@ public string Debug
431431
}
432432

433433
private string _debug = "\x1b[33;1m";
434+
435+
/// <summary>
436+
/// Gets or sets the style for rendering feedback provider names.
437+
/// </summary>
438+
public string FeedbackProvider
439+
{
440+
get => _feedbackProvider;
441+
set => _feedbackProvider = ValidateNoContent(value);
442+
}
443+
444+
private string _feedbackProvider = "\x1b[33m";
445+
446+
/// <summary>
447+
/// Gets or sets the style for rendering feedback text.
448+
/// </summary>
449+
public string FeedbackText
450+
{
451+
get => _feedbackText;
452+
set => _feedbackText = ValidateNoContent(value);
453+
}
454+
455+
private string _feedbackText = "\x1b[96m";
434456
}
435457

436458
/// <summary>

src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class ExperimentalFeature
2323
internal const string EngineSource = "PSEngine";
2424
internal const string PSNativeCommandErrorActionPreferenceFeatureName = "PSNativeCommandErrorActionPreference";
2525
internal const string PSCustomTableHeaderLabelDecoration = "PSCustomTableHeaderLabelDecoration";
26+
internal const string PSFeedbackProvider = "PSFeedbackProvider";
2627

2728
#endregion
2829

@@ -120,6 +121,9 @@ static ExperimentalFeature()
120121
new ExperimentalFeature(
121122
name: PSCustomTableHeaderLabelDecoration,
122123
description: "Formatting differentiation for table header labels that aren't property members"),
124+
new ExperimentalFeature(
125+
name: PSFeedbackProvider,
126+
description: "Replace the hard-coded suggestion framework with the extensible feedback provider"),
123127
};
124128

125129
EngineExperimentalFeatures = new ReadOnlyCollection<ExperimentalFeature>(engineFeatures);

0 commit comments

Comments
 (0)