135 lines
3.0 KiB
Go
135 lines
3.0 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/charmbracelet/bubbles/list"
|
|
"github.com/charmbracelet/bubbles/viewport"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
|
|
"github.com/oug-t/difi/internal/git"
|
|
"github.com/oug-t/difi/internal/tree"
|
|
)
|
|
|
|
const TargetBranch = "main"
|
|
|
|
type Model struct {
|
|
fileTree list.Model
|
|
diffViewport viewport.Model
|
|
selectedPath string
|
|
width, height int
|
|
}
|
|
|
|
func NewModel() Model {
|
|
files, _ := git.ListChangedFiles(TargetBranch)
|
|
items := tree.Build(files)
|
|
|
|
l := list.New(items, listDelegate{}, 0, 0)
|
|
l.SetShowTitle(false)
|
|
l.SetShowHelp(false)
|
|
l.SetShowStatusBar(false)
|
|
l.SetFilteringEnabled(false)
|
|
|
|
m := Model{
|
|
fileTree: l,
|
|
diffViewport: viewport.New(0, 0),
|
|
}
|
|
|
|
if len(items) > 0 {
|
|
if first, ok := items[0].(tree.TreeItem); ok {
|
|
m.selectedPath = first.FullPath
|
|
}
|
|
}
|
|
return m
|
|
}
|
|
|
|
func (m Model) Init() tea.Cmd {
|
|
if m.selectedPath != "" {
|
|
return git.DiffCmd(TargetBranch, m.selectedPath)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
var cmd tea.Cmd
|
|
var cmds []tea.Cmd
|
|
|
|
switch msg := msg.(type) {
|
|
case tea.WindowSizeMsg:
|
|
m.width = msg.Width
|
|
m.height = msg.Height
|
|
treeWidth := int(float64(m.width) * 0.25)
|
|
m.fileTree.SetSize(treeWidth, m.height)
|
|
m.diffViewport.Width = m.width - treeWidth - 2
|
|
m.diffViewport.Height = m.height
|
|
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "q", "ctrl+c":
|
|
return m, tea.Quit
|
|
case "up", "k", "down", "j":
|
|
m.fileTree, cmd = m.fileTree.Update(msg)
|
|
cmds = append(cmds, cmd)
|
|
if item, ok := m.fileTree.SelectedItem().(tree.TreeItem); ok && !item.IsDir {
|
|
if item.FullPath != m.selectedPath {
|
|
m.selectedPath = item.FullPath
|
|
cmds = append(cmds, git.DiffCmd(TargetBranch, m.selectedPath))
|
|
}
|
|
}
|
|
case "e":
|
|
if m.selectedPath != "" {
|
|
return m, git.OpenEditorCmd(m.selectedPath)
|
|
}
|
|
}
|
|
|
|
case git.DiffMsg:
|
|
m.diffViewport.SetContent(msg.Content)
|
|
|
|
case git.EditorFinishedMsg:
|
|
if msg.Err != nil {
|
|
}
|
|
return m, git.DiffCmd(TargetBranch, m.selectedPath)
|
|
}
|
|
|
|
return m, tea.Batch(cmds...)
|
|
}
|
|
|
|
func (m Model) View() string {
|
|
if m.width == 0 {
|
|
return "Loading..."
|
|
}
|
|
|
|
treeView := PaneStyle.Copy().
|
|
Width(m.fileTree.Width()).
|
|
Height(m.fileTree.Height()).
|
|
Render(m.fileTree.View())
|
|
|
|
diffView := DiffStyle.Copy().
|
|
Width(m.diffViewport.Width).
|
|
Height(m.diffViewport.Height).
|
|
Render(m.diffViewport.View())
|
|
|
|
return lipgloss.JoinHorizontal(lipgloss.Top, treeView, diffView)
|
|
}
|
|
|
|
type listDelegate struct{}
|
|
|
|
func (d listDelegate) Height() int { return 1 }
|
|
func (d listDelegate) Spacing() int { return 0 }
|
|
func (d listDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
|
|
func (d listDelegate) Render(w io.Writer, m list.Model, index int, item list.Item) {
|
|
i, ok := item.(tree.TreeItem)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
str := i.Title()
|
|
if index == m.Index() {
|
|
fmt.Fprint(w, SelectedItemStyle.Render("│ "+str))
|
|
} else {
|
|
fmt.Fprint(w, ItemStyle.Render(str))
|
|
}
|
|
}
|