hosts-go/internal/tui/model.go

120 lines
2.5 KiB
Go

package tui
import (
"fmt"
"hosts-go/internal/core"
"strings"
list "github.com/charmbracelet/bubbles/list"
viewport "github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
)
// entryItem wraps a HostEntry for display in a list component.
type entryItem struct{ entry *core.HostEntry }
func (e entryItem) Title() string {
prefix := "[ ]"
if e.entry.Active {
prefix = "[✓]"
}
return fmt.Sprintf("%s %s", prefix, e.entry.Hostname)
}
func (e entryItem) Description() string { return e.entry.IP }
func (e entryItem) FilterValue() string { return e.entry.Hostname }
// Model is the main Bubble Tea model for the application.
type Mode int
const (
ViewMode Mode = iota
EditMode
)
type pane int
const (
listPane pane = iota
detailPane
)
type Model struct {
list list.Model
detail viewport.Model
hosts *core.HostsFile
hostsPath string
width int
height int
mode Mode
focus pane
}
// NewModel constructs the TUI model from a parsed HostsFile and its path.
func NewModel(hf *core.HostsFile, path string) Model {
items := make([]list.Item, len(hf.Entries))
for i, e := range hf.Entries {
items[i] = entryItem{entry: e}
}
l := list.New(items, list.NewDefaultDelegate(), 0, 0)
l.SetShowStatusBar(false)
l.SetFilteringEnabled(false)
l.SetShowHelp(false)
l.SetShowPagination(false)
m := Model{
list: l,
detail: viewport.New(0, 0),
hosts: hf,
hostsPath: path,
mode: ViewMode,
focus: listPane,
}
m.refreshDetail()
return m
}
func (m *Model) refreshDetail() {
if len(m.hosts.Entries) == 0 {
m.detail.SetContent("")
return
}
entry := m.hosts.Entries[m.list.Index()]
var b strings.Builder
status := "active"
if !entry.Active {
status = "inactive"
}
fmt.Fprintf(&b, "IP: %s\n", entry.IP)
fmt.Fprintf(&b, "Host: %s\n", entry.Hostname)
if len(entry.Aliases) > 0 {
fmt.Fprintf(&b, "Aliases: %s\n", strings.Join(entry.Aliases, ", "))
}
if entry.Comment != "" {
fmt.Fprintf(&b, "Comment: %s\n", entry.Comment)
}
fmt.Fprintf(&b, "Status: %s", status)
m.detail.SetContent(b.String())
m.detail.YOffset = 0
}
// Init satisfies tea.Model.
func (m Model) Init() tea.Cmd { return nil }
// SelectedEntry returns the currently selected host entry.
func (m Model) SelectedEntry() *core.HostEntry {
if len(m.hosts.Entries) == 0 {
return nil
}
idx := m.list.Index()
if idx < 0 || idx >= len(m.hosts.Entries) {
return nil
}
return m.hosts.Entries[idx]
}
// Mode returns the current operating mode of the TUI.
func (m Model) Mode() Mode {
return m.mode
}