mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	Merge pull request #25806 from zeertzjq/vim-9.0.2074
vim-patch:9.0.{2074,2077}: Completion menu may be wrong
			
			
This commit is contained in:
		@@ -2702,10 +2702,41 @@ static int info_add_completion_info(list_T *li)
 | 
			
		||||
    return OK;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool forward = compl_dir_forward();
 | 
			
		||||
  compl_T *match = compl_first_match;
 | 
			
		||||
  // There are four cases to consider here:
 | 
			
		||||
  // 1) when just going forward through the menu,
 | 
			
		||||
  //    compl_first_match should point to the initial entry with
 | 
			
		||||
  //    number zero and CP_ORIGINAL_TEXT flag set
 | 
			
		||||
  // 2) when just going backwards,
 | 
			
		||||
  //    compl-first_match should point to the last entry before
 | 
			
		||||
  //    the entry with the CP_ORIGINAL_TEXT flag set
 | 
			
		||||
  // 3) when first going forwards and then backwards, e.g.
 | 
			
		||||
  //    pressing C-N, C-P, compl_first_match points to the
 | 
			
		||||
  //    last entry before the entry with the CP_ORIGINAL_TEXT
 | 
			
		||||
  //    flag set and next-entry moves opposite through the list
 | 
			
		||||
  //    compared to case 2, so pretend the direction is forward again
 | 
			
		||||
  // 4) when first going backwards and then forwards, e.g.
 | 
			
		||||
  //    pressing C-P, C-N, compl_first_match points to the
 | 
			
		||||
  //    first entry with the CP_ORIGINAL_TEXT
 | 
			
		||||
  //    flag set and next-entry moves in opposite direction through the list
 | 
			
		||||
  //    compared to case 1, so pretend the direction is backwards again
 | 
			
		||||
  //
 | 
			
		||||
  // But only do this when the 'noselect' option is not active!
 | 
			
		||||
 | 
			
		||||
  if (!compl_no_select) {
 | 
			
		||||
    if (forward && !match_at_original_text(match)) {
 | 
			
		||||
      forward = false;
 | 
			
		||||
    } else if (!forward && match_at_original_text(match)) {
 | 
			
		||||
      forward = true;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Skip the element with the CP_ORIGINAL_TEXT flag at the beginning, in case of
 | 
			
		||||
  // forward completion, or at the end, in case of backward completion.
 | 
			
		||||
  compl_T *match = compl_dir_forward() ? compl_first_match->cp_next
 | 
			
		||||
                                       : compl_first_match->cp_prev->cp_prev;
 | 
			
		||||
  match = forward ? match->cp_next
 | 
			
		||||
                  : (compl_no_select ? match->cp_prev : match->cp_prev->cp_prev);
 | 
			
		||||
 | 
			
		||||
  while (match != NULL && !match_at_original_text(match)) {
 | 
			
		||||
    dict_T *di = tv_dict_alloc();
 | 
			
		||||
 | 
			
		||||
@@ -2722,7 +2753,7 @@ static int info_add_completion_info(list_T *li)
 | 
			
		||||
      tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    match = compl_dir_forward() ? match->cp_next : match->cp_prev;
 | 
			
		||||
    match = forward ? match->cp_next : match->cp_prev;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return OK;
 | 
			
		||||
 
 | 
			
		||||
@@ -2315,17 +2315,72 @@ func Test_complete_info_index()
 | 
			
		||||
  " Ensure 'index' in complete_info() is coherent with the 'items' array.
 | 
			
		||||
 | 
			
		||||
  set completeopt=menu,preview
 | 
			
		||||
  " Search forward.
 | 
			
		||||
  " Search forward
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("bbb", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("ccc", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("ddd", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("eee", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  " Search forward: unselected item
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call assert_equal(-1 , g:compl_info['selected'])
 | 
			
		||||
 | 
			
		||||
  " Search backward.
 | 
			
		||||
  " Search backward
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("eee", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("ddd", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("ccc", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("bbb", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  " search backwards: unselected item
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call assert_equal(-1 , g:compl_info['selected'])
 | 
			
		||||
 | 
			
		||||
  " switch direction: forwards, then backwards
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  " switch direction: forwards, then backwards, then forwards again
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-P>\<C-P>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
 | 
			
		||||
  " switch direction: backwards, then forwards
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  " switch direction: backwards, then forwards, then backwards again
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-N>\<C-N>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
 | 
			
		||||
  " Add 'noselect', check that 'selected' is -1 when nothing is selected.
 | 
			
		||||
  set completeopt+=noselect
 | 
			
		||||
@@ -2337,6 +2392,16 @@ func Test_complete_info_index()
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal(-1, g:compl_info['selected'])
 | 
			
		||||
 | 
			
		||||
  " Check if index out of range
 | 
			
		||||
  " https://github.com/vim/vim/pull/12971
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-P>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal(0, g:compl_info['selected'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
  call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
 | 
			
		||||
  call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
 | 
			
		||||
  call assert_equal(6 , len(g:compl_info['items']))
 | 
			
		||||
 | 
			
		||||
  set completeopt&
 | 
			
		||||
  bwipe!
 | 
			
		||||
endfunc
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user