Mercurial > vim
changeset 32533:aa64fdad1f60 v9.0.1598
patch 9.0.1598: screenchar() and others are wrong with DBCS 'encoding'
Commit: https://github.com/vim/vim/commit/47eec6716b8621fd43bac8ecc9c19089df26705e
Author: zeertzjq <zeertzjq@outlook.com>
Date: Thu Jun 1 20:26:55 2023 +0100
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)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 01 Jun 2023 21:30:03 +0200 |
parents | 26aa788bed3f |
children | f139a13965f2 |
files | src/evalfunc.c src/screen.c src/testdir/test_functions.vim src/testdir/test_utf8.vim src/version.c |
diffstat | 5 files changed, 58 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -8934,7 +8934,6 @@ f_screenchar(typval_T *argvars, typval_T { int row; int col; - int off; int c; if (in_vim9script() @@ -8948,11 +8947,9 @@ f_screenchar(typval_T *argvars, typval_T c = -1; else { - off = LineOffset[row] + col; - if (enc_utf8 && ScreenLinesUC[off] != 0) - c = ScreenLinesUC[off]; - else - c = ScreenLines[off]; + char_u buf[MB_MAXBYTES + 1]; + screen_getbytes(row, col, buf, NULL); + c = (*mb_ptr2char)(buf); } rettv->vval.v_number = c; } @@ -8965,7 +8962,6 @@ f_screenchars(typval_T *argvars, typval_ { int row; int col; - int off; int c; int i; @@ -8982,18 +8978,18 @@ f_screenchars(typval_T *argvars, typval_ if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns) return; - off = LineOffset[row] + col; - if (enc_utf8 && ScreenLinesUC[off] != 0) - c = ScreenLinesUC[off]; + char_u buf[MB_MAXBYTES + 1]; + screen_getbytes(row, col, buf, NULL); + int pcc[MAX_MCO]; + if (enc_utf8) + c = utfc_ptr2char(buf, pcc); else - c = ScreenLines[off]; + c = (*mb_ptr2char)(buf); list_append_number(rettv->vval.v_list, (varnumber_T)c); if (enc_utf8) - - for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i) - list_append_number(rettv->vval.v_list, - (varnumber_T)ScreenLinesC[i][off]); + for (i = 0; i < Screen_mco && pcc[i] != 0; ++i) + list_append_number(rettv->vval.v_list, (varnumber_T)pcc[i]); } /* @@ -9024,11 +9020,7 @@ f_screenstring(typval_T *argvars, typval { int row; int col; - int off; - int c; - int i; char_u buf[MB_MAXBYTES + 1]; - int buflen = 0; rettv->vval.v_string = NULL; rettv->v_type = VAR_STRING; @@ -9043,18 +9035,7 @@ f_screenstring(typval_T *argvars, typval if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns) return; - off = LineOffset[row] + col; - 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; + screen_getbytes(row, col, buf, NULL); rettv->vval.v_string = vim_strsave(buf); } @@ -9433,7 +9414,7 @@ f_searchpos(typval_T *argvars, typval_T /* * 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. */ static void
--- a/src/screen.c +++ b/src/screen.c @@ -1199,8 +1199,9 @@ screen_putchar(int c, int row, int col, } /* - * Get a single character directly from ScreenLines into "bytes[]". - * Also return its attribute in *attrp; + * Get a single character directly from ScreenLines into "bytes", which must + * have a size of "MB_MAXBYTES + 1". + * If "attrp" is not NULL, return the character's attribute in "*attrp". */ void screen_getbytes(int row, int col, char_u *bytes, int *attrp) @@ -1212,7 +1213,8 @@ screen_getbytes(int row, int col, char_u return; off = LineOffset[row] + col; - *attrp = ScreenAttrs[off]; + if (attrp != NULL) + *attrp = ScreenAttrs[off]; bytes[0] = ScreenLines[off]; bytes[1] = NUL;
--- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -3217,6 +3217,31 @@ func Test_screen_functions() call assert_equal(-1, screenattr(-1, -1)) call assert_equal(-1, screenchar(-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 " Test for getcurpos() and setpos()
--- a/src/testdir/test_utf8.vim +++ b/src/testdir/test_utf8.vim @@ -135,6 +135,19 @@ func Test_screenchar_utf8() call assert_equal("B", screenstring(1, 2)) 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 let text = "\u3042\u3044\u3046\u3099" call setline(1, text)