aboutsummaryrefslogtreecommitdiff
path: root/internal/app/preview.go
blob: 8578808c9cc5d5a45d4480872429c958758e46e1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package app

import (
	"strings"

	"github.com/Fuwn/faustus/internal/claude"
)

func (m *Model) invalidatePreviewCache() {
	m.previewCache = nil
	m.previewFor = ""
	m.previewScroll = 0
}

func (m *Model) preview() *claude.PreviewContent {
	if len(m.filtered) == 0 {
		return nil
	}

	session := &m.filtered[m.cursor]

	if m.previewCache != nil && m.previewFor == session.SessionID {
		return m.previewCache
	}

	previewContent := claude.LoadSessionPreview(session, 50)
	m.previewCache = &previewContent
	m.previewFor = session.SessionID

	return m.previewCache
}

type previewMetrics struct {
	totalLines   int
	messageLines []int
}

func (m *Model) calculatePreviewMetrics() previewMetrics {
	preview := m.preview()

	if preview == nil || preview.Error != "" {
		return previewMetrics{}
	}

	width := m.previewWidth() - 8

	if width <= 0 {
		width = 40
	}

	var metrics previewMetrics

	lineCount := 0

	if m.cursor < len(m.filtered) {
		lineCount += 1
		lineCount += 1
		lineCount += 1
		lineCount += 1
	}

	for _, previewMessage := range preview.Messages {
		metrics.messageLines = append(metrics.messageLines, lineCount)

		lineCount += 1

		wrapped := wrapText(previewMessage.Content, width)
		contentLines := strings.Count(wrapped, "\n") + 1

		lineCount += contentLines
		lineCount += 1
	}

	metrics.totalLines = lineCount

	return metrics
}

func (m *Model) clampPreviewScroll() {
	height := m.listHeight() - 2
	metrics := m.calculatePreviewMetrics()
	maxScroll := max(0, metrics.totalLines-height+1)

	if m.previewScroll < 0 {
		m.previewScroll = 0
	}

	if m.previewScroll > maxScroll {
		m.previewScroll = maxScroll
	}
}

func (m *Model) scrollToPreviewMatch() {
	if len(m.previewSearchMatches) == 0 {
		return
	}

	matchMessageIndex := m.previewSearchMatches[m.previewSearchIndex]
	metrics := m.calculatePreviewMetrics()

	if matchMessageIndex >= len(metrics.messageLines) {
		return
	}

	lineNumber := metrics.messageLines[matchMessageIndex]
	height := m.listHeight() - 2
	m.previewScroll = max(0, lineNumber-height/3)

	m.clampPreviewScroll()
}