-
Notifications
You must be signed in to change notification settings - Fork 273
Description
Describe the bug
When adding a string as a border that contains ANSI colors, the border is not rendered correctly (specifically its usually taking less width and can contain invalid chars, see screenshots).
I found that fixing this problem would help a lot to the implementation of the top borders, since it would already calculate correctly the margins and use the expected top corners (in contrast of removing top border). And it might also make the border interface more powerful.
Setup
- OS macOS (intel)
- Shell: bash & zsh
- Terminal Emulator: macos terminal & kitty
To Reproduce
Steps to reproduce the behavior:
go run .
Source Code
package main
import (
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"log"
)
type model struct {
exiting bool
style lipgloss.Style
colorStyle lipgloss.Style
}
func initial(style lipgloss.Style) model {
return model{
style: style,
colorStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("10")),
}
}
func (m model) Init() tea.Cmd {
return nil
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, tea.Quit
}
func (m model) View() string {
borderStyle := m.style.GetBorderStyle()
borderStyle.Top = m.colorStyle.Render(borderStyle.Top)
m.style = m.style.BorderStyle(borderStyle)
return m.style.Render("") + "\n"
}
func main() {
width := 10
style := lipgloss.NewStyle().
BorderStyle(lipgloss.RoundedBorder()).
Width(width).
Margin(1, 2).
MarginBackground(lipgloss.Color("#000000")).
BorderForeground(lipgloss.Color("12"))
model := initial(style)
p := tea.NewProgram(model)
if _, err := p.Run(); err != nil {
log.Fatal(err)
}
}
Expected behavior
- I would expect that the text is rendered to the full length (omiting ANSI chars).
- I would also expect the full ANSI colorization is added (probably overriding the topRight, but that should be a problem for the user to fix). Though a behavior that I would also find acceptable is that the border deletes the ANSI chars and is colorized only by the color style.
Screenshots
*Black background displays the margins
Additional context
The execution of the function ansi.StringWidth, works correctly calculating the width submitting ANSI chars when processing the full string, though when processing iteratively rune by rune it fails.
One solution could be to do something similar to StringWidth by parsing the string and finish when either you process the full string or you have achieved your max length, the following function could be an example of it:
package main
import (
"fmt"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/x/ansi/parser"
"github.com/rivo/uniseg"
"strings"
)
func ProcessString(s string, maxLen int) string {
if s == "" {
return ""
}
var (
pstate = parser.GroundState // initial state
cluster string
width int
out = strings.Builder{}
)
for i := 0; i < len(s); i++ {
state, action := parser.Table.Transition(pstate, s[i])
if state == parser.Utf8State {
var w int
cluster, _, w, _ = uniseg.FirstGraphemeClusterInString(s[i:], -1)
width += w
if width > maxLen {
// Break if we will exceed the max length, and return string up to here
break
}
i += len(cluster) - 1
out.WriteString(cluster)
pstate = parser.GroundState
continue
}
if action == parser.PrintAction {
// TODO: Not sure if something should be done here
}
out.Write([]byte{s[i]})
pstate = state
}
return out.String()
}
func main() {
s := lipgloss.NewStyle().Foreground(lipgloss.Color("10")).Render("──────")
fmt.Println(ProcessString(s, 2))
}