vim-patch:9.1.0120: hard to get visual region using Vim script

Problem:  hard to get visual region using Vim script
Solution: Add getregion() Vim script function
          (Shougo Matsushita, Jakub Łuczyński)

closes: vim/vim#13998
closes: vim/vim#11579

3f905ab3c4

Cherry-pick changes from patch 9.1.0122, with :echom instead of :echow.

Co-authored-by: Shougo Matsushita <Shougo.Matsu@gmail.com>
Co-authored-by: Jakub Łuczyński <doubleloop@o2.pl>
This commit is contained in:
zeertzjq
2024-02-22 20:32:52 +08:00
parent bb15fa0356
commit 20e4001eee
8 changed files with 500 additions and 78 deletions

View File

@@ -84,25 +84,6 @@ static bool clipboard_delay_update = false; // delay clipboard update
static bool clipboard_needs_update = false; // clipboard was updated
static bool clipboard_didwarn = false;
// structure used by block_prep, op_delete and op_yank for blockwise operators
// also op_change, op_shift, op_insert, op_replace - AKelly
struct block_def {
int startspaces; // 'extra' cols before first char
int endspaces; // 'extra' cols after last char
int textlen; // chars in block
char *textstart; // pointer to 1st char (partially) in block
colnr_T textcol; // index of chars (partially) in block
colnr_T start_vcol; // start col of 1st char wholly inside block
colnr_T end_vcol; // start col of 1st char wholly after block
int is_short; // true if line is too short to fit in block
int is_MAX; // true if curswant==MAXCOL when starting
int is_oneChar; // true if block within one character
int pre_whitesp; // screen cols of ws before block
int pre_whitesp_c; // chars of ws before block
colnr_T end_char_vcols; // number of vcols of post-block char
colnr_T start_char_vcols; // number of vcols of pre-block char
};
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ops.c.generated.h"
#endif
@@ -2655,66 +2636,11 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
reg->y_array[y_idx] = xstrdup(ml_get(lnum));
break;
case kMTCharWise: {
colnr_T startcol = 0;
colnr_T endcol = MAXCOL;
bool is_oneChar = false;
colnr_T cs, ce;
char *p = ml_get(lnum);
bd.startspaces = 0;
bd.endspaces = 0;
if (lnum == oap->start.lnum) {
startcol = oap->start.col;
if (virtual_op) {
getvcol(curwin, &oap->start, &cs, NULL, &ce);
if (ce != cs && oap->start.coladd > 0) {
// Part of a tab selected -- but don't double-count it.
bd.startspaces = (ce - cs + 1) - oap->start.coladd;
if (bd.startspaces < 0) {
bd.startspaces = 0;
}
startcol++;
}
}
}
if (lnum == oap->end.lnum) {
endcol = oap->end.col;
if (virtual_op) {
getvcol(curwin, &oap->end, &cs, NULL, &ce);
if (p[endcol] == NUL || (cs + oap->end.coladd < ce
// Don't add space for double-wide
// char; endcol will be on last byte
// of multi-byte char.
&& utf_head_off(p, p + endcol) == 0)) {
if (oap->start.lnum == oap->end.lnum
&& oap->start.col == oap->end.col) {
// Special case: inside a single char
is_oneChar = true;
bd.startspaces = oap->end.coladd
- oap->start.coladd + oap->inclusive;
endcol = startcol;
} else {
bd.endspaces = oap->end.coladd
+ oap->inclusive;
endcol -= oap->inclusive;
}
}
}
}
if (endcol == MAXCOL) {
endcol = (colnr_T)strlen(p);
}
if (startcol > endcol || is_oneChar) {
bd.textlen = 0;
} else {
bd.textlen = endcol - startcol + oap->inclusive;
}
bd.textstart = p + startcol;
case kMTCharWise:
charwise_block_prep(oap->start, oap->end, &bd, lnum, oap->inclusive);
yank_copy_line(reg, &bd, y_idx, false);
break;
}
// NOTREACHED
case kMTUnknown:
abort();
@@ -4203,7 +4129,7 @@ static void restore_lbr(bool lbr_saved)
/// - textlen includes the first/last char to be wholly yanked
/// - start/endspaces is the number of columns of the first/last yanked char
/// that are to be yanked.
static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool is_del)
void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool is_del)
{
int incr = 0;
// Avoid a problem with unwanted linebreaks in block mode.
@@ -4326,6 +4252,65 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool
restore_lbr(lbr_saved);
}
/// Get block text from "start" to "end"
void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T lnum,
bool inclusive)
{
colnr_T startcol = 0;
colnr_T endcol = MAXCOL;
bool is_oneChar = false;
colnr_T cs, ce;
char *p = ml_get(lnum);
bdp->startspaces = 0;
bdp->endspaces = 0;
if (lnum == start.lnum) {
startcol = start.col;
if (virtual_op) {
getvcol(curwin, &start, &cs, NULL, &ce);
if (ce != cs && start.coladd > 0) {
// Part of a tab selected -- but don't double-count it.
bdp->startspaces = (ce - cs + 1) - start.coladd;
if (bdp->startspaces < 0) {
bdp->startspaces = 0;
}
startcol++;
}
}
}
if (lnum == end.lnum) {
endcol = end.col;
if (virtual_op) {
getvcol(curwin, &end, &cs, NULL, &ce);
if (p[endcol] == NUL || (cs + end.coladd < ce
// Don't add space for double-wide
// char; endcol will be on last byte
// of multi-byte char.
&& utf_head_off(p, p + endcol) == 0)) {
if (start.lnum == end.lnum && start.col == end.col) {
// Special case: inside a single char
is_oneChar = true;
bdp->startspaces = end.coladd - start.coladd + inclusive;
endcol = startcol;
} else {
bdp->endspaces = end.coladd + inclusive;
endcol -= inclusive;
}
}
}
}
if (endcol == MAXCOL) {
endcol = (colnr_T)strlen(p);
}
if (startcol > endcol || is_oneChar) {
bdp->textlen = 0;
} else {
bdp->textlen = endcol - startcol + inclusive;
}
bdp->textstart = p + startcol;
}
/// Handle the add/subtract operator.
///
/// @param[in] oap Arguments of operator.