|
|
@@ -1,16 +1,15 @@
|
|
|
package layout
|
|
|
|
|
|
import (
|
|
|
- "bytes"
|
|
|
"strings"
|
|
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
|
- "github.com/opencode-ai/opencode/internal/tui/styles"
|
|
|
- "github.com/opencode-ai/opencode/internal/tui/util"
|
|
|
- "github.com/mattn/go-runewidth"
|
|
|
+ chAnsi "github.com/charmbracelet/x/ansi"
|
|
|
"github.com/muesli/ansi"
|
|
|
"github.com/muesli/reflow/truncate"
|
|
|
"github.com/muesli/termenv"
|
|
|
+ "github.com/opencode-ai/opencode/internal/tui/styles"
|
|
|
+ "github.com/opencode-ai/opencode/internal/tui/util"
|
|
|
)
|
|
|
|
|
|
// Most of this code is borrowed from
|
|
|
@@ -117,42 +116,7 @@ func PlaceOverlay(
|
|
|
// cutLeft cuts printable characters from the left.
|
|
|
// This function is heavily based on muesli's ansi and truncate packages.
|
|
|
func cutLeft(s string, cutWidth int) string {
|
|
|
- var (
|
|
|
- pos int
|
|
|
- isAnsi bool
|
|
|
- ab bytes.Buffer
|
|
|
- b bytes.Buffer
|
|
|
- )
|
|
|
- for _, c := range s {
|
|
|
- var w int
|
|
|
- if c == ansi.Marker || isAnsi {
|
|
|
- isAnsi = true
|
|
|
- ab.WriteRune(c)
|
|
|
- if ansi.IsTerminator(c) {
|
|
|
- isAnsi = false
|
|
|
- if bytes.HasSuffix(ab.Bytes(), []byte("[0m")) {
|
|
|
- ab.Reset()
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- w = runewidth.RuneWidth(c)
|
|
|
- }
|
|
|
-
|
|
|
- if pos >= cutWidth {
|
|
|
- if b.Len() == 0 {
|
|
|
- if ab.Len() > 0 {
|
|
|
- b.Write(ab.Bytes())
|
|
|
- }
|
|
|
- if pos-cutWidth > 1 {
|
|
|
- b.WriteByte(' ')
|
|
|
- continue
|
|
|
- }
|
|
|
- }
|
|
|
- b.WriteRune(c)
|
|
|
- }
|
|
|
- pos += w
|
|
|
- }
|
|
|
- return b.String()
|
|
|
+ return chAnsi.Cut(s, cutWidth, lipgloss.Width(s))
|
|
|
}
|
|
|
|
|
|
func max(a, b int) int {
|