compound rewriter inserts 'spring, gobbling up line breaks
The program
#lang racket
(require redex/reduction-semantics redex/pict)
(define-language empty)
(with-compound-rewriter 'R
(λ (lws) `(,(list-ref lws 2) "•" ,(list-ref lws 3)))
(term->pict empty
(R 0 ;; line 7
1))) ;; line 8
produces a pict with 0 and 1 overlapped. After some tracking, I think this because the 'spring inserted during the conversion from "•" to lw gobbled up the new line:
;; debugging output
After apply-rewrites, before build-lines:
(lw
(list
(lw "0" 7 0 17 1 #f #f)
(lw "•" 7 0 14 0 #f #f)
'spring
(lw . 7 1 14 3 #f #f)
'spring
(lw . 8 0 17 0 #f #f)
(lw "1" 8 0 17 1 #f #f))
7
1
14
5
#f
#f)
eject (current=7, gobbled=0) 7:17-7:18 "0"
eject (current=7, gobbled=0) 7:14-7:14 "•"
eject (current=7, gobbled=0) 7:14-8:17 #<pict>
eject (current=7, gobbled=0) 8:17-8:17 #<pict>
eject (current=8, gobbled=1) 8:17-8:18 "1"
After build-lines, before setup-lines:
(list
(line
7
(list (spacer-token 0 3) (pict-token 3 0 .) (string-token 3 1 "1" 'roman)))
(line
7
(list
(string-token 0 3 " " 'roman)
(string-token 3 1 "0" 'roman)
(string-token 0 0 "•" 'roman)
(pict-token 0 3 .))))
I find it surprising that inserting elements ("•") in the rewriter would gobble line breaks. Maybe apply-rewrites should not insert 'spring when the two lws surrounding the non-lw are at different lines. If this is intended, I think the column counts need some fix to avoid overlapping.
I believe I just didn't think about newlines and being smart about them when gobbling up space. It would be better to do something more sophisticated in that case. It isn't obvious which line the • belongs on, but picking a default seems like a nice thing.
Indeed, I have written code in rewriters that examines the arguments and has multiple cases based on whether or not two arguments are on the same line or not. But I'll point out that in this case, if there is one line in the input, then you probably want to use " • " and if there are two lines and the dot is on the first line, you probably want " •" (dropping the last space so the pict doesn't get too wide in the case that the thing on the second line is especially wide).
Another approach is to use just-after or just-before, but this doesn't avoid the problem of the inter-"word" space.
I tried using just-after for the inserted "•". Indeed, the inter-"word" space problem exists.
(λ (lws) (list (list-ref lws 2)
(just-after "•" (list-ref lws 2))
(list-ref lws 3)))
I tried removing the second 'spring between the two blank images inserted by Redex provided they are not on the same line. This seems to work. For the case where the two lws are on the same line, I leave the output as-is (though I think the space is already being gobbled up by the 'spring in the first place).
Somehow removing the second 'spring in all cases also work but I don't know why.

+++ b/redex-pict-lib/redex/private/core-layout.rkt
@@ -434,11 +434,13 @@
(- next-lw-line line)
new-lw-col
new-lw-col-span)
- 'spring
- (build-lw to-wrap2 next-lw-line 0 (+ new-lw-col new-lw-col-span) 0)
- (if after-next-lw
- (cons next-lw (loop after-next-lw next-line next-column))
- '()))))])))))
+ (append
+ (cond [(= line next-lw-line) '(spring)]
+ [else '()])
+ (list (build-lw to-wrap2 next-lw-line 0 (+ new-lw-col new-lw-col-span) 0))
+ (if after-next-lw
+ (cons next-lw (loop after-next-lw next-line next-column))
+ '())))))])))))
(define (extract-pieces-to-wrap who lst)
(let ([fst (car lst)])
Testing program:
#lang racket
(require redex/reduction-semantics redex/pict pict)
(define-language empty)
(define (pic thunk)
(begin0
(begin
(printf "========================================\n")
(frame
(scale
(with-compound-rewriter 'R
(λ (lws) (list (list-ref lws 2)
"X" "V"
(list-ref lws 3)))
(thunk))
2)))
(printf "========================================\n")))
(lt-superimpose
(filled-rectangle 250 200
#:color "white"
#:draw-border? #f)
(inset
(vl-append
10
(pic
(λ ()
(term->pict empty
(R 0 1))))
(pic
(λ ()
(term->pict empty
(R 0
1))))
(pic
(λ ()
(term->pict empty
(R 0
1234567890)))))
10))
Thank you for taking the time to look into this. Looking at the code again, I don't fully understand what's going on in the interaction between multiple lines and inserted items but this change is definitely an improvement and seems quite conservative so I pushed it.