patch 9.1.1056: Vim doesn't highlight to be inserted text when completing

Problem:  Vim doesn't highlight to be inserted text when completing
Solution: Add support for the "preinsert" 'completeopt' value
          (glepnir)

Support automatically inserting the currently selected candidate word
that does not belong to the latter part of the leader.

fixes: #3433
closes: #16403

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim
index 7a4ffa8..30de286 100644
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -155,7 +155,7 @@
       \		['xxx']],
       \ 'concealcursor': [['', 'n', 'v', 'i', 'c', 'nvic'], ['xxx']],
       \ 'completeopt': [['', 'menu', 'menuone', 'longest', 'preview', 'popup',
-      \		'popuphidden', 'noinsert', 'noselect', 'fuzzy', 'menu,longest'],
+      \		'popuphidden', 'noinsert', 'noselect', 'fuzzy', "preinsert", 'menu,longest'],
       \		['xxx', 'menu,,,longest,']],
       \ 'completeitemalign': [['abbr,kind,menu', 'menu,abbr,kind'],
       \		['', 'xxx', 'abbr', 'abbr,menu', 'abbr,menu,kind,abbr',
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
index 466e358..e4bc98a 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -3025,4 +3025,121 @@
   set cot&
 endfunc
 
+function Test_completeopt_preinsert()
+  func Omni_test(findstart, base)
+    if a:findstart
+      return col(".")
+    endif
+    return [#{word: "fobar"}, #{word: "foobar"}, #{word: "你的"}, #{word: "你好世界"}]
+  endfunc
+  set omnifunc=Omni_test
+  set completeopt=menu,menuone,preinsert
+
+  new
+  call feedkeys("S\<C-X>\<C-O>f", 'tx')
+  call assert_equal("fobar", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  call feedkeys("S\<C-X>\<C-O>foo", 'tx')
+  call assert_equal("foobar", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  call feedkeys("S\<C-X>\<C-O>foo\<BS>\<BS>\<BS>", 'tx')
+  call assert_equal("", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  " delete a character and input new leader
+  call feedkeys("S\<C-X>\<C-O>foo\<BS>b", 'tx')
+  call assert_equal("fobar", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  " delete preinsert when prepare completion
+  call feedkeys("S\<C-X>\<C-O>f\<Space>", 'tx')
+  call assert_equal("f ", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  call feedkeys("S\<C-X>\<C-O>你", 'tx')
+  call assert_equal("你的", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  call feedkeys("S\<C-X>\<C-O>你好", 'tx')
+  call assert_equal("你好世界", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  call feedkeys("Shello   wo\<Left>\<Left>\<Left>\<C-X>\<C-O>f", 'tx')
+  call assert_equal("hello  fobar wo", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  call feedkeys("Shello   wo\<Left>\<Left>\<Left>\<C-X>\<C-O>f\<BS>", 'tx')
+  call assert_equal("hello   wo", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  call feedkeys("Shello   wo\<Left>\<Left>\<Left>\<C-X>\<C-O>foo", 'tx')
+  call assert_equal("hello  foobar wo", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  call feedkeys("Shello   wo\<Left>\<Left>\<Left>\<C-X>\<C-O>foo\<BS>b", 'tx')
+  call assert_equal("hello  fobar wo", getline('.'))
+  call feedkeys("\<C-E>\<ESC>", 'tx')
+
+  " confrim
+  call feedkeys("S\<C-X>\<C-O>f\<C-Y>", 'tx')
+  call assert_equal("fobar", getline('.'))
+  call assert_equal(5, col('.'))
+
+  " cancel
+  call feedkeys("S\<C-X>\<C-O>fo\<C-E>", 'tx')
+  call assert_equal("fo", getline('.'))
+  call assert_equal(2, col('.'))
+
+  call feedkeys("S hello hero\<CR>h\<C-X>\<C-N>", 'tx')
+  call assert_equal("hello", getline('.'))
+  call assert_equal(1, col('.'))
+
+  call feedkeys("Sh\<C-X>\<C-N>\<C-Y>", 'tx')
+  call assert_equal("hello", getline('.'))
+  call assert_equal(5, col('.'))
+
+  " delete preinsert part
+  call feedkeys("S\<C-X>\<C-O>fo ", 'tx')
+  call assert_equal("fo ", getline('.'))
+  call assert_equal(3, col('.'))
+
+  " whole line
+  call feedkeys("Shello hero\<CR>\<C-X>\<C-L>", 'tx')
+  call assert_equal("hello hero", getline('.'))
+  call assert_equal(1, col('.'))
+
+  call feedkeys("Shello hero\<CR>he\<C-X>\<C-L>", 'tx')
+  call assert_equal("hello hero", getline('.'))
+  call assert_equal(2, col('.'))
+
+  " can not work with fuzzy
+  set cot+=fuzzy
+  call feedkeys("S\<C-X>\<C-O>", 'tx')
+  call assert_equal("fobar", getline('.'))
+  call assert_equal(5, col('.'))
+
+  " test for fuzzy and noinsert
+  set cot+=noinsert
+  call feedkeys("S\<C-X>\<C-O>fb", 'tx')
+  call assert_equal("fb", getline('.'))
+  call assert_equal(2, col('.'))
+
+  call feedkeys("S\<C-X>\<C-O>你", 'tx')
+  call assert_equal("你", getline('.'))
+  call assert_equal(1, col('.'))
+
+  call feedkeys("S\<C-X>\<C-O>fb\<C-Y>", 'tx')
+  call assert_equal("fobar", getline('.'))
+  call assert_equal(5, col('.'))
+
+  bw!
+  bw!
+  set cot&
+  set omnifunc&
+  delfunc Omni_test
+  autocmd! CompleteChanged
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab nofoldenable