Add noinsert and noselect features in completeopt #2564

Backported from vim_dev:
https://groups.google.com/forum/#!searchin/vim_dev/completeopt/vim_dev/tVsk0pdOGvs/fCzBbPkA4w0J

Use case:
https://github.com/Shougo/neocomplcache.vim/issues/426

Reviewed-by: Felipe Morales <hel.sheep@gmail.com>
Reviewed-by: Scott Prager <splinterofchaos@gmail.com>
Reviewed-by: Michael Reed <m.reed@mykolab.com>
This commit is contained in:
Shougo Matsushita 2015-05-02 09:44:54 +09:00 committed by Michael Reed
parent 2271b746d7
commit e6c62c80ef
4 changed files with 70 additions and 13 deletions

View File

@ -1609,6 +1609,14 @@ A jump table for the options with a short description can be found at |Q_op|.
completion in the preview window. Only works in completion in the preview window. Only works in
combination with "menu" or "menuone". combination with "menu" or "menuone".
noinsert Do not insert any text for a match until the user selects
a match from the menu. Only works in combination with
"menu" or "menuone". No effect if "longest" is present.
noselect Do not select a match in the menu, force the user to
select one from the menu. Only works in combination with
"menu" or "menuone".
*'concealcursor'* *'cocu'* *'concealcursor'* *'cocu'*
'concealcursor' 'cocu' string (default: "") 'concealcursor' 'cocu' string (default: "")

View File

@ -154,6 +154,11 @@ static char_u *compl_leader = NULL;
static int compl_get_longest = FALSE; /* put longest common string static int compl_get_longest = FALSE; /* put longest common string
in compl_leader */ in compl_leader */
static int compl_no_insert = FALSE; /* FALSE: select & insert
TRUE: noinsert */
static int compl_no_select = FALSE; /* FALSE: select & insert
TRUE: noselect */
static int compl_used_match; /* Selected one of the matches. When static int compl_used_match; /* Selected one of the matches. When
FALSE the match was edited or using FALSE the match was edited or using
the longest common string. */ the longest common string. */
@ -2972,8 +2977,19 @@ static int ins_compl_prep(int c)
/* Set "compl_get_longest" when finding the first matches. */ /* Set "compl_get_longest" when finding the first matches. */
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
|| (ctrl_x_mode == 0 && !compl_started)) { || (ctrl_x_mode == 0 && !compl_started)) {
compl_get_longest = (vim_strchr(p_cot, 'l') != NULL); compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
compl_used_match = TRUE; compl_used_match = TRUE;
if (strstr((char *)p_cot, "noselect") != NULL) {
compl_no_insert = FALSE;
compl_no_select = TRUE;
} else if (strstr((char *)p_cot, "noinsert") != NULL) {
compl_no_insert = TRUE;
compl_no_select = FALSE;
} else {
compl_no_insert = FALSE;
compl_no_select = FALSE;
}
} }
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET) { if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET) {
@ -3875,6 +3891,7 @@ ins_compl_next (
compl_T *found_compl = NULL; compl_T *found_compl = NULL;
int found_end = FALSE; int found_end = FALSE;
int advance; int advance;
int started = compl_started;
/* When user complete function return -1 for findstart which is next /* When user complete function return -1 for findstart which is next
* time of 'always', compl_shown_match become NULL. */ * time of 'always', compl_shown_match become NULL. */
@ -3945,7 +3962,7 @@ ins_compl_next (
return -1; return -1;
} }
if (advance) { if (!compl_no_select && advance) {
if (compl_shows_dir == BACKWARD) if (compl_shows_dir == BACKWARD)
--compl_pending; --compl_pending;
else else
@ -3990,13 +4007,18 @@ ins_compl_next (
} }
/* Insert the text of the new completion, or the compl_leader. */ /* Insert the text of the new completion, or the compl_leader. */
if (insert_match) { if (compl_no_insert && !started) {
if (!compl_get_longest || compl_used_match) ins_bytes(compl_orig_text + ins_compl_len());
ins_compl_insert();
else
ins_bytes(compl_leader + ins_compl_len());
} else
compl_used_match = FALSE; compl_used_match = FALSE;
} else if (insert_match) {
if (!compl_get_longest || compl_used_match) {
ins_compl_insert();
} else {
ins_bytes(compl_leader + ins_compl_len());
}
} else {
compl_used_match = FALSE;
}
if (!allow_get_expansion) { if (!allow_get_expansion) {
/* may undisplay the popup menu first */ /* may undisplay the popup menu first */
@ -4015,7 +4037,11 @@ ins_compl_next (
/* Enter will select a match when the match wasn't inserted and the popup /* Enter will select a match when the match wasn't inserted and the popup
* menu is visible. */ * menu is visible. */
compl_enter_selects = !insert_match && compl_match_array != NULL; if (compl_no_insert && !started) {
compl_enter_selects = TRUE;
} else {
compl_enter_selects = !insert_match && compl_match_array != NULL;
}
/* /*
* Show the file name for the match (if any) * Show the file name for the match (if any)
@ -4082,7 +4108,7 @@ void ins_compl_check_keys(int frequency)
} }
} }
} }
if (compl_pending != 0 && !got_int) { if (compl_pending != 0 && !got_int && !compl_no_insert) {
int todo = compl_pending > 0 ? compl_pending : -compl_pending; int todo = compl_pending > 0 ? compl_pending : -compl_pending;
compl_pending = 0; compl_pending = 0;

View File

@ -1705,7 +1705,8 @@ static char *(p_fdm_values[]) = {"manual", "expr", "marker", "indent", "syntax",
"diff", "diff",
NULL}; NULL};
static char *(p_fcl_values[]) = {"all", NULL}; static char *(p_fcl_values[]) = {"all", NULL};
static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", NULL}; static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview",
"noinsert", "noselect", NULL};
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "option.c.generated.h" # include "option.c.generated.h"

View File

@ -3,12 +3,12 @@ local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq
local execute, source = helpers.execute, helpers.source local execute, source = helpers.execute, helpers.source
describe("completion", function() describe('completion', function()
before_each(function() before_each(function()
clear() clear()
end) end)
describe("v:completed_item", function() describe('v:completed_item', function()
it('returns expected dict in normal completion', function() it('returns expected dict in normal completion', function()
feed('ifoo<ESC>o<C-x><C-n><ESC>') feed('ifoo<ESC>o<C-x><C-n><ESC>')
eq('foo', eval('getline(2)')) eq('foo', eval('getline(2)'))
@ -53,4 +53,26 @@ describe("completion", function()
eval('v:completed_item')) eval('v:completed_item'))
end) end)
end) end)
describe('completeopt', function()
it('inserts the first candidate if default', function()
execute('set completeopt+=menuone')
feed('ifoo<ESC>o<C-x><C-n>bar<ESC>')
eq('foobar', eval('getline(2)'))
end)
it('selects the first candidate if noinsert', function()
execute('set completeopt+=menuone,noinsert')
feed('ifoo<ESC>o<C-x><C-n><C-y><ESC>')
eq('foo', eval('getline(2)'))
end)
it('does not insert the first candidate if noselect', function()
execute('set completeopt+=menuone,noselect')
feed('ifoo<ESC>o<C-x><C-n>bar<ESC>')
eq('bar', eval('getline(2)'))
end)
it('does not select/insert the first candidate if noselect and noinsert', function()
execute('set completeopt+=menuone,noselect,noinsert')
feed('ifoo<ESC>o<C-x><C-n><ESC>')
eq('', eval('getline(2)'))
end)
end)
end) end)