diff src/digraph.c @ 25294:c626fd34b66f v8.2.3184

patch 8.2.3184: cannot add a digraph with a leading space Commit: https://github.com/vim/vim/commit/6106504e9edc8500131f7a36e59bc146f90180fa Author: mityu <mityu.mail@gmail.com> Date: Mon Jul 19 20:07:21 2021 +0200 patch 8.2.3184: cannot add a digraph with a leading space Problem: Cannot add a digraph with a leading space. It is not easy to list existing digraphs. Solution: Add setdigraph(), setdigraphlist(), getdigraph() and getdigraphlist(). (closes #8580)
author Bram Moolenaar <Bram@vim.org>
date Mon, 19 Jul 2021 20:15:04 +0200
parents 1b23391fac7e
children 078edc1821bf
line wrap: on
line diff
--- a/src/digraph.c
+++ b/src/digraph.c
@@ -1993,6 +1993,65 @@ getdigraph(int char1, int char2, int met
 }
 
 /*
+ * Add a digraph to the digraph table.
+ */
+    static void
+registerdigraph(int char1, int char2, int n)
+{
+    int		i;
+    digr_T	*dp;
+
+    // If the digraph already exists, replace "result".
+    dp = (digr_T *)user_digraphs.ga_data;
+    for (i = 0; i < user_digraphs.ga_len; ++i)
+    {
+	if ((int)dp->char1 == char1 && (int)dp->char2 == char2)
+	{
+	    dp->result = n;
+	    return;
+	}
+	++dp;
+    }
+
+    // Add a new digraph to the table.
+    if (ga_grow(&user_digraphs, 1) == OK)
+    {
+	dp = (digr_T *)user_digraphs.ga_data + user_digraphs.ga_len;
+	dp->char1 = char1;
+	dp->char2 = char2;
+	dp->result = n;
+	++user_digraphs.ga_len;
+    }
+}
+
+/*
+ * Check the characters are valid for a digraph.
+ * If they are valid, returns TRUE; otherwise, give an error message and
+ * returns FALSE.
+ */
+    int
+check_digraph_chars_valid(int char1, int char2)
+{
+    if (char2 == 0)
+    {
+	char_u msg[MB_MAXBYTES + 1];
+
+	msg[mb_char2bytes(char1, msg)] = NUL;
+
+	semsg(_(e_digraph_must_be_just_two_characters_str), msg);
+	return FALSE;
+    }
+    if (char1 == ESC || char2 == ESC)
+    {
+	emsg(_("E104: Escape not allowed in digraph"));
+	return FALSE;
+    }
+    return TRUE;
+}
+
+
+
+/*
  * Add the digraphs in the argument to the digraph table.
  * format: {c1}{c2} char {c1}{c2} char ...
  */
@@ -2000,8 +2059,6 @@ getdigraph(int char1, int char2, int met
 putdigraph(char_u *str)
 {
     int		char1, char2, n;
-    int		i;
-    digr_T	*dp;
 
     while (*str != NUL)
     {
@@ -2010,16 +2067,10 @@ putdigraph(char_u *str)
 	    return;
 	char1 = *str++;
 	char2 = *str++;
-	if (char2 == 0)
-	{
-	    emsg(_(e_invarg));
+
+	if (!check_digraph_chars_valid(char1, char2))
 	    return;
-	}
-	if (char1 == ESC || char2 == ESC)
-	{
-	    emsg(_("E104: Escape not allowed in digraph"));
-	    return;
-	}
+
 	str = skipwhite(str);
 	if (!VIM_ISDIGIT(*str))
 	{
@@ -2028,30 +2079,7 @@ putdigraph(char_u *str)
 	}
 	n = getdigits(&str);
 
-	// If the digraph already exists, replace the result.
-	dp = (digr_T *)user_digraphs.ga_data;
-	for (i = 0; i < user_digraphs.ga_len; ++i)
-	{
-	    if ((int)dp->char1 == char1 && (int)dp->char2 == char2)
-	    {
-		dp->result = n;
-		break;
-	    }
-	    ++dp;
-	}
-
-	// Add a new digraph to the table.
-	if (i == user_digraphs.ga_len)
-	{
-	    if (ga_grow(&user_digraphs, 1) == OK)
-	    {
-		dp = (digr_T *)user_digraphs.ga_data + user_digraphs.ga_len;
-		dp->char1 = char1;
-		dp->char2 = char2;
-		dp->result = n;
-		++user_digraphs.ga_len;
-	    }
-	}
+	registerdigraph(char1, char2, n);
     }
 }
 
@@ -2114,6 +2142,97 @@ listdigraphs(int use_headers)
 			    // wrong, in which case we messed up ScreenLines
 }
 
