Skip to content

Commit 870ffca

Browse files
authored
Add WriteWithChanges() method (#2)
1 parent 095aea6 commit 870ffca

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed

vt.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ type Terminal interface {
1919
// buffer empties. State is locked as soon as first rune is read, and unlocked
2020
// when buffer is empty.
2121
Parse(bf *bufio.Reader) error
22+
23+
// WriteWithChanges writes terminal changes to state and returns the line numbers that changed.
24+
WriteWithChanges(p []byte) ([]int, error)
2225
}
2326

2427
// View represents the view of the virtual terminal emulator.

vt_other.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,36 @@ func (t *terminal) Write(p []byte) (int, error) {
5656
return written, nil
5757
}
5858

59+
// WriteWithChanges writes to the terminal state and returns the line numbers that changed.
60+
func (t *terminal) WriteWithChanges(p []byte) ([]int, error) {
61+
var dirtyLines = make(map[int]bool)
62+
var written int
63+
r := bytes.NewReader(p)
64+
t.lock()
65+
defer t.unlock()
66+
for {
67+
c, sz, err := r.ReadRune()
68+
if err != nil {
69+
if err == io.EOF {
70+
break
71+
}
72+
return nil, err
73+
}
74+
written += sz
75+
if c == unicode.ReplacementChar && sz == 1 {
76+
if r.Len() == 0 {
77+
// not enough bytes for a full rune
78+
return nil, nil
79+
}
80+
t.logln("invalid utf8 sequence")
81+
continue
82+
}
83+
t.put(c)
84+
dirtyLines[t.cur.Y] = true
85+
}
86+
return uniqueSorted(dirtyLines), nil
87+
}
88+
5989
// TODO: add tests for expected blocking behavior
6090
func (t *terminal) Parse(br *bufio.Reader) error {
6191
var locked bool

vt_posix.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"bufio"
77
"bytes"
88
"io"
9+
"slices"
910
"unicode"
1011
"unicode/utf8"
1112
)
@@ -57,6 +58,61 @@ func (t *terminal) Write(p []byte) (int, error) {
5758
return written, nil
5859
}
5960

61+
// WriteWithChanges writes to the terminal state and returns the line numbers that changed.
62+
func (t *terminal) WriteWithChanges(p []byte) ([]int, error) {
63+
var dirtyLines = make(map[int]bool)
64+
r := bytes.NewReader(p)
65+
t.lock()
66+
67+
prevRow := t.cur.Y
68+
69+
defer t.unlock()
70+
for {
71+
c, sz, err := r.ReadRune()
72+
if err != nil {
73+
if err == io.EOF {
74+
break
75+
}
76+
return uniqueSorted(dirtyLines), err
77+
}
78+
if c == unicode.ReplacementChar && sz == 1 {
79+
if r.Len() == 0 {
80+
return uniqueSorted(dirtyLines), nil
81+
}
82+
t.logln("invalid utf8 sequence")
83+
continue
84+
}
85+
86+
beforeRow := t.cur.Y
87+
t.put(c)
88+
afterRow := t.cur.Y
89+
90+
dirtyLines[beforeRow] = true
91+
if afterRow != beforeRow {
92+
dirtyLines[afterRow] = true
93+
}
94+
95+
if t.cur.Y != prevRow {
96+
prevRow = t.cur.Y
97+
}
98+
}
99+
100+
return uniqueSorted(dirtyLines), nil
101+
}
102+
103+
func uniqueSorted(m map[int]bool) []int {
104+
lines := make([]int, 0, len(m))
105+
for line := range m {
106+
lines = append(lines, line)
107+
}
108+
if len(lines) == 0 {
109+
return lines
110+
}
111+
112+
slices.Sort(lines)
113+
return lines
114+
}
115+
60116
// TODO: add tests for expected blocking behavior
61117
func (t *terminal) Parse(br *bufio.Reader) error {
62118
var locked bool

0 commit comments

Comments
 (0)