Skip to content

Commit f3329a8

Browse files
zeertzjqShougojustinmk
authored andcommitted
vim-patch:9.1.0394: Cannot get a list of positions describing a region
Problem: Cannot get a list of positions describing a region (Justin M. Keyes, after v9.1.0120) Solution: Add the getregionpos() function (Shougo Matsushita) fixes: vim/vim#14609 closes: vim/vim#14617 vim/vim@b4757e6 Co-authored-by: Shougo Matsushita <Shougo.Matsu@gmail.com> Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
1 parent b9ded42 commit f3329a8

File tree

6 files changed

+299
-71
lines changed

6 files changed

+299
-71
lines changed

runtime/doc/builtin.txt

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runtime/doc/usr_41.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,7 @@ Cursor and mark position: *cursor-functions* *mark-functions*
794794
Working with text in the current buffer: *text-functions*
795795
getline() get a line or list of lines from the buffer
796796
getregion() get a region of text from the buffer
797+
getregionpos() get a list of positions for a region
797798
setline() replace a line in the buffer
798799
append() append line or list of lines in the buffer
799800
indent() indent of a specific line

runtime/lua/vim/_meta/vimfn.lua

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/nvim/eval.lua

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4414,6 +4414,31 @@ M.funcs = {
44144414
returns = 'string[]',
44154415
signature = 'getregion({pos1}, {pos2} [, {opts}])',
44164416
},
4417+
getregionpos = {
4418+
args = { 2, 3 },
4419+
base = 1,
4420+
desc = [=[
4421+
Same as |getregion()|, but returns a list of positions
4422+
describing the buffer text segments bound by {pos1} and
4423+
{pos2}.
4424+
The segments are a pair of positions for every line: >
4425+
[[{start_pos}, {end_pos}], ...]
4426+
<
4427+
The position is a |List| with four numbers:
4428+
[bufnum, lnum, col, off]
4429+
"bufnum" is the buffer number.
4430+
"lnum" and "col" are the position in the buffer. The first
4431+
column is 1.
4432+
The "off" number is zero, unless 'virtualedit' is used. Then
4433+
it is the offset in screen columns from the start of the
4434+
character. E.g., a position within a <Tab> or after the last
4435+
character.
4436+
]=],
4437+
name = 'getregionpos',
4438+
params = { { 'pos1', 'table' }, { 'pos2', 'table' }, { 'opts', 'table' } },
4439+
returns = 'integer[][][]',
4440+
signature = 'getregionpos({pos1}, {pos2} [, {opts}])',
4441+
},
44174442
getregtype = {
44184443
args = { 0, 1 },
44194444
base = 1,

src/nvim/eval/funcs.c

Lines changed: 159 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,24 +2823,25 @@ static char *block_def2str(struct block_def *bd)
28232823
return ret;
28242824
}
28252825

2826-
/// "getregion()" function
2827-
static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
2826+
static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2,
2827+
bool *const inclusive, MotionType *region_type, oparg_T *oa,
2828+
int *const fnum)
2829+
FUNC_ATTR_NONNULL_ALL
28282830
{
28292831
tv_list_alloc_ret(rettv, kListLenMayKnow);
28302832

28312833
if (tv_check_for_list_arg(argvars, 0) == FAIL
28322834
|| tv_check_for_list_arg(argvars, 1) == FAIL
28332835
|| tv_check_for_opt_dict_arg(argvars, 2) == FAIL) {
2834-
return;
2836+
return FAIL;
28352837
}
28362838

28372839
int fnum1 = -1;
28382840
int fnum2 = -1;
2839-
pos_T p1, p2;
2840-
if (list2fpos(&argvars[0], &p1, &fnum1, NULL, false) != OK
2841-
|| list2fpos(&argvars[1], &p2, &fnum2, NULL, false) != OK
2841+
if (list2fpos(&argvars[0], p1, &fnum1, NULL, false) != OK
2842+
|| list2fpos(&argvars[1], p2, &fnum2, NULL, false) != OK
28422843
|| fnum1 != fnum2) {
2843-
return;
2844+
return FAIL;
28442845
}
28452846

28462847
bool is_select_exclusive;
@@ -2858,108 +2859,123 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
28582859
type = default_type;
28592860
}
28602861

2861-
MotionType region_type = kMTUnknown;
28622862
if (type[0] == 'v' && type[1] == NUL) {
2863-
region_type = kMTCharWise;
2863+
*region_type = kMTCharWise;
28642864
} else if (type[0] == 'V' && type[1] == NUL) {
2865-
region_type = kMTLineWise;
2865+
*region_type = kMTLineWise;
28662866
} else if (type[0] == Ctrl_V && type[1] == NUL) {
2867-
region_type = kMTBlockWise;
2867+
*region_type = kMTBlockWise;
28682868
} else {
28692869
semsg(_(e_invargNval), "type", type);
2870-
return;
2870+
return FAIL;
28712871
}
28722872

28732873
buf_T *findbuf = fnum1 != 0 ? buflist_findnr(fnum1) : curbuf;
2874+
*fnum = fnum1 != 0 ? fnum1 : curbuf->b_fnum;
28742875
if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL) {
28752876
emsg(_(e_buffer_is_not_loaded));
2876-
return;
2877+
return FAIL;
28772878
}
28782879

2879-
if (p1.lnum < 1 || p1.lnum > findbuf->b_ml.ml_line_count) {
2880-
semsg(_(e_invalid_line_number_nr), p1.lnum);
2881-
return;
2880+
if (p1->lnum < 1 || p1->lnum > findbuf->b_ml.ml_line_count) {
2881+
semsg(_(e_invalid_line_number_nr), p1->lnum);
2882+
return FAIL;
28822883
}
2883-
if (p1.col == MAXCOL) {
2884-
p1.col = ml_get_buf_len(findbuf, p1.lnum) + 1;
2885-
} else if (p1.col < 1 || p1.col > ml_get_buf_len(findbuf, p1.lnum) + 1) {
2886-
semsg(_(e_invalid_column_number_nr), p1.col);
2887-
return;
2884+
if (p1->col == MAXCOL) {
2885+
p1->col = ml_get_buf_len(findbuf, p1->lnum) + 1;
2886+
} else if (p1->col < 1 || p1->col > ml_get_buf_len(findbuf, p1->lnum) + 1) {
2887+
semsg(_(e_invalid_column_number_nr), p1->col);
2888+
return FAIL;
28882889
}
28892890

2890-
if (p2.lnum < 1 || p2.lnum > findbuf->b_ml.ml_line_count) {
2891-
semsg(_(e_invalid_line_number_nr), p2.lnum);
2892-
return;
2891+
if (p2->lnum < 1 || p2->lnum > findbuf->b_ml.ml_line_count) {
2892+
semsg(_(e_invalid_line_number_nr), p2->lnum);
2893+
return FAIL;
28932894
}
2894-
if (p2.col == MAXCOL) {
2895-
p2.col = ml_get_buf_len(findbuf, p2.lnum) + 1;
2896-
} else if (p2.col < 1 || p2.col > ml_get_buf_len(findbuf, p2.lnum) + 1) {
2897-
semsg(_(e_invalid_column_number_nr), p2.col);
2898-
return;
2895+
if (p2->col == MAXCOL) {
2896+
p2->col = ml_get_buf_len(findbuf, p2->lnum) + 1;
2897+
} else if (p2->col < 1 || p2->col > ml_get_buf_len(findbuf, p2->lnum) + 1) {
2898+
semsg(_(e_invalid_column_number_nr), p2->col);
2899+
return FAIL;
28992900
}
29002901

2901-
buf_T *const save_curbuf = curbuf;
29022902
curbuf = findbuf;
29032903
curwin->w_buffer = curbuf;
2904-
const TriState save_virtual = virtual_op;
29052904
virtual_op = virtual_active(curwin);
29062905

2907-
// NOTE: Adjust is needed.
2908-
p1.col--;
2909-
p2.col--;
2906+
// NOTE: Adjustment is needed.
2907+
p1->col--;
2908+
p2->col--;
29102909

2911-
if (!lt(p1, p2)) {
2910+
if (!lt(*p1, *p2)) {
29122911
// swap position
2913-
pos_T p = p1;
2914-
p1 = p2;
2915-
p2 = p;
2912+
pos_T p = *p1;
2913+
*p1 = *p2;
2914+
*p2 = p;
29162915
}
29172916

2918-
oparg_T oa;
2919-
bool inclusive = true;
2920-
2921-
if (region_type == kMTCharWise) {
2917+
if (*region_type == kMTCharWise) {
29222918
// handle 'selection' == "exclusive"
2923-
if (is_select_exclusive && !equalpos(p1, p2)) {
2924-
if (p2.coladd > 0) {
2925-
p2.coladd--;
2926-
} else if (p2.col > 0) {
2927-
p2.col--;
2928-
mark_mb_adjustpos(curbuf, &p2);
2929-
} else if (p2.lnum > 1) {
2930-
p2.lnum--;
2931-
p2.col = ml_get_len(p2.lnum);
2932-
if (p2.col > 0) {
2933-
p2.col--;
2934-
mark_mb_adjustpos(curbuf, &p2);
2919+
if (is_select_exclusive && !equalpos(*p1, *p2)) {
2920+
if (p2->coladd > 0) {
2921+
p2->coladd--;
2922+
} else if (p2->col > 0) {
2923+
p2->col--;
2924+
mark_mb_adjustpos(curbuf, p2);
2925+
} else if (p2->lnum > 1) {
2926+
p2->lnum--;
2927+
p2->col = ml_get_len(p2->lnum);
2928+
if (p2->col > 0) {
2929+
p2->col--;
2930+
mark_mb_adjustpos(curbuf, p2);
29352931
}
29362932
}
29372933
}
29382934
// if fp2 is on NUL (empty line) inclusive becomes false
2939-
if (*ml_get_pos(&p2) == NUL && !virtual_op) {
2940-
inclusive = false;
2935+
if (*ml_get_pos(p2) == NUL && !virtual_op) {
2936+
*inclusive = false;
29412937
}
2942-
} else if (region_type == kMTBlockWise) {
2938+
} else if (*region_type == kMTBlockWise) {
29432939
colnr_T sc1, ec1, sc2, ec2;
2944-
getvvcol(curwin, &p1, &sc1, NULL, &ec1);
2945-
getvvcol(curwin, &p2, &sc2, NULL, &ec2);
2946-
oa.motion_type = kMTBlockWise;
2947-
oa.inclusive = true;
2948-
oa.op_type = OP_NOP;
2949-
oa.start = p1;
2950-
oa.end = p2;
2951-
oa.start_vcol = MIN(sc1, sc2);
2940+
getvvcol(curwin, p1, &sc1, NULL, &ec1);
2941+
getvvcol(curwin, p2, &sc2, NULL, &ec2);
2942+
oa->motion_type = kMTBlockWise;
2943+
oa->inclusive = true;
2944+
oa->op_type = OP_NOP;
2945+
oa->start = *p1;
2946+
oa->end = *p2;
2947+
oa->start_vcol = MIN(sc1, sc2);
29522948
if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) {
2953-
oa.end_vcol = sc2 - 1;
2949+
oa->end_vcol = sc2 - 1;
29542950
} else {
2955-
oa.end_vcol = MAX(ec1, ec2);
2951+
oa->end_vcol = MAX(ec1, ec2);
29562952
}
29572953
}
29582954

29592955
// Include the trailing byte of a multi-byte char.
2960-
int l = utfc_ptr2len(ml_get_pos(&p2));
2956+
int l = utfc_ptr2len(ml_get_pos(p2));
29612957
if (l > 1) {
2962-
p2.col += l - 1;
2958+
p2->col += l - 1;
2959+
}
2960+
2961+
return OK;
2962+
}
2963+
2964+
/// "getregion()" function
2965+
static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
2966+
{
2967+
buf_T *const save_curbuf = curbuf;
2968+
const TriState save_virtual = virtual_op;
2969+
2970+
pos_T p1, p2;
2971+
bool inclusive = true;
2972+
MotionType region_type = kMTUnknown;
2973+
oparg_T oa;
2974+
int fnum;
2975+
2976+
if (getregionpos(argvars, rettv,
2977+
&p1, &p2, &inclusive, &region_type, &oa, &fnum) == FAIL) {
2978+
return;
29632979
}
29642980

29652981
for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) {
@@ -2983,6 +2999,80 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
29832999
tv_list_append_allocated_string(rettv->vval.v_list, akt);
29843000
}
29853001

3002+
// getregionpos() breaks curbuf and virtual_op
3003+
curbuf = save_curbuf;
3004+
curwin->w_buffer = curbuf;
3005+
virtual_op = save_virtual;
3006+
}
3007+
3008+
static void add_regionpos_range(typval_T *rettv, int bufnr, int lnum1, int col1, int coladd1,
3009+
int lnum2, int col2, int coladd2)
3010+
{
3011+
list_T *l1 = tv_list_alloc(2);
3012+
tv_list_append_list(rettv->vval.v_list, l1);
3013+
3014+
list_T *l2 = tv_list_alloc(4);
3015+
tv_list_append_list(l1, l2);
3016+
3017+
list_T *l3 = tv_list_alloc(4);
3018+
tv_list_append_list(l1, l3);
3019+
3020+
buf_T *findbuf = bufnr != 0 ? buflist_findnr(bufnr) : curbuf;
3021+
3022+
int max_col1 = ml_get_buf_len(findbuf, lnum1);
3023+
tv_list_append_number(l2, bufnr);
3024+
tv_list_append_number(l2, lnum1);
3025+
tv_list_append_number(l2, col1 > max_col1 ? max_col1 : col1);
3026+
tv_list_append_number(l2, coladd1);
3027+
3028+
int max_col2 = ml_get_buf_len(findbuf, lnum2);
3029+
tv_list_append_number(l3, bufnr);
3030+
tv_list_append_number(l3, lnum2);
3031+
tv_list_append_number(l3, col2 > max_col2 ? max_col2 : col2);
3032+
tv_list_append_number(l3, coladd2);
3033+
}
3034+
3035+
/// "getregionpos()" function
3036+
static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
3037+
{
3038+
buf_T *const save_curbuf = curbuf;
3039+
const TriState save_virtual = virtual_op;
3040+
3041+
pos_T p1, p2;
3042+
bool inclusive = true;
3043+
MotionType region_type = kMTUnknown;
3044+
oparg_T oa;
3045+
int fnum;
3046+
3047+
if (getregionpos(argvars, rettv,
3048+
&p1, &p2, &inclusive, &region_type, &oa, &fnum) == FAIL) {
3049+
return;
3050+
}
3051+
3052+
for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) {
3053+
int start_col, end_col;
3054+
3055+
if (region_type == kMTLineWise) {
3056+
start_col = 1;
3057+
end_col = MAXCOL;
3058+
} else if (region_type == kMTBlockWise) {
3059+
struct block_def bd;
3060+
block_prep(&oa, &bd, lnum, false);
3061+
start_col = bd.start_vcol + 1;
3062+
end_col = bd.end_vcol;
3063+
} else if (p1.lnum < lnum && lnum < p2.lnum) {
3064+
start_col = 1;
3065+
end_col = MAXCOL;
3066+
} else {
3067+
start_col = p1.lnum == lnum ? p1.col + 1 : 1;
3068+
end_col = p2.lnum == lnum ? p2.col + 1 : MAXCOL;
3069+
}
3070+
3071+
add_regionpos_range(rettv, fnum, lnum, start_col,
3072+
p1.coladd, lnum, end_col, p2.coladd);
3073+
}
3074+
3075+
// getregionpos() may change curbuf and virtual_op
29863076
curbuf = save_curbuf;
29873077
curwin->w_buffer = curbuf;
29883078
virtual_op = save_virtual;

0 commit comments

Comments
 (0)