+    static void
+getdigraphlist_appendpair(digr_T *dp, list_T *l)
+{
+    char_u	buf[30];
+    char_u	*p;
+    list_T	*l2;
+    listitem_T	*li, *li2;
+
+
+    li = listitem_alloc();
+    if (li == NULL)
+	return;
+    list_append(l, li);
+    li->li_tv.v_type = VAR_LIST;
+    li->li_tv.v_lock = 0;
+
+    l2 = list_alloc();
+    li->li_tv.vval.v_list = l2;
+    if (l2 == NULL)
+	return;
+    ++l2->lv_refcount;
+
+    li2 = listitem_alloc();
+    if (li2 == NULL)
+	return;
+    list_append(l2, li2);
+    li2->li_tv.v_type = VAR_STRING;
+    li2->li_tv.v_lock = 0;
+
+    buf[0] = dp->char1;
+    buf[1] = dp->char2;
+    buf[2] = NUL;
+    li2->li_tv.vval.v_string = vim_strsave(&buf[0]);
+
+    li2 = listitem_alloc();
+    if (li2 == NULL)
+	return;
+    list_append(l2, li2);
+    li2->li_tv.v_type = VAR_STRING;
+    li2->li_tv.v_lock = 0;
+
+    p = buf;
+    if (has_mbyte)
+	p += (*mb_char2bytes)(dp->result, p);
+    else
+	*p++ = (char_u)dp->result;
+    *p = NUL;
+
+    li2->li_tv.vval.v_string = vim_strsave(buf);
+}
+
+    void
+getdigraphlist_common(int list_all, typval_T *rettv)
+{
+    int		i;
+    digr_T	*dp;
+
+    if (rettv_list_alloc(rettv) == FAIL)
+	return;
+
+    if (list_all)
+    {
+	dp = digraphdefault;
+	for (i = 0; dp->char1 != NUL && !got_int; ++i)
+	{
+#ifdef USE_UNICODE_DIGRAPHS
+	    digr_T tmp;
+
+	    tmp.char1 = dp->char1;
+	    tmp.char2 = dp->char2;
+	    tmp.result = getexactdigraph(tmp.char1, tmp.char2, FALSE);
+	    if (tmp.result != 0 && tmp.result != tmp.char2
+					  && (has_mbyte || tmp.result <= 255))
+		getdigraphlist_appendpair(&tmp, rettv->vval.v_list);
+#else
+	    if (getexactdigraph(dp->char1, dp->char2, FALSE) == dp->result
+		    && (has_mbyte || dp->result <= 255))
+		getdigraphlist_appendpair(dp, rettv->vval.v_list);
+#endif
+	    ++dp;
+	}
+    }
+
+    dp = (digr_T *)user_digraphs.ga_data;
+    for (i = 0; i < user_digraphs.ga_len && !got_int; ++i)
+    {
+	getdigraphlist_appendpair(dp, rettv->vval.v_list);
+	++dp;
+    }
+}
+
 static struct dg_header_entry {
     int	    dg_start;
     char    *dg_header;
@@ -2210,8 +2329,207 @@ printdigraph(digr_T *dp, result_T *previ
     }
 }
 
