patch 9.1.1341: cannot define completion triggers
Problem: Cannot define completion triggers and act upon it
Solution: add the new option 'isexpand' and add the complete_match()
function to return the completion matches according to the
'isexpand' setting (glepnir)
Currently, completion trigger position is determined solely by the
'iskeyword' pattern (\k\+$), which causes issues when users need
different completion behaviors - such as triggering after '/' for
comments or '.' for methods. Modifying 'iskeyword' to include these
characters has undesirable side effects on other Vim functionality that
relies on keyword definitions.
Introduce a new buffer-local option 'isexpand' that allows specifying
different completion triggers and add the complete_match() function that
finds the appropriate start column for completion based on these
triggers, scanning backwards from cursor position.
This separation of concerns allows customized completion behavior
without affecting iskeyword-dependent features. The option's
buffer-local nature enables per-filetype completion triggers.
closes: #16716
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 a087629..3d798e9 100644
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -229,6 +229,7 @@
\ 'imactivatekey': [['', 'S-space'], ['xxx']],
\ 'isfname': [['', '@', '@,48-52'], ['xxx', '@48']],
\ 'isident': [['', '@', '@,48-52'], ['xxx', '@48']],
+ \ 'isexpand': [['', '.,->', '/,/*,\\,'], [',,', '\\,,']],
\ 'iskeyword': [['', '@', '@,48-52'], ['xxx', '@48']],
\ 'isprint': [['', '@', '@,48-52'], ['xxx', '@48']],
\ 'jumpoptions': [['', 'stack'], ['xxx']],
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
index b03132f..73565a5 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -4328,4 +4328,86 @@
delfunc PrintMenuWords
endfunc
+func Test_complete_match()
+ set isexpand=.,/,->,abc,/*,_
+ func TestComplete()
+ let res = complete_match()
+ if res->len() == 0
+ return
+ endif
+ let [startcol, expandchar] = res[0]
+
+ if startcol >= 0
+ let line = getline('.')
+
+ let items = []
+ if expandchar == '/*'
+ let items = ['/** */']
+ elseif expandchar =~ '^/'
+ let items = ['/*! */', '// TODO:', '// fixme:']
+ elseif expandchar =~ '^\.' && startcol < 4
+ let items = ['length()', 'push()', 'pop()', 'slice()']
+ elseif expandchar =~ '^\.' && startcol > 4
+ let items = ['map()', 'filter()', 'reduce()']
+ elseif expandchar =~ '^\abc'
+ let items = ['def', 'ghk']
+ elseif expandchar =~ '^\->'
+ let items = ['free()', 'xfree()']
+ else
+ let items = ['test1', 'test2', 'test3']
+ endif
+
+ call complete(expandchar =~ '^/' ? startcol : startcol + strlen(expandchar), items)
+ endif
+ endfunc
+
+ new
+ inoremap <buffer> <F5> <cmd>call TestComplete()<CR>
+
+ call feedkeys("S/*\<F5>\<C-Y>", 'tx')
+ call assert_equal('/** */', getline('.'))
+
+ call feedkeys("S/\<F5>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('// TODO:', getline('.'))
+
+ call feedkeys("Swp.\<F5>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('wp.push()', getline('.'))
+
+ call feedkeys("Swp.property.\<F5>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('wp.property.filter()', getline('.'))
+
+ call feedkeys("Sp->\<F5>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('p->xfree()', getline('.'))
+
+ call feedkeys("Swp->property.\<F5>\<C-Y>", 'tx')
+ call assert_equal('wp->property.map()', getline('.'))
+
+ call feedkeys("Sabc\<F5>\<C-Y>", 'tx')
+ call assert_equal('abcdef', getline('.'))
+
+ call feedkeys("S_\<F5>\<C-Y>", 'tx')
+ call assert_equal('_test1', getline('.'))
+
+ set ise&
+ call feedkeys("Sabc \<ESC>:let g:result=complete_match()\<CR>", 'tx')
+ call assert_equal([[1, 'abc']], g:result)
+
+ call assert_fails('call complete_match(99, 0)', 'E966:')
+ call assert_fails('call complete_match(1, 99)', 'E964:')
+ call assert_fails('call complete_match(1)', 'E474:')
+
+ set ise=你好,好
+ call feedkeys("S你好 \<ESC>:let g:result=complete_match()\<CR>", 'tx')
+ call assert_equal([[1, '你好'], [4, '好']], g:result)
+
+ set ise=\\,,->
+ call feedkeys("Sabc, \<ESC>:let g:result=complete_match()\<CR>", 'tx')
+ call assert_equal([[4, ',']], g:result)
+
+ bw!
+ unlet g:result
+ set isexpand&
+ delfunc TestComplete
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab nofoldenable