codeplain 0.2.3__py3-none-any.whl → 0.2.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/METADATA +3 -3
  2. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/RECORD +43 -43
  3. codeplain_REST_api.py +57 -43
  4. config/system_config.yaml +1 -16
  5. file_utils.py +5 -4
  6. git_utils.py +43 -13
  7. memory_management.py +1 -1
  8. module_renderer.py +114 -0
  9. plain2code.py +91 -30
  10. plain2code_console.py +3 -5
  11. plain2code_exceptions.py +26 -6
  12. plain2code_logger.py +11 -5
  13. plain2code_utils.py +7 -5
  14. plain_file.py +15 -37
  15. plain_modules.py +1 -4
  16. plain_spec.py +24 -6
  17. render_machine/actions/create_dist.py +1 -1
  18. render_machine/actions/exit_with_error.py +1 -1
  19. render_machine/actions/prepare_testing_environment.py +1 -1
  20. render_machine/actions/render_conformance_tests.py +2 -4
  21. render_machine/actions/render_functional_requirement.py +6 -6
  22. render_machine/actions/run_conformance_tests.py +3 -2
  23. render_machine/actions/run_unit_tests.py +1 -1
  24. render_machine/render_context.py +3 -3
  25. render_machine/render_utils.py +14 -6
  26. standard_template_library/golang-console-app-template.plain +2 -2
  27. standard_template_library/python-console-app-template.plain +2 -2
  28. standard_template_library/typescript-react-app-template.plain +2 -2
  29. system_config.py +3 -11
  30. tests/test_imports.py +2 -2
  31. tests/test_plainfile.py +2 -2
  32. tests/test_plainfileparser.py +10 -10
  33. tests/test_plainspec.py +2 -2
  34. tests/test_requires.py +2 -1
  35. tui/components.py +311 -103
  36. tui/plain2code_tui.py +101 -52
  37. tui/state_handlers.py +94 -47
  38. tui/styles.css +240 -52
  39. tui/widget_helpers.py +43 -47
  40. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/WHEEL +0 -0
  41. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/entry_points.txt +0 -0
  42. {codeplain-0.2.3.dist-info → codeplain-0.2.5.dist-info}/licenses/LICENSE +0 -0
  43. /spinner.py → /tui/spinner.py +0 -0
tui/styles.css CHANGED
@@ -2,6 +2,19 @@ Screen {
2
2
  layout: vertical;
3
3
  }
4
4
 
5
+ /* Dashboard View - main container */
6
+ #dashboard-view {
7
+ margin: 0 2;
8
+ }
9
+
10
+ /* Codeplain Header Box - *codeplain (version)*/
11
+ #codeplain-header {
12
+ dock: top;
13
+ margin: 1 0;
14
+ width: auto;
15
+ height: auto;
16
+ }
17
+
5
18
  /*
6
19
  We might need those at some point, so just commenting them out for now.
7
20
  #status-widget {
@@ -21,14 +34,10 @@ We might need those at some point, so just commenting them out for now.
21
34
  margin-left: 2;
22
35
  margin-right: 2;
23
36
  height: auto;
24
- color: grey;
25
37
  }
26
38
 
27
39
  #render-status-widget {
28
- margin-left: 2;
29
- margin-right: 2;
30
40
  height: auto;
31
- color: #4D4D4D;
32
41
  }
33
42
 
34
43
  #render-status-widget.success {
@@ -40,8 +49,35 @@ We might need those at some point, so just commenting them out for now.
40
49
  }
41
50
 
42
51
  #frid-progress {
52
+ margin: 0;
53
+ height: auto;
54
+ }
55
+
56
+ /* Module Status */
57
+ RenderingInfoBox {
58
+ height: auto;
43
59
  margin: 1 0;
60
+ }
61
+
62
+ /* Module Status box border */
63
+ .rendering-info-box {
44
64
  height: auto;
65
+ border: solid #888;
66
+ padding: 0 1;
67
+ }
68
+
69
+ .rendering-info-row {
70
+ color: #FFF;
71
+ }
72
+
73
+ .rendering-info-title {
74
+ color: #888;
75
+ margin-bottom: 0;
76
+ }
77
+
78
+ .frid-state-machine-title {
79
+ color: #888;
80
+ margin-bottom: 0;
45
81
  }
