From b80c354e8b9532d7deec463625f129d106f8f51c Mon Sep 17 00:00:00 2001 From: Takafumi ONAKA Date: Sun, 9 Nov 2025 14:06:21 +0900 Subject: [PATCH 1/3] Fix ANSI carry-over indexes when wrapping Fixes an IndexError raised when an ANSI code starts at the end of a wrapped line and carries over to a shorter next line. The carry-over kept the original column index, so insert_ansi tried to insert beyond the new string length. Normalize carried-over ANSI entries to [code, 0] so they always reapply at the beginning of the next line. --- lib/strings/wrap.rb | 2 +- spec/unit/wrap/insert_ansi_spec.rb | 2 +- spec/unit/wrap/wrap_spec.rb | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/strings/wrap.rb b/lib/strings/wrap.rb index 7dbda07..0e204fe 100644 --- a/lib/strings/wrap.rb +++ b/lib/strings/wrap.rb @@ -146,7 +146,7 @@ def insert_ansi(string, ansi_stack = []) next elsif !matched_reset # ansi without reset matched_reset = false - new_stack << ansi # keep the ansi + new_stack.unshift([ansi[0], 0]) # carry over ANSI to the start of next line preserving order next if ansi[1] == length if output.end_with?(NEWLINE) output.insert(-2, ansi_reset) diff --git a/spec/unit/wrap/insert_ansi_spec.rb b/spec/unit/wrap/insert_ansi_spec.rb index 4497da3..15b84d2 100644 --- a/spec/unit/wrap/insert_ansi_spec.rb +++ b/spec/unit/wrap/insert_ansi_spec.rb @@ -60,6 +60,6 @@ val = Strings::Wrap.insert_ansi(text, stack) expect(val).to eq("\e[32mone\e[0m") - expect(stack).to eq([["\e[33m", 3]]) + expect(stack).to eq([["\e[33m", 0]]) end end diff --git a/spec/unit/wrap/wrap_spec.rb b/spec/unit/wrap/wrap_spec.rb index 1fdcc96..bd11584 100644 --- a/spec/unit/wrap/wrap_spec.rb +++ b/spec/unit/wrap/wrap_spec.rb @@ -178,6 +178,14 @@ ].join("\n")) end + it "wraps when ANSI start carries over to the next line" do + text = "aaaaaaa \e[31mbb" + expect(Strings::Wrap.wrap(text, 8)).to eq([ + "aaaaaaa ", + "\e[31mbb\e[0m" + ].join("\n")) + end + it "applies ANSI codes when below wrap width" do str = "\e[32mone\e[0m\e[33mtwo\e[0m" From 6db3f382a3fb593437199d0805cb5cf3f7061e4a Mon Sep 17 00:00:00 2001 From: Takafumi ONAKA Date: Sun, 9 Nov 2025 15:59:48 +0900 Subject: [PATCH 2/3] Add stacked ANSI wrap reapply order test --- spec/unit/wrap/wrap_spec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/unit/wrap/wrap_spec.rb b/spec/unit/wrap/wrap_spec.rb index bd11584..fcf89e4 100644 --- a/spec/unit/wrap/wrap_spec.rb +++ b/spec/unit/wrap/wrap_spec.rb @@ -186,6 +186,15 @@ ].join("\n")) end + it "applies stacked ANSI colors after wrapping" do + text = "aaaa \e[31mbbbb \e[32mcc" + expect(Strings::Wrap.wrap(text, 5)).to eq([ + "aaaa ", + "\e[31mbbbb \e[0m", + "\e[31m\e[32mcc\e[0m\e[0m" + ].join("\n")) + end + it "applies ANSI codes when below wrap width" do str = "\e[32mone\e[0m\e[33mtwo\e[0m" From 803d27d9345df27f77a4c2dabb74f21875fd3e9c Mon Sep 17 00:00:00 2001 From: Takafumi ONAKA Date: Sun, 9 Nov 2025 17:01:28 +0900 Subject: [PATCH 3/3] Add CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d48391..ff817f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change log +## Unreleased + +### Fixed + +* Fix IndexError in `Strings::Wrap.wrap` and correct ANSI color insertion on wrap (@onk) + ## [v0.2.1] - 2021-03-09 ### Changed