Skip to content

Commit 9305af9

Browse files
authored
fix: add node cache so you can view collapsed nodes diff (#71)
1 parent 6e5d9c3 commit 9305af9

2 files changed

Lines changed: 87 additions & 31 deletions

File tree

pkg/filenode/file_node.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ func (f *FileNode) SetHidden(bool) {}
178178
func (f *FileNode) SetValue(any) {}
179179

180180
func LinesCounts(file *gitdiff.File) (int64, int64) {
181+
if file == nil {
182+
return 0, 0
183+
}
181184
var added int64 = 0
182185
var deleted int64 = 0
183186
frags := file.TextFragments

pkg/ui/panes/diffviewer/diffviewer.go

Lines changed: 84 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,30 @@ import (
2020

2121
const dirHeaderHeight = 3
2222

23+
type cachedNode struct {
24+
path string
25+
files []*gitdiff.File
26+
additions int64
27+
deletions int64
28+
diff string
29+
}
30+
31+
type nodeCache map[string]*cachedNode
32+
2333
type Model struct {
2434
common.Common
2535
vp viewport.Model
26-
file *gitdiff.File
27-
dir string
28-
dirFiles []*gitdiff.File
36+
file *cachedNode
37+
dir *cachedNode
38+
cache nodeCache
2939
sideBySide bool
3040
}
3141

3242
func New(sideBySide bool) Model {
3343
return Model{
3444
vp: viewport.Model{},
3545
sideBySide: sideBySide,
46+
cache: map[string]*cachedNode{},
3647
}
3748
}
3849

@@ -63,7 +74,11 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
6374
lines[i] = ansi.Truncate(line, m.vp.Width(), "")
6475
}
6576
}
66-
m.vp.SetContent(strings.Join(lines, "\n"))
77+
diff := strings.Join(lines, "\n")
78+
if _, ok := m.cache[msg.path]; ok {
79+
m.cache[msg.path].diff = diff
80+
}
81+
m.vp.SetContent(diff)
6782
}
6883

