@@ -25,6 +25,7 @@ redraw_event: std.Thread.ResetEvent,
2525/// Accessed atomically.
2626done : bool ,
2727need_clear : bool ,
28+ status : Status ,
2829
2930refresh_rate_ns : u64 ,
3031initial_delay_ns : u64 ,
@@ -47,6 +48,22 @@ node_freelist: Freelist,
4748/// value may at times temporarily exceed the node count.
4849node_end_index : u32 ,
4950
51+ pub const Status = enum {
52+ /// Indicates the application is progressing towards completion of a task.
53+ /// Unless the application is interactive, this is the only status the
54+ /// program will ever have!
55+ working ,
56+ /// The application has completed an operation, and is now waiting for user
57+ /// input rather than calling exit(0).
58+ success ,
59+ /// The application encountered an error, and is now waiting for user input
60+ /// rather than calling exit(1).
61+ failure ,
62+ /// The application encountered at least one error, but is still working on
63+ /// more tasks.
64+ failure_working ,
65+ };
66+
5067const Freelist = packed struct (u32 ) {
5168 head : Node.OptionalIndex ,
5269 /// Whenever `node_freelist` is added to, this generation is incremented
@@ -383,6 +400,7 @@ var global_progress: Progress = .{
383400 .draw_buffer = undefined ,
384401 .done = false ,
385402 .need_clear = false ,
403+ .status = .working ,
386404
387405 .node_parents = & node_parents_buffer ,
388406 .node_storage = & node_storage_buffer ,
@@ -498,6 +516,11 @@ pub fn start(options: Options) Node {
498516 return root_node ;
499517}
500518
519+ pub fn setStatus (new_status : Status ) void {
520+ if (noop_impl ) return ;
521+ @atomicStore (Status , & global_progress .status , new_status , .monotonic );
522+ }
523+
501524/// Returns whether a resize is needed to learn the terminal size.
502525fn wait (timeout_ns : u64 ) bool {
503526 const resize_flag = if (global_progress .redraw_event .timedWait (timeout_ns )) | _ |
@@ -678,6 +701,14 @@ const save = "\x1b7";
678701const restore = "\x1b 8" ;
679702const finish_sync = "\x1b [?2026l" ;
680703
704+ const progress_remove = "\x1b ]9;4;0\x07 " ;
705+ const @"progress_normal {d}" = "\x1b ]9;4;1;{d}\x07 " ;
706+ const @"progress_error {d}" = "\x1b ]9;4;2;{d}\x07 " ;
707+ const progress_pulsing = "\x1b ]9;4;3\x07 " ;
708+ const progress_pulsing_error = "\x1b ]9;4;2\x07 " ;
709+ const progress_normal_100 = "\x1b ]9;4;1;100\x07 " ;
710+ const progress_error_100 = "\x1b ]9;4;2;100\x07 " ;
711+
681712const TreeSymbol = enum {
682713 /// ├─
683714 tee ,
@@ -760,7 +791,7 @@ fn clearWrittenWithEscapeCodes() anyerror!void {
760791 if (noop_impl or ! global_progress .need_clear ) return ;
761792
762793 global_progress .need_clear = false ;
763- try write (clear );
794+ try write (clear ++ progress_remove );
764795}
765796
766797/// U+25BA or ►
@@ -1203,6 +1234,43 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {
12031234 i , const nl_n = computeNode (buf , i , 0 , serialized , children , root_node_index );
12041235
12051236 if (global_progress .terminal_mode == .ansi_escape_codes ) {
1237+ {
1238+ // Set progress state https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC
1239+ const root_storage = & serialized .storage [0 ];
1240+ const storage = if (root_storage .name [0 ] != 0 or children [0 ].child == .none ) root_storage else & serialized .storage [@intFromEnum (children [0 ].child )];
1241+ const estimated_total = storage .estimated_total_count ;
1242+ const completed_items = storage .completed_count ;
1243+ const status = @atomicLoad (Status , & global_progress .status , .monotonic );
1244+ switch (status ) {
1245+ .working = > {
1246+ if (estimated_total == 0 ) {
1247+ buf [i .. ][0.. progress_pulsing .len ].* = progress_pulsing .* ;
1248+ i += progress_pulsing .len ;
1249+ } else {
1250+ const percent = completed_items * 100 / estimated_total ;
1251+ i += (std .fmt .bufPrint (buf [i .. ], @"progress_normal {d}" , .{percent }) catch &.{}).len ;
1252+ }
1253+ },
1254+ .success = > {
1255+ buf [i .. ][0.. progress_remove .len ].* = progress_remove .* ;
1256+ i += progress_remove .len ;
1257+ },
1258+ .failure = > {
1259+ buf [i .. ][0.. progress_error_100 .len ].* = progress_error_100 .* ;
1260+ i += progress_error_100 .len ;
1261+ },
1262+ .failure_working = > {
1263+ if (estimated_total == 0 ) {
1264+ buf [i .. ][0.. progress_pulsing_error .len ].* = progress_pulsing_error .* ;
1265+ i += progress_pulsing_error .len ;
1266+ } else {
1267+ const percent = completed_items * 100 / estimated_total ;
1268+ i += (std .fmt .bufPrint (buf [i .. ], @"progress_error {d}" , .{percent }) catch &.{}).len ;
1269+ }
1270+ },
1271+ }
1272+ }
1273+
12061274 if (nl_n > 0 ) {
12071275 buf [i ] = '\r ' ;
12081276 i += 1 ;
0 commit comments