From 5e7845f0bb81dfcae06a6fa9c3a56b29d606d8f1 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 7 Jun 2026 12:57:49 -0400 Subject: [PATCH] Parentheticals rhyme internally but never claim the line ending (justify greed) now lights up with need/breed as internal rhyme; the ending slot stays with the last word outside parens, so (yeah) tails still can't set the scheme. The old all-or-nothing exclusion is gone. Co-Authored-By: Claude Opus 4.8 (1M context) --- app.py | 13 ++++++++----- tests/test_rhymes.py | 13 +++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/app.py b/app.py index e3c149c..eee450c 100644 --- a/app.py +++ b/app.py @@ -487,8 +487,9 @@ def analyze(draft: Draft): for i, line in enumerate(lines): if sids[i] is None: continue - # ad-libs — anything in (parens) mid-line — are delivery, not - # text: they don't rhyme and can't claim the line-ending slot + # parentheticals can rhyme internally, but the line-ending slot + # belongs to the last word OUTSIDE parens — "(yeah)" tails and + # backing vocals never set the scheme adlib, depth, astart = [], 0, None for j, ch in enumerate(line): if ch == "(": @@ -501,12 +502,14 @@ def analyze(draft: Draft): adlib.append((astart, j + 1)) if depth: adlib.append((astart, len(line))) - matches = [m for m in WORD_RE.finditer(line) + all_matches = list(WORD_RE.finditer(line)) + outside = [m for m in all_matches if not any(s <= m.start() < e for s, e in adlib)] - for j, m in enumerate(matches): + last_out = outside[-1] if outside else None + for m in all_matches: tokens.append({ "line": i, "start": m.start(), "end": m.end(), - "word": m.group(0), "is_end": j == len(matches) - 1, + "word": m.group(0), "is_end": m is last_out, "sid": sids[i], "gid": None, "slant": False, }) diff --git a/tests/test_rhymes.py b/tests/test_rhymes.py index e643b40..8dc81df 100644 --- a/tests/test_rhymes.py +++ b/tests/test_rhymes.py @@ -617,3 +617,16 @@ def test_repetition_alone_does_not_color(): def test_repetition_colors_once_a_differing_word_joins(): text = "it was Tammy\npure whammy\nstill Tammy" group_with(text, "tammy", "whammy") + + +def test_paren_words_highlight_but_never_end(): + # (justify greed) rhymes internally with need/breed, but the line's + # ending slot belongs to "tragedies", outside the parens + text = ("How can we still succeed taking what we don't need?\n" + "Telling lies, alibis, selling all the hate that we breed,\n" + "Super-size our tragedies (you can't define me, or justify greed),") + group_with(text, "need", "breed", "greed", "succeed") + res = analyze(Draft(text=text)) + ends = {res["lines"][t["l"]][t["s"]:t["e"]].lower() + for t in res["tokens"] if t["end"] and not t["ph"]} + assert "greed" not in ends