6984
return m, tea.Batch(cmds...)
@@ -83,31 +98,37 @@ func (m *Model) SetSize(width, height int) tea.Cmd {
8398

8499
func (m *Model) diff() tea.Cmd {
85100
if m.file != nil {
101+
if m.file.diff != "" {
102+
return nil
103+
}
86104
return diffFile(m.file, m.Width, m.sideBySide)
87-
} else if m.dir != "" {
88-
return diffDir(m.dir, m.dirFiles, m.Width, m.sideBySide)
105+
} else if m.dir != nil {
106+
if m.dir.diff != "" {
107+
return nil
108+
}
109+
return diffDir(m.dir, m.Width, m.sideBySide)
89110
}
90111

91112
return nil
92113
}
93114

94115
func (m Model) headerView() string {
95-
if m.dir != "" {
116+
if m.dir != nil {
96117
return m.dirHeaderView()
97118
}
98119

99-
if m.file == nil {
120+
if m.file == nil || len(m.file.files) != 1 {
100121
return ""
101122
}
102-
name := filenode.GetFileName(m.file)
123+
name := m.file.path
103124
base := lipgloss.NewStyle()
104125

105126
fileIcon := icons.GetIcon(name, false)
106127
prefix := base.Render(fileIcon) + base.Render(" ")
107128
name = utils.TruncateString(name, m.Width-lipgloss.Width(prefix))
108129
top := prefix + base.Bold(true).Render(name)
109130

110-
bottom := filenode.ViewFileLinesCounts(m.file, base)
131+
bottom := filenode.ViewFileLinesCounts(m.file.files[0], base)
111132

112133
return base.
113134
Width(m.Width).
@@ -121,17 +142,10 @@ func (m Model) headerView() string {
121142
func (m Model) dirHeaderView() string {
122143
base := lipgloss.NewStyle().Foreground(lipgloss.Blue)
123144
prefix := base.Render(" ")
124-
name := utils.TruncateString(m.dir, m.Width-lipgloss.Width(prefix))
125-
126-
var additions, deletions int64
127-
for _, file := range m.dirFiles {
128-
a, d := filenode.LinesCounts(file)
129-
additions += a
130-
deletions += d
131-
}
145+
name := utils.TruncateString(m.dir.path, m.Width-lipgloss.Width(prefix))
132146

133147
top := prefix + base.Bold(true).Render(name)
134-
bottom := filenode.ViewLinesCounts(additions, deletions, base)
148+
bottom := filenode.ViewLinesCounts(m.dir.additions, m.dir.deletions, base)
135149
return base.
136150
Width(m.Width).
137151
Height(dirHeaderHeight - 1).
@@ -142,16 +156,52 @@ func (m Model) dirHeaderView() string {
142156
}
143157

144158
func (m Model) SetFilePatch(file *gitdiff.File) (Model, tea.Cmd) {
145-
m.file = file
146-
m.dir = ""
159+
m.dir = nil
160+
161+
fname := filenode.GetFileName(file)
162+
if cached, ok := m.cache[fname]; ok {
163+
m.file = cached
164+
m.vp.SetContent(cached.diff)
165+
return m, nil
166+
}
167+
168+
files := make([]*gitdiff.File, 1)
169+
files[0] = file
170+
additions, deletions := filenode.LinesCounts(file)
171+
m.file = &cachedNode{
172+
path: fname,
173+
files: files,
174+
additions: additions,
175+
deletions: deletions,
176+
}
177+
m.cache[fname] = m.file
178+
147179
return m, diffFile(m.file, m.Width, m.sideBySide)
148180
}
149181

150182
func (m Model) SetDirPatch(dirPath string, files []*gitdiff.File) (Model, tea.Cmd) {
151183
m.file = nil
152-
m.dir = dirPath
153-
m.dirFiles = files
154-
return m, diffDir(dirPath, files, m.Width, m.sideBySide)
184+
185+
if cached, ok := m.cache[dirPath]; ok {
186+
m.dir = cached
187+
m.vp.SetContent(cached.diff)
188+
return m, nil
189+
}
190+
191+
var added, deleted int64
192+
for _, file := range files {
193+
na, nd := filenode.LinesCounts(file)
194+
added += na
195+
deleted += nd
196+
}
197+
m.dir = &cachedNode{
198+
path: dirPath,
199+
files: files,
200+
additions: added,
201+
deletions: deleted,
202+
}
203+
m.cache[dirPath] = m.dir
204+
return m, diffDir(m.dir, m.Width, m.sideBySide)
155205
}
156206

157207
func (m *Model) GoToTop() {
@@ -174,10 +224,12 @@ func (m *Model) ScrollDown(lines int) {
174224
m.vp.ScrollDown(lines)
175225
}
176226

177-
func diffFile(file *gitdiff.File, width int, sideBySidePreference bool) tea.Cmd {
178-
if width == 0 || file == nil {
227+
func diffFile(node *cachedNode, width int, sideBySidePreference bool) tea.Cmd {
228+
if width == 0 || node == nil || len(node.files) != 1 {
179229
return nil
180230
}
231+
232+
file := node.files[0]
181233
return func() tea.Msg {
182234
// Only use side-by-side if preference is true AND file is not new/deleted
183235
useSideBySide := sideBySidePreference && !file.IsNew && !file.IsDelete
@@ -197,12 +249,12 @@ func diffFile(file *gitdiff.File, width int, sideBySidePreference bool) tea.Cmd
197249
return common.ErrMsg{Err: err}
198250
}
199251

200-
return diffContentMsg{text: string(out)}
252+
return diffContentMsg{path: filenode.GetFileName(file), text: string(out)}
201253
}
202254
}
203255

204-
func diffDir(dirPath string, files []*gitdiff.File, width int, sideBySidePreference bool) tea.Cmd {
205-
if width == 0 || dirPath == "" {
256+
func diffDir(dir *cachedNode, width int, sideBySidePreference bool) tea.Cmd {
257+
if width == 0 || dir == nil {
206258
return nil
207259
}
208260
return func() tea.Msg {
@@ -229,7 +281,7 @@ func diffDir(dirPath string, files []*gitdiff.File, width int, sideBySidePrefere
229281
deltac := exec.Command("delta", args...)
230282
deltac.Env = os.Environ()
231283
strs := strings.Builder{}
232-
for _, file := range files {
284+
for _, file := range dir.files {
233285
strs.WriteString(file.String())
234286
}
235287
deltac.Stdin = strings.NewReader(strs.String() + "\n")
@@ -238,10 +290,11 @@ func diffDir(dirPath string, files []*gitdiff.File, width int, sideBySidePrefere
238290
return common.ErrMsg{Err: err}
239291
}
240292

241-
return diffContentMsg{text: string(out)}
293+
return diffContentMsg{path: dir.path, text: string(out)}
242294
}
243295
}
244296

245297
type diffContentMsg struct {
298+
path string
246299
text string
247300
}

0 commit comments

Comments
 (0)