From a47ec50d7263c26270470e8a65a3fe6bebfc79ae Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 23 Apr 2026 17:23:21 +0530 Subject: [PATCH] More work on the dnd kitten --- kittens/dnd/drop.go | 53 ++++++++++++++++++++++++++++++++------- kitty_tests/dnd_kitten.py | 19 ++++++++++++++ 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/kittens/dnd/drop.go b/kittens/dnd/drop.go index 2a1446d6e..54fd578d3 100644 --- a/kittens/dnd/drop.go +++ b/kittens/dnd/drop.go @@ -198,9 +198,19 @@ type drop_status struct { reading_data bool is_remote_client bool - root_remote_dir *remote_dir_entry - open_remote_dir *remote_dir_entry - current_remote_entry *remote_dir_entry // used for m=1 only + root_remote_dir *remote_dir_entry + open_remote_dir *remote_dir_entry + current_remote_entry *remote_dir_entry // used for m=1 only + pending_remote_dirs []*remote_dir_entry + remote_dir_handle_counter int32 +} + +func (d *drop_status) next_dir_handle() int32 { + d.remote_dir_handle_counter++ + for d.remote_dir_handle_counter == 0 || d.remote_dir_handle_counter == 1 { + d.remote_dir_handle_counter++ + } + return d.remote_dir_handle_counter } var reset_drop_status = drop_status{cell_x: -1, cell_y: -1} @@ -394,13 +404,38 @@ func (dnd *dnd) on_remote_drop_data(cmd DC) (err error) { if err = e.add_remote_data(cmd.Payload, drop_buf, cmd.Has_more, dnd.is_case_sensitive_filesystem); err != nil { return err } - if e.dest == nil { // this entry is finished - drop_status.open_remote_dir.num_children_finished++ - if len(e.children) > 0 { - if e.item_type != 0 && e.item_type != 1 { - dnd.lp.QueueDnDData(DC{Type: 'r', Yp: e.item_type}) // close directory in terminal + if e.dest == nil { // received all data for this entry + drop_status.current_remote_entry = nil + parent := drop_status.open_remote_dir + parent.num_children_finished++ + if parent.num_children_finished >= len(parent.children) { // parent is finished + drop_status.open_remote_dir = nil + parent.base_dir = parent.base_dir.unref() + if parent.item_type != 0 { + dnd.lp.QueueDnDData(DC{Type: 'r', Yp: parent.item_type}) // close directory in terminal + } + for _, c := range parent.children { + is_pending := false + if c.item_type != 0 && c.item_type != 1 { + if len(c.children) > 0 { + dnd.drop_status.pending_remote_dirs = append(dnd.drop_status.pending_remote_dirs, c) + is_pending = true + } + } + if !is_pending { + c.base_dir = c.base_dir.unref() + } + } + if len(drop_status.pending_remote_dirs) > 0 { + drop_status.open_remote_dir = drop_status.pending_remote_dirs[0] + drop_status.pending_remote_dirs = drop_status.pending_remote_dirs[1:] + for i := range drop_status.open_remote_dir.children { + dnd.lp.QueueDnDData(DC{Type: 'r', X: i + 1, Yp: drop_status.open_remote_dir.item_type}) // close directory in terminal + } + } else { + dnd.data_has_been_dropped = true + dnd.end_drop() } - // TODO: request the children } } return nil diff --git a/kitty_tests/dnd_kitten.py b/kitty_tests/dnd_kitten.py index f50b26bee..9fc796d93 100644 --- a/kitty_tests/dnd_kitten.py +++ b/kitty_tests/dnd_kitten.py @@ -4,6 +4,7 @@ import os import random import shutil +import stat import tempfile import uuid from base64 import standard_b64encode @@ -57,6 +58,24 @@ def create_fs(base): class TestDnDKitten(BaseTest): + def assert_trees_equal(self, a: str, b: str): + a_name = os.path.relpath(a, self.test_dir) + b_name = os.path.relpath(b, self.test_dir) + entries_a, entries_b = os.listdir(a), os.listdir(b) + self.assertEqual(set(entries_a), set(entries_b), f'readdir() different for {a_name} vs {b_name}') + for x in entries_a: + ca, cb = os.path.join(a, x), os.path.join(b, x) + sta, stb = os.lstat(ca), os.lstat(cb) + self.assertEqual( + stat.S_IFMT(sta.st_mode), stat.S_IFMT(stb.st_mode), f'type mismatch for {a_name}/{x} vs {b_name}/{x}') + if stat.S_ISDIR(sta.st_mode): + self.assert_trees_equal(ca, cb) + elif stat.S_ISLNK(sta.st_mode): + self.assertEqual(os.readlink(ca), os.readlink(cb)) + elif stat.S_ISREG(sta.st_mode): + with open(ca, 'rb') as fa, open(cb, 'rb') as fb: + self.assertEqual(fa.read(), fb.read()) + def setUp(self): capture = Capture() dnd_set_test_write_func(capture)