void completion_deinit(void) { free_completions(); chat_completion_deinit(); signal_remove("complete word", (SIGNAL_FUNC) sig_complete_word); signal_remove("complete command set", (SIGNAL_FUNC) sig_complete_set); signal_remove("complete command toggle", (SIGNAL_FUNC) sig_complete_toggle); signal_remove("complete command cat", (SIGNAL_FUNC) sig_complete_filename); signal_remove("complete command run", (SIGNAL_FUNC) sig_complete_filename); signal_remove("complete command save", (SIGNAL_FUNC) sig_complete_filename); signal_remove("complete command reload", (SIGNAL_FUNC) sig_complete_filename); signal_remove("complete command rawlog open", (SIGNAL_FUNC) sig_complete_filename); signal_remove("complete command rawlog save", (SIGNAL_FUNC) sig_complete_filename); signal_remove("complete command help", (SIGNAL_FUNC) sig_complete_command); }
char *fetchline(xfs_mount_t *mp, char *path) { xfs_inode_t *inode; xfs_off_t ofs = 0; char *line; int r; free_completions(); r = find_path(mp, path, &inode); if (r == 0) { r = xfs_readdir(inode, NULL, 102400, &ofs, cli_complete_xfs_filldir); libxfs_iput(inode, 0); } rl_completion_entry_function = (Function *)dir_generator; rl_bind_key('\t', rl_complete); line = readline(get_prompt(path)); if (line && *line) add_history(line); return line; }
/* manual word completion - called when TAB is pressed */ char *word_complete(WINDOW_REC *window, const char *line, int *pos) { static int startpos = 0, wordlen = 0; GString *result; char *word, *wordstart, *linestart, *ret; int want_space; g_return_val_if_fail(line != NULL, NULL); g_return_val_if_fail(pos != NULL, NULL); if (complist != NULL && *pos == last_line_pos && strcmp(line, last_line) == 0) { /* complete from old list */ complist = complist->next != NULL ? complist->next : g_list_first(complist); want_space = last_want_space; } else { /* get new completion list */ free_completions(); /* get the word we want to complete */ word = get_word_at(line, *pos, &wordstart); startpos = (int) (wordstart-line); wordlen = strlen(word); /* get the start of line until the word we're completing */ if (isseparator(*line)) { /* empty space at the start of line */ if (wordstart == line) wordstart += strlen(wordstart); } else { while (wordstart > line && isseparator(wordstart[-1])) wordstart--; } linestart = g_strndup(line, (int) (wordstart-line)); /* completions usually add space after the word, that makes things a bit harder. When continuing a completion "/msg nick1 "<tab> we have to cycle to nick2, etc. BUT if we start completion with "/msg "<tab>, we don't want to complete the /msg word, but instead complete empty word with /msg being in linestart. */ if (*pos > 0 && line[*pos-1] == ' ') { char *old; old = linestart; linestart = *linestart == '\0' ? g_strdup(word) : g_strconcat(linestart, " ", word, NULL); g_free(old); g_free(word); word = g_strdup(""); startpos = strlen(linestart)+1; wordlen = 0; } want_space = TRUE; signal_emit("complete word", 5, &complist, window, word, linestart, &want_space); last_want_space = want_space; g_free(linestart); g_free(word); } if (complist == NULL) return NULL; /* word completed */ *pos = startpos+strlen(complist->data); /* replace the word in line - we need to return a full new line */ result = g_string_new(line); g_string_erase(result, startpos, wordlen); g_string_insert(result, startpos, complist->data); if (want_space) { if (!isseparator(result->str[*pos])) g_string_insert_c(result, *pos, ' '); (*pos)++; } wordlen = strlen(complist->data); last_line_pos = *pos; g_free_not_null(last_line); last_line = g_strdup(result->str); ret = result->str; g_string_free(result, FALSE); return ret; }
/* Returns 1 if the user would like to see us again */ static 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 || ((what_to_do & DO_QUERY) && !in->completions[1])) { if (insert_text (in, in->completions [0], strlen (in->completions [0]))){ if (in->completions [1]) beep (); else free_completions (in); } else beep (); } if ((what_to_do & DO_QUERY) && in->completions && 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]", NULL, DLG_COMPACT); query_list = listbox_new (1, 1, w - 2, h - 2, 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; }
/* manual word completion - called when TAB is pressed */ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, int backward) { static int startpos = 0, wordlen = 0; int old_startpos, old_wordlen; GString *result; const char *cmdchars; char *word, *wordstart, *linestart, *ret, *data; int continue_complete, want_space, expand_escapes; g_return_val_if_fail(line != NULL, NULL); g_return_val_if_fail(pos != NULL, NULL); continue_complete = complist != NULL && *pos == last_line_pos && g_strcmp0(line, last_line) == 0; if (erase && !continue_complete) return NULL; old_startpos = startpos; old_wordlen = wordlen; if (!erase && continue_complete) { word = NULL; linestart = NULL; } else { char* old_wordstart; /* get the word we want to complete */ word = get_word_at(line, *pos, &wordstart); old_wordstart = wordstart; startpos = (int) (wordstart-line); wordlen = strlen(word); /* remove trailing spaces from linestart */ while (wordstart > line && isseparator_space(wordstart[-1])) wordstart--; /* unless everything was spaces */ if (old_wordstart > line && wordstart == line) wordstart = old_wordstart - 1; linestart = g_strndup(line, (int) (wordstart-line)); /* completions usually add space after the word, that makes things a bit harder. When continuing a completion "/msg nick1 "<tab> we have to cycle to nick2, etc. BUT if we start completion with "/msg "<tab>, we don't want to complete the /msg word, but instead complete empty word with /msg being in linestart. */ if (!erase && *pos > 0 && isseparator_space(line[*pos-1]) && (*linestart == '\0' || !isseparator_space(wordstart[-1]))) { char *old; old = linestart; /* we want to move word into linestart */ if (*linestart == '\0') { linestart = g_strdup(word); } else { GString *str = g_string_new(linestart); if (old_wordstart[-1] != str->str[str->len - 1]) { /* do not accidentally duplicate the word separator */ g_string_append_c(str, old_wordstart[-1]); } g_string_append(str, word); linestart = g_string_free(str, FALSE); } g_free(old); g_free(word); word = g_strdup(""); startpos = *linestart == '\0' ? 0 : strlen(linestart)+1; wordlen = 0; } } if (erase) { signal_emit("complete erase", 3, window, word, linestart); /* jump to next completion */ startpos = old_startpos; wordlen = old_wordlen; } if (continue_complete) { /* complete from old list */ if (backward) complist = complist->prev != NULL ? complist->prev : g_list_last(complist); else complist = complist->next != NULL ? complist->next : g_list_first(complist); want_space = last_want_space; } else { int keep_word = settings_get_bool("completion_keep_word"); /* get new completion list */ free_completions(); want_space = TRUE; signal_emit("complete word", 5, &complist, window, word, linestart, &want_space); last_want_space = want_space; if (complist != NULL) { /* Remove all nulls (from the signal) before doing further processing */ complist = g_list_remove_all(g_list_first(complist), NULL); if (keep_word) { complist = g_list_append(complist, g_strdup(word)); } if (backward) { complist = g_list_last(complist); if (keep_word) { complist = complist->prev; } } } } g_free(linestart); g_free(word); if (complist == NULL) return NULL; /* get the cmd char */ cmdchars = settings_get_str("cmdchars"); /* get the expand_escapes setting */ expand_escapes = settings_get_bool("expand_escapes"); /* escape if the word doesn't begin with '/' and expand_escapes are turned on */ data = strchr(cmdchars, *line) == NULL && expand_escapes ? escape_string_backslashes(complist->data) : g_strdup(complist->data); /* word completed */ *pos = startpos + strlen(data); /* replace the word in line - we need to return a full new line */ result = g_string_new(line); g_string_erase(result, startpos, wordlen); g_string_insert(result, startpos, data); if (want_space) { if (!isseparator(result->str[*pos])) g_string_insert_c(result, *pos, ' '); (*pos)++; } wordlen = strlen(data); last_line_pos = *pos; g_free_not_null(last_line); last_line = g_strdup(result->str); ret = result->str; g_string_free(result, FALSE); /* free the data */ g_free(data); return ret; }