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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
package loop
import (
"fmt"
"io"
"os"
"regexp"
"strings"
"time"
"golang.org/x/sys/unix"
"github.com/kovidgoyal/go-parallel"
"github.com/kovidgoyal/kitty/tools/tty"
"github.com/kovidgoyal/kitty/tools/utils"
)
var _ = fmt.Print
func (self *Loop) dispatch_input_data(data []byte) error {
if self.OnReceivedData != nil {
err := self.OnReceivedData(data)
if err != nil {
return err
}
}
err := self.escape_code_parser.Parse(data)
if err != nil {
return err
}
return nil
}
func read_ignoring_temporary_errors(f *tty.Term, buf []byte) (int, error) {
n, err := f.Read(buf)
if is_temporary_error(err) {
return 0, nil
}
if n == 0 {
return 0, io.EOF
}
return n, err
}
func read_from_tty(pipe_r *os.File, term *tty.Term, results_channel chan<- []byte, err_channel chan<- error, quit_channel <-chan byte, leftover_channel chan<- []byte) {
defer func() {
if r := recover(); r != nil {
err := parallel.Format_stacktrace_on_panic(r, 1)
err_channel <- err
}
}()
keep_going := true
pipe_fd := int(pipe_r.Fd())
tty_fd := term.Fd()
selector := utils.CreateSelect(2)
selector.RegisterRead(pipe_fd)
selector.RegisterRead(tty_fd)
defer func() {
close(results_channel)
pipe_r.Close()
}()
const bufsize = 2 * utils.DEFAULT_IO_BUFFER_SIZE
wait_for_read_available := func() {
for {
n, err := selector.WaitForever()
if err != nil && err != unix.EINTR {
err_channel <- err
keep_going = false
return
}
if n > 0 {
break
}
}
if selector.IsReadyToRead(pipe_fd) {
keep_going = false
}
}
buf := make([]byte, bufsize)
for keep_going {
if len(buf) < 64 {
buf = make([]byte, bufsize)
}
if wait_for_read_available(); !keep_going {
break
}
n, err := read_ignoring_temporary_errors(term, buf)
if err != nil {
err_channel <- err
keep_going = false
break
}
if n == 0 { // temporary error
continue
}
send := buf[:n]
buf = buf[n:]
select {
case results_channel <- send:
case <-quit_channel:
leftover_channel <- send
keep_going = false
}
}
}
func has_da1_response(s string) bool {
pat := regexp.MustCompile("\x1b\\[\\?[0-9:;]+c")
return pat.FindString(s) != ""
}
func read_until_primary_device_attributes_response(term *tty.Term, initial_bytes []byte, timeout time.Duration) {
s := strings.Builder{}
if initial_bytes != nil {
s.Write(initial_bytes)
}
received := make(chan error)
go func() {
defer func() {
if r := recover(); r != nil {
text := parallel.Format_stacktrace_on_panic(r, 1).Error()
received <- fmt.Errorf("%s", text)
}
}()
buf := make([]byte, 1024)
n, err := read_ignoring_temporary_errors(term, buf)
if n > 0 {
s.Write(buf[:n])
if has_da1_response(s.String()) {
received <- nil
return
}
}
if err != nil {
received <- err
}
}()
select {
case <-received:
case <-time.After(timeout):
}
}
|