Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style.Width() and Style.GetHorizontalFrameSize() both include padding #298

Open
qualidafial opened this issue May 18, 2024 · 2 comments · May be fixed by #450
Open

Style.Width() and Style.GetHorizontalFrameSize() both include padding #298

qualidafial opened this issue May 18, 2024 · 2 comments · May be fixed by #450
Labels
documentation Improvements or additions to documentation

Comments

@qualidafial
Copy link

I am attempting to render a block of content to some size (e.g. to fill up the full width of the terminal). Based on the API docs, I intuitively expected to be able to do so using code like this:

style := lipgloss.NewStyle().Padding(0, 2).Border(lipgloss.NormalBorder(), true)
contentWidth := m.Width - style.GetHorizontalFrameSize()
rendered := style.Width(contentWidth).Render(content)

However when you dig down into the code, Style.Width sets the width including padding, and GetHorizontalFrameSize() also includes the padding width. So in the above case, contentWidth ends up being 4 spaces narrower than wanted.

Part of this stems from the current Style.Width(int) docs, which aren't very specific about what's happening:

Width sets the width of the block before applying margins. The width, if set, also determines where text will wrap.

Margins are mentioned, but padding and borders are not. It would be helpful if the documentation was more explicit about how each property will be used and which frame elements are and are not included in the width.

I attempted to use Style.MaxWidth(int) instead, but this causes the content to be truncated rather than word wrapped like what happens with Style.Width(int).

We could really use APIs that make it easier and more intuitive to set style sizes in order to achieve the layouts we want.

One option would be the ability to set the content size, where content is mutually exclusive from the frame sizes:

style := lipgloss.NewStyle().Padding(0, 2).Border(lipgloss.NormalBorder(), true)
contentWidth := m.Width - style.GetHorizontalFrameSize()
rendered := style.ContentWidth(contentWidth).Render(content)

However I think the most useful option would be to add methods that set the overall size of the content and frame together:

style := lipgloss.NewStyle().Padding(0, 2).Border(lipgloss.NormalBorder(), true)
rendered := style.OverallWidth(m.Width).Render(content)

With the expectation that the content would be word wrapped / truncated to overallWidth - horizontalFrameWidth.

@bashbunni bashbunni added the documentation Improvements or additions to documentation label Aug 20, 2024
@bashbunni
Copy link
Member

Hey, I'll update the documentation of Width to mention borders and padding. I don't know if I'm understanding the rest of the problem you're describing. When you set the width on a style that is the total amount of cells that styled block will take up. If you have set padding or borders, it will factor those in when wrapping the text. You're likely encountering a narrower output because you're using the size of contentWidth to size the entire styled block, so the actual text width ends up being contentWidth - style.GetHorizontalFrameSize().

You don't need to do those calculations, just set the width of the block that you want along with the other styles and it will calculate the text wrapping for you. Let me know if this clears anything up for you or if it would be helpful for a little sketch to describe what I've said here :)

@bashbunni
Copy link
Member

bashbunni commented Dec 2, 2024

That said, I just noticed we aren't accounting for border in Width which we will fix :) The behaviour should be that when you set Width on a style, that is the total width of that block of content

Edit: here's a runnable example

func TestWidth(t *testing.T) {
	width, _, _ := term.GetSize(os.Stdout.Fd())
	content := "The Romans learned from the Greeks that quinces slowly cooked with honey would “set” when cool. The Apicius gives a recipe for preserving whole quinces, stems and leaves attached, in a bath of honey diluted with defrutum: Roman marmalade. Preserves of quince and lemon appear (along with rose, apple, plum and pear) in the Book of ceremonies of the Byzantine Emperor Constantine VII Porphyrogennetos."
	style := NewStyle().Padding(0, 2).Border(NormalBorder(), true)
	t.Log(width)
	t.Log(style.GetHorizontalFrameSize())
	contentWidth := width - style.GetHorizontalFrameSize()
	t.Log(contentWidth)
	rendered := style.Width(contentWidth).Render(content)
	t.Log(Width(rendered))
}

@bashbunni bashbunni linked a pull request Dec 2, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants