plumbing.lisp 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. ;;; TABLE PRINTING
  2. ;;; Taken from: https://gist.github.com/WetHat/a49e6f2140b401a190d45d31e052af8f
  3. ;;; Used for pretty printing output
  4. (defvar +CELL-FORMATS+ '(:left "~vA"
  5. :center "~v:@<~A~>"
  6. :right "~v@A"))
  7. (defun format-table (stream data &key (column-label (loop for i from 1 to (length (car data))
  8. collect (format nil "COL~D" i)))
  9. (column-align (loop for i from 1 to (length (car data))
  10. collect :left)))
  11. (let* ((col-count (length column-label))
  12. (strtable (cons column-label ; table header
  13. (loop for row in data ; table body with all cells as strings
  14. collect (loop for cell in row
  15. collect (if (stringp cell)
  16. cell
  17. ;else
  18. (format nil "~A" cell))))))
  19. (col-widths (loop with widths = (make-array col-count :initial-element 0)
  20. for row in strtable
  21. do (loop for cell in row
  22. for i from 0
  23. do (setf (aref widths i)
  24. (max (aref widths i) (length cell))))
  25. finally (return widths))))
  26. ;------------------------------------------------------------------------------------
  27. ; splice in the header separator
  28. (setq strtable
  29. (nconc (list (car strtable) ; table header
  30. (loop for align in column-align ; generate separator
  31. for width across col-widths
  32. collect (case align
  33. (:left (format nil ":~v@{~A~:*~}"
  34. (1- width) "-"))
  35. (:right (format nil "~v@{~A~:*~}:"
  36. (1- width) "-"))
  37. (:center (format nil ":~v@{~A~:*~}:"
  38. (- width 2) "-")))))
  39. (cdr strtable))) ; table body
  40. ;------------------------------------------------------------------------------------
  41. ; Generate the formatted table
  42. (let ((row-fmt (format nil "| ~{~A~^ | ~} |~~%" ; compile the row format
  43. (loop for align in column-align
  44. collect (getf +CELL-FORMATS+ align))))
  45. (widths (loop for w across col-widths collect w)))
  46. ; write each line to the given stream
  47. (dolist (row strtable)
  48. (apply #'format stream row-fmt (mapcan #'list widths row))))))
  49. ;; https://stackoverflow.com/questions/4882361/which-command-could-be-used-to-clear-screen-in-clisp
  50. (defun cls()
  51. (format t "~A[H~@*~A[J" #\escape))
  52. (defun prompt-read (prompt)
  53. (format *query-io* "~a" prompt)
  54. (force-output *query-io*)
  55. (read-line *query-io*))
  56. (defun handle-opt (opt lookup-table)
  57. "When given a string and a list 'lookup table' call the
  58. function associated with the opt used"
  59. (let ((handler (cdr (assoc opt lookup-table))))
  60. (if handler (funcall handler) (format t "Invalid opt~%~%"))))
  61. (defun return-slots (obj)
  62. "Given an object, return the names of it's slots"
  63. (map 'list #'closer-mop:slot-definition-name (closer-mop:class-slots (class-of obj))))
  64. (defun simple-print-object (obj)
  65. "Given an object, print it's slots and slot values"
  66. (loop for slot in (return-slots obj)
  67. do (format T "Slot: ~A Value: ~A~%"
  68. slot
  69. (slot-value obj slot))))
  70. (defun make-name (name-prefixes name-values)
  71. "Expects a list of strings to use as prefixes for a name, and a list
  72. of possible names"
  73. (let ((name (nth (random (length name-values)) name-values))
  74. (prefix (nth (random (length name-prefixes)) name-prefixes)))
  75. (concatenate 'string prefix " " name)))