mirror of
https://github.com/MidnightCommander/mc
synced 2025-01-20 18:29:19 +03:00
input complete: reimplement using GPtrArray.
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
parent
4eacf0f99b
commit
e496af7a1c
@ -58,7 +58,7 @@ typedef struct
|
|||||||
gboolean init_from_history; /* init text will be get from history */
|
gboolean init_from_history; /* init text will be get from history */
|
||||||
gboolean need_push; /* need to push the current Input on hist? */
|
gboolean need_push; /* need to push the current Input on hist? */
|
||||||
gboolean strip_password; /* need to strip password before placing string to history */
|
gboolean strip_password; /* need to strip password before placing string to history */
|
||||||
char **completions; /* possible completions array */
|
GPtrArray *completions; /* possible completions array */
|
||||||
input_complete_t completion_flags;
|
input_complete_t completion_flags;
|
||||||
char charbuf[MB_LEN_MAX]; /* buffer for multibytes characters */
|
char charbuf[MB_LEN_MAX]; /* buffer for multibytes characters */
|
||||||
size_t charpoint; /* point to end of mulibyte sequence in charbuf */
|
size_t charpoint; /* point to end of mulibyte sequence in charbuf */
|
||||||
|
@ -88,7 +88,7 @@ typedef struct
|
|||||||
|
|
||||||
/*** forward declarations (file scope functions) *************************************************/
|
/*** forward declarations (file scope functions) *************************************************/
|
||||||
|
|
||||||
char **try_complete (char *text, int *lc_start, int *lc_end, input_complete_t flags);
|
GPtrArray *try_complete (char *text, int *lc_start, int *lc_end, input_complete_t flags);
|
||||||
void complete_engine_fill_completions (WInput * in);
|
void complete_engine_fill_completions (WInput * in);
|
||||||
|
|
||||||
/*** file scope variables ************************************************************************/
|
/*** file scope variables ************************************************************************/
|
||||||
@ -681,7 +681,7 @@ command_completion_function (const char *text, int state, input_complete_t flags
|
|||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
match_compare (const void *a, const void *b)
|
match_compare (gconstpointer a, gconstpointer b)
|
||||||
{
|
{
|
||||||
return strcmp (*(char *const *) a, *(char *const *) b);
|
return strcmp (*(char *const *) a, *(char *const *) b);
|
||||||
}
|
}
|
||||||
@ -695,72 +695,54 @@ match_compare (const void *a, const void *b)
|
|||||||
as the second.
|
as the second.
|
||||||
In case no matches were found we return NULL. */
|
In case no matches were found we return NULL. */
|
||||||
|
|
||||||
static char **
|
static GPtrArray *
|
||||||
completion_matches (const char *text, CompletionFunction entry_function, input_complete_t flags)
|
completion_matches (const char *text, CompletionFunction entry_function, input_complete_t flags)
|
||||||
{
|
{
|
||||||
/* Number of slots in match_list. */
|
GPtrArray *match_list;
|
||||||
size_t match_list_size = 30;
|
|
||||||
/* The list of matches. */
|
|
||||||
char **match_list;
|
|
||||||
/* Number of matches actually found. */
|
|
||||||
size_t matches = 0;
|
|
||||||
|
|
||||||
/* Temporary string binder. */
|
|
||||||
char *string;
|
char *string;
|
||||||
|
|
||||||
match_list = g_new (char *, match_list_size + 1);
|
match_list = g_ptr_array_new_with_free_func (g_free);
|
||||||
match_list[1] = NULL;
|
|
||||||
|
|
||||||
while ((string = (*entry_function) (text, matches, flags)) != NULL)
|
while ((string = entry_function (text, match_list->len, flags)) != NULL)
|
||||||
{
|
g_ptr_array_add (match_list, string);
|
||||||
if (matches + 1 == match_list_size)
|
|
||||||
{
|
|
||||||
match_list_size += 30;
|
|
||||||
match_list = (char **) g_renew (char *, match_list, match_list_size + 1);
|
|
||||||
}
|
|
||||||
match_list[++matches] = string;
|
|
||||||
match_list[matches + 1] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there were any matches, then look through them finding out the
|
/* If there were any matches, then look through them finding out the
|
||||||
lowest common denominator. That then becomes match_list[0]. */
|
lowest common denominator. That then becomes match_list[0]. */
|
||||||
if (matches == 0)
|
if (match_list->len == 0)
|
||||||
MC_PTR_FREE (match_list); /* There were no matches. */
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
/* If only one match, just use that. */
|
/* There were no matches. */
|
||||||
if (matches == 1)
|
g_ptr_array_free (match_list, TRUE);
|
||||||
{
|
return NULL;
|
||||||
match_list[0] = match_list[1];
|
|
||||||
match_list[1] = NULL;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t i = 1;
|
|
||||||
int low = 4096; /* Count of max-matched characters. */
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
qsort (match_list + 1, matches, sizeof (char *), match_compare);
|
/* If only one match, just use that. */
|
||||||
|
|
||||||
|
if (match_list->len > 1)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
size_t low = 4096; /* Count of max-matched characters. */
|
||||||
|
|
||||||
|
g_ptr_array_sort (match_list, match_compare);
|
||||||
|
|
||||||
/* And compare each member of the list with
|
/* And compare each member of the list with
|
||||||
the next, finding out where they stop matching.
|
the next, finding out where they stop matching.
|
||||||
If we find two equal strings, we have to put one away... */
|
If we find two equal strings, we have to put one away... */
|
||||||
|
for (i = 0, j = 1; j < match_list->len;)
|
||||||
j = i + 1;
|
{
|
||||||
while (j < matches + 1)
|
char *si, *sj, *mi;
|
||||||
|
|
||||||
|
si = g_ptr_array_index (match_list, i);
|
||||||
|
sj = g_ptr_array_index (match_list, j);
|
||||||
|
mi = si;
|
||||||
|
|
||||||
|
while (si[0] != '\0' && sj[0] != '\0')
|
||||||
{
|
{
|
||||||
char *si, *sj;
|
|
||||||
char *ni, *nj;
|
char *ni, *nj;
|
||||||
|
|
||||||
for (si = match_list[i], sj = match_list[j]; si[0] != '\0' && sj[0] != '\0';)
|
|
||||||
{
|
|
||||||
|
|
||||||
ni = str_get_next_char (si);
|
ni = str_get_next_char (si);
|
||||||
nj = str_get_next_char (sj);
|
nj = str_get_next_char (sj);
|
||||||
|
|
||||||
if (ni - si != nj - sj)
|
if (ni - si != nj - sj || strncmp (si, sj, ni - si) != 0)
|
||||||
break;
|
|
||||||
if (strncmp (si, sj, ni - si) != 0)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
si = ni;
|
si = ni;
|
||||||
@ -768,24 +750,21 @@ completion_matches (const char *text, CompletionFunction entry_function, input_c
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (si[0] == '\0' && sj[0] == '\0')
|
if (si[0] == '\0' && sj[0] == '\0')
|
||||||
{ /* Two equal strings */
|
{
|
||||||
g_free (match_list[j]);
|
/* Two equal strings */
|
||||||
j++;
|
g_ptr_array_remove_index (match_list, j);
|
||||||
if (j > matches)
|
|
||||||
break;
|
|
||||||
continue; /* Look for a run of equal strings */
|
|
||||||
}
|
}
|
||||||
else if (low > si - match_list[i])
|
else
|
||||||
low = si - match_list[i];
|
{
|
||||||
if (i + 1 != j) /* So there's some gap */
|
low = MIN (low, (size_t) (si - mi));
|
||||||
match_list[i + 1] = match_list[j];
|
|
||||||
i++;
|
i++;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
matches = i;
|
|
||||||
match_list[matches + 1] = NULL;
|
|
||||||
match_list[0] = g_strndup (match_list[1], low);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string = g_ptr_array_index (match_list, 0);
|
||||||
|
g_ptr_array_insert (match_list, 0, g_strndup (string, low));
|
||||||
}
|
}
|
||||||
|
|
||||||
return match_list;
|
return match_list;
|
||||||
@ -886,10 +865,10 @@ try_complete_find_start_sign (try_complete_automation_state_t * state)
|
|||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static char **
|
static GPtrArray *
|
||||||
try_complete_all_possible (try_complete_automation_state_t * state, char *text, int *lc_start)
|
try_complete_all_possible (try_complete_automation_state_t * state, char *text, int *lc_start)
|
||||||
{
|
{
|
||||||
char **matches = NULL;
|
GPtrArray *matches = NULL;
|
||||||
|
|
||||||
if (state->in_command_position != 0)
|
if (state->in_command_position != 0)
|
||||||
{
|
{
|
||||||
@ -1201,32 +1180,37 @@ complete_engine (WInput * in, int what_to_do)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((what_to_do & DO_INSERTION) != 0
|
if ((what_to_do & DO_INSERTION) != 0
|
||||||
|| ((what_to_do & DO_QUERY) != 0 && in->completions[1] == NULL))
|
|| ((what_to_do & DO_QUERY) != 0 && in->completions->len == 1))
|
||||||
{
|
{
|
||||||
char *lc_complete = in->completions[0];
|
const char *lc_complete;
|
||||||
|
|
||||||
if (!insert_text (in, lc_complete, -1) || in->completions[1] != NULL)
|
lc_complete = g_ptr_array_index (in->completions, 0);
|
||||||
|
if (!insert_text (in, lc_complete, -1) || in->completions->len > 1)
|
||||||
tty_beep ();
|
tty_beep ();
|
||||||
else
|
else
|
||||||
input_complete_free (in);
|
input_complete_free (in);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((what_to_do & DO_QUERY) != 0 && in->completions != NULL && in->completions[1] != NULL)
|
if ((what_to_do & DO_QUERY) != 0 && in->completions != NULL && in->completions->len > 1)
|
||||||
{
|
{
|
||||||
int maxlen = 0, count = 0, i;
|
int maxlen = 0;
|
||||||
|
int i;
|
||||||
|
size_t k;
|
||||||
|
int count;
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
int start_x, start_y;
|
int start_x, start_y;
|
||||||
char **p, *q;
|
char *q;
|
||||||
WDialog *complete_dlg;
|
WDialog *complete_dlg;
|
||||||
WListbox *complete_list;
|
WListbox *complete_list;
|
||||||
|
|
||||||
for (p = in->completions + 1; *p != NULL; count++, p++)
|
for (k = 1; k < in->completions->len; k++)
|
||||||
{
|
{
|
||||||
i = str_term_width1 (*p);
|
q = g_ptr_array_index (in->completions, k);
|
||||||
if (i > maxlen)
|
i = str_term_width1 (q);
|
||||||
maxlen = i;
|
maxlen = MAX (maxlen, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
count = in->completions->len - 1;
|
||||||
start_x = WIDGET (in)->rect.x;
|
start_x = WIDGET (in)->rect.x;
|
||||||
start_y = WIDGET (in)->rect.y;
|
start_y = WIDGET (in)->rect.y;
|
||||||
if (start_y - 2 >= count)
|
if (start_y - 2 >= count)
|
||||||
@ -1262,8 +1246,11 @@ complete_engine (WInput * in, int what_to_do)
|
|||||||
complete_list = listbox_new (1, 1, h - 2, w - 2, FALSE, NULL);
|
complete_list = listbox_new (1, 1, h - 2, w - 2, FALSE, NULL);
|
||||||
group_add_widget (GROUP (complete_dlg), complete_list);
|
group_add_widget (GROUP (complete_dlg), complete_list);
|
||||||
|
|
||||||
for (p = in->completions + 1; *p != NULL; p++)
|
for (k = 1; k < in->completions->len; k++)
|
||||||
listbox_add_item (complete_list, LISTBOX_APPEND_AT_END, 0, *p, NULL, FALSE);
|
{
|
||||||
|
q = g_ptr_array_index (in->completions, k);
|
||||||
|
listbox_add_item (complete_list, LISTBOX_APPEND_AT_END, 0, q, NULL, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
i = dlg_run (complete_dlg);
|
i = dlg_run (complete_dlg);
|
||||||
q = NULL;
|
q = NULL;
|
||||||
@ -1290,11 +1277,11 @@ complete_engine (WInput * in, int what_to_do)
|
|||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/** Returns an array of matches, or NULL if none. */
|
/** Returns an array of matches, or NULL if none. */
|
||||||
char **
|
GPtrArray *
|
||||||
try_complete (char *text, int *lc_start, int *lc_end, input_complete_t flags)
|
try_complete (char *text, int *lc_start, int *lc_end, input_complete_t flags)
|
||||||
{
|
{
|
||||||
try_complete_automation_state_t state;
|
try_complete_automation_state_t state;
|
||||||
char **matches = NULL;
|
GPtrArray *matches = NULL;
|
||||||
|
|
||||||
memset (&state, 0, sizeof (state));
|
memset (&state, 0, sizeof (state));
|
||||||
state.flags = flags;
|
state.flags = flags;
|
||||||
@ -1371,16 +1358,16 @@ try_complete (char *text, int *lc_start, int *lc_end, input_complete_t flags)
|
|||||||
(flags & INPUT_COMPLETE_SHELL_ESC) == 0)
|
(flags & INPUT_COMPLETE_SHELL_ESC) == 0)
|
||||||
{
|
{
|
||||||
/* FIXME: HACK? INPUT_COMPLETE_SHELL_ESC is used only in command line. */
|
/* FIXME: HACK? INPUT_COMPLETE_SHELL_ESC is used only in command line. */
|
||||||
char **m;
|
size_t i;
|
||||||
|
|
||||||
for (m = matches; *m != NULL; m++)
|
for (i = 0; i < matches->len; i++)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
p = *m;
|
p = g_ptr_array_index (matches, i);
|
||||||
/* Escape only '?', '*', and '&' symbols as described in the
|
/* Escape only '?', '*', and '&' symbols as described in the
|
||||||
manual page (see a11995e12b88285e044f644904c306ed6c342ad0). */
|
manual page (see a11995e12b88285e044f644904c306ed6c342ad0). */
|
||||||
*m = str_escape (*m, -1, "?*&", TRUE);
|
g_ptr_array_index (matches, i) = str_escape (p, -1, "?*&", TRUE);
|
||||||
g_free (p);
|
g_free (p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1456,8 +1443,11 @@ input_complete (WInput * in)
|
|||||||
void
|
void
|
||||||
input_complete_free (WInput * in)
|
input_complete_free (WInput * in)
|
||||||
{
|
{
|
||||||
g_strfreev (in->completions);
|
if (in->completions != NULL)
|
||||||
|
{
|
||||||
|
g_ptr_array_free (in->completions, TRUE);
|
||||||
in->completions = NULL;
|
in->completions = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
void complete_engine_fill_completions (WInput * in);
|
void complete_engine_fill_completions (WInput * in);
|
||||||
char **try_complete (char *text, int *lc_start, int *lc_end, input_complete_t flags);
|
GPtrArray *try_complete (char *text, int *lc_start, int *lc_end, input_complete_t flags);
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
@ -47,10 +47,10 @@ static int try_complete__lc_end__captured;
|
|||||||
static input_complete_t try_complete__flags__captured;
|
static input_complete_t try_complete__flags__captured;
|
||||||
|
|
||||||
/* @ThenReturnValue */
|
/* @ThenReturnValue */
|
||||||
static char **try_complete__return_value;
|
static GPtrArray *try_complete__return_value;
|
||||||
|
|
||||||
/* @Mock */
|
/* @Mock */
|
||||||
char **
|
GPtrArray *
|
||||||
try_complete (char *text, int *lc_start, int *lc_end, input_complete_t flags)
|
try_complete (char *text, int *lc_start, int *lc_end, input_complete_t flags)
|
||||||
{
|
{
|
||||||
try_complete__text__captured = g_strdup (text);
|
try_complete__text__captured = g_strdup (text);
|
||||||
|
Loading…
Reference in New Issue
Block a user