(ns joker.pprint
  "Pretty printing utilities. Based on Clojure implementation."
  {:added "1.0"})

(def ^:private osc8-seq-re
  #"\x1b\]8;[^\x07\x1b]*(\x07|\x1b\\)")

(defn- visible-width
  [s]
  (let [s (str s)]
    (if (re-find osc8-seq-re s)
      (- (count s)
         (apply +
                (map (fn [m]
                       (count (if (vector? m) (first m) m)))
                     (re-seq osc8-seq-re s))))
      (count s))))

(defn- pad-cell
  [width col]
  (let [s (str col)]
    (str (apply str (repeat (max 0 (- width (visible-width s))) " "))
         s)))

(defn print-table
  "Prints a collection of maps in a textual table. Prints table headings
   ks, and then a line of output for each row, corresponding to the keys
   in ks. If ks are not specified, use the keys of the first item in rows."
  {:added "1.0"}
  ([ks rows]
     (when (seq rows)
       (let [widths (map
                     (fn [k]
                       (apply max (visible-width (str k))
                              (map #(visible-width (str (get % k))) rows)))
                     ks)
             spacers (map #(apply str (repeat % "-")) widths)
             fmt-row (fn [leader divider trailer row]
                       (str leader
                            (apply str (interpose divider
                                                  (for [[col width] (map vector (map #(get row %) ks) widths)]
                                                    (pad-cell width col))))
                            trailer))]
         (println)
         (println (fmt-row "| " " | " " |" (zipmap ks ks)))
         (println (fmt-row "|-" "-+-" "-|" (zipmap ks spacers)))
         (doseq [row rows]
           (println (fmt-row "| " " | " " |" row))))))
  ([rows] (print-table (keys (first rows)) rows)))
