summaryrefslogtreecommitdiffstats
path: root/src/digraph.c
diff options
context:
space:
mode:
authormityu <mityu.mail@gmail.com>2021-07-19 20:07:21 +0200
committerBram Moolenaar <Bram@vim.org>2021-07-19 20:07:21 +0200
commit6106504e9edc8500131f7a36e59bc146f90180fa (patch)
tree69249dd7c9375375cb414ea31e3b5523e8947344 /src/digraph.c
parent98c2eaed27579602e05e7b96aa3a60428a8b9cb2 (diff)
patch 8.2.3184: cannot add a digraph with a leading spacev8.2.3184
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)
Diffstat (limited to 'src/digraph.c')
-rw-r--r--src/digraph.c388
1 files changed, 353 insertions, 35 deletions
diff --git a/src/digraph.c b/src/digraph.c
index fd78a16ecd..9b1836eef0 100644
--- a/src/digraph.c
+++ b/src/digraph.c
@@ -1993,6 +1993,65 @@ getdigraph(int char1, int char2, int meta_char)
}
/*
+ * 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 meta_char)
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));
- return;
- }
- if (char1 == ESC || char2 == ESC)
- {
- emsg(_("E104: Escape not allowed in digraph"));
+
+ if (!check_digraph_chars_valid(char1, char2))
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 *previous)
}
}
+# 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