diff --git a/src/glitzer.gleam b/src/glitzer.gleam index 03d7c6e..4ce9586 100644 --- a/src/glitzer.gleam +++ b/src/glitzer.gleam @@ -1,3 +1,6 @@ +import gleam/int +import gleam/iterator + import glitzer/progress @external(erlang, "glitzer_ffi", "sleep") @@ -10,15 +13,14 @@ pub fn main() { |> progress.with_length(10) do_something(bar, 0) + do_something_else() + do_cool_shit_with_2_it() } fn do_something(bar, count) { case count < 10 { True -> { - let bar = case count > 5 { - True -> progress.finish(bar) - False -> progress.tick(bar) - } + let bar = progress.tick(bar) progress.print_bar(bar) sleep(100) do_something(bar, count + 1) @@ -26,3 +28,31 @@ fn do_something(bar, count) { False -> Nil } } + +fn do_something_else() { + let bar = + progress.fancy_slim_arrow_bar() + |> progress.with_length(10) + + iterator.range(0, 10) + |> progress.each_iterator(bar, fn(bar, i) { + progress.with_left_text(bar, int.to_string(i) <> " ") + |> progress.print_bar + sleep(100) + }) +} + +fn do_cool_shit_with_2_it() { + let bar = + progress.default_bar() + |> progress.with_length(10) + let i1 = iterator.range(0, 10) + let i2 = iterator.range(100, 150) + progress.map2_iterator(i1, i2, bar, fn(bar, e1, e2) { + progress.with_left_text(bar, int.to_string(e1) <> " ") + |> progress.with_right_text(" " <> int.to_string(e2)) + |> progress.print_bar + sleep(100) + }) + |> iterator.run +} diff --git a/src/glitzer/progress.gleam b/src/glitzer/progress.gleam index 0716a64..b4b3d54 100644 --- a/src/glitzer/progress.gleam +++ b/src/glitzer/progress.gleam @@ -1,4 +1,5 @@ import gleam/io +import gleam/iterator.{type Iterator} import gleam/option.{type Option} import gleam/string import gleam/string_builder.{type StringBuilder} @@ -281,17 +282,28 @@ pub fn finish(bar bar: ProgressStyle) -> ProgressStyle { /// } /// ``` pub fn print_bar(bar bar: ProgressStyle) { + let bar = + ProgressStyle( + ..bar, + state: State(..bar.state, finished: bar.state.progress >= bar.length), + ) let fill = - build_progress_fill(string_builder.new(), bar, bar.state.progress, 0) + build_progress_fill(string_builder.new(), bar, bar.state.progress + 1, 0) |> string_builder.to_string + let end = case bar.state.finished { + True -> "\n" + False -> "" + } + io.print_error( codes.hide_cursor_code <> codes.clear_line_code <> codes.return_line_start_code <> bar.left <> fill - <> bar.right, + <> bar.right + <> end, ) } @@ -356,3 +368,69 @@ fn get_finished_fill(fill: StringBuilder, bar: ProgressStyle) -> StringBuilder { False -> string_builder.append(fill, bar.fill.char) } } + +/// Map an iterator to a function with a bar that ticks every run of the +/// function. +/// +///
+/// Example: +/// +/// ```gleam +/// import glitzer/progress +/// +/// fn example(bar) { +/// iterator.range(0, 100) +/// |> progress.map_iterator(fn(bar, element) { +/// progress.print_bar(bar) +/// // do some heavy calculations here >:) +/// }) +/// } +/// ``` +pub fn map_iterator( + over i: Iterator(a), + bar bar: ProgressStyle, + with fun: fn(ProgressStyle, a) -> b, +) -> Iterator(b) { + iterator.index(i) + |> iterator.map(fn(pair) { + let #(el, i) = pair + tick_bar_by_i(bar, i) + |> fun(el) + }) +} + +fn tick_bar_by_i(bar, i) -> ProgressStyle { + case i > 0 { + True -> tick_bar_by_i(tick(bar), i - 1) + False -> bar + } +} + +pub fn map2_iterator( + iterator1 i1: Iterator(a), + iterator2 i2: Iterator(b), + bar bar: ProgressStyle, + with fun: fn(ProgressStyle, a, b) -> c, +) -> Iterator(c) { + iterator.zip(i1, i2) + |> iterator.index + |> iterator.map(fn(pair) { + let #(pair, i) = pair + let #(el1, el2) = pair + tick_bar_by_i(bar, i) + |> fun(el1, el2) + }) +} + +pub fn each_iterator( + over i: Iterator(a), + bar bar: ProgressStyle, + with fun: fn(ProgressStyle, a) -> b, +) -> Nil { + iterator.index(i) + |> iterator.each(fn(pair) { + let #(el, i) = pair + tick_bar_by_i(bar, i) + |> fun(el) + }) +}