📄 complete.c
字号:
fprintf (stderr, "\r\nreadline: bad value %d for what_to_do in rl_complete\n", what_to_do);
ding ();
FREE (saved_line_buffer);
return 1;
}
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;
free (saved_line_buffer);
}
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 **
completion_matches (text, entry_function)
char *text;
CPFunction *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;
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 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. */
{
free (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 *
username_completion_function (text, state)
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 ();
}
while (entry = getpwent ())
{
/* Null usernames should result in all users as possible completions. */
if (namelen == 0 || (STREQN (username, entry->pw_name, namelen)))
break;
}
if (entry == 0)
{
endpwent ();
return ((char *)NULL);
}
else
{
value = 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 */
}
/* 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 *
filename_completion_function (text, state)
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;
int dirlen;
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 (__DJGPP__)
/* special hack for /dev/X/ */
if (dirname[0] == '/'
&& strcmp (dirname + 1, "dev") == 0
&& (dirname[4] == '/')
&& dirname[5]
&& (dirname[6] == '/'))
temp = strrchr (dirname + 6, '/');
#endif
if (temp)
{
strcpy (filename, ++temp);
*temp = '\0';
}
#if defined (HAVE_DOS_STYLE_FILE_SYSTEM)
/* searches from current directory on the drive */
else if (isalpha (dirname[0]) && dirname[1] == ':')
{
strcpy (filename, dirname + 2);
dirname[2] = '\0';
}
#endif
else
{
dirname[0] = '.';
dirname[1] = '\0';
}
/* We aren't done yet. We also support the "~user" syntax. */
/* Save the version of the directory that the user typed. */
users_dirname = savestring (dirname);
if (*dirname == '~')
{
temp = tilde_expand (dirname);
free (dirname);
dirname = temp;
}
if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dirname))
{
free (users_dirname);
users_dirname = savestring (dirname);
}
directory = opendir (dirname);
filename_len = strlen (filename);
rl_filename_completion_desired = 1;
}
/* At this point we should entertain the possibility of hacking wildcarded
filenames, like /usr/man/man<WILD>/te<TAB>. If the directory name
contains globbing characters, then build an array of directories, and
then map over that list while completing. */
/* *** UNIMPLEMENTED *** */
/* Now that we have some state, we can read the directory. */
entry = (struct dirent *)NULL;
while (directory && (entry = readdir (directory)))
{
/* Special case for no filename.
All entries except "." and ".." match. */
if (filename_len == 0)
{
if (entry->d_name[0] != '.' ||
(entry->d_name[1] &&
(entry->d_name[1] != '.' || entry->d_name[2])))
break;
}
else
{
/* Otherwise, if these match up to the length of filename, then
it is a match. */
if (_rl_completion_case_fold)
{
if ((_rl_to_lower (entry->d_name[0]) == _rl_to_lower (filename[0])) &&
(((int)D_NAMLEN (entry)) >= filename_len) &&
(_rl_strnicmp (filename, entry->d_name, filename_len) == 0))
break;
}
else
{
if ((entry->d_name[0] == filename[0]) &&
(((int)D_NAMLEN (entry)) >= filename_len) &&
(strncmp (filename, entry->d_name, filename_len) == 0))
break;
}
}
}
if (entry == 0)
{
if (directory)
{
closedir (directory);
directory = (DIR *)NULL;
}
if (dirname)
{
free (dirname);
dirname = (char *)NULL;
}
if (filename)
{
free (filename);
filename = (char *)NULL;
}
if (users_dirname)
{
free (users_dirname);
users_dirname = (char *)NULL;
}
return (char *)NULL;
}
else
{
/* dirname && (strcmp (dirname, ".") != 0) */
if (dirname && (dirname[0] != '.' || dirname[1]))
{
if (rl_complete_with_tilde_expansion && *users_dirname == '~')
{
dirlen = strlen (dirname);
temp = xmalloc (2 + dirlen + D_NAMLEN (entry));
strcpy (temp, dirname);
/* Canonicalization cuts off any final slash present. We
may need to add it back. */
if (dirname[dirlen - 1] != '/')
{
temp[dirlen++] = '/';
temp[dirlen] = '\0';
}
}
else
{
dirlen = strlen (users_dirname);
temp = xmalloc (1 + dirlen + D_NAMLEN (entry));
strcpy (temp, users_dirname);
}
strcpy (temp + dirlen, entry->d_name);
}
else
temp = savestring (entry->d_name);
return (temp);
}
}
/* An initial implementation of a menu completion function a la tcsh. The
first time (if the last readline command was not rl_menu_complete), we
generate the list of matches. This code is very similar to the code in
rl_complete_internal -- there should be a way to combine the two. Then,
for each item in the list of matches, we insert the match in an undoable
fashion, with the appropriate character appended (this happens on the
second and subsequent consecutive calls to rl_menu_complete). When we
hit the end of the match list, we restore the original unmatched text,
ring the bell, and reset the counter to zero. */
int
rl_menu_complete (count, ignore)
int count, ignore;
{
Function *our_func;
int matching_filenames, found_quote;
static char *orig_text;
static char **matches = (char **)0;
static int match_list_index = 0;
static int match_list_size = 0;
static int orig_start, orig_end;
static char quote_char;
static int delimiter;
/* The first time through, we generate the list of matches and set things
up to insert them. */
if (rl_last_func != rl_menu_complete)
{
/* Clean up from previous call, if any. */
FREE (orig_text);
if (matches)
free_match_list (matches);
match_list_index = match_list_size = 0;
matches = (char **)NULL;
/* Only the completion entry function can change these. */
rl_filename_completion_desired = 0;
rl_filename_quoting_desired = 1;
rl_completion_type = '%';
our_func = rl_completion_entry_function
? rl_completion_entry_function
: (Function *)filename_completion_function;
/* We now look backwards for the start of a filename/variable word. */
orig_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 = find_completion_word (&found_quote, &delimiter);
orig_start = rl_point;
rl_point = orig_end;
orig_text = rl_copy_text (orig_start, orig_end);
matches = gen_completion_matches (orig_text, orig_start, orig_end,
our_func, found_quote, quote_char);
#if 0
/* If we are matching filenames, our_func will have been set to
filename_completion_function */
matching_filenames = our_func == (Function *)filename_completion_function;
#else
/* If we are matching filenames, the attempted completion function will
have set rl_filename_completion_desired to a non-zero value. The basic
filename_completion_function does this. */
matching_filenames = rl_filename_completion_desired;
#endif
if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0)
{
ding ();
FREE (matches);
matches = (char **)0;
FREE (orig_text);
orig_text = (char *)0;
completion_changed_buffer = 0;
return (0);
}
for (match_list_size = 0; matches[match_list_size]; match_list_size++)
;
/* matches[0] is lcd if match_list_size > 1, but the circular buffer
code below should take care of it. */
}
/* Now we have the list of matches. Replace the text between
rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with
matches[match_list_index], and add any necessary closing char. */
if (matches == 0 || match_list_size == 0)
{
ding ();
FREE (matches);
matches = (char **)0;
completion_changed_buffer = 0;
return (0);
}
match_list_index = (match_list_index + count) % match_list_size;
if (match_list_index < 0)
match_list_index += match_list_size;
if (match_list_index == 0 && match_list_size > 1)
{
ding ();
insert_match (orig_text, orig_start, MULT_MATCH, "e_char);
}
else
{
insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char);
append_to_match (matches[match_list_index], delimiter, quote_char);
}
completion_changed_buffer = 1;
return (0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -