Work on implementing ttyio via TUI

This commit is contained in:
Kovid Goyal
2022-08-25 13:07:39 +05:30
parent 0913b64c6b
commit 2ffba1c422
5 changed files with 134 additions and 6 deletions

View File

@@ -5,6 +5,7 @@ package at
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"os"
@@ -128,6 +129,34 @@ type rc_io_data struct {
send_keypresses bool
string_response_is_err bool
timeout time.Duration
pending_chunks [][]byte
}
func (self *rc_io_data) next_chunk(limit_size bool) (chunk []byte, err error) {
if len(self.pending_chunks) > 0 {
chunk = self.pending_chunks[0]
copy(self.pending_chunks, self.pending_chunks[1:])
self.pending_chunks = self.pending_chunks[:len(self.pending_chunks)-1]
return
}
block, err := self.next_block(self.rc, self.serializer)
if err != nil && !errors.Is(err, io.EOF) {
return
}
err = nil
const limit = 2048
if !limit_size || len(block) < limit {
chunk = block
return
}
chunk = block[:limit]
block = block[limit:]
for len(block) > 0 {
self.pending_chunks = append(self.pending_chunks, block[:limit])
block = block[limit:]
}
return
}
func get_response(do_io func(io_data *rc_io_data) ([]byte, error), io_data *rc_io_data) (ans *Response, err error) {
@@ -137,6 +166,9 @@ func get_response(do_io func(io_data *rc_io_data) ([]byte, error), io_data *rc_i
io_data.rc.Payload = nil
io_data.rc.CancelAsync = true
io_data.rc.NoResponse = true
io_data.next_block = func(rc *utils.RemoteControlCmd, serializer serializer_func) ([]byte, error) {
return serializer(rc)
}
_, err = do_io(io_data)
}
return

View File

@@ -63,7 +63,7 @@ func run_CMD_NAME(cmd *cobra.Command, args []string) (err error) {
timeout: time.Duration(timeout * float64(time.Second)),
string_response_is_err: STRING_RESPONSE_IS_ERROR,
next_block: func(rc *utils.RemoteControlCmd, serializer serializer_func) ([]byte, error) {
return make([]byte, 0), nil
return serializer(rc)
},
}
err = create_payload_CMD_NAME(&io_data, args)

View File

@@ -2,6 +2,79 @@
package at
func do_tty_io(io_data *rc_io_data) (serialized_response []byte, err error) {
import (
"kitty/tools/tui"
"os"
"time"
)
func do_chunked_io(io_data *rc_io_data) (serialized_response []byte, err error) {
serialized_response = make([]byte, 0)
loop, err := tui.CreateLoop()
loop.NoAlternateScreen()
if err != nil {
return
}
var last_received_data_at time.Time
check_for_timeout := func(loop *tui.Loop, timer_id tui.TimerId) error {
if time.Now().Sub(last_received_data_at) > io_data.timeout {
return os.ErrDeadlineExceeded
}
return nil
}
transition_to_read := func() {
if io_data.rc.NoResponse {
loop.Quit(0)
}
last_received_data_at = time.Now()
loop.AddTimer(10*time.Millisecond, true, check_for_timeout)
}
loop.OnReceivedData = func(loop *tui.Loop, data []byte) error {
last_received_data_at = time.Now()
return nil
}
loop.OnInitialize = func(loop *tui.Loop) (string, error) {
chunk, err := io_data.next_chunk(true)
if err != nil {
return "", err
}
if len(chunk) == 0 {
transition_to_read()
} else {
loop.QueueWriteBytes(chunk)
}
return "", nil
}
loop.OnWriteComplete = func(loop *tui.Loop) error {
chunk, err := io_data.next_chunk(true)
if err != nil {
return err
}
if len(chunk) == 0 {
transition_to_read()
} else {
loop.QueueWriteBytes(chunk)
}
return nil
}
loop.OnRCResponse = func(loop *tui.Loop, raw []byte) error {
serialized_response = raw
loop.Quit(0)
return nil
}
err = loop.Run()
return
}
func do_tty_io(io_data *rc_io_data) (serialized_response []byte, err error) {
return do_chunked_io(io_data)
}