@@ -17,6 +17,7 @@ internal class GroupableTask(string inProgressMessage, GroupableTask? parent) :
1717 public bool IsCompleted { get ; protected set ; }
1818 public GroupableTask ? Parent { get ; } = parent ;
1919 public string InProgressMessage { get ; set ; } = inProgressMessage ;
20+ public bool EscapeInProgressMessage { get ; set ; } = true ;
2021 public string ? SubStatus { get ; set ; }
2122
2223 public void Dispose ( )
@@ -33,16 +34,16 @@ internal class GroupableTask<T> : GroupableTask
3334 public T ? CompletedMessage { get ; protected set ; }
3435 private readonly Func < TaskContext , CancellationToken , Task < T > > ? _taskFunc ;
3536 protected readonly IAnsiConsole AnsiConsole ;
36- protected readonly LiveUpdateSignal Signal ;
37+ protected readonly Lock RenderLock ;
3738 private readonly ILogger _logger ;
3839
39- public GroupableTask ( string inProgressMessage , GroupableTask ? parent , Func < TaskContext , CancellationToken , Task < T > > ? taskFunc , IAnsiConsole ansiConsole , ILogger logger , LiveUpdateSignal signal )
40+ public GroupableTask ( string inProgressMessage , GroupableTask ? parent , Func < TaskContext , CancellationToken , Task < T > > ? taskFunc , IAnsiConsole ansiConsole , ILogger logger , Lock renderLock )
4041 : base ( inProgressMessage , parent )
4142 {
4243 _taskFunc = taskFunc ;
4344 AnsiConsole = ansiConsole ;
4445 _logger = logger ;
45- Signal = signal ;
46+ RenderLock = renderLock ;
4647 }
4748
4849 public virtual async Task < T ? > ExecuteAsync ( Action ? onUpdate , CancellationToken cancellationToken , bool startSpinner = true )
@@ -53,7 +54,7 @@ public GroupableTask(string inProgressMessage, GroupableTask? parent, Func<TaskC
5354 {
5455 if ( _taskFunc != null )
5556 {
56- var context = new TaskContext ( this , onUpdate , AnsiConsole , _logger , Signal ) ;
57+ var context = new TaskContext ( this , onUpdate , AnsiConsole , _logger , RenderLock ) ;
5758 CompletedMessage = await _taskFunc ( context , cancellationToken ) ;
5859 IsCompleted = true ;
5960 }
@@ -72,43 +73,47 @@ public GroupableTask(string inProgressMessage, GroupableTask? parent, Func<TaskC
7273 return CompletedMessage ;
7374 }
7475
75- public ( IRenderable , int ) Render ( )
76+ public IRenderable Render ( )
7677 {
7778 var sb = new StringBuilder ( ) ;
7879
7980 int maxDepth = _logger . IsEnabled ( LogLevel . Debug ) ? int . MaxValue : 1 ;
80- var lineCount = RenderTask ( this , sb , 0 , string . Empty , maxDepth ) ;
81+ RenderTask ( this , sb , 0 , string . Empty , maxDepth ) ;
82+ var allTasksString = sb . ToString ( ) . TrimEnd ( [ .. Environment . NewLine ] ) ;
83+ if ( ! allTasksString . Contains ( Environment . NewLine ) )
84+ {
85+ allTasksString = $ "{ allTasksString } { Environment . NewLine } ";
86+ }
8187
82- var panel = new Panel ( new Markup ( sb . ToString ( ) . TrimEnd ( [ .. Environment . NewLine ] ) ) )
88+ var panel = new Panel ( allTasksString )
8389 {
8490 Border = BoxBorder . None ,
8591 Padding = new Padding ( 0 , 0 ) ,
8692 Expand = true
8793 } ;
8894
89- return ( panel , lineCount ) ;
95+ return panel ;
9096 }
9197
92- private static int RenderSubTasks ( GroupableTask task , StringBuilder sb , int indentLevel , int maxForcedDepth )
98+ private static void RenderSubTasks ( GroupableTask task , StringBuilder sb , int indentLevel , int maxForcedDepth )
9399 {
94100 if ( task . SubTasks . Count == 0 )
95101 {
96- return 0 ;
102+ return ;
97103 }
98104
99105 var indentStr = new string ( ' ' , indentLevel * 2 ) ;
100- int lineCount = 0 ;
101106
102107 foreach ( var subTask in task . SubTasks )
103108 {
104- lineCount += RenderTask ( subTask , sb , indentLevel , indentStr , maxForcedDepth ) ;
109+ RenderTask ( subTask , sb , indentLevel , indentStr , maxForcedDepth ) ;
105110 }
106-
107- return lineCount ;
108111 }
109112
110- private static int RenderTask ( GroupableTask task , StringBuilder sb , int indentLevel , string indentStr , int maxForcedDepth )
113+ private static void RenderTask ( GroupableTask task , StringBuilder sb , int indentLevel , string indentStr , int maxForcedDepth )
111114 {
115+ string msg ;
116+
112117 if ( task . IsCompleted )
113118 {
114119 static string FormatCheckMarkMessage ( string indentStr , string message )
@@ -123,7 +128,8 @@ static string FormatCheckMarkMessage(string indentStr, string message)
123128 }
124129 return firstCharIsEmojiOrOpenBracket ? $ "{ indentStr } { message } " : $ "{ indentStr } [green]{ Emoji . Known . CheckMarkButton } [/] { message } ";
125130 }
126- sb . AppendLine ( task switch
131+
132+ msg = task switch
127133 {
128134 StatusMessageTask statusMessageTask => $ "{ indentStr } { Markup . Escape ( statusMessageTask . CompletedMessage ?? string . Empty ) } ",
129135 GroupableTask < T > genericTask => FormatCheckMarkMessage ( indentStr , ( genericTask . CompletedMessage as ITuple ) switch
@@ -133,31 +139,38 @@ static string FormatCheckMarkMessage(string indentStr, string message)
133139 _ => genericTask . CompletedMessage ? . ToString ( ) ?? string . Empty
134140 } ) ,
135141 GroupableTask _ => FormatCheckMarkMessage ( indentStr , Markup . Escape ( task . InProgressMessage ) ) ,
136- } ) ;
142+ } ;
137143 }
138144 else
139145 {
140146 var spinnerChars = new [ ] { "⠋" , "⠙" , "⠹" , "⠸" , "⠼" , "⠴" , "⠦" , "⠧" , "⠇" , "⠏" } ;
141147 var spinnerIndex = ( int ) ( DateTimeOffset . UtcNow . ToUnixTimeMilliseconds ( ) / 100 ) % spinnerChars . Length ;
142148 var spinner = spinnerChars [ spinnerIndex ] ;
143149
144- var msg = task . InProgressMessage ;
150+ msg = task . InProgressMessage ;
145151 if ( ! string . IsNullOrEmpty ( task . SubStatus ) )
146152 {
147153 msg = $ "{ msg } ({ task . SubStatus } )";
148154 }
149-
150- sb . AppendLine ( $ "{ indentStr } [yellow]{ spinner } [/] { Markup . Escape ( msg ) } ") ;
155+ if ( task . EscapeInProgressMessage )
156+ {
157+ msg = Markup . Escape ( msg ) ;
158+ }
159+ if ( task is not PromptConfirmationTask promptConfirmationTask || promptConfirmationTask . State != PromptState . WaitingForInput )
160+ {
161+ msg = $ "{ indentStr } [yellow]{ spinner } [/] { msg } ";
162+ }
151163 }
152164
153- int lineCount = 1 ;
165+ // make line endings consistent
166+ msg = msg . Replace ( "\r \n " , "\n " ) . Replace ( "\r " , "\n " ) . Replace ( "\n " , Environment . NewLine ) . TrimEnd ( [ .. Environment . NewLine ] ) ;
167+
168+ sb . AppendLine ( msg ) ;
154169
155170 bool shouldRenderChildren = indentLevel + 1 <= maxForcedDepth || ! task . IsCompleted ;
156171 if ( shouldRenderChildren )
157172 {
158- lineCount += RenderSubTasks ( task , sb , indentLevel + 1 , maxForcedDepth ) ;
173+ RenderSubTasks ( task , sb , indentLevel + 1 , maxForcedDepth ) ;
159174 }
160-
161- return lineCount ;
162175 }
163176}
0 commit comments