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