0
0
mirror of https://github.com/vim/vim.git synced 2025-09-28 04:24:06 -04:00

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)
This commit is contained in:
mityu
2021-07-19 20:07:21 +02:00
committed by Bram Moolenaar
parent 98c2eaed27
commit 6106504e9e
11 changed files with 583 additions and 37 deletions

View File

@@ -1992,6 +1992,65 @@ getdigraph(int char1, int char2, int meta_char)
return retval;
}
/*
* 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));
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 *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