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);
// 拦截只敲 Tab 的情况
if (text == NULL || *text == '\0') {
printf("用户未输入任何文本,只敲 Tab,不提供补全\n");
return NULL;
}
printf("000000000000000\n");
// 特殊处理:dir f → dir flash:/
if (state == 0 && strncmp(text, "f", 1) == 0) {
reset_completion_state();
printf("111111111111111111\n");
comp_state.persistent_path = XSTRDUP(MTYPE_TMP, "flash:/");
comp_state.base_dir = XSTRDUP(MTYPE_TMP, "/mnt/switch/");
comp_state.current_text = XSTRDUP(MTYPE_TMP, text);
comp_state.original_prefix = XSTRDUP(MTYPE_TMP, "");
comp_state.current_level = 0;
comp_state.max_level = 3;
// 生成 flash:/ 目录下的补全项
comp_state.matches = generate_current_dir_paths("/mnt/switch/", "", 1);
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);
}
comp_state.last_state = -1;
// 返回 flash:/ 作为第一次补全结果
char *flash_path = XSTRDUP(MTYPE_TMP, "flash:/");
printf("22222222222222222 flash_path = %s\n", flash_path);
return flash_path;
}
// 检查是否是 flash:/ 开头
int is_flash = strncmp(text, "flash:/", 7) == 0;
if (is_flash) {
// 从缓存中读取匹配项
if (!comp_state.matches || comp_state.count == 0) {
return NULL;
}
printf("3333333333333333\n");
int next_index = (comp_state.last_state + 1) % comp_state.count;
comp_state.last_state = next_index;
char *match = comp_state.matches[next_index];
// 构建 flash:/xxx 格式的路径
char *flash_path = (char *)XCALLOC(MTYPE_TMP, strlen("flash:/") + strlen(match) + 2);
snprintf(flash_path, strlen("flash:/") + strlen(match) + 2, "flash:/%s", match);
printf("444444444444444 flash_path = %s\n", flash_path);
return flash_path;
}
char current_dir[PATH_MAX];
char abs_path[PATH_MAX];
int reset_completion = 0;
// 初始化新补全
if (state == 0) {
printf(" Starting new completion\n");
int same_context = is_same_completion_context(text);
printf(" Same context: %d\n", same_context);
getcwd(current_dir, sizeof(current_dir));
snprintf(abs_path, sizeof(abs_path), "%s/%s", current_dir, text);
if (access(abs_path, F_OK) != 0) {
reset_completion = 1;
}
printf("\nfilename_completion_function: reset_completion = %d, abs_path = %s\n", reset_completion, abs_path);
int same_reset = 0;
struct stat st_tmp;
char tmp_path[PATH_MAX];
char *tmp_base = NULL;
char *tmp_prefix = NULL;
int tmp_level = 0;
parse_input_text(text, &tmp_base, &tmp_prefix, &tmp_level);
printf("\nfilename_completion_function: text = %s, tmp_base = %s, tmp_prefix = %s\n",
text, tmp_base, tmp_prefix);
if (comp_state.matches && comp_state.matches[0]) {
for (int i = 0; comp_state.matches[i]; i++) {
printf("\nfilename_completion_function: comp_state.matches[%d] = %s\n", i, comp_state.matches[i]);
if (strncmp(comp_state.matches[i], tmp_prefix, strlen(tmp_prefix)) == 0) {
int tmp_i = i;
snprintf(tmp_path, sizeof(tmp_path), "%s/%s%s", current_dir, tmp_base, comp_state.matches[i]);
printf("\nfilename_completion_function: tmp_path = %s, current_dir = %s, comp_state.matches[%d] = %s, tmp_i = %d\n",
tmp_path, current_dir, i, comp_state.matches[i], tmp_i);
if (stat(tmp_path, &st_tmp) == 0 && S_ISDIR(st_tmp.st_mode)) {
same_reset = 1;
printf("\nfilename_completion_function: same_reset = %d\n", same_reset);
break;
}
}
}
}
// 释放临时解析结果
if (tmp_base) XFREE(MTYPE_TMP, tmp_base);
if (tmp_prefix) XFREE(MTYPE_TMP, tmp_prefix);
printf("\nfilename_completion_function: current_dir = %s, text = %s, abs_path = %s, reset_completion = %d, same_reset = %d\n",
current_dir, text, abs_path, reset_completion, same_reset);
printf("\nfilename_completion_function: 11111111 comp_state.persistent_path = %s\n", comp_state.persistent_path);
if ((!same_context) || (reset_completion && same_reset) || (!comp_state.persistent_path || comp_state.persistent_path[0] == '\0')) {
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 (current_base) XFREE(MTYPE_TMP, current_base);
if (current_prefix) XFREE(MTYPE_TMP, current_prefix);
}
}
printf("\nfilename_completion_function: comp_state.base_dir = %s, comp_state.current_text = %s, comp_state.original_prefix = %s, comp_state.persistent_path = %s\n",
comp_state.base_dir, comp_state.current_text, comp_state.original_prefix, comp_state.persistent_path);
// 没有匹配项
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;
}
按照你的修改后,还是有异常:
打印如下:
<dahua>dir f
【cmlsh_completion】text = f
[MATCHES] Called with text='f'
[COMP] Entering: text='f', state=0, last_state=-1
000000000000000
111111111111111111
[generate] Scanning directory: '/mnt/switch/' with prefix: ''
跳过软链接: main_uImage
[generate] Found 9 matches.
generate_current_dir_paths: matches = cfg/, ea/, etc/, ew/, home/, installers/, logfile/, 1.txt, ew.txt,
Generated 9 matches
22222222222222222 flash_path = flash:/
[MATCHES] Returning single match: 'flash:/'
lash:/
【cmlsh_completion】text = flash:/
[MATCHES] Called with text='flash:/'
[COMP] Entering: text='flash:/', state=0, last_state=-1
000000000000000
111111111111111111
[generate] Scanning directory: '/mnt/switch/' with prefix: ''
跳过软链接: main_uImage
[generate] Found 9 matches.
generate_current_dir_paths: matches = cfg
Username: