Implement sen text from stdin for the tty backend

This commit is contained in:
Kovid Goyal 2022-09-01 18:58:35 +05:30
parent 85169c989f
commit cb452ba9fc
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 80 additions and 3 deletions

View File

@ -17,16 +17,18 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"github.com/jamesruan/go-rfc1924/base85"
"kitty" "kitty"
"kitty/tools/cli" "kitty/tools/cli"
"kitty/tools/crypto" "kitty/tools/crypto"
"kitty/tools/tty" "kitty/tools/tty"
"kitty/tools/tui" "kitty/tools/tui"
"kitty/tools/tui/loop"
"kitty/tools/utils" "kitty/tools/utils"
"github.com/jamesruan/go-rfc1924/base85"
) )
var ProtocolVersion [3]int = [3]int{0, 20, 0} var ProtocolVersion [3]int = [3]int{0, 26, 0}
func add_bool_set(cmd *cobra.Command, name string, short string, usage string) *bool { func add_bool_set(cmd *cobra.Command, name string, short string, usage string) *bool {
if short == "" { if short == "" {
@ -143,7 +145,7 @@ type rc_io_data struct {
cmd *cobra.Command cmd *cobra.Command
rc *utils.RemoteControlCmd rc *utils.RemoteControlCmd
serializer serializer_func serializer serializer_func
send_keypresses bool on_key_event func(lp *loop.Loop, ke *loop.KeyEvent) error
string_response_is_err bool string_response_is_err bool
timeout time.Duration timeout time.Duration
multiple_payload_generator func(io_data *rc_io_data) (bool, error) multiple_payload_generator func(io_data *rc_io_data) (bool, error)
@ -184,6 +186,11 @@ func get_response(do_io func(io_data *rc_io_data) ([]byte, error), io_data *rc_i
return return
} }
if len(serialized_response) == 0 { if len(serialized_response) == 0 {
if io_data.rc.NoResponse {
res := Response{Ok: true}
ans = &res
return
}
err = fmt.Errorf("Received empty response from kitty") err = fmt.Errorf("Received empty response from kitty")
return return
} }

View File

@ -6,11 +6,16 @@ import (
"encoding/base64" "encoding/base64"
"errors" "errors"
"io" "io"
"kitty/tools/tui/loop"
"os" "os"
"strings" "strings"
) )
var end_reading_from_stdin = errors.New("end reading from STDIN")
var waiting_on_stdin = errors.New("wait for key events from STDIN")
func parse_send_text(io_data *rc_io_data, args []string) error { func parse_send_text(io_data *rc_io_data, args []string) error {
io_data.rc.NoResponse = true
generators := make([]func(io_data *rc_io_data) (bool, error), 0, 1) generators := make([]func(io_data *rc_io_data) (bool, error), 0, 1)
if len(args) > 0 { if len(args) > 0 {
@ -44,6 +49,39 @@ func parse_send_text(io_data *rc_io_data, args []string) error {
generators = append(generators, file_gen) generators = append(generators, file_gen)
} }
if options_send_text.stdin {
pending_key_events := make([]string, 0, 1)
io_data.on_key_event = func(lp *loop.Loop, ke *loop.KeyEvent) error {
ke.Handled = true
if ke.MatchesPressOrRepeat("ctrl+d") {
return end_reading_from_stdin
}
bs := "kitty-key:" + base64.StdEncoding.EncodeToString([]byte(ke.AsCSI()))
pending_key_events = append(pending_key_events, bs)
if ke.Text != "" {
lp.QueueWriteString(ke.Text)
} else if ke.MatchesPressOrRepeat("backspace") {
lp.QueueWriteString("\x08\x1b[P")
}
return nil
}
key_gen := func(io_data *rc_io_data) (bool, error) {
if len(pending_key_events) > 0 {
payload := io_data.rc.Payload.(send_text_json_type)
payload.Exclude_active = true
io_data.rc.Payload = payload
set_payload_data(io_data, pending_key_events[0])
pending_key_events = pending_key_events[1:]
return false, nil
}
return false, waiting_on_stdin
}
generators = append(generators, key_gen)
}
io_data.multiple_payload_generator = func(io_data *rc_io_data) (bool, error) { io_data.multiple_payload_generator = func(io_data *rc_io_data) (bool, error) {
if len(generators) == 0 { if len(generators) == 0 {
set_payload_data(io_data, "text:") set_payload_data(io_data, "text:")

View File

@ -46,6 +46,9 @@ func do_chunked_io(io_data *rc_io_data) (serialized_response []byte, err error)
if state != WAITING_FOR_RESPONSE && state != WAITING_FOR_STREAMING_RESPONSE { if state != WAITING_FOR_RESPONSE && state != WAITING_FOR_STREAMING_RESPONSE {
return nil return nil
} }
if io_data.on_key_event != nil {
return nil
}
time_since_last_received_data := time.Now().Sub(last_received_data_at) time_since_last_received_data := time.Now().Sub(last_received_data_at)
if time_since_last_received_data >= io_data.timeout { if time_since_last_received_data >= io_data.timeout {
return os.ErrDeadlineExceeded return os.ErrDeadlineExceeded
@ -77,6 +80,9 @@ func do_chunked_io(io_data *rc_io_data) (serialized_response []byte, err error)
chunk, err := io_data.next_chunk() chunk, err := io_data.next_chunk()
wants_streaming = io_data.rc.Stream wants_streaming = io_data.rc.Stream
if err != nil { if err != nil {
if err == waiting_on_stdin {
return "", nil
}
return "", err return "", err
} }
queue_escape_code(chunk) queue_escape_code(chunk)
@ -93,6 +99,9 @@ func do_chunked_io(io_data *rc_io_data) (serialized_response []byte, err error)
} }
chunk, err := io_data.next_chunk() chunk, err := io_data.next_chunk()
if err != nil { if err != nil {
if err == waiting_on_stdin {
return nil
}
return err return err
} }
queue_escape_code(chunk) queue_escape_code(chunk)
@ -111,6 +120,29 @@ func do_chunked_io(io_data *rc_io_data) (serialized_response []byte, err error)
return nil return nil
} }
lp.OnKeyEvent = func(event *loop.KeyEvent) error {
if io_data.on_key_event == nil {
return nil
}
err := io_data.on_key_event(lp, event)
if err == end_reading_from_stdin {
lp.Quit(0)
return nil
}
if err != nil {
return err
}
chunk, err := io_data.next_chunk()
if err != nil {
if err == waiting_on_stdin {
return nil
}
return err
}
queue_escape_code(chunk)
return err
}
lp.OnRCResponse = func(raw []byte) error { lp.OnRCResponse = func(raw []byte) error {
if state == WAITING_FOR_STREAMING_RESPONSE && is_stream_response(raw) { if state == WAITING_FOR_STREAMING_RESPONSE && is_stream_response(raw) {
state = SENDING state = SENDING