From 4f40703e4fa01a749b306b2161a425a314b85606 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Fri, 4 Oct 2024 11:55:26 +0100 Subject: [PATCH 1/4] fix for split cells --- rich/segment.py | 33 +++++++++++++++------------------ tests/test_segment.py | 15 ++++++++++----- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/rich/segment.py b/rich/segment.py index 5986aac7..34f84b9d 100644 --- a/rich/segment.py +++ b/rich/segment.py @@ -129,34 +129,31 @@ class Segment(NamedTuple): cell_size = get_character_cell_size - pos = int((cut / cell_length) * (len(text))) - 1 - if pos < 0: - pos = 0 + pos = int((cut / cell_length) * len(text)) - before = text[:pos] - cell_pos = cell_len(before) - if cell_pos == cut: - return ( - _Segment(before, style, control), - _Segment(text[pos:], style, control), - ) - while pos < len(text): - char = text[pos] - pos += 1 - cell_pos += cell_size(char) + while True: before = text[:pos] - if cell_pos == cut: + cell_pos = cell_len(before) + out_by = cell_pos - cut + if not out_by: return ( _Segment(before, style, control), _Segment(text[pos:], style, control), ) - if cell_pos > cut: + if out_by == -1 and cell_size(text[pos]) == 2: + return ( + _Segment(before[:pos] + " ", style, control), + _Segment(" " + text[pos + 1 :], style, control), + ) + if out_by == +1 and cell_size(text[pos]) == 2: return ( _Segment(before[: pos - 1] + " ", style, control), _Segment(" " + text[pos:], style, control), ) - - raise AssertionError("Will never reach here") + if cell_pos < cut: + pos += 1 + else: + pos -= 1 def split_cells(self, cut: int) -> Tuple["Segment", "Segment"]: """Split segment in to two segments at the specified column. diff --git a/tests/test_segment.py b/tests/test_segment.py index 4dac53c8..4bdb0145 100644 --- a/tests/test_segment.py +++ b/tests/test_segment.py @@ -288,11 +288,16 @@ def test_split_cells_emoji(text, split, result): def test_split_cells_mixed() -> None: """Check that split cells splits on cell positions.""" # Caused https://github.com/Textualize/textual/issues/4996 in Textual - test = Segment("早乙女リリエル (CV: 徳井青)") - for position in range(1, test.cell_length): - left, right = Segment.split_cells(test, position) - assert cell_len(left.text) == position - assert cell_len(right.text) == test.cell_length - position + tests = [ + Segment("早乙女リリエル (CV: 徳井青)"), + Segment("メイド・イン・きゅんクチュアリ☆"), + Segment("TVアニメ「メルクストーリア -無気力少年と瓶の中の少女-」 主題歌CD"), + ] + for test in tests: + for position in range(1, test.cell_length): + left, right = Segment.split_cells(test, position) + assert cell_len(left.text) == position + assert cell_len(right.text) == test.cell_length - position def test_split_cells_doubles() -> None: From babf74a7eafb0a989efd88dcfb969cfa2922a58d Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Fri, 4 Oct 2024 12:38:55 +0100 Subject: [PATCH 2/4] more tests --- rich/segment.py | 6 +++--- tests/test_segment.py | 30 +++++++++++++++++++----------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/rich/segment.py b/rich/segment.py index 34f84b9d..0f067687 100644 --- a/rich/segment.py +++ b/rich/segment.py @@ -142,12 +142,12 @@ class Segment(NamedTuple): ) if out_by == -1 and cell_size(text[pos]) == 2: return ( - _Segment(before[:pos] + " ", style, control), + _Segment(text[:pos] + " ", style, control), _Segment(" " + text[pos + 1 :], style, control), ) - if out_by == +1 and cell_size(text[pos]) == 2: + if out_by == +1 and cell_size(text[pos - 1]) == 2: return ( - _Segment(before[: pos - 1] + " ", style, control), + _Segment(text[: pos - 1] + " ", style, control), _Segment(" " + text[pos:], style, control), ) if cell_pos < cut: diff --git a/tests/test_segment.py b/tests/test_segment.py index 4bdb0145..3673f129 100644 --- a/tests/test_segment.py +++ b/tests/test_segment.py @@ -285,19 +285,27 @@ def test_split_cells_emoji(text, split, result): assert Segment(text).split_cells(split) == result -def test_split_cells_mixed() -> None: +@pytest.mark.parametrize( + "segment", + [ + Segment("早乙女リリエル (CV: 徳井青)"), + Segment("メイド・イン・きゅんクチュアリ☆ "), + Segment("TVアニメ「メルクストーリア -無気力少年と瓶の中の少女-」 主題歌CD"), + Segment("南無阿弥JKうらめしや?! "), + Segment("メルク (CV: 水瀬いのり) "), + ], +) +def test_split_cells_mixed(segment: Segment) -> None: """Check that split cells splits on cell positions.""" # Caused https://github.com/Textualize/textual/issues/4996 in Textual - tests = [ - Segment("早乙女リリエル (CV: 徳井青)"), - Segment("メイド・イン・きゅんクチュアリ☆"), - Segment("TVアニメ「メルクストーリア -無気力少年と瓶の中の少女-」 主題歌CD"), - ] - for test in tests: - for position in range(1, test.cell_length): - left, right = Segment.split_cells(test, position) - assert cell_len(left.text) == position - assert cell_len(right.text) == test.cell_length - position + + for position in range(0, segment.cell_length + 1): + left, right = Segment.split_cells(segment, position) + assert all( + cell_len(c) > 0 for c in segment.text + ) # Sanity check there aren't any sneaky control codes + assert cell_len(left.text) == position + assert cell_len(right.text) == segment.cell_length - position def test_split_cells_doubles() -> None: From 834d1785f4ff422dcc9cc94984225f1d2ff8f527 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Fri, 4 Oct 2024 12:41:32 +0100 Subject: [PATCH 3/4] tests --- tests/test_segment.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_segment.py b/tests/test_segment.py index 3673f129..2264dbe5 100644 --- a/tests/test_segment.py +++ b/tests/test_segment.py @@ -293,6 +293,9 @@ def test_split_cells_emoji(text, split, result): Segment("TVアニメ「メルクストーリア -無気力少年と瓶の中の少女-」 主題歌CD"), Segment("南無阿弥JKうらめしや?! "), Segment("メルク (CV: 水瀬いのり) "), + Segment(" メルク (CV: 水瀬いのり) "), + Segment(" メルク (CV: 水瀬いのり) "), + Segment(" メルク (CV: 水瀬いのり) "), ], ) def test_split_cells_mixed(segment: Segment) -> None: From 661ae8dfacb04b317f0c50689ddd9b1d2f19e926 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Fri, 4 Oct 2024 12:43:43 +0100 Subject: [PATCH 4/4] version bump --- CHANGELOG.md | 4 +++- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1915a9d3..d3e1a20c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## [13.9.2] - 2024-10-04 ### Fixed - Fixed `Table` columns not highlighting when added by `add_row` https://github.com/Textualize/rich/issues/3517 +- Fixed an issue with Segment.split_cells reported in Textual https://github.com/Textualize/textual/issues/5090 ## [13.9.1] - 2024-10-01 @@ -2096,6 +2097,7 @@ Major version bump for a breaking change to `Text.stylize signature`, which corr - First official release, API still to be stabilized +[13.9.2]: https://github.com/textualize/rich/compare/v13.9.1...v13.9.2 [13.9.1]: https://github.com/textualize/rich/compare/v13.9.0...v13.9.1 [13.9.0]: https://github.com/textualize/rich/compare/v13.8.1...v13.9.0 [13.8.1]: https://github.com/textualize/rich/compare/v13.8.0...v13.8.1 diff --git a/pyproject.toml b/pyproject.toml index 8aa9cd04..b079ffea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "rich" homepage = "https://github.com/Textualize/rich" documentation = "https://rich.readthedocs.io/en/latest/" -version = "13.9.1" +version = "13.9.2" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" authors = ["Will McGugan "] license = "MIT"