summaryrefslogtreecommitdiff
path: root/src/edit.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2006-02-04 22:43:20 +0000
committerBram Moolenaar <Bram@vim.org>2006-02-04 22:43:20 +0000
commita65576059ffd417d98091029f400bc931b4251ca (patch)
treec62a52fa84d4e3bc8d5b374d4aad0499e87d8b56 /src/edit.c
parent41cabdadc280c26b06752be6606b0cc39845dafc (diff)
downloadvim-git-a65576059ffd417d98091029f400bc931b4251ca.tar.gz
updated for version 7.0193
Diffstat (limited to 'src/edit.c')
-rw-r--r--src/edit.c221
1 files changed, 181 insertions, 40 deletions
diff --git a/src/edit.c b/src/edit.c
index f38422926..ee574ad6c 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -87,6 +87,14 @@ static compl_T *compl_first_match = NULL;
static compl_T *compl_curr_match = NULL;
static compl_T *compl_shown_match = NULL;
+/* When "compl_leader" is not NULL only matches that start with this string
+ * are used. */
+static char_u *compl_leader = NULL;
+
+static int compl_used_match; /* Selected one of the matches. When
+ FALSE the match was edited or using
+ the longest common string. */
+
/* When the first completion is done "compl_started" is set. When it's
* FALSE the word to be completed must be located. */
static int compl_started = FALSE;
@@ -112,9 +120,12 @@ static int ins_compl_make_cyclic __ARGS((void));
static void ins_compl_upd_pum __ARGS((void));
static void ins_compl_del_pum __ARGS((void));
static int pum_wanted __ARGS((void));
+static int pum_two_or_more __ARGS((void));
static void ins_compl_dictionaries __ARGS((char_u *dict, char_u *pat, int dir, int flags, int thesaurus));
static void ins_compl_free __ARGS((void));
static void ins_compl_clear __ARGS((void));
+static int ins_compl_bs __ARGS((void));
+static void ins_compl_addleader __ARGS((int c));
static int ins_compl_prep __ARGS((int c));
static buf_T *ins_compl_next_buf __ARGS((buf_T *buf, int flag));
static int ins_compl_get_exp __ARGS((pos_T *ini, int dir));
@@ -673,13 +684,26 @@ edit(cmdchar, startln, count)
if (c == K_DOWN && pum_visible())
c = Ctrl_N;
- /* Prepare for or stop CTRL-X mode. This doesn't do completion, but
- * it does fix up the text when finishing completion. */
- if (c != K_IGNORE)
+ /* When using BS while the popup menu is wanted and still after the
+ * character where completion started: Change the subset of matches to
+ * what matches "compl_leader". */
+ if (compl_started && pum_wanted() && curwin->w_cursor.col > compl_col)
{
- if (ins_compl_prep(c))
+ if ((c == K_BS || c == Ctrl_H) && ins_compl_bs())
+ continue;
+
+ /* Editing the word. */
+ if (!compl_used_match && vim_isprintc(c))
+ {
+ ins_compl_addleader(c);
continue;
+ }
}
+
+ /* Prepare for or stop CTRL-X mode. This doesn't do completion, but
+ * it does fix up the text when finishing completion. */
+ if (c != K_IGNORE && ins_compl_prep(c))
+ continue;
#endif
/* CTRL-\ CTRL-N goes to Normal mode,
@@ -2159,9 +2183,6 @@ ins_compl_del_pum()
static int
pum_wanted()
{
- compl_T *compl;
- int i;
-
/* 'completeopt' must contain "menu" */
if (*p_cot == NUL)
return FALSE;
@@ -2173,6 +2194,17 @@ pum_wanted()
#endif
)
return FALSE;
+ return TRUE;
+}
+
+/*
+ * Return TRUE if there are two or more matches to be shown in the popup menu.
+ */
+ static int
+pum_two_or_more()
+{
+ compl_T *compl;
+ int i;
/* Don't display the popup menu if there are no matches or there is only
* one (ignoring the original text). */
@@ -2199,8 +2231,9 @@ ins_compl_show_pum()
int i;
int cur = -1;
colnr_T col;
+ int lead_len = 0;
- if (!pum_wanted())
+ if (!pum_wanted() || !pum_two_or_more())
return;
/* Update the screen before drawing the popup menu over it. */
@@ -2211,12 +2244,18 @@ ins_compl_show_pum()
/* Need to build the popup menu list. */
compl_match_arraysize = 0;
compl = compl_first_match;
+ if (compl_leader != NULL)
+ lead_len = STRLEN(compl_leader);
do
{
- if ((compl->cp_flags & ORIGINAL_TEXT) == 0)
+ if ((compl->cp_flags & ORIGINAL_TEXT) == 0
+ && (compl_leader == NULL
+ || STRNCMP(compl->cp_str, compl_leader, lead_len) == 0))
++compl_match_arraysize;
compl = compl->cp_next;
} while (compl != NULL && compl != compl_first_match);
+ if (compl_match_arraysize == 0)
+ return;
compl_match_array = (char_u **)alloc((unsigned)(sizeof(char_u **)
* compl_match_arraysize));
if (compl_match_array != NULL)
@@ -2225,7 +2264,10 @@ ins_compl_show_pum()
compl = compl_first_match;
do
{
- if ((compl->cp_flags & ORIGINAL_TEXT) == 0)
+ if ((compl->cp_flags & ORIGINAL_TEXT) == 0
+ && (compl_leader == NULL
+ || STRNCMP(compl->cp_str, compl_leader,
+ lead_len) == 0))
{
if (compl == compl_shown_match)
cur = i;
@@ -2238,21 +2280,10 @@ ins_compl_show_pum()
else
{
/* popup menu already exists, only need to find the current item.*/
- i = 0;
- compl = compl_first_match;
- do
- {
- if ((compl->cp_flags & ORIGINAL_TEXT) == 0)
- {
- if (compl == compl_shown_match)
- {
- cur = i;
- break;
- }
- ++i;
- }
- compl = compl->cp_next;
- } while (compl != NULL && compl != compl_first_match);
+ for (i = 0; i < compl_match_arraysize; ++i)
+ if (compl_match_array[i] == compl_shown_match->cp_str)
+ break;
+ cur = i;
}
if (compl_match_array != NULL)
@@ -2472,6 +2503,8 @@ ins_compl_free()
vim_free(compl_pattern);
compl_pattern = NULL;
+ vim_free(compl_leader);
+ compl_leader = NULL;
if (compl_first_match == NULL)
return;
@@ -2501,11 +2534,102 @@ ins_compl_clear()
compl_matches = 0;
vim_free(compl_pattern);
compl_pattern = NULL;
+ vim_free(compl_leader);
+ compl_leader = NULL;
save_sm = -1;
edit_submode_extra = NULL;
}
/*
+ * Delete one character before the cursor and make a subset of the matches
+ * that match now.
+ * Returns TRUE if the work is done and another char to be got from the user.
+ */
+ static int
+ins_compl_bs()
+{
+ char_u *line;
+ char_u *p;
+
+ if (curwin->w_cursor.col <= compl_col + compl_length)
+ {
+ /* Deleted more than what was used to find matches, need to look for
+ * matches all over again. */
+ ins_compl_free();
+ compl_started = FALSE;
+ compl_matches = 0;
+ }
+
+ line = ml_get_curline();
+ p = line + curwin->w_cursor.col;
+ mb_ptr_back(line, p);
+
+ vim_free(compl_leader);
+ compl_leader = vim_strnsave(line + compl_col, (p - line) - compl_col);
+ if (compl_leader != NULL)
+ {
+ ins_compl_del_pum();
+ ins_compl_delete();
+ ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
+
+ if (!compl_started)
+ {
+ /* Matches were cleared, need to search for them now. */
+ if (ins_complete(Ctrl_N) == FAIL)
+ compl_cont_status = 0;
+ else
+ {
+ /* Remove the completed word again. */
+ ins_compl_delete();
+ ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
+ }
+ }
+
+ /* Show the popup menu with a different set of matches. */
+ ins_compl_show_pum();
+ compl_used_match = FALSE;
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Append one character to the match leader. May reduce the number of
+ * matches.
+ */
+ static void
+ins_compl_addleader(c)
+ int c;
+{
+#ifdef FEAT_MBYTE
+ int cc;
+
+ if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
+ {
+ char_u buf[MB_MAXBYTES + 1];
+
+ (*mb_char2bytes)(c, buf);
+ buf[cc] = NUL;
+ ins_char_bytes(buf, cc);
+ }
+ else
+#endif
+ ins_char(c);
+
+ vim_free(compl_leader);
+ compl_leader = vim_strnsave(ml_get_curline() + compl_col,
+ curwin->w_cursor.col - compl_col);
+ if (compl_leader != NULL)
+ {
+ /* Show the popup menu with a different set of matches. */
+ ins_compl_del_pum();
+ ins_compl_show_pum();
+ compl_used_match = FALSE;
+ }
+}
+
+/*
* Prepare for Insert mode completion, or stop it.
* Called just after typing a character in Insert mode.
* Returns TRUE when the character is not to be inserted;
@@ -3290,6 +3414,7 @@ ins_compl_delete()
ins_compl_insert()
{
ins_bytes(compl_shown_match->cp_str + curwin->w_cursor.col - compl_col);
+ compl_used_match = TRUE;
}
/*
@@ -3317,6 +3442,8 @@ ins_compl_next(allow_get_expansion, count)
int num_matches = -1;
int i;
int todo = count;
+ compl_T *found_compl = NULL;
+ int found_end = FALSE;
if (allow_get_expansion)
{
@@ -3332,32 +3459,46 @@ ins_compl_next(allow_get_expansion, count)
if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL)
{
compl_shown_match = compl_shown_match->cp_next;
- if (compl_shown_match->cp_next != NULL
- && compl_shown_match->cp_next == compl_first_match)
- break;
+ found_end = (compl_first_match != NULL
+ && (compl_shown_match->cp_next == compl_first_match
+ || compl_shown_match == compl_first_match));
}
else if (compl_shows_dir == BACKWARD
&& compl_shown_match->cp_prev != NULL)
{
+ found_end = (compl_shown_match == compl_first_match);
compl_shown_match = compl_shown_match->cp_prev;
- if (compl_shown_match == compl_first_match)
- break;
+ found_end |= (compl_shown_match == compl_first_match);
}
else
{
compl_pending = TRUE;
- if (allow_get_expansion)
+ if (!allow_get_expansion)
+ return -1;
+
+ num_matches = ins_compl_get_exp(&compl_startpos, compl_direction);
+ if (compl_pending && compl_direction == compl_shows_dir)
+ compl_shown_match = compl_curr_match;
+ found_end = FALSE;
+ }
+ if ((compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0
+ && compl_leader != NULL
+ && STRNCMP(compl_shown_match->cp_str,
+ compl_leader, STRLEN(compl_leader)) != 0)
+ ++todo;
+ else
+ /* Remember a matching item. */
+ found_compl = compl_shown_match;
+
+ /* Stop at the end of the list when we found a usable match. */
+ if (found_end)
+ {
+ if (found_compl != NULL)
{
- num_matches = ins_compl_get_exp(&compl_startpos,
- compl_direction);
- if (compl_pending)
- {
- if (compl_direction == compl_shows_dir)
- compl_shown_match = compl_curr_match;
- }
+ compl_shown_match = found_compl;
+ break;
}
- else
- return -1;
+ todo = 1; /* use first usable match after wrapping around */
}
}