Hi list. I have implemented wcwidth() function. Based commit was 7.2.444.
It is useful to get width of character, for e.g., when creating plugin which needs to align text not to exceed &columns, or which needs to concern character width like tetris game :) I'm new to hack Vim source. So please tell me if I did it wrongly. -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 1e7d6f3..98407f1 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1932,6 +1932,8 @@ type( {name}) Number type of variable {name} values( {dict}) List values in {dict} virtcol( {expr}) Number screen column of cursor or mark visualmode( [expr]) String last visual mode used +wcwidth( {expr}) + Number the number of display cells String {expr} occupies winbufnr( {nr}) Number buffer number of window {nr} wincol() Number window column of the cursor winheight( {nr}) Number height of window {nr} @@ -5669,6 +5671,14 @@ visualmode([expr]) *visualmode()* Dictionary or Float is not a Number or String, thus does not cause the mode to be cleared. + *wcwidth()* +wcwidth( {expr}) The result is a Number, which is + the number of display cells String {expr} occupies. + When {expr} contains characters with East Asian Width Class + Ambiguous, this function's return value depends on 'ambiwidth'. + If 'ambiwidth' is "single", wcwidth() counts that character as 1. + If 'ambiwidth' is "double", wcwidth() counts that character as 2. + *winbufnr()* winbufnr({nr}) The result is a Number, which is the number of the buffer associated with window {nr}. When {nr} is zero, the number of diff --git a/src/eval.c b/src/eval.c index 32e3d20..7ed5403 100644 --- a/src/eval.c +++ b/src/eval.c @@ -717,6 +717,7 @@ static void f_type __ARGS((typval_T *argvars, typval_T *rettv)); static void f_values __ARGS((typval_T *argvars, typval_T *rettv)); static void f_virtcol __ARGS((typval_T *argvars, typval_T *rettv)); static void f_visualmode __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_wcwidth __ARGS((typval_T *argvars, typval_T *rettv)); static void f_winbufnr __ARGS((typval_T *argvars, typval_T *rettv)); static void f_wincol __ARGS((typval_T *argvars, typval_T *rettv)); static void f_winheight __ARGS((typval_T *argvars, typval_T *rettv)); @@ -7795,6 +7796,7 @@ static struct fst {"values", 1, 1, f_values}, {"virtcol", 1, 1, f_virtcol}, {"visualmode", 0, 1, f_visualmode}, + {"wcwidth", 1, 1, f_wcwidth}, {"winbufnr", 1, 1, f_winbufnr}, {"wincol", 0, 0, f_wincol}, {"winheight", 1, 1, f_winheight}, @@ -17360,6 +17362,18 @@ f_visualmode(argvars, rettv) } /* + * "wcwidth()" function + */ + static void +f_wcwidth(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + char_u *str = get_tv_string(&argvars[0]); + rettv->vval.v_number = (varnumber_T)MB_CHARWIDTH(str); +} + +/* * "winbufnr(nr)" function */ static void diff --git a/src/macros.h b/src/macros.h index 51e4dd4..d974d86 100644 --- a/src/macros.h +++ b/src/macros.h @@ -285,6 +285,7 @@ # define MB_COPY_CHAR(f, t) if (has_mbyte) mb_copy_char(&f, &t); else *t++ = *f++ # define MB_CHARLEN(p) (has_mbyte ? mb_charlen(p) : (int)STRLEN(p)) +# define MB_CHARWIDTH(p) (has_mbyte ? mb_charwidth(p) : (int)STRLEN(p)) # define PTR2CHAR(p) (has_mbyte ? mb_ptr2char(p) : (int)*(p)) #else # define mb_ptr_adv(p) ++p @@ -292,6 +293,7 @@ # define mb_ptr_back(s, p) --p # define MB_COPY_CHAR(f, t) *t++ = *f++ # define MB_CHARLEN(p) STRLEN(p) +# define MB_CHARWIDTH(p) STRLEN(p) # define PTR2CHAR(p) ((int)*(p)) #endif diff --git a/src/mbyte.c b/src/mbyte.c index 7a3a27e..5985a6b 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -3607,6 +3607,36 @@ mb_charlen(str) return count; } +/* + * Return the number of display cells "str" occupies. + */ + int +mb_charwidth(str) + char_u *str; +{ + int len; + int clen; + char_u *im_str, *p; + + len = (int)STRLEN(str); + + if (input_conv.vc_type != CONV_NONE) + { + im_str = string_convert(&input_conv, (char_u *)str, &len); + if (im_str == NULL) + return; + } + else + im_str = (char_u *)str; + clen = 0; + for (p = im_str; p < im_str + len; p += (*mb_ptr2len)(p)) + clen += (*mb_ptr2cells)(p); + if (input_conv.vc_type != CONV_NONE) + vim_free(im_str); + + return clen; +} + #if defined(FEAT_SPELL) || defined(PROTO) /* * Like mb_charlen() but for a string with specified length. @@ -4367,10 +4397,7 @@ im_commit_cb(GtkIMContext *context UNUSED, { int slen = (int)STRLEN(str); int add_to_input = TRUE; - int clen; - int len = slen; int commit_with_preedit = TRUE; - char_u *im_str, *p; #ifdef XIM_DEBUG xim_log("im_commit_cb(): %s\n", str); @@ -4396,19 +4423,7 @@ im_commit_cb(GtkIMContext *context UNUSED, * flushed to screen, then it can't get correct "preedit_start_col". * Thus, it should calculate the cells by adding cells of the committed * string. */ - if (input_conv.vc_type != CONV_NONE) - { - im_str = string_convert(&input_conv, (char_u *)str, &len); - g_return_if_fail(im_str != NULL); - } - else - im_str = (char_u *)str; - clen = 0; - for (p = im_str; p < im_str + len; p += (*mb_ptr2len)(p)) - clen += (*mb_ptr2cells)(p); - if (input_conv.vc_type != CONV_NONE) - vim_free(im_str); - preedit_start_col += clen; + preedit_start_col += MB_CHARWIDTH(str); /* Is this a single character that matches a keypad key that's just * been pressed? If so, we don't want it to be entered as such - let