fix: measure runes instead of bytes when truncating

There are a couple of gotchas in LipGlossTruncate:

* len() returns the number of bytes in a string
* slicing a string slices it on a byte level

The fix would normally be to convert the string to a slice of runes and
operate on that new slice:

r := []rune(str)

However, reflow already contains an ansi-aware truncate feature that we
can use instead as a drop-in replacement for the LipGlossTruncate
function.
This commit is contained in:
Christian Rocha 2023-05-18 11:34:53 -04:00 committed by Maas Lalani
parent c8710071ad
commit b23ebce896
3 changed files with 6 additions and 13 deletions

View file

@ -6,14 +6,6 @@ import (
"github.com/charmbracelet/lipgloss"
)
// LipglossTruncate truncates a given line based on its lipgloss width.
func LipglossTruncate(s string, width int) string {
var i int
for i = 0; i < len(s) && lipgloss.Width(s[:i]) < width; i++ {
} //revive:disable-line:empty-block
return s[:i]
}
// LipglossLengthPadding calculated calculates how much padding a string is given by a style.
func LipglossPadding(style lipgloss.Style) (int, int) {
render := style.Render(" ")

View file

@ -9,8 +9,8 @@ import (
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/gum/internal/utils"
"github.com/charmbracelet/lipgloss"
"github.com/muesli/reflow/truncate"
)
type model struct {
@ -64,7 +64,7 @@ func (m *model) ProcessText(msg tea.WindowSizeMsg) {
text.WriteString(m.lineNumberStyle.Render(fmt.Sprintf("%4d │ ", i+1)))
}
for m.softWrap && lipgloss.Width(line) > m.maxWidth {
truncatedLine := utils.LipglossTruncate(line, m.maxWidth)
truncatedLine := truncate.String(line, uint(m.maxWidth))
text.WriteString(textStyle.Render(truncatedLine))
text.WriteString("\n")
if m.showLineNumbers {
@ -72,7 +72,7 @@ func (m *model) ProcessText(msg tea.WindowSizeMsg) {
}
line = strings.Replace(line, truncatedLine, "", 1)
}
text.WriteString(textStyle.Render(utils.LipglossTruncate(line, m.maxWidth)))
text.WriteString(textStyle.Render(truncate.String(line, uint(m.maxWidth))))
text.WriteString("\n")
}

View file

@ -8,6 +8,7 @@ import (
"github.com/charmbracelet/bubbles/textinput"
"github.com/charmbracelet/gum/internal/utils"
"github.com/charmbracelet/lipgloss"
"github.com/muesli/reflow/truncate"
)
type search struct {
@ -150,12 +151,12 @@ func softWrapEm(str string, maxWidth int, softWrap bool) string {
var text strings.Builder
for _, line := range strings.Split(str, "\n") {
for softWrap && lipgloss.Width(line) > maxWidth {
truncatedLine := utils.LipglossTruncate(line, maxWidth)
truncatedLine := truncate.String(line, uint(maxWidth))
text.WriteString(truncatedLine)
text.WriteString("\n")
line = strings.Replace(line, truncatedLine, "", 1)
}
text.WriteString(utils.LipglossTruncate(line, maxWidth))
text.WriteString(truncate.String(line, uint(maxWidth)))
text.WriteString("\n")
}