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/optionstr.c b/src/optionstr.c
index 90b8e52..f60957e 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -310,6 +310,7 @@
     check_string_option(&buf->b_p_cinw);
     check_string_option(&buf->b_p_cot);
     check_string_option(&buf->b_p_cpt);
+    check_string_option(&buf->b_p_ise);
 #ifdef FEAT_COMPL_FUNC
     check_string_option(&buf->b_p_cfu);
     check_string_option(&buf->b_p_ofu);
@@ -2865,6 +2866,48 @@
 #endif
 
 /*
+ * The 'isexpand' option is changed.
+ */
+    char *
+did_set_isexpand(optset_T *args)
+{
+    char_u  *ise = p_ise;
+    char_u  *p;
+    int     last_was_comma = FALSE;
+
+    if (args->os_flags & OPT_LOCAL)
+	ise = curbuf->b_p_ise;
+
+    for (p = ise; *p != NUL;)
+    {
+	if (*p == '\\' && p[1] == ',')
+	{
+	    p += 2;
+	    last_was_comma = FALSE;
+	    continue;
+	}
+
+	if (*p == ',')
+	{
+	    if (last_was_comma)
+		return e_invalid_argument;
+	    last_was_comma = TRUE;
+	    p++;
+	    continue;
+	}
+
+	last_was_comma = FALSE;
+	MB_PTR_ADV(p);
+    }
+
+    if (last_was_comma)
+	return e_invalid_argument;
+
+    return NULL;
+}
+
+
+/*
  * The 'iskeyword' option is changed.
  */
     char *