|
36 | 36 | process_prompt as build_prompt_content, |
37 | 37 | ) |
38 | 38 | from .layout import LayoutMap, LayoutResult, LayoutRow, WrappedRow, layout_content_lines |
39 | | -from .render import RenderCell, RenderLine, RenderedScreen, StyleRef |
| 39 | +from .render import RenderCell, RenderLine, RenderedScreen, ScreenOverlay, StyleRef |
40 | 40 | from .utils import ANSI_ESCAPE_SEQUENCE, wlen, gen_colors |
41 | 41 | from .trace import trace |
42 | 42 |
|
@@ -380,7 +380,7 @@ def collect_keymap(self) -> tuple[tuple[KeySpec, CommandName], ...]: |
380 | 380 | return default_keymap |
381 | 381 |
|
382 | 382 | def calc_screen(self) -> RenderedScreen: |
383 | | - """Translate changes in self.buffer into a structured rendered screen.""" |
| 383 | + """Translate the editable buffer into a base rendered screen.""" |
384 | 384 | num_common_lines = 0 |
385 | 385 | offset = 0 |
386 | 386 | if self.last_refresh_cache.valid(self): |
@@ -427,12 +427,7 @@ def calc_screen(self) -> RenderedScreen: |
427 | 427 | layout_rows, |
428 | 428 | last_refresh_line_end_offsets, |
429 | 429 | ) |
430 | | - |
431 | | - render_lines = base_render_lines.copy() |
432 | | - render_lines.extend(self._render_message_lines()) |
433 | | - |
434 | | - self.rendered_screen = RenderedScreen(tuple(render_lines), self.cxy) |
435 | | - return self.rendered_screen |
| 430 | + return RenderedScreen(tuple(base_render_lines), self.cxy) |
436 | 431 |
|
437 | 432 | def _buffer_refresh_from_pos(self) -> int | None: |
438 | 433 | buffer_from_pos = self.invalidation.buffer_rebuild_from_pos |
@@ -536,13 +531,25 @@ def _render_wrapped_rows( |
536 | 531 | for row in wrapped_rows |
537 | 532 | ] |
538 | 533 |
|
539 | | - def _render_message_lines(self) -> list[RenderLine]: |
| 534 | + def _render_message_lines(self) -> tuple[RenderLine, ...]: |
540 | 535 | if not self.msg: |
541 | | - return [] |
542 | | - return [ |
| 536 | + return () |
| 537 | + return tuple( |
543 | 538 | RenderLine.from_rendered_text(message_line) |
544 | 539 | for message_line in self.msg.split("\n") |
545 | | - ] |
| 540 | + ) |
| 541 | + |
| 542 | + def get_screen_overlays(self) -> tuple[ScreenOverlay, ...]: |
| 543 | + return () |
| 544 | + |
| 545 | + def compose_rendered_screen(self, base_screen: RenderedScreen) -> RenderedScreen: |
| 546 | + overlays = list(self.get_screen_overlays()) |
| 547 | + message_lines = self._render_message_lines() |
| 548 | + if message_lines: |
| 549 | + overlays.append(ScreenOverlay(len(base_screen.lines), message_lines)) |
| 550 | + if not overlays: |
| 551 | + return base_screen |
| 552 | + return RenderedScreen(base_screen.lines, base_screen.cursor, tuple(overlays)) |
546 | 553 |
|
547 | 554 | def _render_line( |
548 | 555 | self, |
@@ -754,7 +761,8 @@ def prepare(self) -> None: |
754 | 761 | self.rendered_screen = RenderedScreen.empty() |
755 | 762 | self.invalidate_full() |
756 | 763 | self.last_command = None |
757 | | - self.calc_screen() |
| 764 | + base_screen = self.calc_screen() |
| 765 | + self.rendered_screen = self.compose_rendered_screen(base_screen) |
758 | 766 | except BaseException: |
759 | 767 | self.restore() |
760 | 768 | raise |
@@ -813,7 +821,9 @@ def update_screen(self) -> None: |
813 | 821 | def refresh(self) -> None: |
814 | 822 | """Recalculate and refresh the screen.""" |
815 | 823 | # this call sets up self.cxy, so call it first. |
816 | | - rendered_screen = self.calc_screen() |
| 824 | + base_screen = self.calc_screen() |
| 825 | + rendered_screen = self.compose_rendered_screen(base_screen) |
| 826 | + self.rendered_screen = rendered_screen |
817 | 827 | trace( |
818 | 828 | "reader.refresh cursor={cursor} lines={lines} " |
819 | 829 | "dims=({width},{height}) invalidation={invalidation}", |
|
0 commit comments