mirror of
https://github.com/aljazceru/opencode.git
synced 2026-01-06 17:34:58 +01:00
feat(tui): file viewer, select messages
This commit is contained in:
109
packages/tui/internal/util/file.go
Normal file
109
packages/tui/internal/util/file.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/charmbracelet/lipgloss/v2/compat"
|
||||
"github.com/charmbracelet/x/ansi"
|
||||
"github.com/sst/opencode/internal/styles"
|
||||
"github.com/sst/opencode/internal/theme"
|
||||
)
|
||||
|
||||
var RootPath string
|
||||
var CwdPath string
|
||||
|
||||
type fileRenderer struct {
|
||||
filename string
|
||||
content string
|
||||
height int
|
||||
}
|
||||
|
||||
type fileRenderingOption func(*fileRenderer)
|
||||
|
||||
func WithTruncate(height int) fileRenderingOption {
|
||||
return func(c *fileRenderer) {
|
||||
c.height = height
|
||||
}
|
||||
}
|
||||
|
||||
func RenderFile(
|
||||
filename string,
|
||||
content string,
|
||||
width int,
|
||||
options ...fileRenderingOption) string {
|
||||
t := theme.CurrentTheme()
|
||||
renderer := &fileRenderer{
|
||||
filename: filename,
|
||||
content: content,
|
||||
}
|
||||
for _, option := range options {
|
||||
option(renderer)
|
||||
}
|
||||
|
||||
lines := []string{}
|
||||
for line := range strings.SplitSeq(content, "\n") {
|
||||
line = strings.TrimRightFunc(line, unicode.IsSpace)
|
||||
line = strings.ReplaceAll(line, "\t", " ")
|
||||
lines = append(lines, line)
|
||||
}
|
||||
content = strings.Join(lines, "\n")
|
||||
|
||||
if renderer.height > 0 {
|
||||
content = TruncateHeight(content, renderer.height)
|
||||
}
|
||||
content = fmt.Sprintf("```%s\n%s\n```", Extension(renderer.filename), content)
|
||||
content = ToMarkdown(content, width, t.BackgroundPanel())
|
||||
return content
|
||||
}
|
||||
|
||||
func TruncateHeight(content string, height int) string {
|
||||
lines := strings.Split(content, "\n")
|
||||
if len(lines) > height {
|
||||
return strings.Join(lines[:height], "\n")
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
func Relative(path string) string {
|
||||
path = strings.TrimPrefix(path, CwdPath+"/")
|
||||
return strings.TrimPrefix(path, RootPath+"/")
|
||||
}
|
||||
|
||||
func Extension(path string) string {
|
||||
ext := filepath.Ext(path)
|
||||
if ext == "" {
|
||||
ext = ""
|
||||
} else {
|
||||
ext = strings.ToLower(ext[1:])
|
||||
}
|
||||
return ext
|
||||
}
|
||||
|
||||
func ToMarkdown(content string, width int, backgroundColor compat.AdaptiveColor) string {
|
||||
r := styles.GetMarkdownRenderer(width-7, backgroundColor)
|
||||
content = strings.ReplaceAll(content, RootPath+"/", "")
|
||||
rendered, _ := r.Render(content)
|
||||
lines := strings.Split(rendered, "\n")
|
||||
|
||||
if len(lines) > 0 {
|
||||
firstLine := lines[0]
|
||||
cleaned := ansi.Strip(firstLine)
|
||||
nospace := strings.ReplaceAll(cleaned, " ", "")
|
||||
if nospace == "" {
|
||||
lines = lines[1:]
|
||||
}
|
||||
if len(lines) > 0 {
|
||||
lastLine := lines[len(lines)-1]
|
||||
cleaned = ansi.Strip(lastLine)
|
||||
nospace = strings.ReplaceAll(cleaned, " ", "")
|
||||
if nospace == "" {
|
||||
lines = lines[:len(lines)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
content = strings.Join(lines, "\n")
|
||||
return strings.TrimSuffix(content, "\n")
|
||||
}
|
||||
Reference in New Issue
Block a user