C2H Command Line Utility
Now updated to work with Clojure 1.2!!!
If you want to post Clojure code on the web, the first question you are going
to ask yourself is, how do I make this look pretty in html? Your answer is c2h!
This little app converts your properly formated Clojure file into an HTML page. (Mostly, ...
there are a few minor bugs still. Feel free to send me fixes for those ;-)
Here is my contribution based heavily off René Ghosh's code. René did all the
hard work. I added comment coloring, rainbow parens, and a few other bits.
The c2h tool assumes a *nix environment, and that you have configured your system
to run Clojure scripts from the terminal with the command clj. Install it as you would any
other tool.
You may download c2h from here, or copy it from below.
#!/usr/bin/env clj
(ns html-outputter)
;; Based off code from René Ghosh at: ;; http://sardakcode.blogspot.com/2009/02/litterate-programming-in-clojure.html
;; Additional code by T. Gene Davis ;; http://t.genedavis.com
;; I'm new to LISP, Clojure and functional thought, so this is pretty messy. However, ;; it works for creating pretty HTML from clojure code. It even provides rainbow parens! ;; This code is provided "AS IS".
;; obtaining input and output file names if they exist (def input-file) (def output-file)
(defn usage[] (println "usage: html-transform <input clojure file> <output-html-file>") (System/exit -1))
;; -? --help and other arguments trigger this (if (<= (count *command-line-args*) 1) (usage))
;; obtaining input and output file names if they exist (if (= (count *command-line-args*) 2) (do (def input-file (nth *command-line-args* 0)) (def output-file (nth *command-line-args* 1))))
(def input (java.io.InputStreamReader. (java.io.FileInputStream. input-file)))
(def rainbow-depth 0)
(def reserved #{ "def" "defn" "defmacro" "let" "letrec" "if" "cond" "when" "do" "recur" "loop" "ns" "import" "." ".." }) (def definitions #{"def" "defn" "defmacro"}) (def punc #{"(" ")" "[" "]" "`" "'" "&" "{" "}"}) (def punc-parens #{"(" ")"})
(defn htmlize[st] "replace certain characters in a string with their html equivalents to render it html-ready" (.replaceAll (.replaceAll (.replaceAll st "&" "&") ">" ">") "<" "<"))
(defn text[st] "convert a string into another string representing a list of html paragraphs" (let [paraphed (reverse (loop [lines (.split st "n") buffer "" result nil] (let [line (first lines)] (if line (let [line (.trim line)] (if (= line "") (if (= buffer "") (recur (rest lines) "" result) (recur (rest lines) "" (cons buffer result))) (recur (rest lines) (.trim (str buffer " " line)) result))) (if (= buffer "") result (cons buffer result))))))] (reduce (fn[a b](str a b)) (map (fn[a](str "<p>" a "</p>")) paraphed))))
; font colors
(def string-color "#AA7777") (def keyword-color "#458") (def splice-color "#485") (def reserved-word-color "#BB44BB;font-weight:bold") (def punctuation-color "#600;font-weight:bold") ; curely braces and square brackets (def definition-color "#08d") (def symbol-color "#444") (def comment-color "#a33") (def rainbow-paren-color [ "#f00" "#00f" "#f90" "#a8522d" "#0f0" "#a05270" "#aa8e23" ])
(defn color[st previous] (cond (= "" (.trim st)) "" (.startsWith st """) (str "<font style="color: " string-color "">" (htmlize st) "</font>") (.startsWith st ";") (str "<font style="color: " comment-color "">" (htmlize st) "</font>") (.startsWith st ":") (str "<font style="color: " keyword-color "">" (htmlize st) "</font>") (.startsWith st "~") (str "<font style="color: " splice-color "">" (htmlize st) "</font>") (contains? reserved (. st trim)) (str "<font style="color: " reserved-word-color "">" (htmlize st) "</font>") (contains? punc (. st trim)) (if (contains? punc-parens (. st trim)) (str "<font style="color: " (rainbow-paren-color (rem rainbow-depth (count rainbow-paren-color))) "">" (htmlize st) "</font>") (str "<font style="color: " punctuation-color "">" (htmlize st) "</font>")) :default (if (contains? definitions previous) (str "<font style="font-weight: bold;color: " definition-color "">" (htmlize st) "</font>") (str "<font style="color: " symbol-color "">" (htmlize st) "</font>"))))
(defn process-code [] (loop [buffer "" state :symbol word "" previous-word "" level 0] (let [ next-char-read (int (.read input)) next-char (str "" (if (not (= next-char-read (int -1))) (char next-char-read) ""))] (if (= next-char-read (int -1)) buffer ( cond (= :escaping state) (recur buffer :string (str word next-char) "" level) (= :string state) (cond (= next-char "\") (recur buffer :escaping word "" level) (= next-char """) (if (= 0 level) (recur (text (str buffer word)) :symbol "" "" level) (recur (str buffer (color (str """ word """) "")) :symbol "" "" level)) :default (recur buffer state (str word next-char) "" level)) (= :comment state) (cond (= next-char "n") (recur (str buffer (color word previous-word) "<br/>") :symbol "" word level) :default (recur buffer state (str word next-char) "" level)) (= :symbol state) (cond (= next-char """) (recur (str buffer (color word previous-word)) :string "" word level) (= next-char "n") (recur (str buffer (color word previous-word) "<br/>") state "" word level) (= next-char " ") (recur (str buffer (color word previous-word) " ") state "" word level) (= next-char ";") (recur (str buffer (color word previous-word)) :comment ";" word level) (or (= next-char "[") (= next-char "{") (= next-char "(")) (let [word-color (str (color word previous-word) (color next-char ""))] (if (= next-char "(") (def rainbow-depth (inc rainbow-depth))) (recur (str buffer word-color) state "" word (inc level))) (or (= next-char "]") (= next-char ")") (= next-char "}") ) (do (if (= next-char ")") (def rainbow-depth (dec rainbow-depth))) (recur (str buffer (color word previous-word)(color next-char "")) state "" word (dec level))) (= next-char "t") (recur (str buffer " " (color word previous-word)) state "" word level) :default (recur buffer state (str word next-char) previous-word level)))))))
(let [out (java.io.PrintStream. (java.io.FileOutputStream. output-file))]
(. out println
(str "<html> n" "<head>" "</head> n" "<body>nnn<code>"
(process-code) "</code>nnn</body> </html>")))
|