49 lines
1.8 KiB
Common Lisp
49 lines
1.8 KiB
Common Lisp
(defun nonempty (seq)
|
|
(position-if (lambda (x) (declare (ignore x)) t) seq))
|
|
|
|
(defun split (delim seq)
|
|
"Splits seq on delim into a list of subsequences. Trailing empty
|
|
subsequences are removed."
|
|
(labels
|
|
((f (seq &aux (pos (position delim seq)))
|
|
(if pos
|
|
(cons
|
|
(subseq seq 0 pos)
|
|
(f (subseq seq (1+ pos))))
|
|
(list seq))))
|
|
(let* ((list (f seq))
|
|
(end (position-if #'nonempty list :from-end t)))
|
|
(subseq list 0 (1+ end)))))
|
|
|
|
(defun lengthen (list minlen filler-elem &aux (len (length list)))
|
|
"Destructively pads list with filler-elem up to minlen."
|
|
(if (< len minlen)
|
|
(nconc list (make-list (- minlen len) :initial-element filler-elem))
|
|
list))
|
|
|
|
(defun align-columns (text
|
|
&key (align :left)
|
|
&aux
|
|
(fmtmod (case align
|
|
(:left "@")
|
|
(:right ":")
|
|
(:center "@:")
|
|
(t (error "Invalid alignment."))))
|
|
(fields (mapcar (lambda (line) (split #\$ line))
|
|
(split #\Newline text)))
|
|
(mostcols (loop for l in fields
|
|
maximize (length l)))
|
|
widest)
|
|
(setf fields (mapcar (lambda (l) (lengthen l mostcols ""))
|
|
fields))
|
|
(setf widest (loop for col below (length (first fields))
|
|
collect (loop for row in fields
|
|
maximize (length (elt row col)))))
|
|
(format nil
|
|
(with-output-to-string (s)
|
|
(princ "~{~{" s)
|
|
(dolist (w widest)
|
|
(format s "~~~d~a<~~a~~>" (1+ w) fmtmod))
|
|
(princ "~}~%~}" s))
|
|
fields))
|