-
Notifications
You must be signed in to change notification settings - Fork 1
/
fmt-table.scm
90 lines (72 loc) · 3.26 KB
/
fmt-table.scm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
(module fmt-table
(fmt-table)
(import scheme (chicken base) (chicken string) (chicken format)
srfi-1 utf8 utf8-lolevel
fmt yasos yasos-collections)
;; See
;; https://en.wikipedia.org/wiki/Box-drawing_character
;; http://www.utf8-chartable.de/unicode-utf8-table.pl?start=9472&unicodeinhtml=dec
(define table-borders-dict
'((space . (#\space (" " " " " ") (" " " " " ") (" " " " " ") (" " " " " ")))
(space-single . (#\x2500 ("│" " " "│") ("┌" "─" "┐") ("├" "─" "┤") ("└" "─" "┘")))
(single . (#\x2500 ("│" "│" "│") ("┌" "┬" "┐") ("├" "┼" "┤") ("└" "┴" "┘")))
(rounded . (#\x2500 ("│" "│" "│") ("╭" "┬" "╮") ("├" "┼" "┤") ("╰" "┴" "╯")))
(double . (#\═ ("║" "║" "║") ("╔" "╦" "╗") ("╠" "╬" "╣") ("╚" "╩" "╝")))))
(define (fmt-table labels cols #!key
(formatter ->string)
(border-style 'single)
(port #f)
(framed? #t)
(row-sep? #t)
(align 'left))
(let* ([lens (map size cols)]
[len1 (first lens)])
(if (not (every (lambda (len)(= len len1)) (cdr lens)))
(error 'fmt-table "All columns must have the same length")))
(let
((cell-sizes
(map max
(map (lambda (col)
(reduce (lambda (x ax) (max (string-length (->string x)) ax)) 0 col))
cols)
(map (lambda (label) (string-length (->string label)))
labels)))
(style (alist-ref border-style table-borders-dict)))
(if (and (list? align)
(not (= (length align) (length cols))))
(error "align does not have the same number of elements of the number of columns in the table"))
(define-values (row-sep col-seps first-row-corners mid-row-corners last-row-corners)
(apply values style))
(define align-list
(if (symbol? align)
(list-tabulate (length cell-sizes) (lambda (i) align))
align))
(define (make-row-line row-corners)
(let ((s (fmt-join
(lambda (n) (dsp (make-utf8-string n row-sep)))
cell-sizes
(second row-corners))))
(if framed? (cat (first row-corners) s (third row-corners))
s)))
(define (fmt-row row-data)
(let ((s (fmt-join
(lambda (elem)
(let-values (((item size al) (apply values elem)))
(let ((str (formatter item)))
(case al
((right) (pad/left size str))
((left) (pad size str))
(else (pad/both size str))))))
(zip row-data cell-sizes align-list)
(second col-seps))))
(if framed? (cat (first col-seps) s (third col-seps)) s)))
(let* ((rows-str (fmt-join fmt-row (generator->list (apply g-zip (map gen-elts cols))) "\n"))
(labels-str (fmt-row labels)))
(fmt port (cat (make-row-line first-row-corners) "\n"
labels-str "\n"
(make-row-line mid-row-corners) "\n"
rows-str "\n"
(make-row-line last-row-corners) "\n"))
))
)
)