commit 6ae7a56e0f08ffd6e04a5312789e91ddb3059fc9 from: Sven M. Hallberg date: Sat Jul 5 20:48:03 2025 UTC add underline progress bar commit - e3f361530d5b3c16f397a90c6f03e76715955985 commit + 6ae7a56e0f08ffd6e04a5312789e91ddb3059fc9 blob - 13f6ba8319a779dea33ffc6865f0366a04382848 blob + a1f4b1c0cbcb37cca869106d9198736e47d3467c --- exercise +++ exercise @@ -110,11 +110,11 @@ proc execute_test {countervar path} { # Report test failures and errors to our stderr. if {$what ne "ok"} { - set foot "$what $path" + set foot [list "$what $path"] if {[isatty stderr]} { - set foot [color {33} $foot] ;# dark yellow + set foot [color 3 $foot] ;# dark yellow } - puts stderr $foot + puts stderr [join $foot ""] puts stderr "" } @@ -177,10 +177,58 @@ proc isatty {chan} { dict exists [fconfigure $chan] -mode } +# ANSI (ECMA-48) escape sequences +set esc(bu) [list "\033\[4m"] ;# begin underline +set esc(eu) [list "\033\[24m"] ;# end underline +set esc(ce) [list "\033\[0K"] ;# clear to end +set esc(endc) [list "\033\[39m"] ;# end color +set esc(endcb) [list "\033\[39;22m"] ;# end color and bold + proc color {c s} { - return "\033\[${c}m$s\033\[0m" + global esc + concat [list "\033\[3${c}m"] $s $esc(endc) } +proc boldc {c s} { + global esc + concat [list "\033\[1;3${c}m"] $s $esc(endcb) +} + +proc cinsert {line pos args} { + set cur 0 + set idx 0 + + foreach elem $line { + if {$cur == $pos} { + return [linsert $line $idx {*}$args] + } + if {[string index $elem 0] ne "\033"} { + set len [string length $elem] + + if {$pos < $cur + $len} { + set split [expr {$pos - $cur}] + set left [string range $elem 0 [expr {$split - 1}]] + set right [string range $elem $split end] + return [lreplace $line $idx $idx $left {*}$args $right] + } + + incr cur $len + } + incr idx + } + + # if we reach here, pos is beyond the end of line + lappend line [string repeat " " [expr {$pos - $cur}]] {*}$args +} + +proc clength {line} { + foreach elem $line { + if {[string index $elem 0] eq "\033"} continue + incr len [string length $elem] + } + return $len +} + proc inconsistent {counters} { dict with counters { expr {$run < $ok + $fail + $error} @@ -194,23 +242,36 @@ proc notok {counters} { } proc summary {counters} { + global esc + dict with counters { - set r "run $run" - set o "ok $ok" - set f "fail $fail" - set e "error $error" + set r [list "run $run"] + set o [list "ok $ok"] + set f [list "fail $fail"] + set e [list "error $error"] # color if {[isatty stdout]} { set good [expr {$ok>0 && ![notok $counters]}] - if {$run == 0} {set r [color {31} $r]} ;# dark red - if {$good} {set o [color {1;32} $o]} ;# bright green - if {$fail > 0} {set f [color {1;31} $f]} ;# bright red - if {$error > 0} {set e [color {31} $e]} ;# dark red + if {$run == 0} {set r [color 1 $r]} ;# dark red + if {$good} {set o [boldc 2 $o]} ;# bright green + if {$fail > 0} {set f [boldc 1 $f]} ;# bright red + if {$error > 0} {set e [color 1 $e]} ;# dark red } - return "$r $o $f $e" + set line [concat $r "{ }" $o "{ }" $f "{ }" $e] + + # progress bar, using underlining + if {[isatty stdout]} { + set ran [expr {$ok + $fail + $error}] + if {$run > 0 && $ran < $run} { + set pos [expr {[clength $line] * $ran / $run}] + set line [concat $esc(bu) [cinsert $line $pos {*}$esc(eu)]] + } + } + + return [join $line ""] } }