Skip to content

Commit

Permalink
refactor of tab_size
Browse files Browse the repository at this point in the history
  • Loading branch information
willmcgugan committed Jul 28, 2023
1 parent f25cb16 commit 7a15d62
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 20 deletions.
38 changes: 21 additions & 17 deletions rich/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class Text(JupyterMixin):
overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None.
no_wrap (bool, optional): Disable text wrapping, or None for default. Defaults to None.
end (str, optional): Character to end text with. Defaults to "\\\\n".
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to 8.
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to None.
spans (List[Span], optional). A list of predefined style spans. Defaults to None.
"""

Expand All @@ -148,7 +148,7 @@ def __init__(
overflow: Optional["OverflowMethod"] = None,
no_wrap: Optional[bool] = None,
end: str = "\n",
tab_size: Optional[int] = 8,
tab_size: Optional[int] = None,
spans: Optional[List[Span]] = None,
) -> None:
sanitized_text = strip_control_codes(text)
Expand Down Expand Up @@ -307,7 +307,7 @@ def from_ansi(
overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None.
no_wrap (bool, optional): Disable text wrapping, or None for default. Defaults to None.
end (str, optional): Character to end text with. Defaults to "\\\\n".
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to 8.
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to None.
"""
from .ansi import AnsiDecoder

Expand Down Expand Up @@ -369,7 +369,7 @@ def assemble(
justify (str, optional): Justify method: "left", "center", "full", "right". Defaults to None.
overflow (str, optional): Overflow method: "crop", "fold", "ellipsis". Defaults to None.
end (str, optional): Character to end text with. Defaults to "\\\\n".
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to 8.
tab_size (int): Number of spaces per tab, or ``None`` to use ``console.tab_size``. Defaults to None.
meta (Dict[str, Any], optional). Meta data to apply to text, or None for no meta data. Default to None
Returns:
Expand Down Expand Up @@ -576,14 +576,14 @@ def extend_style(self, spaces: int) -> None:
new_spaces = " " * spaces
if spans:
end_offset = len(self)
self._spans = [
self._spans[:] = [
span.add_padding(spaces) if span.end >= end_offset else span
for span in spans
]
self._text.append(new_spaces)
self._length += spaces
else:
self += new_spaces
self.plain += new_spaces

def highlight_regex(
self,
Expand Down Expand Up @@ -682,7 +682,7 @@ def set_length(self, new_length: int) -> None:
def __rich_console__(
self, console: "Console", options: "ConsoleOptions"
) -> Iterable[Segment]:
tab_size: int = console.tab_size or self.tab_size or 8
tab_size: int = console.tab_size if self.tab_size is None else self.tab_size
justify = self.justify or options.justify or DEFAULT_JUSTIFY

overflow = self.overflow or options.overflow or DEFAULT_OVERFLOW
Expand Down Expand Up @@ -824,18 +824,22 @@ def expand_tabs(self, tab_size: Optional[int] = None) -> None:
result = self.blank_copy()
append = result.append

_style = self.style
for line in self.split("\n", include_separator=True):
parts = line.split("\t", include_separator=True)
tab_parts: list[Text] = []
for part in parts:
if part.plain.endswith("\t"):
part.right_crop(1)
pos += len(part)
spaces = tab_size - ((pos - 1) % tab_size)
if spaces:
part._text[-1] = part._text[-1][:-1] + " "
pos += part.cell_len
tab_remainder = pos % tab_size
if tab_remainder:
spaces = tab_size - (pos % tab_size)
part.extend_style(spaces)
pos += spaces
append(part)
else:
pos += part.cell_len
tab_parts.append(part)
append(Text("").join(tab_parts))

self._text = [result.plain]
self._length = len(self.plain)
Expand Down Expand Up @@ -967,7 +971,7 @@ def append(
self._text.append(sanitized_text)
offset = len(self)
text_length = len(sanitized_text)
if style is not None:
if style:
self._spans.append(Span(offset, offset + text_length, style))
self._length += text_length
elif isinstance(text, Text):
Expand All @@ -977,7 +981,7 @@ def append(
"style must not be set when appending Text instance"
)
text_length = self._length
if text.style is not None:
if text.style:
self._spans.append(
_Span(text_length, text_length + len(text), text.style)
)
Expand All @@ -998,7 +1002,7 @@ def append_text(self, text: "Text") -> "Text":
"""
_Span = Span
text_length = self._length
if text.style is not None:
if text.style:
self._spans.append(_Span(text_length, text_length + len(text), text.style))
self._text.append(text.plain)
self._spans.extend(
Expand All @@ -1025,7 +1029,7 @@ def append_tokens(
offset = len(self)
for content, style in tokens:
append_text(content)
if style is not None:
if style:
append_span(_Span(offset, offset + len(content), style))
offset += len(content)
self._length = offset
Expand Down
6 changes: 3 additions & 3 deletions tests/test_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ def test_render_size():
expected = [
[
Segment("╭─", Style()),
Segment("──────────────────────────────────", Style()),
Segment(" Hello ", Style()),
Segment("───────────────────────────────────", Style()),
Segment(
"────────────────────────────────── Hello ───────────────────────────────────"
),
Segment("─╮", Style()),
],
[
Expand Down
38 changes: 38 additions & 0 deletions tests/test_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,44 @@ def test_tabs_to_spaces():
assert text.plain == "No Tabs"


@pytest.mark.parametrize(
"markup,tab_size,expected_text,expected_spans",
[
("", 4, "", []),
("\t", 4, " ", []),
("\tbar", 4, " bar", []),
("foo\tbar", 4, "foo bar", []),
(
"[bold]foo\tbar",
4,
"foo bar",
[
Span(0, 4, "bold"),
Span(4, 7, "bold"),
],
),
("[bold]\tbar", 4, " bar", [Span(0, 4, "bold"), Span(4, 7, "bold")]),
(
"\t[bold]bar",
4,
" bar",
[
Span(4, 7, "bold"),
],
),
],
)
def test_tabs_to_spaces_spans(
markup: str, tab_size: int, expected_text: str, expected_spans: list[Span]
):
"""Test spans are correct after expand_tabs"""
text = Text.from_markup(markup)
text.expand_tabs(tab_size)
print(expected_spans)
assert text.plain == expected_text
assert text._spans == expected_spans


def test_markup_switch():
"""Test markup can be disabled."""
console = Console(file=StringIO(), markup=False)
Expand Down

0 comments on commit 7a15d62

Please sign in to comment.