Skip to content

Commit 5436202

Browse files
committed
feat: file + status icons
1 parent 6b1accc commit 5436202

File tree

2 files changed

+68
-27
lines changed

2 files changed

+68
-27
lines changed

filetree.go

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,75 @@
11
package main
22

33
import (
4+
"log"
45
"os"
56
"path/filepath"
67
"strings"
78

9+
"github.com/bluekeyes/go-gitdiff/gitdiff"
810
tea "github.com/charmbracelet/bubbletea"
911
"github.com/charmbracelet/lipgloss"
1012
"github.com/charmbracelet/lipgloss/tree"
1113
)
1214

1315
type ftModel struct {
14-
files []string
16+
files []*gitdiff.File
1517
tree *tree.Tree
1618
selectedFile *string
1719
}
1820

19-
func (m ftModel) SetFiles(files []string) ftModel {
21+
func (m ftModel) SetFiles(files []*gitdiff.File) ftModel {
2022
m.files = files
2123
t := buildFullFileTree(files)
24+
log.Printf("full: %v\n", t)
2225
collapsed := collapseTree(t)
26+
log.Printf("collapsed: %v\n", collapsed)
2327
m.tree = truncateTree(collapsed, 0)
2428
return m
2529
}
2630

2731
type FileNode struct {
28-
path string
32+
file *gitdiff.File
2933
depth int
3034
}
3135

36+
func (f FileNode) path() string {
37+
return getFileName(f.file)
38+
}
39+
3240
func (f FileNode) Value() string {
33-
return truncateValue(filepath.Base(f.path), f.depth)
41+
icon := " "
42+
status := " "
43+
if f.file.IsNew {
44+
status += lipgloss.NewStyle().Foreground(lipgloss.Color("2")).Render("")
45+
} else if f.file.IsDelete {
46+
status += lipgloss.NewStyle().Foreground(lipgloss.Color("1")).Render("")
47+
} else {
48+
status += lipgloss.NewStyle().Foreground(lipgloss.Color("3")).Render("")
49+
}
50+
51+
depth := f.depth
52+
if f.depth > 0 {
53+
depth = depth - 1
54+
}
55+
depthWidth := depth * 2
56+
iconsWidth := lipgloss.Width(icon) + lipgloss.Width(status)
57+
nameMaxWidth := openFileTreeWidth - depthWidth - iconsWidth
58+
base := filepath.Base(f.path())
59+
name := truncateValue(base, nameMaxWidth)
60+
61+
spacerWidth := openFileTreeWidth - lipgloss.Width(name) - iconsWidth - depthWidth
62+
if len(name) < len(base) {
63+
spacerWidth = spacerWidth - 1
64+
}
65+
spacer := ""
66+
if spacerWidth > 0 {
67+
spacer = strings.Repeat(" ", spacerWidth)
68+
}
69+
70+
log.Printf("name: %s, nameWidth: %d, nameMaxWidth: %d, iconsWidth: %d, depthWidth: %d, spacerWidth: %d\n", name, lipgloss.Width(name), nameMaxWidth, iconsWidth, depth*2, spacerWidth)
71+
72+
return lipgloss.JoinHorizontal(lipgloss.Top, icon, name, spacer, status)
3473
}
3574

3675
func (f FileNode) String() string {
@@ -49,14 +88,15 @@ func (m ftModel) SetCursor(cursor int) ftModel {
4988
if len(m.files) == 0 {
5089
return m
5190
}
52-
m.selectedFile = &m.files[cursor]
91+
name := getFileName(m.files[cursor])
92+
m.selectedFile = &name
5393
applyStyles(m.tree, m.selectedFile)
5494
return m
5595
}
5696

5797
func initialFileTreeModel() ftModel {
5898
return ftModel{
59-
files: []string{},
99+
files: []*gitdiff.File{},
60100
}
61101
}
62102

@@ -117,12 +157,13 @@ func (m ftModel) printWithoutRoot() string {
117157
return s
118158
}
119159

120-
func buildFullFileTree(files []string) *tree.Tree {
160+
func buildFullFileTree(files []*gitdiff.File) *tree.Tree {
121161
t := tree.Root(".")
122162
for _, file := range files {
123163
subTree := t
124164

125-
dir := filepath.Dir(file)
165+
name := getFileName(file)
166+
dir := filepath.Dir(name)
126167
parts := strings.Split(dir, string(os.PathSeparator))
127168
path := ""
128169

@@ -147,12 +188,12 @@ func buildFullFileTree(files []string) *tree.Tree {
147188
}
148189

149190
// path does not exist from this point, need to creat it
150-
leftover := strings.TrimPrefix(file, path)
191+
leftover := strings.TrimPrefix(name, path)
151192
parts = strings.Split(leftover, string(os.PathSeparator))
152193
for i, part := range parts {
153194
var c *tree.Tree
154195
if i == len(parts)-1 {
155-
subTree.Child(FileNode{path: file})
196+
subTree.Child(FileNode{file: file})
156197
} else {
157198
c = tree.Root(part)
158199
subTree.Child(c)
@@ -164,12 +205,8 @@ func buildFullFileTree(files []string) *tree.Tree {
164205
return t
165206
}
166207

167-
func truncateValue(value string, depth int) string {
168-
d := depth
169-
if depth > 0 {
170-
d = d - 1
171-
}
172-
return TruncateString(value, openFileTreeWidth-d*2)
208+
func truncateValue(value string, width int) string {
209+
return TruncateString(value, width)
173210
}
174211

175212
func collapseTree(t *tree.Tree) *tree.Tree {
@@ -209,15 +246,19 @@ func collapseTree(t *tree.Tree) *tree.Tree {
209246
}
210247

211248
func truncateTree(t *tree.Tree, depth int) *tree.Tree {
212-
newT := tree.Root(truncateValue(t.Value(), depth))
249+
d := depth
250+
if d > 0 {
251+
d = d - 1
252+
}
253+
newT := tree.Root(truncateValue(t.Value(), openFileTreeWidth-d*2))
213254
children := t.Children()
214255
for i := 0; i < children.Length(); i++ {
215256
child := children.At(i)
216257
switch child := child.(type) {
217258
case *tree.Tree:
218259
newT.Child(truncateTree(child, depth+1))
219260
case FileNode:
220-
newT.Child(FileNode{path: child.path, depth: depth + 1})
261+
newT.Child(FileNode{file: child.file, depth: depth + 1})
221262
default:
222263
newT.Child(child)
223264
}
@@ -252,7 +293,7 @@ func applyStyleToNode(node tree.Node, selectedFile *string) lipgloss.Style {
252293
st := lipgloss.NewStyle().MaxHeight(1)
253294
switch n := node.(type) {
254295
case FileNode:
255-
if selectedFile != nil && n.path == *selectedFile {
296+
if selectedFile != nil && n.path() == *selectedFile {
256297
return st.Background(lipgloss.Color("#1b1b33")).Bold(true)
257298
}
258299
case *tree.Tree:
@@ -262,3 +303,10 @@ func applyStyleToNode(node tree.Node, selectedFile *string) lipgloss.Style {
262303
}
263304
return st
264305
}
306+
307+
func getFileName(file *gitdiff.File) string {
308+
if file.NewName != "" {
309+
return file.NewName
310+
}
311+
return file.OldName
312+
}

main.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,7 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
9191
if len(m.files) == 0 {
9292
return m, tea.Quit
9393
}
94-
paths := make([]string, len(m.files))
95-
for i, f := range m.files {
96-
paths[i] = f.NewName
97-
if paths[i] == "" {
98-
paths[i] = f.OldName
99-
}
100-
}
101-
m.fileTree = m.fileTree.(ftModel).SetFiles(paths)
94+
m.fileTree = m.fileTree.(ftModel).SetFiles(m.files)
10295
m.diffViewer, cmd = m.diffViewer.(diffModel).SetFilePatch(m.files[0])
10396
cmds = append(cmds, cmd)
10497

0 commit comments

Comments
 (0)