use math use re use str fn chars {|v| str:split '' $v } fn len {|v| chars $v | count } fn string {|v| var k = (kind-of $v) if (eq $k 'string') { put $v } elif (eq $k 'number') { to-string $v } elif (eq $k 'bool') { if $v { put 'X' } else { put '' } } elif (eq $k 'list') { each $string~ $v | str:join '' } elif (eq $v $nil) { put '' } else { to-string $v } } fn int {|v| var k = (kind-of $v) if (eq $k 'string') { try { var n = (math:trunc $v) var s @_ = (str:split '.' (to-string $n)) put $s } except e { fail (printf '%s n’est pas un nombre' $v) } } elif (eq $k 'number') { int (to-string $v) } elif (eq $k 'bool') { if $v { put 1 } else { put 0 } } elif (eq $v $nil) { put 0 } else { put 0 } } fn repeat {|n s| use builtin builtin:repeat $n $s | str:join '' } fn blank {|n| repeat $n ' ' } fn left {|str size| var l = (len $str) if (< $l $size) { string [ $str (blank (- $size $l)) ] } elif (== $l $size) { put $str } else { string [ (chars $str) ][..$size] } } fn right {|str size| var l = (len $str) if (< $l $size) { string [ (blank (- $size $l)) $str ] } elif (== $l $size) { put $str } else { string [ (chars $str) ][(- $l $size)..] } } fn center {|str size| var l = (len $str) if (< $l $size) { var d = (- $size $l) var b = (math:trunc (/ $d 2)) var e = (- $d $b) string [ (blank $b) $str (blank $e) ] } elif (== $l $size) { put $str } else { var d = (- $l $size) var b = (math:trunc (/ $d 2)) var e = (+ $b $size) string [ (chars $str) ][$b..$e] } } var -align = [ ¢er=$center~ &right=$right~ &left=$left~ ] fn column {|&align=left name @label| var c = [ &name=$name &align=$-align[$align] &size=0 &label='' ] if (> (count $label) 0) { set c[label] = $label[0] set c[size] = (count $label[0]) } put $c } fn update-props {|props data| each {|d| set @props = (each {|c| var n = $c[name] if (has-key $d $n) { var v = (string $d[$n]) var l = (count $v) if (< $c[size] $l) { set c[size] = $l } } put $c } $props) } $data put $props } fn line-header {|&sep=' ' props| var @data = (each {|c| $c[align] $c[label] $c[size] } $props) str:join $sep $data } fn line {|&sep=' ' props line| var @data = (each {|c| var n v = $c[name] '' if (has-key $line $n) { set v = (string $line[$n]) } $c[align] $v $c[size] } $props) str:join $sep $data } fn list {|&with-header=$true &csep=' ' &hsep='-' &recompute=$true props data| if $recompute { set props = (update-props $props $data) } if $with-header { echo (line-header &sep=$csep $props) if (bool $hsep) { var s = (* (- (count $props) 1) (count $csep)) each {|c| set s = (+ $s $c[size]) } $props echo (repeat (math:trunc (/ $s (count $hsep))) $hsep) } } each {|d| echo (line &sep=$csep $props $d) } $data }