46
82
 
47
83
  ProgressItem {
@@ -58,9 +94,16 @@ ProgressItem {
58
94
  padding: 0;
59
95
  }
60
96
 
61
- .substate {
62
- margin: 0;
63
- padding: 0;
97
+ .substate-row {
98
+ height: auto;
99
+ width: 100%;
100
+ padding: 0 1;
101
+ }
102
+
103
+ .substate-line-text {
104
+ width: 1fr;
105
+ color: #FFF;
106
+ content-align: left middle;
64
107
  }
65
108
 
66
109
  #frid-progress Vertical {
@@ -68,22 +111,47 @@ ProgressItem {
68
111
  }
69
112
 
70
113
  #frid-progress-header {
71
- margin-bottom: 1;
72
114
  margin-left: 2;
73
115
  margin-right: 2;
74
- color: #4D4D4D;
116
+ color: #FFF;
75
117
  }
76
118
 
77
119
  #render-module-name-widget {
78
120
  margin-left: 2;
79
121
  margin-right: 2;
80
- color: #4D4D4D;
122
+ color: #FFF;
123
+ }
124
+
125
+ TestScriptsContainer {
126
+ margin: 1 0;
127
+ height: auto;
128
+ }
129
+
130
+ /* Latest script output container */
131
+ .test-scripts-box {
132
+ height: auto;
133
+ color: #888;
134
+ border: solid #888;
135
+ padding: 0 1;
136
+ }
137
+
138
+ .test-scripts-title {
139
+ color: #888;
140
+ margin-bottom: 0;
81
141
  }
82
142
 
143
+ .test-script-row {
144
+ color: #FFF;
145
+ }
146
+
147
+ /* State machine container border */
148
+ .frid-state-machine-box {
149
+ border: solid #888;
150
+ padding: 0 1;
151
+ }
83
152
  #unit-test-script-output-widget,
84
153
  #conformance-tests-script-output-widget,
85
154
  #testing-environment-script-output-widget {
86
- margin: 0 2;
87
155
  height: auto;
88
156
  color: #888;
89
157
  }
@@ -93,7 +161,7 @@ ProgressItem {
93
161
  }
94
162
 
95
163
  .status {
96
- width: 15;
164
+ width: 14;
97
165
  padding: 0 1;
98
166
  }
99
167
 
@@ -129,85 +197,205 @@ ProgressItem {
129
197
  height: 1;
130
198
  }
131
199
 
132
- /* Log Filter Styles */
200
+ /* Log Filter Styles - Segmented Control Design */
133
201
  #log-filter {
134
202
  dock: top;
135
203
  height: auto;
136
- padding: 0 1;
137
- background: $surface-darken-1;
138
- border-bottom: solid $accent;
204
+ padding: 1;
139
205
  }
140
206
 
207
+ /* Spacer after filter */
208
+ .filter-spacer {
209
+ height: 1;
210
+ width: 100%;
211
+ }
212
+
213
+ /* Label style */
141
214
  .filter-label {
142
215
  width: auto;
216
+ text-style: bold;
217
+ color: #FFFFFF;
143
218
  padding: 0 1 0 0;
144
- content-align: center middle;
145
219
  }
146
220
 
