Skip to content

Commit

Permalink
link style
Browse files Browse the repository at this point in the history
  • Loading branch information
willmcgugan committed Jan 2, 2025
1 parent ccd54fd commit 273cc04
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 16 deletions.
1 change: 0 additions & 1 deletion src/textual/_styles_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ def render_widget(self, widget: Widget, crop: Region) -> list[Strip]:
and hover_style._meta
and "@click" in hover_style.meta
):
1 / 0
link_style_hover = widget.link_style_hover
if link_style_hover:
strips = [
Expand Down
69 changes: 54 additions & 15 deletions src/textual/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def get_optimal_width(self, container_width: int) -> int:
lines = self.without_spans.split("\n")
return max(line.cell_length for line in lines)

def wrap(
def _wrap_and_format(
self,
width: int,
align: TextAlign = "left",
Expand All @@ -219,8 +219,22 @@ def wrap(
tab_size: int = 8,
selection: Selection | None = None,
selection_style: Style | None = None,
) -> list[ContentLine]:
output_lines: list[ContentLine] = []
) -> list[FormattedLine]:
"""Wraps the text and applies formatting.
Args:
width: Desired width.
align: Text alignment.
overflow: Overflow method.
no_wrap: Disabled wrapping.
tab_size: Cell with of tabs.
selection: Selection information or `None` if no selection.
selection_style: Selection style, or `None` if no selection.
Returns:
List of formatted lines.
"""
output_lines: list[FormattedLine] = []

if selection is not None:
get_span = selection.get_span
Expand All @@ -236,7 +250,7 @@ def get_span(y: int) -> tuple[int, int] | None:
end = len(line.plain)
line = line.stylize(selection_style, start, end)

content_line = ContentLine(
content_line = FormattedLine(
line.expand_tabs(tab_size), width, y=y, align=align
)

Expand All @@ -246,7 +260,7 @@ def get_span(y: int) -> tuple[int, int] | None:
offsets = divide_line(line.plain, width, fold=overflow == "fold")
divided_lines = content_line.content.divide(offsets)
new_lines = [
ContentLine(
FormattedLine(
content.rstrip_end(width), width, offset, y, align=align
)
for content, offset in zip(divided_lines, [0, *offsets])
Expand Down Expand Up @@ -277,7 +291,7 @@ def render_strips(
selection_style = None

align = self._align
lines = self.wrap(
lines = self._wrap_and_format(
width,
align=align,
overflow=(
Expand All @@ -292,11 +306,11 @@ def render_strips(
if height is not None:
lines = lines[:height]

strip_lines = [line.to_strip(style) for line in lines]
strip_lines = [line.to_strip(widget, style) for line in lines]
return strip_lines

def get_height(self, width: int) -> int:
lines = self.wrap(width)
lines = self._wrap_and_format(width)
return len(lines)

def __len__(self) -> int:
Expand Down Expand Up @@ -982,7 +996,9 @@ def highlight_regex(
return Content(self._text, spans)


class ContentLine:
class FormattedLine:
"""A line of content with additional formatting information."""

def __init__(
self,
content: Content,
Expand All @@ -991,13 +1007,15 @@ def __init__(
y: int = 0,
align: TextAlign = "left",
line_end: bool = False,
link_style: Style | None = None,
) -> None:
self.content = content
self.width = width
self.x = x
self.y = y
self.align = align
self.line_end = line_end
self.link_style = link_style
self.highlight_style: Style | None = None
self.highlight_range: tuple[int | None, int | None] | None = None

Expand All @@ -1009,7 +1027,7 @@ def highlight(self, style: Style, start: int | None, end: int | None) -> None:
self.highlight_style = style
self.highlight_range = (start, end)

def to_strip(self, style: Style) -> Strip:
def to_strip(self, widget: Widget, style: Style) -> Strip:
_Segment = Segment
align = self.align
width = self.width
Expand All @@ -1024,8 +1042,6 @@ def to_strip(self, style: Style) -> Strip:

if align in ("start", "left") or (align == "justify" and self.line_end):
pass
# pad_right = width - self.content.cell_length
# pad_right = 0

elif align == "center":
excess_space = width - self.content.cell_length
Expand Down Expand Up @@ -1061,7 +1077,7 @@ def to_strip(self, style: Style) -> Strip:
if index < len(spaces) and (pad := spaces[index]):
add_segment(_Segment(" " * pad, (style + text_style).rich_style))

strip = Strip(segments, width)
strip = Strip(self._apply_link_style(widget, segments), width)
return strip

segments = (
Expand All @@ -1080,9 +1096,32 @@ def to_strip(self, style: Style) -> Strip:
segments.append(
_Segment(" " * pad_right, style.background_style.rich_style)
)
strip = Strip(segments, content.cell_length + pad_left + pad_right)
strip = Strip(
self._apply_link_style(widget, segments),
content.cell_length + pad_left + pad_right,
)
return strip

def _apply_link_style(
self, widget: Widget, segments: list[Segment]
) -> list[Segment]:
link_style = widget.link_style
_Segment = Segment
segments = [
_Segment(
text,
(
style
if style._meta is None
else (style + link_style if "@click" in style.meta else style)
),
control,
)
for text, style, control in segments
if style is not None
]
return segments


if __name__ == "__main__":
from rich import print
Expand Down Expand Up @@ -1116,7 +1155,7 @@ def to_strip(self, style: Style) -> Strip:
"will", Style(background=Color.parse("rgba(255, 255, 20, 0.3)"))
)

lines = content.wrap(40, align="full")
lines = content._wrap_and_format(40, align="full")
print(lines)
print("x" * 40)
for line in lines:
Expand Down
1 change: 1 addition & 0 deletions src/textual/visual.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ def render_strips(
render_width = width - (left + right)
if render_width <= 0:
return []

strips = self._visual.render_strips(
widget,
render_width,
Expand Down

0 comments on commit 273cc04

Please sign in to comment.