More work on dnd kitten

This commit is contained in:
Kovid Goyal
2026-05-11 21:51:23 +05:30
parent 43b028bd6a
commit 634f13e65f
4 changed files with 79 additions and 61 deletions

View File

@@ -391,7 +391,7 @@ examine the :ref:`machine_id` sent with the enable drag offers
from the URI list. To request data for a particular entry, terminals send an
escape code of the form::
OSC _dnd_code ; t=k:x=idx ; base64 encoded file data ST
OSC _dnd_code ; t=k:x=idx ST
Here ``idx`` is the one based index into the list of entries in the
``text/uri-list`` MIME type. Then the client can respond with the data

View File

@@ -23,7 +23,6 @@ var _ = fmt.Print
type data_request struct {
drag_source *drag_source
send_remote_data bool
index int
write_id loop.IdType
base64 streaming_base64.StreamingBase64Encoder
@@ -51,7 +50,7 @@ type drag_status struct {
current_remote_file *remote_data_item
dir_handle_counter int
remote_item_write_id loop.IdType
remote_data_was_sent bool
remote_data_requests []int
}
func find_drag_image(drag_sources map[string]*drag_source) image.Image {
@@ -66,12 +65,10 @@ func find_drag_image(drag_sources map[string]*drag_source) image.Image {
}
}
var uri_list []string
if ds := drag_sources["text/uri-list"]; ds != nil && len(ds.data) > 0 {
if q, err := parse_uri_list(string(ds.data)); err == nil {
for _, path := range q {
if path != "" {
uri_list = append(uri_list, path)
}
if ds := drag_sources["text/uri-list"]; ds != nil {
for _, e := range ds.uri_list {
if e.path != "" {
uri_list = append(uri_list, e.path)
}
}
}
@@ -102,16 +99,14 @@ func (dnd *dnd) set_drag_image_text() (err error) {
}
}
if icon == "" {
if ds := dnd.drag_sources["text/uri-list"]; ds != nil && len(ds.data) > 0 {
if q, err := parse_uri_list(string(ds.data)); err == nil {
for _, path := range q {
if path != "" && from_path(path) {
if ds := dnd.drag_sources["text/uri-list"]; ds != nil {
for _, e := range ds.uri_list {
if e.path != "" && from_path(e.path) {
break
}
}
}
}
}
if icon == "" {
icon = strings.TrimSpace("󰮐 ")
}
@@ -219,7 +214,7 @@ func (dnd *dnd) reset_drag() {
dnd.drag_status = drag_status{}
}
func (dnd *dnd) on_drag_event(x, y, operation, Y int) (err error) {
func (dnd *dnd) on_drag_event(x, y, operation int) (err error) {
switch x {
case 1:
dnd.drag_status.accepted_mime = y
@@ -230,14 +225,14 @@ func (dnd *dnd) on_drag_event(x, y, operation, Y int) (err error) {
case 4:
was_dropped := dnd.drag_status.dropped
was_move := dnd.drag_status.accepted_operation == 2
was_remote := dnd.drag_status.remote_data_was_sent
dnd.reset_drag()
if was_dropped && dnd.has_exit_on("drag-finish") {
dnd.lp.Quit(0)
}
if was_dropped && was_move && was_remote {
if was_dropped && was_move {
if ds := dnd.drag_sources["text/uri-list"]; ds != nil {
for _, item := range ds.uri_list {
if item.was_sent {
if item.metadata.IsDir() {
err = os.RemoveAll(item.path)
} else {
@@ -248,6 +243,7 @@ func (dnd *dnd) on_drag_event(x, y, operation, Y int) (err error) {
}
}
}
}
dnd.drag_sources = nil
dnd.allow_drags = false
dnd.lp.StopOfferingDrags()
@@ -256,7 +252,7 @@ func (dnd *dnd) on_drag_event(x, y, operation, Y int) (err error) {
}
}
case 5:
if err = dnd.handle_data_request(y, Y == 1); err != nil {
if err = dnd.handle_data_request(y); err != nil {
return err
}
}
@@ -272,28 +268,24 @@ func (dnd *dnd) finish_drag(errname string) {
dnd.reset_drag()
}
func (dnd *dnd) handle_data_request(idx int, send_remote_data bool) (err error) {
func (dnd *dnd) handle_data_request(idx int) (err error) {
if idx < 0 || idx >= len(dnd.drag_status.offered_mimes) {
dnd.finish_drag("EINVAL")
return fmt.Errorf("terminal asked for drag data from MIME list with out of bounds index: %d", idx)
}
mime := dnd.drag_status.offered_mimes[idx]
ds := dnd.drag_sources[mime]
send_remote_data = send_remote_data && mime == "text/uri-list" && len(ds.uri_list) > 0
for _, dr := range dnd.drag_status.data_requests {
if dr.index == idx {
dnd.finish_drag("EINVAL")
return fmt.Errorf("terminal sent a duplicate drag data request")
}
}
dr := &data_request{drag_source: ds, send_remote_data: send_remote_data, index: idx}
dr := &data_request{drag_source: ds, index: idx}
if ds.path == "" {
dnd.lp.QueueDnDData(DC{Type: 'e', Y: idx, Payload: utils.UnsafeStringToBytes(base64.RawStdEncoding.EncodeToString(ds.data))})
dnd.lp.QueueDnDData(DC{Type: 'e', Y: idx}) // EOF
if !dr.send_remote_data {
return
}
return dnd.start_remote_data_send(ds)
} else {
if ds.file != nil {
ds.file.Close()
@@ -356,9 +348,7 @@ func (dnd *dnd) on_data_request_finished(i int) (err error) {
dr.drag_source.file = nil
}
dnd.drag_status.data_requests = slices.Delete(dnd.drag_status.data_requests, i, i+1)
if dr.send_remote_data {
err = dnd.start_remote_data_send(dr.drag_source)
} else if len(dnd.drag_status.data_requests) > 0 {
if len(dnd.drag_status.data_requests) > 0 {
err = dnd.send_data_for_data_request(0)
}
return
@@ -386,6 +376,9 @@ func (dnd *dnd) send_remote_dir(path string, idx_in_uri_list, parent_dir_handle,
dnd.finish_drag("EIO")
return nil, err
}
for dnd.drag_status.dir_handle_counter < 2 {
dnd.drag_status.dir_handle_counter++
}
handle := dnd.drag_status.dir_handle_counter
dnd.drag_status.dir_handle_counter++
names := make([]string, 0, len(entries))
@@ -447,7 +440,11 @@ func (dnd *dnd) send_next_file_chunk() (err error) {
func (dnd *dnd) next_remote_item() (err error) {
if len(dnd.drag_status.remote_items) < 1 {
dnd.lp.QueueDnDData(DC{Type: 'k'}) // inform terminal remote data is finished
// current remote data request finished
dnd.drag_status.remote_data_requests = dnd.drag_status.remote_data_requests[1:]
if len(dnd.drag_status.remote_data_requests) > 0 {
return dnd.send_next_remote_data_request()
}
if len(dnd.drag_status.data_requests) > 0 {
err = dnd.send_data_for_data_request(0)
}
@@ -478,12 +475,31 @@ func (dnd *dnd) next_remote_item() (err error) {
return
}
func (dnd *dnd) start_remote_data_send(ds *drag_source) (err error) {
dnd.drag_status.dir_handle_counter = 2
dnd.drag_status.remote_item_write_id = 0
dnd.drag_status.remote_data_was_sent = true
func (dnd *dnd) on_drag_remote_data_request(idx int) (err error) {
ds := dnd.drag_sources["text/uri_list"]
if ds == nil || len(ds.uri_list) < 1 {
dnd.finish_drag("EINVAL")
return fmt.Errorf("terminal asked for drag data from URI list but no list present")
}
if idx < 0 || idx >= len(ds.uri_list) {
dnd.finish_drag("EINVAL")
return fmt.Errorf("terminal asked for drag data from URI list with out of bounds index: %d", idx)
}
ds.uri_list[idx].was_sent = true
dnd.drag_status.remote_data_requests = append(dnd.drag_status.remote_data_requests, idx)
if len(dnd.drag_status.remote_data_requests) == 1 {
err = dnd.send_next_remote_data_request()
}
return
}
func (dnd *dnd) send_next_remote_data_request() (err error) {
if len(dnd.drag_status.remote_data_requests) == 0 {
return nil
}
i := dnd.drag_status.remote_data_requests[0]
x := dnd.drag_sources["text/uri-list"].uri_list[i]
items := []*remote_data_item{}
for i, x := range ds.uri_list {
if x.metadata.IsDir() {
if children, err := dnd.send_remote_dir(x.path, i, 0, i); err != nil {
return err
@@ -498,7 +514,6 @@ func (dnd *dnd) start_remote_data_send(ds *drag_source) (err error) {
f := remote_data_item{idx_in_parent: i, idx_in_uri_list: i, metadata: x.metadata, path: x.path}
dnd.drag_status.remote_items = append(dnd.drag_status.remote_items, &f)
}
}
dnd.drag_status.remote_items = append(dnd.drag_status.remote_items, items...)
if dnd.drag_status.remote_item_write_id == 0 {
return dnd.next_remote_item()

View File

@@ -31,6 +31,7 @@ type uri_list_item struct {
path, uri, human_name string
file *os.File
metadata os.FileInfo
was_sent bool
}
type drag_source struct {
@@ -105,7 +106,7 @@ func (dnd *dnd) send_test_response(payload string) {
}
func (dnd *dnd) has_exit_on(event string) bool {
for _, e := range strings.Split(dnd.opts.ExitOn, ",") {
for e := range strings.SplitSeq(dnd.opts.ExitOn, ",") {
if strings.TrimSpace(e) == event {
return true
}
@@ -276,7 +277,9 @@ func (dnd *dnd) run_loop() (err error) {
case 'E':
return dnd.on_drag_error(cmd)
case 'e':
return dnd.on_drag_event(cmd.X, cmd.Y, cmd.Operation, cmd.Yp)
return dnd.on_drag_event(cmd.X, cmd.Y, cmd.Operation)
case 'k':
return dnd.on_drag_remote_data_request(cmd.X - 1)
}
return nil
}

View File

@@ -426,7 +426,7 @@ class PTY:
if isinstance(data, str):
data = data.encode('utf-8')
if self.log_data_flow:
print('t -> c:', data)
print('t -> c:', bytes(data))
self.write_buf += data
if flush:
self.process_input_from_child(0)