1
0
mirror of https://github.com/MidnightCommander/mc synced 2025-02-27 12:44:11 +03:00

editor: word completion: refactoring.

(edit_collect_completions): return GQueue. Use GQueue inside.
Do not return an empty queue, create it if needed only.

(edit_complete_word_cmd): Use GQueue inside. Ged rid of limitation
of completions count. Rename variable.

(editcmd_dialog_completion_show): take GQueue. Rename and reorder
arguments.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
Andrew Borodin 2020-12-31 17:08:08 +03:00
parent feca634073
commit 29720d04ab
4 changed files with 127 additions and 112 deletions

@ -96,8 +96,6 @@ gboolean option_drop_selection_on_copy = TRUE;
#define TEMP_BUF_LEN 1024
#define MAX_WORD_COMPLETIONS 100 /* in listbox */
/*** file scope type declarations ****************************************************************/
typedef struct
@ -1211,18 +1209,24 @@ edit_collect_completions_get_current_word (edit_search_status_msg_t * esm, mc_se
return temp;
}
/* --------------------------------------------------------------------------------------------- */
static void
edit_completion_string_free (gpointer data)
{
g_string_free ((GString *) data, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
/** collect the possible completions */
static gsize
static GQueue *
edit_collect_completions (WEdit * edit, off_t word_start, gsize word_len,
char *match_expr, GString ** compl, gsize * num)
const char *match_expr, int *max_width)
{
GQueue *compl = NULL;
gsize len = 0;
gsize max_len = 0;
gsize i;
int skip;
GString *temp;
GString *temp = NULL;
mc_search_t *srch;
off_t last_byte, start = -1;
GString *current_word;
@ -1235,11 +1239,11 @@ edit_collect_completions (WEdit * edit, off_t word_start, gsize word_len,
srch = mc_search_new (match_expr, NULL);
#endif
if (srch == NULL)
return 0;
return NULL;
entire_file =
mc_config_get_bool (mc_global.main_config, CONFIG_APP_SECTION,
"editor_wordcompletion_collect_entire_file", 0);
"editor_wordcompletion_collect_entire_file", FALSE);
last_byte = entire_file ? edit->buffer.size : word_start;
@ -1257,26 +1261,35 @@ edit_collect_completions (WEdit * edit, off_t word_start, gsize word_len,
current_word = edit_collect_completions_get_current_word (&esm, srch, word_start);
temp = g_string_new ("");
*max_width = 0;
/* collect max MAX_WORD_COMPLETIONS completions */
/* collect completions */
while (mc_search_run (srch, (void *) &esm, start + 1, last_byte, &len))
{
g_string_set_size (temp, 0);
gsize i;
int width;
if (temp == NULL)
temp = g_string_sized_new (8);
else
g_string_set_size (temp, 0);
start = srch->normal_offset;
/* add matched completion if not yet added */
for (i = 0; i < len; i++)
{
skip = edit_buffer_get_byte (&edit->buffer, start + i);
if (isspace (skip))
int ch;
ch = edit_buffer_get_byte (&edit->buffer, start + i);
if (isspace (ch))
continue;
/* skip current word */
if (start + (off_t) i == word_start)
break;
g_string_append_c (temp, skip);
g_string_append_c (temp, ch);
}
if (temp->len == 0)
@ -1285,60 +1298,65 @@ edit_collect_completions (WEdit * edit, off_t word_start, gsize word_len,
if (current_word != NULL && g_string_equal (current_word, temp))
continue;
skip = 0;
for (i = 0; i < *num; i++)
if (compl == NULL)
compl = g_queue_new ();
else
{
if (strncmp
((char *) &compl[i]->str[word_len],
(char *) &temp->str[word_len], MAX (len, compl[i]->len) - word_len) == 0)
GList *l;
for (l = g_queue_peek_head_link (compl); l != NULL; l = g_list_next (l))
{
GString *this = compl[i];
GString *s = (GString *) l->data;
for (++i; i < *num; i++)
compl[i - 1] = compl[i];
compl[*num - 1] = this;
/* skip if already added */
if (strncmp (s->str + word_len, temp->str + word_len,
MAX (len, s->len) - word_len) == 0)
break;
}
skip = 1;
break; /* skip it, already added */
if (l != NULL)
{
if (l != g_queue_peek_tail_link (compl))
{
/* move to the end */
g_queue_unlink (compl, l);
g_queue_push_tail_link (compl, l);
}
continue;
}
}
if (skip != 0)
continue;
if (*num == MAX_WORD_COMPLETIONS)
{
g_string_free (compl[0], TRUE);
for (i = 1; i < *num; i++)
compl[i - 1] = compl[i];
(*num)--;
}
#ifdef HAVE_CHARSET
{
GString *recoded;
recoded = str_convert_to_display (temp->str);
if (recoded->len != 0)
g_string_assign (temp, recoded->str);
mc_g_string_copy (temp, recoded);
g_string_free (recoded, TRUE);
}
#endif
compl[(*num)++] = g_string_new_len (temp->str, temp->len);
g_queue_push_tail (compl, temp);
start += len;
/* note the maximal length needed for the completion dialog */
if (len > max_len)
max_len = len;
width = str_term_width1 (temp->str);
*max_width = MAX (*max_width, width);
temp = NULL;
}
status_msg_deinit (STATUS_MSG (&esm));
mc_search_free (srch);
g_string_free (temp, TRUE);
if (temp != NULL)
g_string_free (temp, TRUE);
if (current_word != NULL)
g_string_free (current_word, TRUE);
return max_len;
return compl;
}
/* --------------------------------------------------------------------------------------------- */
@ -3339,10 +3357,12 @@ edit_mail_dialog (WEdit * edit)
void
edit_complete_word_cmd (WEdit * edit)
{
gsize i, max_len, word_len = 0, num_compl = 0;
off_t word_start = 0;
gsize word_len = 0;
GString *match_expr;
GString *compl[MAX_WORD_COMPLETIONS]; /* completions */
gsize i;
GQueue *compl; /* completions: list of GString* */
int max_width;
/* search start of word to be completed */
if (!edit_find_word_start (&edit->buffer, &word_start, &word_len))
@ -3356,43 +3376,39 @@ edit_complete_word_cmd (WEdit * edit)
g_string_append (match_expr,
"[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+");
/* collect the possible completions */
/* start search from begin to end of file */
max_len =
edit_collect_completions (edit, word_start, word_len, match_expr->str, (GString **) & compl,
&num_compl);
/* collect possible completions */
compl = edit_collect_completions (edit, word_start, word_len, match_expr->str, &max_width);
if (num_compl > 0)
g_string_free (match_expr, TRUE);
if (compl == NULL)
return;
if (g_queue_get_length (compl) == 1)
{
/* insert completed word if there is only one match */
if (num_compl == 1)
edit_complete_word_insert_recoded_completion (edit, compl[0]->str, word_len);
GString *curr_compl;
curr_compl = (GString *) g_queue_peek_head (compl);
edit_complete_word_insert_recoded_completion (edit, curr_compl->str, word_len);
}
else
{
/* more than one possible completion => ask the user */
else
char *curr_compl;
/* let the user select the preferred completion */
curr_compl = editcmd_dialog_completion_show (edit, compl, max_width);
if (curr_compl != NULL)
{
char *curr_compl;
/* !!! usually only a beep is expected and when <ALT-TAB> is !!! */
/* !!! pressed again the selection dialog pops up, but that !!! */
/* !!! seems to require a further internal state !!! */
/*tty_beep (); */
/* let the user select the preferred completion */
curr_compl = editcmd_dialog_completion_show (edit, max_len,
(GString **) & compl, num_compl);
if (curr_compl != NULL)
{
edit_complete_word_insert_recoded_completion (edit, curr_compl, word_len);
g_free (curr_compl);
}
edit_complete_word_insert_recoded_completion (edit, curr_compl, word_len);
g_free (curr_compl);
}
}
g_string_free (match_expr, TRUE);
/* release memory before return */
for (i = 0; i < num_compl; i++)
g_string_free (compl[i], TRUE);
g_queue_free_full (compl, edit_completion_string_free);
}
/* --------------------------------------------------------------------------------------------- */

@ -345,19 +345,20 @@ editcmd_dialog_raw_key_query (const char *heading, const char *query, gboolean c
/* let the user select its preferred completion */
char *
editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** compl, int num_compl)
editcmd_dialog_completion_show (const WEdit * edit, GQueue * compl, int max_width)
{
const Widget *we = CONST_WIDGET (edit);
int start_x, start_y, offset, i;
int start_x, start_y, offset;
char *curr = NULL;
WDialog *compl_dlg;
WListbox *compl_list;
int compl_dlg_h; /* completion dialog height */
int compl_dlg_w; /* completion dialog width */
GList *i;
/* calculate the dialog metrics */
compl_dlg_h = num_compl + 2;
compl_dlg_w = max_len + 4;
compl_dlg_h = g_queue_get_length (compl) + 2;
compl_dlg_w = max_width + 4;
start_x = we->x + edit->curs_col + edit->start_col + EDIT_TEXT_HORIZONTAL_OFFSET +
(edit->fullscreen ? 0 : 1) + option_line_state_width;
start_y = we->y + edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen ? 0 : 1) + 1;
@ -386,14 +387,13 @@ editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** comp
/* create the listbox */
compl_list = listbox_new (1, 1, compl_dlg_h - 2, compl_dlg_w - 2, FALSE, NULL);
/* add the dialog */
group_add_widget (GROUP (compl_dlg), compl_list);
/* fill the listbox with the completions */
for (i = num_compl - 1; i >= 0; i--) /* reverse order */
listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0, (char *) compl[i]->str, NULL,
/* fill the listbox with the completions in the reverse order */
for (i = g_queue_peek_tail_link (compl); i != NULL; i = g_list_previous (i))
listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0, ((GString *) i->data)->str, NULL,
FALSE);
group_add_widget (GROUP (compl_dlg), compl_list);
/* pop up the dialog and apply the chosen completion */
if (dlg_run (compl_dlg) == B_ENTER)
{

@ -25,8 +25,7 @@ gboolean editcmd_dialog_search_show (WEdit * edit);
int editcmd_dialog_raw_key_query (const char *heading, const char *query, gboolean cancel);
char *editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** compl,
int num_compl);
char *editcmd_dialog_completion_show (const WEdit * edit, GQueue * compl, int max_width);
void editcmd_dialog_select_definition_show (WEdit *, char *, int, int, struct etags_hash_struct *,
int);

@ -6,6 +6,7 @@
Written by:
Slava Zanko <slavazanko@gmail.com>, 2013
Andrew Borodin <aborodin@vmail.ru>, 2021
This file is part of the Midnight Commander.
@ -89,32 +90,33 @@ edit_load_macro_cmd (WEdit * _edit)
/* @CapturedValue */
static const WEdit *editcmd_dialog_completion_show__edit;
/* @CapturedValue */
static int editcmd_dialog_completion_show__max_len;
static int editcmd_dialog_completion_show__max_width;
/* @CapturedValue */
static GString **editcmd_dialog_completion_show__compl;
/* @CapturedValue */
static int editcmd_dialog_completion_show__num_compl;
static GQueue *editcmd_dialog_completion_show__compl;
/* @ThenReturnValue */
static char *editcmd_dialog_completion_show__return_value;
/* @Mock */
char *
editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** compl, int num_compl)
editcmd_dialog_completion_show (const WEdit * edit, GQueue * compl, int max_width)
{
editcmd_dialog_completion_show__edit = edit;
editcmd_dialog_completion_show__max_len = max_len;
editcmd_dialog_completion_show__num_compl = num_compl;
editcmd_dialog_completion_show__max_width = max_width;
{
int iterator;
GList *i;
editcmd_dialog_completion_show__compl = g_new0 (GString *, num_compl);
editcmd_dialog_completion_show__compl = g_queue_new ();
for (iterator = 0; iterator < editcmd_dialog_completion_show__num_compl; iterator++)
editcmd_dialog_completion_show__compl[iterator] =
g_string_new_len (compl[iterator]->str, compl[iterator]->len);
for (i = g_queue_peek_tail_link (compl); i != NULL; i = g_list_previous (i))
{
GString *s = (GString *) i->data;
g_queue_push_tail (editcmd_dialog_completion_show__compl,
g_string_new_len (s->str, s->len));
}
}
return editcmd_dialog_completion_show__return_value;
@ -124,27 +126,25 @@ static void
editcmd_dialog_completion_show__init (void)
{
editcmd_dialog_completion_show__edit = NULL;
editcmd_dialog_completion_show__max_len = 0;
editcmd_dialog_completion_show__max_width = 0;
editcmd_dialog_completion_show__compl = NULL;
editcmd_dialog_completion_show__num_compl = 0;
editcmd_dialog_completion_show__return_value = NULL;
}
static void
editcmd_dialog_completion_show__string_free (gpointer data)
{
g_string_free ((GString *) data, TRUE);
}
static void
editcmd_dialog_completion_show__deinit (void)
{
if (editcmd_dialog_completion_show__compl != NULL)
{
int iterator;
for (iterator = 0; iterator < editcmd_dialog_completion_show__num_compl; iterator++)
g_string_free (editcmd_dialog_completion_show__compl[iterator], TRUE);
g_free (editcmd_dialog_completion_show__compl);
}
g_queue_free_full (editcmd_dialog_completion_show__compl,
editcmd_dialog_completion_show__string_free);
}
/* --------------------------------------------------------------------------------------------- */
/* @Before */
@ -201,7 +201,7 @@ static const struct test_autocomplete_ds
int input_display_codepage_id;
const char *input_completed_word;
int expected_max_len;
int expected_max_width;
int expected_compl_word_count;
int input_completed_word_start_pos;
const char *expected_completed_word;
@ -259,9 +259,9 @@ START_PARAMETRIZED_TEST (test_autocomplete, test_autocomplete_ds)
/* then */
mctest_assert_ptr_eq (editcmd_dialog_completion_show__edit, test_edit);
mctest_assert_int_eq (editcmd_dialog_completion_show__num_compl,
mctest_assert_int_eq (g_queue_get_length (editcmd_dialog_completion_show__compl),
data->expected_compl_word_count);
mctest_assert_int_eq (editcmd_dialog_completion_show__max_len, data->expected_max_len);
mctest_assert_int_eq (editcmd_dialog_completion_show__max_width, data->expected_max_width);
{
off_t i = 0;