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
121
122
123
124
125
126
127
128
129
130
131
132
|
package avt
import (
"avt-go/parser"
"avt-go/terminal"
)
// Vt is the public virtual terminal API.
type Vt struct {
parser *parser.Parser
terminal *terminal.Terminal
}
// Builder builds a Vt with optional configuration.
type Builder struct {
cols int
rows int
scrollbackLimit *int
}
func NewBuilder() *Builder {
return &Builder{cols: 80, rows: 24}
}
func (b *Builder) Size(cols, rows int) *Builder {
b.cols = cols
b.rows = rows
return b
}
func (b *Builder) ScrollbackLimit(limit int) *Builder {
b.scrollbackLimit = &limit
return b
}
func (b *Builder) Build() *Vt {
return &Vt{
parser: parser.New(),
terminal: terminal.New(b.cols, b.rows, b.scrollbackLimit),
}
}
// New creates a Vt with the given dimensions and unlimited scrollback.
func New(cols, rows int) *Vt {
return NewBuilder().Size(cols, rows).Build()
}
// Changes holds what changed after a FeedStr or Resize call.
type Changes struct {
Lines []int
Scrollback []Line
}
// FeedStr feeds a string into the terminal and returns what changed.
func (v *Vt) FeedStr(s string) Changes {
for _, ch := range s {
if fun := v.parser.Feed(ch); fun != nil {
v.terminal.Execute(fun)
}
}
lines := v.terminal.Changes()
scrollback := v.terminal.GC()
return Changes{Lines: lines, Scrollback: scrollback}
}
// Feed feeds a single rune into the terminal.
func (v *Vt) Feed(ch rune) {
if fun := v.parser.Feed(ch); fun != nil {
v.terminal.Execute(fun)
}
}
// Size returns (cols, rows).
func (v *Vt) Size() (int, int) { return v.terminal.Size() }
// Resize resizes the terminal and returns what changed.
func (v *Vt) Resize(cols, rows int) Changes {
v.terminal.Resize(cols, rows)
lines := v.terminal.Changes()
scrollback := v.terminal.GC()
return Changes{Lines: lines, Scrollback: scrollback}
}
// View returns the visible lines (rows in viewport).
func (v *Vt) View() []*Line { return v.terminal.View() }
// Lines returns all lines including scrollback.
func (v *Vt) Lines() []*Line { return v.terminal.Lines() }
// Line returns the visual line at index n.
func (v *Vt) Line(n int) *Line { return v.terminal.Line(n) }
// Text returns the text content of the primary buffer.
func (v *Vt) Text() []string { return v.terminal.Text() }
// Cursor returns the current cursor state.
func (v *Vt) Cursor() terminal.Cursor { return v.terminal.Cursor() }
// CursorKeyAppMode returns whether cursor keys are in application mode.
func (v *Vt) CursorKeyAppMode() bool { return v.terminal.CursorKeysAppMode() }
// Snapshot returns a comparable snapshot of all terminal + parser state.
func (v *Vt) Snapshot() VtSnapshot {
return VtSnapshot{
Terminal: v.terminal.Snapshot(),
Parser: v.parser.Snapshot(),
}
}
// Verify checks internal consistency invariants. Returns a list of violation
// strings; empty means the terminal is in a valid state.
func (v *Vt) Verify() []string {
return v.terminal.Verify()
}
// VtSnapshot holds a comparable snapshot of Vt state.
type VtSnapshot struct {
Terminal terminal.Snapshot
Parser parser.ParserSnapshot
}
// Dump serialises the terminal state to a string that can be replayed.
func (v *Vt) Dump() string {
funs := v.terminal.Dump()
seq := parser.DumpFunctions(funs)
seq += v.parser.Dump()
return seq
}
|