difi/internal/ui/delegate.go
2026-01-30 13:42:23 -05:00

114 lines
2.6 KiB
Go

package ui
import (
"fmt"
"io"
"path/filepath"
"strings"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/oug-t/difi/internal/tree"
)
type TreeDelegate struct {
Focused bool
}
func (d TreeDelegate) Height() int { return 1 }
func (d TreeDelegate) Spacing() int { return 0 }
func (d TreeDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d TreeDelegate) Render(w io.Writer, m list.Model, index int, item list.Item) {
i, ok := item.(tree.TreeItem)
if !ok {
return
}
// 1. Setup Indentation
indentSize := i.Depth * 2
indent := strings.Repeat(" ", indentSize)
// 2. Get Icon and Raw Name
iconStr, iconStyle := getIconInfo(i.Path, i.IsDir)
// 3. Truncation (Safety)
availableWidth := m.Width() - indentSize - 4
displayName := i.Path
if availableWidth > 0 && len(displayName) > availableWidth {
displayName = displayName[:max(0, availableWidth-1)] + "…"
}
// 4. Render Logic ("Oil" Block Cursor)
var row string
isSelected := index == m.Index()
if isSelected && d.Focused {
// -- SELECTED STATE (Oil Style) --
// We do NOT use iconStyle here. We want the icon to inherit the
// selection text color so the background block is unbroken.
// Content: Icon + Space + Name
content := fmt.Sprintf("%s %s", iconStr, displayName)
// Apply the solid block style to the whole content
renderedContent := SelectedBlockStyle.Render(content)
// Combine: Indent (unhighlighted) + Block (highlighted)
row = fmt.Sprintf("%s%s", indent, renderedContent)
} else {
// -- NORMAL / INACTIVE STATE --
// Render icon with its specific color
renderedIcon := iconStyle.Render(iconStr)
// Combine
row = fmt.Sprintf("%s%s %s", indent, renderedIcon, displayName)
// Apply generic padding/style
row = ItemStyle.Render(row)
}
fmt.Fprint(w, row)
}
// Helper: Returns raw icon string and its preferred style
func getIconInfo(name string, isDir bool) (string, lipgloss.Style) {
if isDir {
return "", FolderIconStyle
}
ext := filepath.Ext(name)
icon := ""
switch strings.ToLower(ext) {
case ".go":
icon = ""
case ".js", ".ts", ".tsx", ".jsx":
icon = ""
case ".md":
icon = ""
case ".json", ".yml", ".yaml", ".toml":
icon = ""
case ".css", ".scss":
icon = ""
case ".html":
icon = ""
case ".git":
icon = ""
case ".dockerfile":
icon = ""
case ".svelte":
icon = ""
}
return icon, FileIconStyle
}
func max(a, b int) int {
if a > b {
return a
}
return b
}