Skip to content

Commit 77eee7b

Browse files
committed
Use/demo history from PR for golang/go#68780
1 parent c1304b2 commit 77eee7b

File tree

4 files changed

+74
-7
lines changed

4 files changed

+74
-7
lines changed

example/main.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"errors"
5+
"flag"
56
"fmt"
67
"io"
78
"os"
@@ -56,7 +57,7 @@ func autoCompleteCallback(line string, pos int, key rune) (newLine string, newPo
5657

5758
func Main() int {
5859
// Pending https://github.com/golang/go/issues/68780
59-
// flagHistory := flag.String("history", "", "History `file` to use")
60+
flagHistory := flag.String("history", "/tmp/terminal_history", "History `file` to use")
6061
cli.Main()
6162
t, err := terminal.Open()
6263
if err != nil {
@@ -65,6 +66,7 @@ func Main() int {
6566
defer t.Close()
6667
t.SetPrompt("Terminal demo> ")
6768
t.LoggerSetup()
69+
t.SetHistoryFile(*flagHistory)
6870
fmt.Fprintf(t.Out, "Terminal is open\nis valid %t\nuse exit or ^D or ^C to exit\n", t.IsTerminal())
6971
fmt.Fprintf(t.Out, "Use 'prompt <new prompt>' to change the prompt\n")
7072
fmt.Fprintf(t.Out, "Try 'after duration text...' to see text showing in the middle of edits after said duration\n")

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
)
1010

1111
// replace fortio.org/cli => ../cli
12+
replace golang.org/x/term => github.com/ldemailly/term v0.0.0-20240808164309-1ca6c26d14bf
1213

1314
require (
1415
fortio.org/struct2env v0.4.1 // indirect

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ fortio.org/version v1.0.4 h1:FWUMpJ+hVTNc4RhvvOJzb0xesrlRmG/a+D6bjbQ4+5U=
88
fortio.org/version v1.0.4/go.mod h1:2JQp9Ax+tm6QKiGuzR5nJY63kFeANcgrZ0osoQFDVm0=
99
github.com/kortschak/goroutine v1.1.2 h1:lhllcCuERxMIK5cYr8yohZZScL1na+JM5JYPRclWjck=
1010
github.com/kortschak/goroutine v1.1.2/go.mod h1:zKpXs1FWN/6mXasDQzfl7g0LrGFIOiA6cLs9eXKyaMY=
11+
github.com/ldemailly/term v0.0.0-20240808164309-1ca6c26d14bf h1:tSC3QHTyGX/bno3fLgNBikbqJ5+/qBh8bFJVnCXsBrw=
12+
github.com/ldemailly/term v0.0.0-20240808164309-1ca6c26d14bf/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
1113
golang.org/x/crypto/x509roots/fallback v0.0.0-20240626151235-a6a393ffd658 h1:i7K6wQLN/0oxF7FT3tKkfMCstxoT4VGG36YIB9ZKLzI=
1214
golang.org/x/crypto/x509roots/fallback v0.0.0-20240626151235-a6a393ffd658/go.mod h1:kNa9WdvYnzFwC79zRpLRMJbdEFlhyM5RPFBBZp/wWH8=
1315
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
1416
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
15-
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
16-
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=

terminal.go

+68-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
package terminal // import "fortio.org/terminal"
33

44
import (
5+
"bufio"
56
"io"
67
"os"
78

@@ -10,10 +11,11 @@ import (
1011
)
1112

1213
type Terminal struct {
13-
fd int
14-
oldState *term.State
15-
term *term.Terminal
16-
Out io.Writer
14+
fd int
15+
oldState *term.State
16+
term *term.Terminal
17+
Out io.Writer
18+
historyFile string
1719
}
1820

1921
// CRWriter is a writer that adds \r before each \n.
@@ -100,13 +102,75 @@ func (t *Terminal) LoggerSetup() {
100102
log.SetColorMode()
101103
}
102104

105+
func (t *Terminal) SetHistoryFile(f string) {
106+
t.historyFile = f
107+
entries := readOrCreateHistory(f)
108+
for _, e := range entries {
109+
t.term.AddToHistory(e)
110+
}
111+
log.Infof("Loaded %d history entries from %s", len(entries), f)
112+
}
113+
114+
func readOrCreateHistory(f string) []string {
115+
if f == "" {
116+
log.Infof("No history file specified")
117+
return nil
118+
}
119+
// open file or create it
120+
h, err := os.OpenFile(f, os.O_RDWR|os.O_CREATE, 0o600)
121+
if err != nil {
122+
log.Errf("Error opening history file %s: %v", f, err)
123+
return nil
124+
}
125+
defer h.Close()
126+
// read lines separated by \n
127+
var lines []string
128+
scanner := bufio.NewScanner(h)
129+
for scanner.Scan() {
130+
lines = append(lines, scanner.Text())
131+
}
132+
if err := scanner.Err(); err != nil {
133+
log.Errf("Error reading history file %s: %v", f, err)
134+
return nil
135+
}
136+
return lines
137+
}
138+
139+
func saveHistory(f string, h []string) {
140+
if f == "" {
141+
log.Infof("No history file specified")
142+
return
143+
}
144+
// open file or create it
145+
hf, err := os.OpenFile(f, os.O_RDWR|os.O_CREATE, 0o600)
146+
if err != nil {
147+
log.Errf("Error opening history file %s: %v", f, err)
148+
return
149+
}
150+
defer hf.Close()
151+
// write lines separated by \n
152+
for _, l := range h {
153+
_, err := hf.WriteString(l + "\n")
154+
if err != nil {
155+
log.Errf("Error writing history file %s: %v", f, err)
156+
return
157+
}
158+
}
159+
}
160+
103161
func (t *Terminal) Close() error {
104162
if t.oldState == nil {
105163
return nil
106164
}
107165
err := term.Restore(t.fd, t.oldState)
108166
t.oldState = nil
109167
t.Out = os.Stderr
168+
// saving history if any
169+
if t.historyFile != "" {
170+
h := t.term.History()
171+
log.Infof("Saving history (%d commands) to %s", len(h), t.historyFile)
172+
saveHistory(t.historyFile, h)
173+
}
110174
return err
111175
}
112176

0 commit comments

Comments
 (0)