|
15 | 15 |
|
16 | 16 | ;; TODO: |
17 | 17 | ;; - miser and fill newlines |
18 | | -;; - indent controls |
19 | 18 |
|
20 | 19 | (declare simple-dispatch code-dispatch write-out) |
21 | 20 |
|
|
127 | 126 | ;; Types ;; |
128 | 127 | ;;;;;;;;;;; |
129 | 128 |
|
130 | | -(deftype LogicalBlock [parent prefix per-line-prefix suffix ^:mutable indent ^:mutable force-nl?] |
| 129 | +;; `indent` may be changed later by an indent token, whereas `start-col` is fixed at |
| 130 | +;; the point the start block token is encountered in the stream. |
| 131 | +(deftype LogicalBlock [parent prefix per-line-prefix suffix ^:mutable indent ^:mutable start-col ^:mutable force-nl?] |
131 | 132 | (__repr__ [self] |
132 | 133 | (str [(python/id self) (python/repr parent) prefix suffix indent force-nl?]))) |
133 | 134 |
|
|
143 | 144 | (__repr__ [self] |
144 | 145 | data)) |
145 | 146 |
|
146 | | -(deftype Indent [block relative-to offset start end]) |
| 147 | +(deftype Indent [block relative-to offset start end] |
| 148 | + (__repr__ [self] |
| 149 | + (str [(python/id block) relative-to offset]))) |
147 | 150 |
|
148 | 151 | (deftype Newline [block kind start end] |
149 | 152 | (__repr__ [self] |
|
217 | 220 | (defprotocol PrettyWriter |
218 | 221 | (start-block [this prefix per-line-prefix suffix]) |
219 | 222 | (end-block [this]) |
| 223 | + (pp-indent [this relative-to offset]) |
220 | 224 | (pp-newline [this kind])) |
221 | 225 |
|
222 | 226 | (defn get-pretty-writer |
|
228 | 232 | ([writer max-columns] |
229 | 233 | (let [lock (threading/RLock) |
230 | 234 | writer (get-column-writer writer max-columns) |
231 | | - state (volatile! {:block (LogicalBlock nil nil nil nil 0 false) |
| 235 | + state (volatile! {:block (LogicalBlock nil nil nil nil 0 0 false) |
232 | 236 | :buffer (queue) |
233 | 237 | :pos 0})] |
234 | 238 | (letfn [;; Private helpers can only be called while the lock is held |
|
249 | 253 | (set! (.-force-nl? block) true) |
250 | 254 | (recur (.-parent block)))))) |
251 | 255 |
|
252 | | - ;; Set the `indent` of the current logical block to match the current |
253 | | - ;; column position of the base writer. |
254 | | - (set-block-indent! [block prefix] |
| 256 | + ;; Set the `indent` and `start-col` of the current logical block to match |
| 257 | + ;; the current column position of the base writer. |
| 258 | + (set-block-cols! [block prefix] |
255 | 259 | (let [indent (+ (:col @writer) (count prefix))] |
256 | | - (set! (.-indent block) indent))) |
| 260 | + (set! (.-indent block) indent) |
| 261 | + (set! (.-start-col block) indent))) |
257 | 262 |
|
258 | 263 | ;; Return `true` if the given newline type should be emitted. |
259 | 264 | (emit-nl? [token section] |
|
281 | 286 | Newline (when (or (= (.-kind token) :mandatory) |
282 | 287 | (.-force-nl? (.-block token))) |
283 | 288 | (gen-nl token)) |
284 | | - StartBlock (let [block (.-block token)] |
285 | | - (when-let [prefix (.-prefix block)] |
286 | | - (set-block-indent! block prefix) |
287 | | - prefix)) |
| 289 | + Indent (let [block (.-block token) |
| 290 | + indent (+ (.-offset token) |
| 291 | + (case (.-relative-to token) |
| 292 | + :block (.-start-col block) |
| 293 | + :current (:col @writer)))] |
| 294 | + (set! (.-indent block) indent) |
| 295 | + nil) |
| 296 | + StartBlock (let [block (.-block token) |
| 297 | + prefix (.-prefix block)] |
| 298 | + (set-block-cols! block (or prefix "")) |
| 299 | + prefix) |
288 | 300 | EndBlock (.-suffix (.-block token)))] |
289 | 301 | (.write writer s)))) |
290 | 302 |
|
|
370 | 382 | (start-block [self prefix per-line-prefix suffix] |
371 | 383 | (with [_ lock] |
372 | 384 | (let [current-block (:block @state) |
373 | | - new-block (LogicalBlock current-block prefix per-line-prefix suffix 0 false) |
| 385 | + new-block (LogicalBlock current-block prefix per-line-prefix suffix 0 0 false) |
374 | 386 | [old-pos new-pos] (update-pos prefix) |
375 | 387 | start-block (StartBlock new-block old-pos new-pos)] |
376 | 388 | (vswap! state #(-> % |
|
389 | 401 | (add-to-buffer end-block))) |
390 | 402 | nil) |
391 | 403 |
|
| 404 | + (pp-indent [self relative-to offset] |
| 405 | + (with [_ lock] |
| 406 | + (let [{:keys [block pos]} @state |
| 407 | + indent (Indent block relative-to offset pos pos)] |
| 408 | + (add-to-buffer indent))) |
| 409 | + nil) |
| 410 | + |
392 | 411 | (pp-newline [self kind] |
393 | 412 | (with [_ lock] |
394 | 413 | (let [{:keys [block pos]} @state |
|
436 | 455 | (do ~@body) |
437 | 456 | (.write *out* "..."))))) |
438 | 457 |
|
| 458 | +(defn pprint-indent |
| 459 | + "Configure the indent of `offset` characters relative to an anchor at this point |
| 460 | + in the pretty print output. |
| 461 | + |
| 462 | + ``relative-to`` must be one of the following keywords: |
| 463 | + - ``:current``, meaning that the indent offset is relative to the current column |
| 464 | + when the indent token is encountered |
| 465 | + - ``:block``, meaning that the indent offset is relative to the starting column of |
| 466 | + the current logical block" |
| 467 | + [relative-to offset] |
| 468 | + (when-not (#{:block :current} relative-to) |
| 469 | + (throw |
| 470 | + (ex-info "relative-to must be one of: :block, :current" |
| 471 | + {:relative-to relative-to}))) |
| 472 | + (pp-indent *out* relative-to offset)) |
| 473 | + |
439 | 474 | (defn pprint-newline |
440 | 475 | "Emit a newline to the output buffer. |
441 | 476 |
|
|
631 | 666 | (not (realized? obj))) :not-delivered |
632 | 667 | :else @obj)] |
633 | 668 | (pprint-logical-block :prefix prefix :suffix ">" |
| 669 | + (pprint-indent :block (- (- (count prefix) 2))) |
| 670 | + (pprint-newline :linear) |
634 | 671 | (write-out contents)))) |
635 | 672 |
|
636 | 673 | (alter-var-root #'*print-pprint-dispatch* (constantly simple-dispatch)) |
|
0 commit comments