diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 20631e9d88..cee565b2e4 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6431,14 +6431,17 @@ int buf_charidx_to_byteidx(buf_T *buf, linenr_T lnum, int charidx) /// @param[in] dollar_lnum True when "$" is last line. /// @param[out] ret_fnum Set to fnum for marks. /// @param[in] charcol True to return character column. +/// @param[in] wp Window for which to get the position. /// /// @return Pointer to position or NULL in case of error (e.g. invalid type). pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret_fnum, - const bool charcol) + const bool charcol, win_T *wp) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { static pos_T pos; + buf_T *bp = wp->w_buffer; + // Argument can be [lnum, col, coladd]. if (tv->v_type == VAR_LIST) { bool error = false; @@ -6450,7 +6453,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret // Get the line number. pos.lnum = (linenr_T)tv_list_find_nr(l, 0, &error); - if (error || pos.lnum <= 0 || pos.lnum > curbuf->b_ml.ml_line_count) { + if (error || pos.lnum <= 0 || pos.lnum > bp->b_ml.ml_line_count) { // Invalid line number. return NULL; } @@ -6462,9 +6465,9 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret } int len; if (charcol) { - len = mb_charlen(ml_get(pos.lnum)); + len = mb_charlen(ml_get_buf(bp, pos.lnum)); } else { - len = ml_get_len(pos.lnum); + len = ml_get_buf_len(bp, pos.lnum); } // We accept "$" for the column number: last column. @@ -6499,18 +6502,18 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret pos.lnum = 0; if (name[0] == '.') { // cursor - pos = curwin->w_cursor; + pos = wp->w_cursor; } else if (name[0] == 'v' && name[1] == NUL) { // Visual start - if (VIsual_active) { + if (VIsual_active && wp == curwin) { pos = VIsual; } else { - pos = curwin->w_cursor; + pos = wp->w_cursor; } } else if (name[0] == '\'') { // mark int mname = (uint8_t)name[1]; - const fmark_T *const fm = mark_get(curbuf, curwin, NULL, kMarkAll, mname); + const fmark_T *const fm = mark_get(bp, wp, NULL, kMarkAll, mname); if (fm == NULL || fm->mark.lnum <= 0) { return NULL; } @@ -6520,7 +6523,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret } if (pos.lnum != 0) { if (charcol) { - pos.col = buf_byteidx_to_charidx(curbuf, pos.lnum, pos.col); + pos.col = buf_byteidx_to_charidx(bp, pos.lnum, pos.col); } return &pos; } @@ -6530,31 +6533,31 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret if (name[0] == 'w' && dollar_lnum) { // the "w_valid" flags are not reset when moving the cursor, but they // do matter for update_topline() and validate_botline(). - check_cursor_moved(curwin); + check_cursor_moved(wp); pos.col = 0; if (name[1] == '0') { // "w0": first visible line - update_topline(curwin); + update_topline(wp); // In silent Ex mode topline is zero, but that's not a valid line // number; use one instead. - pos.lnum = curwin->w_topline > 0 ? curwin->w_topline : 1; + pos.lnum = wp->w_topline > 0 ? wp->w_topline : 1; return &pos; } else if (name[1] == '$') { // "w$": last visible line - validate_botline(curwin); + validate_botline(wp); // In silent Ex mode botline is zero, return zero then. - pos.lnum = curwin->w_botline > 0 ? curwin->w_botline - 1 : 0; + pos.lnum = wp->w_botline > 0 ? wp->w_botline - 1 : 0; return &pos; } } else if (name[0] == '$') { // last column or line if (dollar_lnum) { - pos.lnum = curbuf->b_ml.ml_line_count; + pos.lnum = bp->b_ml.ml_line_count; pos.col = 0; } else { - pos.lnum = curwin->w_cursor.lnum; + pos.lnum = wp->w_cursor.lnum; if (charcol) { - pos.col = (colnr_T)mb_charlen(get_cursor_line_ptr()); + pos.col = (colnr_T)mb_charlen(ml_get_buf(bp, wp->w_cursor.lnum)); } else { - pos.col = get_cursor_line_len(); + pos.col = ml_get_buf_len(bp, wp->w_cursor.lnum); } } return &pos; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 7eac106063..8451cb78b2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -718,33 +718,27 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) return; } - switchwin_T switchwin; - bool winchanged = false; + win_T *wp = curwin; if (argvars[1].v_type != VAR_UNKNOWN) { // use the window specified in the second argument tabpage_T *tp; - win_T *wp = win_id2wp_tp((int)tv_get_number(&argvars[1]), &tp); + wp = win_id2wp_tp((int)tv_get_number(&argvars[1]), &tp); if (wp == NULL || tp == NULL) { return; } - - if (switch_win_noblock(&switchwin, wp, tp, true) != OK) { - return; - } - - check_cursor(curwin); - winchanged = true; + check_cursor(wp); } + buf_T *bp = wp->w_buffer; colnr_T col = 0; - int fnum = curbuf->b_fnum; - pos_T *fp = var2fpos(&argvars[0], false, &fnum, charcol); - if (fp != NULL && fnum == curbuf->b_fnum) { + int fnum = bp->b_fnum; + pos_T *fp = var2fpos(&argvars[0], false, &fnum, charcol, wp); + if (fp != NULL && fnum == bp->b_fnum) { if (fp->col == MAXCOL) { // '> can be MAXCOL, get the length of the line then - if (fp->lnum <= curbuf->b_ml.ml_line_count) { - col = ml_get_len(fp->lnum) + 1; + if (fp->lnum <= bp->b_ml.ml_line_count) { + col = ml_get_buf_len(bp, fp->lnum) + 1; } else { col = MAXCOL; } @@ -752,11 +746,11 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) col = fp->col + 1; // col(".") when the cursor is on the NUL at the end of the line // because of "coladd" can be seen as an extra column. - if (virtual_active(curwin) && fp == &curwin->w_cursor) { - char *p = get_cursor_pos_ptr(); - if (curwin->w_cursor.coladd >= - (colnr_T)win_chartabsize(curwin, p, - curwin->w_virtcol - curwin->w_cursor.coladd)) { + if (virtual_active(wp) && fp == &wp->w_cursor) { + char *p = ml_get_buf(bp, wp->w_cursor.lnum) + wp->w_cursor.col; + if (wp->w_cursor.coladd >= + (colnr_T)win_chartabsize(wp, p, + wp->w_virtcol - wp->w_cursor.coladd)) { int l; if (*p != NUL && p[(l = utfc_ptr2len(p))] == NUL) { col += l; @@ -766,10 +760,6 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) } } rettv->vval.v_number = col; - - if (winchanged) { - restore_win_noblock(&switchwin, true); - } } /// "charcol()" function @@ -2460,7 +2450,7 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos, bool fp = &pos; } } else { - fp = var2fpos(&argvars[0], true, &fnum, charcol); + fp = var2fpos(&argvars[0], true, &fnum, charcol, curwin); } list_T *const l = tv_list_alloc_ret(rettv, 4 + getcurpos); @@ -4435,22 +4425,18 @@ static void f_line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tabpage_T *tp; win_T *wp = win_id2wp_tp(id, &tp); if (wp != NULL && tp != NULL) { - switchwin_T switchwin; - if (switch_win_noblock(&switchwin, wp, tp, true) == OK) { - // With 'splitkeep' != cursor and in diff mode, prevent that the - // window scrolls and keep the topline. - if (*p_spk != 'c' || (curwin->w_p_diff && switchwin.sw_curwin->w_p_diff)) { - skip_update_topline = true; - } - check_cursor(curwin); - fp = var2fpos(&argvars[0], true, &fnum, false); + // With 'splitkeep' != cursor and in diff mode, prevent that the + // window scrolls and keep the topline. + if (*p_spk != 'c' || (wp->w_p_diff && curwin->w_p_diff)) { + skip_update_topline = true; } + check_cursor(wp); + fp = var2fpos(&argvars[0], true, &fnum, false, wp); skip_update_topline = false; - restore_win_noblock(&switchwin, true); } } else { // use current window - fp = var2fpos(&argvars[0], true, &fnum, false); + fp = var2fpos(&argvars[0], true, &fnum, false, curwin); } if (fp != NULL) { @@ -8245,39 +8231,33 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { colnr_T vcol_start = 0; colnr_T vcol_end = 0; - switchwin_T switchwin; - bool winchanged = false; + win_T *wp = curwin; if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) { // use the window specified in the third argument tabpage_T *tp; - win_T *wp = win_id2wp_tp((int)tv_get_number(&argvars[2]), &tp); + wp = win_id2wp_tp((int)tv_get_number(&argvars[2]), &tp); if (wp == NULL || tp == NULL) { goto theend; } - - if (switch_win_noblock(&switchwin, wp, tp, true) != OK) { - goto theend; - } - - check_cursor(curwin); - winchanged = true; + check_cursor(wp); } - int fnum = curbuf->b_fnum; - pos_T *fp = var2fpos(&argvars[0], false, &fnum, false); - if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count - && fnum == curbuf->b_fnum) { + buf_T *bp = wp->w_buffer; + int fnum = bp->b_fnum; + pos_T *fp = var2fpos(&argvars[0], false, &fnum, false, wp); + if (fp != NULL && fp->lnum <= bp->b_ml.ml_line_count + && fnum == bp->b_fnum) { // Limit the column to a valid value, getvvcol() doesn't check. if (fp->col < 0) { fp->col = 0; } else { - const colnr_T len = ml_get_len(fp->lnum); + const colnr_T len = ml_get_buf_len(bp, fp->lnum); if (fp->col > len) { fp->col = len; } } - getvvcol(curwin, fp, &vcol_start, NULL, &vcol_end); + getvvcol(wp, fp, &vcol_start, NULL, &vcol_end); vcol_start++; vcol_end++; } @@ -8290,10 +8270,6 @@ theend: } else { rettv->vval.v_number = vcol_end; } - - if (winchanged) { - restore_win_noblock(&switchwin, true); - } } /// "visualmode()" function diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index f2cf23bc15..68ede2f8da 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -4235,7 +4235,7 @@ linenr_T tv_get_lnum(const typval_T *const tv) if (lnum <= 0 && did_emsg_before == did_emsg && tv->v_type != VAR_NUMBER) { int fnum; // No valid number, try using same function as line() does. - pos_T *const fp = var2fpos(tv, true, &fnum, false); + pos_T *const fp = var2fpos(tv, true, &fnum, false, curwin); if (fp != NULL) { lnum = fp->lnum; } diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 2e37204921..0b7604dc04 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -3088,6 +3088,42 @@ describe('extmark decorations', function() ]] }) end) + + it('line("w$", win) considers conceal_lines', function() + api.nvim_buf_set_lines(0, 0, -1, true, { 'line 1', 'line 2', 'line 3' }) + api.nvim_buf_set_extmark(0, ns, 0, 0, { conceal_lines = '' }) -- conceal line 1 + + local win = exec_lua(function() + local provider_ns = vim.api.nvim_create_namespace('test_f_line') + _G.line_w_dollar = {} + vim.api.nvim_set_decoration_provider(provider_ns, { + on_start = function() + for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do + table.insert(_G.line_w_dollar, { win, vim.fn.line('w$', win) }) + end + end, + }) + + local win = vim.api.nvim_open_win(0, false, { + relative = 'editor', + width = 20, + height = 1, + row = 0, + col = 0, + border = 'single', + }) + vim.api.nvim_set_option_value('conceallevel', 2, { scope = 'local', win = win }) + + return win + end) + + local line_w_dollar = exec_lua('return _G.line_w_dollar') + for _, win_line in ipairs(line_w_dollar) do + if win_line[1] == win then + eq(2, win_line[2]) + end + end + end) end) describe('decorations: inline virtual text', function()