Skip to content

Commit 038d3ee

Browse files
bug: rendering issues
move to a background refreshing thread approach
1 parent 18baa90 commit 038d3ee

File tree

5 files changed

+74
-57
lines changed

5 files changed

+74
-57
lines changed

area.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ func (a *area) Fd() uintptr {
2424
return os.Stdout.Fd()
2525
}
2626

27-
func (a *area) Finish(text string) {
28-
a.Update(text)
29-
cursor.Show()
30-
}
31-
3227
func (a *area) Update(text string) {
3328
if a.cursor == nil {
3429
c := cursor.NewArea().WithWriter(a)

display.go

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,28 @@ package tui
22

33
import (
44
"strings"
5+
"sync"
56
"time"
67

7-
"github.com/pterm/pterm"
8+
"atomicgo.dev/cursor"
89
)
910

1011
var (
11-
defaultDuration = 200 * time.Millisecond
12+
loopDelay = 200 * time.Millisecond
1213
)
1314

15+
type displayState struct {
16+
area area
17+
lastPrint string
18+
content string
19+
finish bool
20+
}
21+
1422
type display struct {
15-
area area
16-
prompter *prompter
17-
last time.Time
18-
lastDuration time.Duration
19-
stopped bool
23+
displayState
24+
prompter *prompter
25+
contentLock sync.Mutex
26+
closer func()
2027
}
2128

2229
func newDisplay(tool string) (*display, error) {
@@ -25,25 +32,43 @@ func newDisplay(tool string) (*display, error) {
2532
return nil, err
2633
}
2734

28-
return &display{
29-
prompter: prompter,
30-
lastDuration: defaultDuration,
31-
}, nil
35+
t := time.NewTicker(loopDelay)
36+
d := &display{
37+
prompter: prompter,
38+
closer: t.Stop,
39+
}
40+
41+
go func() {
42+
for range t.C {
43+
d.paint()
44+
}
45+
}()
46+
47+
return d, nil
48+
}
49+
50+
func (a *display) readline(f func() (string, bool)) (string, bool) {
51+
a.paint()
52+
cursor.Show()
53+
defer cursor.Hide()
54+
return f()
3255
}
3356

3457
func (a *display) Ask(text string, sensitive bool) (string, bool) {
3558
a.setMultiLinePrompt(text)
3659
if sensitive {
37-
return a.prompter.ReadPassword()
60+
return a.readline(a.prompter.ReadPassword)
3861
}
39-
return a.prompter.Readline()
62+
return a.readline(a.prompter.Readline)
4063
}
4164

4265
func (a *display) setMultiLinePrompt(text string) {
4366
lines := strings.Split(text, "\n")
4467
a.prompter.SetPrompt(lines[len(lines)-1])
4568
if len(lines) > 1 {
46-
a.area.Update(a.area.content + "\n" + strings.Join(lines[:len(lines)-1], "\n") + "\n")
69+
a.contentLock.Lock()
70+
defer a.contentLock.Unlock()
71+
a.content = a.area.content + "\n" + strings.Join(lines[:len(lines)-1], "\n") + "\n"
4772
}
4873
}
4974

@@ -58,7 +83,7 @@ const (
5883
func (a *display) AskYesNo(text string) (Answer, bool, error) {
5984
a.setMultiLinePrompt(text)
6085
for {
61-
line, ok := a.prompter.Readline()
86+
line, ok := a.readline(a.prompter.Readline)
6287
if !ok {
6388
return No, ok, nil
6489
}
@@ -75,49 +100,49 @@ func (a *display) AskYesNo(text string) (Answer, bool, error) {
75100

76101
func (a *display) Prompt(text string) (string, bool) {
77102
a.prompter.SetPrompt(text)
78-
return a.prompter.Readline()
103+
return a.readline(a.prompter.Readline)
79104
}
80105

81-
func (a *display) Progress(text string) error {
82-
if text == "" {
83-
return nil
106+
func (a *display) paint() {
107+
a.contentLock.Lock()
108+
if a.finish {
109+
a.area.Update(a.content)
110+
cursor.Show()
111+
a.displayState = displayState{}
112+
a.contentLock.Unlock()
113+
return
84114
}
85115

86-
if a.stopped {
87-
a.area = area{}
88-
a.stopped = false
89-
a.last = time.Time{}
90-
a.lastDuration = defaultDuration
91-
}
116+
newContent := a.content
117+
a.contentLock.Unlock()
92118

93-
start := time.Now()
94-
if start.Sub(a.last) > a.lastDuration {
95-
lines := strings.Split(text, "\n")
96-
height := pterm.GetTerminalHeight()
97-
if len(lines) > height {
98-
lines = lines[len(lines)-height:]
99-
}
100-
newText := strings.Join(lines, "\n")
101-
a.area.Update(newText)
102-
done := time.Now()
103-
delta := done.Sub(start)
104-
if delta > a.lastDuration {
105-
a.lastDuration = delta
106-
}
107-
a.last = done
119+
if newContent == a.lastPrint {
120+
return
108121
}
109122

110-
return nil
123+
a.area.Update(newContent)
124+
a.lastPrint = newContent
125+
}
126+
127+
func (a *display) Progress(text string) {
128+
a.contentLock.Lock()
129+
defer a.contentLock.Unlock()
130+
a.content = text
111131
}
112132

113133
func (a *display) Close() error {
134+
a.closer()
114135
return a.prompter.Close()
115136
}
116137

117138
func (a *display) Finished(text string) {
139+
defer a.paint()
140+
a.contentLock.Lock()
141+
defer a.contentLock.Unlock()
142+
118143
if !strings.HasSuffix(text, "\n") {
119144
text += "\n"
120145
}
121-
a.stopped = true
122-
a.area.Finish(text)
146+
a.finish = true
147+
a.content = text
123148
}

go.mod

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ require (
99
github.com/charmbracelet/lipgloss v0.11.0
1010
github.com/chzyer/readline v1.5.1
1111
github.com/fatih/color v1.17.0
12-
github.com/gptscript-ai/go-gptscript v0.9.3-0.20240731222146-b67275f3fa69
12+
github.com/gptscript-ai/go-gptscript v0.9.4-0.20240801203434-840b14393b17
1313
github.com/pterm/pterm v0.12.79
1414
github.com/sourcegraph/go-diff-patch v0.0.0-20240223163233-798fd1e94a8e
15-
github.com/stretchr/testify v1.8.4
1615
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc
1716
)
1817

@@ -24,7 +23,6 @@ require (
2423
github.com/aymerick/douceur v0.2.0 // indirect
2524
github.com/charmbracelet/x/ansi v0.1.1 // indirect
2625
github.com/containerd/console v1.0.4 // indirect
27-
github.com/davecgh/go-spew v1.1.1 // indirect
2826
github.com/dlclark/regexp2 v1.4.0 // indirect
2927
github.com/getkin/kin-openapi v0.124.0 // indirect
3028
github.com/go-openapi/jsonpointer v0.20.2 // indirect
@@ -45,7 +43,6 @@ require (
4543
github.com/muesli/termenv v0.15.2 // indirect
4644
github.com/olekukonko/tablewriter v0.0.6-0.20230925090304-df64c4bbad77 // indirect
4745
github.com/perimeterx/marshmallow v1.1.5 // indirect
48-
github.com/pmezard/go-difflib v1.0.0 // indirect
4946
github.com/rivo/uniseg v0.4.7 // indirect
5047
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
5148
github.com/yuin/goldmark v1.5.4 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
6464
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
6565
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
6666
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
67-
github.com/gptscript-ai/go-gptscript v0.9.3-0.20240731222146-b67275f3fa69 h1:c+Tf6I8jUg8hDgfP8jKs93UcC9dDIGxClWGZUL36Hd0=
68-
github.com/gptscript-ai/go-gptscript v0.9.3-0.20240731222146-b67275f3fa69/go.mod h1:Dh6vYRAiVcyC3ElZIGzTvNF1FxtYwA07BHfSiFKQY7s=
67+
github.com/gptscript-ai/go-gptscript v0.9.4-0.20240801203434-840b14393b17 h1:BTfJ6ls31Roq42lznlZnuPzRf0wrT8jT+tWcvq7wDXY=
68+
github.com/gptscript-ai/go-gptscript v0.9.4-0.20240801203434-840b14393b17/go.mod h1:Dh6vYRAiVcyC3ElZIGzTvNF1FxtYwA07BHfSiFKQY7s=
6969
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
7070
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
7171
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=

run.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"strings"
1515
"time"
1616

17+
"atomicgo.dev/cursor"
1718
"github.com/fatih/color"
1819
"github.com/gptscript-ai/go-gptscript"
1920
"github.com/pterm/pterm"
@@ -129,6 +130,7 @@ func Run(ctx context.Context, tool string, opts ...RunOptions) error {
129130
eventOut io.Writer
130131
)
131132
defer cancel()
133+
defer cursor.Show()
132134

133135
if err != nil {
134136
return err
@@ -256,9 +258,7 @@ func Run(ctx context.Context, tool string, opts ...RunOptions) error {
256258

257259
if event.Call != nil {
258260
text = render(input, run)
259-
if err := ui.Progress(text); err != nil {
260-
return err
261-
}
261+
ui.Progress(text)
262262
}
263263

264264
if ok, err := confirm.HandlePrompt(localCtx, event, ui.Ask); !ok {

0 commit comments

Comments
 (0)