0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 9.0.1598: screenchar() and others are wrong with DBCS 'encoding'

Problem:    screenchar(), screenchars() and screenstring() do not work
            properly when 'encoding' is set to a double-byte encoding.
Solution:   Fix the way the bytes of the characters are obtained.
            (issue #12469)
This commit is contained in:
zeertzjq 2023-06-01 20:26:55 +01:00 committed by Bram Moolenaar
parent 8509014add
commit 47eec6716b
5 changed files with 58 additions and 35 deletions

View File

@ -8934,7 +8934,6 @@ f_screenchar(typval_T *argvars, typval_T *rettv)
{ {
int row; int row;
int col; int col;
int off;
int c; int c;
if (in_vim9script() if (in_vim9script()
@ -8948,11 +8947,9 @@ f_screenchar(typval_T *argvars, typval_T *rettv)
c = -1; c = -1;
else else
{ {
off = LineOffset[row] + col; char_u buf[MB_MAXBYTES + 1];
if (enc_utf8 && ScreenLinesUC[off] != 0) screen_getbytes(row, col, buf, NULL);
c = ScreenLinesUC[off]; c = (*mb_ptr2char)(buf);
else
c = ScreenLines[off];
} }
rettv->vval.v_number = c; rettv->vval.v_number = c;
} }
@ -8965,7 +8962,6 @@ f_screenchars(typval_T *argvars, typval_T *rettv)
{ {
int row; int row;
int col; int col;
int off;
int c; int c;
int i; int i;
@ -8982,18 +8978,18 @@ f_screenchars(typval_T *argvars, typval_T *rettv)
if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns) if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
return; return;
off = LineOffset[row] + col; char_u buf[MB_MAXBYTES + 1];
if (enc_utf8 && ScreenLinesUC[off] != 0) screen_getbytes(row, col, buf, NULL);
c = ScreenLinesUC[off]; int pcc[MAX_MCO];
if (enc_utf8)
c = utfc_ptr2char(buf, pcc);
else else
c = ScreenLines[off]; c = (*mb_ptr2char)(buf);
list_append_number(rettv->vval.v_list, (varnumber_T)c); list_append_number(rettv->vval.v_list, (varnumber_T)c);
if (enc_utf8) if (enc_utf8)
for (i = 0; i < Screen_mco && pcc[i] != 0; ++i)
for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i) list_append_number(rettv->vval.v_list, (varnumber_T)pcc[i]);
list_append_number(rettv->vval.v_list,
(varnumber_T)ScreenLinesC[i][off]);
} }
/* /*
@ -9024,11 +9020,7 @@ f_screenstring(typval_T *argvars, typval_T *rettv)
{ {
int row; int row;
int col; int col;
int off;
int c;
int i;
char_u buf[MB_MAXBYTES + 1]; char_u buf[MB_MAXBYTES + 1];
int buflen = 0;
rettv->vval.v_string = NULL; rettv->vval.v_string = NULL;
rettv->v_type = VAR_STRING; rettv->v_type = VAR_STRING;
@ -9043,18 +9035,7 @@ f_screenstring(typval_T *argvars, typval_T *rettv)
if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns) if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
return; return;
off = LineOffset[row] + col; screen_getbytes(row, col, buf, NULL);
if (enc_utf8 && ScreenLinesUC[off] != 0)
c = ScreenLinesUC[off];
else
c = ScreenLines[off];
buflen += mb_char2bytes(c, buf);
if (enc_utf8 && ScreenLinesUC[off] != 0)
for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
buf[buflen] = NUL;
rettv->vval.v_string = vim_strsave(buf); rettv->vval.v_string = vim_strsave(buf);
} }
@ -9433,7 +9414,7 @@ f_searchpos(typval_T *argvars, typval_T *rettv)
/* /*
* Set the cursor or mark position. * Set the cursor or mark position.
* If 'charpos' is TRUE, then use the column number as a character offset. * If "charpos" is TRUE, then use the column number as a character offset.
* Otherwise use the column number as a byte offset. * Otherwise use the column number as a byte offset.
*/ */
static void static void

View File

@ -1199,8 +1199,9 @@ screen_putchar(int c, int row, int col, int attr)
} }
/* /*
* Get a single character directly from ScreenLines into "bytes[]". * Get a single character directly from ScreenLines into "bytes", which must
* Also return its attribute in *attrp; * have a size of "MB_MAXBYTES + 1".
* If "attrp" is not NULL, return the character's attribute in "*attrp".
*/ */
void void
screen_getbytes(int row, int col, char_u *bytes, int *attrp) screen_getbytes(int row, int col, char_u *bytes, int *attrp)
@ -1212,7 +1213,8 @@ screen_getbytes(int row, int col, char_u *bytes, int *attrp)
return; return;
off = LineOffset[row] + col; off = LineOffset[row] + col;
*attrp = ScreenAttrs[off]; if (attrp != NULL)
*attrp = ScreenAttrs[off];
bytes[0] = ScreenLines[off]; bytes[0] = ScreenLines[off];
bytes[1] = NUL; bytes[1] = NUL;

View File

@ -3217,6 +3217,31 @@ func Test_screen_functions()
call assert_equal(-1, screenattr(-1, -1)) call assert_equal(-1, screenattr(-1, -1))
call assert_equal(-1, screenchar(-1, -1)) call assert_equal(-1, screenchar(-1, -1))
call assert_equal([], screenchars(-1, -1)) call assert_equal([], screenchars(-1, -1))
" Run this in a separate Vim instance to avoid messing up.
let after =<< trim [CODE]
scriptencoding utf-8
call setline(1, '口')
redraw
call assert_equal(0, screenattr(1, 1))
call assert_equal(char2nr('口'), screenchar(1, 1))
call assert_equal([char2nr('口')], screenchars(1, 1))
call assert_equal('口', screenstring(1, 1))
call writefile(v:errors, 'Xresult')
qall!
[CODE]
let encodings = ['utf-8', 'cp932', 'cp936', 'cp949', 'cp950']
if !has('win32')
let encodings += ['euc-jp']
endif
for enc in encodings
let msg = 'enc=' .. enc
if RunVim([], after, $'--clean --cmd "set encoding={enc}"')
call assert_equal([], readfile('Xresult'), msg)
endif
call delete('Xresult')
endfor
endfunc endfunc
" Test for getcurpos() and setpos() " Test for getcurpos() and setpos()

View File

@ -135,6 +135,19 @@ func Test_screenchar_utf8()
call assert_equal("B", screenstring(1, 2)) call assert_equal("B", screenstring(1, 2))
call assert_equal("C\u0308", screenstring(1, 3)) call assert_equal("C\u0308", screenstring(1, 3))
" 1-cell, with 6 composing characters
set maxcombine=6
call setline(1, ["ABC" .. repeat("\u0308", 6)])
redraw
call assert_equal([0x0041], screenchars(1, 1))
call assert_equal([0x0042], 1->screenchars(2))
" This should not use uninitialized memory
call assert_equal([0x0043] + repeat([0x0308], 6), screenchars(1, 3))
call assert_equal("A", screenstring(1, 1))
call assert_equal("B", screenstring(1, 2))
call assert_equal("C" .. repeat("\u0308", 6), screenstring(1, 3))
set maxcombine&
" 2-cells, with composing characters " 2-cells, with composing characters
let text = "\u3042\u3044\u3046\u3099" let text = "\u3042\u3044\u3046\u3099"
call setline(1, text) call setline(1, text)

View File

@ -695,6 +695,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1598,
/**/ /**/
1597, 1597,
/**/ /**/