📄 bashline.c
字号:
} }}/* Completion inside an unterminated command substitution. */static char *command_subst_completion_function (text, state) const char *text; int state;{ static char **matches = (char **)NULL; static const char *orig_start; static char *filename_text = (char *)NULL; static int cmd_index, start_len; char *value; if (state == 0) { if (filename_text) free (filename_text); orig_start = text; if (*text == '`') text++; else if (*text == '$' && text[1] == '(') /* ) */ text += 2; /* If the text was quoted, suppress any quote character that the readline completion code would insert. */ rl_completion_suppress_quote = 1; start_len = text - orig_start; filename_text = savestring (text); if (matches) free (matches); /* * At this point we can entertain the idea of re-parsing * `filename_text' into a (possibly incomplete) command name and * arguments, and doing completion based on that. This is * currently very rudimentary, but it is a small improvement. */ for (value = filename_text + strlen (filename_text) - 1; value > filename_text; value--) if (whitespace (*value) || member (*value, COMMAND_SEPARATORS)) break; if (value <= filename_text) matches = rl_completion_matches (filename_text, command_word_completion_function); else { value++; start_len += value - filename_text; if (whitespace (value[-1])) matches = rl_completion_matches (value, rl_filename_completion_function); else matches = rl_completion_matches (value, command_word_completion_function); } /* If there is more than one match, rl_completion_matches has already put the lcd in matches[0]. Skip over it. */ cmd_index = matches && matches[0] && matches[1]; /* If there's a single match and it's a directory, set the append char to the expected `/'. Otherwise, don't append anything. */ if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) rl_completion_append_character = '/'; else rl_completion_suppress_append = 1; } if (!matches || !matches[cmd_index]) { rl_filename_quoting_desired = 0; /* disable quoting */ return ((char *)NULL); } else { value = (char *)xmalloc (1 + start_len + strlen (matches[cmd_index])); if (start_len == 1) value[0] = *orig_start; else strncpy (value, orig_start, start_len); strcpy (value + start_len, matches[cmd_index]); cmd_index++; return (value); }}/* Okay, now we write the entry_function for variable completion. */static char *variable_completion_function (text, state) const char *text; int state;{ static char **varlist = (char **)NULL; static int varlist_index; static char *varname = (char *)NULL; static int namelen; static int first_char, first_char_loc; if (!state) { if (varname) free (varname); first_char_loc = 0; first_char = text[0]; if (first_char == '$') first_char_loc++; if (text[first_char_loc] == '{') first_char_loc++; varname = savestring (text + first_char_loc); namelen = strlen (varname); if (varlist) strvec_dispose (varlist); varlist = all_variables_matching_prefix (varname); varlist_index = 0; } if (!varlist || !varlist[varlist_index]) { return ((char *)NULL); } else { char *value; value = (char *)xmalloc (4 + strlen (varlist[varlist_index])); if (first_char_loc) { value[0] = first_char; if (first_char_loc == 2) value[1] = '{'; } strcpy (value + first_char_loc, varlist[varlist_index]); if (first_char_loc == 2) strcat (value, "}"); varlist_index++; return (value); }}/* How about a completion function for hostnames? */static char *hostname_completion_function (text, state) const char *text; int state;{ static char **list = (char **)NULL; static int list_index = 0; static int first_char, first_char_loc; /* If we don't have any state, make some. */ if (state == 0) { FREE (list); list = (char **)NULL; first_char_loc = 0; first_char = *text; if (first_char == '@') first_char_loc++; list = hostnames_matching ((char *)text+first_char_loc); list_index = 0; } if (list && list[list_index]) { char *t; t = (char *)xmalloc (2 + strlen (list[list_index])); *t = first_char; strcpy (t + first_char_loc, list[list_index]); list_index++; return (t); } return ((char *)NULL);}/* * A completion function for service names from /etc/services (or wherever). */char *bash_servicename_completion_function (text, state) const char *text; int state;{#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GETSERVENT) return ((char *)NULL);#else static char *sname = (char *)NULL; static struct servent *srvent; static int snamelen, firstc; char *value; char **alist, *aentry; int afound; if (state == 0) { FREE (sname); firstc = *text; sname = savestring (text); snamelen = strlen (sname); setservent (0); } while (srvent = getservent ()) { afound = 0; if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen))) break; /* Not primary, check aliases */ for (alist = srvent->s_aliases; *alist; alist++) { aentry = *alist; if (STREQN (sname, aentry, snamelen)) { afound = 1; break; } } if (afound) break; } if (srvent == 0) { endservent (); return ((char *)NULL); } value = afound ? savestring (aentry) : savestring (srvent->s_name); return value;#endif}/* * A completion function for group names from /etc/group (or wherever). */char *bash_groupname_completion_function (text, state) const char *text; int state;{#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H) return ((char *)NULL);#else static char *gname = (char *)NULL; static struct group *grent; static int gnamelen; char *value; if (state == 0) { FREE (gname); gname = savestring (text); gnamelen = strlen (gname); setgrent (); } while (grent = getgrent ()) { if (gnamelen == 0 || (STREQN (gname, grent->gr_name, gnamelen))) break; } if (grent == 0) { endgrent (); return ((char *)NULL); } value = savestring (grent->gr_name); return (value);#endif}/* Functions to perform history and alias expansions on the current line. */#if defined (BANG_HISTORY)/* Perform history expansion on the current line. If no history expansion is done, pre_process_line() returns what it was passed, so we need to allocate a new line here. */static char *history_expand_line_internal (line) char *line;{ char *new_line; int old_verify; old_verify = hist_verify; hist_verify = 0; new_line = pre_process_line (line, 0, 0); hist_verify = old_verify; return (new_line == line) ? savestring (line) : new_line;}#endif/* There was an error in expansion. Let the preprocessor print the error here. */static voidcleanup_expansion_error (){ char *to_free;#if defined (BANG_HISTORY) int old_verify; old_verify = hist_verify; hist_verify = 0;#endif fprintf (rl_outstream, "\r\n"); to_free = pre_process_line (rl_line_buffer, 1, 0);#if defined (BANG_HISTORY) hist_verify = old_verify;#endif if (to_free != rl_line_buffer) FREE (to_free); putc ('\r', rl_outstream); rl_forced_update_display ();}/* If NEW_LINE differs from what is in the readline line buffer, add an undo record to get from the readline line buffer contents to the new line and make NEW_LINE the current readline line. */static voidmaybe_make_readline_line (new_line) char *new_line;{ if (strcmp (new_line, rl_line_buffer) != 0) { rl_point = rl_end; rl_add_undo (UNDO_BEGIN, 0, 0, 0); rl_delete_text (0, rl_point); rl_point = rl_end = rl_mark = 0; rl_insert_text (new_line); rl_add_undo (UNDO_END, 0, 0, 0); }}/* Make NEW_LINE be the current readline line. This frees NEW_LINE. */static voidset_up_new_line (new_line) char *new_line;{ int old_point, at_end; old_point = rl_point; at_end = rl_point == rl_end; /* If the line was history and alias expanded, then make that be one thing to undo. */ maybe_make_readline_line (new_line); free (new_line); /* Place rl_point where we think it should go. */ if (at_end) rl_point = rl_end; else if (old_point < rl_end) { rl_point = old_point; if (!whitespace (rl_line_buffer[rl_point])) rl_forward_word (1, 0); }}#if defined (ALIAS)/* Expand aliases in the current readline line. */static intalias_expand_line (count, ignore) int count, ignore;{ char *new_line; new_line = alias_expand (rl_line_buffer); if (new_line) { set_up_new_line (new_line); return (0); } else { cleanup_expansion_error (); return (1); }}#endif#if defined (BANG_HISTORY)/* History expand the line. */static inthistory_expand_line (count, ignore) int count, ignore;{ char *new_line; new_line = history_expand_line_internal (rl_line_buffer); if (new_line) { set_up_new_line (new_line); return (0); } else { cleanup_expansion_error (); return (1); }}/* Expand history substitutions in the current line and then insert a space (hopefully close to where we were before). */static inttcsh_magic_space (count, ignore) int count, ignore;{ int dist_from_end, old_point; old_point = rl_point; dist_from_end = rl_end - rl_point; if (history_expand_line (count, ignore) == 0) { /* Try a simple heuristic from Stephen Gildea <gildea@intouchsys.com>. This works if all expansions were before rl_point or if no expansions were performed. */ rl_point = (old_point == 0) ? old_point : rl_end - dist_from_end; rl_insert (1, ' '); return (0); } else return (1);}#endif /* BANG_HISTORY *//* History and alias expand the line. */static inthistory_and_alias_expand_line (count, ignore) int count, ignore;{ char *new_line; new_line = 0;#if defined (BANG_HISTORY) new_line = history_expand_line_internal (rl_line_buffer);#en
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -