annotate src/clojure/pprint/pretty_writer.clj @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
rlm@10 1 ;;; pretty_writer.clj -- part of the pretty printer for Clojure
rlm@10 2
rlm@10 3 ; Copyright (c) Rich Hickey. All rights reserved.
rlm@10 4 ; The use and distribution terms for this software are covered by the
rlm@10 5 ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
rlm@10 6 ; which can be found in the file epl-v10.html at the root of this distribution.
rlm@10 7 ; By using this software in any fashion, you are agreeing to be bound by
rlm@10 8 ; the terms of this license.
rlm@10 9 ; You must not remove this notice, or any other, from this software.
rlm@10 10
rlm@10 11 ;; Author: Tom Faulhaber
rlm@10 12 ;; April 3, 2009
rlm@10 13 ;; Revised to use proxy instead of gen-class April 2010
rlm@10 14
rlm@10 15 ;; This module implements a wrapper around a java.io.Writer which implements the
rlm@10 16 ;; core of the XP algorithm.
rlm@10 17
rlm@10 18 (in-ns 'clojure.pprint)
rlm@10 19
rlm@10 20 (import [clojure.lang IDeref]
rlm@10 21 [java.io Writer])
rlm@10 22
rlm@10 23 ;; TODO: Support for tab directives
rlm@10 24
rlm@10 25
rlm@10 26 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 27 ;;; Forward declarations
rlm@10 28 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 29
rlm@10 30 (declare get-miser-width)
rlm@10 31
rlm@10 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 33 ;;; Macros to simplify dealing with types and classes. These are
rlm@10 34 ;;; really utilities, but I'm experimenting with them here.
rlm@10 35 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 36
rlm@10 37 (defmacro ^{:private true}
rlm@10 38 getf
rlm@10 39 "Get the value of the field a named by the argument (which should be a keyword)."
rlm@10 40 [sym]
rlm@10 41 `(~sym @@~'this))
rlm@10 42
rlm@10 43 (defmacro ^{:private true}
rlm@10 44 setf [sym new-val]
rlm@10 45 "Set the value of the field SYM to NEW-VAL"
rlm@10 46 `(alter @~'this assoc ~sym ~new-val))
rlm@10 47
rlm@10 48 (defmacro ^{:private true}
rlm@10 49 deftype [type-name & fields]
rlm@10 50 (let [name-str (name type-name)]
rlm@10 51 `(do
rlm@10 52 (defstruct ~type-name :type-tag ~@fields)
rlm@10 53 (alter-meta! #'~type-name assoc :private true)
rlm@10 54 (defn- ~(symbol (str "make-" name-str))
rlm@10 55 [& vals#] (apply struct ~type-name ~(keyword name-str) vals#))
rlm@10 56 (defn- ~(symbol (str name-str "?")) [x#] (= (:type-tag x#) ~(keyword name-str))))))
rlm@10 57
rlm@10 58 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 59 ;;; The data structures used by pretty-writer
rlm@10 60 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 61
rlm@10 62 (defstruct ^{:private true} logical-block
rlm@10 63 :parent :section :start-col :indent
rlm@10 64 :done-nl :intra-block-nl
rlm@10 65 :prefix :per-line-prefix :suffix
rlm@10 66 :logical-block-callback)
rlm@10 67
rlm@10 68 (defn- ancestor? [parent child]
rlm@10 69 (loop [child (:parent child)]
rlm@10 70 (cond
rlm@10 71 (nil? child) false
rlm@10 72 (identical? parent child) true
rlm@10 73 :else (recur (:parent child)))))
rlm@10 74
rlm@10 75 (defstruct ^{:private true} section :parent)
rlm@10 76
rlm@10 77 (defn- buffer-length [l]
rlm@10 78 (let [l (seq l)]
rlm@10 79 (if l
rlm@10 80 (- (:end-pos (last l)) (:start-pos (first l)))
rlm@10 81 0)))
rlm@10 82
rlm@10 83 ; A blob of characters (aka a string)
rlm@10 84 (deftype buffer-blob :data :trailing-white-space :start-pos :end-pos)
rlm@10 85
rlm@10 86 ; A newline
rlm@10 87 (deftype nl-t :type :logical-block :start-pos :end-pos)
rlm@10 88
rlm@10 89 (deftype start-block-t :logical-block :start-pos :end-pos)
rlm@10 90
rlm@10 91 (deftype end-block-t :logical-block :start-pos :end-pos)
rlm@10 92
rlm@10 93 (deftype indent-t :logical-block :relative-to :offset :start-pos :end-pos)
rlm@10 94
rlm@10 95 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 96 ;;; Functions to write tokens in the output buffer
rlm@10 97 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 98
rlm@10 99 (declare emit-nl)
rlm@10 100
rlm@10 101 (defmulti ^{:private true} write-token #(:type-tag %2))
rlm@10 102 (defmethod write-token :start-block-t [^Writer this token]
rlm@10 103 (when-let [cb (getf :logical-block-callback)] (cb :start))
rlm@10 104 (let [lb (:logical-block token)]
rlm@10 105 (dosync
rlm@10 106 (when-let [^String prefix (:prefix lb)]
rlm@10 107 (.write (getf :base) prefix))
rlm@10 108 (let [col (get-column (getf :base))]
rlm@10 109 (ref-set (:start-col lb) col)
rlm@10 110 (ref-set (:indent lb) col)))))
rlm@10 111
rlm@10 112 (defmethod write-token :end-block-t [^Writer this token]
rlm@10 113 (when-let [cb (getf :logical-block-callback)] (cb :end))
rlm@10 114 (when-let [^String suffix (:suffix (:logical-block token))]
rlm@10 115 (.write (getf :base) suffix)))
rlm@10 116
rlm@10 117 (defmethod write-token :indent-t [^Writer this token]
rlm@10 118 (let [lb (:logical-block token)]
rlm@10 119 (ref-set (:indent lb)
rlm@10 120 (+ (:offset token)
rlm@10 121 (condp = (:relative-to token)
rlm@10 122 :block @(:start-col lb)
rlm@10 123 :current (get-column (getf :base)))))))
rlm@10 124
rlm@10 125 (defmethod write-token :buffer-blob [^Writer this token]
rlm@10 126 (.write (getf :base) ^String (:data token)))
rlm@10 127
rlm@10 128 (defmethod write-token :nl-t [^Writer this token]
rlm@10 129 ; (prlabel wt @(:done-nl (:logical-block token)))
rlm@10 130 ; (prlabel wt (:type token) (= (:type token) :mandatory))
rlm@10 131 (if (or (= (:type token) :mandatory)
rlm@10 132 (and (not (= (:type token) :fill))
rlm@10 133 @(:done-nl (:logical-block token))))
rlm@10 134 (emit-nl this token)
rlm@10 135 (if-let [^String tws (getf :trailing-white-space)]
rlm@10 136 (.write (getf :base) tws)))
rlm@10 137 (dosync (setf :trailing-white-space nil)))
rlm@10 138
rlm@10 139 (defn- write-tokens [^Writer this tokens force-trailing-whitespace]
rlm@10 140 (doseq [token tokens]
rlm@10 141 (if-not (= (:type-tag token) :nl-t)
rlm@10 142 (if-let [^String tws (getf :trailing-white-space)]
rlm@10 143 (.write (getf :base) tws)))
rlm@10 144 (write-token this token)
rlm@10 145 (setf :trailing-white-space (:trailing-white-space token)))
rlm@10 146 (let [^String tws (getf :trailing-white-space)]
rlm@10 147 (when (and force-trailing-whitespace tws)
rlm@10 148 (.write (getf :base) tws)
rlm@10 149 (setf :trailing-white-space nil))))
rlm@10 150
rlm@10 151 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 152 ;;; emit-nl? method defs for each type of new line. This makes
rlm@10 153 ;;; the decision about whether to print this type of new line.
rlm@10 154 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 155
rlm@10 156
rlm@10 157 (defn- tokens-fit? [^Writer this tokens]
rlm@10 158 ;;; (prlabel tf? (get-column (getf :base) (buffer-length tokens))
rlm@10 159 (let [maxcol (get-max-column (getf :base))]
rlm@10 160 (or
rlm@10 161 (nil? maxcol)
rlm@10 162 (< (+ (get-column (getf :base)) (buffer-length tokens)) maxcol))))
rlm@10 163
rlm@10 164 (defn- linear-nl? [this lb section]
rlm@10 165 ; (prlabel lnl? @(:done-nl lb) (tokens-fit? this section))
rlm@10 166 (or @(:done-nl lb)
rlm@10 167 (not (tokens-fit? this section))))
rlm@10 168
rlm@10 169 (defn- miser-nl? [^Writer this lb section]
rlm@10 170 (let [miser-width (get-miser-width this)
rlm@10 171 maxcol (get-max-column (getf :base))]
rlm@10 172 (and miser-width maxcol
rlm@10 173 (>= @(:start-col lb) (- maxcol miser-width))
rlm@10 174 (linear-nl? this lb section))))
rlm@10 175
rlm@10 176 (defmulti ^{:private true} emit-nl? (fn [t _ _ _] (:type t)))
rlm@10 177
rlm@10 178 (defmethod emit-nl? :linear [newl this section _]
rlm@10 179 (let [lb (:logical-block newl)]
rlm@10 180 (linear-nl? this lb section)))
rlm@10 181
rlm@10 182 (defmethod emit-nl? :miser [newl this section _]
rlm@10 183 (let [lb (:logical-block newl)]
rlm@10 184 (miser-nl? this lb section)))
rlm@10 185
rlm@10 186 (defmethod emit-nl? :fill [newl this section subsection]
rlm@10 187 (let [lb (:logical-block newl)]
rlm@10 188 (or @(:intra-block-nl lb)
rlm@10 189 (not (tokens-fit? this subsection))
rlm@10 190 (miser-nl? this lb section))))
rlm@10 191
rlm@10 192 (defmethod emit-nl? :mandatory [_ _ _ _]
rlm@10 193 true)
rlm@10 194
rlm@10 195 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 196 ;;; Various support functions
rlm@10 197 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 198
rlm@10 199
rlm@10 200 (defn- get-section [buffer]
rlm@10 201 (let [nl (first buffer)
rlm@10 202 lb (:logical-block nl)
rlm@10 203 section (seq (take-while #(not (and (nl-t? %) (ancestor? (:logical-block %) lb)))
rlm@10 204 (next buffer)))]
rlm@10 205 [section (seq (drop (inc (count section)) buffer))]))
rlm@10 206
rlm@10 207 (defn- get-sub-section [buffer]
rlm@10 208 (let [nl (first buffer)
rlm@10 209 lb (:logical-block nl)
rlm@10 210 section (seq (take-while #(let [nl-lb (:logical-block %)]
rlm@10 211 (not (and (nl-t? %) (or (= nl-lb lb) (ancestor? nl-lb lb)))))
rlm@10 212 (next buffer)))]
rlm@10 213 section))
rlm@10 214
rlm@10 215 (defn- update-nl-state [lb]
rlm@10 216 (dosync
rlm@10 217 (ref-set (:intra-block-nl lb) false)
rlm@10 218 (ref-set (:done-nl lb) true)
rlm@10 219 (loop [lb (:parent lb)]
rlm@10 220 (if lb
rlm@10 221 (do (ref-set (:done-nl lb) true)
rlm@10 222 (ref-set (:intra-block-nl lb) true)
rlm@10 223 (recur (:parent lb)))))))
rlm@10 224
rlm@10 225 (defn- emit-nl [^Writer this nl]
rlm@10 226 (.write (getf :base) (int \newline))
rlm@10 227 (dosync (setf :trailing-white-space nil))
rlm@10 228 (let [lb (:logical-block nl)
rlm@10 229 ^String prefix (:per-line-prefix lb)]
rlm@10 230 (if prefix
rlm@10 231 (.write (getf :base) prefix))
rlm@10 232 (let [^String istr (apply str (repeat (- @(:indent lb) (count prefix))
rlm@10 233 \space))]
rlm@10 234 (.write (getf :base) istr))
rlm@10 235 (update-nl-state lb)))
rlm@10 236
rlm@10 237 (defn- split-at-newline [tokens]
rlm@10 238 (let [pre (seq (take-while #(not (nl-t? %)) tokens))]
rlm@10 239 [pre (seq (drop (count pre) tokens))]))
rlm@10 240
rlm@10 241 ;;; Methods for showing token strings for debugging
rlm@10 242
rlm@10 243 (defmulti ^{:private true} tok :type-tag)
rlm@10 244 (defmethod tok :nl-t [token]
rlm@10 245 (:type token))
rlm@10 246 (defmethod tok :buffer-blob [token]
rlm@10 247 (str \" (:data token) (:trailing-white-space token) \"))
rlm@10 248 (defmethod tok :default [token]
rlm@10 249 (:type-tag token))
rlm@10 250 (defn- toks [toks] (map tok toks))
rlm@10 251
rlm@10 252 ;;; write-token-string is called when the set of tokens in the buffer
rlm@10 253 ;;; is longer than the available space on the line
rlm@10 254
rlm@10 255 (defn- write-token-string [this tokens]
rlm@10 256 (let [[a b] (split-at-newline tokens)]
rlm@10 257 ;; (prlabel wts (toks a) (toks b))
rlm@10 258 (if a (write-tokens this a false))
rlm@10 259 (if b
rlm@10 260 (let [[section remainder] (get-section b)
rlm@10 261 newl (first b)]
rlm@10 262 ;; (prlabel wts (toks section)) (prlabel wts (:type newl)) (prlabel wts (toks remainder))
rlm@10 263 (let [do-nl (emit-nl? newl this section (get-sub-section b))
rlm@10 264 result (if do-nl
rlm@10 265 (do
rlm@10 266 ;; (prlabel emit-nl (:type newl))
rlm@10 267 (emit-nl this newl)
rlm@10 268 (next b))
rlm@10 269 b)
rlm@10 270 long-section (not (tokens-fit? this result))
rlm@10 271 result (if long-section
rlm@10 272 (let [rem2 (write-token-string this section)]
rlm@10 273 ;;; (prlabel recurse (toks rem2))
rlm@10 274 (if (= rem2 section)
rlm@10 275 (do ; If that didn't produce any output, it has no nls
rlm@10 276 ; so we'll force it
rlm@10 277 (write-tokens this section false)
rlm@10 278 remainder)
rlm@10 279 (into [] (concat rem2 remainder))))
rlm@10 280 result)
rlm@10 281 ;; ff (prlabel wts (toks result))
rlm@10 282 ]
rlm@10 283 result)))))
rlm@10 284
rlm@10 285 (defn- write-line [^Writer this]
rlm@10 286 (dosync
rlm@10 287 (loop [buffer (getf :buffer)]
rlm@10 288 ;; (prlabel wl1 (toks buffer))
rlm@10 289 (setf :buffer (into [] buffer))
rlm@10 290 (if (not (tokens-fit? this buffer))
rlm@10 291 (let [new-buffer (write-token-string this buffer)]
rlm@10 292 ;; (prlabel wl new-buffer)
rlm@10 293 (if-not (identical? buffer new-buffer)
rlm@10 294 (recur new-buffer)))))))
rlm@10 295
rlm@10 296 ;;; Add a buffer token to the buffer and see if it's time to start
rlm@10 297 ;;; writing
rlm@10 298 (defn- add-to-buffer [^Writer this token]
rlm@10 299 ; (prlabel a2b token)
rlm@10 300 (dosync
rlm@10 301 (setf :buffer (conj (getf :buffer) token))
rlm@10 302 (if (not (tokens-fit? this (getf :buffer)))
rlm@10 303 (write-line this))))
rlm@10 304
rlm@10 305 ;;; Write all the tokens that have been buffered
rlm@10 306 (defn- write-buffered-output [^Writer this]
rlm@10 307 (write-line this)
rlm@10 308 (if-let [buf (getf :buffer)]
rlm@10 309 (do
rlm@10 310 (write-tokens this buf true)
rlm@10 311 (setf :buffer []))))
rlm@10 312
rlm@10 313 ;;; If there are newlines in the string, print the lines up until the last newline,
rlm@10 314 ;;; making the appropriate adjustments. Return the remainder of the string
rlm@10 315 (defn- write-initial-lines
rlm@10 316 [^Writer this ^String s]
rlm@10 317 (let [lines (.split s "\n" -1)]
rlm@10 318 (if (= (count lines) 1)
rlm@10 319 s
rlm@10 320 (dosync
rlm@10 321 (let [^String prefix (:per-line-prefix (first (getf :logical-blocks)))
rlm@10 322 ^String l (first lines)]
rlm@10 323 (if (= :buffering (getf :mode))
rlm@10 324 (let [oldpos (getf :pos)
rlm@10 325 newpos (+ oldpos (count l))]
rlm@10 326 (setf :pos newpos)
rlm@10 327 (add-to-buffer this (make-buffer-blob l nil oldpos newpos))
rlm@10 328 (write-buffered-output this))
rlm@10 329 (.write (getf :base) l))
rlm@10 330 (.write (getf :base) (int \newline))
rlm@10 331 (doseq [^String l (next (butlast lines))]
rlm@10 332 (.write (getf :base) l)
rlm@10 333 (.write (getf :base) (int \newline))
rlm@10 334 (if prefix
rlm@10 335 (.write (getf :base) prefix)))
rlm@10 336 (setf :buffering :writing)
rlm@10 337 (last lines))))))
rlm@10 338
rlm@10 339
rlm@10 340 (defn- write-white-space [^Writer this]
rlm@10 341 (if-let [^String tws (getf :trailing-white-space)]
rlm@10 342 (dosync
rlm@10 343 (.write (getf :base) tws)
rlm@10 344 (setf :trailing-white-space nil))))
rlm@10 345
rlm@10 346 (defn- p-write-char [^Writer this ^Integer c]
rlm@10 347 (if (= (getf :mode) :writing)
rlm@10 348 (do
rlm@10 349 (write-white-space this)
rlm@10 350 (.write (getf :base) c))
rlm@10 351 (if (= c \newline)
rlm@10 352 (write-initial-lines this "\n")
rlm@10 353 (let [oldpos (getf :pos)
rlm@10 354 newpos (inc oldpos)]
rlm@10 355 (dosync
rlm@10 356 (setf :pos newpos)
rlm@10 357 (add-to-buffer this (make-buffer-blob (str (char c)) nil oldpos newpos)))))))
rlm@10 358
rlm@10 359
rlm@10 360 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 361 ;;; Initialize the pretty-writer instance
rlm@10 362 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 363
rlm@10 364
rlm@10 365 (defn- pretty-writer [writer max-columns miser-width]
rlm@10 366 (let [lb (struct logical-block nil nil (ref 0) (ref 0) (ref false) (ref false))
rlm@10 367 fields (ref {:pretty-writer true
rlm@10 368 :base (column-writer writer max-columns)
rlm@10 369 :logical-blocks lb
rlm@10 370 :sections nil
rlm@10 371 :mode :writing
rlm@10 372 :buffer []
rlm@10 373 :buffer-block lb
rlm@10 374 :buffer-level 1
rlm@10 375 :miser-width miser-width
rlm@10 376 :trailing-white-space nil
rlm@10 377 :pos 0})]
rlm@10 378 (proxy [Writer IDeref] []
rlm@10 379 (deref [] fields)
rlm@10 380
rlm@10 381 (write
rlm@10 382 ([x]
rlm@10 383 ;; (prlabel write x (getf :mode))
rlm@10 384 (condp = (class x)
rlm@10 385 String
rlm@10 386 (let [^String s0 (write-initial-lines this x)
rlm@10 387 ^String s (.replaceFirst s0 "\\s+$" "")
rlm@10 388 white-space (.substring s0 (count s))
rlm@10 389 mode (getf :mode)]
rlm@10 390 (dosync
rlm@10 391 (if (= mode :writing)
rlm@10 392 (do
rlm@10 393 (write-white-space this)
rlm@10 394 (.write (getf :base) s)
rlm@10 395 (setf :trailing-white-space white-space))
rlm@10 396 (let [oldpos (getf :pos)
rlm@10 397 newpos (+ oldpos (count s0))]
rlm@10 398 (setf :pos newpos)
rlm@10 399 (add-to-buffer this (make-buffer-blob s white-space oldpos newpos))))))
rlm@10 400
rlm@10 401 Integer
rlm@10 402 (p-write-char this x))))
rlm@10 403
rlm@10 404 (flush []
rlm@10 405 (if (= (getf :mode) :buffering)
rlm@10 406 (dosync
rlm@10 407 (write-tokens this (getf :buffer) true)
rlm@10 408 (setf :buffer []))
rlm@10 409 (write-white-space this)))
rlm@10 410
rlm@10 411 (close []
rlm@10 412 (.flush this)))))
rlm@10 413
rlm@10 414
rlm@10 415 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 416 ;;; Methods for pretty-writer
rlm@10 417 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 418
rlm@10 419 (defn- start-block
rlm@10 420 [^Writer this
rlm@10 421 ^String prefix ^String per-line-prefix ^String suffix]
rlm@10 422 (dosync
rlm@10 423 (let [lb (struct logical-block (getf :logical-blocks) nil (ref 0) (ref 0)
rlm@10 424 (ref false) (ref false)
rlm@10 425 prefix per-line-prefix suffix)]
rlm@10 426 (setf :logical-blocks lb)
rlm@10 427 (if (= (getf :mode) :writing)
rlm@10 428 (do
rlm@10 429 (write-white-space this)
rlm@10 430 (when-let [cb (getf :logical-block-callback)] (cb :start))
rlm@10 431 (if prefix
rlm@10 432 (.write (getf :base) prefix))
rlm@10 433 (let [col (get-column (getf :base))]
rlm@10 434 (ref-set (:start-col lb) col)
rlm@10 435 (ref-set (:indent lb) col)))
rlm@10 436 (let [oldpos (getf :pos)
rlm@10 437 newpos (+ oldpos (if prefix (count prefix) 0))]
rlm@10 438 (setf :pos newpos)
rlm@10 439 (add-to-buffer this (make-start-block-t lb oldpos newpos)))))))
rlm@10 440
rlm@10 441 (defn- end-block [^Writer this]
rlm@10 442 (dosync
rlm@10 443 (let [lb (getf :logical-blocks)
rlm@10 444 ^String suffix (:suffix lb)]
rlm@10 445 (if (= (getf :mode) :writing)
rlm@10 446 (do
rlm@10 447 (write-white-space this)
rlm@10 448 (if suffix
rlm@10 449 (.write (getf :base) suffix))
rlm@10 450 (when-let [cb (getf :logical-block-callback)] (cb :end)))
rlm@10 451 (let [oldpos (getf :pos)
rlm@10 452 newpos (+ oldpos (if suffix (count suffix) 0))]
rlm@10 453 (setf :pos newpos)
rlm@10 454 (add-to-buffer this (make-end-block-t lb oldpos newpos))))
rlm@10 455 (setf :logical-blocks (:parent lb)))))
rlm@10 456
rlm@10 457 (defn- nl [^Writer this type]
rlm@10 458 (dosync
rlm@10 459 (setf :mode :buffering)
rlm@10 460 (let [pos (getf :pos)]
rlm@10 461 (add-to-buffer this (make-nl-t type (getf :logical-blocks) pos pos)))))
rlm@10 462
rlm@10 463 (defn- indent [^Writer this relative-to offset]
rlm@10 464 (dosync
rlm@10 465 (let [lb (getf :logical-blocks)]
rlm@10 466 (if (= (getf :mode) :writing)
rlm@10 467 (do
rlm@10 468 (write-white-space this)
rlm@10 469 (ref-set (:indent lb)
rlm@10 470 (+ offset (condp = relative-to
rlm@10 471 :block @(:start-col lb)
rlm@10 472 :current (get-column (getf :base))))))
rlm@10 473 (let [pos (getf :pos)]
rlm@10 474 (add-to-buffer this (make-indent-t lb relative-to offset pos pos)))))))
rlm@10 475
rlm@10 476 (defn- get-miser-width [^Writer this]
rlm@10 477 (getf :miser-width))
rlm@10 478
rlm@10 479 (defn- set-miser-width [^Writer this new-miser-width]
rlm@10 480 (dosync (setf :miser-width new-miser-width)))
rlm@10 481
rlm@10 482 (defn- set-logical-block-callback [^Writer this f]
rlm@10 483 (dosync (setf :logical-block-callback f)))