Skip to content

Commit 0177c2d

Browse files
committed
Add more docstrings/comments
1 parent 4f68c04 commit 0177c2d

File tree

6 files changed

+47
-1
lines changed

6 files changed

+47
-1
lines changed

Lib/_pyrepl/content.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class PromptContent:
2121

2222
@dataclass(frozen=True, slots=True)
2323
class SourceLine:
24+
"""One logical line from the editor buffer, before styling."""
25+
2426
lineno: int
2527
text: str
2628
start_offset: int
@@ -59,6 +61,7 @@ def build_body_fragments(
5961
colors: list[ColorSpan] | None,
6062
start_index: int,
6163
) -> tuple[ContentFragment, ...]:
64+
"""Convert a line's text into styled content fragments."""
6265
# Two separate loops to avoid the THEME() call in the common uncolored path.
6366
if colors is None:
6467
return tuple(

Lib/_pyrepl/layout.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Wrap content lines to the terminal width before rendering."""
2+
13
from __future__ import annotations
24

35
from dataclasses import dataclass
@@ -9,6 +11,7 @@
911

1012
@dataclass(frozen=True, slots=True)
1113
class LayoutRow:
14+
"""Metadata for one physical screen row."""
1215
prompt_width: int
1316
char_widths: tuple[int, ...]
1417
suffix_width: int = 0
@@ -28,6 +31,10 @@ def screeninfo(self) -> ScreenInfoRow:
2831

2932
@dataclass(frozen=True, slots=True)
3033
class LayoutMap:
34+
"""Mapping between buffer positions and screen coordinates.
35+
36+
Single source of truth for cursor placement.
37+
"""
3138
rows: tuple[LayoutRow, ...]
3239

3340
@classmethod
@@ -95,6 +102,7 @@ def xy_to_pos(self, x: int, y: int) -> int:
95102

96103
@dataclass(frozen=True, slots=True)
97104
class WrappedRow:
105+
"""One physical screen row after wrapping, with all metadata needed for rendering."""
98106
prompt_text: str = ""
99107
prompt_width: int = 0
100108
fragments: tuple[ContentFragment, ...] = ()
@@ -116,6 +124,10 @@ def layout_content_lines(
116124
width: int,
117125
start_offset: int,
118126
) -> LayoutResult:
127+
"""Wrap content lines to fit *width* columns.
128+
129+
Line boundaries are marked with ``\\``.
130+
"""
119131
if width <= 0:
120132
return LayoutResult((), LayoutMap(()), ())
121133

@@ -140,6 +152,7 @@ def layout_content_lines(
140152
body = tuple(line.body)
141153
body_widths = tuple(fragment.width for fragment in body)
142154

155+
# Fast path: line fits on one row.
143156
if not body_widths or (sum(body_widths) + prompt_width) < width:
144157
offset += len(body) + newline_advance
145158
line_end_offsets.append(offset)
@@ -161,11 +174,13 @@ def layout_content_lines(
161174
)
162175
continue
163176

177+
# Slow path: line needs wrapping.
164178
current_prompt = prompt_text
165179
current_prompt_width = prompt_width
166180
start = 0
167181
total = len(body)
168182
while True:
183+
# Find how many characters fit on this row.
169184
index_to_wrap_before = 0
170185
column = 0
171186
for char_width in body_widths[start:]:

Lib/_pyrepl/reader.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ def make_default_commands() -> dict[CommandName, CommandClass]:
157157

158158
@dataclass(frozen=True, slots=True)
159159
class RefreshInvalidation:
160+
"""Parts of the screen state that have changed and need to be refreshed."""
161+
160162
cursor_only: bool = False
161163
buffer_from_pos: int | None = None
162164
prompt: bool = False
@@ -308,6 +310,8 @@ class Reader:
308310
## cached metadata to speed up screen refreshes
309311
@dataclass
310312
class RefreshCache:
313+
"""Previously computed render/layout data for incremental refresh."""
314+
311315
render_lines: list[RenderLine] = field(default_factory=list)
312316
layout_rows: list[LayoutRow] = field(default_factory=list)
313317
line_end_offsets: list[int] = field(default_factory=list)
@@ -412,6 +416,7 @@ def calc_screen(self) -> RenderedScreen:
412416
)
413417
and (self.invalidation.message or self.invalidation.overlay)
414418
):
419+
# Fast path: only overlays or messages changed.
415420
offset, num_common_lines = self.last_refresh_cache.get_cached_location(
416421
self,
417422
reuse_full=True,

Lib/_pyrepl/render.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919

2020
class _ThemeSyntax(Protocol):
21+
"""Protocol for theme objects that map tag names to SGR escape strings."""
2122
def __getitem__(self, key: str, /) -> str: ...
2223

2324

@@ -173,9 +174,11 @@ def _compose(self) -> tuple[RenderLine, ...]:
173174
"overlays must be sorted by ascending y"
174175
)
175176
if overlay.insert:
177+
# Splice overlay lines in, pushing existing content down.
176178
lines[adjusted_y:adjusted_y] = overlay.lines
177179
y_offset += len(overlay.lines)
178180
else:
181+
# Replace existing lines at the overlay position.
179182
target_len = adjusted_y + len(overlay.lines)
180183
if len(lines) < target_len:
181184
lines.extend([EMPTY_RENDER_LINE] * (target_len - len(lines)))
@@ -250,10 +253,13 @@ class LineUpdate:
250253
y: int
251254
start_cell: int
252255
start_x: int
256+
"""Screen x-coordinate where the update begins. Used for cursor positioning."""
253257
cells: tuple[RenderCell, ...]
254258
char_width: int = 0
255259
clear_eol: bool = False
256260
reset_to_margin: bool = False
261+
"""If True, the console must resync the cursor position after writing
262+
(needed when cells contain non-SGR escape sequences that may move the cursor)."""
257263
text: str = field(init=False, default="")
258264

259265
def __post_init__(self) -> None:
@@ -273,6 +279,14 @@ def render_cells(
273279
cells: Sequence[RenderCell],
274280
visual_style: str | None = None,
275281
) -> str:
282+
"""Render a sequence of cells into a terminal string with SGR escapes.
283+
284+
Tracks the active SGR state to emit resets only when the style
285+
actually changes, minimizing output bytes.
286+
287+
If *visual_style* is given (used by redraw visualization), it is appended
288+
to every cell's style.
289+
"""
276290
rendered: list[str] = []
277291
active_escape = ""
278292
for cell in cells:
@@ -305,6 +319,8 @@ def diff_render_lines(old: RenderLine, new: RenderLine) -> LineDiff | None:
305319
start_x = 0
306320
max_prefix = min(len(old.cells), len(new.cells))
307321
while prefix < max_prefix and old.cells[prefix] == new.cells[prefix]:
322+
# Stop at any cell with non-SGR controls, since those might affect
323+
# cursor position and must be re-emitted.
308324
if old.cells[prefix].controls:
309325
break
310326
start_x += old.cells[prefix].width

Lib/_pyrepl/unix_console.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,19 @@ def poll(self, timeout: float | None = None) -> list[int]:
152152
@dataclass(frozen=True, slots=True)
153153
class UnixRefreshPlan:
154154
grow_lines: int
155+
"""Number of blank lines to append at the bottom to accommodate new content."""
155156
use_tall_mode: bool
157+
"""Use absolute cursor addressing via ``cup`` instead of relative moves.
158+
Activated when content exceeds one screen height."""
156159
offset: int
160+
"""Vertical scroll offset: the buffer row displayed at the top of the terminal window."""
157161
reverse_scroll: int
162+
"""Number of lines to scroll backwards (content moves down)."""
158163
forward_scroll: int
164+
"""Number of lines to scroll forwards (content moves up)."""
159165
line_updates: tuple[LineUpdate, ...]
160166
cleared_lines: tuple[int, ...]
167+
"""Row indices to erase (old content with no replacement)."""
161168
rendered_screen: RenderedScreen
162169
cursor: tuple[int, int]
163170

Lib/_pyrepl/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ def prev_next_window[T](
437437

438438
@dataclass(frozen=True, slots=True)
439439
class StyleRef:
440-
tag: str | None = None
440+
tag: str | None = None # From THEME().syntax, e.g. "keyword", "builtin"
441441
sgr: str = ""
442442

443443
@classmethod

0 commit comments

Comments
 (0)