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