mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-05-13 08:26:56 +00:00
More work on the dnd kitten
This commit is contained in:
parent
a7a7a4fd8f
commit
0de313e178
3 changed files with 49 additions and 28 deletions
|
|
@ -33,6 +33,7 @@ type remote_data_item struct {
|
|||
write_id loop.IdType
|
||||
base64 streaming_base64.StreamingBase64Encoder
|
||||
parent_dir_handle, idx_in_parent int
|
||||
idx_in_uri_list int
|
||||
}
|
||||
|
||||
type drag_status struct {
|
||||
|
|
@ -220,21 +221,19 @@ func (dnd *dnd) on_data_request_finished(i int) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (dnd *dnd) send_remote_item_payload(parent_dir_handle, idx, item_type int, payload []byte) loop.IdType {
|
||||
cmd := DC{Type: 'k', X: item_type}
|
||||
func (dnd *dnd) send_remote_item_payload(parent_dir_handle, idx_in_parent, idx_in_uri_list, item_type int, payload []byte) loop.IdType {
|
||||
cmd := DC{Type: 'k', Xp: item_type, X: idx_in_uri_list + 1}
|
||||
if len(payload) > 0 {
|
||||
cmd.Payload = utils.UnsafeStringToBytes(base64.RawStdEncoding.EncodeToString(payload))
|
||||
}
|
||||
if parent_dir_handle != 0 {
|
||||
cmd.Yp = parent_dir_handle
|
||||
cmd.Y = idx + 1
|
||||
} else {
|
||||
cmd.X = idx + 1
|
||||
cmd.Y = idx_in_parent + 1
|
||||
}
|
||||
return dnd.lp.QueueDnDData(cmd)
|
||||
}
|
||||
|
||||
func (dnd *dnd) send_remote_dir(path string, parent_dir_handle, idx int) (children []*remote_data_item, err error) {
|
||||
func (dnd *dnd) send_remote_dir(path string, idx_in_uri_list, parent_dir_handle, idx int) (children []*remote_data_item, err error) {
|
||||
entries, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
dnd.finish_drag("EIO")
|
||||
|
|
@ -249,24 +248,26 @@ func (dnd *dnd) send_remote_dir(path string, parent_dir_handle, idx int) (childr
|
|||
dnd.finish_drag("EIO")
|
||||
return nil, err
|
||||
}
|
||||
x := remote_data_item{parent_dir_handle: handle, idx_in_parent: i, metadata: st, path: filepath.Join(path, entry.Name())}
|
||||
x := remote_data_item{
|
||||
parent_dir_handle: handle, idx_in_parent: i, metadata: st, idx_in_uri_list: idx_in_uri_list,
|
||||
path: filepath.Join(path, entry.Name())}
|
||||
children = append(children, &x)
|
||||
names = append(names, entry.Name())
|
||||
}
|
||||
payload := utils.UnsafeStringToBytes(strings.Join(names, "\x00"))
|
||||
dnd.send_remote_item_payload(parent_dir_handle, idx, handle, payload)
|
||||
dnd.drag_status.remote_item_write_id = dnd.send_remote_item_payload(parent_dir_handle, idx, handle, nil)
|
||||
dnd.send_remote_item_payload(parent_dir_handle, idx, idx_in_uri_list, handle, payload)
|
||||
dnd.drag_status.remote_item_write_id = dnd.send_remote_item_payload(parent_dir_handle, idx, idx_in_uri_list, handle, nil)
|
||||
return
|
||||
}
|
||||
|
||||
func (dnd *dnd) send_remote_symlink(path string, parent_dir_handle, idx int) (err error) {
|
||||
func (dnd *dnd) send_remote_symlink(path string, idx_in_uri_list, parent_dir_handle, idx int) (err error) {
|
||||
target, err := os.Readlink(path)
|
||||
if err != nil {
|
||||
dnd.finish_drag("EIO")
|
||||
return err
|
||||
}
|
||||
dnd.send_remote_item_payload(parent_dir_handle, idx, 1, utils.UnsafeStringToBytes(target))
|
||||
dnd.drag_status.remote_item_write_id = dnd.send_remote_item_payload(parent_dir_handle, idx, 1, nil)
|
||||
dnd.send_remote_item_payload(parent_dir_handle, idx, idx_in_uri_list, 1, utils.UnsafeStringToBytes(target))
|
||||
dnd.drag_status.remote_item_write_id = dnd.send_remote_item_payload(parent_dir_handle, idx, idx_in_uri_list, 1, nil)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -278,18 +279,17 @@ func (dnd *dnd) send_next_file_chunk() (err error) {
|
|||
n, err := cr.file.Read(read_buf[:])
|
||||
if n > 0 {
|
||||
for chunk := range cr.base64.Encode(read_buf[:n], encode_buf[:]) {
|
||||
dnd.drag_status.remote_item_write_id = dnd.send_remote_item_payload(cr.parent_dir_handle, cr.idx_in_parent, 0, chunk)
|
||||
dnd.drag_status.remote_item_write_id = dnd.send_remote_item_payload(cr.parent_dir_handle, cr.idx_in_parent, cr.idx_in_uri_list, 0, chunk)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
cr.file.Close()
|
||||
dnd.drag_status.current_remote_file = nil
|
||||
dnd.drag_status.remote_items = dnd.drag_status.remote_items[1:]
|
||||
if chunk := cr.base64.Finish(); len(chunk) > 0 {
|
||||
dnd.send_remote_item_payload(cr.parent_dir_handle, cr.idx_in_parent, 0, chunk)
|
||||
dnd.send_remote_item_payload(cr.parent_dir_handle, cr.idx_in_parent, cr.idx_in_uri_list, 0, chunk)
|
||||
}
|
||||
dnd.drag_status.remote_item_write_id = dnd.send_remote_item_payload(cr.parent_dir_handle, cr.idx_in_parent, 0, nil)
|
||||
dnd.drag_status.remote_item_write_id = dnd.send_remote_item_payload(cr.parent_dir_handle, cr.idx_in_parent, cr.idx_in_uri_list, 0, nil)
|
||||
return
|
||||
}
|
||||
dnd.finish_drag("EIO")
|
||||
|
|
@ -300,20 +300,22 @@ 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
|
||||
if len(dnd.drag_status.data_requests) > 0 {
|
||||
err = dnd.send_data_for_data_request(0)
|
||||
}
|
||||
return
|
||||
}
|
||||
x := dnd.drag_status.remote_items[0]
|
||||
dnd.drag_status.remote_items = dnd.drag_status.remote_items[1:]
|
||||
if x.metadata.IsDir() {
|
||||
children, err := dnd.send_remote_dir(x.path, x.parent_dir_handle, x.idx_in_parent)
|
||||
children, err := dnd.send_remote_dir(x.path, x.idx_in_uri_list, x.parent_dir_handle, x.idx_in_parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dnd.drag_status.remote_items = append(dnd.drag_status.remote_items, children...)
|
||||
} else if x.metadata.Mode().Type()&os.ModeSymlink != 0 {
|
||||
if err = dnd.send_remote_symlink(x.path, x.parent_dir_handle, x.idx_in_parent); err != nil {
|
||||
if err = dnd.send_remote_symlink(x.path, x.idx_in_uri_list, x.parent_dir_handle, x.idx_in_parent); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
|
@ -335,13 +337,13 @@ func (dnd *dnd) start_remote_data_send(ds *drag_source) (err error) {
|
|||
items := []*remote_data_item{}
|
||||
for i, x := range ds.uri_list {
|
||||
if x.metadata.IsDir() {
|
||||
if children, err := dnd.send_remote_dir(x.path, 0, i); err != nil {
|
||||
if children, err := dnd.send_remote_dir(x.path, i, 0, i); err != nil {
|
||||
return err
|
||||
} else {
|
||||
items = append(items, children...)
|
||||
}
|
||||
} else if x.metadata.Mode().Type()&os.ModeSymlink != 0 {
|
||||
if err = dnd.send_remote_symlink(x.path, 0, i); err != nil {
|
||||
if err = dnd.send_remote_symlink(x.path, i, 0, i); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1492,6 +1492,10 @@ drag_get_data(Window *w, const char *mime_type, size_t *sz, int *err_code) {
|
|||
ds.items[i].fd_plus_one = 0;
|
||||
return NULL;
|
||||
}
|
||||
if (ds.items[i].requested_remote_files) { // wait for remote files to be read
|
||||
*err_code = EAGAIN;
|
||||
return NULL;
|
||||
}
|
||||
if (ds.items[i].fd_plus_one > 0) {
|
||||
// data_size = read position, data_capacity = bytes written to file
|
||||
if (ds.items[i].data_capacity > ds.items[i].data_size) {
|
||||
|
|
@ -1728,6 +1732,7 @@ write_all(int fd, const void *buf, size_t sz) {
|
|||
static void
|
||||
finish_remote_data(Window *w, size_t item_idx) {
|
||||
const int fd = ds.items[item_idx].fd_plus_one - 1;
|
||||
ds.items[item_idx].requested_remote_files = false;
|
||||
if (safe_ftruncate(fd, 0) != 0) abrt(errno);
|
||||
if (lseek(fd, 0, SEEK_SET) == -1) abrt(errno);
|
||||
for (size_t i = 0; i < ds.items[item_idx].num_uris; i++) {
|
||||
|
|
@ -1738,7 +1743,7 @@ finish_remote_data(Window *w, size_t item_idx) {
|
|||
}
|
||||
free(ds.items[item_idx].uri_list); ds.items[item_idx].uri_list = NULL; ds.items[item_idx].num_uris = 0;
|
||||
int ret = dnd_is_test_mode() ? 0 : notify_drag_data_ready(global_state.drag_source.from_os_window, ds.items[item_idx].mime_type);
|
||||
abrt(ret);
|
||||
if (ret) abrt(ret);
|
||||
}
|
||||
|
||||
#define mi ds.items[mime_item_idx]
|
||||
|
|
|
|||
|
|
@ -329,13 +329,20 @@ class TestDnDKitten(BaseTest):
|
|||
|
||||
def test_dnd_kitten_drag(self):
|
||||
img_drag_path = 'image.png'
|
||||
with open(os.path.join(self.kitten_wd, img_drag_path), 'wb') as f:
|
||||
self.img_drag_data = os.urandom(10113)
|
||||
f.write(self.img_drag_data)
|
||||
create_fs(self.src_data_dir)
|
||||
def create_files():
|
||||
with open(os.path.join(self.kitten_wd, img_drag_path), 'wb') as f:
|
||||
self.img_drag_data = os.urandom(10113)
|
||||
f.write(self.img_drag_data)
|
||||
create_fs(self.src_data_dir)
|
||||
create_files()
|
||||
tl = tuple(os.path.join(self.src_data_dir, x) for x in os.listdir(self.src_data_dir))
|
||||
self.finish_setup(cli_args=(f'--drag=image/png:{img_drag_path}', ) + tl) # )))
|
||||
self.dnd_kitten_drag(False, img_drag_path)
|
||||
with self.subTest(remote_client=False):
|
||||
self.dnd_kitten_drag(False, img_drag_path)
|
||||
self.reset_kitten(True)
|
||||
create_files()
|
||||
with self.subTest(remote_client=True):
|
||||
self.dnd_kitten_drag(True, img_drag_path)
|
||||
self.exit_kitten()
|
||||
self.img_drag_data = None
|
||||
|
||||
|
|
@ -352,7 +359,7 @@ class TestDnDKitten(BaseTest):
|
|||
if err.errno == errno.EAGAIN:
|
||||
self.pty.process_input_from_child()
|
||||
continue
|
||||
del chunk, ans
|
||||
chunk = ans = b''
|
||||
raise
|
||||
return ans
|
||||
|
||||
|
|
@ -388,6 +395,8 @@ class TestDnDKitten(BaseTest):
|
|||
self.send_dnd_command_to_kitten('DRAG_STATUS')
|
||||
self.wait_for_responses('text/uri-list:2:true')
|
||||
self.assertEqual(self.img_drag_data, self.read_drag_data('image/png'))
|
||||
# if remote_client:
|
||||
# self.pty.log_data_flow = True
|
||||
uri_list = self.read_drag_data('text/uri-list').decode().splitlines()
|
||||
paths = set()
|
||||
for line in uri_list:
|
||||
|
|
@ -396,5 +405,10 @@ class TestDnDKitten(BaseTest):
|
|||
purl = urlparse(line)
|
||||
if purl.scheme == 'file':
|
||||
paths.add(purl.path)
|
||||
self.assertEqual(set(os.listdir(self.src_data_dir)), {os.path.basename(x) for x in paths})
|
||||
if remote_client:
|
||||
self.assertNotEqual(self.src_data_dir, os.path.dirname(purl.path))
|
||||
else:
|
||||
self.assertEqual(self.src_data_dir, os.path.dirname(purl.path))
|
||||
src_items = set(os.listdir(self.src_data_dir))
|
||||
self.assertEqual(src_items, {os.path.basename(x) for x in paths})
|
||||
end_drag(False)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue