Skip to content

Commit faa6f3a

Browse files
kaja-sTjaz Erzen
authored andcommitted
Redesigned the TUI and hierarchicaly organized the information
1 parent 0f23e43 commit faa6f3a

6 files changed

Lines changed: 250 additions & 84 deletions

File tree

tui/components.py

Lines changed: 162 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ def compose(self):
2323

2424

2525
class ScriptOutputType(str, Enum):
26-
UNIT_TEST_OUTPUT_TEXT = "Latest unit test script execution output: "
27-
CONFORMANCE_TEST_OUTPUT_TEXT = "Latest conformance tests script execution output: "
28-
TESTING_ENVIRONMENT_OUTPUT_TEXT = "Latest testing environment preparation script execution output: "
26+
UNIT_TEST_OUTPUT_TEXT = "Unit tests: "
27+
CONFORMANCE_TEST_OUTPUT_TEXT = "Conformance tests: "
28+
TESTING_ENVIRONMENT_OUTPUT_TEXT = "Testing environment preparation execution output: "
2929

3030
@staticmethod
3131
def get_max_label_width(active_types: list["ScriptOutputType"]) -> int:
@@ -42,16 +42,16 @@ def get_max_label_width(active_types: list["ScriptOutputType"]) -> int:
4242
return max(len(script_type.value) for script_type in active_types)
4343