147
- .filter-button {
221
+ /* Container for the buttons */
222
+ .filter-buttons-container {
223
+ width: auto;
224
+ height: auto;
225
+ }
226
+
227
+ /* Base button - flat style with minimal decoration */
228
+ Button.filter-button {
229
+ width: auto;
230
+ height: 1;
231
+ min-width: 0;
232
+ padding: 0 1;
148
233
  margin: 0 1;
149
- min-width: 10;
150
- height: 3;
234
+ background: transparent;
235
+ border: none;
236
+ color: #FFF;
237
+ content-align: center middle;
238
+ }
239
+
240
+ /* Hover state for inactive buttons */
241
+ Button.filter-button:hover {
242
+ background: #2A2A2A;
243
+ color: #DDD;
244
+ }
245
+
246
+ /* Focus state for inactive buttons - no visual change */
247
+ Button.filter-button:focus {
248
+ background: transparent;
249
+ color: #FFF;
250
+ }
251
+
252
+ /* Focus-within state for inactive buttons */
253
+ Button.filter-button:focus-within {
254
+ background: transparent;
255
+ color: #FFF;
256
+ }
257
+
258
+ /* Primary variant - active/selected button */
259
+ Button.filter-button.-primary {
260
+ background: #FFF;
261
+ color: #000;
262
+ text-style: bold;
151
263
  }
152
264
 
153
- CollapsibleLogEntry {
265
+ /* Primary focus - maintain appearance */
266
+ Button.filter-button.-primary:focus {
267
+ background: #FFF;
268
+ color: #000;
269
+ text-style: bold;
270
+ }
271
+
272
+ /* Primary focus-within - maintain appearance */
273
+ Button.filter-button.-primary:focus-within {
274
+ background: #E0FF6E;
275
+ color: #000;
276
+ text-style: bold;
277
+ }
278
+
279
+ /* Disabled state - should be dim and non-interactive */
280
+ Button.filter-button:disabled,
281
+ Button.filter-button.-disabled {
282
+ opacity: 0.4;
283
+ color: #555;
284
+ background: transparent;
285
+ }
286
+
287
+ /* Disabled buttons should not show hover effects */
288
+ Button.filter-button:disabled:hover,
289
+ Button.filter-button.-disabled:hover {
290
+ background: transparent;
291
+ color: #555;
292
+ }
293
+
294
+ /* Log Entry Rows */
295
+ .log-entry {
154
296
  height: auto;
297
+ width: 100%;
155
298
  padding: 0;
156
299
  margin: 0;
157
- border-left: solid transparent;
158
300
  }
159
301
 
160
- CollapsibleLogEntry:hover {
161
- background: $surface-lighten-1;
162
- border-left: solid $accent;
302
+ .log-entry:hover {
303
+ background: #1A1A1A;
163
304
  }
164
305
 
165
- .log-arrow {
166
- width: auto;
167
- min-width: 3;
306
+ .log-main-row {
307
+ height: auto;
308
+ width: 100%;
168
309
  padding: 0 1;
169
310
  }
170
311
 
171
- .log-arrow:hover {
172
- text-style: bold;
173
- background: $surface-lighten-2;
312
+ .log-expand-indicator {
313
+ width: 3;
314
+ color: #888;
174
315
  }
175
316
 
176
- .log-summary {
177
- height: auto;
317
+ .log-col-message {
178
318
  width: 1fr;
179
- padding: 0 1;
319
+ color: #FFF;
180
320
  }
181
321
 
182
- .log-expanded {
322
+ .log-details-row {
183
323
  height: auto;
324
+ width: 100%;
325
+ padding: 0 0 0 13;
326
+ margin: 0;
327
+ }
328
+
329
+ .log-details-text {
184
330
  width: 1fr;
185
- padding: 0 1;
331
+ color: #888;
332
+ margin: 0;
333
+ padding: 0;
186
334
  }
187
335
 
188
- /* Log level specific colors with left border */
189
- .log-entry.log-debug {
336
+ /* Legacy columns (keeping for compatibility) */
337
+ .log-col-time {
338
+ width: 14;
190
339
  color: #888;
191
- border-left: thick #555;
192
340
  }
193
341
 
194
- .log-entry.log-info {
195
- color: white;
196
- border-left: thick #4A9FD8;
342
+ .log-col-level {
343
+ width: 10;
197
344
  }
198
345
 
199
- .log-entry.log-warning {
200
- color: #FFD700;
201
- border-left: thick #CCA700;
346
+ .log-col-location {
347
+ width: 12;
348
+ color: #888;
202
349
  }
203
350
 
204
- .log-entry.log-error {
205
- color: #FF6B6B;
206
- border-left: thick #CC4444;
351
+ /* Log spacer for visual separation */
352
+ .log-spacer {
353
+ height: 1;
354
+ width: 100%;
355
+ }
356
+
357
+ /* Level-specific styling for the level column */
358
+ .log-debug .log-col-level {
359
+ color: #fff;
360
+ }
361
+
362
+ .log-info .log-col-level {
363
+ color: #888;
364
+ }
365
+
366
+ .log-warning .log-col-level {
367
+ color: #C5DCD9;
207
368
  }
208
369
 
209
- .log-entry.log-critical {
210
- color: #FF0000;
211
- background: $surface-darken-1;
212
- border-left: thick #FF0000;
370
+ .log-error .log-col-level {
371
+ color: #DD5353;
213
372
  }
373
+
374
+ /* Footer Styling */
375
+ Footer {
376
+ background: transparent;
377
+ height: 2;
378
+ padding: 0 1;
379
+ color: #888;
380
+ align: left bottom;
381
+ }
382
+
383
+ /* Custom Footer */
384
+ CustomFooter {
385
+ dock: bottom;
386
+ height: 2;
387
+ background: transparent;
388
+ padding: 0 1;
389
+ align: left bottom;
390
+ }
391
+
392
+ .custom-footer-text {
393
+ width: 1fr;
394
+ color: #888;
395
+ }
396
+
397
+ .custom-footer-render-id {
398
+ width: auto;
399
+ color: #888;
400
+ text-align: right;
401
+ }
tui/widget_helpers.py CHANGED
@@ -1,8 +1,11 @@
1
1
  """Widget update helper utilities for Plain2Code TUI."""
2
2
 
3
+ from datetime import datetime
4
+
5
+ from textual.css.query import NoMatches
3
6
  from textual.widgets import Static
4
7
 
5
- from .components import FRIDProgress, ProgressItem, TUIComponents
8
+ from .components import FRIDProgress, ProgressItem, StructuredLogView, TUIComponents
6
9
  from .models import Substate
7
10
 
8
11
 
@@ -21,6 +24,29 @@ async def _async_clear_substates(widget: ProgressItem) -> None:
21
24
  await widget.clear_substates()
22
25
 
23
26
 
27
+ def log_to_widget(tui, level: str, message: str) -> None:
28
+ """Helper to log messages to the TUI log widget.
29
+
30
+ Args:
31
+ tui: The Plain2CodeTUI instance
32
+ level: Log level (e.g., "WARNING", "ERROR")
33
+ message: The log message
34
+ """
35
+ try:
36
+ log_widget = tui.query_one(f"#{TUIComponents.LOG_WIDGET.value}", StructuredLogView)
37
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
38
+ tui.call_later(
39
+ log_widget.add_log,
40
+ "tui.widget_helpers",
41
+ level,
42
+ message,
43
+ timestamp,
44
+ )
45
+ except Exception:
46
+ # Silently fail if log widget is not available
47
+ pass
48
+
49
+
24
50
  def update_progress_item_status(tui, widget_id: str, status: str) -> None:
25
51
  """Helper function to safely update a ProgressItem's status.
26
52
 
@@ -31,12 +57,11 @@ def update_progress_item_status(tui, widget_id: str, status: str) -> None:
31
57
  """
32
58
  try:
33
59
  widget = tui.query_one(f"#{widget_id}", ProgressItem)
34
- if widget:
35
- tui.call_later(_async_update_status, widget, status)
36
- else:
37
- raise ValueError(f"ProgressItem {widget_id} not found")
60
+ tui.call_later(_async_update_status, widget, status)
61
+ except NoMatches as e:
62
+ log_to_widget(tui, "WARNING", f"ProgressItem {widget_id} not found: {e}")
38
63
  except Exception as e:
39
- print(f"Error updating progress item {widget_id}: {e}")
64
+ log_to_widget(tui, "ERROR", f"Error updating progress item {widget_id}: {e}")
40
65
 
41
66
  if status == ProgressItem.COMPLETED:
42
67
  clear_progress_item_substates(tui, widget_id)
@@ -54,10 +79,10 @@ def update_widget_text(tui, widget_id: str, text: str) -> None:
54
79
  widget = tui.query_one(f"#{widget_id}")
55
80
  if widget and hasattr(widget, "update"):
56
81
  widget.update(text)
57
- else:
58
- raise ValueError(f"Widget {widget_id} not found")
82
+ except NoMatches as e:
83
+ log_to_widget(tui, "WARNING", f"Widget {widget_id} not found: {e}")
59
84
  except Exception as e:
60
- print(f"Error updating widget {widget_id}: {e}")
85
+ log_to_widget(tui, "ERROR", f"Error updating widget {widget_id}: {e}")
61
86
 
62
87
 
63
88
  def get_frid_progress(tui) -> FRIDProgress:
@@ -72,34 +97,6 @@ def get_frid_progress(tui) -> FRIDProgress:
72
97
  return tui.query_one(f"#{TUIComponents.FRID_PROGRESS.value}", FRIDProgress)
73
98
 
74
99
 
75
- def update_script_outputs(tui, history) -> None:
76
- """Update script output widgets from execution history.
77
-
78
- Args:
79
- tui: The Plain2CodeTUI instance
80
- history: The script execution history object
81
- """
82
- if not history:
83
- return
84
-
85
- if history.latest_unit_test_output_path:
86
- update_widget_text(
87
- tui, TUIComponents.UNIT_TEST_SCRIPT_OUTPUT_WIDGET.value, history.latest_unit_test_output_path
88
- )
89
- if history.latest_conformance_test_output_path:
90
- update_widget_text(
91
- tui,
92
- TUIComponents.CONFORMANCE_TESTS_SCRIPT_OUTPUT_WIDGET.value,
93
- history.latest_conformance_test_output_path,
94
- )
95
- if history.latest_testing_environment_output_path:
96
- update_widget_text(
97
- tui,
98
- TUIComponents.TESTING_ENVIRONMENT_SCRIPT_OUTPUT_WIDGET.value,
99
- history.latest_testing_environment_output_path,
100
- )
101
-
102
-
103
100
  def display_success_message(tui):
104
101
  widget: Static = tui.query_one(f"#{TUIComponents.RENDER_STATUS_WIDGET.value}", Static)
105
102
  widget.add_class("success")
@@ -116,6 +113,7 @@ def set_frid_progress_to_stopped(tui):
116
113
 
117
114
  for widget_id in progress_ids:
118
115
  update_progress_item_status(tui, widget_id, ProgressItem.STOPPED)
116
+ clear_progress_item_substates(tui, widget_id)
119
117
 
120
118
 
121
119
  def display_error_message(tui, error_message: str):
@@ -134,12 +132,11 @@ def update_progress_item_substates(tui, widget_id: str, substates: list[Substate
134
132
  """
135
133
  try:
136
134
  widget = tui.query_one(f"#{widget_id}", ProgressItem)
137
- if widget:
138
- tui.call_later(_async_set_substates, widget, substates)
139
- else:
140
- raise ValueError(f"ProgressItem {widget_id} not found")
135
+ tui.call_later(_async_set_substates, widget, substates)
136
+ except NoMatches as e:
137
+ log_to_widget(tui, "WARNING", f"ProgressItem {widget_id} not found: {e}")
141
138
  except Exception as e:
142
- print(f"Error updating substates for {widget_id}: {e}")
139
+ log_to_widget(tui, "ERROR", f"Error updating substates for {widget_id}: {e}")
143
140
 
144
141
 
145
142
  def clear_progress_item_substates(tui, widget_id: str) -> None:
@@ -151,9 +148,8 @@ def clear_progress_item_substates(tui, widget_id: str) -> None:
151
148
  """
152
149
  try:
153
150
  widget = tui.query_one(f"#{widget_id}", ProgressItem)
154
- if widget:
155
- tui.call_later(_async_clear_substates, widget)
156
- else:
157
- raise ValueError(f"ProgressItem {widget_id} not found")
151
+ tui.call_later(_async_clear_substates, widget)
152
+ except NoMatches as e:
153
+ log_to_widget(tui, "WARNING", f"ProgressItem {widget_id} not found: {e}")
158
154
  except Exception as e:
159
- print(f"Error clearing substates for {widget_id}: {e}")
155
+ log_to_widget(tui, "ERROR", f"Error clearing substates for {widget_id}: {e}")
File without changes