mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-05-13 08:26:56 +00:00
Merge branch 'copilot/handle-case-conflict-dnd' of https://github.com/kovidgoyal/kitty
This commit is contained in:
commit
b8dd685363
1 changed files with 91 additions and 0 deletions
91
kitty/dnd.c
91
kitty/dnd.c
|
|
@ -11,6 +11,7 @@
|
|||
#include "safe-wrappers.h"
|
||||
#include "iqsort.h"
|
||||
#include "png-reader.h"
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
|
@ -137,6 +138,33 @@ mktempdir_in_cache(const char *prefix, int *fd) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// -1 = unknown, 0 = case-sensitive, 1 = case-insensitive
|
||||
static int tempdir_case_insensitive = -1;
|
||||
|
||||
static void
|
||||
detect_tempdir_case_sensitivity(const char *tempdir_path) {
|
||||
if (tempdir_case_insensitive >= 0) return;
|
||||
tempdir_case_insensitive = 0; // default: case-sensitive
|
||||
const char *slash = strrchr(tempdir_path, '/');
|
||||
if (!slash) return;
|
||||
size_t dirname_len = (size_t)(slash - tempdir_path);
|
||||
const char *basename = slash + 1;
|
||||
size_t basename_len = strlen(basename);
|
||||
if (!basename_len) return;
|
||||
char upper_basename[PATH_MAX];
|
||||
if (basename_len >= sizeof(upper_basename)) return;
|
||||
for (size_t i = 0; i < basename_len; i++) upper_basename[i] = (char)toupper((unsigned char)basename[i]);
|
||||
upper_basename[basename_len] = '\0';
|
||||
if (strcmp(upper_basename, basename) == 0) return; // already all-uppercase, cannot distinguish
|
||||
char upper_path[PATH_MAX];
|
||||
if (dirname_len + 1 + basename_len + 1 > sizeof(upper_path)) return;
|
||||
memcpy(upper_path, tempdir_path, dirname_len);
|
||||
upper_path[dirname_len] = '/';
|
||||
memcpy(upper_path + dirname_len + 1, upper_basename, basename_len + 1);
|
||||
struct stat st;
|
||||
if (stat(upper_path, &st) == 0) tempdir_case_insensitive = 1;
|
||||
}
|
||||
|
||||
static char*
|
||||
as_file_url(const char *wd, const char *middle, const char *filename) {
|
||||
RAII_PyObject(mname, PyUnicode_DecodeFSDefault("kitty.utils"));
|
||||
|
|
@ -1818,6 +1846,66 @@ finish_remote_data(Window *w, size_t item_idx) {
|
|||
|
||||
#define mi ds.items[mime_item_idx]
|
||||
|
||||
static char*
|
||||
lowercase_copy(const char *s) {
|
||||
size_t len = strlen(s);
|
||||
char *ans = malloc(len + 1);
|
||||
if (!ans) return NULL;
|
||||
for (size_t i = 0; i < len; i++) ans[i] = (char)tolower((unsigned char)s[i]);
|
||||
ans[len] = '\0';
|
||||
return ans;
|
||||
}
|
||||
|
||||
static bool
|
||||
has_lowercase_conflict(const char *lower_name, char **seen_lower, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (strcmp(lower_name, seen_lower[i]) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
uniqify_dir_entries_for_case_insensitive_fs(DragRemoteItem *children, size_t count) {
|
||||
if (!count) return;
|
||||
char **seen_lower = calloc(count, sizeof(char*));
|
||||
if (!seen_lower) return;
|
||||
size_t seen_count = 0;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (!children[i].dir_entry_name) continue;
|
||||
const char *orig_name = children[i].dir_entry_name;
|
||||
char *lower = lowercase_copy(orig_name);
|
||||
if (!lower) continue;
|
||||
if (!has_lowercase_conflict(lower, seen_lower, seen_count)) {
|
||||
seen_lower[seen_count++] = lower;
|
||||
continue;
|
||||
}
|
||||
free(lower);
|
||||
bool renamed = false;
|
||||
for (int q = 1; q <= 1000; q++) {
|
||||
size_t buflen = 26 + strlen(orig_name); // "case-conflict-" + 10 digits + "-" + name + null
|
||||
char *new_name = malloc(buflen);
|
||||
if (!new_name) break;
|
||||
snprintf(new_name, buflen, "case-conflict-%d-%s", q, orig_name);
|
||||
lower = lowercase_copy(new_name);
|
||||
if (!lower) { free(new_name); break; }
|
||||
if (!has_lowercase_conflict(lower, seen_lower, seen_count)) {
|
||||
free(children[i].dir_entry_name);
|
||||
children[i].dir_entry_name = new_name;
|
||||
seen_lower[seen_count++] = lower;
|
||||
renamed = true;
|
||||
break;
|
||||
}
|
||||
free(lower); free(new_name);
|
||||
}
|
||||
if (!renamed) {
|
||||
lower = lowercase_copy(children[i].dir_entry_name);
|
||||
if (lower) seen_lower[seen_count++] = lower;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < seen_count; i++) free(seen_lower[i]);
|
||||
free(seen_lower);
|
||||
}
|
||||
|
||||
static void
|
||||
populate_dir_entries(Window *w, DragRemoteItem *ri) {
|
||||
size_t num = count_occurrences((char*)ri->data, ri->data_sz, 0) + 1;
|
||||
|
|
@ -1836,6 +1924,8 @@ populate_dir_entries(Window *w, DragRemoteItem *ri) {
|
|||
}
|
||||
ptr = p ? p + 1 : end;
|
||||
}
|
||||
if (tempdir_case_insensitive == 1)
|
||||
uniqify_dir_entries_for_case_insensitive_fs(ri->children, ri->children_sz);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1914,6 +2004,7 @@ toplevel_data_for_drag(
|
|||
mi.base_dir_for_remote_items = mktempdir_in_cache("dnd-drag-", &fd);
|
||||
if (!mi.base_dir_for_remote_items) abrt(errno);
|
||||
mi.base_dir_fd_plus_one = fd + 1;
|
||||
detect_tempdir_case_sensitivity(mi.base_dir_for_remote_items);
|
||||
}
|
||||
if (uri_item_idx >= mi.num_remote_items) abrt(EINVAL);
|
||||
DragRemoteItem *ri = mi.remote_items + uri_item_idx;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue