progress

progress
git clone git://brookjeynes.dev/bjeynes/progress.git
Log | Files | Refs | README | LICENSE

commit be0bea6140acbd2296b9a8e89fe8f2ed281d9158
parent db9de7f75a49688a91134f65534912210b119aa7
Author: BrookJeynes <jeynesbrook@gmail.com>
Date:   Sat,  7 Sep 2024 09:33:32 +1000

Added new `updateDescriptionNewline` to spinner
- Added new `completionCharacter` config. This character, if defined,
  gets printed instead of the spinner symbol on `Spinner.finish()`.
- `updateDescriptionNewline` allows you to now retain the previous
  spinner symbol / description on the previous line and start a new task
  on the next. This goes hand in hand with the new `completionCharacter`
  config.
- Updated casing from `update_description()` to `updateDescription()`.

Diffstat:
Mexamples/spinner/complex.zig | 14+++++++++-----
Msrc/bar.zig | 2+-
Msrc/spinner.zig | 37++++++++++++++++++++++++++++++++++++-
3 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/examples/spinner/complex.zig b/examples/spinner/complex.zig @@ -4,19 +4,23 @@ const ProgressSpinner = @import("progress").Spinner; pub fn main() !void { const stdout = std.io.getStdOut().writer(); var ps = ProgressSpinner.init(stdout.any(), .{ - .description = "Progress spinner", + .description = "Task 1", .symbols = &[_]u21{ '⣾', '⣷', '⣯', '⣟', '⡿', '⢿', '⣻', '⣽' }, - .write_newline_on_finish = false, + .completion_character = '✓', }); - defer ps.clear() catch {}; var iterations: usize = 0; while (!ps.isFinished()) { iterations += 1; try ps.render(); - if (iterations == 10) ps.update_description("Half way there"); - if (iterations == 20) try ps.finish(); + if (iterations == 10) ps.updateDescription("Task 1.1"); + if (iterations == 13) ps.updateDescription("Task 1.2"); + if (iterations == 20) try ps.updateDescriptionNewline("Task 2.0"); + if (iterations == 23) try ps.updateDescriptionNewline("Task 3.0"); + if (iterations == 26) ps.updateDescription("Task 3.1"); + if (iterations == 30) try ps.updateDescriptionNewline("Task 4.0"); + if (iterations == 40) try ps.finish(); std.time.sleep(std.time.ns_per_ms * 150); } diff --git a/src/bar.zig b/src/bar.zig @@ -202,7 +202,7 @@ pub fn set(self: *Bar, num: usize) void { } ///Update the description. -pub fn update_description(self: *Bar, description: []const u8) void { +pub fn updateDescription(self: *Bar, description: []const u8) void { self.mutex.lock(); defer self.mutex.unlock(); diff --git a/src/spinner.zig b/src/spinner.zig @@ -23,6 +23,8 @@ const Config = struct { clear_on_finish: bool = false, ///Write a newline when the progress spinner finishes. write_newline_on_finish: bool = true, + ///Character to write on completion. + completion_character: ?u21 = null, }; const Spinner = @This(); @@ -41,6 +43,20 @@ pub fn init(writer: std.io.AnyWriter, config: Config) Spinner { }; } +fn renderComplete(self: *Spinner, completion_char: u21) !void { + try self.clear(); + var buf: [8]u8 = undefined; + const bytes = try std.unicode.utf8Encode(completion_char, &buf); + _ = try self.bw.write(buf[0..bytes]); + + if (self.config.description) |desc| { + try escape_codes.cursorForward(self.bw.writer(), 1); + _ = try self.bw.write(desc); + } + + try self.bw.flush(); +} + ///Render the progress spinner and advance a visual cycle. pub fn render(self: *Spinner) !void { self.mutex.lock(); @@ -79,6 +95,10 @@ pub fn finish(self: *Spinner) !void { self.finished = true; + if (self.config.completion_character) |char| { + try self.renderComplete(char); + } + if (self.config.clear_on_finish) try self.clear(); if (self.config.write_newline_on_finish) _ = try self.bw.write("\n"); @@ -87,11 +107,26 @@ pub fn finish(self: *Spinner) !void { } ///Update the description. -pub fn update_description(self: *Spinner, description: []const u8) void { +pub fn updateDescription(self: *Spinner, description: []const u8) void { + self.mutex.lock(); + defer self.mutex.unlock(); + + self.config.description = description; +} + +///Update the description and continue the spinner on a newline. +pub fn updateDescriptionNewline(self: *Spinner, description: []const u8) !void { self.mutex.lock(); defer self.mutex.unlock(); + if (self.config.completion_character) |char| { + try self.renderComplete(char); + } + self.config.description = description; + + _ = try self.bw.write("\n"); + try self.bw.flush(); } ///Clear the progress spinner.