Skip to content

Commit 4b2241c

Browse files
authored
Merge pull request #36 from pmonks/dev
Release 2.0.270
2 parents 89eba34 + 6dd8bfe commit 4b2241c

File tree

3 files changed

+66
-37
lines changed

3 files changed

+66
-37
lines changed

spinner-demo.gif

24 KB
Loading

spinner-demo.tape

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Require clojure
22
Output spinner-demo.gif
3+
Sleep 50ms
34
Type "clojure -T:build test"
45
Sleep 250ms
56
Enter

src/progress/determinate.clj

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -50,36 +50,54 @@
5050
:tip "🟡"}
5151
:emoji-boxes {:empty "⬛️"
5252
:full "⬜️"
53-
:tip "🟨"}
54-
})
53+
:tip "🟨"}})
5554

5655
(defn- clamp
5756
"Clamps a value within a range."
5857
[mn mx x]
5958
(max mn (min mx x)))
6059

60+
(defn- round
61+
"Rounds `n` to the nearest integer. Unlike `Math/round` returns an integer."
62+
[n]
63+
(int (Math/round (double n))))
64+
65+
(defn- round-up
66+
"Rounds `n` up to the nearest integer. Unlike `Math/ceil` returns an integer."
67+
[n]
68+
(int (Math/ceil (double n))))
69+
70+
(defn- round-down
71+
"Rounds `n` down to the nearest integer. Unlike `Math/floor` returns an integer."
72+
[n]
73+
(int (Math/floor (double n))))
74+
75+
(defn- pad-to-width
76+
"Pads `s` to width `w`, if needed."
77+
[s w]
78+
(if (< (w/display-width s) w)
79+
(str s s)
80+
s))
81+
6182
(defn- redraw-progress-indicator!
6283
"Redraws the progress indicator."
63-
[style style-widths label line width counter? total digits-in-total units new-value]
84+
[style unit-width-cols body-width-chars label line counter? total digits-in-total units new-value]
6485
; Make sure this code is non re-entrant
6586
(locking lock
66-
(let [percent-complete (/ (double new-value) total)
67-
body-cols (- width
68-
(if-not (s/blank? label) (:label style-widths) 0)
69-
(if (:left style) (:left style-widths) 0)
70-
(if (:right style) (:right style-widths) 0)
71-
(if counter? (inc (* 2 (count (str total)))) 0)
72-
(if (and counter? (not (s/blank? units))) (:units style-widths) 0))
73-
tip-cols (if (:tip style) 1 0)
74-
tip-chars (* tip-cols (get style-widths :tip 0))
75-
fill-cols (clamp 0 body-cols (Math/ceil (* percent-complete body-cols)))
76-
fill-chars (- (Math/ceil (/ fill-cols (:full style-widths))) tip-chars)
77-
empty-cols (- body-cols (* fill-chars (:full style-widths))) ; We do it this way due to rounding
78-
empty-chars (Math/floor (/ empty-cols (:empty style-widths)))
87+
(let [; How complete are we?
88+
percent-complete (/ (double new-value) total)
89+
90+
; How many characters of each type?
91+
tip-chars (if (:tip style) 1 0)
92+
complete-chars (clamp 0 body-width-chars (round-up (* percent-complete body-width-chars)))
93+
fill-chars (clamp 0 body-width-chars (- complete-chars tip-chars))
94+
empty-chars (clamp 0 body-width-chars (- body-width-chars complete-chars))
95+
96+
; Separately, calculate how much to pad the current value
7997
counter-pad (- digits-in-total (count (str new-value)))]
98+
(ansi/hide-cursor!)
8099
(when line
81100
(ansi/save-cursor!)
82-
(ansi/hide-cursor!)
83101
(jansi/cursor! 1 line))
84102
(print (str ; Go to the start of the line
85103
"\r"
@@ -98,21 +116,23 @@
98116
(:left-attrs style)
99117
(:left style)))
100118
; Full
101-
(ansi/apply-colours-and-attrs (:full-fg-colour style)
102-
(:full-bg-colour style)
103-
(:full-attrs style)
104-
(s/join (repeat fill-chars (:full style))))
119+
(when (pos? fill-chars)
120+
(ansi/apply-colours-and-attrs (:full-fg-colour style)
121+
(:full-bg-colour style)
122+
(:full-attrs style)
123+
(s/join (repeat fill-chars (pad-to-width (:full style) unit-width-cols)))))
105124
; Tip (optional)
106-
(when (:tip style)
125+
(when (and (:tip style) (pos? complete-chars))
107126
(ansi/apply-colours-and-attrs (:tip-fg-colour style)
108127
(:tip-bg-colour style)
109128
(:tip-attrs style)
110-
(:tip style)))
129+
(pad-to-width (:tip style) unit-width-cols)))
111130
; Empty
112-
(ansi/apply-colours-and-attrs (:empty-fg-colour style)
113-
(:empty-bg-colour style)
114-
(:empty-attrs style)
115-
(s/join (repeat empty-chars (:empty style))))
131+
(when (pos? empty-chars)
132+
(ansi/apply-colours-and-attrs (:empty-fg-colour style)
133+
(:empty-bg-colour style)
134+
(:empty-attrs style)
135+
(s/join (repeat empty-chars (pad-to-width (:empty style) unit-width-cols)))))
116136
; Right (optional)
117137
(when (:right style)
118138
(ansi/apply-colours-and-attrs (:right-fg-colour style)
@@ -205,23 +225,31 @@
205225
redraw-rate 10}}
206226
f]
207227
(when (and a f)
208-
(let [style-widths (merge {:empty (valid-width (:empty style))
209-
:full (valid-width (:full style))}
210-
(when-not (s/blank? label) {:label (inc (valid-width label))}) ; Include space delimiter
211-
(when (:left style) {:left (valid-width (:left style))})
212-
(when (:right style) {:right (valid-width (:right style))})
213-
(when (:tip style) {:tip (valid-width (:tip style))})
214-
(when-not (s/blank? units) {:units (inc (valid-width units))})) ; Include space delimiter
215-
render-fn! (partial redraw-progress-indicator! style style-widths label line width counter? total (count (str total)) units)
228+
(let [; We pre-compute a lot of stuff here, so that we're not doing it every pass through the rendering loop
229+
label-width (if-not (s/blank? label) (inc (valid-width label)) 0) ; Include space delimiter
230+
left-width (if-not (s/blank? (:left style)) (valid-width (:left style)) 0)
231+
full-width (valid-width (:full style))
232+
tip-width (if-not (s/blank? (:tip style)) (valid-width (:tip style)) 0)
233+
empty-width (valid-width (:empty style))
234+
right-width (if-not (s/blank? (:right style)) (valid-width (:right style)) 0)
235+
digits-in-total (count (str total))
236+
counter-width (if counter? (+ 2 (* 2 digits-in-total)) 0) ; Include space delimier, / delimiter, current value and total
237+
units-width (if (and counter? (not (s/blank? (:units style)))) (inc (valid-width (:units style))) 0) ; Include space delimiter
238+
body-width-cols (- width label-width left-width right-width counter-width units-width)
239+
unit-width-cols (max empty-width full-width tip-width)
240+
body-width-chars (round-down (/ body-width-cols unit-width-cols))
241+
242+
; Now setup the rendering function with all that pre-computed stuff baked in, and fire it off in a future that polls the atom
243+
render-fn! (partial redraw-progress-indicator! style unit-width-cols body-width-chars label line counter? total digits-in-total units)
216244
running-promise? (promise)
217-
poll-interval-ms (Math/round (double (/ 1000 redraw-rate)))
245+
poll-interval-ms (round (/ 1000 redraw-rate))
218246
fut (e/future* (poll-atom a running-promise? poll-interval-ms render-fn!))]
219247
(try
220248
(f)
221249
(finally
222250
; Teardown logic
223251
(deliver running-promise? false)
224-
(future-cancel fut) ; Just in case...
252+
@fut ; Ensures any exceptions are rethrown
225253
(locking lock ; Make sure this isn't re-entrant with the future, since the TTY can only save a single cursor position at a time
226254
(if preserve?
227255
; Make sure we draw the indicator with the final value of the atom

0 commit comments

Comments
 (0)