(defstruct tag :opening :closing)
(def *ansi-html-mapping*
{ 1 (struct tag "<b>" "</b>")
4 (struct tag "<u>" "</u>")
5 (struct tag "<blink>" "</blink>")
7 (struct tag "<i>" "</i>")
30 (struct tag "<font color=black>" "</font>")
31 (struct tag "<font color=red>" "</font>")
32 (struct tag "<font color=green>" "</font>")
33 (struct tag "<font color=yellow>" "</font>")
34 (struct tag "<font color=blue>" "</font>")
35 (struct tag "<font color=purple>" "</font>")
36 (struct tag "<font color=cyan>" "</font>")
37 (struct tag "<font color=white>" "</font>") })
(def *closing-tags* (atom (list)))
(defn ansi-code-to-tag
[code]
(if (zero? code)
(let [tags (str* @*closing-tags*)]
(reset! *closing-tags* (list))
tags)
(let [{:keys [opening closing]} (*ansi-html-mapping* code)]
(swap! *closing-tags* conj closing)
opening
)))
(defn ansi-to-html
[string]
(if (re-find #"\[\d*m" string)
(let [[_ pre code post]
(re-matches #"(.*)\[(\d*)m(.*)" string)]
(recur (str pre
(ansi-code-to-tag (try
(Integer/parseInt code)
(catch NumberFormatException e
0)))
post)))
string))
(ns dhl.midas.colors
(use (clojure.contrib str-utils))
)
(defmacro aif
[test then-form else-form]
`(let [~'it ~test]
(if ~'it
~then-form
~else-form)))
(defn str* [s]
(apply str s))
(defstruct tag :opening :closing)
(def *ansi-html-mapping*
{ 1 (struct tag "<b>" "</b>")
4 (struct tag "<u>" "</u>")
5 (struct tag "<blink>" "</blink>")
7 (struct tag "<i>" "</i>")
30 (struct tag "<font color=black>" "</font>")
31 (struct tag "<font color=red>" "</font>")
32 (struct tag "<font color=green>" "</font>")
33 (struct tag "<font color=yellow>" "</font>")
34 (struct tag "<font color=blue>" "</font>")
35 (struct tag "<font color=purple>" "</font>")
36 (struct tag "<font color=cyan>" "</font>")
37 (struct tag "<font color=white>" "</font>") })
(def *closing-tags* (atom (list)))
(defn ansi-code-to-tag
[code]
(if (zero? code)
(let [tags (str* @*closing-tags*)]
(reset! *closing-tags* (list))
tags)
(let [{:keys [opening closing]} (*ansi-html-mapping* code)]
(swap! *closing-tags* conj closing)
opening
)))
(defn extract-ansi-code
[ansi-sequence]
(let [[_ code] (re-matches #"\[(\d*)m" ansi-sequence)]
(try
(Integer/parseInt code)
(catch NumberFormatException e
0))))
(defn ansi-to-html
[string]
(str* (let [chunks (re-partition #"\[\d*m" string)]
(mapcat (fn [[text ansi-sequence]]
[text (aif ansi-sequence
(ansi-code-to-tag (extract-ansi-code it))
"")])
(partition 2 2 [nil] chunks)))))
(defmacro aif
[test then-form else-form]
`(let [~'it ~test]
(if ~'it
~then-form
~else-form)))
(defn str* [s]
(apply str s))
(defstruct tag :opening :closing)
(def *ansi-html-mapping*
{ 1 (struct tag "<b>" "</b>")
4 (struct tag "<u>" "</u>")
5 (struct tag "<blink>" "</blink>")
7 (struct tag "<i>" "</i>")
30 (struct tag "<font color=black>" "</font>")
31 (struct tag "<font color=red>" "</font>")
32 (struct tag "<font color=green>" "</font>")
33 (struct tag "<font color=yellow>" "</font>")
34 (struct tag "<font color=blue>" "</font>")
35 (struct tag "<font color=purple>" "</font>")
36 (struct tag "<font color=cyan>" "</font>")
37 (struct tag "<font color=white>" "</font>") })
(defn extract-ansi-code
[ansi-sequence]
(let [[_ code] (re-matches #"\[(\d*)m" ansi-sequence)]
(try
(Integer/parseInt code)
(catch NumberFormatException e
0))))
(defn ansi-code-to-tag
[[text-acc closing-tags] code]
(if (zero? code)
[[(str* (concat text-acc closing-tags))] '()]
(let [{:keys [opening closing]} (*ansi-html-mapping* code)]
[(conj text-acc opening) (conj closing-tags closing)])))
(defn ansi-to-html
[string]
(let [[html-chunks leftovers]
(let [chunks (re-partition #"\[\d*m" string)]
(reduce (fn [[text-acc closing-tags] [text-chunk ansi-sequence]]
(let [acc [(conj text-acc text-chunk) closing-tags]]
(aif ansi-sequence
(ansi-code-to-tag acc (extract-ansi-code it))
acc)))
[[] '()] (partition 2 2 [nil] chunks)))]
(str* (concat html-chunks leftovers))))(defn str* [s]
(apply str s))
(defstruct tag :opening :closing)
(def *ansi-html-mapping*
{ 1 (struct tag "<b>" "</b>")
4 (struct tag "<u>" "</u>")
5 (struct tag "<blink>" "</blink>")
7 (struct tag "<i>" "</i>")
30 (struct tag "<font color=black>" "</font>")
31 (struct tag "<font color=red>" "</font>")
32 (struct tag "<font color=green>" "</font>")
33 (struct tag "<font color=yellow>" "</font>")
34 (struct tag "<font color=blue>" "</font>")
35 (struct tag "<font color=purple>" "</font>")
36 (struct tag "<font color=cyan>" "</font>")
37 (struct tag "<font color=white>" "</font>") })
(defn extract-ansi-code
[ansi-sequence]
(let [[_ code] (re-matches #"\[(\d*)m" ansi-sequence)]
(try
(Integer/parseInt code)
(catch NumberFormatException e
0))))
(defn transform-ansi-code
[[text-acc closing-tags] code]
(if (zero? code)
[[(str* (concat text-acc closing-tags))] '()]
(let [{:keys [opening closing]} (*ansi-html-mapping* code)]
[(conj text-acc opening) (conj closing-tags closing)])))
(defn process-partitions
[[text-acc closing-tags] [text-chunk ansi-sequence]]
(let [acc [(conj text-acc text-chunk) closing-tags]]
(if-let [it ansi-sequence]
(transform-ansi-code acc (extract-ansi-code it))
acc)))
(defn chunk-string
([string] (chunk-string string [[] '()]))
([string acc]
(let [chunks (re-partition #"\[\d*m" string)]
(reduce process-partitions
acc
(partition 2 2 [nil] chunks)))))
(defn ansi-to-html [string]
(str* (apply concat (chunk-string string))))