diff --git a/tools/cmd/at/main.go b/tools/cmd/at/main.go index 86a141b25..7894d5e55 100644 --- a/tools/cmd/at/main.go +++ b/tools/cmd/at/main.go @@ -118,11 +118,12 @@ func do_io(device IOAbstraction, input utils.Reader, no_response bool, response_ response_received := false cmd_prefix := []byte("@kitty-cmd") - handle_dcs := func(b []byte) { + handle_dcs := func(b []byte) error { if bytes.HasPrefix(b, cmd_prefix) { response_received = true } serialized_response = b[len(cmd_prefix):] + return nil } var p utils.EscapeCodeParser = utils.EscapeCodeParser{HandleDCS: handle_dcs} diff --git a/tools/tui/loop.go b/tools/tui/loop.go index 97b25604f..11a0f7bd5 100644 --- a/tools/tui/loop.go +++ b/tools/tui/loop.go @@ -6,21 +6,56 @@ import ( "kitty/tools/tty" "os" "time" + + "kitty/tools/utils" ) -type TerminalState struct { - alternate_screen, grab_mouse bool +type Loop struct { + controlling_term *tty.Term + terminal_options TerminalStateOptions + escape_code_parser utils.EscapeCodeParser + keep_going bool + flush_write_buf bool + write_buf []byte } -type Loop struct { - controlling_term *tty.Term - keep_going bool - flush_write_buf bool - write_buf []byte +func (self *Loop) handle_csi(raw []byte) error { + return nil +} + +func (self *Loop) handle_osc(raw []byte) error { + return nil +} + +func (self *Loop) handle_dcs(raw []byte) error { + return nil +} + +func (self *Loop) handle_apc(raw []byte) error { + return nil +} + +func (self *Loop) handle_sos(raw []byte) error { + return nil +} + +func (self *Loop) handle_pm(raw []byte) error { + return nil +} + +func (self *Loop) handle_rune(raw rune) error { + return nil } func CreateLoop() (*Loop, error) { l := Loop{controlling_term: nil} + l.escape_code_parser.HandleCSI = l.handle_csi + l.escape_code_parser.HandleOSC = l.handle_osc + l.escape_code_parser.HandleDCS = l.handle_dcs + l.escape_code_parser.HandleAPC = l.handle_apc + l.escape_code_parser.HandleSOS = l.handle_sos + l.escape_code_parser.HandlePM = l.handle_pm + l.escape_code_parser.HandleRune = l.handle_rune return &l, nil } @@ -51,6 +86,7 @@ func (self *Loop) Run() (err error) { if err != nil { return err } + tty_fd := controlling_term.Fd() self.controlling_term = controlling_term defer func() { self.controlling_term.RestoreAndClose() @@ -63,18 +99,29 @@ func (self *Loop) Run() (err error) { var selector Select selector.RegisterRead(int(signal_read_file.Fd())) - selector.RegisterRead(controlling_term.Fd()) + selector.RegisterRead(tty_fd) self.keep_going = true self.flush_write_buf = true + self.queue_write_to_tty(self.terminal_options.SetStateEscapeCodes()) defer func() { if self.flush_write_buf { self.flush() } + self.write_buf = self.write_buf[:] + self.queue_write_to_tty(self.terminal_options.ResetStateEscapeCodes()) + self.flush() }() + read_buf := make([]byte, utils.DEFAULT_IO_BUFFER_SIZE) + self.escape_code_parser.Reset() for self.keep_going { + if len(self.write_buf) > 0 { + selector.RegisterWrite(tty_fd) + } else { + selector.UnRegisterWrite(tty_fd) + } num_ready, err := selector.WaitForever() if err != nil { return fmt.Errorf("Failed to call select() with error: %w", err) @@ -82,12 +129,36 @@ func (self *Loop) Run() (err error) { if num_ready == 0 { continue } + if len(self.write_buf) > 0 && selector.IsReadyToWrite(tty_fd) { + err := self.write_to_tty() + if err != nil { + return err + } + } + if selector.IsReadyToRead(tty_fd) { + read_buf = read_buf[:cap(read_buf)] + num_read, err := self.controlling_term.Read(read_buf) + if err != nil { + return err + } + if num_read == 0 { + return io.EOF + } + err = self.escape_code_parser.Parse(read_buf[:num_read]) + if err != nil { + return err + } + } } return nil } -func (self *Loop) write() error { +func (self *Loop) queue_write_to_tty(data []byte) { + self.write_buf = append(self.write_buf, data...) +} + +func (self *Loop) write_to_tty() error { if len(self.write_buf) == 0 || self.controlling_term == nil { return nil } @@ -125,7 +196,7 @@ func (self *Loop) flush() error { return err } if num_ready > 0 && selector.IsReadyToWrite(self.controlling_term.Fd()) { - err = self.write() + err = self.write_to_tty() if err != nil { return err } diff --git a/tools/tui/terminal-state.go b/tools/tui/terminal-state.go index 300525bd2..ee2503530 100644 --- a/tools/tui/terminal-state.go +++ b/tools/tui/terminal-state.go @@ -73,9 +73,9 @@ const ( FULL_MOUSE_TRACKING ) -type TerminalState struct { - alternate_screen, kitty_keyboard_mode bool - mouse_tracking MouseTracking +type TerminalStateOptions struct { + alternate_screen, no_kitty_keyboard_mode bool + mouse_tracking MouseTracking } func set_modes(sb *strings.Builder, modes ...Mode) { @@ -90,7 +90,7 @@ func reset_modes(sb *strings.Builder, modes ...Mode) { } } -func (self *TerminalState) SetStateEscapeCodes() []byte { +func (self *TerminalStateOptions) SetStateEscapeCodes() []byte { var sb strings.Builder sb.Grow(256) sb.WriteString(S7C1T) @@ -107,10 +107,10 @@ func (self *TerminalState) SetStateEscapeCodes() []byte { set_modes(&sb, ALTERNATE_SCREEN) sb.WriteString(CLEAR_SCREEN) } - if self.kitty_keyboard_mode { - sb.WriteString("\033[>31u") - } else { + if self.no_kitty_keyboard_mode { sb.WriteString("\033[>u") + } else { + sb.WriteString("\033[>31u") } if self.mouse_tracking != NO_MOUSE_TRACKING { sb.WriteString(MOUSE_SGR_PIXEL_MODE.EscapeCodeToSet()) @@ -126,7 +126,7 @@ func (self *TerminalState) SetStateEscapeCodes() []byte { return []byte(sb.String()) } -func (self *TerminalState) ResetStateData() []byte { +func (self *TerminalStateOptions) ResetStateEscapeCodes() []byte { var sb strings.Builder sb.Grow(64) sb.WriteString("\033[