@@ -20,19 +20,30 @@ import (
2020
2121const 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+
2333type 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
3242func 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
8499func (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
94115func (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 {
121142func (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
144158func (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
150182func (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
157207func (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
245297type diffContentMsg struct {
298+ path string
246299 text string
247300}
0 commit comments