vim-patch:8.2.1907: complete_info().selected may be wrong

Problem:    Complete_info().selected may be wrong.
Solution:   Update cp_number if it was never set. (issue vim/vim#6945)
f9d51354de

Misc changes:

For variables and function parameters that use "Direction" enum values,
update their type from from "int" to "Direction".
It is hard to review function parameters that must accept
"Direction" enum values only.
This commit is contained in:
Jan Edmund Lazo
2020-12-02 23:43:43 -05:00
parent 6bc1844b11
commit f85386d170
5 changed files with 81 additions and 64 deletions

View File

@@ -196,8 +196,8 @@ static int ctrl_x_mode = CTRL_X_NORMAL;
static int compl_matches = 0; static int compl_matches = 0;
static char_u *compl_pattern = NULL; static char_u *compl_pattern = NULL;
static int compl_direction = FORWARD; static Direction compl_direction = FORWARD;
static int compl_shows_dir = FORWARD; static Direction compl_shows_dir = FORWARD;
static int compl_pending = 0; // > 1 for postponed CTRL-N static int compl_pending = 0; // > 1 for postponed CTRL-N
static pos_T compl_startpos; static pos_T compl_startpos;
static colnr_T compl_col = 0; /* column where the text starts static colnr_T compl_col = 0; /* column where the text starts
@@ -2156,7 +2156,7 @@ static bool ins_compl_accept_char(int c)
/// ///
/// @param[in] cont_s_ipos next ^X<> will set initial_pos /// @param[in] cont_s_ipos next ^X<> will set initial_pos
int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
int dir, bool cont_s_ipos) Direction dir, bool cont_s_ipos)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(1)
{ {
char_u *str = str_arg; char_u *str = str_arg;
@@ -2308,7 +2308,7 @@ static int ins_compl_add(char_u *const str, int len,
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(1)
{ {
compl_T *match; compl_T *match;
int dir = (cdir == kDirectionNotSet ? compl_direction : cdir); const Direction dir = (cdir == kDirectionNotSet ? compl_direction : cdir);
int flags = flags_arg; int flags = flags_arg;
os_breakcheck(); os_breakcheck();
@@ -2511,7 +2511,7 @@ static void ins_compl_add_matches(int num_matches, char_u **matches, int icase)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
int add_r = OK; int add_r = OK;
int dir = compl_direction; Direction dir = compl_direction;
for (int i = 0; i < num_matches && add_r != FAIL; i++) { for (int i = 0; i < num_matches && add_r != FAIL; i++) {
if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir, if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir,
@@ -2864,7 +2864,7 @@ ins_compl_dictionaries (
char_u **files; char_u **files;
int count; int count;
int save_p_scs; int save_p_scs;
int dir = compl_direction; Direction dir = compl_direction;
if (*dict == NUL) { if (*dict == NUL) {
/* When 'dictionary' is empty and spell checking is enabled use /* When 'dictionary' is empty and spell checking is enabled use
@@ -2945,7 +2945,10 @@ theend:
xfree(buf); xfree(buf);
} }
static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir) static void ins_compl_files(int count, char_u **files, int thesaurus,
int flags, regmatch_T *regmatch, char_u *buf,
Direction *dir)
FUNC_ATTR_NONNULL_ARG(2, 7)
{ {
char_u *ptr; char_u *ptr;
int i; int i;
@@ -3137,6 +3140,56 @@ bool ins_compl_active(void)
return compl_started; return compl_started;
} }
static void ins_compl_update_sequence_numbers(void)
{
int number = 0;
compl_T *match;
if (compl_direction == FORWARD) {
// search backwards for the first valid (!= -1) number.
// This should normally succeed already at the first loop
// cycle, so it's fast!
for (match = compl_curr_match->cp_prev;
match != NULL && match != compl_first_match;
match = match->cp_prev) {
if (match->cp_number != -1) {
number = match->cp_number;
break;
}
}
if (match != NULL) {
// go up and assign all numbers which are not assigned yet
for (match = match->cp_next;
match != NULL && match->cp_number == -1;
match = match->cp_next) {
match->cp_number = ++number;
}
}
} else { // BACKWARD
assert(compl_direction == BACKWARD);
// search forwards (upwards) for the first valid (!= -1)
// number. This should normally succeed already at the
// first loop cycle, so it's fast!
for (match = compl_curr_match->cp_next;
match != NULL && match != compl_first_match;
match = match->cp_next) {
if (match->cp_number != -1) {
number = match->cp_number;
break;
}
}
if (match != NULL) {
// go down and assign all numbers which are not
// assigned yet
for (match = match->cp_prev;
match && match->cp_number == -1;
match = match->cp_prev) {
match->cp_number = ++number;
}
}
}
}
// Get complete information // Get complete information
void get_complete_info(list_T *what_list, dict_T *retdict) void get_complete_info(list_T *what_list, dict_T *retdict)
{ {
@@ -3214,6 +3267,9 @@ void get_complete_info(list_T *what_list, dict_T *retdict)
} }
if (ret == OK && (what_flag & CI_WHAT_SELECTED)) { if (ret == OK && (what_flag & CI_WHAT_SELECTED)) {
if (compl_curr_match != NULL && compl_curr_match->cp_number == -1) {
ins_compl_update_sequence_numbers();
}
ret = tv_dict_add_nr(retdict, S_LEN("selected"), ret = tv_dict_add_nr(retdict, S_LEN("selected"),
(compl_curr_match != NULL) (compl_curr_match != NULL)
? compl_curr_match->cp_number - 1 : -1); ? compl_curr_match->cp_number - 1 : -1);
@@ -3865,7 +3921,7 @@ theend:
*/ */
static void ins_compl_add_list(list_T *const list) static void ins_compl_add_list(list_T *const list)
{ {
int dir = compl_direction; Direction dir = compl_direction;
// Go through the List with matches and add each of them. // Go through the List with matches and add each of them.
TV_LIST_ITER(list, li, { TV_LIST_ITER(list, li, {
@@ -5242,53 +5298,11 @@ static int ins_complete(int c, bool enable_pum)
} else if (compl_curr_match->cp_next == compl_curr_match->cp_prev) { } else if (compl_curr_match->cp_next == compl_curr_match->cp_prev) {
edit_submode_extra = (char_u *)_("The only match"); edit_submode_extra = (char_u *)_("The only match");
edit_submode_highl = HLF_COUNT; edit_submode_highl = HLF_COUNT;
compl_curr_match->cp_number = 0; compl_curr_match->cp_number = 1;
} else { } else {
// Update completion sequence number when needed. // Update completion sequence number when needed.
if (compl_curr_match->cp_number == -1) { if (compl_curr_match->cp_number == -1) {
int number = 0; ins_compl_update_sequence_numbers();
compl_T *match;
if (compl_direction == FORWARD) {
/* search backwards for the first valid (!= -1) number.
* This should normally succeed already at the first loop
* cycle, so it's fast! */
for (match = compl_curr_match->cp_prev; match != NULL
&& match != compl_first_match;
match = match->cp_prev)
if (match->cp_number != -1) {
number = match->cp_number;
break;
}
if (match != NULL)
/* go up and assign all numbers which are not assigned
* yet */
for (match = match->cp_next;
match != NULL && match->cp_number == -1;
match = match->cp_next)
match->cp_number = ++number;
} else { // BACKWARD
// search forwards (upwards) for the first valid (!= -1)
// number. This should normally succeed already at the
// first loop cycle, so it's fast!
for (match = compl_curr_match->cp_next;
match != NULL && match != compl_first_match;
match = match->cp_next) {
if (match->cp_number != -1) {
number = match->cp_number;
break;
}
}
if (match != NULL) {
// go down and assign all numbers which are not
// assigned yet
for (match = match->cp_prev;
match && match->cp_number == -1;
match = match->cp_prev) {
match->cp_number = ++number;
}
}
}
} }
/* The match should always have a sequence number now, this is /* The match should always have a sequence number now, this is

View File

@@ -89,7 +89,7 @@ static struct spat spats[2] =
static int last_idx = 0; /* index in spats[] for RE_LAST */ static int last_idx = 0; /* index in spats[] for RE_LAST */
static char_u lastc[2] = { NUL, NUL }; // last character searched for static char_u lastc[2] = { NUL, NUL }; // last character searched for
static int lastcdir = FORWARD; // last direction of character search static Direction lastcdir = FORWARD; // last direction of character search
static int last_t_cmd = true; // last search t_cmd static int last_t_cmd = true; // last search t_cmd
static char_u lastc_bytes[MB_MAXBYTES + 1]; static char_u lastc_bytes[MB_MAXBYTES + 1];
static int lastc_bytelen = 1; // >1 for multi-byte char static int lastc_bytelen = 1; // >1 for multi-byte char
@@ -437,7 +437,7 @@ void set_last_csearch(int c, char_u *s, int len)
memset(lastc_bytes, 0, sizeof(lastc_bytes)); memset(lastc_bytes, 0, sizeof(lastc_bytes));
} }
void set_csearch_direction(int cdir) void set_csearch_direction(Direction cdir)
{ {
lastcdir = cdir; lastcdir = cdir;
} }
@@ -1430,7 +1430,7 @@ end_do_search:
* ADDING is set. If p_ic is set then the pattern must be in lowercase. * ADDING is set. If p_ic is set then the pattern must be in lowercase.
* Return OK for success, or FAIL if no line found. * Return OK for success, or FAIL if no line found.
*/ */
int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat) int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat)
{ {
linenr_T start = 0; linenr_T start = 0;
char_u *ptr; char_u *ptr;
@@ -1496,10 +1496,11 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat)
* Return FAIL or OK. * Return FAIL or OK.
*/ */
int searchc(cmdarg_T *cap, int t_cmd) int searchc(cmdarg_T *cap, int t_cmd)
FUNC_ATTR_NONNULL_ALL
{ {
int c = cap->nchar; /* char to search for */ int c = cap->nchar; // char to search for
int dir = cap->arg; /* TRUE for searching forward */ Direction dir = cap->arg; // TRUE for searching forward
long count = cap->count1; /* repeat count */ long count = cap->count1; // repeat count
int col; int col;
char_u *p; char_u *p;
int len; int len;
@@ -4462,7 +4463,7 @@ static void search_stat(int dirc, pos_T *pos,
void void
find_pattern_in_path( find_pattern_in_path(
char_u *ptr, // pointer to search pattern char_u *ptr, // pointer to search pattern
int dir, // direction of expansion Direction dir, // direction of expansion
size_t len, // length of search pattern size_t len, // length of search pattern
bool whole, // match whole words only bool whole, // match whole words only
bool skip_comments, // don't match inside comments bool skip_comments, // don't match inside comments

View File

@@ -79,7 +79,6 @@
/* for offsetof() */ /* for offsetof() */
#include <stddef.h> #include <stddef.h>
#include "nvim/vim.h"
#include "nvim/ascii.h" #include "nvim/ascii.h"
#include "nvim/spell.h" #include "nvim/spell.h"
#include "nvim/buffer.h" #include "nvim/buffer.h"
@@ -6653,7 +6652,7 @@ void
spell_dump_compl ( spell_dump_compl (
char_u *pat, // leading part of the word char_u *pat, // leading part of the word
int ic, // ignore case int ic, // ignore case
int *dir, // direction for adding matches Direction *dir, // direction for adding matches
int dumpflags_arg // DUMPFLAG_* int dumpflags_arg // DUMPFLAG_*
) )
{ {
@@ -6820,7 +6819,9 @@ spell_dump_compl (
// Dumps one word: apply case modifications and append a line to the buffer. // Dumps one word: apply case modifications and append a line to the buffer.
// When "lnum" is zero add insert mode completion. // When "lnum" is zero add insert mode completion.
static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int dumpflags, int wordflags, linenr_T lnum) static void dump_word(slang_T *slang, char_u *word, char_u *pat,
Direction *dir, int dumpflags, int wordflags,
linenr_T lnum)
{ {
bool keepcap = false; bool keepcap = false;
char_u *p; char_u *p;
@@ -6906,7 +6907,7 @@ dump_prefixes (
slang_T *slang, slang_T *slang,
char_u *word, // case-folded word char_u *word, // case-folded word
char_u *pat, char_u *pat,
int *dir, Direction *dir,
int dumpflags, int dumpflags,
int flags, // flags with prefix ID int flags, // flags with prefix ID
linenr_T startlnum linenr_T startlnum

View File

@@ -6,6 +6,7 @@
#include "nvim/spell_defs.h" #include "nvim/spell_defs.h"
#include "nvim/ex_cmds_defs.h" #include "nvim/ex_cmds_defs.h"
#include "nvim/globals.h" #include "nvim/globals.h"
#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "spell.h.generated.h" # include "spell.h.generated.h"

View File

@@ -324,7 +324,7 @@ func Test_completefunc_info()
set completeopt=menuone set completeopt=menuone
set completefunc=CompleteTest set completefunc=CompleteTest
call feedkeys("i\<C-X>\<C-U>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx") call feedkeys("i\<C-X>\<C-U>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx")
call assert_equal("matched{'pum_visible': 1, 'mode': 'function', 'selected': -1, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1)) call assert_equal("matched{'pum_visible': 1, 'mode': 'function', 'selected': 0, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1))
bwipe! bwipe!
set completeopt& set completeopt&
set completefunc& set completefunc&