From f8dd59ebb0767c302a93782caaf8260a025333b2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 16 Apr 2026 20:47:16 +0530 Subject: [PATCH] Loop callback for dnd escape codes --- tools/tui/loop/api.go | 11 ++++++++++ tools/tui/loop/run.go | 51 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/tools/tui/loop/api.go b/tools/tui/loop/api.go index e43a9665e..9fcbacc5e 100644 --- a/tools/tui/loop/api.go +++ b/tools/tui/loop/api.go @@ -41,6 +41,14 @@ const ( PM ) +type DndCommand struct { + Type byte + Has_more bool + Operation int + X, Y, Xp, Yp int + Payload []byte +} + type Loop struct { controlling_term *tty.Term terminal_options TerminalStateOptions @@ -102,6 +110,9 @@ type Loop struct { // Called when a response to a query command is received OnQueryResponse func(key, val string, valid bool) error + // Called when a drag and drop protocol escape code is received + OnDnDData func(cmd DndCommand) error + // Called when any input from tty is received OnReceivedData func(data []byte) error diff --git a/tools/tui/loop/run.go b/tools/tui/loop/run.go index cf6651cf7..1a9c1aa79 100644 --- a/tools/tui/loop/run.go +++ b/tools/tui/loop/run.go @@ -16,6 +16,7 @@ import ( "golang.org/x/sys/unix" + "github.com/kovidgoyal/kitty" "github.com/kovidgoyal/kitty/tools/tty" "github.com/kovidgoyal/kitty/tools/utils" ) @@ -233,7 +234,57 @@ func (self *Loop) handle_key_event(ev *KeyEvent) error { return nil } +func (self *Loop) handle_dnd(data []byte) error { + var payload []byte + if idx := bytes.IndexByte(data, ';'); idx >= 0 { + payload = data[idx+1:] + data = data[:idx] + } + cmd := DndCommand{Payload: payload} + for field := range bytes.SplitSeq(data, []byte{':'}) { + if k, v, found := bytes.Cut(field, []byte{'='}); found && len(k) == 1 && len(v) > 0 { + switch k[0] { + case 't': + cmd.Type = v[0] + case 'm': + cmd.Has_more = v[0] == '1' + case 'o': + if val, err := strconv.Atoi(utils.UnsafeBytesToString(v)); err == nil { + cmd.Operation = val + } + case 'x': + if val, err := strconv.Atoi(utils.UnsafeBytesToString(v)); err == nil { + cmd.X = val + } + case 'y': + if val, err := strconv.Atoi(utils.UnsafeBytesToString(v)); err == nil { + cmd.Y = val + } + case 'X': + if val, err := strconv.Atoi(utils.UnsafeBytesToString(v)); err == nil { + cmd.Xp = val + } + case 'Y': + if val, err := strconv.Atoi(utils.UnsafeBytesToString(v)); err == nil { + cmd.Yp = val + } + } + } + } + return self.OnDnDData(cmd) +} + func (self *Loop) handle_osc(raw []byte) error { + if idx := bytes.IndexByte(raw, ';'); idx >= 2 { + if code, err := strconv.ParseUint(utils.UnsafeBytesToString(raw[:idx]), 10, 0); err == nil { + switch code { + case uint64(kitty.DndCode): + if self.OnDnDData != nil { + return self.handle_dnd(raw[idx+1:]) + } + } + } + } if self.OnEscapeCode != nil { return self.OnEscapeCode(OSC, raw) }