A few beginner questions #867
-
I recently ran across the "rich" library, and am thinking about using it in a project here. It looks very impressive! There are a few things I haven't figured out how to do with it yet, and I was hoping someone here might offer some suggestions... First, I have some cases where I'd like to output a block of text with every line beginning with a constant prefix. In some cases, that block might be something like a table, where rich would be doing wrapping, so the output might contain more lines than what my input started with, and also the wrapping would need to take into account the space taken up by the prefix. So far, the only thing I can think of here is to shrink the terminal width I give to rich and have it output to something like io.StringIO, and then post-process the output to add my prefix before actually outputting it. Is there a better option? Second, I have some tables I'd like to output where I'd like the horizontal line below the header to only be the width of the individual column labels, with spaces before/after that which fill the rest of the width. For example:
The "-" there could be a solid horizontal underline instead (or one of the heavy or double variants) on terminals that support it, but I'd like the width to match the column widths. I'm pretty sure this is a feature request, but I was wondering if I could potentially build this myself by subclassing the Box class. It looks like it is provided with the column widths, but I'm not sure if it has access to the display widths of the column headers. At a minimum here, I'd like to have at least one space between the columns, where the vertical separator would normally go. Alternately, is there a way to query a table object for the current column widths, so that I could build the headers outside of the table and output them separately? Finally, there are a few places in my code where I'd like to determine the display width of a string. I've built my own function for this based on unicodedata.east_asian_width, but I'm sure this is something rich must also be doing. Does it have a utility function which will return the display width of a Rich object? The Measurement class and associated measure_renderables() function looks promising, but I'm not sure that's considered a public API. I don't see it in the documentation. Thanks in advance for any advice! |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments
-
If I have understood you correctly, you could create a Table with 2 columns, were the first column contains your prefix, and the second column contains your content. If you use the Table.grid constructor it will create a table with no lines.
Does the line absolutely have to be the width of the header? Because you could use one of the box styles such as If it is essential to have the underline match the title, you could implement a renderable that renders it contents plus a line. Have a look at the Panel class which does something similar (although your underline will be simpler).
You can use the
|
Beta Was this translation helpful? Give feedback.
-
Thanks so much for the quick response, Will!
Yeah - I thought of that, but how would I know the number of copies of my prefix to put in the left column in this case? It would vary depending on the rendering of the right column (specifically the number of wraps which occurred). Is there a call which would tell me the height of a rendered object, so I can repeat the the content in the left column the right number of times?
Going with "SIMPLE" definitely gets close, along with setting show_edge=False and pad_edge=False. However, this application's UI is based on another existing tool which uses separate underlines for each column like I mentioned above, and I'm on the fence about which actually looks better. I'll experiment a bit and try it both ways. Thinking about it some more, I can probably do this by passing the column headers explicitly into a custom Box class I create, so, it would have access to both the actual width of the column and the width of the column header. I'd just need to make sure to take into account the justification and padding. The cell_len function is exactly what I was looking for to get the display width of strings. Thanks very much -- "rich" is a really amazing package. I think I'm going to have lots of fun with it! |
Beta Was this translation helpful? Give feedback.
-
Regarding outputting text with a prefix at the beginning of each line, would Console.render_lines() work here? I did an experiment where I created a Table object and got its height by calling from rich.console import Console
from rich.table import Table
table = Table(title="Star Wars Movies")
table.add_column("Released", justify="right", style="cyan", no_wrap=True)
table.add_column("Title", style="magenta")
table.add_column("Box Office", justify="right", style="green")
table.add_row("Dec 20, 2019", "Star Wars: The Rise of Skywalker", "$952,110,690")
table.add_row("May 25, 2018", "Solo: A Star Wars Story", "$393,151,347")
table.add_row("Dec 15, 2017", "Star Wars Ep. V111: The Last Jedi", "$1,332,539,889")
table.add_row("Dec 16, 2016", "Rogue One: A Star Wars Story", "$1,332,439,889")
console = Console()
height = len(console.render_lines(table))
grid = Table.grid(expand=True)
grid.add_column()
grid.add_column()
grid.add_row(height * '> \n', table)
console.print(grid) |
Beta Was this translation helpful? Give feedback.
-
That wouldn't work I'm afraid. But the principle is correct. You should probably create a new component which renders a child component with a prefix. In the Something like this (untested). class WithPrefix:
def __init__(self, renderable) -> None:
self.renderable = renderable
def __rich_console__(
self, console: Console, options: ConsoleOptions
) -> RenderResult:
render_options = options.update(width=options.max_width - 2)
lines = console.render_lines(self.renderable, render_options)
new_line = Segment("\n")
padding = Segment("> ")
for line in lines:
yield padding
yield from line
yield new_line You would use it like this: print(WithPrefix(table)) |
Beta Was this translation helpful? Give feedback.
-
Ah, very nice! I like that much better than the Grid approach. Thanks so much! One small tweak I made here was to change "width=" to "max_width=" on the setting of render_options, since that's the value it is updating. |
Beta Was this translation helpful? Give feedback.
That wouldn't work I'm afraid. But the principle is correct.
You should probably create a new component which renders a child component with a prefix. In the
__rich_console__
method call render_lines with a smaller width, then yield the prefix + line for each line.Something like this (untested).