Merge branch 'copilot/fix-empty-file-drag-issue' of https://github.com/kovidgoyal/kitty
This commit is contained in:
commit
ce68e96582
2 changed files with 57 additions and 2 deletions
33
kitty/dnd.c
33
kitty/dnd.c
|
|
@ -2088,8 +2088,16 @@ add_payload(Window *w, DragRemoteItem *ri, bool has_more, const uint8_t *payload
|
|||
if (!has_more && !payload_sz) { // all data received
|
||||
switch (ri->type) {
|
||||
case 0:
|
||||
safe_close(ri->fd_plus_one-1, __FILE__, __LINE__);
|
||||
ri->fd_plus_one = 0;
|
||||
if (ri->fd_plus_one) {
|
||||
safe_close(ri->fd_plus_one - 1, __FILE__, __LINE__);
|
||||
ri->fd_plus_one = 0;
|
||||
} else {
|
||||
// Empty file: no data payload was ever received so the file was never opened;
|
||||
// create it now so that it exists at the expected path for the caller.
|
||||
int fd = safe_openat(dirfd, ri->dir_entry_name, O_CREAT | O_WRONLY, file_permissions);
|
||||
if (fd < 0) abrt(errno, "could not create empty drag source item file");
|
||||
safe_close(fd, __FILE__, __LINE__);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// Ensure room for the null terminator needed by symlinkat
|
||||
|
|
@ -2636,6 +2644,27 @@ dnd_test_probe_state(PyObject *self UNUSED, PyObject *args) {
|
|||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
// "drag_remote_item_path:N" returns the full filesystem path for URI item N (0-based)
|
||||
if (strncmp(q, "drag_remote_item_path:", 22) == 0) {
|
||||
size_t uri_idx = (size_t)atoi(q + 22);
|
||||
if (w->drag_source.base_dir_for_remote_items) {
|
||||
for (size_t idx = 0; idx < w->drag_source.num_mimes; idx++) {
|
||||
#define mi w->drag_source.items[idx]
|
||||
if (mi.is_uri_list && mi.remote_items && uri_idx < mi.num_remote_items) {
|
||||
const char *name = mi.remote_items[uri_idx].dir_entry_name;
|
||||
if (name) {
|
||||
char path[PATH_MAX + 1];
|
||||
int n = snprintf(path, sizeof(path), "%s/%zu/%s",
|
||||
w->drag_source.base_dir_for_remote_items, uri_idx, name);
|
||||
if (n <= 0 || (size_t)n >= sizeof(path)) Py_RETURN_NONE;
|
||||
return PyUnicode_FromStringAndSize(path, (Py_ssize_t)n);
|
||||
}
|
||||
}
|
||||
#undef mi
|
||||
}
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
# License: GPL v3 Copyright: 2026, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
from base64 import standard_b64encode
|
||||
from contextlib import contextmanager
|
||||
|
|
@ -2933,6 +2934,11 @@ def test_remote_drag_empty_file(self) -> None:
|
|||
parse_bytes(screen, client_remote_file(1, '', item_type=0))
|
||||
self._assert_no_output(cap)
|
||||
self.assert_drag_data_complete(cap)
|
||||
# Verify the empty file was actually created on disk
|
||||
path = dnd_test_probe_state(cap.window_id, 'drag_remote_item_path:0')
|
||||
self.assertIsNotNone(path, 'empty file path should be known')
|
||||
self.assertTrue(os.path.isfile(path), f'empty file must exist on disk: {path}')
|
||||
self.assertEqual(os.path.getsize(path), 0, f'file must be empty: {path}')
|
||||
|
||||
def test_remote_drag_empty_directory(self) -> None:
|
||||
"""Transfer a directory with no entries."""
|
||||
|
|
@ -2945,6 +2951,26 @@ def test_remote_drag_empty_directory(self) -> None:
|
|||
parse_bytes(screen, client_remote_file(1, '', item_type=2))
|
||||
self.assert_drag_data_complete(cap)
|
||||
|
||||
def test_remote_drag_dir_with_empty_file(self) -> None:
|
||||
"""Directory containing an empty file: the empty child file must be created on disk."""
|
||||
uri_list = b'file:///home/user/mydir\r\n'
|
||||
dir_entries = b'empty_child.txt'
|
||||
with dnd_test_window() as (screen, cap):
|
||||
self._setup_remote_drag(screen, cap, uri_list)
|
||||
b64 = standard_b64encode(dir_entries).decode()
|
||||
parse_bytes(screen, client_remote_file(1, b64, item_type=2))
|
||||
parse_bytes(screen, client_remote_file(1, '', item_type=2))
|
||||
# Send end-of-data for the child with no payload (empty file)
|
||||
parse_bytes(screen, client_remote_file(1, '', item_type=0, parent_handle=2, entry_num=1))
|
||||
self._assert_no_output(cap)
|
||||
self.assert_drag_data_complete(cap)
|
||||
# Verify the empty child file was actually created on disk
|
||||
dir_path = dnd_test_probe_state(cap.window_id, 'drag_remote_item_path:0')
|
||||
self.assertIsNotNone(dir_path, 'dir path should be known')
|
||||
child_path = os.path.join(dir_path, 'empty_child.txt')
|
||||
self.assertTrue(os.path.isfile(child_path), f'empty child file must exist on disk: {child_path}')
|
||||
self.assertEqual(os.path.getsize(child_path), 0, f'child file must be empty: {child_path}')
|
||||
|
||||
def test_remote_drag_uri_list_with_comments(self) -> None:
|
||||
"""URI list with comment lines (starting with #) should filter them out."""
|
||||
uri_list = b'# this is a comment\r\nfile:///home/user/f.txt\r\n# another comment\r\n'
|
||||
|
|
|
|||
Loading…
Reference in a new issue