Skip to content

Commit 08903fc

Browse files
committed
Factor REPL into CLI part and agnostic part and add tests
This is to facilitate reuse of the REPL. It also makes testing possible.
1 parent d13383c commit 08903fc

File tree

4 files changed

+350
-138
lines changed

4 files changed

+350
-138
lines changed

‎main.go‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import (
1212
"runtime/pprof"
1313

1414
_ "github.com/go-python/gpython/builtin"
15-
"github.com/go-python/gpython/repl"
15+
"github.com/go-python/gpython/repl/cli"
16+
1617
//_ "github.com/go-python/gpython/importlib"
1718
"io/ioutil"
1819
"log"
@@ -62,7 +63,7 @@ func main(){
6263
args:=flag.Args()
6364
py.MustGetModule("sys").Globals["argv"] =pysys.MakeArgv(args)
6465
iflen(args) ==0{
65-
repl.Run()
66+
cli.RunREPL()
6667
return
6768
}
6869
prog:=args[0]

‎repl/cli/cli.go‎

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Copyright 2018 The go-python Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Read Eval Print Loop for CLI
6+
package cli
7+
8+
import (
9+
"fmt"
10+
"io"
11+
"os"
12+
"os/user"
13+
"path/filepath"
14+
15+
"github.com/go-python/gpython/py"
16+
"github.com/go-python/gpython/repl"
17+
"github.com/peterh/liner"
18+
)
19+
20+
constHistoryFileName=".gpyhistory"
21+
22+
// homeDirectory finds the home directory or returns ""
23+
funchomeDirectory() string{
24+
usr, err:=user.Current()
25+
iferr==nil{
26+
returnusr.HomeDir
27+
}
28+
// Fall back to reading $HOME - work around user.Current() not
29+
// working for cross compiled binaries on OSX.
30+
// https://github.com/golang/go/issues/6376
31+
returnos.Getenv("HOME")
32+
}
33+
34+
// Holds state for readline services
35+
typereadlinestruct{
36+
*liner.State
37+
repl*repl.REPL
38+
historyFilestring
39+
module*py.Module
40+
promptstring
41+
}
42+
43+
// newReadline creates a new instance of readline
44+
funcnewReadline(repl*repl.REPL) *readline{
45+
rl:=&readline{
46+
State: liner.NewLiner(),
47+
repl: repl,
48+
}
49+
home:=homeDirectory()
50+
ifhome!=""{
51+
rl.historyFile=filepath.Join(home, HistoryFileName)
52+
}
53+
rl.SetTabCompletionStyle(liner.TabPrints)
54+
rl.SetWordCompleter(rl.Completer)
55+
returnrl
56+
}
57+
58+
// readHistory reads the history into the term
59+
func (rl*readline) ReadHistory() error{
60+
f, err:=os.Open(rl.historyFile)
61+
iferr!=nil{
62+
returnerr
63+
}
64+
deferf.Close()
65+
_, err=rl.State.ReadHistory(f)
66+
iferr!=nil{
67+
returnerr
68+
}
69+
returnnil
70+
}
71+
72+
// writeHistory writes the history from the term
73+
func (rl*readline) WriteHistory() error{
74+
f, err:=os.OpenFile(rl.historyFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
75+
iferr!=nil{
76+
returnerr
77+
}
78+
deferf.Close()
79+
_, err=rl.State.WriteHistory(f)
80+
iferr!=nil{
81+
returnerr
82+
}
83+
returnnil
84+
}
85+
86+
// Close the readline and write history
87+
func (rl*readline) Close() error{
88+
err:=rl.State.Close()
89+
iferr!=nil{
90+
returnerr
91+
}
92+
ifrl.historyFile!=""{
93+
err:=rl.WriteHistory()
94+
iferr!=nil{
95+
returnerr
96+
}
97+
}
98+
returnnil
99+
}
100+
101+
// Completer takes the currently edited line with the cursor
102+
// position and returns the completion candidates for the partial word
103+
// to be completed. If the line is "Hello, wo!!!" and the cursor is
104+
// before the first '!', ("Hello, wo!!!", 9) is passed to the
105+
// completer which may returns ("Hello, ",{"world", "Word"}, "!!!")
106+
// to have "Hello, world!!!".
107+
func (rl*readline) Completer(linestring, posint) (headstring, completions []string, tailstring){
108+
returnrl.repl.Completer(line, pos)
109+
}
110+
111+
// SetPrompt sets the current terminal prompt
112+
func (rl*readline) SetPrompt(promptstring){
113+
rl.prompt=prompt
114+
}
115+
116+
// Print prints the output
117+
func (rl*readline) Print(outstring){
118+
_, _=os.Stdout.WriteString(out+"\n")
119+
}
120+
121+
// RunREPL starts the REPL loop
122+
funcRunREPL(){
123+
repl:=repl.New()
124+
rl:=newReadline(repl)
125+
repl.SetUI(rl)
126+
deferrl.Close()
127+
err:=rl.ReadHistory()
128+
iferr!=nil{
129+
fmt.Printf("Failed to open history: %v\n", err)
130+
}
131+
132+
fmt.Printf("Gpython 3.4.0\n")
133+
134+
for{
135+
line, err:=rl.Prompt(rl.prompt)
136+
iferr!=nil{
137+
iferr==io.EOF{
138+
fmt.Printf("\n")
139+
break
140+
}
141+
fmt.Printf("Problem reading line: %v\n", err)
142+
continue
143+
}
144+
ifline!=""{
145+
rl.AppendHistory(line)
146+
}
147+
rl.repl.Run(line)
148+
}
149+
}

0 commit comments

Comments
(0)