📄 complete.c
字号:
if (qc && *qc && point && rl_line_buffer[point - 1] == *qc) point--; rl_delete_text (point, rl_point); rl_point = point; if (matches[1]) { for (i = 1; matches[i]; i++) { rp = make_quoted_replacement (matches[i], SINGLE_MATCH, qc); rl_insert_text (rp); rl_insert_text (" "); if (rp != matches[i]) xfree (rp); } } else { rp = make_quoted_replacement (matches[0], SINGLE_MATCH, qc); rl_insert_text (rp); rl_insert_text (" "); if (rp != matches[0]) xfree (rp); } rl_end_undo_group ();}void_rl_free_match_list (matches) char **matches;{ register int i; if (matches == 0) return; for (i = 0; matches[i]; i++) xfree (matches[i]); xfree (matches);}/* Complete the word at or before point. WHAT_TO_DO says what to do with the completion. `?' means list the possible completions. TAB means do standard completion. `*' means insert all of the possible completions. `!' means to do standard completion, and list all possible completions if there is more than one. `@' means to do standard completion, and list all possible completions if there is more than one and partial completion is not possible. */intrl_complete_internal (what_to_do) int what_to_do;{ char **matches; rl_compentry_func_t *our_func; int start, end, delimiter, found_quote, i, nontrivial_lcd; char *text, *saved_line_buffer; char quote_char;#if 1 int tlen, mlen;#endif RL_SETSTATE(RL_STATE_COMPLETING); set_completion_defaults (what_to_do); saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL; our_func = rl_completion_entry_function ? rl_completion_entry_function : rl_filename_completion_function; /* We now look backwards for the start of a filename/variable word. */ end = rl_point; found_quote = delimiter = 0; quote_char = '\0'; if (rl_point) /* This (possibly) changes rl_point. If it returns a non-zero char, we know we have an open quote. */ quote_char = _rl_find_completion_word (&found_quote, &delimiter); start = rl_point; rl_point = end; text = rl_copy_text (start, end); matches = gen_completion_matches (text, start, end, our_func, found_quote, quote_char); /* nontrivial_lcd is set if the common prefix adds something to the word being completed. */ nontrivial_lcd = matches && strcmp (text, matches[0]) != 0;#if 1 if (what_to_do == '!' || what_to_do == '@') tlen = strlen (text);#endif xfree (text); if (matches == 0) { rl_ding (); FREE (saved_line_buffer); completion_changed_buffer = 0; RL_UNSETSTATE(RL_STATE_COMPLETING); _rl_reset_completion_state (); return (0); } /* If we are matching filenames, the attempted completion function will have set rl_filename_completion_desired to a non-zero value. The basic rl_filename_completion_function does this. */ i = rl_filename_completion_desired; if (postprocess_matches (&matches, i) == 0) { rl_ding (); FREE (saved_line_buffer); completion_changed_buffer = 0; RL_UNSETSTATE(RL_STATE_COMPLETING); _rl_reset_completion_state (); return (0); } switch (what_to_do) { case TAB: case '!': case '@': /* Insert the first match with proper quoting. */#if 0 if (*matches[0]) insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);#else if (what_to_do == TAB) { if (*matches[0]) insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); } else if (*matches[0] && matches[1] == 0) /* should we perform the check only if there are multiple matches? */ insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); else if (*matches[0]) /* what_to_do != TAB && multiple matches */ { mlen = *matches[0] ? strlen (matches[0]) : 0; if (mlen >= tlen) insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); }#endif /* If there are more matches, ring the bell to indicate. If we are in vi mode, Posix.2 says to not ring the bell. If the `show-all-if-ambiguous' variable is set, display all the matches immediately. Otherwise, if this was the only match, and we are hacking files, check the file to see if it was a directory. If so, and the `mark-directories' variable is set, add a '/' to the name. If not, and we are at the end of the line, then add a space. */ if (matches[1]) { if (what_to_do == '!') { display_matches (matches); break; } else if (what_to_do == '@') { if (nontrivial_lcd == 0) display_matches (matches); break; } else if (rl_editing_mode != vi_mode) rl_ding (); /* There are other matches remaining. */ } else append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd); break; case '*': insert_all_matches (matches, start, "e_char); break; case '?': display_matches (matches); break; default: _rl_ttymsg ("bad value %d for what_to_do in rl_complete", what_to_do); rl_ding (); FREE (saved_line_buffer); RL_UNSETSTATE(RL_STATE_COMPLETING); _rl_reset_completion_state (); return 1; } _rl_free_match_list (matches); /* Check to see if the line has changed through all of this manipulation. */ if (saved_line_buffer) { completion_changed_buffer = strcmp (rl_line_buffer, saved_line_buffer) != 0; xfree (saved_line_buffer); } RL_UNSETSTATE(RL_STATE_COMPLETING); _rl_reset_completion_state (); return 0;}/***************************************************************//* *//* Application-callable completion match generator functions *//* *//***************************************************************//* Return an array of (char *) which is a list of completions for TEXT. If there are no completions, return a NULL pointer. The first entry in the returned array is the substitution for TEXT. The remaining entries are the possible completions. The array is terminated with a NULL pointer. ENTRY_FUNCTION is a function of two args, and returns a (char *). The first argument is TEXT. The second is a state argument; it should be zero on the first call, and non-zero on subsequent calls. It returns a NULL pointer to the caller when there are no more matches. */char **rl_completion_matches (text, entry_function) const char *text; rl_compentry_func_t *entry_function;{ /* Number of slots in match_list. */ int match_list_size; /* The list of matches. */ char **match_list; /* Number of matches actually found. */ int matches; /* Temporary string binder. */ char *string; matches = 0; match_list_size = 10; match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); match_list[1] = (char *)NULL; _rl_interrupt_immediately++; while (string = (*entry_function) (text, matches)) { if (matches + 1 == match_list_size) match_list = (char **)xrealloc (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); match_list[++matches] = string; match_list[matches + 1] = (char *)NULL; } if (_rl_interrupt_immediately > 0) _rl_interrupt_immediately--; /* If there were any matches, then look through them finding out the lowest common denominator. That then becomes match_list[0]. */ if (matches) compute_lcd_of_matches (match_list, matches, text); else /* There were no matches. */ { xfree (match_list); match_list = (char **)NULL; } return (match_list);}/* A completion function for usernames. TEXT contains a partial username preceded by a random character (usually `~'). */char *rl_username_completion_function (text, state) const char *text; int state;{#if defined (__WIN32__) || defined (__OPENNT) return (char *)NULL;#else /* !__WIN32__ && !__OPENNT) */ static char *username = (char *)NULL; static struct passwd *entry; static int namelen, first_char, first_char_loc; char *value; if (state == 0) { FREE (username); first_char = *text; first_char_loc = first_char == '~'; username = savestring (&text[first_char_loc]); namelen = strlen (username); setpwent (); }#if defined (HAVE_GETPWENT) while (entry = getpwent ()) { /* Null usernames should result in all users as possible completions. */ if (namelen == 0 || (STREQN (username, entry->pw_name, namelen))) break; }#endif if (entry == 0) {#if defined (HAVE_GETPWENT) endpwent ();#endif return ((char *)NULL); } else { value = (char *)xmalloc (2 + strlen (entry->pw_name)); *value = *text; strcpy (value + first_char_loc, entry->pw_name); if (first_char == '~') rl_filename_completion_desired = 1; return (value); }#endif /* !__WIN32__ && !__OPENNT */}/* Return non-zero if CONVFN matches FILENAME up to the length of FILENAME (FILENAME_LEN). If _rl_completion_case_fold is set, compare without regard to the alphabetic case of characters. CONVFN is the possibly- converted directory entry; FILENAME is what the user typed. */static intcomplete_fncmp (convfn, convlen, filename, filename_len) const char *convfn; int convlen; const char *filename; int filename_len;{ register char *s1, *s2; int d, len; /* Otherwise, if these match up to the length of filename, then it is a match. */ if (_rl_completion_case_fold && _rl_completion_case_map) { /* Case-insensitive comparison treating _ and - as equivalent */ if (filename_len == 0) return 1; if (convlen < filename_len) return 0; s1 = (char *)convfn; s2 = (char *)filename; len = filename_len; do { d = _rl_to_lower (*s1) - _rl_to_lower (*s2); /* *s1 == [-_] && *s2 == [-_] */ if ((*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_')) d = 0; if (d != 0) return 0; s1++; s2++; /* already checked convlen >= filename_len */ } while (--len != 0); return 1; } else if (_rl_completion_case_fold) { if ((_rl_to_lower (convfn[0]) == _rl_to_lower (filename[0])) && (convlen >= filename_len) && (_rl_strnicmp (filename, convfn, filename_len) == 0)) return 1; } else { if ((convfn[0] == filename[0]) && (convlen >= filename_len) && (strncmp (filename, convfn, filename_len) == 0)) return 1; } return 0;}/* Okay, now we write the entry_function for filename completion. In the general case. Note that completion in the shell is a little different because of all the pathnames that must be followed when looking up the completion for a command. */char *rl_filename_completion_function (text, state) const char *text; int state;{ static DIR *directory = (DIR *)NULL; static char *filename = (char *)NULL; static char *dirname = (char *)NULL; static char *users_dirname = (char *)NULL; static int filename_len; char *temp, *dentry, *convfn; int dirlen, dentlen, convlen; struct dirent *entry; /* If we don't have any state, then do some initialization. */ if (state == 0) { /* If we were interrupted before closing the directory or reading all of its contents, close it. */ if (directory) { closedir (directory); directory = (DIR *)NULL; } FREE (dirname); FREE (filename); FREE (users_dirname); filename = savestring (text); if (*text == 0) text = "."; dirname = savestring (text); temp = strrchr (dirname, '/');#if defined (__MSDOS__) /* special hack for //X/... */ if (dirname[0] == '/' && dirname[1] == '/' && ISALPHA ((unsigned char)dirname[2]) && dirname[3] == '/') temp = strrchr (dirname + 3, '/');#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -