aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-05-24 15:44:52 +0800
committerGitHub <noreply@github.com>2024-05-24 15:44:52 +0800
commitcd05fbef170b29083973fd11170d25225feb8bed (patch)
tree5c5f336651131811a83d27122ebc302eece6e2b7 /src
parentc836383d21b6d38ecf59e46e76da55ca97a4fc65 (diff)
downloadrneovim-cd05fbef170b29083973fd11170d25225feb8bed.tar.gz
rneovim-cd05fbef170b29083973fd11170d25225feb8bed.tar.bz2
rneovim-cd05fbef170b29083973fd11170d25225feb8bed.zip
vim-patch:9.1.0441: getregionpos() can't properly indicate positions beyond eol (#28957)
Problem: getregionpos() can't properly indicate positions beyond eol. Solution: Add an "eol" flag that enables handling positions beyond end of line like getpos() does (zeertzjq). Also fix the problem that a position still has the coladd beyond the end of the line when its column has been clamped. In the last test case with TABs at the end of the line the old behavior is obviously wrong. I decided to gate this behind a flag because returning positions that don't correspond to actual characters in the line may lead to mistakes for callers that want to calculate the length of the selected text, so the behavior is only enabled if the caller wants it. closes: vim/vim#14838 https://github.com/vim/vim/commit/2b09de910458247b70751928217422c38fd5abf8
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.lua13
-rw-r--r--src/nvim/eval/funcs.c33
2 files changed, 41 insertions, 5 deletions
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index b377643917..7d4438ded6 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -4435,6 +4435,19 @@ M.funcs = {
If the "off" number of an ending position is non-zero, it is
the offset of the character's first cell not included in the
selection, otherwise all its cells are included.
+
+ Apart from the options supported by |getregion()|, {opts} also
+ supports the following:
+
+ eol If |TRUE|, indicate positions beyond
+ the end of a line with "col" values
+ one more than the length of the line.
+ If |FALSE|, positions are limited
+ within their lines, and if a line is
+ empty or the selection is entirely
+ beyond the end of a line, a "col"
+ value of 0 is used for both positions.
+ (default: |FALSE|)
]=],
name = 'getregionpos',
params = { { 'pos1', 'table' }, { 'pos2', 'table' }, { 'opts', 'table' } },
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index fcc86bb708..048f744532 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -3001,16 +3001,14 @@ static void add_regionpos_range(typval_T *rettv, pos_T p1, pos_T p2)
list_T *l3 = tv_list_alloc(4);
tv_list_append_list(l1, l3);
- int max_col1 = ml_get_len(p1.lnum);
tv_list_append_number(l2, curbuf->b_fnum);
tv_list_append_number(l2, p1.lnum);
- tv_list_append_number(l2, p1.col > max_col1 ? max_col1 : p1.col);
+ tv_list_append_number(l2, p1.col);
tv_list_append_number(l2, p1.coladd);
- int max_col2 = ml_get_len(p2.lnum);
tv_list_append_number(l3, curbuf->b_fnum);
tv_list_append_number(l3, p2.lnum);
- tv_list_append_number(l3, p2.col > max_col2 ? max_col2 : p2.col);
+ tv_list_append_number(l3, p2.col);
tv_list_append_number(l3, p2.coladd);
}
@@ -3023,14 +3021,20 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
pos_T p1, p2;
bool inclusive = true;
MotionType region_type = kMTUnknown;
+ bool allow_eol = false;
oparg_T oa;
if (getregionpos(argvars, rettv, &p1, &p2, &inclusive, &region_type, &oa) == FAIL) {
return;
}
+ if (argvars[2].v_type == VAR_DICT) {
+ allow_eol = tv_dict_get_bool(argvars[2].vval.v_dict, "eol", false);
+ }
+
for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) {
pos_T ret_p1, ret_p2;
+ colnr_T line_len = ml_get_len(lnum);
if (region_type == kMTLineWise) {
ret_p1.col = 1;
@@ -3054,6 +3058,11 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
ret_p1.col = p1.col + 1;
ret_p1.coladd = p1.coladd;
}
+ } else if (region_type == kMTBlockWise && oa.start_vcol > bd.start_vcol) {
+ // blockwise selection entirely beyond end of line
+ ret_p1.col = MAXCOL;
+ ret_p1.coladd = oa.start_vcol - bd.start_vcol;
+ bd.is_oneChar = true;
} else if (bd.startspaces > 0) {
ret_p1.col = bd.textcol;
ret_p1.coladd = bd.start_char_vcols - bd.startspaces;
@@ -3064,7 +3073,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
if (bd.is_oneChar) { // selection entirely inside one char
ret_p2.col = ret_p1.col;
- ret_p2.coladd = ret_p1.coladd + bd.startspaces;
+ ret_p2.coladd = ret_p1.coladd + bd.startspaces + bd.endspaces;
} else if (bd.endspaces > 0) {
ret_p2.col = bd.textcol + bd.textlen + 1;
ret_p2.coladd = bd.endspaces;
@@ -3074,6 +3083,20 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
}
}
+ if (!allow_eol && ret_p1.col > line_len) {
+ ret_p1.col = 0;
+ ret_p1.coladd = 0;
+ } else if (ret_p1.col > line_len + 1) {
+ ret_p1.col = line_len + 1;
+ }
+
+ if (!allow_eol && ret_p2.col > line_len) {
+ ret_p2.col = ret_p1.col == 0 ? 0 : line_len;
+ ret_p2.coladd = 0;
+ } else if (ret_p2.col > line_len + 1) {
+ ret_p2.col = line_len + 1;
+ }
+
ret_p1.lnum = lnum;
ret_p2.lnum = lnum;
add_regionpos_range(rettv, ret_p1, ret_p2);