+# ifdef FEAT_EVAL
+/*
+ * Get the two digraph characters from a typval.
+ * Return OK or FAIL.
+ */
+    static int
+get_digraph_chars(typval_T *arg, int *char1, int *char2)
+{
+    char_u	buf_chars[NUMBUFLEN];
+    char_u	*chars = tv_get_string_buf_chk(arg, buf_chars);
+    char_u	*p = chars;
+
+    if (p != NULL)
+    {
+	if (*p != NUL)
+	{
+	    *char1 = mb_cptr2char_adv(&p);
+	    if (*p != NUL)
+	    {
+		*char2 = mb_cptr2char_adv(&p);
+		if (*p == NUL)
+		{
+		    if (check_digraph_chars_valid(*char1, *char2))
+			return OK;
+		    return FAIL;
+		}
+	    }
+	}
+    }
+    semsg(_(e_digraph_must_be_just_two_characters_str), chars);
+    return FAIL;
+}
+
+    static int
+setdigraph_common(typval_T *argchars, typval_T *argdigraph)
+{
+    int		char1, char2;
+    char_u	*digraph;
+    char_u	*p;
+    char_u	buf_digraph[NUMBUFLEN];
+    varnumber_T n;
+
+    if (get_digraph_chars(argchars, &char1, &char2) == FAIL)
+	return FALSE;
+
+    digraph = tv_get_string_buf_chk(argdigraph, buf_digraph);
+    if (digraph == NULL)
+	return FALSE;
+    p = digraph;
+    n = mb_cptr2char_adv(&p);
+    if (*p != NUL)
+    {
+	semsg(_(e_digraph_argument_must_be_one_character_str), digraph);
+	return FALSE;
+    }
+
+    registerdigraph(char1, char2, (int)n);
+    return TRUE;
+}
+# endif
+
 #endif // FEAT_DIGRAPHS
 
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * "getdigraph()" function
+ */
+    void
+f_getdigraph(typval_T *argvars, typval_T *rettv)
+{
+# ifdef FEAT_DIGRAPHS
+    int		code;
+    char_u	buf[NUMBUFLEN];
+    char_u	*digraphs;
+
+    rettv->v_type = VAR_STRING;
+    rettv->vval.v_string = NULL;  // Return empty string for failure
+    digraphs = tv_get_string_chk(&argvars[0]);
+
+    if (digraphs == NULL)
+	return;
+    else if (STRLEN(digraphs) != 2)
+    {
+	semsg(_(e_digraph_must_be_just_two_characters_str), digraphs);
+	return;
+    }
+    code = getdigraph(digraphs[0], digraphs[1], FALSE);
+
+    if (has_mbyte)
+	buf[(*mb_char2bytes)(code, buf)] = NUL;
+    else {
+	buf[0] = code;
+	buf[1] = NUL;
+    }
+
+    rettv->vval.v_string = vim_strsave(buf);
+# else
+    emsg(_(e_no_digraphs_version));
+# endif
+}
+
+/*
+ * "getdigraphlist()" function
+ */
+    void
+f_getdigraphlist(typval_T *argvars, typval_T *rettv)
+{
+# ifdef FEAT_DIGRAPHS
+    int     flag_list_all;
+
+    if (argvars[0].v_type == VAR_UNKNOWN)
+	flag_list_all = FALSE;
+    else
+    {
+	int         error = FALSE;
+	varnumber_T flag = tv_get_number_chk(&argvars[0], &error);
+	if (error)
+	    return;
+	flag_list_all = flag ? TRUE : FALSE;
+    }
+
+    getdigraphlist_common(flag_list_all, rettv);
+# else
+    emsg(_(e_no_digraphs_version));
+# endif
+}
+
+/*
+ * "setdigraph()" function
+ */
+    void
+f_setdigraph(typval_T *argvars, typval_T *rettv)
+{
+# ifdef FEAT_DIGRAPHS
+    rettv->v_type = VAR_BOOL;
+    rettv->vval.v_number = VVAL_FALSE;
+
+    if (!setdigraph_common(&argvars[0], &argvars[1]))
+	return;
+
+    rettv->vval.v_number = VVAL_TRUE;
+# else
+    emsg(_(e_no_digraphs_version));
+# endif
+}
+
+/*
+ * "setdigraphlist()" function
+ */
+    void
+f_setdigraphlist(typval_T * argvars, typval_T *rettv)
+{
+# ifdef FEAT_DIGRAPHS
+    list_T	*pl, *l;
+    listitem_T	*pli;
+
+    rettv->v_type = VAR_BOOL;
+    rettv->vval.v_number = VVAL_FALSE;
+
+    if (argvars[0].v_type != VAR_LIST)
+    {
+	emsg(_(e_setdigraphlist_argument_must_be_list_of_lists_with_two_items));
+	return;
+    }
+
+    pl = argvars[0].vval.v_list;
+    if (pl == NULL)
+    {
+	// Empty list always results in success.
+	rettv->vval.v_number = VVAL_TRUE;
+	return;
+    }
+
+    FOR_ALL_LIST_ITEMS(pl, pli)
+    {
+	if (pli->li_tv.v_type != VAR_LIST)
+	{
+	    emsg(_(e_setdigraphlist_argument_must_be_list_of_lists_with_two_items));
+	    return;
+	}
+
+	l = pli->li_tv.vval.v_list;
+	if (l == NULL || l->lv_len != 2)
+	{
+	    emsg(_(e_setdigraphlist_argument_must_be_list_of_lists_with_two_items));
+	    return;
+	}
+
+	if (!setdigraph_common(&l->lv_first->li_tv,
+						 &l->lv_first->li_next->li_tv))
+	    return;
+    }
+    rettv->vval.v_number = VVAL_TRUE;
+# else
+    emsg(_(e_no_digraphs_version));
+# endif
+}
+
+#endif // FEAT_EVAL
+
+
 #if defined(FEAT_KEYMAP) || defined(PROTO)
 
 // structure used for b_kmap_ga.ga_data