@@ -15,6 +15,11 @@ type LogPanelComponent struct {
1515 testLogs map [string ][]string
1616 currentTestID string
1717 logMutex sync.RWMutex
18+
19+ // Caching to avoid expensive rebuilds on every View() call
20+ lastWrapWidth int
21+ contentNeedsSync bool
22+ pendingGotoBottom bool
1823}
1924
2025// NewLogPanelComponent creates a new log panel
@@ -39,7 +44,22 @@ func (lp *LogPanelComponent) View(width, height int) string {
3944 lp .logMutex .Lock ()
4045 defer lp .logMutex .Unlock ()
4146
42- lp .rebuildContent (false )
47+ // Only rebuild content if something actually changed
48+ currentWrapWidth := lp .ContentPanel .GetViewportWidth () - 2
49+ if currentWrapWidth <= 0 {
50+ currentWrapWidth = 70
51+ }
52+
53+ // Check if we need to rebuild: width changed or content was marked dirty
54+ widthChanged := lp .lastWrapWidth != currentWrapWidth
55+ if lp .contentNeedsSync || widthChanged {
56+ // Go to bottom if new content was added, but not if just width changed
57+ gotoBottom := lp .pendingGotoBottom && ! widthChanged
58+ lp .rebuildContent (gotoBottom )
59+ lp .lastWrapWidth = currentWrapWidth
60+ lp .contentNeedsSync = false
61+ lp .pendingGotoBottom = false
62+ }
4363
4464 return lp .ContentPanel .View (width , height )
4565}
@@ -56,7 +76,8 @@ func (lp *LogPanelComponent) AddServiceLog(line string) {
5676 }
5777
5878 if lp .currentTestID == "" {
59- lp .rebuildContent (true )
79+ lp .contentNeedsSync = true
80+ lp .pendingGotoBottom = true
6081 }
6182}
6283
@@ -76,7 +97,8 @@ func (lp *LogPanelComponent) AddTestLog(testID, line string) {
7697 }
7798
7899 if lp .currentTestID == testID {
79- lp .rebuildContent (true )
100+ lp .contentNeedsSync = true
101+ lp .pendingGotoBottom = true
80102 }
81103}
82104
@@ -106,7 +128,8 @@ func (lp *LogPanelComponent) SetCurrentTest(testID string) {
106128
107129 lp .currentTestID = testID
108130 lp .updateTitle ()
109- lp .rebuildContent (true )
131+ lp .contentNeedsSync = true
132+ lp .pendingGotoBottom = true
110133}
111134
112135// SetOffset sets the panel's position on screen (for mouse coordinate translation)
@@ -170,3 +193,9 @@ func (lp *LogPanelComponent) updateTitle() {
170193 lp .ContentPanel .SetTitle (title )
171194 }
172195}
196+
197+ // CopyAllLogs copies all currently visible logs to the clipboard
198+ func (lp * LogPanelComponent ) CopyAllLogs () tea.Cmd {
199+ text := lp .GetRawLogs ()
200+ return lp .ContentPanel .CopyText (text )
201+ }
0 commit comments