📄 complete.c
字号:
this_char = text[i];
prev_char = text[i - 1];
if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) ||
(this_char == '|' && prev_char == '>'))
in_command_position = 0;
else if (i > 0 && text [i-1] == '\\') /* Quoted */
in_command_position = 0;
}
}
}
if (flags & INPUT_COMPLETE_COMMANDS)
p = strrchr (word, '`');
if (flags & (INPUT_COMPLETE_COMMANDS | INPUT_COMPLETE_VARIABLES))
q = strrchr (word, '$');
if (flags & INPUT_COMPLETE_HOSTNAMES)
r = strrchr (word, '@');
if (q && q [1] == '(' && INPUT_COMPLETE_COMMANDS){
if (q > p)
p = q + 1;
q = NULL;
}
/* Command substitution? */
if (p > q && p > r){
matches = completion_matches (p + 1, command_completion_function);
if (matches)
*start += p + 1 - word;
}
/* Variable name? */
else if (q > p && q > r){
matches = completion_matches (q, variable_completion_function);
if (matches)
*start += q - word;
}
/* Starts with '@', then look through the known hostnames for
completion first. */
else if (r > p && r > q){
matches = completion_matches (r, hostname_completion_function);
if (matches)
*start += r - word;
}
/* Starts with `~' and there is no slash in the word, then
try completing this word as a username. */
if (!matches && *word == '~' && (flags & INPUT_COMPLETE_USERNAMES) && !strchr (word, PATH_SEP))
matches = completion_matches (word, username_completion_function);
/* And finally if this word is in a command position, then
complete over possible command names, including aliases, functions,
and command names. */
if (!matches && in_command_position)
matches = completion_matches (word, command_completion_function);
else if (!matches && (flags & INPUT_COMPLETE_FILENAMES)){
if (is_cd)
ignore_filenames = 1;
matches = completion_matches (word, filename_completion_function);
ignore_filenames = 0;
if (!matches && is_cd && *word != PATH_SEP && *word != '~'){
char *p, *q = text + *start;
for (p = text; *p && p < q && (*p == ' ' || *p == '\t'); p++);
if (!strncmp (p, "cd", 2))
for (p += 2; *p && p < q && (*p == ' ' || *p == '\t'); p++);
if (p == q){
char *cdpath = getenv ("CDPATH");
char c, *s, *r;
if (cdpath == NULL)
c = 0;
else
c = ':';
while (!matches && c == ':'){
s = strchr (cdpath, ':');
if (s == NULL)
s = strchr (cdpath, 0);
c = *s;
*s = 0;
if (*cdpath){
r = concat_dir_and_file (cdpath, word);
ignore_filenames = 1;
matches = completion_matches (r, filename_completion_function);
ignore_filenames = 0;
free (r);
}
*s = c;
cdpath = s + 1;
}
}
}
}
if (word)
free (word);
return matches;
}
void free_completions (WInput *in)
{
char **p;
if (!in->completions)
return;
for (p=in->completions; *p; p++)
free (*p);
free (in->completions);
in->completions = NULL;
}
static int query_height, query_width;
static WInput *input;
static int start, end, min_end;
static int insert_text (WInput *in, char *text, int len)
{
len = min (len, strlen (text)) + start - end;
if (strlen (in->buffer) + len >= in->current_max_len){
/* Expand the buffer */
char *narea = realloc(in->buffer, in->current_max_len + len + in->field_len);
if (narea){
in->buffer = narea;
in->current_max_len += len + in->field_len;
}
}
if (strlen (in->buffer)+1 < in->current_max_len){
if (len > 0){
int i, l = strlen (&in->buffer [end]);
for (i = l + 1; i >= 0; i--)
in->buffer [end + len + i] = in->buffer [end + i];
} else if (len < 0){
char *p = in->buffer + end + len, *q = in->buffer + end;
while (*q)
*(p++) = *(q++);
*p = 0;
}
strncpy (in->buffer + start, text, len - start + end);
in->point += len;
update_input (in, 1);
end += len;
}
return len != 0;
}
static int query_callback (Dlg_head * h, int Par, int Msg)
{
switch (Msg) {
case DLG_DRAW:
attrset (COLOR_NORMAL);
dlg_erase (h);
draw_box (h, 0, 0, query_height, query_width);
break;
case DLG_KEY:
switch (Par) {
case KEY_LEFT:
case KEY_RIGHT:
h->ret_value = 0;
dlg_stop (h);
return 1;
case 0177:
case KEY_BACKSPACE:
case XCTRL('h'):
if (end == min_end){
h->ret_value = 0;
dlg_stop (h);
return 1;
} else {
WLEntry *e, *e1;
e1 = e = ((WListbox *)(h->current->widget))->list;
do {
if (!strncmp (input->buffer + start, e1->text, end - start - 1)){
listbox_select_entry((WListbox *)(h->current->widget), e1);
handle_char (input, Par);
end--;
send_message (h, h->current->widget,
WIDGET_DRAW, 0);
break;
}
e1 = e1->next;
} while (e != e1);
}
return 1;
default:
if (Par > 0xff || !is_printable (Par)){
if (is_in_input_map (input, Par) == 2){
if (end == min_end)
return 1;
h->ret_value = B_USER; /* This means we want to refill the
list box and start again */
dlg_stop (h);
return 1;
} else
return 0;
} else {
WLEntry *e, *e1;
int need_redraw = 0;
int low = 4096;
char *last_text = NULL;
e1 = e = ((WListbox *)(h->current->widget))->list;
do {
if (!strncmp (input->buffer + start, e1->text, end - start)){
if (e1->text [end - start] == Par){
if (need_redraw){
register int c1, c2, si;
for (si = end - start + 1;
(c1 = last_text [si]) &&
(c2 = e1->text [si]); si++)
if (c1 != c2)
break;
if (low > si)
low = si;
last_text = e1->text;
need_redraw = 2;
} else {
need_redraw = 1;
listbox_select_entry((WListbox *)(h->current->widget), e1);
last_text = e1->text;
}
}
}
e1 = e1->next;
} while (e != e1);
if (need_redraw == 2){
insert_text (input, last_text, low);
send_message (h, h->current->widget,WIDGET_DRAW,0);
} else if (need_redraw == 1){
h->ret_value = B_ENTER;
dlg_stop (h);
}
}
return 1;
}
break;
}
return 0;
}
static int querylist_callback (void *data)
{
return 1;
}
#define DO_INSERTION 1
#define DO_QUERY 2
/* Returns 1 if the user would like to see us again */
int complete_engine (WInput *in, int what_to_do)
{
if (in->completions && in->point != end)
free_completions (in);
if (!in->completions){
end = in->point;
for (start = end ? end - 1 : 0; start > -1; start--)
if (strchr (" \t;|<>", in->buffer [start]))
break;
if (start < end)
start++;
in->completions = try_complete (in->buffer, &start, &end, in->completion_flags);
}
if (in->completions){
if (what_to_do & DO_INSERTION) {
if (insert_text (in, in->completions [0], strlen (in->completions [0]))){
if (in->completions [1])
beep ();
} else
beep ();
}
if ((what_to_do & DO_QUERY) && in->completions [1]) {
int maxlen = 0, i, count = 0;
int x, y, w, h;
int start_x, start_y;
char **p, *q;
Dlg_head *query_dlg;
WListbox *query_list;
for (p=in->completions + 1; *p; count++, p++)
if ((i = strlen (*p)) > maxlen)
maxlen = i;
start_x = in->widget.x;
start_y = in->widget.y;
if (start_y - 2 >= count) {
y = start_y - 2 - count;
h = 2 + count;
} else {
if (start_y >= LINES - start_y - 1) {
y = 0;
h = start_y;
} else {
y = start_y + 1;
h = LINES - start_y - 1;
}
}
x = start - in->first_shown - 2 + start_x;
w = maxlen + 4;
if (x + w > COLS)
x = COLS - w;
if (x < 0)
x = 0;
if (x + w > COLS)
w = COLS;
input = in;
min_end = end;
query_height = h;
query_width = w;
query_dlg = create_dlg (y, x, query_height, query_width,
dialog_colors, query_callback,
"[Completion-query]", "complete", DLG_NONE);
query_list = listbox_new (1, 1, w - 2, h - 2, 0, querylist_callback, NULL);
add_widget (query_dlg, query_list);
for (p = in->completions + 1; *p; p++)
listbox_add_item (query_list, 0, 0, *p, NULL);
run_dlg (query_dlg);
q = NULL;
if (query_dlg->ret_value == B_ENTER){
listbox_get_current (query_list, &q, NULL);
if (q)
insert_text (in, q, strlen (q));
}
if (q || end != min_end)
free_completions (in);
i = query_dlg->ret_value; /* B_USER if user wants to start over again */
destroy_dlg (query_dlg);
if (i == B_USER)
return 1;
}
} else
beep ();
return 0;
}
void complete (WInput *in)
{
if (in->completions)
while (complete_engine (in, DO_QUERY));
else if (show_all_if_ambiguous){
complete_engine (in, DO_INSERTION);
while (complete_engine (in, DO_QUERY));
} else
complete_engine (in, DO_INSERTION);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -