changeset 26921:b975b7c16ba1 v8.2.3989

patch 8.2.3989: some insert completion code is not tested Commit: https://github.com/vim/vim/commit/e982586f8eebf2b055987218f6d3f7a084c4bf69 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Mon Jan 3 11:03:48 2022 +0000 patch 8.2.3989: some insert completion code is not tested Problem: Some insert completion code is not tested. Solution: Add a few tests. Refactor thesaurus completion. (Yegappan Lakshmanan, closes #9460)
author Bram Moolenaar <Bram@vim.org>
date Mon, 03 Jan 2022 12:15:03 +0100
parents eb2c9f5f376e
children a73b904a2dab
files src/insexpand.c src/testdir/test_edit.vim src/testdir/test_ins_complete.vim src/version.c
diffstat 4 files changed, 210 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -1017,6 +1017,10 @@ ins_compl_dict_alloc(compl_T *match)
     return dict;
 }
 
+/*
+ * Trigger the CompleteChanged autocmd event. Invoked each time the Insert mode
+ * completion menu is changed.
+ */
     static void
 trigger_complete_changed_event(int cur)
 {
@@ -1219,8 +1223,8 @@ ins_compl_show_pum(void)
 #define DICT_EXACT	(2)	// "dict" is the exact name of a file
 
 /*
- * Add any identifiers that match the given pattern in the list of dictionary
- * files "dict_start" to the list of completions.
+ * Add any identifiers that match the given pattern "pat" in the list of
+ * dictionary files "dict_start" to the list of completions.
  */
     static void
 ins_compl_dictionaries(
@@ -1346,6 +1350,66 @@ theend:
     vim_free(buf);
 }
 
+/*
+ * Add all the words in the line "*buf_arg" from the thesaurus file "fname"
+ * skipping the word at 'skip_word'.  Returns OK on success.
+ */
+    static int
+thesarurs_add_words_in_line(
+	char_u	*fname,
+	char_u	**buf_arg,
+	int	dir,
+	char_u	*skip_word)
+{
+    int		status = OK;
+    char_u	*ptr;
+    char_u	*wstart;
+
+    // Add the other matches on the line
+    ptr = *buf_arg;
+    while (!got_int)
+    {
+	// Find start of the next word.  Skip white
+	// space and punctuation.
+	ptr = find_word_start(ptr);
+	if (*ptr == NUL || *ptr == NL)
+	    break;
+	wstart = ptr;
+
+	// Find end of the word.
+	if (has_mbyte)
+	    // Japanese words may have characters in
+	    // different classes, only separate words
+	    // with single-byte non-word characters.
+	    while (*ptr != NUL)
+	    {
+		int l = (*mb_ptr2len)(ptr);
+
+		if (l < 2 && !vim_iswordc(*ptr))
+		    break;
+		ptr += l;
+	    }
+	else
+	    ptr = find_word_end(ptr);
+
+	// Add the word. Skip the regexp match.
+	if (wstart != skip_word)
+	{
+	    status = ins_compl_add_infercase(wstart, (int)(ptr - wstart), p_ic,
+							fname, dir, FALSE);
+	    if (status == FAIL)
+		break;
+	}
+    }
+
+    *buf_arg = ptr;
+    return status;
+}
+
+/*
+ * Process "count" dictionary/thesaurus "files" and add the text matching
+ * "regmatch".
+ */
     static void
 ins_compl_files(
     int		count,
@@ -1392,41 +1456,10 @@ ins_compl_files(
 			p_ic, files[i], *dir, FALSE);
 		if (thesaurus)
 		{
-		    char_u *wstart;
-
-		    // Add the other matches on the line
+		    // For a thesaurus, add all the words in the line
 		    ptr = buf;
-		    while (!got_int)
-		    {
-			// Find start of the next word.  Skip white
-			// space and punctuation.
-			ptr = find_word_start(ptr);
-			if (*ptr == NUL || *ptr == NL)
-			    break;
-			wstart = ptr;
-
-			// Find end of the word.
-			if (has_mbyte)
-			    // Japanese words may have characters in
-			    // different classes, only separate words
-			    // with single-byte non-word characters.
-			    while (*ptr != NUL)
-			    {
-				int l = (*mb_ptr2len)(ptr);
-
-				if (l < 2 && !vim_iswordc(*ptr))
-				    break;
-				ptr += l;
-			    }
-			else
-			    ptr = find_word_end(ptr);
-
-			// Add the word. Skip the regexp match.
-			if (wstart != regmatch->startp[0])
-			    add_r = ins_compl_add_infercase(wstart,
-				    (int)(ptr - wstart),
-				    p_ic, files[i], *dir, FALSE);
-		    }
+		    add_r = thesarurs_add_words_in_line(files[i], &ptr, *dir,
+							regmatch->startp[0]);
 		}
 		if (add_r == OK)
 		    // if dir was BACKWARD then honor it just once
@@ -1649,15 +1682,14 @@ ins_compl_bs(void)
 
     vim_free(compl_leader);
     compl_leader = vim_strnsave(line + compl_col, (p - line) - compl_col);
-    if (compl_leader != NULL)
-    {
-	ins_compl_new_leader();
-	if (compl_shown_match != NULL)
-	    // Make sure current match is not a hidden item.
-	    compl_curr_match = compl_shown_match;
-	return NUL;
-    }
-    return K_BS;
+    if (compl_leader == NULL)
+	return K_BS;
+
+    ins_compl_new_leader();
+    if (compl_shown_match != NULL)
+	// Make sure current match is not a hidden item.
+	compl_curr_match = compl_shown_match;
+    return NUL;
 }
 
 /*
@@ -2795,6 +2827,10 @@ ins_compl_mode(void)
     return (char_u *)"";
 }
 
+/*
+ * Assign the sequence number to all the completion matches which don't have
+ * one assigned yet.
+ */
     static void
 ins_compl_update_sequence_numbers()
 {
@@ -4853,6 +4889,9 @@ ins_complete(int c, int enable_pum)
     return OK;
 }
 
+/*
+ * Remove (if needed) and show the popup menu
+ */
     static void
 show_pum(int prev_w_wrow, int prev_w_leftcol)
 {
--- a/src/testdir/test_edit.vim
+++ b/src/testdir/test_edit.vim
@@ -733,8 +733,13 @@ func Test_edit_CTRL_N()
     call feedkeys("Ii\<c-n>\<cr>\<esc>", "tnix")
     call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
     call assert_equal(['INFER', 'loWER', 'infer', 'LOWER', '', ''], getline(1, '$'), e)
-
-    set noignorecase noinfercase complete&
+    set noignorecase noinfercase
+    %d
+    call setline(1, ['one word', 'two word'])
+    exe "normal! Goo\<C-P>\<C-X>\<C-P>"
+    call assert_equal('one word', getline(3))
+    %d
+    set complete&
     bw!
   endfor
 endfunc
@@ -900,6 +905,23 @@ func Test_edit_CTRL_T()
   bw!
 endfunc
 
+" Test thesaurus completion with different encodings
+func Test_thesaurus_complete_with_encoding()
+  call writefile(['angry furious mad enraged'], 'Xthesaurus')
+  set thesaurus=Xthesaurus
+  for e in ['latin1', 'utf-8']
+    exe 'set encoding=' .. e
+    new
+    call setline(1, 'mad')
+    call cursor(1, 1)
+    call feedkeys("A\<c-x>\<c-t>\<cr>\<esc>", 'tnix')
+    call assert_equal(['mad', ''], getline(1, '$'))
+    bw!
+  endfor
+  set thesaurus=
+  call delete('Xthesaurus')
+endfunc
+
 " Test 'thesaurusfunc'
 func MyThesaurus(findstart, base)
   let mythesaurus = [
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -709,6 +709,21 @@ func Test_complete_func_error()
   call assert_equal([], complete_info(['items']).items)
 endfunc
 
+" Test for recursively starting completion mode using complete()
+func Test_recursive_complete_func()
+  func ListColors()
+    call complete(5, ["red", "blue"])
+    return ''
+  endfunc
+  new
+  call setline(1, ['a1', 'a2'])
+  set complete=.
+  exe "normal Goa\<C-X>\<C-L>\<C-R>=ListColors()\<CR>\<C-N>"
+  call assert_equal('a2blue', getline(3))
+  delfunc ListColors
+  bw!
+endfunc
+
 " Test for completing words following a completed word in a line
 func Test_complete_wrapscan()
   " complete words from another buffer
@@ -932,6 +947,91 @@ func Test_issue_7021()
   set completeslash=
 endfunc
 
+" Test for 'longest' setting in 'completeopt' with latin1 and utf-8 encodings
+func Test_complete_longest_match()
+  for e in ['latin1', 'utf-8']
+    exe 'set encoding=' .. e
+    new
+    set complete=.
+    set completeopt=menu,longest
+    call setline(1, ['pfx_a1', 'pfx_a12', 'pfx_a123', 'pfx_b1'])
+    exe "normal Gopfx\<C-P>"
+    call assert_equal('pfx_', getline(5))
+    bw!
+  endfor
+
+  " Test for completing additional words with longest match set
+  new
+  call setline(1, ['abc1', 'abd2'])
+  exe "normal Goab\<C-P>\<C-X>\<C-P>"
+  call assert_equal('ab', getline(3))
+  bw!
+  set complete& completeopt&
+endfunc
+
+" Test for removing the first displayed completion match and selecting the
+" match just before that.
+func Test_complete_erase_firstmatch()
+  new
+  call setline(1, ['a12', 'a34', 'a56'])
+  set complete=.
+  exe "normal Goa\<C-P>\<BS>\<BS>3\<CR>"
+  call assert_equal('a34', getline('$'))
+  set complete&
+  bw!
+endfunc
+
+" Test for completing whole lines from unloaded buffers
+func Test_complete_wholeline_unloadedbuf()
+  call writefile(['a line1', 'a line2', 'a line3'], "Xfile1")
+  edit Xfile1
+  enew
+  set complete=u
+  exe "normal! ia\<C-X>\<C-L>\<C-P>"
+  call assert_equal('a line2', getline(1))
+  %d
+  " completing from an unlisted buffer should fail
+  bdel Xfile1
+  exe "normal! ia\<C-X>\<C-L>\<C-P>"
+  call assert_equal('a', getline(1))
+  set complete&
+  %bw!
+  call delete("Xfile1")
+endfunc
+
+" Test for completing whole lines from unlisted buffers
+func Test_complete_wholeline_unlistedbuf()
+  call writefile(['a line1', 'a line2', 'a line3'], "Xfile1")
+  edit Xfile1
+  enew
+  set complete=U
+  " completing from a unloaded buffer should fail
+  exe "normal! ia\<C-X>\<C-L>\<C-P>"
+  call assert_equal('a', getline(1))
+  %d
+  bdel Xfile1
+  exe "normal! ia\<C-X>\<C-L>\<C-P>"
+  call assert_equal('a line2', getline(1))
+  set complete&
+  %bw!
+  call delete("Xfile1")
+endfunc
+
+" Test for adding a multibyte character using CTRL-L in completion mode
+func Test_complete_mbyte_char_add()
+  new
+  set complete=.
+  call setline(1, 'abė')
+  exe "normal! oa\<C-P>\<BS>\<BS>\<C-L>\<C-L>"
+  call assert_equal('abė', getline(2))
+  " Test for a leader with multibyte character
+  %d
+  call setline(1, 'abėĕ')
+  exe "normal! oabė\<C-P>"
+  call assert_equal('abėĕ', getline(2))
+  bw!
+endfunc
+
 " Test to ensure 'Scanning...' messages are not recorded in messages history
 func Test_z1_complete_no_history()
   new
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3989,
+/**/
     3988,
 /**/
     3987,