4444
def get_padded_label(self, active_types: list["ScriptOutputType"]) -> str:
45-
"""Get the label right-padded to align with other active labels.
45+
"""Get the label left-aligned (no padding).
4646
4747
Args:
4848
active_types: List of ScriptOutputType enum members that are currently active
4949
5050
Returns:
51-
Right-aligned label padded to match the longest active label
51+
Label without padding (left-aligned)
5252
"""
53-
max_width = ScriptOutputType.get_max_label_width(active_types)
54-
return self.value.rjust(max_width)
53+
# Return label as-is without padding for left alignment
54+
return self.value
5555

5656

5757
class TUIComponents(str, Enum):
@@ -189,6 +189,155 @@ async def clear_substates(self):
189189
pass
190190

191191

192+
class RenderingInfoBox(Vertical):
193+
"""Container with ASCII border for module and functionality information."""
194+
195+
def __init__(self, **kwargs):
196+
super().__init__(**kwargs)
197+
self.module_text = ""
198+
self.functionality_text = ""
199+
200+
def update_module(self, text: str) -> None:
201+
"""Update the module name and refresh the display."""
202+
self.module_text = text
203+
self._refresh_content()
204+
205+
def update_functionality(self, text: str) -> None:
206+
"""Update the functionality text and refresh the display."""
207+
self.functionality_text = text
208+
self._refresh_content()
209+
210+
def _refresh_content(self) -> None:
211+
"""Refresh the content of the box."""
212+
try:
213+
widget = self.query_one("#rendering-info-content", Static)
214+
# Calculate the width needed for the border
215+
lines = []
216+
if self.module_text:
217+
lines.append(f" {self.module_text}")
218+
if self.functionality_text:
219+
lines.append(f" {self.functionality_text}")
220+
221+
if not lines:
222+
widget.update("")
223+
return
224+
225+
# Find the longest line to determine border width
226+
max_width = max(len(line) for line in lines) if lines else 40
227+
border_width = max(max_width + 2, 42) # At least 42 chars wide
228+
229+
# Build the bordered box with title
230+
title = " Currently rendering "
231+
top_border = "┌[#FFFFFF]" + title + "[/#FFFFFF]" + "─" * (border_width - len(title)) + "┐"
232+
bottom_border = "└" + "─" * border_width + "┘"
233+
234+
content_lines = [top_border]
235+
# Add top padding (empty line)
236+
content_lines.append(f"│{' ' * border_width}│")
237+
for line in lines:
238+
padding = border_width - len(line)
239+
content_lines.append(f"│{line}{' ' * padding}│")
240+
# Add bottom padding (empty line)
241+
content_lines.append(f"│{' ' * border_width}│")
242+
content_lines.append(bottom_border)
243+
244+
widget.update("\n".join(content_lines))
245+
except Exception:
246+
pass
247+
248+
def on_mount(self) -> None:
249+
"""Initialize the box with empty state on mount."""
250+
# Set default empty labels
251+
self.module_text = "Module: "
252+
self.functionality_text = "Functionality:"
253+
self._refresh_content()
254+
255+
def compose(self):
256+
yield Static("", id="rendering-info-content", classes="rendering-info-box")
257+
258+
259+
class TestScriptsContainer(Vertical):
260+
"""Container with ASCII border for test script outputs."""
261+
262+
def __init__(
263+
self,
264+
show_unit_test: bool = True,
265+
show_conformance_test: bool = True,
266+
show_testing_env: bool = True,
267+
**kwargs,
268+
):
269+
super().__init__(**kwargs)
270+
self.show_unit_test = show_unit_test
271+
self.show_conformance_test = show_conformance_test
272+
self.show_testing_env = show_testing_env
273+
self.unit_test_text = ScriptOutputType.UNIT_TEST_OUTPUT_TEXT.value
274+
self.conformance_test_text = ScriptOutputType.CONFORMANCE_TEST_OUTPUT_TEXT.value
275+
self.testing_env_text = ScriptOutputType.TESTING_ENVIRONMENT_OUTPUT_TEXT.value
276+
277+
def update_unit_test(self, text: str) -> None:
278+
"""Update unit test output and refresh."""
279+
self.unit_test_text = text
280+
self._refresh_content()
281+
282+
def update_conformance_test(self, text: str) -> None:
283+
"""Update conformance test output and refresh."""
284+
self.conformance_test_text = text
285+
self._refresh_content()
286+
287+
def update_testing_env(self, text: str) -> None:
288+
"""Update testing env output and refresh."""
289+
self.testing_env_text = text
290+
self._refresh_content()
291+
292+
def _refresh_content(self) -> None:
293+
"""Refresh the bordered box content."""
294+
try:
295+
widget = self.query_one("#test-scripts-content", Static)
296+
297+
# Collect lines to display
298+
lines = []
299+
if self.show_unit_test:
300+
lines.append(f" {self.unit_test_text}")
301+
if self.show_conformance_test:
302+
lines.append(f" {self.conformance_test_text}")
303+
if self.show_testing_env:
304+
lines.append(f" {self.testing_env_text}")
305+
306+
if not lines:
307+
widget.update("")
308+
return
309+
310+
# Find the longest line to determine border width
311+
max_width = max(len(line) for line in lines)
312+
border_width = max(max_width + 2, 80) # Minimum width of 80 chars
313+
314+
# Build the bordered box with title
315+
title = " Latest test scripts "
316+
top_border = "┌[#FFFFFF]" + title + "[/#FFFFFF]" + "─" * (border_width - len(title)) + "┐"
317+
bottom_border = "└" + "─" * border_width + "┘"
318+
319+
content_lines = [top_border]
320+
# Add top padding (empty line)
321+
content_lines.append(f"│{' ' * border_width}│")
322+
for line in lines:
323+
padding = border_width - len(line)
324+
content_lines.append(f"│{line}{' ' * padding}│")
325+
# Add bottom padding (empty line)
326+
content_lines.append(f"│{' ' * border_width}│")
327+
content_lines.append(bottom_border)
328+
329+
widget.update("\n".join(content_lines))
330+
except Exception:
331+
pass
332+
333+
def on_mount(self) -> None:
334+
"""Initialize the box on mount."""
335+
self._refresh_content()
336+
337+
def compose(self):
338+
yield Static("", id="test-scripts-content", classes="test-scripts-box")
339+
340+
192341
class FRIDProgress(Vertical):
193342
"""A widget to display the status of subcomponent tasks."""
194343

@@ -198,16 +347,17 @@ class FRIDProgress(Vertical):
198347
REFACTORING_TEXT = "Refactoring"
199348
CONFORMANCE_TEST_VALIDATION_TEXT = "Conformance tests"
200349

201-
RENDERING_MODULE_TEXT = "Rendering module: "
202-
RENDERING_FUNCTIONALITY_TEXT = "Rendering functionality:"
350+
RENDERING_MODULE_TEXT = "Module: "
351+
RENDERING_FUNCTIONALITY_TEXT = "Functionality:"
203352

204353
def __init__(self, **kwargs):
205354
super().__init__(**kwargs)
206355

207356
def update_fr_text(self, text: str) -> None:
208357
try:
209-
widget = self.query_one(f"#{TUIComponents.FRID_PROGRESS_HEADER.value}", Static)
210-
widget.update(text)
358+
# Update the rendering info box instead
359+
info_box = self.query_one(RenderingInfoBox)
360+
info_box.update_functionality(text)
211361
except Exception:
212362
pass
213363

@@ -222,8 +372,7 @@ def on_mount(self) -> None:
222372
self.border_title = "FRID Progress"
223373

224374
def compose(self):
225-
yield Static(self.RENDERING_MODULE_TEXT, id=TUIComponents.RENDER_MODULE_NAME_WIDGET.value)
226-
yield Static(self.RENDERING_FUNCTIONALITY_TEXT, id=TUIComponents.FRID_PROGRESS_HEADER.value)
375+
yield RenderingInfoBox()
227376
yield ProgressItem(
228377
self.IMPLEMENTING_FUNCTIONALITY_TEXT,
229378
id=TUIComponents.FRID_PROGRESS_RENDER_FR.value,

tui/plain2code_tui.py

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
FRIDProgress,
2626
LogFilterChanged,
2727
LogLevelFilter,
28+
RenderingInfoBox,
2829
ScriptOutputType,
2930
StructuredLogView,
31+
TestScriptsContainer,
3032
TUIComponents,
3133
CustomFooter,
3234
)
@@ -133,34 +135,18 @@ def compose(self) -> ComposeResult:
133135
classes="codeplain-header"
134136
)
135137
yield Static(
136-
"Rendering in progress...",
138+
"[#FFFFFF]Rendering in progress...[/#FFFFFF]",
137139
id=TUIComponents.RENDER_STATUS_WIDGET.value,
138140
)
139141
yield FRIDProgress(id=TUIComponents.FRID_PROGRESS.value)
140142

141-
# Get active script types for proper label alignment
142-
active_script_types = self.get_active_script_types()
143-
144-
# Conditionally display unit test output widget
145-
if self.unittests_script is not None:
146-
yield Static(
147-
ScriptOutputType.UNIT_TEST_OUTPUT_TEXT.get_padded_label(active_script_types),
148-
id=TUIComponents.UNIT_TEST_SCRIPT_OUTPUT_WIDGET.value,
149-
)
150-
151-
# Conditionally display conformance test output widget
152-
if self.conformance_tests_script is not None:
153-
yield Static(
154-
ScriptOutputType.CONFORMANCE_TEST_OUTPUT_TEXT.get_padded_label(active_script_types),
155-
id=TUIComponents.CONFORMANCE_TESTS_SCRIPT_OUTPUT_WIDGET.value,
156-
)
157-
158-
# Conditionally display testing environment preparation output widget
159-
if self.prepare_environment_script is not None:
160-
yield Static(
161-
ScriptOutputType.TESTING_ENVIRONMENT_OUTPUT_TEXT.get_padded_label(active_script_types),
162-
id=TUIComponents.TESTING_ENVIRONMENT_SCRIPT_OUTPUT_WIDGET.value,
163-
)
143+
# Test scripts container with border
144+
yield TestScriptsContainer(
145+
id="test-scripts-container",
146+
show_unit_test=self.unittests_script is not None,
147+
show_conformance_test=self.conformance_tests_script is not None,
148+
show_testing_env=self.prepare_environment_script is not None,
149+
)
164150
with Vertical(id=TUIComponents.LOG_VIEW.value):
165151
yield LogLevelFilter(id=TUIComponents.LOG_FILTER.value)
166152
yield Static("", classes="filter-spacer")
@@ -178,16 +164,18 @@ def action_toggle_logs(self) -> None:
178164
def on_render_module_started(self, event: RenderModuleStarted):
179165
"""Update TUI based on the current state machine state."""
180166
try:
181-
widget = self.query_one(f"#{TUIComponents.RENDER_MODULE_NAME_WIDGET.value}", Static)
182-
widget.update(f"{FRIDProgress.RENDERING_MODULE_TEXT}{event.module_name}")
167+
frid_progress = self.query_one(f"#{TUIComponents.FRID_PROGRESS.value}", FRIDProgress)
168+
info_box = frid_progress.query_one(RenderingInfoBox)
169+
info_box.update_module(f"{FRIDProgress.RENDERING_MODULE_TEXT}{event.module_name}")
183170
except Exception as e:
184171
console.debug(f"Error updating render module name: {type(e).__name__}: {e}")
185172

186173
def on_render_module_completed(self, _event: RenderModuleCompleted):
187174
"""Update TUI based on the current state machine state."""
188175
try:
189-
widget = self.query_one(f"#{TUIComponents.RENDER_MODULE_NAME_WIDGET.value}", Static)
190-
widget.update(FRIDProgress.RENDERING_MODULE_TEXT)
176+
frid_progress = self.query_one(f"#{TUIComponents.FRID_PROGRESS.value}", FRIDProgress)
177+
info_box = frid_progress.query_one(RenderingInfoBox)
178+
info_box.update_module(FRIDProgress.RENDERING_MODULE_TEXT)
191179
except Exception as e:
192180
console.debug(f"Error resetting render module name: {type(e).__name__}: {e}")
193181

File renamed without changes.

tui/state_handlers.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -232,29 +232,33 @@ def handle(self, _segments: list[str], snapshot: RenderContextSnapshot, previous
232232
# Get active script types for proper label alignment
233233
active_script_types = self.tui.get_active_script_types()
234234

235-
if any(segment == States.UNIT_TESTS_READY.value for segment in previous_state_segments):
236-
update_widget_text(
237-
self.tui,
238-
TUIComponents.UNIT_TEST_SCRIPT_OUTPUT_WIDGET.value,
239-
f"{ScriptOutputType.UNIT_TEST_OUTPUT_TEXT.get_padded_label(active_script_types)}{snapshot.script_execution_history.latest_unit_test_output_path}", # type: ignore
240-
)
235+
# Update test scripts container
236+
try:
237+
from .components import TestScriptsContainer
238+
container = self.tui.query_one("#test-scripts-container", TestScriptsContainer)
239+
240+
if any(segment == States.UNIT_TESTS_READY.value for segment in previous_state_segments):
241+
if snapshot.script_execution_history.latest_unit_test_output_path:
242+
container.update_unit_test(
243+
f"{ScriptOutputType.UNIT_TEST_OUTPUT_TEXT.value}{snapshot.script_execution_history.latest_unit_test_output_path}"
244+
)
241245

242-
if len(previous_state_segments) > 2 and previous_state_segments[2] == States.CONFORMANCE_TEST_GENERATED.value:
243-
update_widget_text(
244-
self.tui,
245-
TUIComponents.TESTING_ENVIRONMENT_SCRIPT_OUTPUT_WIDGET.value,
246-
f"{ScriptOutputType.TESTING_ENVIRONMENT_OUTPUT_TEXT.get_padded_label(active_script_types)}{snapshot.script_execution_history.latest_testing_environment_output_path}", # type: ignore
247-
)
246+
if len(previous_state_segments) > 2 and previous_state_segments[2] == States.CONFORMANCE_TEST_GENERATED.value:
247+
if snapshot.script_execution_history.latest_testing_environment_output_path:
248+
container.update_testing_env(
249+
f"{ScriptOutputType.TESTING_ENVIRONMENT_OUTPUT_TEXT.value}{snapshot.script_execution_history.latest_testing_environment_output_path}"
250+
)
248251

249-
if (
250-
len(previous_state_segments) > 2
251-
and previous_state_segments[2] == States.CONFORMANCE_TEST_ENV_PREPARED.value
252-
):
253-
update_widget_text(
254-
self.tui,
255-
TUIComponents.CONFORMANCE_TESTS_SCRIPT_OUTPUT_WIDGET.value,
256-
f"{ScriptOutputType.CONFORMANCE_TEST_OUTPUT_TEXT.get_padded_label(active_script_types)}{snapshot.script_execution_history.latest_conformance_test_output_path}", # type: ignore
257-
)
252+
if (
253+
len(previous_state_segments) > 2
254+
and previous_state_segments[2] == States.CONFORMANCE_TEST_ENV_PREPARED.value
255+
):
256+
if snapshot.script_execution_history.latest_conformance_test_output_path:
257+
container.update_conformance_test(
258+
f"{ScriptOutputType.CONFORMANCE_TEST_OUTPUT_TEXT.value}{snapshot.script_execution_history.latest_conformance_test_output_path}"
259+
)
260+
except Exception:
261+
pass
258262

259263

260264
class FridFullyImplementedHandler(StateHandler):

0 commit comments

Comments
 (0)