forked from x-motemen/gore
-
Notifications
You must be signed in to change notification settings - Fork 0
/
liner.go
120 lines (101 loc) · 1.96 KB
/
liner.go
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
111
112
113
114
115
116
117
118
119
120
package gore
import (
"bytes"
"fmt"
"io"
"strings"
"text/scanner"
"github.com/peterh/liner"
)
const (
promptDefault = "gore> "
promptContinue = "..... "
indent = " "
)
type contLiner struct {
*liner.State
buffer string
depth int
}
func newContLiner() *contLiner {
rl := liner.NewLiner()
rl.SetCtrlCAborts(true)
return &contLiner{State: rl}
}
func (cl *contLiner) promptString() string {
if cl.buffer != "" {
return promptContinue + strings.Repeat(indent, cl.depth)
}
return promptDefault
}
func (cl *contLiner) Prompt() (string, error) {
line, err := cl.State.Prompt(cl.promptString())
if err == io.EOF {
if cl.buffer != "" {
// cancel line continuation
cl.Accepted()
fmt.Println()
err = nil
}
} else if err == liner.ErrPromptAborted {
err = nil
if cl.buffer != "" {
cl.Accepted()
} else {
fmt.Println("(^D to quit)")
}
} else if err == nil {
if cl.buffer != "" {
cl.buffer = cl.buffer + "\n" + line
} else {
cl.buffer = line
}
}
return cl.buffer, err
}
func (cl *contLiner) Accepted() {
cl.State.AppendHistory(cl.buffer)
cl.buffer = ""
}
func (cl *contLiner) Clear() {
cl.buffer = ""
cl.depth = 0
}
var errUnmatchedBraces = fmt.Errorf("unmatched braces")
func (cl *contLiner) Reindent() error {
oldDepth := cl.depth
cl.depth = cl.countDepth()
if cl.depth < 0 {
return errUnmatchedBraces
}
if cl.depth < oldDepth {
lines := strings.Split(cl.buffer, "\n")
if len(lines) > 1 {
lastLine := lines[len(lines)-1]
cursorUp()
fmt.Printf("\r%s%s", cl.promptString(), lastLine)
eraseInLine()
fmt.Print("\n")
}
}
return nil
}
func (cl *contLiner) countDepth() int {
reader := bytes.NewBufferString(cl.buffer)
sc := new(scanner.Scanner)
sc.Init(reader)
sc.Error = func(_ *scanner.Scanner, msg string) {
debugf("scanner: %s", msg)
}
depth := 0
for {
switch sc.Scan() {
case '{', '(':
depth++
case '}', ')':
depth--
case scanner.EOF:
return depth
}
}
}