You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Use PPrint to handle printing of REPL output values (#23849)
This PR demonstrates using the https://github.com/com-lihaoyi/PPrint
library to handle pretty-printing of values in the REPL.
Visible improvements:
- Data structures like sequences and case classes are now nicely
formatted and indented, including deeply nested data structures, to make
best use of the vertical and horizontal space available
- Strings are consistently quoted in collections and case classes,
rather than sometimes quoted and sometimes not.
- The rendering of `Seq("")` and `Seq()` is no longer identical
(sometimes!)
- Unusual characters within strings are now properly quoted, rather than
being butchered during the rendering
- (not shown) Character literals like `'X'` are properly pretty-printed
with quotes
- Adjustments to the syntax highlighting colour scheme, making it
subjectively easier to read and converging it with the scheme used by
`pprint`'s own internal highlighter:
- Unified `StringColor` and `LiteralColor` as green rather than red.
This should help avoid the red of literals being visually confused with
the red of error messages when pretty printing code during compilation
errors, which is something I have had problems with in the past
- Highlighted capitalized identifies like `Foo` or `Seq` or `List`,
since the vast majority of these identifiers are likely to be the
companion object of types, and highlighting them helps greatly in
visually finding your way around pretty-printed data structures
Before:
<img width="976" height="659" alt="Screenshot 2025年09月01日 at 9 42 52 AM"
src="https://github.com/user-attachments/assets/1f082d42-7ac3-4785-b957-029e96603819"
/>
After:
<img width="976" height="835" alt="Screenshot 2025年09月01日 at 1 41 05 PM"
src="https://github.com/user-attachments/assets/847e6210-eb3d-40f9-a96c-5fc658cb1de4"
/>
Notes:
* This PR only uses PPrint for formatting and not coloring, relying on
the existing REPL code that deals with syntax highlighting (with
tweaks). Using PPrint's highlighter directly would require a larger
refactor that can come in a follow up iff we decide to do so
* We build pprint/fansi/sourcecode from source using `sourceGenerators`.
This requires a bit of patching to work around `-Xexplicit-nulls` and
`-Xfatal-warnings`, but otherwise is straightforward and means for all
intents and purposes it's just part of the Dotty codebase. We mangle the
package paths to make them `dotty.shaded.*` packages to avoid conflict
with user code
* The verbosity of `PPrint` can be configured, e.g. we can decide
whether we want to print field names or not. By default it prints field
names for any `case class` with more than `1` field
I set the default pprint dimensions to width=100 height=50, and added a
`import dotty.shaded.pprint.pprintln` to the predef of every REPL so
users have `pprintln` available in scope. Users who want to print more
than 50 lines can call `pprintln` which prints up to 100x500 by default,
and can take a custom `height=9999` if they want to print more.
The numbers 100x50 and 100x500 are heuristics:
- 100x50 as the default for echo-ed values is a heuristic optimizing for
terminal use, where width=100 approximates the common maximum width
people tend to format their code to (typically 80-120), and 50 reflects
about 0.5 to 1 vertical screenful of text so it doesn't kick previous
terminal output off the top of your terminal
- 100x500 as the default for `pprintln` is a heuristic optimizing for
non-terminal use: it's about 5-10 vertical screenfuls of text, and about
the limit of what we expect people to usefully be able to skim through.
Typically, in most cases when the output is larger than this, you'd want
to cut it down by selecting a subset of the output programmatically.
- If the user really wants to print everything, they can run
`pprintln(foo, height=99999)` or similar
The heuristics can be tweaked, but they should provide a decent baseline
for printing a useful amount of output to screen without flooding the
user's terminal.
TODO/Future-Work:
* Automatically select max height/width based on terminal size, and
provide a helper (similar to Ammonite's `show(...)`) to bypass the max
height. For now, it's fixed at the default width of 100 columns
* We can use the same approach to make use of `os-lib` and other
libraries within `scala3-compiler` by building them from source
* Make use of `fansi` elsewhere in the dotty codebase. e.g. the
highlighting of stack traces via the code syntax highlighter is super
ugly and could be cleaned up:
<img width="675" height="259" alt="Screenshot 2025年09月01日 at 1 09 22 PM"
src="https://github.com/user-attachments/assets/47515039-b2e1-4299-86fe-22fd2c199958"
/>
0 commit comments