To: vim_dev@googlegroups.com Subject: Patch 9.0.1598 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.1598 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) Files: src/evalfunc.c, src/screen.c, src/testdir/test_functions.vim, src/testdir/test_utf8.vim *** ../vim-9.0.1597/src/evalfunc.c 2023-05-11 15:02:52.231456894 +0100 --- src/evalfunc.c 2023-06-01 20:21:12.233128848 +0100 *************** *** 8934,8940 **** { int row; int col; - int off; int c; if (in_vim9script() --- 8934,8939 ---- *************** *** 8948,8958 **** c = -1; else { ! off = LineOffset[row] + col; ! if (enc_utf8 && ScreenLinesUC[off] != 0) ! c = ScreenLinesUC[off]; ! else ! c = ScreenLines[off]; } rettv->vval.v_number = c; } --- 8947,8955 ---- c = -1; else { ! char_u buf[MB_MAXBYTES + 1]; ! screen_getbytes(row, col, buf, NULL); ! c = (*mb_ptr2char)(buf); } rettv->vval.v_number = c; } *************** *** 8965,8971 **** { int row; int col; - int off; int c; int i; --- 8962,8967 ---- *************** *** 8982,8999 **** 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]; 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]); } /* --- 8978,8995 ---- if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns) return; ! 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 = (*mb_ptr2char)(buf); list_append_number(rettv->vval.v_list, (varnumber_T)c); if (enc_utf8) ! for (i = 0; i < Screen_mco && pcc[i] != 0; ++i) ! list_append_number(rettv->vval.v_list, (varnumber_T)pcc[i]); } /* *************** *** 9024,9034 **** { 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; --- 9020,9026 ---- *************** *** 9043,9060 **** 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; rettv->vval.v_string = vim_strsave(buf); } --- 9035,9041 ---- if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns) return; ! screen_getbytes(row, col, buf, NULL); rettv->vval.v_string = vim_strsave(buf); } *************** *** 9433,9439 **** /* * Set the cursor or mark position. ! * If 'charpos' is TRUE, then use the column number as a character offset. * Otherwise use the column number as a byte offset. */ static void --- 9414,9420 ---- /* * Set the cursor or mark position. ! * If "charpos" is TRUE, then use the column number as a character offset. * Otherwise use the column number as a byte offset. */ static void *** ../vim-9.0.1597/src/screen.c 2023-05-20 14:06:56.673542805 +0100 --- src/screen.c 2023-06-01 20:26:30.112235831 +0100 *************** *** 1199,1206 **** } /* ! * Get a single character directly from ScreenLines into "bytes[]". ! * Also return its attribute in *attrp; */ void screen_getbytes(int row, int col, char_u *bytes, int *attrp) --- 1199,1207 ---- } /* ! * 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,1218 **** return; off = LineOffset[row] + col; ! *attrp = ScreenAttrs[off]; bytes[0] = ScreenLines[off]; bytes[1] = NUL; --- 1213,1220 ---- return; off = LineOffset[row] + col; ! if (attrp != NULL) ! *attrp = ScreenAttrs[off]; bytes[0] = ScreenLines[off]; bytes[1] = NUL; *** ../vim-9.0.1597/src/testdir/test_functions.vim 2023-05-24 21:02:20.489162125 +0100 --- src/testdir/test_functions.vim 2023-06-01 20:17:49.333389396 +0100 *************** *** 3217,3222 **** --- 3217,3247 ---- 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() *** ../vim-9.0.1597/src/testdir/test_utf8.vim 2023-05-08 15:31:34.251545087 +0100 --- src/testdir/test_utf8.vim 2023-06-01 20:17:49.333389396 +0100 *************** *** 135,140 **** --- 135,153 ---- 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) *** ../vim-9.0.1597/src/version.c 2023-06-01 19:26:23.435627545 +0100 --- src/version.c 2023-06-01 20:16:22.041494837 +0100 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 1598, /**/ -- From "know your smileys": C=}>;*{)) Drunk, devilish chef with a toupee in an updraft, a mustache, and a double chin /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///