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

Background style is not rendered when wrapping other rendered styles #209

Open
drakenstar opened this issue Jul 25, 2023 · 4 comments
Open
Labels
bug Something isn't working

Comments

@drakenstar
Copy link

drakenstar commented Jul 25, 2023

Describe the bug
When rendering strings with backgrounds already applied, the background from our rendering style has issues. In this test case, I've joined 3 other strings using JoinHorizontal that each have their own background. Note the missing background beneath the "right text" section:

Note the area beneath "right text" that does not have a background style applied.

Screen Shot 2023-07-26 at 12 07 59 am

Setup

  • macOS 11.5.2
  • zsh and bash
  • iTerm2 and Terminal.app
  • Locale: en_US.UTF-8

Source Code
Simple reproduce:

	redStyle := lipgloss.NewStyle().
		Background(lipgloss.Color("#FF0000")).
		Width(10)

	greenStyle := lipgloss.NewStyle().
		Background(lipgloss.Color("#00FF00")).
		Width(10)

	outerStyle := lipgloss.NewStyle().
		Width(40).
		Background(lipgloss.Color("#0000FF"))

	fmt.Print(outerStyle.Render(lipgloss.JoinHorizontal(0,
		greenStyle.Render("left text"),
		redStyle.Render("multi\nline\ncenter\ntext"),
		greenStyle.Render("right text"),
	)))

Expected behavior
In this case I would have expected the blue background from style3 to be rendered in all spaces where there is no background applied.

@drakenstar drakenstar changed the title Background is not rendered Background style is not rendered when wrapping other rendered styles Jul 26, 2023
@drakenstar
Copy link
Author

drakenstar commented Jul 26, 2023

Ok I dug into this and I think found the reason for this output. wordwrap.String called by Style.Render will not output spaces at the end of a line unless it finds a \n character before the limit. For example:

s := wordwrap.String("test  test  ", 6)
fmt.Print(s)
// "test\ntest"

s := wordwrap.String("test  \ntest  ", 6)
fmt.Print(s)
// "test  \ntest"

This is arguably surprising from their end, however lipgloss could workaround this by trimming whitespace this output if it is not styled by seeking backwards per line for \x1b[0m and trimming spaces after it.

I'm happy to PR this if there's agreement it should be fixed.

@meowgorithm meowgorithm added the bug Something isn't working label Jul 26, 2023
@meowgorithm
Copy link
Member

Okay yep, this is indeed a bug. I suspect the solution may be may complex than this, though we'll need to look into it further before we can have an opinion on the fix.

Here's a centered use case to further illustrate the issue.

image
package main

import (
	"fmt"

	"github.com/charmbracelet/lipgloss"
)

func main() {
	redStyle := lipgloss.NewStyle().
		Background(lipgloss.Color("#FF0000")).
		Width(10)

	greenStyle := lipgloss.NewStyle().
		Background(lipgloss.Color("#00FF00")).
		Width(10)

	outerStyle := lipgloss.NewStyle().
		Width(40).
		Background(lipgloss.Color("#0000FF"))

	fmt.Println(outerStyle.Render(lipgloss.JoinHorizontal(lipgloss.Center,
		greenStyle.Render("left text"),
		redStyle.Render("multi\nline\ncenter\ntext\nwow"),
		greenStyle.Render("right text"),
	)))
}

@drakenstar
Copy link
Author

I've worked around this locally doing as I described above and trimming space characters from the end of a line if they are immediately preceded by a reset sequence.

However there's another harder case that workaround still doesn't solve:

redStyle := lipgloss.NewStyle().
		Background(lipgloss.Color("#FF0000")).
		Width(10)

	greenStyle := lipgloss.NewStyle().
		Background(lipgloss.Color("#00FF00")).
		Width(10)

	outerStyle := lipgloss.NewStyle().
		Width(40).
		Background(lipgloss.Color("#0000FF"))

	fmt.Println(outerStyle.Render(lipgloss.JoinHorizontal(0,
		redStyle.Render("multi\nline"),
		greenStyle.Render("left text"),
		redStyle.Render("multi\nline"),
	)))

Resulting in:

image

A more complete solve for this is probably inspecting each line for segments that have no styling any applying the current style to them.

@meowgorithm
Copy link
Member

For now, I'd probably workaround this by simply placing the short column (or all columns) over the appropriate background color with lipgloss.Place (see example and docs).

Here’s how I'd fix my above example (in a real scenario I'd abstract the Place stuff and generalize it to work for all columns):

package main

import (
	"fmt"

	"github.com/charmbracelet/lipgloss"
)

func main() {
	const blue = lipgloss.Color("#0000FF")

	redStyle := lipgloss.NewStyle().
		Background(lipgloss.Color("#FF0000")).
		Width(10)

	greenStyle := lipgloss.NewStyle().
		Background(lipgloss.Color("#00FF00")).
		Width(10)

	outerStyle := lipgloss.NewStyle().
		Width(40).
		Background(blue)

	leftContent := greenStyle.Render("left text")
	middleContent := redStyle.Render("multi\nline\ncenter\ntext\nwow")
	rightContent := greenStyle.Render("right text")

	fmt.Println(outerStyle.Render(
		lipgloss.JoinHorizontal(
			lipgloss.Center,
			leftContent,
			middleContent,
			lipgloss.Place(
				lipgloss.Width(rightContent),            // width
				lipgloss.Height(middleContent),          // height
				lipgloss.Left,                           // x
				lipgloss.Center,                         // y
				rightContent,                            // content
				lipgloss.WithWhitespaceBackground(blue), // background
			),
		)))
}

Output:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants