To: vim_dev@googlegroups.com Subject: Patch 8.2.2342 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2342 Problem: "char" functions return the wront column in Insert mode when the cursor is beyond the end of the line. Solution: Compute the column correctly. (Yegappan Lakshmanan, closes #7669) Files: src/eval.c, src/evalfunc.c, src/testdir/test_cursor_func.vim *** ../vim-8.2.2341/src/eval.c 2021-01-10 20:22:20.763926913 +0100 --- src/eval.c 2021-01-13 20:05:35.725553517 +0100 *************** *** 5056,5067 **** /* * Convert the specified byte index of line 'lnum' in buffer 'buf' to a * character index. Works only for loaded buffers. Returns -1 on failure. ! * The index of the first character is one. */ int buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx) { char_u *str; if (buf == NULL || buf->b_ml.ml_mfp == NULL) return -1; --- 5056,5069 ---- /* * Convert the specified byte index of line 'lnum' in buffer 'buf' to a * character index. Works only for loaded buffers. Returns -1 on failure. ! * The index of the first byte and the first character is zero. */ int buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx) { char_u *str; + char_u *t; + int count; if (buf == NULL || buf->b_ml.ml_mfp == NULL) return -1; *************** *** 5074,5088 **** return -1; if (*str == NUL) ! return 1; ! return mb_charlen_len(str, byteidx + 1); } /* * Convert the specified character index of line 'lnum' in buffer 'buf' to a ! * byte index. Works only for loaded buffers. Returns -1 on failure. The index ! * of the first byte and the first character is one. */ int buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx) --- 5076,5101 ---- return -1; if (*str == NUL) ! return 0; ! ! // count the number of characters ! t = str; ! for (count = 0; *t != NUL && t <= str + byteidx; count++) ! t += mb_ptr2len(t); ! ! // In insert mode, when the cursor is at the end of a non-empty line, ! // byteidx points to the NUL character immediately past the end of the ! // string. In this case, add one to the character count. ! if (*t == NUL && byteidx != 0 && t == str + byteidx) ! count++; ! return count - 1; } /* * Convert the specified character index of line 'lnum' in buffer 'buf' to a ! * byte index. Works only for loaded buffers. Returns -1 on failure. ! * The index of the first byte and the first character is zero. */ int buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx) *************** *** 5105,5111 **** while (*t != NUL && --charidx > 0) t += mb_ptr2len(t); ! return t - str + 1; } /* --- 5118,5124 ---- while (*t != NUL && --charidx > 0) t += mb_ptr2len(t); ! return t - str; } /* *************** *** 5180,5186 **** { pos = curwin->w_cursor; if (charcol) ! pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col) - 1; return &pos; } if (name[0] == 'v' && name[1] == NUL) // Visual start --- 5193,5199 ---- { pos = curwin->w_cursor; if (charcol) ! pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col); return &pos; } if (name[0] == 'v' && name[1] == NUL) // Visual start *************** *** 5190,5196 **** else pos = curwin->w_cursor; if (charcol) ! pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col) - 1; return &pos; } if (name[0] == '\'') // mark --- 5203,5209 ---- else pos = curwin->w_cursor; if (charcol) ! pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col); return &pos; } if (name[0] == '\'') // mark *************** *** 5199,5205 **** if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0) return NULL; if (charcol) ! pp->col = buf_byteidx_to_charidx(curbuf, pp->lnum, pp->col) - 1; return pp; } --- 5212,5218 ---- if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0) return NULL; if (charcol) ! pp->col = buf_byteidx_to_charidx(curbuf, pp->lnum, pp->col); return pp; } *************** *** 5300,5306 **** if (buf == NULL || buf->b_ml.ml_mfp == NULL) return FAIL; ! n = buf_charidx_to_byteidx(buf, posp->lnum, n); } posp->col = n; --- 5313,5319 ---- if (buf == NULL || buf->b_ml.ml_mfp == NULL) return FAIL; ! n = buf_charidx_to_byteidx(buf, posp->lnum, n) + 1; } posp->col = n; *** ../vim-8.2.2341/src/evalfunc.c 2021-01-13 19:48:41.628312470 +0100 --- src/evalfunc.c 2021-01-13 20:05:35.725553517 +0100 *************** *** 2748,2754 **** semsg(_(e_invarg2), tv_get_string(&argvars[0])); col = (long)tv_get_number_chk(&argvars[1], NULL); if (charcol) ! col = buf_charidx_to_byteidx(curbuf, line, col); if (argvars[2].v_type != VAR_UNKNOWN) coladd = (long)tv_get_number_chk(&argvars[2], NULL); } --- 2748,2754 ---- semsg(_(e_invarg2), tv_get_string(&argvars[0])); col = (long)tv_get_number_chk(&argvars[1], NULL); if (charcol) ! col = buf_charidx_to_byteidx(curbuf, line, col) + 1; if (argvars[2].v_type != VAR_UNKNOWN) coladd = (long)tv_get_number_chk(&argvars[2], NULL); } *************** *** 4011,4018 **** if (fp != NULL && charcol) { pos = *fp; ! pos.col = buf_byteidx_to_charidx(wp->w_buffer, pos.lnum, ! pos.col) - 1; fp = &pos; } } --- 4011,4018 ---- if (fp != NULL && charcol) { pos = *fp; ! pos.col = ! buf_byteidx_to_charidx(wp->w_buffer, pos.lnum, pos.col); fp = &pos; } } *** ../vim-8.2.2341/src/testdir/test_cursor_func.vim 2021-01-10 20:22:20.767926906 +0100 --- src/testdir/test_cursor_func.vim 2021-01-13 20:05:35.725553517 +0100 *************** *** 123,133 **** --- 123,140 ---- bwipe! endfunc + " Save the visual start character position func SaveVisualStartCharPos() call add(g:VisualStartPos, getcharpos('v')) return '' endfunc + " Save the current cursor character position in insert mode + func SaveInsertCurrentCharPos() + call add(g:InsertCurrentPos, getcharpos('.')) + return '' + endfunc + " Test for the getcharpos() function func Test_getcharpos() call assert_fails('call getcharpos({})', 'E731:') *************** *** 156,171 **** vnoremap SaveVisualStartCharPos() let g:VisualStartPos = [] exe "normal 2G6lv$\ohh\o\" ! call assert_equal([[0, 2, 7, 0], [0, 2, 9, 0], [0, 2, 5, 0]], g:VisualStartPos) call assert_equal([0, 2, 9, 0], getcharpos('v')) let g:VisualStartPos = [] exe "normal 3Gv$\o\" ! call assert_equal([[0, 3, 1, 0], [0, 3, 1, 0]], g:VisualStartPos) let g:VisualStartPos = [] exe "normal 1Gv$\o\" call assert_equal([[0, 1, 1, 0], [0, 1, 1, 0]], g:VisualStartPos) vunmap %bw! endfunc --- 163,191 ---- vnoremap SaveVisualStartCharPos() let g:VisualStartPos = [] exe "normal 2G6lv$\ohh\o\" ! call assert_equal([[0, 2, 7, 0], [0, 2, 10, 0], [0, 2, 5, 0]], g:VisualStartPos) call assert_equal([0, 2, 9, 0], getcharpos('v')) let g:VisualStartPos = [] exe "normal 3Gv$\o\" ! call assert_equal([[0, 3, 1, 0], [0, 3, 2, 0]], g:VisualStartPos) let g:VisualStartPos = [] exe "normal 1Gv$\o\" call assert_equal([[0, 1, 1, 0], [0, 1, 1, 0]], g:VisualStartPos) vunmap + " Test for getting the position in insert mode with the cursor after the + " last character in a line + inoremap SaveInsertCurrentCharPos() + let g:InsertCurrentPos = [] + exe "normal 1GA\" + exe "normal 2GA\" + exe "normal 3GA\" + exe "normal 4GA\" + exe "normal 2G6li\" + call assert_equal([[0, 1, 1, 0], [0, 2, 10, 0], [0, 3, 2, 0], [0, 4, 10, 0], + \ [0, 2, 7, 0]], g:InsertCurrentPos) + iunmap + %bw! endfunc *************** *** 192,197 **** --- 212,221 ---- call setcharpos("'m", [0, 2, 9, 0]) normal `m call assert_equal([2, 11], [line('.'), col('.')]) + " unload the buffer and try to set the mark + let bnr = bufnr() + enew! + call assert_equal(-1, setcharpos("'m", [bnr, 2, 2, 0])) %bw! call assert_equal(-1, setcharpos('.', [10, 3, 1, 0])) *************** *** 202,207 **** --- 226,236 ---- return '' endfunc + func SaveInsertCurrentCharCol() + call add(g:InsertCurrentCol, charcol('.')) + return '' + endfunc + " Test for the charcol() function func Test_charcol() call assert_fails('call charcol({})', 'E731:') *************** *** 239,257 **** vnoremap SaveVisualStartCharCol() let g:VisualStartCol = [] exe "normal 2G6lv$\ohh\o\" ! call assert_equal([7, 9, 5], g:VisualStartCol) call assert_equal(9, charcol('v')) let g:VisualStartCol = [] exe "normal 3Gv$\o\" ! call assert_equal([1, 1], g:VisualStartCol) let g:VisualStartCol = [] exe "normal 1Gv$\o\" call assert_equal([1, 1], g:VisualStartCol) vunmap %bw! endfunc " Test for getcursorcharpos() func Test_getcursorcharpos() call assert_equal(getcursorcharpos(), getcursorcharpos(0)) --- 268,303 ---- vnoremap SaveVisualStartCharCol() let g:VisualStartCol = [] exe "normal 2G6lv$\ohh\o\" ! call assert_equal([7, 10, 5], g:VisualStartCol) call assert_equal(9, charcol('v')) let g:VisualStartCol = [] exe "normal 3Gv$\o\" ! call assert_equal([1, 2], g:VisualStartCol) let g:VisualStartCol = [] exe "normal 1Gv$\o\" call assert_equal([1, 1], g:VisualStartCol) vunmap + " Test for getting the column number in insert mode with the cursor after + " the last character in a line + inoremap SaveInsertCurrentCharCol() + let g:InsertCurrentCol = [] + exe "normal 1GA\" + exe "normal 2GA\" + exe "normal 3GA\" + exe "normal 4GA\" + exe "normal 2G6li\" + call assert_equal([1, 10, 2, 10, 7], g:InsertCurrentCol) + iunmap + %bw! endfunc + func SaveInsertCursorCharPos() + call add(g:InsertCursorPos, getcursorcharpos('.')) + return '' + endfunc + " Test for getcursorcharpos() func Test_getcursorcharpos() call assert_equal(getcursorcharpos(), getcursorcharpos(0)) *************** *** 269,274 **** --- 315,333 ---- normal 4G9l call assert_equal([0, 4, 9, 0, 9], getcursorcharpos()) + " Test for getting the cursor position in insert mode with the cursor after + " the last character in a line + inoremap SaveInsertCursorCharPos() + let g:InsertCursorPos = [] + exe "normal 1GA\" + exe "normal 2GA\" + exe "normal 3GA\" + exe "normal 4GA\" + exe "normal 2G6li\" + call assert_equal([[0, 1, 1, 0, 1], [0, 2, 10, 0, 15], [0, 3, 2, 0, 2], + \ [0, 4, 10, 0, 10], [0, 2, 7, 0, 12]], g:InsertCursorPos) + iunmap + let winid = win_getid() normal 2G5l wincmd w *** ../vim-8.2.2341/src/version.c 2021-01-13 19:48:41.628312470 +0100 --- src/version.c 2021-01-13 20:07:47.081188096 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2342, /**/ -- hundred-and-one symptoms of being an internet addict: 137. You decide to stay in college for an additional year or two, just so you can have the free Internet access. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///