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/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index e6747ad..9f91f47 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -1,4 +1,4 @@
-*builtin.txt*	For Vim version 9.1.  Last change: 2025 Apr 23
+*builtin.txt*	For Vim version 9.1.  Last change: 2025 Apr 24
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -136,6 +136,7 @@
 complete_add({expr})		Number	add completion match
 complete_check()		Number	check for key typed during completion
 complete_info([{what}])		Dict	get current completion information
+complete_match([{lnum}, {col}])	List	get completion column and trigger text
 confirm({msg} [, {choices} [, {default} [, {type}]]])
 				Number	number of choice picked by user
 copy({expr})			any	make a shallow copy of {expr}
@@ -2032,6 +2033,50 @@
 <
 		Return type: dict<any>
 
+complete_match([{lnum}, {col}])			*complete_match()*
+		Returns a List of matches found according to the 'isexpand'
+		option. Each match is represented as a List containing
+		[startcol, trigger_text] where:
+		- startcol: column position where completion should start,
+		  or -1 if no trigger position is found. For multi-character
+		  triggers, returns the column of the first character.
+		- trigger_text: the matching trigger string from 'isexpand',
+		  or empty string if no match was found or when using the
+		  default 'iskeyword' pattern.
+
+		When 'isexpand' is empty, uses the 'iskeyword' pattern
+		"\k\+$" to find the start of the current keyword.
+
+		When no arguments are provided, uses the current cursor
+		position.
+
+		Examples: >
+	set isexpand=.,->,/,/*,abc
+	func CustomComplete()
+	  let res = complete_match()
+	  if res->len() == 0 | return | endif
+	  let [col, trigger] = res[0]
+	  let items = []
+	  if trigger == '/*'
+	    let items = ['/** */']
+	  elseif trigger == '/'
+	    let items = ['/*! */', '// TODO:', '// fixme:']
+	  elseif trigger == '.'
+	    let items = ['length()']
+	  elseif trigger =~ '^\->'
+	    let items = ['map()', 'reduce()']
+	  elseif trigger =~ '^\abc'
+	    let items = ['def', 'ghk']
+	  endif
+	  if items->len() > 0
+	    let startcol = trigger =~ '^/' ? col : col + len(trigger)
+	    call complete(startcol, items)
+	  endif
+	endfunc
+	inoremap <Tab> <Cmd>call CustomComplete()<CR>
+<
+		Return type: list<list<any>>
+
 						*confirm()*
 confirm({msg} [, {choices} [, {default} [, {type}]]])
 		confirm() offers the user a dialog, from which a choice can be