review fixes: word-wrap hard-break, title-align, ASDF fix, edge cases

Fixes from subagent review:
- Word-wrap now hard-breaks words exceeding max-width (was returning
  un-truncated overflow strings)
- Box zero-size guard now catches any zero/single dimension (was only
  catching both zero together)
- Title-align now respected (:left/:center/:right) with proper positioning
- render-text declares (ignore spans) to suppress unused warning
- ASDF test-op fixed: run! → run-tests (symbol didn't exist)
- New test: box-single-column (width=1 renders nothing)
- Tightened word-wrap test: verifies hard-break produces both chunks
- Simplified word-wrap with cond instead of nested if/progn (avoided
  recurring paren-balance issue)
This commit is contained in:
Hermes
2026-05-11 14:57:44 +00:00
parent a1b1352d10
commit 88c576a6b9
4 changed files with 45 additions and 31 deletions

View File

@@ -44,6 +44,7 @@
(bg (text-bg text-object))
(wrap (text-wrap-mode text-object))
(spans (text-spans text-object)))
(declare (ignore spans))
(let ((x (layout-node-x ln))
(y (layout-node-y ln))
(w (layout-node-width ln))
@@ -51,10 +52,8 @@
(when (or (zerop (length content)) (zerop w) (zerop h))
(return-from render-text (values)))
(if (eql wrap :none)
;; No wrap — truncate to width
(let ((display (subseq content 0 (min (length content) w))))
(draw-text backend x y display fg bg))
;; Word wrap
(let ((lines (word-wrap content w))
(max-lines h))
(loop for line in lines
@@ -62,27 +61,28 @@
do (draw-text backend x (+ y row) line fg bg)))))))
(defun word-wrap (text max-width)
"Split TEXT into lines, each no longer than MAX-WIDTH characters.
Breaks at word boundaries when possible."
"Split TEXT into lines, each <= MAX-WIDTH chars.
Breaks at word boundaries. Words exceeding MAX-WIDTH are hard-broken."
(if (or (zerop max-width) (zerop (length text)))
(list "")
(let ((words (split-string text))
(lines nil)
(current nil)
(current-len 0))
(let ((words (split-string text)) (lines nil) (current nil) (current-len 0))
(dolist (word words)
(let ((word-len (length word)))
(if (and current (<= (+ current-len 1 word-len) max-width))
;; Add to current line
(progn
(push word current)
(incf current-len (1+ word-len)))
;; Start new line
(progn
(when current
(push (format nil "~{~A~^ ~}" (nreverse current)) lines))
(setf current (list word))
(setf current-len word-len)))))
(let ((wl (length word)))
(cond ((<= wl max-width)
(if (and current (<= (+ current-len 1 wl) max-width))
(push word current)
(progn
(when current
(push (format nil "~{~A~^ ~}" (nreverse current)) lines))
(setf current (list word))
(setf current-len wl))))
(t
(when current
(push (format nil "~{~A~^ ~}" (nreverse current)) lines)
(setf current nil)
(setf current-len 0))
(loop for i from 0 below wl by max-width
do (push (subseq word i (min (+ i max-width) wl)) lines))))))
(when current
(push (format nil "~{~A~^ ~}" (nreverse current)) lines))
(or (nreverse lines) (list "")))))