The following, which I relinquish into the public domain and certify is
original to me, takes a string and reformats it as Clojure code, returning a
string. It behaves similarly to the Enclojure reformatter, but:
1. Outside string literals and comments, it will take care of all
spacing.
2. Comments get one space before and one after the ; before the
comment text. If the comment text originally started with a space
none is inserted after the ;.
3. If two comments are on successive lines and the second can be
aligned with the first by inserting additional spaces before the
;, the comments are aligned in this manner; exception to item 2.
4. Delimiters in character literals (e.g. \{) don't screw up
the indenting of susbequent lines.
Note that this doesn't use the reader, which at first blush would seem to
make things simpler. But using the reader would clobber comments, expand #()
and the like, and fail if the input contained unbalanced delimiters. The
below code appears to indent the same as Enclojure in the face of unbalanced
delimiters.
As a little demonstration, the code below appears as formatted by itself:
(defn format-code [string]
(loop [s string col 0 dstack [] out [] space nil incl false
insl false incm false lwcr false sups true cmindent nil]
(if-let [c (first s)] ; test comment 1 { ; )
(let [r (rest s) ; test comment 2 ( [
begins "([{"
ends ")]}" ; test comment 3 " ;
delim-indents (zipmap begins [1 0 0]) ; test comment 4
delim-ends (zipmap ends begins)
sups-char? #{\' \` \~ \@ \#} ; characters to suppress
indent (fn [] ; spaces after
(if (or (empty? r) (empty? dstack))
[\newline]
(into [\newline]
(repeat
(let [[delim pos] (peek dstack)]
(+ pos (delim-indents delim)))
\space))))
conc (fn [c]
(if sups [c] (conj space c)))
pop-d (fn [stack c]
(if (empty? stack)
[]
(let [ps (pop stack)]
(if (empty? ps)
[]
(if (= (first (peek stack)) (delim-ends c))
ps
(recur ps c))))))]
(cond
incm (let [nl (or (= c \newline) (= c \return))
spc (Character/isWhitespace c)
cc (if nl
(indent)
(if spc
(if-not sups [c])
[c]))]
(recur
r (if nl (dec (count cc)) (+ col (count cc)))
dstack (into out cc) nil false false
(if-not nl incm) (= c \return) nl cmindent))
(= c \") (let [cc (if (or incl insl) [c] [\space c])]
(recur
r (+ col (count cc)) dstack (into out cc)
(if (and insl (not incl)) [\space]) false
(if incl insl (not insl)) false false false
cmindent))
(or incl insl) (recur
r (if (or (= c \newline) (= c \return))
0
(inc col))
dstack (conj out c) nil
(and insl (not incl) (= c \\)) insl false
false false cmindent)
(= c \;) (let [padding (if sups 0 1)
padding (if cmindent
(max padding (- cmindent col))
padding)
padding (repeat padding \space)
padding (concat padding [\; \space])]
(recur
r (+ col (count padding)) dstack
(into out padding) nil false false true false
true (+ col (count padding) -2)))
(= c \\) (let [cc (if sups [c] [\space c])]
(recur
r (+ col (count cc)) dstack (into out cc) nil
true false false false false cmindent))
(or
(and (= c \newline) (not lwcr))
(= c \return)) (let [i (indent)]
(recur
r (dec (count i)) dstack (into out i)
nil false false false (= c \return)
true nil))
(= c \newline) (recur
r col dstack out nil false false false
false true cmindent)
(Character/isWhitespace c) (recur
r col dstack out [\space]
false false false false sups
cmindent)
(delim-indents c) (let [cc (if sups [c] [\space c])
cn (count cc)]
(recur
r (+ col cn)
(conj dstack [c (+ col cn)])
(into out cc) nil false false false
false true cmindent))
(delim-ends c) (recur
r (inc col) (pop-d dstack c) (conj out c)
[\space] false false false false false
cmindent)
:else (let [cc (conc c)]
(recur
r (+ col (count cc)) dstack (into out cc) nil
false false false false (sups-char? c)
cmindent))))
(apply str out))))
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---