@@ -32,6 +32,7 @@ public abstract class EditorServicesPSHostUserInterface :
32
32
{
33
33
#region Private Fields
34
34
35
+ private readonly HashSet < ProgressKey > currentProgressMessages = new HashSet < ProgressKey > ( ) ;
35
36
private PromptHandler activePromptHandler ;
36
37
private PSHostRawUserInterface rawUserInterface ;
37
38
private CancellationTokenSource commandLoopCancellationToken ;
@@ -83,6 +84,11 @@ public abstract class EditorServicesPSHostUserInterface :
83
84
/// </summary>
84
85
protected ILogger Logger { get ; private set ; }
85
86
87
+ /// <summary>
88
+ /// Gets a value indicating whether writing progress is supported.
89
+ /// </summary>
90
+ internal protected virtual bool SupportsWriteProgress => false ;
91
+
86
92
#endregion
87
93
88
94
#region Constructors
@@ -582,17 +588,74 @@ public override void WriteErrorLine(string value)
582
588
}
583
589
584
590
/// <summary>
585
- ///
591
+ /// Invoked by <see cref="Cmdlet.WriteProgress(ProgressRecord)" /> to display a progress record.
586
592
/// </summary>
587
- /// <param name="sourceId"></param>
588
- /// <param name="record"></param>
589
- public override void WriteProgress (
593
+ /// <param name="sourceId">
594
+ /// Unique identifier of the source of the record. An int64 is used because typically,
595
+ /// the 'this' pointer of the command from whence the record is originating is used, and
596
+ /// that may be from a remote Runspace on a 64-bit machine.
597
+ /// </param>
598
+ /// <param name="record">
599
+ /// The record being reported to the host.
600
+ /// </param>
601
+ public sealed override void WriteProgress (
590
602
long sourceId ,
591
603
ProgressRecord record )
592
604
{
593
- this . UpdateProgress (
594
- sourceId ,
595
- ProgressDetails . Create ( record ) ) ;
605
+ // Maintain old behavior if this isn't overridden.
606
+ if ( ! this . SupportsWriteProgress )
607
+ {
608
+ this . UpdateProgress ( sourceId , ProgressDetails . Create ( record ) ) ;
609
+ return ;
610
+ }
611
+
612
+ // Keep a list of progress records we write so we can automatically
613
+ // clean them up after the pipeline ends.
614
+ if ( record . RecordType == ProgressRecordType . Completed )
615
+ {
616
+ this . currentProgressMessages . Remove ( new ProgressKey ( sourceId , record ) ) ;
617
+ }
618
+ else
619
+ {
620
+ this . currentProgressMessages . Add ( new ProgressKey ( sourceId , record ) ) ;
621
+ }
622
+
623
+ this . WriteProgressImpl ( sourceId , record ) ;
624
+ }
625
+
626
+ /// <summary>
627
+ /// Invoked by <see cref="Cmdlet.WriteProgress(ProgressRecord)" /> to display a progress record.
628
+ /// </summary>
629
+ /// <param name="sourceId">
630
+ /// Unique identifier of the source of the record. An int64 is used because typically,
631
+ /// the 'this' pointer of the command from whence the record is originating is used, and
632
+ /// that may be from a remote Runspace on a 64-bit machine.
633
+ /// </param>
634
+ /// <param name="record">
635
+ /// The record being reported to the host.
636
+ /// </param>
637
+ protected virtual void WriteProgressImpl ( long sourceId , ProgressRecord record )
638
+ {
639
+ }
640
+
641
+ internal void ClearProgress ( )
642
+ {
643
+ const string nonEmptyString = "noop" ;
644
+ if ( ! this . SupportsWriteProgress )
645
+ {
646
+ return ;
647
+ }
648
+
649
+ foreach ( ProgressKey key in this . currentProgressMessages )
650
+ {
651
+ // This constructor throws if the activity description is empty even
652
+ // with completed records.
653
+ var record = new ProgressRecord ( key . ActivityId , nonEmptyString , nonEmptyString ) ;
654
+ record . RecordType = ProgressRecordType . Completed ;
655
+ this . WriteProgressImpl ( key . SourceId , record ) ;
656
+ }
657
+
658
+ this . currentProgressMessages . Clear ( ) ;
596
659
}
597
660
598
661
#endregion
@@ -917,6 +980,8 @@ private void PowerShellContext_ExecutionStatusChanged(object sender, ExecutionSt
917
980
// The command loop should only be manipulated if it's already started
918
981
if ( eventArgs . ExecutionStatus == ExecutionStatus . Aborted )
919
982
{
983
+ this . ClearProgress ( ) ;
984
+
920
985
// When aborted, cancel any lingering prompts
921
986
if ( this . activePromptHandler != null )
922
987
{
@@ -932,6 +997,8 @@ private void PowerShellContext_ExecutionStatusChanged(object sender, ExecutionSt
932
997
// the display of the prompt
933
998
if ( eventArgs . ExecutionStatus != ExecutionStatus . Running )
934
999
{
1000
+ this . ClearProgress ( ) ;
1001
+
935
1002
// Execution has completed, start the input prompt
936
1003
this . ShowCommandPrompt ( ) ;
937
1004
StartCommandLoop ( ) ;
@@ -948,11 +1015,48 @@ private void PowerShellContext_ExecutionStatusChanged(object sender, ExecutionSt
948
1015
( eventArgs . ExecutionStatus == ExecutionStatus . Failed ||
949
1016
eventArgs . HadErrors ) )
950
1017
{
1018
+ this . ClearProgress ( ) ;
951
1019
this . WriteOutput ( string . Empty , true ) ;
952
1020
var unusedTask = this . WritePromptStringToHostAsync ( CancellationToken . None ) ;
953
1021
}
954
1022
}
955
1023
956
1024
#endregion
1025
+
1026
+ private readonly struct ProgressKey : IEquatable < ProgressKey >
1027
+ {
1028
+ internal readonly long SourceId ;
1029
+
1030
+ internal readonly int ActivityId ;
1031
+
1032
+ internal readonly int ParentActivityId ;
1033
+
1034
+ internal ProgressKey ( long sourceId , ProgressRecord record )
1035
+ {
1036
+ SourceId = sourceId ;
1037
+ ActivityId = record . ActivityId ;
1038
+ ParentActivityId = record . ParentActivityId ;
1039
+ }
1040
+
1041
+ public bool Equals ( ProgressKey other )
1042
+ {
1043
+ return SourceId == other . SourceId
1044
+ && ActivityId == other . ActivityId
1045
+ && ParentActivityId == other . ParentActivityId ;
1046
+ }
1047
+
1048
+ public override int GetHashCode ( )
1049
+ {
1050
+ // Algorithm from https://stackoverflow.com/questions/1646807/quick-and-simple-hash-code-combinations
1051
+ unchecked
1052
+ {
1053
+ int hash = 17 ;
1054
+ hash = hash * 31 + SourceId . GetHashCode ( ) ;
1055
+ hash = hash * 31 + ActivityId . GetHashCode ( ) ;
1056
+ hash = hash * 31 + ParentActivityId . GetHashCode ( ) ;
1057
+ return hash ;
1058
+ }
1059
+ }
1060
+ }
957
1061
}
958
1062
}
0 commit comments