Extra newlines in console.render_lines
output
#2051
-
I'm trying to write a custom >>> rich.print(Message("Hello, world!"))
│ Message
│
│ Hello, world! The problem is, multi-line messages have newlines in places I don't expect. # My output looks like this
>>> rich.print(Message("Hello\nWorld!"))
│ Message
│
│ Hello
│ World! Here's the really weird thing... when I copy and paste the output of the terminal into GitHub here, the extra newlines actually disappear. I had to manually add the newline between "Hello" and "World" above to show you what the result looks like in my terminal. # Copying and pasting the output looks like this
>>> rich.print(Message("Hello\nWorld!"))
│ Message
│
│ Hello
│ World! The method I'm using is below... for reference, the whole class is at the bottom of this post. Does anyone see anything glaringly wrong with the def __rich_console__(self, console: Console, options: ConsoleOptions) -> Iterable[Segment]:
"""Render the message as a rich string."""
from rich.segment import Segment, Segments
from rich.text import Text
from rich.padding import Padding
header = Text(self.header.rstrip(), style = console.get_style(self.header_style), end = "") if isinstance(self.header, str) else self.header
separator = Segment("│ ", style = console.get_style(self.header_style))
content = Text(self.content, style = console.get_style(self.style), end = "") if isinstance(self.content, str) else self.content
content = Padding(content, (0, 3, 0, 0))
yield separator
yield header
yield Segment.line()
yield separator
yield Segment.line()
for line in console.render_lines(content, options = options, style = console.get_style(self.style), new_lines=True):
yield separator
yield from line Full Class"""Rich-formatted types!
More to come!
"""
from dataclasses import dataclass
from os import sep
from typing import Iterable
from rich.segment import Segment
from rich.style import Style
from rich.text import Text
from rich.console import Console, ConsoleOptions, Measurement, ConsoleRenderable
@dataclass(frozen=False, slots=True, repr=False, unsafe_hash=True)
class Message:
"""A rich-formatted message, with built-in themes!
More to come!
"""
content: str | ConsoleRenderable
style: str | Style = "none"
header: str | Text = "Message"
header_style: str | Style = "bold"
def __str__(self) -> str:
"""Render the message as a str."""
return str(self.content)
def __repr__(self) -> str:
return f"Message(content={self.content}, style={self.style}, header={self.header}, header_style={self.header_style})"
def __rich_console__(self, console: Console, options: ConsoleOptions) -> Iterable[Segment]:
"""Render the message as a rich string."""
from rich.segment import Segment, Segments
from rich.text import Text
from rich.padding import Padding
header = Text(self.header.rstrip(), style = console.get_style(self.header_style), end = "") if isinstance(self.header, str) else self.header
separator = Segment("│ ", style = console.get_style(self.header_style))
content = Text(self.content, style = console.get_style(self.style), end = "") if isinstance(self.content, str) else self.content
content = Padding(content, (0, 3, 0, 0))
yield separator
yield header
yield Segment.line()
yield separator
yield Segment.line()
for line in console.render_lines(content, options = options, style = console.get_style(self.style), new_lines=True):
yield separator
yield from line
def __rich_measure__(self, console: Console, options: ConsoleOptions) -> Measurement:
"""Measure the message."""
from math import floor
return Measurement(
floor(len(self.header) * 1.25) if self.header else 8,
options.max_width
)
@classmethod
def note(cls, content: ConsoleRenderable, style: str | Style = "none", header: str = "Note", header_style: str | Style = "bold violet") -> "Message":
"""A note message."""
return cls(content, style, header, header_style)
@classmethod
def tip(cls, content: ConsoleRenderable, style: str | Style = "none", header: str = "Tip", header_style: str | Style = "bold green") -> "Message":
"""A tip message."""
return cls(content, style, header, header_style)
@classmethod
def info(cls, content: ConsoleRenderable, style: str | Style = "none", header: str = "Info", header_style: str | Style = "bold cyan") -> "Message":
"""An info message."""
return cls(content, style, header, header_style)
@classmethod
def warning(cls, content: ConsoleRenderable, style: str | Style = "none", header: str = "Info", header_style: str | Style = "bold orange3") -> "Message":
"""A warning message."""
return cls(content, style, header, header_style)
@classmethod
def danger(cls, content: ConsoleRenderable, style: str | Style = "none", header: str = "Info", header_style: str | Style = "bold red") -> "Message":
"""A danger message."""
return cls(content, style, header, header_style)
del (
Iterable,
Segment,
Style,
Text,
Console,
ConsoleOptions,
Measurement,
ConsoleRenderable,
) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
The problem there is not new lines, but spaces. You are writing spaces past the ned of the line which wrap and push the following line down. That's why you don't see any new lines when you cut and paste them.
|
Beta Was this translation helpful? Give feedback.
The problem there is not new lines, but spaces. You are writing spaces past the ned of the line which wrap and push the following line down. That's why you don't see any new lines when you cut and paste them.
render_lines
is padding to the full width and your separator segment is adding a few characters. You can tell render_lines to adjust to a smaller space by doingoptions=options.update_width(options.width - 2)
. Alternatively you can setpad=False
onrender_lines
so that it doesn't add spaces.