Readline:如何在双选项卡上列出所有自动完成匹配项?
Readline: How to list all autocomplete matches on double tab?
我正在使用 "readline" 库为我的程序创建控制台界面。我可以使用 tab 自动完成单词,但是当我有共享相同前缀的单词时,如 (car, card, carbon) 它总是选择最短的一个。这是我的程序(主要取自 link):
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <iostream>
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wifes"};
void *xmalloc (int size)
{
void *buf;
buf = malloc (size);
if (!buf)
{
fprintf (stderr, "Error: Out of memory. Exiting.\n");
exit (1);
}
return buf;
}
char *dupstr (const char *str)
{
char *temp;
temp = (char *) xmalloc (strlen (str) + 1);
strcpy (temp, str);
return (temp);
}
char *my_generator (const char *text, int state)
{
static int list_index, len;
const char *name;
if (!state)
{
list_index = 0;
len = strlen (text);
}
while (name = words[list_index])
{
list_index++;
if (strncmp (name, text, len) == 0) return dupstr (name);
}
// If no names matched, then return NULL.
return ((char *) NULL);
}
static char **my_completion (const char *text, int start, int end)
{
char **matches = (char **) NULL;
if (start == 0)
{
matches = rl_completion_matches ((char *) text, &my_generator);
}
else rl_bind_key ('\t', rl_abort);
return matches;
}
int main (int argc, char *argv[])
{
char *buf;
rl_attempted_completion_function = my_completion;
while ((buf = readline(">> ")) != NULL)
{
rl_bind_key ('\t', rl_complete);
if (strcmp (buf, "exit") == 0) break;
else if (buf[0] == '[=10=]') continue;
else
{
std::cout << buf << std::endl;
add_history (buf);
}
}
free (buf);
return 0;
}
是否可以像 ubuntu 终端一样在双 选项卡 上列出所有匹配项?
我设法通过注释掉这两行使其工作:
rl_bind_key ('\t', rl_complete);
和:
else rl_bind_key ('\t', rl_abort);
readline 的默认完成行为与 ubuntu 终端完全一样,一个选项卡完成,两个选项卡列出可能的完成。不确定与 Tab 键绑定的默认完成功能是什么,从 documentation 我认为它是 rl_possible_completions
但它没有给出相同的结果。
我还向 my_completion
函数添加了以下行,以防止在匹配词的末尾添加 space:
rl_completion_append_character = '[=12=]';
我删除了dupstr
function 并用原生的strdup
函数替换了它(这与自动完成问题无关,只是为了删除不必要的代码)。
这是最终代码:
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <iostream>
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wives"};
// Generator function for word completion.
char *my_generator (const char *text, int state)
{
static int list_index, len;
const char *name;
if (!state)
{
list_index = 0;
len = strlen (text);
}
while (name = words[list_index])
{
list_index++;
if (strncmp (name, text, len) == 0) return strdup (name);
}
// If no names matched, then return NULL.
return ((char *) NULL);
}
// Custom completion function
static char **my_completion (const char *text, int start, int end)
{
// This prevents appending space to the end of the matching word
rl_completion_append_character = '[=13=]';
char **matches = (char **) NULL;
if (start == 0)
{
matches = rl_completion_matches ((char *) text, &my_generator);
}
// else rl_bind_key ('\t', rl_abort);
return matches;
}
int main (int argc, char *argv[])
{
char *buf;
rl_attempted_completion_function = my_completion;
while ((buf = readline(">> ")) != NULL)
{
// rl_bind_key ('\t', rl_complete);
if (strcmp (buf, "exit") == 0) break;
else if (buf[0] == '[=13=]')
{
free (buf);
continue;
}
else
{
std::cout << buf << std::endl;
add_history (buf);
}
free (buf);
buf = NULL;
}
if (buf != NULL) free (buf);
return 0;
}
razzak 的回答几乎是正确的,但是这个 NULL 必须添加在字符串数组的末尾:
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wives", NULL};
my_generator()
函数中非警告编译的一些更改:
while ((name = words[list_index++]))
{
if (strncmp (name, text, len) == 0) return strdup (name);
}
我正在使用 "readline" 库为我的程序创建控制台界面。我可以使用 tab 自动完成单词,但是当我有共享相同前缀的单词时,如 (car, card, carbon) 它总是选择最短的一个。这是我的程序(主要取自 link):
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <iostream>
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wifes"};
void *xmalloc (int size)
{
void *buf;
buf = malloc (size);
if (!buf)
{
fprintf (stderr, "Error: Out of memory. Exiting.\n");
exit (1);
}
return buf;
}
char *dupstr (const char *str)
{
char *temp;
temp = (char *) xmalloc (strlen (str) + 1);
strcpy (temp, str);
return (temp);
}
char *my_generator (const char *text, int state)
{
static int list_index, len;
const char *name;
if (!state)
{
list_index = 0;
len = strlen (text);
}
while (name = words[list_index])
{
list_index++;
if (strncmp (name, text, len) == 0) return dupstr (name);
}
// If no names matched, then return NULL.
return ((char *) NULL);
}
static char **my_completion (const char *text, int start, int end)
{
char **matches = (char **) NULL;
if (start == 0)
{
matches = rl_completion_matches ((char *) text, &my_generator);
}
else rl_bind_key ('\t', rl_abort);
return matches;
}
int main (int argc, char *argv[])
{
char *buf;
rl_attempted_completion_function = my_completion;
while ((buf = readline(">> ")) != NULL)
{
rl_bind_key ('\t', rl_complete);
if (strcmp (buf, "exit") == 0) break;
else if (buf[0] == '[=10=]') continue;
else
{
std::cout << buf << std::endl;
add_history (buf);
}
}
free (buf);
return 0;
}
是否可以像 ubuntu 终端一样在双 选项卡 上列出所有匹配项?
我设法通过注释掉这两行使其工作:
rl_bind_key ('\t', rl_complete);
和:
else rl_bind_key ('\t', rl_abort);
readline 的默认完成行为与 ubuntu 终端完全一样,一个选项卡完成,两个选项卡列出可能的完成。不确定与 Tab 键绑定的默认完成功能是什么,从 documentation 我认为它是 rl_possible_completions
但它没有给出相同的结果。
我还向 my_completion
函数添加了以下行,以防止在匹配词的末尾添加 space:
rl_completion_append_character = '[=12=]';
我删除了dupstr
function 并用原生的strdup
函数替换了它(这与自动完成问题无关,只是为了删除不必要的代码)。
这是最终代码:
#include <readline/readline.h>
#include <readline/history.h>
#include <stdlib.h>
#include <iostream>
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wives"};
// Generator function for word completion.
char *my_generator (const char *text, int state)
{
static int list_index, len;
const char *name;
if (!state)
{
list_index = 0;
len = strlen (text);
}
while (name = words[list_index])
{
list_index++;
if (strncmp (name, text, len) == 0) return strdup (name);
}
// If no names matched, then return NULL.
return ((char *) NULL);
}
// Custom completion function
static char **my_completion (const char *text, int start, int end)
{
// This prevents appending space to the end of the matching word
rl_completion_append_character = '[=13=]';
char **matches = (char **) NULL;
if (start == 0)
{
matches = rl_completion_matches ((char *) text, &my_generator);
}
// else rl_bind_key ('\t', rl_abort);
return matches;
}
int main (int argc, char *argv[])
{
char *buf;
rl_attempted_completion_function = my_completion;
while ((buf = readline(">> ")) != NULL)
{
// rl_bind_key ('\t', rl_complete);
if (strcmp (buf, "exit") == 0) break;
else if (buf[0] == '[=13=]')
{
free (buf);
continue;
}
else
{
std::cout << buf << std::endl;
add_history (buf);
}
free (buf);
buf = NULL;
}
if (buf != NULL) free (buf);
return 0;
}
razzak 的回答几乎是正确的,但是这个 NULL 必须添加在字符串数组的末尾:
const char *words[] = {"add", "remove", "rm", "update", "child", "children", "wife", "wives", NULL};
my_generator()
函数中非警告编译的一些更改:
while ((name = words[list_index++]))
{
if (strncmp (name, text, len) == 0) return strdup (name);
}