• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

fyne-io / terminal / 24010791979

05 Apr 2026 09:22PM UTC coverage: 54.077% (+1.2%) from 52.875%
24010791979

Pull #147

github

andydotxyz
First pass getting scrolling set up

I wanted to use the RichText scroller, but we need to align the cursor too...
Pull Request #147: Add scroll support

111 of 145 new or added lines in 6 files covered. (76.55%)

1 existing line in 1 file now uncovered.

1101 of 2036 relevant lines covered (54.08%)

1098.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.25
/render.go
1
package terminal
2

3
import (
4
        "image/color"
5

6
        "fyne.io/fyne/v2"
7
        "fyne.io/fyne/v2/canvas"
8
        "fyne.io/fyne/v2/container"
9
        "fyne.io/fyne/v2/theme"
10
        widget2 "github.com/fyne-io/terminal/internal/widget"
11
)
12

13
const cursorWidth = 2
14

15
// termContentLayout sizes the TextGrid to fill the container while
16
// reporting the TextGrid's full content MinSize for scroll bounds.
17
// The cursor is positioned manually and not affected by layout.
18
type termContentLayout struct {
19
        grid *widget2.TermGrid
20
}
21

22
func (l *termContentLayout) MinSize(_ []fyne.CanvasObject) fyne.Size {
119✔
23
        return l.grid.MinSize()
119✔
24
}
119✔
25

26
func (l *termContentLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) {
31✔
27
        for _, o := range objects {
93✔
28
                if o == l.grid {
93✔
29
                        o.Resize(size)
31✔
30
                        o.Move(fyne.NewPos(0, 0))
31✔
31
                }
31✔
32
        }
33
}
34

35
type render struct {
36
        term *Terminal
37
}
38

39
func (r *render) Layout(s fyne.Size) {
25✔
40
        if r.term.scrollContainer != nil {
50✔
41
                r.term.scrollContainer.Resize(s)
25✔
42
        }
25✔
43
}
44

45
func (r *render) MinSize() fyne.Size {
×
46
        return fyne.NewSize(0, 0) // don't get propped open by the text cells
×
47
}
×
48

49
func (r *render) Refresh() {
23✔
50
        fyne.Do(func() { // TODO fix root cause in refresh on wrong thread
46✔
51
                r.moveCursor()
23✔
52
                r.term.refreshCursor()
23✔
53
        })
23✔
54

55
        r.term.content.Refresh()
23✔
56
}
57

58
func (r *render) BackgroundColor() color.Color {
×
59
        return color.Transparent
×
60
}
×
61

62
func (r *render) Objects() []fyne.CanvasObject {
×
NEW
63
        return []fyne.CanvasObject{r.term.scrollContainer}
×
64
}
×
65

66
func (r *render) Destroy() {
×
67
}
×
68

69
func (r *render) moveCursor() {
197✔
70
        cell := r.term.guessCellSize()
197✔
71
        contentRow := r.term.rowOffset() + r.term.cursorRow
197✔
72

197✔
73
        // Position cursor at content-relative coordinates;
197✔
74
        // the scroll container handles making it scroll with the grid.
197✔
75
        r.term.cursor.Move(fyne.NewPos(cell.Width*float32(r.term.cursorCol), cell.Height*float32(contentRow)))
197✔
76
}
197✔
77

78
func (t *Terminal) refreshCursor() {
23✔
79
        t.cursor.Hidden = !t.focused || t.cursorHidden
23✔
80
        if t.bell {
23✔
81
                t.cursor.FillColor = theme.Color(theme.ColorNameError)
×
82
        } else {
23✔
83
                t.cursor.FillColor = theme.Color(theme.ColorNamePrimary)
23✔
84
        }
23✔
85
        t.cursor.Resize(fyne.NewSize(cursorWidth, t.guessCellSize().Height))
23✔
86
        t.cursor.Refresh()
23✔
87
}
88

89
// CreateRenderer requests a new renderer for this terminal (just a wrapper around the TextGrid)
90
func (t *Terminal) CreateRenderer() fyne.WidgetRenderer {
41✔
91
        t.ExtendBaseWidget(t)
41✔
92

41✔
93
        t.content = widget2.NewTermGrid()
41✔
94
        t.setupShortcuts()
41✔
95

41✔
96
        t.cursor = canvas.NewRectangle(theme.Color(theme.ColorNamePrimary))
41✔
97
        t.cursor.Hidden = true
41✔
98
        t.cursor.Resize(fyne.NewSize(cursorWidth, t.guessCellSize().Height))
41✔
99

41✔
100
        inner := container.New(&termContentLayout{grid: t.content}, t.content, t.cursor)
41✔
101
        t.scrollContainer = container.NewVScroll(inner)
41✔
102

41✔
103
        r := &render{term: t}
41✔
104
        t.cursorMoved = r.moveCursor
41✔
105
        return r
41✔
106
}
41✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc