Skip to content

Speed up line-numbered syntax word wrap#4178

Open
KRRT7 wants to merge 3 commits into
Textualize:mainfrom
KRRT7:perf/syntax-line-numbers-word-wrap
Open

Speed up line-numbered syntax word wrap#4178
KRRT7 wants to merge 3 commits into
Textualize:mainfrom
KRRT7:perf/syntax-line-numbers-word-wrap

Conversation

@KRRT7

@KRRT7 KRRT7 commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Optimizes Syntax(word_wrap=True, line_numbers=True) by wrapping each highlighted Text source line directly instead of routing every source line through Console.render_lines(...).

This stacks on #4177 and targets the remaining line-numbered wrapping path.

Chiasmus framing

Observed:
Syntax(word_wrap=True, line_numbers=True) renders each source line separately through Console.render_lines(...) so it can prefix only the first visual row with a line number.

Mirrored target:
Keep per-source-line numbering, but avoid the heavier Console.render_lines(...) pipeline by using Text.wrap(...) and rendering the wrapped rows directly.

Hypothesis:
Per-source-line render_lines calls are a meaningful share of runtime for syntax output with many line-numbered lines.

Target workload

User-visible operation: Console.print(Syntax(...)) for line-numbered, word-wrapped Python syntax output.

Workload:

code = snippets.PYTHON_SNIPPET * 120
syntax = Syntax(code=code, lexer="python", word_wrap=True, line_numbers=True)
console = Console(file=StringIO(), color_system="truecolor", legacy_windows=False, width=30)
console.print(syntax)

Environment:

  • Darwin arm64, Darwin Kernel Version 25.5.0
  • Python 3.14.6
  • Pygments 2.20.0
  • pytest 9.0.3

Performance

Before, on #4177 tip before this change:

median: 0.769979s over 7 runs
profile: 8,041 Console.render_lines calls; render_lines cumulative 1.340s

After:

median: 0.681495s over 7 runs
profile: Console.render_lines no longer appears in the top 20 cumulative functions

This is about an 11.5% speedup for the target workload.

Correctness

python3 -m pytest tests/test_syntax.py tests/test_console.py
126 passed

I also smoke-tested the new ASV benchmark method:

SyntaxLineNumbersWrappingSuite.setup()
SyntaxLineNumbersWrappingSuite.time_text_thin_terminal_heavy_wrapping()

Tradeoffs

No new cache or retained state. The implementation duplicates the small part of Console.render_lines(...) needed for this hot path: style application and fixed-width line adjustment after Text.wrap(...).

Stack

Order PR Branch Merge after
1 #4177 optimize-syntax-word-wrap main
2 #4178 perf/syntax-line-numbers-word-wrap #4177

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@9d8f9a3). Learn more about missing BASE report.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4178   +/-   ##
=======================================
  Coverage        ?   97.81%           
=======================================
  Files           ?       96           
  Lines           ?     8390           
  Branches        ?        0           
=======================================
  Hits            ?     8207           
  Misses          ?      183           
  Partials        ?        0           
Flag Coverage Δ
unittests 97.81% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants