charmbracelet/glamour

`Render` fills shorter lines with spaces

gsalvatella opened this issue · 5 comments

The following program:

func main() {
	txt, _ := glamour.Render("Hello World", "auto")
	fmt.Printf(strings.Replace(txt, " ", "_", -1))
}

Produces the following output:

__Hello_World_________________________________________________________________

The rendering engine adds spaces to every line until the value of WordWrap (80 by default). This resizes shorter strings and prevents lipgloss.{Width,Height} from measuring the actual size of a cell. Notice that strings.TrimSpace() won't work here. The spaces are intermingled with escape codes in a convoluted way. You can test this by writing txt to a file. Is this the intended behavior?

I believe that is expected due to the nature of TUIs. In order to respect the widths defined by the user, in this case 80 characters, it needs to get filled with whitespace to make that width consistent across all lines. Otherwise any borders would be staggered depending on the width of each line.

Is this blocking something for you? We might be able to find a workaround if we have a better idea of what you're trying to do :)

Let's say you want to center some glamorous text in the screen:

txt, _ := glamour.Render("Hello World", "auto")
vp, hp := viewport.Height - lipgloss.Height(txt), viewport.Width - lipgloss.Width(txt)
txt = lipgloss.NewStyle().Padding(vp/2, hp/2).Render(txt)

This will not work because the W and H that lipgloss measures are incorrect.

In order to respect the widths defined by the user

The word wrap width should have nothing to do with the margin or padding. The reflow library itself doesn't add any blank spaces for text shorter than the wrap width. The blank space addition happens here. It seems that BlockStack.Width computes the "available rendering width" using the passed WordWrap option, instead of the actual width of the stack.

If at all, I would say that padding and margin should be the ones defining the word wrap width, as it happens in e.g. HTML/CSS, and not the other way around?

@gsalvatella ah gotcha, thank you so much for the info and context!
@muesli any thoughts on this one?

We pad the content to ensure the background color gets rendered.

So the background width is set throught the WordWrap option? Why should glamour be anyway responsible for the background or the document layout? Don't you think this would be better handled in a higher level lib like a bubble (e.g viewport)? This would make glamour seamlessly integrate with lipgloss to create layouts containing rendered markdown in a flexible way, while resembling more the behavior of goldmark