// 补全状态结构(优化版)
typedef struct {
char **matches; // 所有匹配项
int count; // 匹配项总数
char *base_dir; // 当前基础目录
char *original_prefix; // 原始前缀
char *current_text; // 当前输入文本
int last_state; // 上一次使用的state值
int current_level; // 当前目录层级
char *persistent_path; // 持久化路径(同时作为初始化标志)
int is_directory;
int max_level; // 最大允许层级(关键新增)
} CompletionState;
static CompletionState comp_state = {
.matches = NULL,
.count = 0,
.base_dir = NULL,
.original_prefix = NULL,
.current_text = NULL,
.last_state = -1,
.current_level = 0,
.persistent_path = NULL,
.is_directory = 0,
.max_level = -1
};
// 重置补全状态
void reset_completion_state() {
if (comp_state.matches) {
for (int i = 0; i < comp_state.count; i++) {
XFREE(MTYPE_TMP, comp_state.matches[i]);
}
XFREE(MTYPE_TMP, comp_state.matches);
comp_state.matches = NULL;
}
if (comp_state.original_prefix) {
XFREE(MTYPE_TMP, comp_state.original_prefix);
}
if (comp_state.base_dir) {
XFREE(MTYPE_TMP, comp_state.base_dir);
}
if (comp_state.current_text) {
XFREE(MTYPE_TMP, comp_state.current_text);
}
if (comp_state.persistent_path) {
XFREE(MTYPE_TMP, comp_state.persistent_path);
}
comp_state.count = 0;
comp_state.original_prefix = NULL;
comp_state.base_dir = NULL;
comp_state.current_text = NULL;
comp_state.last_state = -1;
comp_state.current_level = 0;
comp_state.persistent_path = NULL; // 关键:清除持久化路径
comp_state.is_directory = 0;
comp_state.max_level = -1;
}
// 路径比较函数(目录优先)
int compare_paths(const void *a, const void *b) {
const char *sa = *(const char **)a;
const char *sb = *(const char **)b;
// 目录优先
int is_dir_a = (sa[strlen(sa)-1] == '/');
int is_dir_b = (sb[strlen(sb)-1] == '/');
if (is_dir_a && !is_dir_b) return -1;
if (!is_dir_a && is_dir_b) return 1;
return strcmp(sa, sb);
}
// 修复的路径解析函数
void parse_input_text(const char *text, char **base_dir, char **prefix, int *level) {
*level = 0;
const char *ptr = text;
while (*ptr) {
if (*ptr == '/') (*level)++;
ptr++;
}
const char *last_slash = strrchr(text, '/');
const char *last_char = text + strlen(text) - 1;
if (last_slash) {
if (last_char == last_slash) {
// 以斜杠结尾:整个路径作为基础目录
*base_dir = XSTRDUP(MTYPE_TMP, text);
*prefix = XSTRDUP(MTYPE_TMP, "");
} else {
// 路径中包含文件名
size_t base_len = last_slash - text + 1;
*base_dir = (char *)XCALLOC(MTYPE_TMP, base_len + 1);
strncpy(*base_dir, text, base_len);
(*base_dir)[base_len] = '\0';
*prefix = XSTRDUP(MTYPE_TMP, last_slash + 1);
}
} else {
// 无斜杠:当前目录
*base_dir = XSTRDUP(MTYPE_TMP, "");
*prefix = XSTRDUP(MTYPE_TMP, text);
}
printf("parse_input_text: text = %s, base_dir = %s, prefix = %s, level = %d\n", text, *base_dir, *prefix, *level);
}
int is_same_completion_context(const char *text) {
if (!comp_state.persistent_path || comp_state.max_level == -1) {
return 0;
}
char *temp_base = NULL;
char *temp_prefix = NULL;
int current_level = 0;
parse_input_text(text, &temp_base, &temp_prefix, ¤t_level);
int same_path = strncmp(text, comp_state.persistent_path, strlen(comp_state.persistent_path)) == 0;
// 只有在当前路径是持久化路径的子目录或匹配时才继续
int within_level = (current_level <= comp_state.max_level);
XFREE(MTYPE_TMP, temp_base);
XFREE(MTYPE_TMP, temp_prefix);
printf("is_same_completion_context: same_path=%d, within_level=%d\n", same_path, within_level);
return same_path && within_level;
}
char **generate_current_dir_paths(const char *base_dir, const char *prefix, int add_empty) {
const char *scan_dir = base_dir;
if (!scan_dir || !*scan_dir) {
scan_dir = ".";
}
printf("[generate] Scanning directory: '%s' with prefix: '%s'\n", scan_dir, prefix ? prefix : "(none)");
DIR *dir = opendir(scan_dir);
if (!dir) {
if (add_empty) {
char **matches = (char **)XCALLOC(MTYPE_TMP, sizeof(char *));
matches[0] = XSTRDUP(MTYPE_TMP, "");
return matches;
}
return NULL;
}
int capacity = 32;
int count = 0;
char **matches = (char **)XCALLOC(MTYPE_TMP, capacity*sizeof(char *));
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
const char *name = entry->d_name;
// 跳过 '.' 和 '..'
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
continue;
}
// 前缀匹配
if (prefix && *prefix && strncmp(name, prefix, strlen(prefix)) != 0) {
continue;
}
// 构造补全项
int is_dir = (entry->d_type == DT_DIR);
if (entry->d_type == DT_UNKNOWN) {
char full_path[PATH_MAX];
snprintf(full_path, sizeof(full_path), "%s/%s", scan_dir, name);
struct stat statbuf;
if (stat(full_path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
is_dir = 1;
}
}
char *new_name;
if (is_dir) {
new_name = (char *)XCALLOC(MTYPE_TMP, strlen(name) + 2);
snprintf(new_name, strlen(name) + 2, "%s/", name);
} else {
new_name = XSTRDUP(MTYPE_TMP, name);
}
// 动态扩展数组
if (count >= capacity) {
capacity *= 2;
matches = (char **)XREALLOC(MTYPE_TMP, matches, capacity * sizeof(char *));
}
matches[count++] = new_name;
}
closedir(dir);
// 排序补全结果
if (count > 0) {
qsort(matches, count, sizeof(char *), compare_paths);
}
// NULL 终止
matches = (char **)XREALLOC(MTYPE_TMP, matches, (count + 2) * sizeof(char *));
matches[count] = NULL;
// 如果非顶层补全,添加空字符串作为补全结束标志
if (!add_empty) {
matches[count] = XSTRDUP(MTYPE_TMP, "");
matches[count + 1] = NULL;
}
printf("[generate] Found %d matches.\n", count);
return matches;
}
// 修复的智能文件补全函数
char *filename_completion_function(const char *text, int state) {
printf("\n[COMP] Entering: text='%s', state=%d, last_state=%d\n",
text, state, comp_state.last_state);
// 初始化新补全
if (state == 0) {
printf(" Starting new completion\n");
int same_context = is_same_completion_context(text);
printf(" Same context: %d\n", same_context);
if (!same_context) {
reset_completion_state();
char *current_base = NULL;
char *current_prefix = NULL;
int current_level = 0;
parse_input_text(text, ¤t_base, ¤t_prefix, ¤t_level);
comp_state.base_dir = current_base;
comp_state.current_text = XSTRDUP(MTYPE_TMP, text);
comp_state.original_prefix = XSTRDUP(MTYPE_TMP, current_prefix);
comp_state.current_level = current_level;
comp_state.max_level = current_level + 3; // 可配置最大补全层级
// 检查是否用户已经明确进入了子目录
int ends_with_slash = text[strlen(text) - 1] == '/';
if (ends_with_slash) {
// 用户明确进入子目录,允许下层补全
comp_state.persistent_path = XSTRDUP(MTYPE_TMP, text);
comp_state.max_level = current_level + 3;
} else {
// 用户未进入子目录,只补全当前目录项
comp_state.persistent_path = XSTRDUP(MTYPE_TMP, current_base);
comp_state.max_level = current_level;
}
// 生成当前目录的补全项
comp_state.matches = generate_current_dir_paths(current_base, current_prefix, current_level == 0);
comp_state.count = 0;
if (comp_state.matches) {
while (comp_state.matches[comp_state.count]) {
comp_state.count++;
}
printf(" Generated %d matches\n", comp_state.count);
} else {
comp_state.count = 0;
}
comp_state.last_state = -1; // 重置索引
}
}
// 没有匹配项
if (!comp_state.matches || comp_state.count == 0) {
printf("[COMP] No matches found\n");
return NULL;
}
// 获取下一个匹配项
int next_index = (comp_state.last_state + 1) % comp_state.count;
comp_state.last_state = next_index;
char *match = comp_state.matches[next_index];
// 构建完整路径
char *full_path = NULL;
if (comp_state.base_dir && strlen(comp_state.base_dir) > 0) {
int base_len = strlen(comp_state.base_dir);
int needs_slash = base_len > 0 && comp_state.base_dir[base_len - 1] != '/';
full_path = (char *)XCALLOC(MTYPE_TMP, strlen(match) + base_len + 2);
if (needs_slash) {
snprintf(full_path, strlen(match) + base_len + 2, "%s/%s", comp_state.base_dir, match);
} else {
snprintf(full_path, strlen(match) + base_len + 2, "%s%s", comp_state.base_dir, match);
}
} else {
full_path = XSTRDUP(MTYPE_TMP, match);
}
printf("[COMP] Returning: '%s'\n", full_path);
return full_path;
}
保持这个逻辑,进行优化