Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions benchmarks/benchmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,71 @@ def _print_with_width(self, width):
self.console.print(self.syntax, width)


class SyntaxLineNumbersWrappingSuite:
def setup(self):
self.console = Console(
file=StringIO(), color_system="truecolor", legacy_windows=False
)
self.syntax = Syntax(
code=snippets.PYTHON_SNIPPET * 120,
lexer="python",
word_wrap=True,
line_numbers=True,
)

def time_text_thin_terminal_heavy_wrapping(self):
self.console.print(self.syntax, width=30)


class SyntaxLargeWrappingSuite:
def setup(self):
self.console = Console(
file=StringIO(), color_system="truecolor", legacy_windows=False
)
self.syntax = Syntax(
code=snippets.PYTHON_SNIPPET * 120,
lexer="python",
word_wrap=True,
line_numbers=False,
)

def time_text_thin_terminal_heavy_wrapping(self):
self.console.print(self.syntax, width=30)


class SyntaxLargeNoWrapSuite:
def setup(self):
self.console = Console(
file=StringIO(), color_system="truecolor", legacy_windows=False
)
self.syntax = Syntax(
code=snippets.PYTHON_SNIPPET * 120,
lexer="python",
word_wrap=False,
line_numbers=False,
)

def time_text_wide_terminal_no_wrapping(self):
self.console.print(self.syntax, width=80)


class SyntaxLineRangeSuite:
def setup(self):
self.console = Console(
file=StringIO(), color_system="truecolor", legacy_windows=False
)
self.syntax = Syntax(
code=snippets.PYTHON_SNIPPET * 120,
lexer="python",
word_wrap=False,
line_numbers=False,
line_range=(3000, 3060),
)

def time_text_wide_terminal_line_range(self):
self.console.print(self.syntax, width=80)


class TableSuite:
def time_table_no_wrapping(self):
self._print_table(width=100)
Expand Down
79 changes: 60 additions & 19 deletions rich/syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,9 +526,10 @@ def tokens_to_spans() -> Iterable[Tuple[str, Optional[Style]]]:
_token_type, token = next(tokens)
except StopIteration:
break
yield (token, None)
if token.endswith("\n"):
line_no += 1
if line_no:
yield ("\n" * line_no, None)
# Generate spans until line end
for token_type, token in tokens:
yield (token, _get_theme_style(token_type))
Expand Down Expand Up @@ -693,15 +694,18 @@ def _get_syntax(
text, options=options.update(width=code_width)
)
else:
syntax_lines = console.render_lines(
text,
options.update(width=code_width, height=None, justify="left"),
style=self.background_style,
pad=True,
new_lines=True,
)
for syntax_line in syntax_lines:
yield from syntax_line
for line in text.split("\n", allow_blank=True):
line_style = console.get_style(line.style, default=Style.null())
yield from Segment.adjust_line_length(
list(
Segment.apply_style(
line.render(console), self.background_style
)
),
code_width,
style=line_style,
)
yield Segment.line()
return

start_line, end_line = self.line_range or (None, None)
Expand Down Expand Up @@ -743,14 +747,51 @@ def _get_syntax(
highlight_number_style,
) = self._get_number_styles(console)

for line_no, line in enumerate(lines, self.start_line + line_offset):
if self.word_wrap:
wrapped_lines = console.render_lines(
line,
render_options.update(height=None, justify="left"),
if self.word_wrap and not self.line_numbers:
text = Text("\n").join(lines)
for wrapped_text_line in text.wrap(
console,
render_options.max_width,
justify="left",
overflow=render_options.overflow,
tab_size=self.tab_size,
no_wrap=render_options.no_wrap,
):
yield from _Segment.adjust_line_length(
list(
_Segment.apply_style(
wrapped_text_line.render(console), background_style
)
),
render_options.max_width,
style=background_style,
pad=not transparent_background,
)
yield new_line
return

for line_no, line in enumerate(lines, self.start_line + line_offset):
if self.word_wrap:
wrapped_lines = [
_Segment.adjust_line_length(
list(
_Segment.apply_style(
wrapped_line.render(console), background_style
)
),
render_options.max_width,
style=background_style,
pad=not transparent_background,
)
for wrapped_line in line.wrap(
console,
render_options.max_width,
justify="left",
overflow=render_options.overflow,
tab_size=self.tab_size,
no_wrap=render_options.no_wrap,
)
]
else:
segments = list(line.render(console, end=""))
if options.no_wrap:
Expand All @@ -769,7 +810,7 @@ def _get_syntax(
wrapped_line_left_pad = _Segment(
" " * numbers_column_width + " ", background_style
)
for first, wrapped_line in loop_first(wrapped_lines):
for first, wrapped_segments in loop_first(wrapped_lines):
if first:
line_column = str(line_no).rjust(numbers_column_width - 2) + " "
if highlight_line(line_no):
Expand All @@ -780,11 +821,11 @@ def _get_syntax(
yield _Segment(line_column, number_style)
else:
yield wrapped_line_left_pad
yield from wrapped_line
yield from wrapped_segments
yield new_line
else:
for wrapped_line in wrapped_lines:
yield from wrapped_line
for wrapped_segments in wrapped_lines:
yield from wrapped_segments
yield new_line

def _apply_stylized_ranges(self, text: Text) -> None:
Expand Down
21 changes: 21 additions & 0 deletions tests/test_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,27 @@ def test_padding_plus_wrap() -> None:
assert output == expected


def test_word_wrap_without_line_numbers_with_line_range() -> None:
console = Console(width=14, file=io.StringIO(), legacy_windows=False, record=True)
syntax = Syntax(
"first line should not appear\n"
"second line wraps around here\n"
"third line stays\n"
"fourth line should not appear",
lexer="text",
word_wrap=True,
line_numbers=False,
line_range=(2, 3),
)

console.print(syntax)

assert (
console.export_text()
== "second line \nwraps around \nhere \nthird line \nstays \n"
)


if __name__ == "__main__":
syntax = Panel.fit(
Syntax(
Expand Down
Loading