diff --git a/ren_browser/renderer/micron.py b/ren_browser/renderer/micron.py index d56a869..9202d0d 100644 --- a/ren_browser/renderer/micron.py +++ b/ren_browser/renderer/micron.py @@ -533,78 +533,9 @@ def render_micron(content: str, ascii_art_scale: float = 0.75) -> ft.Control: parser = MicronParser(ascii_art_scale=ascii_art_scale) controls = parser.convert_micron_to_controls(content) - merged_controls = [] - current_text_parts = [] - current_style = None - - def flush_text_parts(): - """Merge and flush the current text parts into a single Flet Text control, - if any, and append to merged_controls. - """ - nonlocal current_text_parts, current_style - if current_text_parts: - combined_text = "\n".join(current_text_parts) - if current_style: - color, bgcolor, weight, decoration, italic, size, text_align = current_style - style = ft.TextStyle( - color=color, - bgcolor=bgcolor, - weight=weight, - decoration=decoration, - italic=italic, - size=size, - ) - else: - style = None - - merged_controls.append(ft.Text( - combined_text, - style=style, - text_align=text_align if current_style and text_align else "left", - selectable=True, - enable_interactive_selection=True, - expand=True, - font_family="monospace", - )) - current_text_parts = [] - current_style = None - - for control in controls: - if isinstance(control, ft.Text) and not hasattr(control, "content"): - style = control.style or ft.TextStyle() - style_key = ( - getattr(style, "color", None), - getattr(style, "bgcolor", None), - getattr(style, "weight", None), - getattr(style, "decoration", None), - getattr(style, "italic", None), - getattr(style, "size", None), - getattr(control, "text_align", None), - ) - - text_content = "" - if hasattr(control, "spans") and control.spans: - text_content = "".join(span.text for span in control.spans) - elif hasattr(control, "value") and control.value: - text_content = control.value - else: - text_content = "" - - if style_key == current_style: - current_text_parts.append(text_content) - else: - flush_text_parts() - current_style = style_key - current_text_parts = [text_content] - else: - flush_text_parts() - merged_controls.append(control) - - flush_text_parts() - return ft.Container( content=ft.ListView( - controls=merged_controls, + controls=controls, spacing=2, expand=True, ), diff --git a/tests/unit/test_renderers.py b/tests/unit/test_renderers.py index 7a48e89..350e9f5 100644 --- a/tests/unit/test_renderers.py +++ b/tests/unit/test_renderers.py @@ -96,16 +96,32 @@ class TestMicronRenderer: # Should return a Container assert isinstance(result, ft.Container) - # Should contain Text controls with the content + # Should contain controls with the content assert len(result.content.controls) > 0 all_text = "" for control in result.content.controls: - assert isinstance(control, ft.Text) - # Extract text from the merged control - if hasattr(control, "value") and control.value: - all_text += control.value + if isinstance(control, ft.Text): + # Extract text from the control + text_content = "" + if hasattr(control, "value") and control.value: + text_content = control.value + elif hasattr(control, "spans") and control.spans: + text_content = "".join(span.text for span in control.spans) + if text_content: + all_text += text_content + "\n" + elif isinstance(control, ft.Container) and hasattr(control, "content"): + # Handle indented text controls + if isinstance(control.content, ft.Text): + text_content = "" + if hasattr(control.content, "value") and control.content.value: + text_content = control.content.value + elif hasattr(control.content, "spans") and control.content.spans: + text_content = "".join(span.text for span in control.content.spans) + if text_content: + all_text += text_content + "\n" - # Should preserve the content + # Remove trailing newline and should preserve the content + all_text = all_text.rstrip("\n") assert content in all_text def test_render_micron_headings(self): @@ -133,10 +149,16 @@ class TestMicronRenderer: # Should produce some text content all_text = "" for control in result.content.controls: - if hasattr(control, "value") and control.value: - all_text += control.value + if isinstance(control, ft.Text): + text_content = "" + if hasattr(control, "value") and control.value: + text_content = control.value + elif hasattr(control, "spans") and control.spans: + text_content = "".join(span.text for span in control.spans) + if text_content: + all_text += text_content + "\n" - assert len(all_text) > 0 # Should have some processed content + assert len(all_text.strip()) > 0 # Should have some processed content def test_render_micron_colors(self): """Test micron rendering with color codes.""" @@ -149,10 +171,16 @@ class TestMicronRenderer: # Should produce some text content (color codes may consume characters) all_text = "" for control in result.content.controls: - if hasattr(control, "value") and control.value: - all_text += control.value + if isinstance(control, ft.Text): + text_content = "" + if hasattr(control, "value") and control.value: + text_content = control.value + elif hasattr(control, "spans") and control.spans: + text_content = "".join(span.text for span in control.spans) + if text_content: + all_text += text_content + "\n" - assert len(all_text) > 0 # Should have some processed content + assert len(all_text.strip()) > 0 # Should have some processed content def test_render_micron_alignment(self): """Test micron rendering with alignment.""" @@ -165,10 +193,16 @@ class TestMicronRenderer: # Should have some text content all_text = "" for control in result.content.controls: - if hasattr(control, "value") and control.value: - all_text += control.value + if isinstance(control, ft.Text): + text_content = "" + if hasattr(control, "value") and control.value: + text_content = control.value + elif hasattr(control, "spans") and control.spans: + text_content = "".join(span.text for span in control.spans) + if text_content: + all_text += text_content + "\n" - assert len(all_text) > 0 + assert len(all_text.strip()) > 0 def test_render_micron_comments(self): """Test that comments are ignored.""" @@ -179,9 +213,16 @@ class TestMicronRenderer: # Should only contain the visible text, not the comment all_text = "" for control in result.content.controls: - if isinstance(control, ft.Text) and hasattr(control, "value") and control.value: - all_text += control.value + if isinstance(control, ft.Text): + text_content = "" + if hasattr(control, "value") and control.value: + text_content = control.value + elif hasattr(control, "spans") and control.spans: + text_content = "".join(span.text for span in control.spans) + if text_content: + all_text += text_content + "\n" + all_text = all_text.strip() assert "Visible text" in all_text assert "This is a comment" not in all_text @@ -212,13 +253,20 @@ class TestMicronRenderer: result = render_micron(content) assert isinstance(result, ft.Container) - # Text gets merged into single control due to text merging - assert len(result.content.controls) >= 1 + # Each line is kept as separate control + assert len(result.content.controls) >= 3 # Should contain the ASCII art content all_text = "" for control in result.content.controls: - if isinstance(control, ft.Text) and hasattr(control, "value"): - all_text += control.value + if isinstance(control, ft.Text): + text_content = "" + if hasattr(control, "value") and control.value: + text_content = control.value + elif hasattr(control, "spans") and control.spans: + text_content = "".join(span.text for span in control.spans) + if text_content: + all_text += text_content + "\n" + all_text = all_text.strip() assert "┌───┐" in all_text assert "Normal text" in all_text @@ -231,8 +279,14 @@ class TestMicronRenderer: # Should contain the processed content (literal mode may not be fully implemented) all_text = "" for control in result.content.controls: - if isinstance(control, ft.Text) and hasattr(control, "value") and control.value: - all_text += control.value + if isinstance(control, ft.Text): + text_content = "" + if hasattr(control, "value") and control.value: + text_content = control.value + elif hasattr(control, "spans") and control.spans: + text_content = "".join(span.text for span in control.spans) + if text_content: + all_text += text_content + "\n" # At minimum, should contain some text content assert len(all_text.strip()) > 0 @@ -311,13 +365,28 @@ class TestRendererComparison: assert plaintext_result.value == content - # For micron result (Container), extract text from merged controls + # For micron result (Container), extract text from controls micron_text = "" for control in micron_result.content.controls: if isinstance(control, ft.Text): - # Extract text from the merged control + # Extract text from the control + text_content = "" if hasattr(control, "value") and control.value: - micron_text += control.value + "\n" + text_content = control.value + elif hasattr(control, "spans") and control.spans: + text_content = "".join(span.text for span in control.spans) + if text_content: + micron_text += text_content + "\n" + elif isinstance(control, ft.Container) and hasattr(control, "content"): + # Handle indented text controls + if isinstance(control.content, ft.Text): + text_content = "" + if hasattr(control.content, "value") and control.content.value: + text_content = control.content.value + elif hasattr(control.content, "spans") and control.content.spans: + text_content = "".join(span.text for span in control.content.spans) + if text_content: + micron_text += text_content + "\n" # Remove trailing newline and compare micron_text = micron_text.rstrip("\n") @@ -339,7 +408,7 @@ class TestRendererComparison: assert isinstance(micron_result.content, ft.ListView) assert micron_result.content.spacing == 2 - # Check that all Text controls in the column have the expected properties + # Check that all Text controls in the ListView have the expected properties for control in micron_result.content.controls: if isinstance(control, ft.Text): assert control.selectable is True