mirror of
https://github.com/neovim/neovim.git
synced 2025-10-03 16:36:30 +00:00
vim-patch:9.1.1797: completion: autocompletion can be improved
Problem: completion: autocompletion can be improved
Solution: Add support for "longest" and "preinsert" in 'autocomplete';
add preinserted() (Girish Palya)
* Add support for "longest" in 'completeopt' when 'autocomplete'
is enabled. (Note: the cursor position does not change automatically
when 'autocomplete' is enabled.)
* Add support for "preinsert" when 'autocomplete' is enabled. Ensure
"preinsert" works the same with and without 'autocomplete'
* introduce the preinserted() Vim script function, useful for defining
custom key mappings.
fixes: vim/vim#18314
closes: vim/vim#18387
c05335082a
Co-authored-by: Girish Palya <girishji@gmail.com>
This commit is contained in:
@@ -1638,11 +1638,22 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
to gather more alternatives for your candidate list,
|
to gather more alternatives for your candidate list,
|
||||||
see 'completefuzzycollect'.
|
see 'completefuzzycollect'.
|
||||||
|
|
||||||
longest Only insert the longest common text of the matches. If
|
longest
|
||||||
the menu is displayed you can use CTRL-L to add more
|
When 'autocomplete' is not active, only the longest
|
||||||
characters. Whether case is ignored depends on the kind
|
common prefix of the matches is inserted. If the popup
|
||||||
of completion. For buffer text the 'ignorecase' option is
|
menu is displayed, you can use CTRL-L to add more
|
||||||
used.
|
characters. Whether case is ignored depends on the type
|
||||||
|
of completion. For buffer text the 'ignorecase' option
|
||||||
|
applies.
|
||||||
|
|
||||||
|
When 'autocomplete' is active and no completion item is
|
||||||
|
selected, the longest common prefix of the matches is
|
||||||
|
inserted after the cursor. The prefix is taken either
|
||||||
|
from all displayed items or only from items in the current
|
||||||
|
buffer. The inserted text is highlighted with
|
||||||
|
|hl-PreInsert|, and the cursor position does not change
|
||||||
|
(similar to `"preinsert"`). Press CTRL-Y to accept.
|
||||||
|
See also |preinserted()|.
|
||||||
|
|
||||||
menu Use a popup menu to show the possible completions. The
|
menu Use a popup menu to show the possible completions. The
|
||||||
menu is only shown when there is more than one match and
|
menu is only shown when there is more than one match and
|
||||||
@@ -1675,22 +1686,21 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
with "menu" or "menuone". Overrides "preview".
|
with "menu" or "menuone". Overrides "preview".
|
||||||
|
|
||||||
preinsert
|
preinsert
|
||||||
When 'autocomplete' is not active, inserts the part of the
|
Inserts the text of the first completion candidate
|
||||||
first candidate word beyond the current completion leader,
|
beyond the current leader, highlighted with |hl-PreInsert|.
|
||||||
highlighted with |hl-PreInsert|. The cursor doesn't move.
|
The cursor does not move.
|
||||||
Requires "fuzzy" unset and "menuone" in 'completeopt'.
|
Requires "fuzzy" to be unset, and either "menuone" in
|
||||||
|
'completeopt' or 'autocomplete' enabled. When
|
||||||
When 'autocomplete' is active, inserts the longest common
|
'autocomplete' is enabled, this does not work if
|
||||||
prefix of matches (from all shown items or from the
|
'ignorecase' is set without 'infercase'.
|
||||||
current buffer items). This occurs only when no menu item
|
See also |preinserted()|.
|
||||||
is selected. Press CTRL-Y to accept.
|
|
||||||
|
|
||||||
preview Show extra information about the currently selected
|
preview Show extra information about the currently selected
|
||||||
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".
|
||||||
|
|
||||||
Only "fuzzy", "popup", "preinsert" and "preview" have an effect when
|
Only "fuzzy", "longest", "popup", "preinsert" and "preview" have an
|
||||||
'autocomplete' is enabled.
|
effect when 'autocomplete' is enabled.
|
||||||
|
|
||||||
This option does not apply to |cmdline-completion|. See 'wildoptions'
|
This option does not apply to |cmdline-completion|. See 'wildoptions'
|
||||||
for that.
|
for that.
|
||||||
|
@@ -940,6 +940,7 @@ Insert mode completion: *completion-functions*
|
|||||||
complete_info() get current completion information
|
complete_info() get current completion information
|
||||||
complete_match() get insert completion start match col and
|
complete_match() get insert completion start match col and
|
||||||
trigger text
|
trigger text
|
||||||
|
preinserted() check if text is inserted after cursor
|
||||||
pumvisible() check if the popup menu is displayed
|
pumvisible() check if the popup menu is displayed
|
||||||
pum_getpos() position and size of popup menu if visible
|
pum_getpos() position and size of popup menu if visible
|
||||||
|
|
||||||
|
@@ -7232,6 +7232,15 @@ pow({x}, {y}) *pow()*
|
|||||||
Return: ~
|
Return: ~
|
||||||
(`number`)
|
(`number`)
|
||||||
|
|
||||||
|
preinserted() *preinserted()*
|
||||||
|
Returns non-zero if text has been inserted after the cursor
|
||||||
|
because "preinsert" is present in 'completeopt', or if
|
||||||
|
"longest" is present in 'completeopt' while 'autocomplete'
|
||||||
|
is enabled. Otherwise returns zero.
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
(`number`)
|
||||||
|
|
||||||
prevnonblank({lnum}) *prevnonblank()*
|
prevnonblank({lnum}) *prevnonblank()*
|
||||||
Return the line number of the first line at or above {lnum}
|
Return the line number of the first line at or above {lnum}
|
||||||
that is not blank. Example: >vim
|
that is not blank. Example: >vim
|
||||||
|
42
runtime/lua/vim/_meta/options.lua
generated
42
runtime/lua/vim/_meta/options.lua
generated
@@ -1183,11 +1183,22 @@ vim.go.cia = vim.go.completeitemalign
|
|||||||
--- to gather more alternatives for your candidate list,
|
--- to gather more alternatives for your candidate list,
|
||||||
--- see 'completefuzzycollect'.
|
--- see 'completefuzzycollect'.
|
||||||
---
|
---
|
||||||
--- longest Only insert the longest common text of the matches. If
|
--- longest
|
||||||
--- the menu is displayed you can use CTRL-L to add more
|
--- When 'autocomplete' is not active, only the longest
|
||||||
--- characters. Whether case is ignored depends on the kind
|
--- common prefix of the matches is inserted. If the popup
|
||||||
--- of completion. For buffer text the 'ignorecase' option is
|
--- menu is displayed, you can use CTRL-L to add more
|
||||||
--- used.
|
--- characters. Whether case is ignored depends on the type
|
||||||
|
--- of completion. For buffer text the 'ignorecase' option
|
||||||
|
--- applies.
|
||||||
|
---
|
||||||
|
--- When 'autocomplete' is active and no completion item is
|
||||||
|
--- selected, the longest common prefix of the matches is
|
||||||
|
--- inserted after the cursor. The prefix is taken either
|
||||||
|
--- from all displayed items or only from items in the current
|
||||||
|
--- buffer. The inserted text is highlighted with
|
||||||
|
--- `hl-PreInsert`, and the cursor position does not change
|
||||||
|
--- (similar to `"preinsert"`). Press CTRL-Y to accept.
|
||||||
|
--- See also `preinserted()`.
|
||||||
---
|
---
|
||||||
--- menu Use a popup menu to show the possible completions. The
|
--- menu Use a popup menu to show the possible completions. The
|
||||||
--- menu is only shown when there is more than one match and
|
--- menu is only shown when there is more than one match and
|
||||||
@@ -1220,22 +1231,21 @@ vim.go.cia = vim.go.completeitemalign
|
|||||||
--- with "menu" or "menuone". Overrides "preview".
|
--- with "menu" or "menuone". Overrides "preview".
|
||||||
---
|
---
|
||||||
--- preinsert
|
--- preinsert
|
||||||
--- When 'autocomplete' is not active, inserts the part of the
|
--- Inserts the text of the first completion candidate
|
||||||
--- first candidate word beyond the current completion leader,
|
--- beyond the current leader, highlighted with `hl-PreInsert`.
|
||||||
--- highlighted with `hl-PreInsert`. The cursor doesn't move.
|
--- The cursor does not move.
|
||||||
--- Requires "fuzzy" unset and "menuone" in 'completeopt'.
|
--- Requires "fuzzy" to be unset, and either "menuone" in
|
||||||
---
|
--- 'completeopt' or 'autocomplete' enabled. When
|
||||||
--- When 'autocomplete' is active, inserts the longest common
|
--- 'autocomplete' is enabled, this does not work if
|
||||||
--- prefix of matches (from all shown items or from the
|
--- 'ignorecase' is set without 'infercase'.
|
||||||
--- current buffer items). This occurs only when no menu item
|
--- See also `preinserted()`.
|
||||||
--- is selected. Press CTRL-Y to accept.
|
|
||||||
---
|
---
|
||||||
--- preview Show extra information about the currently selected
|
--- preview Show extra information about the currently selected
|
||||||
--- 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".
|
||||||
---
|
---
|
||||||
--- Only "fuzzy", "popup", "preinsert" and "preview" have an effect when
|
--- Only "fuzzy", "longest", "popup", "preinsert" and "preview" have an
|
||||||
--- 'autocomplete' is enabled.
|
--- effect when 'autocomplete' is enabled.
|
||||||
---
|
---
|
||||||
--- This option does not apply to `cmdline-completion`. See 'wildoptions'
|
--- This option does not apply to `cmdline-completion`. See 'wildoptions'
|
||||||
--- for that.
|
--- for that.
|
||||||
|
8
runtime/lua/vim/_meta/vimfn.lua
generated
8
runtime/lua/vim/_meta/vimfn.lua
generated
@@ -6554,6 +6554,14 @@ function vim.fn.perleval(expr) end
|
|||||||
--- @return number
|
--- @return number
|
||||||
function vim.fn.pow(x, y) end
|
function vim.fn.pow(x, y) end
|
||||||
|
|
||||||
|
--- Returns non-zero if text has been inserted after the cursor
|
||||||
|
--- because "preinsert" is present in 'completeopt', or if
|
||||||
|
--- "longest" is present in 'completeopt' while 'autocomplete'
|
||||||
|
--- is enabled. Otherwise returns zero.
|
||||||
|
---
|
||||||
|
--- @return number
|
||||||
|
function vim.fn.preinserted() end
|
||||||
|
|
||||||
--- Return the line number of the first line at or above {lnum}
|
--- Return the line number of the first line at or above {lnum}
|
||||||
--- that is not blank. Example: >vim
|
--- that is not blank. Example: >vim
|
||||||
--- let ind = indent(prevnonblank(v:lnum - 1))
|
--- let ind = indent(prevnonblank(v:lnum - 1))
|
||||||
|
@@ -606,10 +606,10 @@ static int insert_execute(VimState *state, int key)
|
|||||||
&& (s->c == CAR || s->c == K_KENTER || s->c == NL)))
|
&& (s->c == CAR || s->c == K_KENTER || s->c == NL)))
|
||||||
&& stop_arrow() == OK) {
|
&& stop_arrow() == OK) {
|
||||||
ins_compl_delete(false);
|
ins_compl_delete(false);
|
||||||
if (ins_compl_has_preinsert() && ins_compl_autocomplete_enabled()) {
|
ins_compl_insert(false, !ins_compl_has_preinsert());
|
||||||
(void)ins_compl_insert(false, true);
|
if (ins_compl_preinsert_longest()) {
|
||||||
} else {
|
ins_compl_init_get_longest();
|
||||||
(void)ins_compl_insert(false, false);
|
return 1;
|
||||||
}
|
}
|
||||||
} else if (ascii_iswhite_nl_or_nul(s->c) && ins_compl_preinsert_effect()) {
|
} else if (ascii_iswhite_nl_or_nul(s->c) && ins_compl_preinsert_effect()) {
|
||||||
// Delete preinserted text when typing special chars
|
// Delete preinserted text when typing special chars
|
||||||
|
@@ -8024,6 +8024,18 @@ M.funcs = {
|
|||||||
returns = 'number',
|
returns = 'number',
|
||||||
signature = 'pow({x}, {y})',
|
signature = 'pow({x}, {y})',
|
||||||
},
|
},
|
||||||
|
preinserted = {
|
||||||
|
desc = [=[
|
||||||
|
Returns non-zero if text has been inserted after the cursor
|
||||||
|
because "preinsert" is present in 'completeopt', or if
|
||||||
|
"longest" is present in 'completeopt' while 'autocomplete'
|
||||||
|
is enabled. Otherwise returns zero.
|
||||||
|
]=],
|
||||||
|
name = 'preinserted',
|
||||||
|
params = {},
|
||||||
|
returns = 'number',
|
||||||
|
signature = 'preinserted()',
|
||||||
|
},
|
||||||
prevnonblank = {
|
prevnonblank = {
|
||||||
args = 1,
|
args = 1,
|
||||||
base = 1,
|
base = 1,
|
||||||
|
@@ -296,7 +296,7 @@ static bool compl_autocomplete = false; ///< whether autocompletion is ac
|
|||||||
static uint64_t compl_timeout_ms = COMPL_INITIAL_TIMEOUT_MS;
|
static uint64_t compl_timeout_ms = COMPL_INITIAL_TIMEOUT_MS;
|
||||||
static bool compl_time_slice_expired = false; ///< time budget exceeded for current source
|
static bool compl_time_slice_expired = false; ///< time budget exceeded for current source
|
||||||
static bool compl_from_nonkeyword = false; ///< completion started from non-keyword
|
static bool compl_from_nonkeyword = false; ///< completion started from non-keyword
|
||||||
static bool compl_autocomplete_preinsert = false; ///< apply preinsert highlight
|
static bool compl_hi_on_autocompl_longest = false; ///< apply "PreInsert" highlight
|
||||||
|
|
||||||
// Halve the current completion timeout, simulating exponential decay.
|
// Halve the current completion timeout, simulating exponential decay.
|
||||||
#define COMPL_MIN_TIMEOUT_MS 5
|
#define COMPL_MIN_TIMEOUT_MS 5
|
||||||
@@ -889,6 +889,15 @@ static bool is_nearest_active(void)
|
|||||||
&& !(flags & kOptCotFlagFuzzy);
|
&& !(flags & kOptCotFlagFuzzy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if autocomplete is active and the pre-insert effect targets the
|
||||||
|
/// longest prefix.
|
||||||
|
bool ins_compl_preinsert_longest(void)
|
||||||
|
{
|
||||||
|
return compl_autocomplete
|
||||||
|
&& (get_cot_flags() & (kOptCotFlagLongest | kOptCotFlagPreinsert | kOptCotFlagFuzzy))
|
||||||
|
== kOptCotFlagLongest;
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a match to the list of matches
|
/// Add a match to the list of matches
|
||||||
///
|
///
|
||||||
/// @param[in] str text of the match to add
|
/// @param[in] str text of the match to add
|
||||||
@@ -1053,7 +1062,8 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons
|
|||||||
compl_curr_match = match;
|
compl_curr_match = match;
|
||||||
|
|
||||||
// Find the longest common string if still doing that.
|
// Find the longest common string if still doing that.
|
||||||
if (compl_get_longest && (flags & CP_ORIGINAL_TEXT) == 0 && !cfc_has_mode()) {
|
if (compl_get_longest && (flags & CP_ORIGINAL_TEXT) == 0 && !cfc_has_mode()
|
||||||
|
&& !ins_compl_preinsert_longest()) {
|
||||||
ins_compl_longest_match(match);
|
ins_compl_longest_match(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1107,17 +1117,12 @@ static size_t ins_compl_leader_len(void)
|
|||||||
/// -1 means normal item.
|
/// -1 means normal item.
|
||||||
int ins_compl_col_range_attr(linenr_T lnum, int col)
|
int ins_compl_col_range_attr(linenr_T lnum, int col)
|
||||||
{
|
{
|
||||||
const bool has_preinsert = ins_compl_has_preinsert();
|
const bool has_preinsert = ins_compl_has_preinsert() || ins_compl_preinsert_longest();
|
||||||
|
|
||||||
int attr;
|
int attr;
|
||||||
if ((get_cot_flags() & kOptCotFlagFuzzy)
|
if ((get_cot_flags() & kOptCotFlagFuzzy)
|
||||||
|| (!has_preinsert
|
|| (!compl_hi_on_autocompl_longest && ins_compl_preinsert_longest())
|
||||||
&& (attr = syn_name2attr("ComplMatchIns")) == 0)
|
|| (attr = syn_name2attr(has_preinsert ? "PreInsert" : "ComplMatchIns")) == 0) {
|
||||||
|| (!compl_autocomplete && has_preinsert
|
|
||||||
&& (attr = syn_name2attr("PreInsert")) == 0)
|
|
||||||
|| (compl_autocomplete
|
|
||||||
&& (!compl_autocomplete_preinsert
|
|
||||||
|| (attr = syn_name2attr("PreInsert")) == 0))) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1511,7 +1516,8 @@ static int ins_compl_build_pum(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned cur_cot_flags = get_cot_flags();
|
unsigned cur_cot_flags = get_cot_flags();
|
||||||
bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0 || compl_autocomplete;
|
bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0
|
||||||
|
|| (compl_autocomplete && !ins_compl_has_preinsert());
|
||||||
bool fuzzy_filter = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
|
bool fuzzy_filter = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
|
||||||
|
|
||||||
compl_T *match_head = NULL, *match_tail = NULL;
|
compl_T *match_head = NULL, *match_tail = NULL;
|
||||||
@@ -2132,6 +2138,9 @@ int ins_compl_len(void)
|
|||||||
bool ins_compl_has_preinsert(void)
|
bool ins_compl_has_preinsert(void)
|
||||||
{
|
{
|
||||||
unsigned cur_cot_flags = get_cot_flags();
|
unsigned cur_cot_flags = get_cot_flags();
|
||||||
|
if (compl_autocomplete && p_ic && !p_inf) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return (!compl_autocomplete
|
return (!compl_autocomplete
|
||||||
? (cur_cot_flags & (kOptCotFlagPreinsert|kOptCotFlagFuzzy|kOptCotFlagMenuone))
|
? (cur_cot_flags & (kOptCotFlagPreinsert|kOptCotFlagFuzzy|kOptCotFlagMenuone))
|
||||||
== (kOptCotFlagPreinsert|kOptCotFlagMenuone)
|
== (kOptCotFlagPreinsert|kOptCotFlagMenuone)
|
||||||
@@ -2143,19 +2152,13 @@ bool ins_compl_has_preinsert(void)
|
|||||||
/// the `compl_ins_end_col` range.
|
/// the `compl_ins_end_col` range.
|
||||||
bool ins_compl_preinsert_effect(void)
|
bool ins_compl_preinsert_effect(void)
|
||||||
{
|
{
|
||||||
if (!ins_compl_has_preinsert()) {
|
if (!ins_compl_has_preinsert() && !ins_compl_preinsert_longest()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return curwin->w_cursor.col < compl_ins_end_col;
|
return curwin->w_cursor.col < compl_ins_end_col;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if autocompletion is active.
|
|
||||||
bool ins_compl_autocomplete_enabled(void)
|
|
||||||
{
|
|
||||||
return compl_autocomplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delete one character before the cursor and show the subset of the matches
|
/// Delete one character before the cursor and show the subset of the matches
|
||||||
/// that match the word that is now before the cursor.
|
/// that match the word that is now before the cursor.
|
||||||
/// Returns the character to be used, NUL if the work is done and another char
|
/// Returns the character to be used, NUL if the work is done and another char
|
||||||
@@ -2198,7 +2201,7 @@ int ins_compl_bs(void)
|
|||||||
(size_t)(p_off - (ptrdiff_t)compl_col));
|
(size_t)(p_off - (ptrdiff_t)compl_col));
|
||||||
|
|
||||||
// Clear selection if a menu item is currently selected in autocompletion
|
// Clear selection if a menu item is currently selected in autocompletion
|
||||||
if (compl_autocomplete && compl_first_match) {
|
if (compl_autocomplete && compl_first_match && !ins_compl_has_preinsert()) {
|
||||||
compl_shown_match = compl_first_match;
|
compl_shown_match = compl_first_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2291,18 +2294,14 @@ static void ins_compl_new_leader(void)
|
|||||||
// Show the popup menu with a different set of matches.
|
// Show the popup menu with a different set of matches.
|
||||||
ins_compl_show_pum();
|
ins_compl_show_pum();
|
||||||
|
|
||||||
compl_autocomplete_preinsert = false;
|
|
||||||
// Don't let Enter select the original text when there is no popup menu.
|
// Don't let Enter select the original text when there is no popup menu.
|
||||||
if (compl_match_array == NULL) {
|
if (compl_match_array == NULL) {
|
||||||
compl_enter_selects = false;
|
compl_enter_selects = false;
|
||||||
} else if (ins_compl_has_preinsert() && compl_leader.size > 0) {
|
} else if (ins_compl_has_preinsert() && compl_leader.size > 0) {
|
||||||
if (compl_started && compl_autocomplete && !ins_compl_preinsert_effect()) {
|
ins_compl_insert(true, false);
|
||||||
if (ins_compl_insert(true, true) == OK) {
|
} else if (compl_started && ins_compl_preinsert_longest()
|
||||||
compl_autocomplete_preinsert = true;
|
&& compl_leader.size > 0 && !ins_compl_preinsert_effect()) {
|
||||||
}
|
ins_compl_insert(true, true);
|
||||||
} else {
|
|
||||||
(void)ins_compl_insert(true, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Don't let Enter select when use user function and refresh_always is set
|
// Don't let Enter select when use user function and refresh_always is set
|
||||||
if (ins_compl_refresh_always()) {
|
if (ins_compl_refresh_always()) {
|
||||||
@@ -4388,7 +4387,7 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
|
|||||||
ptr = ins_compl_get_next_word_or_line(st->ins_buf,
|
ptr = ins_compl_get_next_word_or_line(st->ins_buf,
|
||||||
st->cur_match_pos, &len, &cont_s_ipos);
|
st->cur_match_pos, &len, &cont_s_ipos);
|
||||||
}
|
}
|
||||||
if (ptr == NULL || (!compl_autocomplete && ins_compl_has_preinsert()
|
if (ptr == NULL || (ins_compl_has_preinsert()
|
||||||
&& strcmp(ptr, compl_pattern.data) == 0)) {
|
&& strcmp(ptr, compl_pattern.data) == 0)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -4895,7 +4894,7 @@ static int ins_compl_get_exp(pos_T *ini)
|
|||||||
}
|
}
|
||||||
may_trigger_modechanged();
|
may_trigger_modechanged();
|
||||||
|
|
||||||
if (is_nearest_active()) {
|
if (is_nearest_active() && !ins_compl_has_preinsert()) {
|
||||||
sort_compl_match_list(cp_compare_nearest);
|
sort_compl_match_list(cp_compare_nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5108,6 +5107,21 @@ static char *find_common_prefix(size_t *prefix_len, bool curbuf_only)
|
|||||||
xfree(match_count);
|
xfree(match_count);
|
||||||
|
|
||||||
if (len > (int)ins_compl_leader_len()) {
|
if (len > (int)ins_compl_leader_len()) {
|
||||||
|
assert(first != NULL);
|
||||||
|
// Avoid inserting text that duplicates the text already present
|
||||||
|
// after the cursor.
|
||||||
|
if (len == (int)strlen(first)) {
|
||||||
|
char *line = get_cursor_line_ptr();
|
||||||
|
char *p = line + curwin->w_cursor.col;
|
||||||
|
if (p && !ascii_iswhite_or_nul(*p)) {
|
||||||
|
char *end = find_word_end(p);
|
||||||
|
int text_len = (int)(end - p);
|
||||||
|
if (text_len > 0 && text_len < (len - (int)ins_compl_leader_len())
|
||||||
|
&& strncmp(first + len - text_len, p, (size_t)text_len) == 0) {
|
||||||
|
len -= text_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
*prefix_len = (size_t)len;
|
*prefix_len = (size_t)len;
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
@@ -5117,9 +5131,9 @@ static char *find_common_prefix(size_t *prefix_len, bool curbuf_only)
|
|||||||
/// Insert the new text being completed.
|
/// Insert the new text being completed.
|
||||||
/// "move_cursor" is used when 'completeopt' includes "preinsert" and when true
|
/// "move_cursor" is used when 'completeopt' includes "preinsert" and when true
|
||||||
/// cursor needs to move back from the inserted text to the compl_leader.
|
/// cursor needs to move back from the inserted text to the compl_leader.
|
||||||
/// When "preinsert_prefix" is true the longest common prefix is inserted
|
/// When "insert_prefix" is true the longest common prefix is inserted instead
|
||||||
/// instead of shown match.
|
/// of shown match.
|
||||||
int ins_compl_insert(bool move_cursor, bool preinsert_prefix)
|
void ins_compl_insert(bool move_cursor, bool insert_prefix)
|
||||||
{
|
{
|
||||||
int compl_len = get_compl_len();
|
int compl_len = get_compl_len();
|
||||||
bool preinsert = ins_compl_has_preinsert();
|
bool preinsert = ins_compl_has_preinsert();
|
||||||
@@ -5128,12 +5142,13 @@ int ins_compl_insert(bool move_cursor, bool preinsert_prefix)
|
|||||||
size_t leader_len = ins_compl_leader_len();
|
size_t leader_len = ins_compl_leader_len();
|
||||||
char *has_multiple = strchr(cp_str, '\n');
|
char *has_multiple = strchr(cp_str, '\n');
|
||||||
|
|
||||||
if (preinsert_prefix) {
|
if (insert_prefix) {
|
||||||
cp_str = find_common_prefix(&cp_str_len, false);
|
cp_str = find_common_prefix(&cp_str_len, false);
|
||||||
if (cp_str == NULL) {
|
if (cp_str == NULL) {
|
||||||
cp_str = find_common_prefix(&cp_str_len, true);
|
cp_str = find_common_prefix(&cp_str_len, true);
|
||||||
if (cp_str == NULL) {
|
if (cp_str == NULL) {
|
||||||
return FAIL;
|
cp_str = compl_shown_match->cp_str.data;
|
||||||
|
cp_str_len = compl_shown_match->cp_str.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (cpt_sources_array != NULL) {
|
} else if (cpt_sources_array != NULL) {
|
||||||
@@ -5160,18 +5175,18 @@ int ins_compl_insert(bool move_cursor, bool preinsert_prefix)
|
|||||||
ins_compl_expand_multiple(cp_str + compl_len);
|
ins_compl_expand_multiple(cp_str + compl_len);
|
||||||
} else {
|
} else {
|
||||||
ins_compl_insert_bytes(cp_str + compl_len,
|
ins_compl_insert_bytes(cp_str + compl_len,
|
||||||
preinsert_prefix ? (int)cp_str_len - compl_len : -1);
|
insert_prefix ? (int)cp_str_len - compl_len : -1);
|
||||||
if (preinsert && move_cursor) {
|
if ((preinsert || insert_prefix) && move_cursor) {
|
||||||
curwin->w_cursor.col -= (colnr_T)(cp_str_len - leader_len);
|
curwin->w_cursor.col -= (colnr_T)(cp_str_len - leader_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compl_used_match = !(match_at_original_text(compl_shown_match)
|
compl_used_match = !(match_at_original_text(compl_shown_match)
|
||||||
|| (preinsert && !compl_autocomplete));
|
|| (preinsert && !insert_prefix));
|
||||||
|
|
||||||
dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
|
dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
|
||||||
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
|
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
|
||||||
return OK;
|
compl_hi_on_autocompl_longest = insert_prefix && move_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// show the file name for the completion match (if any). Truncate the file
|
/// show the file name for the completion match (if any). Truncate the file
|
||||||
@@ -5240,7 +5255,8 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a
|
|||||||
bool found_end = false;
|
bool found_end = false;
|
||||||
compl_T *found_compl = NULL;
|
compl_T *found_compl = NULL;
|
||||||
unsigned cur_cot_flags = get_cot_flags();
|
unsigned cur_cot_flags = get_cot_flags();
|
||||||
bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0 || compl_autocomplete;
|
bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0
|
||||||
|
|| (compl_autocomplete && !ins_compl_has_preinsert());
|
||||||
bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
|
bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
|
||||||
|
|
||||||
while (--todo >= 0) {
|
while (--todo >= 0) {
|
||||||
@@ -5351,7 +5367,8 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
|
|||||||
const bool started = compl_started;
|
const bool started = compl_started;
|
||||||
buf_T *const orig_curbuf = curbuf;
|
buf_T *const orig_curbuf = curbuf;
|
||||||
unsigned cur_cot_flags = get_cot_flags();
|
unsigned cur_cot_flags = get_cot_flags();
|
||||||
bool compl_no_insert = (cur_cot_flags & kOptCotFlagNoinsert) != 0 || compl_autocomplete;
|
bool compl_no_insert = (cur_cot_flags & kOptCotFlagNoinsert) != 0
|
||||||
|
|| (compl_autocomplete && !ins_compl_has_preinsert());
|
||||||
bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
|
bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
|
||||||
bool compl_preinsert = ins_compl_has_preinsert();
|
bool compl_preinsert = ins_compl_has_preinsert();
|
||||||
|
|
||||||
@@ -5397,35 +5414,18 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
compl_autocomplete_preinsert = false;
|
|
||||||
|
|
||||||
// Insert the text of the new completion, or the compl_leader.
|
// Insert the text of the new completion, or the compl_leader.
|
||||||
if (compl_no_insert && !started) {
|
if (!started && ins_compl_preinsert_longest()) {
|
||||||
bool insert_orig = !compl_preinsert;
|
ins_compl_insert(true, true);
|
||||||
if (compl_preinsert && compl_autocomplete) {
|
} else if (compl_no_insert && !started && !compl_preinsert) {
|
||||||
if (ins_compl_insert(true, true) == OK) {
|
ins_compl_insert_bytes(compl_orig_text.data + get_compl_len(), -1);
|
||||||
compl_autocomplete_preinsert = true;
|
|
||||||
} else {
|
|
||||||
insert_orig = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (insert_orig) {
|
|
||||||
ins_compl_insert_bytes(compl_orig_text.data + get_compl_len(), -1);
|
|
||||||
}
|
|
||||||
compl_used_match = false;
|
compl_used_match = false;
|
||||||
restore_orig_extmarks();
|
restore_orig_extmarks();
|
||||||
} else if (insert_match) {
|
} else if (insert_match) {
|
||||||
if (!compl_get_longest || compl_used_match) {
|
if (!compl_get_longest || compl_used_match) {
|
||||||
bool none_selected = match_at_original_text(compl_shown_match);
|
bool preinsert_longest = ins_compl_preinsert_longest()
|
||||||
if (compl_preinsert && compl_autocomplete && none_selected) {
|
&& match_at_original_text(compl_shown_match); // none selected
|
||||||
if (ins_compl_insert(none_selected, true) == OK) {
|
ins_compl_insert(compl_preinsert || preinsert_longest, preinsert_longest);
|
||||||
compl_autocomplete_preinsert = none_selected;
|
|
||||||
} else {
|
|
||||||
(void)ins_compl_insert(false, false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(void)ins_compl_insert(!compl_autocomplete, false);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
assert(compl_leader.data != NULL);
|
assert(compl_leader.data != NULL);
|
||||||
ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1);
|
ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1);
|
||||||
@@ -5534,8 +5534,8 @@ void ins_compl_check_keys(int frequency, bool in_compl_func)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compl_pending != 0 && !got_int && !(cot_flags & kOptCotFlagNoinsert)
|
if (compl_pending && !got_int && !(cot_flags & kOptCotFlagNoinsert)
|
||||||
&& !compl_autocomplete) {
|
&& (!compl_autocomplete || ins_compl_has_preinsert())) {
|
||||||
// Insert the first match immediately and advance compl_shown_match,
|
// Insert the first match immediately and advance compl_shown_match,
|
||||||
// before finding other matches.
|
// before finding other matches.
|
||||||
int todo = compl_pending > 0 ? compl_pending : -compl_pending;
|
int todo = compl_pending > 0 ? compl_pending : -compl_pending;
|
||||||
@@ -6599,3 +6599,11 @@ static void cpt_compl_refresh(void)
|
|||||||
// Make the list cyclic
|
// Make the list cyclic
|
||||||
compl_matches = ins_compl_make_cyclic();
|
compl_matches = ins_compl_make_cyclic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// "preinserted()" function
|
||||||
|
void f_preinserted(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
|
{
|
||||||
|
if (ins_compl_preinsert_effect()) {
|
||||||
|
rettv->vval.v_number = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1663,11 +1663,22 @@ local options = {
|
|||||||
to gather more alternatives for your candidate list,
|
to gather more alternatives for your candidate list,
|
||||||
see 'completefuzzycollect'.
|
see 'completefuzzycollect'.
|
||||||
|
|
||||||
longest Only insert the longest common text of the matches. If
|
longest
|
||||||
the menu is displayed you can use CTRL-L to add more
|
When 'autocomplete' is not active, only the longest
|
||||||
characters. Whether case is ignored depends on the kind
|
common prefix of the matches is inserted. If the popup
|
||||||
of completion. For buffer text the 'ignorecase' option is
|
menu is displayed, you can use CTRL-L to add more
|
||||||
used.
|
characters. Whether case is ignored depends on the type
|
||||||
|
of completion. For buffer text the 'ignorecase' option
|
||||||
|
applies.
|
||||||
|
|
||||||
|
When 'autocomplete' is active and no completion item is
|
||||||
|
selected, the longest common prefix of the matches is
|
||||||
|
inserted after the cursor. The prefix is taken either
|
||||||
|
from all displayed items or only from items in the current
|
||||||
|
buffer. The inserted text is highlighted with
|
||||||
|
|hl-PreInsert|, and the cursor position does not change
|
||||||
|
(similar to `"preinsert"`). Press CTRL-Y to accept.
|
||||||
|
See also |preinserted()|.
|
||||||
|
|
||||||
menu Use a popup menu to show the possible completions. The
|
menu Use a popup menu to show the possible completions. The
|
||||||
menu is only shown when there is more than one match and
|
menu is only shown when there is more than one match and
|
||||||
@@ -1700,22 +1711,21 @@ local options = {
|
|||||||
with "menu" or "menuone". Overrides "preview".
|
with "menu" or "menuone". Overrides "preview".
|
||||||
|
|
||||||
preinsert
|
preinsert
|
||||||
When 'autocomplete' is not active, inserts the part of the
|
Inserts the text of the first completion candidate
|
||||||
first candidate word beyond the current completion leader,
|
beyond the current leader, highlighted with |hl-PreInsert|.
|
||||||
highlighted with |hl-PreInsert|. The cursor doesn't move.
|
The cursor does not move.
|
||||||
Requires "fuzzy" unset and "menuone" in 'completeopt'.
|
Requires "fuzzy" to be unset, and either "menuone" in
|
||||||
|
'completeopt' or 'autocomplete' enabled. When
|
||||||
When 'autocomplete' is active, inserts the longest common
|
'autocomplete' is enabled, this does not work if
|
||||||
prefix of matches (from all shown items or from the
|
'ignorecase' is set without 'infercase'.
|
||||||
current buffer items). This occurs only when no menu item
|
See also |preinserted()|.
|
||||||
is selected. Press CTRL-Y to accept.
|
|
||||||
|
|
||||||
preview Show extra information about the currently selected
|
preview Show extra information about the currently selected
|
||||||
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".
|
||||||
|
|
||||||
Only "fuzzy", "popup", "preinsert" and "preview" have an effect when
|
Only "fuzzy", "longest", "popup", "preinsert" and "preview" have an
|
||||||
'autocomplete' is enabled.
|
effect when 'autocomplete' is enabled.
|
||||||
|
|
||||||
This option does not apply to |cmdline-completion|. See 'wildoptions'
|
This option does not apply to |cmdline-completion|. See 'wildoptions'
|
||||||
for that.
|
for that.
|
||||||
|
@@ -1496,18 +1496,18 @@ describe('completion', function()
|
|||||||
|
|
||||||
-- During delay wait, user can open menu using CTRL_N completion
|
-- During delay wait, user can open menu using CTRL_N completion
|
||||||
feed('<Esc>')
|
feed('<Esc>')
|
||||||
command('set completeopt=menuone,preinsert')
|
command('set completeopt=menuone,longest')
|
||||||
feed('Sf<C-N>')
|
feed('Sf<C-N>')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
foo |
|
foo |
|
||||||
foobar |
|
foobar |
|
||||||
foobarbaz |
|
foobarbaz |
|
||||||
f{102:^oo} |
|
foo^ |
|
||||||
{12:foo }{1: }|
|
{4:foo }{1: }|
|
||||||
{4:foobar }{1: }|
|
{4:foobar }{1: }|
|
||||||
{4:foobarbaz }{1: }|
|
{4:foobarbaz }{1: }|
|
||||||
{1:~ }|*2
|
{1:~ }|*2
|
||||||
{5:-- Keyword completion (^N^P) }{6:match 1 of 3} |
|
{5:-- Keyword completion (^N^P) }{19:Back at original} |
|
||||||
]])
|
]])
|
||||||
|
|
||||||
-- After the menu is open, ^N/^P and Up/Down should not delay
|
-- After the menu is open, ^N/^P and Up/Down should not delay
|
||||||
|
@@ -124,10 +124,9 @@ endfunc
|
|||||||
func Test_omni_dash()
|
func Test_omni_dash()
|
||||||
func Omni(findstart, base)
|
func Omni(findstart, base)
|
||||||
if a:findstart
|
if a:findstart
|
||||||
return 5
|
return 5
|
||||||
else
|
else
|
||||||
echom a:base
|
return ['-help', '-v']
|
||||||
return ['-help', '-v']
|
|
||||||
endif
|
endif
|
||||||
endfunc
|
endfunc
|
||||||
set omnifunc=Omni
|
set omnifunc=Omni
|
||||||
@@ -4231,6 +4230,145 @@ func Test_completeopt_preinsert()
|
|||||||
delfunc Omni_test
|
delfunc Omni_test
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_autocomplete_completeopt_preinsert()
|
||||||
|
func Omni_test(findstart, base)
|
||||||
|
if a:findstart
|
||||||
|
return col(".") - 1
|
||||||
|
endif
|
||||||
|
return [#{word: "fobar"}, #{word: "foobar"}]
|
||||||
|
endfunc
|
||||||
|
set omnifunc=Omni_test complete+=o
|
||||||
|
set completeopt=preinsert autocomplete
|
||||||
|
" set completeopt=preinsert,menuone autocomplete
|
||||||
|
func GetLine()
|
||||||
|
let g:line = getline('.')
|
||||||
|
let g:col = col('.')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
call Ntest_override("char_avail", 1)
|
||||||
|
new
|
||||||
|
inoremap <buffer><F5> <C-R>=GetLine()<CR>
|
||||||
|
call feedkeys("Sfo\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("fobar", g:line)
|
||||||
|
call assert_equal(3, g:col)
|
||||||
|
|
||||||
|
call feedkeys("Sfoo\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("foobar", g:line)
|
||||||
|
|
||||||
|
call feedkeys("Sfoo\<BS>\<BS>\<BS>", 'tx')
|
||||||
|
call assert_equal("", getline('.'))
|
||||||
|
|
||||||
|
" delete a character
|
||||||
|
call feedkeys("Sfoo\<BS>b\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("fobar", g:line)
|
||||||
|
call assert_equal(4, g:col)
|
||||||
|
|
||||||
|
set complete&
|
||||||
|
%d
|
||||||
|
call setline(1, ['fobar', 'foobar'])
|
||||||
|
|
||||||
|
call feedkeys("Gofoo\<BS>\<BS>\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("fobar", g:line)
|
||||||
|
call assert_equal(2, g:col)
|
||||||
|
|
||||||
|
call feedkeys("Shello wo\<Left>\<Left>\<Left>f\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("hello fobar wo", g:line)
|
||||||
|
call assert_equal(9, g:col)
|
||||||
|
|
||||||
|
call feedkeys("Shello wo\<Left>\<Left>\<Left>f\<BS>\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("hello wo", g:line)
|
||||||
|
call assert_equal(8, g:col)
|
||||||
|
|
||||||
|
call feedkeys("Shello wo\<Left>\<Left>\<Left>foo\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("hello foobar wo", g:line)
|
||||||
|
call assert_equal(11, g:col)
|
||||||
|
|
||||||
|
call feedkeys("Shello wo\<Left>\<Left>\<Left>foo\<BS>b\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("hello fobar wo", g:line)
|
||||||
|
call assert_equal(11, g:col)
|
||||||
|
|
||||||
|
" confirm
|
||||||
|
call feedkeys("Sf\<C-Y>", 'tx')
|
||||||
|
call assert_equal("fobar", getline('.'))
|
||||||
|
call assert_equal(5, col('.'))
|
||||||
|
|
||||||
|
" cancel
|
||||||
|
call feedkeys("Sfo\<C-E>", 'tx')
|
||||||
|
call assert_equal("fo", getline('.'))
|
||||||
|
call assert_equal(2, col('.'))
|
||||||
|
|
||||||
|
" delete preinsert part
|
||||||
|
call feedkeys("Sfo ", 'tx')
|
||||||
|
call assert_equal("fo ", getline('.'))
|
||||||
|
call assert_equal(3, col('.'))
|
||||||
|
|
||||||
|
" can not work with fuzzy
|
||||||
|
set cot+=fuzzy
|
||||||
|
call feedkeys("Sf", 'tx')
|
||||||
|
call assert_equal("f", getline('.'))
|
||||||
|
set cot-=fuzzy
|
||||||
|
|
||||||
|
" does not work with 'ignorecase' unless 'infercase' is also enabled
|
||||||
|
%d
|
||||||
|
call setline(1, ['FIX', 'fobar', 'foobar'])
|
||||||
|
set ignorecase
|
||||||
|
call feedkeys("Gof\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("f", g:line) " should not produce 'FIX'
|
||||||
|
set infercase
|
||||||
|
call feedkeys("Gof\<F5>\<ESC>", 'tx')
|
||||||
|
call assert_equal("fix", g:line)
|
||||||
|
set ignorecase& infercase&
|
||||||
|
|
||||||
|
%delete _
|
||||||
|
let &l:undolevels = &l:undolevels
|
||||||
|
normal! ifoo
|
||||||
|
let &l:undolevels = &l:undolevels
|
||||||
|
normal! obar
|
||||||
|
let &l:undolevels = &l:undolevels
|
||||||
|
normal! obaz
|
||||||
|
let &l:undolevels = &l:undolevels
|
||||||
|
|
||||||
|
func CheckUndo()
|
||||||
|
let g:errmsg = ''
|
||||||
|
call assert_equal(['foo', 'bar', 'baz'], getline(1, '$'))
|
||||||
|
undo
|
||||||
|
call assert_equal(['foo', 'bar'], getline(1, '$'))
|
||||||
|
undo
|
||||||
|
call assert_equal(['foo'], getline(1, '$'))
|
||||||
|
undo
|
||||||
|
call assert_equal([''], getline(1, '$'))
|
||||||
|
later 3
|
||||||
|
call assert_equal(['foo', 'bar', 'baz'], getline(1, '$'))
|
||||||
|
call assert_equal('', v:errmsg)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Check that switching buffer with "preinsert" doesn't corrupt undo.
|
||||||
|
new
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
inoremap <buffer> <F2> <Cmd>enew!<CR>
|
||||||
|
call feedkeys("if\<F2>\<Esc>", 'tx')
|
||||||
|
bwipe!
|
||||||
|
call CheckUndo()
|
||||||
|
|
||||||
|
" Check that closing window with "preinsert" doesn't corrupt undo.
|
||||||
|
new
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
inoremap <buffer> <F2> <Cmd>close!<CR>
|
||||||
|
call feedkeys("if\<F2>\<Esc>", 'tx')
|
||||||
|
call CheckUndo()
|
||||||
|
|
||||||
|
%delete _
|
||||||
|
delfunc CheckUndo
|
||||||
|
|
||||||
|
bw!
|
||||||
|
set cot&
|
||||||
|
set omnifunc&
|
||||||
|
set autocomplete&
|
||||||
|
call Ntest_override("char_avail", 0)
|
||||||
|
delfunc Omni_test
|
||||||
|
delfunc GetLine
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Check that mark positions are correct after triggering multiline completion.
|
" Check that mark positions are correct after triggering multiline completion.
|
||||||
func Test_complete_multiline_marks()
|
func Test_complete_multiline_marks()
|
||||||
func Omni_test(findstart, base)
|
func Omni_test(findstart, base)
|
||||||
@@ -5696,7 +5834,7 @@ func Test_autocompletedelay()
|
|||||||
call VerifyScreenDump(buf, 'Test_autocompletedelay_6', {})
|
call VerifyScreenDump(buf, 'Test_autocompletedelay_6', {})
|
||||||
|
|
||||||
" During delay wait, user can open menu using CTRL_N completion
|
" During delay wait, user can open menu using CTRL_N completion
|
||||||
call term_sendkeys(buf, "\<Esc>:set completeopt=menuone,preinsert\<CR>")
|
call term_sendkeys(buf, "\<Esc>:set completeopt=menuone,longest\<CR>")
|
||||||
call term_sendkeys(buf, "Sf\<C-N>")
|
call term_sendkeys(buf, "Sf\<C-N>")
|
||||||
call VerifyScreenDump(buf, 'Test_autocompletedelay_7', {})
|
call VerifyScreenDump(buf, 'Test_autocompletedelay_7', {})
|
||||||
|
|
||||||
@@ -5720,16 +5858,18 @@ func Test_autocompletedelay()
|
|||||||
call StopVimInTerminal(buf)
|
call StopVimInTerminal(buf)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_autocomplete_completeopt_preinsert()
|
" Preinsert longest prefix when autocomplete
|
||||||
|
func Test_autocomplete_longest()
|
||||||
func GetLine()
|
func GetLine()
|
||||||
let g:line = getline('.')
|
let g:line = getline('.')
|
||||||
let g:col = col('.')
|
let g:col = col('.')
|
||||||
|
let g:preinserted = preinserted()
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
call Ntest_override("char_avail", 1)
|
call Ntest_override("char_avail", 1)
|
||||||
new
|
new
|
||||||
inoremap <buffer><F5> <C-R>=GetLine()<CR>
|
inoremap <buffer><F5> <C-R>=GetLine()<CR>
|
||||||
set completeopt=preinsert autocomplete
|
set completeopt=longest autocomplete
|
||||||
call setline(1, ["foobar", "foozbar"])
|
call setline(1, ["foobar", "foozbar"])
|
||||||
call feedkeys("Go\<ESC>", 'tx')
|
call feedkeys("Go\<ESC>", 'tx')
|
||||||
|
|
||||||
@@ -5761,10 +5901,15 @@ func Test_autocomplete_completeopt_preinsert()
|
|||||||
call DoTest("f\<C-P>", 'foobar', 7)
|
call DoTest("f\<C-P>", 'foobar', 7)
|
||||||
call DoTest("fo\<BS>\<C-P>", 'foobar', 7)
|
call DoTest("fo\<BS>\<C-P>", 'foobar', 7)
|
||||||
|
|
||||||
|
" <C-Y> to accept preinserted text
|
||||||
|
inoremap <buffer><F6> <C-R>=pumvisible()<CR>
|
||||||
call DoTest("zar\<C-O>0f", 'foozar', 2)
|
call DoTest("zar\<C-O>0f", 'foozar', 2)
|
||||||
call DoTest("zar\<C-O>0f\<C-Y>", 'foozar', 4)
|
call DoTest("zar\<C-O>0f\<C-Y>", 'foozar', 4)
|
||||||
|
call DoTest("zar\<C-O>0f\<C-Y>\<F6>", 'foo1zar', 5)
|
||||||
call DoTest("zar\<C-O>0f\<C-Y>\<BS>", 'foozar', 3)
|
call DoTest("zar\<C-O>0f\<C-Y>\<BS>", 'foozar', 3)
|
||||||
|
call DoTest("zar\<C-O>0f\<C-Y>\<BS>\<F6>", 'fo1zar', 4)
|
||||||
|
|
||||||
|
" Select items in menu
|
||||||
call DoTest("zar\<C-O>0f\<C-N>", 'foozbarzar', 8)
|
call DoTest("zar\<C-O>0f\<C-N>", 'foozbarzar', 8)
|
||||||
call DoTest("zar\<C-O>0f\<C-N>\<C-N>", 'foobarzar', 7)
|
call DoTest("zar\<C-O>0f\<C-N>\<C-N>", 'foobarzar', 7)
|
||||||
call DoTest("zar\<C-O>0f\<C-N>\<C-N>\<C-N>", 'foozar', 2)
|
call DoTest("zar\<C-O>0f\<C-N>\<C-N>\<C-N>", 'foozar', 2)
|
||||||
@@ -5778,6 +5923,34 @@ func Test_autocomplete_completeopt_preinsert()
|
|||||||
call DoTest("f", 'f', 2)
|
call DoTest("f", 'f', 2)
|
||||||
set cot-=fuzzy
|
set cot-=fuzzy
|
||||||
|
|
||||||
|
" preinserted()
|
||||||
|
call DoTest("f", 'foo', 2)
|
||||||
|
call assert_equal(1, g:preinserted)
|
||||||
|
call assert_equal(0, preinserted())
|
||||||
|
call DoTest("f\<BS>", '', 1)
|
||||||
|
call assert_equal(0, g:preinserted)
|
||||||
|
call DoTest("f ", 'f ', 3)
|
||||||
|
call assert_equal(0, g:preinserted)
|
||||||
|
call DoTest("foob", 'foobar', 5)
|
||||||
|
call assert_equal(1, g:preinserted)
|
||||||
|
call DoTest("foob\<BS>\<BS>x", 'fox', 4)
|
||||||
|
call assert_equal(0, g:preinserted)
|
||||||
|
|
||||||
|
" Complete non-keyword
|
||||||
|
func Omni(findstart, base)
|
||||||
|
if a:findstart
|
||||||
|
return 5
|
||||||
|
else
|
||||||
|
return ['xyz:']
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
set omnifunc=Omni
|
||||||
|
set cpt+=o
|
||||||
|
call DoTest("xyz:", "xyz:xyz:", 5)
|
||||||
|
call DoTest("xyz:\<BS>\<BS>", "xyz:", 3)
|
||||||
|
set omnifunc& cpt&
|
||||||
|
delfunc Omni
|
||||||
|
|
||||||
" leader should match prefix of inserted word
|
" leader should match prefix of inserted word
|
||||||
%delete
|
%delete
|
||||||
set smartcase ignorecase
|
set smartcase ignorecase
|
||||||
@@ -5788,6 +5961,16 @@ func Test_autocomplete_completeopt_preinsert()
|
|||||||
call assert_equal('FOO', g:line)
|
call assert_equal('FOO', g:line)
|
||||||
set smartcase& ignorecase&
|
set smartcase& ignorecase&
|
||||||
|
|
||||||
|
" avoid repeating text that is already present after the cursor
|
||||||
|
%delete
|
||||||
|
call setline(1, ["foobarbaz", ""])
|
||||||
|
call feedkeys($"G", 'tx')
|
||||||
|
call DoTest("baz\<C-O>0f", "foobarbaz", 2)
|
||||||
|
call feedkeys($"Sxfoozar\<CR>\<Esc>", 'tx')
|
||||||
|
call DoTest("baz\<C-O>0f", "foobarbaz", 2)
|
||||||
|
call feedkeys($"Sfoozar\<CR>\<Esc>", 'tx')
|
||||||
|
call DoTest("baz\<C-O>0f", "foobaz", 2)
|
||||||
|
|
||||||
" Verify that redo (dot) works
|
" Verify that redo (dot) works
|
||||||
%delete
|
%delete
|
||||||
call setline(1, ["foobar", "foozbar", "foobaz", "changed", "change"])
|
call setline(1, ["foobar", "foozbar", "foobaz", "changed", "change"])
|
||||||
@@ -5824,7 +6007,7 @@ func Test_autocomplete_completeopt_preinsert()
|
|||||||
call assert_equal('', v:errmsg)
|
call assert_equal('', v:errmsg)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Check that switching buffer with "preinsert" doesn't corrupt undo.
|
" Check that switching buffer with "longest" doesn't corrupt undo.
|
||||||
new
|
new
|
||||||
setlocal bufhidden=wipe
|
setlocal bufhidden=wipe
|
||||||
inoremap <buffer> <F2> <Cmd>enew!<CR>
|
inoremap <buffer> <F2> <Cmd>enew!<CR>
|
||||||
@@ -5832,7 +6015,7 @@ func Test_autocomplete_completeopt_preinsert()
|
|||||||
bwipe!
|
bwipe!
|
||||||
call CheckUndo()
|
call CheckUndo()
|
||||||
|
|
||||||
" Check that closing window with "preinsert" doesn't corrupt undo.
|
" Check that closing window with "longest" doesn't corrupt undo.
|
||||||
new
|
new
|
||||||
setlocal bufhidden=wipe
|
setlocal bufhidden=wipe
|
||||||
inoremap <buffer> <F2> <Cmd>close!<CR>
|
inoremap <buffer> <F2> <Cmd>close!<CR>
|
||||||
|
Reference in New Issue
Block a user