mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #1134 from splinterofchaos/getreg-nl
vim-patch:7.4.242 + vim-patch:7.4.243
This commit is contained in:
commit
4c7fe20bef
100
src/nvim/eval.c
100
src/nvim/eval.c
@ -1835,7 +1835,7 @@ ex_let_one (
|
|||||||
|
|
||||||
p = get_tv_string_chk(tv);
|
p = get_tv_string_chk(tv);
|
||||||
if (p != NULL && op != NULL && *op == '.') {
|
if (p != NULL && op != NULL && *op == '.') {
|
||||||
s = get_reg_contents(*arg == '@' ? '"' : *arg, TRUE, TRUE);
|
s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
p = ptofree = concat_str(s, p);
|
p = ptofree = concat_str(s, p);
|
||||||
free(s);
|
free(s);
|
||||||
@ -4076,7 +4076,7 @@ eval7 (
|
|||||||
case '@': ++*arg;
|
case '@': ++*arg;
|
||||||
if (evaluate) {
|
if (evaluate) {
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
rettv->vval.v_string = get_reg_contents(**arg, TRUE, TRUE);
|
rettv->vval.v_string = get_reg_contents(**arg, kGRegExprSrc);
|
||||||
}
|
}
|
||||||
if (**arg != NUL)
|
if (**arg != NUL)
|
||||||
++*arg;
|
++*arg;
|
||||||
@ -6458,7 +6458,7 @@ static struct fst {
|
|||||||
{"getpid", 0, 0, f_getpid},
|
{"getpid", 0, 0, f_getpid},
|
||||||
{"getpos", 1, 1, f_getpos},
|
{"getpos", 1, 1, f_getpos},
|
||||||
{"getqflist", 0, 0, f_getqflist},
|
{"getqflist", 0, 0, f_getqflist},
|
||||||
{"getreg", 0, 2, f_getreg},
|
{"getreg", 0, 3, f_getreg},
|
||||||
{"getregtype", 0, 1, f_getregtype},
|
{"getregtype", 0, 1, f_getregtype},
|
||||||
{"gettabvar", 2, 3, f_gettabvar},
|
{"gettabvar", 2, 3, f_gettabvar},
|
||||||
{"gettabwinvar", 3, 4, f_gettabwinvar},
|
{"gettabwinvar", 3, 4, f_gettabwinvar},
|
||||||
@ -9518,30 +9518,44 @@ static void f_getqflist(typval_T *argvars, typval_T *rettv)
|
|||||||
(void)get_errorlist(wp, rettv->vval.v_list);
|
(void)get_errorlist(wp, rettv->vval.v_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// "getreg()" function
|
||||||
* "getreg()" function
|
|
||||||
*/
|
|
||||||
static void f_getreg(typval_T *argvars, typval_T *rettv)
|
static void f_getreg(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
char_u *strregname;
|
char_u *strregname;
|
||||||
int regname;
|
int regname;
|
||||||
int arg2 = FALSE;
|
int arg2 = false;
|
||||||
int error = FALSE;
|
bool return_list = false;
|
||||||
|
int error = false;
|
||||||
|
|
||||||
if (argvars[0].v_type != VAR_UNKNOWN) {
|
if (argvars[0].v_type != VAR_UNKNOWN) {
|
||||||
strregname = get_tv_string_chk(&argvars[0]);
|
strregname = get_tv_string_chk(&argvars[0]);
|
||||||
error = strregname == NULL;
|
error = strregname == NULL;
|
||||||
if (argvars[1].v_type != VAR_UNKNOWN)
|
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||||
arg2 = get_tv_number_chk(&argvars[1], &error);
|
arg2 = get_tv_number_chk(&argvars[1], &error);
|
||||||
} else
|
if (!error && argvars[2].v_type != VAR_UNKNOWN) {
|
||||||
|
return_list = get_tv_number_chk(&argvars[2], &error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
strregname = vimvars[VV_REG].vv_str;
|
strregname = vimvars[VV_REG].vv_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
regname = (strregname == NULL ? '"' : *strregname);
|
regname = (strregname == NULL ? '"' : *strregname);
|
||||||
if (regname == 0)
|
if (regname == 0)
|
||||||
regname = '"';
|
regname = '"';
|
||||||
|
|
||||||
rettv->v_type = VAR_STRING;
|
if (return_list) {
|
||||||
rettv->vval.v_string = error ? NULL :
|
rettv->v_type = VAR_LIST;
|
||||||
get_reg_contents(regname, TRUE, arg2);
|
rettv->vval.v_list =
|
||||||
|
get_reg_contents(regname, (arg2 ? kGRegExprSrc : 0) | kGRegList);
|
||||||
|
} else {
|
||||||
|
rettv->v_type = VAR_STRING;
|
||||||
|
rettv->vval.v_string = get_reg_contents(regname, arg2 ? kGRegExprSrc : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -13306,7 +13320,6 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
|
|||||||
int regname;
|
int regname;
|
||||||
char_u *strregname;
|
char_u *strregname;
|
||||||
char_u *stropt;
|
char_u *stropt;
|
||||||
char_u *strval;
|
|
||||||
int append;
|
int append;
|
||||||
char_u yank_type;
|
char_u yank_type;
|
||||||
long block_len;
|
long block_len;
|
||||||
@ -13323,8 +13336,6 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
|
|||||||
regname = *strregname;
|
regname = *strregname;
|
||||||
if (regname == 0 || regname == '@')
|
if (regname == 0 || regname == '@')
|
||||||
regname = '"';
|
regname = '"';
|
||||||
else if (regname == '=')
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||||
stropt = get_tv_string_chk(&argvars[2]);
|
stropt = get_tv_string_chk(&argvars[2]);
|
||||||
@ -13352,10 +13363,46 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strval = get_tv_string_chk(&argvars[1]);
|
if (argvars[1].v_type == VAR_LIST) {
|
||||||
if (strval != NULL)
|
int len = argvars[1].vval.v_list->lv_len;
|
||||||
write_reg_contents_ex(regname, strval, -1,
|
// First half: use for pointers to result lines; second half: use for
|
||||||
append, yank_type, block_len);
|
// pointers to allocated copies.
|
||||||
|
char_u **lstval = xmalloc(sizeof(char_u *) * ((len + 1) * 2));
|
||||||
|
char_u **curval = lstval;
|
||||||
|
char_u **allocval = lstval + len + 2;
|
||||||
|
char_u **curallocval = allocval;
|
||||||
|
|
||||||
|
char_u buf[NUMBUFLEN];
|
||||||
|
for (listitem_T *li = argvars[1].vval.v_list->lv_first;
|
||||||
|
li != NULL;
|
||||||
|
li = li->li_next) {
|
||||||
|
char_u *strval = get_tv_string_buf_chk(&li->li_tv, buf);
|
||||||
|
if (strval == NULL) {
|
||||||
|
goto free_lstval;
|
||||||
|
}
|
||||||
|
if (strval == buf) {
|
||||||
|
// Need to make a copy,
|
||||||
|
// next get_tv_string_buf_chk() will overwrite the string.
|
||||||
|
strval = vim_strsave(buf);
|
||||||
|
*curallocval++ = strval;
|
||||||
|
}
|
||||||
|
*curval++ = strval;
|
||||||
|
}
|
||||||
|
*curval++ = NULL;
|
||||||
|
|
||||||
|
write_reg_contents_lst(regname, lstval, -1, append, yank_type, block_len);
|
||||||
|
|
||||||
|
free_lstval:
|
||||||
|
while (curallocval > allocval)
|
||||||
|
free(*--curallocval);
|
||||||
|
free(lstval);
|
||||||
|
} else {
|
||||||
|
char_u *strval = get_tv_string_chk(&argvars[1]);
|
||||||
|
if (strval == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write_reg_contents_ex(regname, strval, -1, append, yank_type, block_len);
|
||||||
|
}
|
||||||
rettv->vval.v_number = 0;
|
rettv->vval.v_number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16279,28 +16326,33 @@ static linenr_T get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
|
|||||||
* get_tv_string_chk() and get_tv_string_buf_chk() are similar, but return
|
* get_tv_string_chk() and get_tv_string_buf_chk() are similar, but return
|
||||||
* NULL on error.
|
* NULL on error.
|
||||||
*/
|
*/
|
||||||
static char_u *get_tv_string(typval_T *varp)
|
static char_u *get_tv_string(const typval_T *varp)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
|
||||||
{
|
{
|
||||||
static char_u mybuf[NUMBUFLEN];
|
static char_u mybuf[NUMBUFLEN];
|
||||||
|
|
||||||
return get_tv_string_buf(varp, mybuf);
|
return get_tv_string_buf(varp, mybuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char_u *get_tv_string_buf(typval_T *varp, char_u *buf)
|
static char_u *get_tv_string_buf(const typval_T *varp, char_u *buf)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
|
||||||
{
|
{
|
||||||
char_u *res = get_tv_string_buf_chk(varp, buf);
|
char_u *res = get_tv_string_buf_chk(varp, buf);
|
||||||
|
|
||||||
return res != NULL ? res : (char_u *)"";
|
return res != NULL ? res : (char_u *)"";
|
||||||
}
|
}
|
||||||
|
|
||||||
char_u *get_tv_string_chk(typval_T *varp)
|
/// Careful: This uses a single, static buffer. YOU CAN ONLY USE IT ONCE!
|
||||||
|
char_u *get_tv_string_chk(const typval_T *varp)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
static char_u mybuf[NUMBUFLEN];
|
static char_u mybuf[NUMBUFLEN];
|
||||||
|
|
||||||
return get_tv_string_buf_chk(varp, mybuf);
|
return get_tv_string_buf_chk(varp, mybuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char_u *get_tv_string_buf_chk(typval_T *varp, char_u *buf)
|
static char_u *get_tv_string_buf_chk(const typval_T *varp, char_u *buf)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
switch (varp->v_type) {
|
switch (varp->v_type) {
|
||||||
case VAR_NUMBER:
|
case VAR_NUMBER:
|
||||||
|
@ -234,6 +234,43 @@ void memchrsub(void *data, char c, char x, size_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Counts the number of occurrences of `c` in `str`.
|
||||||
|
///
|
||||||
|
/// @warning Unsafe if `c == NUL`.
|
||||||
|
///
|
||||||
|
/// @param str Pointer to the string to search.
|
||||||
|
/// @param c The byte to search for.
|
||||||
|
/// @returns the number of occurrences of `c` in `str`.
|
||||||
|
size_t strcnt(const char *str, char c, size_t len)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
|
||||||
|
{
|
||||||
|
assert(c != 0);
|
||||||
|
size_t cnt = 0;
|
||||||
|
while ((str = strchr(str, c))) {
|
||||||
|
cnt++;
|
||||||
|
str++; // Skip the instance of c.
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Counts the number of occurrences of byte `c` in `data[len]`.
|
||||||
|
///
|
||||||
|
/// @param data Pointer to the data to search.
|
||||||
|
/// @param c The byte to search for.
|
||||||
|
/// @param len The length of `data`.
|
||||||
|
/// @returns the number of occurrences of `c` in `data[len]`.
|
||||||
|
size_t memcnt(const void *data, char c, size_t len)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
|
||||||
|
{
|
||||||
|
size_t cnt = 0;
|
||||||
|
const char *ptr = data, *end = ptr + len;
|
||||||
|
while ((ptr = memchr(ptr, c, (size_t)(end - ptr))) != NULL) {
|
||||||
|
cnt++;
|
||||||
|
ptr++; // Skip the instance of c.
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
/// The xstpcpy() function shall copy the string pointed to by src (including
|
/// The xstpcpy() function shall copy the string pointed to by src (including
|
||||||
/// the terminating NUL character) into the array pointed to by dst.
|
/// the terminating NUL character) into the array pointed to by dst.
|
||||||
///
|
///
|
||||||
|
328
src/nvim/ops.c
328
src/nvim/ops.c
@ -4654,30 +4654,43 @@ char_u get_reg_type(int regname, long *reglen)
|
|||||||
return MAUTO;
|
return MAUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// When `flags` has `kGRegList` return a list with text `s`.
|
||||||
* Return the contents of a register as a single allocated string.
|
/// Otherwise just return `s`.
|
||||||
* Used for "@r" in expressions and for getreg().
|
///
|
||||||
* Returns NULL for error.
|
/// Returns a void * for use in get_reg_contents().
|
||||||
*/
|
static void *get_reg_wrap_one_line(char_u *s, int flags)
|
||||||
char_u *
|
{
|
||||||
get_reg_contents (
|
if (!(flags & kGRegList)) {
|
||||||
int regname,
|
return s;
|
||||||
int allowexpr, /* allow "=" register */
|
}
|
||||||
int expr_src /* get expression for "=" register */
|
list_T *list = list_alloc();
|
||||||
)
|
list_append_string(list, NULL, -1);
|
||||||
|
list->lv_first->li_tv.vval.v_string = s;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the contents of a register.
|
||||||
|
/// @remark Used for `@r` in expressions and for `getreg()`.
|
||||||
|
///
|
||||||
|
/// @param regname The register.
|
||||||
|
/// @param flags see @ref GRegFlags
|
||||||
|
///
|
||||||
|
/// @returns The contents of the register as an allocated string.
|
||||||
|
/// @returns A linked list when `flags` contains @ref kGRegList.
|
||||||
|
/// @returns NULL for error.
|
||||||
|
void *get_reg_contents(int regname, int flags)
|
||||||
{
|
{
|
||||||
long i;
|
long i;
|
||||||
char_u *retval;
|
|
||||||
int allocated;
|
|
||||||
|
|
||||||
/* Don't allow using an expression register inside an expression */
|
// Don't allow using an expression register inside an expression.
|
||||||
if (regname == '=') {
|
if (regname == '=') {
|
||||||
if (allowexpr) {
|
if (flags & kGRegNoExpr) {
|
||||||
if (expr_src)
|
return NULL;
|
||||||
return get_expr_line_src();
|
|
||||||
return get_expr_line();
|
|
||||||
}
|
}
|
||||||
return NULL;
|
if (flags & kGRegExprSrc) {
|
||||||
|
return get_reg_wrap_one_line(get_expr_line_src(), flags);
|
||||||
|
}
|
||||||
|
return get_reg_wrap_one_line(get_expr_line(), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regname == '@') /* "@@" is used for unnamed register */
|
if (regname == '@') /* "@@" is used for unnamed register */
|
||||||
@ -4689,18 +4702,30 @@ get_reg_contents (
|
|||||||
|
|
||||||
get_clipboard(regname);
|
get_clipboard(regname);
|
||||||
|
|
||||||
|
char_u *retval;
|
||||||
|
int allocated;
|
||||||
if (get_spec_reg(regname, &retval, &allocated, FALSE)) {
|
if (get_spec_reg(regname, &retval, &allocated, FALSE)) {
|
||||||
if (retval == NULL)
|
if (retval == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!allocated)
|
if (allocated) {
|
||||||
retval = vim_strsave(retval);
|
return get_reg_wrap_one_line(retval, flags);
|
||||||
return retval;
|
}
|
||||||
|
return get_reg_wrap_one_line(vim_strsave(retval), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
get_yank_register(regname, FALSE);
|
get_yank_register(regname, FALSE);
|
||||||
if (y_current->y_array == NULL)
|
if (y_current->y_array == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (flags & kGRegList) {
|
||||||
|
list_T *list = list_alloc();
|
||||||
|
for (int i = 0; i < y_current->y_size; ++i) {
|
||||||
|
list_append_string(list, y_current->y_array[i], -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute length of resulting string.
|
* Compute length of resulting string.
|
||||||
*/
|
*/
|
||||||
@ -4737,17 +4762,77 @@ get_reg_contents (
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool init_write_reg(int name, struct yankreg **old_y_previous,
|
||||||
|
struct yankreg **old_y_current, int must_append)
|
||||||
|
{
|
||||||
|
if (!valid_yank_reg(name, true)) { // check for valid reg name
|
||||||
|
emsg_invreg(name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't want to change the current (unnamed) register.
|
||||||
|
*old_y_previous = y_previous;
|
||||||
|
*old_y_current = y_current;
|
||||||
|
|
||||||
|
get_yank_register(name, true);
|
||||||
|
if (!y_append && !must_append) {
|
||||||
|
free_yank_all();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void finish_write_reg(int name, struct yankreg *old_y_previous,
|
||||||
|
struct yankreg *old_y_current)
|
||||||
|
{
|
||||||
|
// Send text of clipboard register to the clipboard.
|
||||||
|
set_clipboard(name);
|
||||||
|
|
||||||
|
// ':let @" = "val"' should change the meaning of the "" register
|
||||||
|
if (name != '"') {
|
||||||
|
y_previous = old_y_previous;
|
||||||
|
}
|
||||||
|
y_current = old_y_current;
|
||||||
|
}
|
||||||
|
|
||||||
/// write_reg_contents - store `str` in register `name`
|
/// write_reg_contents - store `str` in register `name`
|
||||||
///
|
///
|
||||||
/// @see write_reg_contents_ex
|
/// @see write_reg_contents_ex
|
||||||
void write_reg_contents(int name,
|
void write_reg_contents(int name, const char_u *str, ssize_t len,
|
||||||
const char_u *str,
|
|
||||||
ssize_t len,
|
|
||||||
int must_append)
|
int must_append)
|
||||||
{
|
{
|
||||||
write_reg_contents_ex(name, str, len, must_append, MAUTO, 0L);
|
write_reg_contents_ex(name, str, len, must_append, MAUTO, 0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void write_reg_contents_lst(int name, char_u **strings, int maxlen,
|
||||||
|
int must_append, int yank_type, long block_len)
|
||||||
|
{
|
||||||
|
if (name == '/' || name == '=') {
|
||||||
|
char_u *s = strings[0];
|
||||||
|
if (strings[0] == NULL) {
|
||||||
|
s = (char_u *)"";
|
||||||
|
} else if (strings[1] != NULL) {
|
||||||
|
EMSG(_("E883: search pattern and expression register may not "
|
||||||
|
"contain two or more lines"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// black hole: nothing to do
|
||||||
|
if (name == '_') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct yankreg *old_y_previous, *old_y_current;
|
||||||
|
if (!init_write_reg(name, &old_y_previous, &old_y_current, must_append)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
str_to_reg(y_current, yank_type, (char_u *) strings, -1, block_len, true);
|
||||||
|
finish_write_reg(name, old_y_previous, old_y_current);
|
||||||
|
}
|
||||||
|
|
||||||
/// write_reg_contents_ex - store `str` in register `name`
|
/// write_reg_contents_ex - store `str` in register `name`
|
||||||
///
|
///
|
||||||
/// If `str` ends in '\n' or '\r', use linewise, otherwise use
|
/// If `str` ends in '\n' or '\r', use linewise, otherwise use
|
||||||
@ -4774,8 +4859,6 @@ void write_reg_contents_ex(int name,
|
|||||||
int yank_type,
|
int yank_type,
|
||||||
long block_len)
|
long block_len)
|
||||||
{
|
{
|
||||||
struct yankreg *old_y_previous, *old_y_current;
|
|
||||||
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
len = (ssize_t) STRLEN(str);
|
len = (ssize_t) STRLEN(str);
|
||||||
}
|
}
|
||||||
@ -4809,29 +4892,16 @@ void write_reg_contents_ex(int name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid_yank_reg(name, TRUE)) { /* check for valid reg name */
|
if (name == '_') { // black hole: nothing to do
|
||||||
emsg_invreg(name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == '_') /* black hole: nothing to do */
|
struct yankreg *old_y_previous, *old_y_current;
|
||||||
return;
|
if (!init_write_reg(name, &old_y_previous, &old_y_current, must_append)) {
|
||||||
|
return;
|
||||||
/* Don't want to change the current (unnamed) register */
|
}
|
||||||
old_y_previous = y_previous;
|
str_to_reg(y_current, yank_type, str, len, block_len, false);
|
||||||
old_y_current = y_current;
|
finish_write_reg(name, old_y_previous, old_y_current);
|
||||||
|
|
||||||
get_yank_register(name, TRUE);
|
|
||||||
if (!y_append && !must_append)
|
|
||||||
free_yank_all();
|
|
||||||
str_to_reg(y_current, yank_type, str, len, block_len);
|
|
||||||
set_clipboard(name);
|
|
||||||
|
|
||||||
|
|
||||||
/* ':let @" = "val"' should change the meaning of the "" register */
|
|
||||||
if (name != '"')
|
|
||||||
y_previous = old_y_previous;
|
|
||||||
y_current = old_y_current;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// str_to_reg - Put a string into a register.
|
/// str_to_reg - Put a string into a register.
|
||||||
@ -4840,100 +4910,100 @@ void write_reg_contents_ex(int name,
|
|||||||
///
|
///
|
||||||
/// @param y_ptr pointer to yank register
|
/// @param y_ptr pointer to yank register
|
||||||
/// @param yank_type MCHAR, MLINE, MBLOCK or MAUTO
|
/// @param yank_type MCHAR, MLINE, MBLOCK or MAUTO
|
||||||
/// @param str string to put in register
|
/// @param str string or list of strings to put in register
|
||||||
/// @param len length of the string
|
/// @param len length of the string (Ignored when str_list=true.)
|
||||||
/// @param blocklen width of visual block
|
/// @param blocklen width of visual block, or -1 for "I don't know."
|
||||||
static void str_to_reg(struct yankreg *y_ptr,
|
/// @param str_list True if str is `char_u **`.
|
||||||
int yank_type,
|
static void str_to_reg(struct yankreg *y_ptr, int yank_type, const char_u *str,
|
||||||
const char_u *str,
|
size_t len, colnr_T blocklen, bool str_list)
|
||||||
long len,
|
FUNC_ATTR_NONNULL_ALL
|
||||||
long blocklen)
|
|
||||||
{
|
{
|
||||||
int type; /* MCHAR, MLINE or MBLOCK */
|
if (y_ptr->y_array == NULL) { // NULL means empty register
|
||||||
int lnum;
|
|
||||||
long start;
|
|
||||||
long i;
|
|
||||||
int extra;
|
|
||||||
size_t newlines; /* number of lines added */
|
|
||||||
int extraline = 0; /* extra line at the end */
|
|
||||||
int append = FALSE; /* append to last line in register */
|
|
||||||
char_u *s;
|
|
||||||
char_u **pp;
|
|
||||||
long maxlen;
|
|
||||||
|
|
||||||
if (y_ptr->y_array == NULL) /* NULL means empty register */
|
|
||||||
y_ptr->y_size = 0;
|
y_ptr->y_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (yank_type == MAUTO)
|
int type = yank_type; // MCHAR, MLINE or MBLOCK
|
||||||
type = ((len > 0 && (str[len - 1] == NL || str[len - 1] == CAR))
|
if (yank_type == MAUTO) {
|
||||||
|
type = ((str_list ||
|
||||||
|
(len > 0 && (str[len - 1] == NL || str[len - 1] == CAR)))
|
||||||
? MLINE : MCHAR);
|
? MLINE : MCHAR);
|
||||||
else
|
|
||||||
type = yank_type;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Count the number of lines within the string
|
|
||||||
*/
|
|
||||||
newlines = 0;
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
if (str[i] == '\n')
|
|
||||||
++newlines;
|
|
||||||
if (type == MCHAR || len == 0 || str[len - 1] != '\n') {
|
|
||||||
extraline = 1;
|
|
||||||
++newlines; /* count extra newline at the end */
|
|
||||||
}
|
|
||||||
if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) {
|
|
||||||
append = TRUE;
|
|
||||||
--newlines; /* uncount newline when appending first line */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
size_t newlines = 0;
|
||||||
* Allocate an array to hold the pointers to the new register lines.
|
bool extraline = false; // extra line at the end
|
||||||
* If the register was not empty, move the existing lines to the new array.
|
bool append = false; // append to last line in register
|
||||||
*/
|
|
||||||
pp = xcalloc((y_ptr->y_size + newlines), sizeof(char_u *));
|
|
||||||
for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
|
|
||||||
pp[lnum] = y_ptr->y_array[lnum];
|
|
||||||
free(y_ptr->y_array);
|
|
||||||
y_ptr->y_array = pp;
|
|
||||||
maxlen = 0;
|
|
||||||
|
|
||||||
/*
|
// Count the number of lines within the string
|
||||||
* Find the end of each line and save it into the array.
|
if (str_list) {
|
||||||
*/
|
for (char_u **ss = (char_u **) str; *ss != NULL; ++ss) {
|
||||||
for (start = 0; start < len + extraline; start += i + 1) {
|
newlines++;
|
||||||
// Let i represent the length of one line.
|
}
|
||||||
const char_u *p = str + start;
|
} else {
|
||||||
i = (char_u *)xmemscan(p, '\n', len - start) - p;
|
newlines = memcnt(str, '\n', len);
|
||||||
if (i > maxlen)
|
if (type == MCHAR || len == 0 || str[len - 1] != '\n') {
|
||||||
maxlen = i;
|
extraline = 1;
|
||||||
if (append) {
|
++newlines; // count extra newline at the end
|
||||||
--lnum;
|
}
|
||||||
extra = (int)STRLEN(y_ptr->y_array[lnum]);
|
if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) {
|
||||||
} else
|
append = true;
|
||||||
extra = 0;
|
--newlines; // uncount newline when appending first line
|
||||||
s = xmalloc(i + extra + 1);
|
}
|
||||||
if (extra)
|
}
|
||||||
memmove(s, y_ptr->y_array[lnum], (size_t)extra);
|
|
||||||
if (append)
|
|
||||||
free(y_ptr->y_array[lnum]);
|
// Grow the register array to hold the pointers to the new lines.
|
||||||
if (i)
|
char_u **pp = xrealloc(y_ptr->y_array,
|
||||||
memmove(s + extra, str + start, (size_t)i);
|
(y_ptr->y_size + newlines) * sizeof(char_u *));
|
||||||
extra += i;
|
y_ptr->y_array = pp;
|
||||||
s[extra] = NUL;
|
|
||||||
y_ptr->y_array[lnum++] = s;
|
linenr_T lnum = y_ptr->y_size; // The current line number.
|
||||||
while (--extra >= 0) {
|
|
||||||
if (*s == NUL)
|
// If called with `blocklen < 0`, we have to update the yank reg's width.
|
||||||
*s = '\n'; /* replace NUL with newline */
|
size_t maxlen = 0;
|
||||||
++s;
|
|
||||||
|
// Find the end of each line and save it into the array.
|
||||||
|
if (str_list) {
|
||||||
|
for (char_u **ss = (char_u **) str; *ss != NULL; ++ss, ++lnum) {
|
||||||
|
size_t ss_len = STRLEN(*ss);
|
||||||
|
pp[lnum] = xmemdupz(*ss, ss_len);
|
||||||
|
if (ss_len > maxlen) {
|
||||||
|
maxlen = ss_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size_t line_len;
|
||||||
|
for (const char_u *start = str, *end = str + len;
|
||||||
|
start < end + extraline;
|
||||||
|
start += line_len + 1, lnum++) {
|
||||||
|
line_len = (const char_u *) xmemscan(start, '\n', end - start) - start;
|
||||||
|
if (line_len > maxlen) {
|
||||||
|
maxlen = line_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When appending, copy the previous line and free it after.
|
||||||
|
size_t extra = append ? STRLEN(pp[--lnum]) : 0;
|
||||||
|
char_u *s = xmallocz(line_len + extra);
|
||||||
|
memcpy(s, pp[lnum], extra);
|
||||||
|
memcpy(s + extra, start, line_len);
|
||||||
|
ssize_t s_len = extra + line_len;
|
||||||
|
|
||||||
|
if (append) {
|
||||||
|
free(pp[lnum]);
|
||||||
|
append = false; // only first line is appended
|
||||||
|
}
|
||||||
|
pp[lnum] = s;
|
||||||
|
|
||||||
|
// Convert NULs to '\n' to prevent truncation.
|
||||||
|
memchrsub(pp[lnum], NUL, '\n', s_len);
|
||||||
}
|
}
|
||||||
append = FALSE; /* only first line is appended */
|
|
||||||
}
|
}
|
||||||
y_ptr->y_type = type;
|
y_ptr->y_type = type;
|
||||||
y_ptr->y_size = lnum;
|
y_ptr->y_size = lnum;
|
||||||
if (type == MBLOCK)
|
if (type == MBLOCK) {
|
||||||
y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
|
y_ptr->y_width = (blocklen == -1 ? (colnr_T) maxlen - 1 : blocklen);
|
||||||
else
|
} else {
|
||||||
y_ptr->y_width = 0;
|
y_ptr->y_width = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_oparg(oparg_T *oap)
|
void clear_oparg(oparg_T *oap)
|
||||||
|
@ -47,6 +47,13 @@ typedef int (*Indenter)(void);
|
|||||||
#define OP_FORMAT2 26 /* "gw" format operator, keeps cursor pos */
|
#define OP_FORMAT2 26 /* "gw" format operator, keeps cursor pos */
|
||||||
#define OP_FUNCTION 27 /* "g@" call 'operatorfunc' */
|
#define OP_FUNCTION 27 /* "g@" call 'operatorfunc' */
|
||||||
|
|
||||||
|
/// Flags for get_reg_contents().
|
||||||
|
enum GRegFlags {
|
||||||
|
kGRegNoExpr = 1, ///< Do not allow expression register.
|
||||||
|
kGRegExprSrc = 2, ///< Return expression itself for "=" register.
|
||||||
|
kGRegList = 4 ///< Return list.
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "ops.h.generated.h"
|
# include "ops.h.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,7 +1,154 @@
|
|||||||
|
Test for various eval features. vim: set ft=vim :
|
||||||
|
|
||||||
|
Note: system clipboard support is not tested. I do not think anybody will thank
|
||||||
|
me for messing with clipboard.
|
||||||
|
|
||||||
STARTTEST
|
STARTTEST
|
||||||
:so small.vim
|
:so small.vim
|
||||||
:set encoding=latin1
|
:set encoding=latin1
|
||||||
:set noswapfile
|
:set noswapfile
|
||||||
|
:lang C
|
||||||
|
:fun AppendRegContents(reg)
|
||||||
|
call append('$', printf('%s: type %s; value: %s (%s), expr: %s (%s)', a:reg, getregtype(a:reg), getreg(a:reg), string(getreg(a:reg, 0, 1)), getreg(a:reg, 1), string(getreg(a:reg, 1, 1))))
|
||||||
|
endfun
|
||||||
|
:command -nargs=? AR :call AppendRegContents(<q-args>)
|
||||||
|
:fun SetReg(...)
|
||||||
|
call call('setreg', a:000)
|
||||||
|
call append('$', printf('{{{2 setreg(%s)', string(a:000)[1:-2]))
|
||||||
|
call AppendRegContents(a:1)
|
||||||
|
if a:1 isnot# '='
|
||||||
|
execute "silent normal! Go==\n==\e\"".a:1."P"
|
||||||
|
endif
|
||||||
|
endfun
|
||||||
|
:fun ErrExe(str)
|
||||||
|
call append('$', 'Executing '.a:str)
|
||||||
|
try
|
||||||
|
execute a:str
|
||||||
|
catch
|
||||||
|
$put =v:exception
|
||||||
|
endtry
|
||||||
|
endfun
|
||||||
|
:fun Test()
|
||||||
|
$put ='{{{1 let tests'
|
||||||
|
let @" = 'abc'
|
||||||
|
AR "
|
||||||
|
let @" = "abc\n"
|
||||||
|
AR "
|
||||||
|
let @" = "abc\<C-m>"
|
||||||
|
AR "
|
||||||
|
let @= = '"abc"'
|
||||||
|
AR =
|
||||||
|
|
||||||
|
$put ='{{{1 Basic setreg tests'
|
||||||
|
call SetReg('a', 'abcA', 'c')
|
||||||
|
call SetReg('b', 'abcB', 'v')
|
||||||
|
call SetReg('c', 'abcC', 'l')
|
||||||
|
call SetReg('d', 'abcD', 'V')
|
||||||
|
call SetReg('e', 'abcE', 'b')
|
||||||
|
call SetReg('f', 'abcF', "\<C-v>")
|
||||||
|
call SetReg('g', 'abcG', 'b10')
|
||||||
|
call SetReg('h', 'abcH', "\<C-v>10")
|
||||||
|
call SetReg('I', 'abcI')
|
||||||
|
|
||||||
|
$put ='{{{1 Appending single lines with setreg()'
|
||||||
|
call SetReg('A', 'abcAc', 'c')
|
||||||
|
call SetReg('A', 'abcAl', 'l')
|
||||||
|
call SetReg('A', 'abcAc2','c')
|
||||||
|
call SetReg('b', 'abcBc', 'ca')
|
||||||
|
call SetReg('b', 'abcBb', 'ba')
|
||||||
|
call SetReg('b', 'abcBc2','ca')
|
||||||
|
call SetReg('b', 'abcBb2','b50a')
|
||||||
|
|
||||||
|
call SetReg('C', 'abcCl', 'l')
|
||||||
|
call SetReg('C', 'abcCc', 'c')
|
||||||
|
call SetReg('D', 'abcDb', 'b')
|
||||||
|
|
||||||
|
call SetReg('E', 'abcEb', 'b')
|
||||||
|
call SetReg('E', 'abcEl', 'l')
|
||||||
|
call SetReg('F', 'abcFc', 'c')
|
||||||
|
|
||||||
|
$put ='{{{1 Appending NL with setreg()'
|
||||||
|
call setreg('a', 'abcA2', 'c')
|
||||||
|
call setreg('b', 'abcB2', 'v')
|
||||||
|
call setreg('c', 'abcC2', 'l')
|
||||||
|
call setreg('d', 'abcD2', 'V')
|
||||||
|
call setreg('e', 'abcE2', 'b')
|
||||||
|
call setreg('f', 'abcF2', "\<C-v>")
|
||||||
|
call setreg('g', 'abcG2', 'b10')
|
||||||
|
call setreg('h', 'abcH2', "\<C-v>10")
|
||||||
|
call setreg('I', 'abcI2')
|
||||||
|
|
||||||
|
call SetReg('A', "\n")
|
||||||
|
call SetReg('B', "\n", 'c')
|
||||||
|
call SetReg('C', "\n")
|
||||||
|
call SetReg('D', "\n", 'l')
|
||||||
|
call SetReg('E', "\n")
|
||||||
|
call SetReg('F', "\n", 'b')
|
||||||
|
|
||||||
|
$put ='{{{1 Setting lists with setreg()'
|
||||||
|
call SetReg('a', ['abcA3'], 'c')
|
||||||
|
call SetReg('b', ['abcB3'], 'l')
|
||||||
|
call SetReg('c', ['abcC3'], 'b')
|
||||||
|
call SetReg('d', ['abcD3'])
|
||||||
|
call SetReg('e', [1, 2, 'abc', 3])
|
||||||
|
call SetReg('f', [1, 2, 3])
|
||||||
|
|
||||||
|
$put ='{{{1 Appending lists with setreg()'
|
||||||
|
call SetReg('A', ['abcA3c'], 'c')
|
||||||
|
call SetReg('b', ['abcB3l'], 'la')
|
||||||
|
call SetReg('C', ['abcC3b'], 'lb')
|
||||||
|
call SetReg('D', ['abcD32'])
|
||||||
|
|
||||||
|
call SetReg('A', ['abcA32'])
|
||||||
|
call SetReg('B', ['abcB3c'], 'c')
|
||||||
|
call SetReg('C', ['abcC3l'], 'l')
|
||||||
|
call SetReg('D', ['abcD3b'], 'b')
|
||||||
|
|
||||||
|
$put ='{{{1 Appending lists with NL with setreg()'
|
||||||
|
call SetReg('A', ["\n", 'abcA3l2'], 'l')
|
||||||
|
call SetReg('B', ["\n", 'abcB3c2'], 'c')
|
||||||
|
call SetReg('C', ["\n", 'abcC3b2'], 'b')
|
||||||
|
call SetReg('D', ["\n", 'abcD3b50'],'b50')
|
||||||
|
|
||||||
|
$put ='{{{1 Setting lists with NLs with setreg()'
|
||||||
|
call SetReg('a', ['abcA4-0', "\n", "abcA4-2\n", "\nabcA4-3", "abcA4-4\nabcA4-4-2"])
|
||||||
|
call SetReg('b', ['abcB4c-0', "\n", "abcB4c-2\n", "\nabcB4c-3", "abcB4c-4\nabcB4c-4-2"], 'c')
|
||||||
|
call SetReg('c', ['abcC4l-0', "\n", "abcC4l-2\n", "\nabcC4l-3", "abcC4l-4\nabcC4l-4-2"], 'l')
|
||||||
|
call SetReg('d', ['abcD4b-0', "\n", "abcD4b-2\n", "\nabcD4b-3", "abcD4b-4\nabcD4b-4-2"], 'b')
|
||||||
|
call SetReg('e', ['abcE4b10-0', "\n", "abcE4b10-2\n", "\nabcE4b10-3", "abcE4b10-4\nabcE4b10-4-2"], 'b10')
|
||||||
|
|
||||||
|
$put ='{{{1 Search and expressions'
|
||||||
|
call SetReg('/', ['abc/'])
|
||||||
|
call SetReg('/', ["abc/\n"])
|
||||||
|
call SetReg('=', ['"abc/"'])
|
||||||
|
call SetReg('=', ["\"abc/\n\""])
|
||||||
|
|
||||||
|
$put ='{{{1 Errors'
|
||||||
|
call ErrExe('call setreg()')
|
||||||
|
call ErrExe('call setreg(1)')
|
||||||
|
call ErrExe('call setreg(1, 2, 3, 4)')
|
||||||
|
call ErrExe('call setreg([], 2)')
|
||||||
|
call ErrExe('call setreg(1, {})')
|
||||||
|
call ErrExe('call setreg(1, 2, [])')
|
||||||
|
call ErrExe('call setreg("/", ["1", "2"])')
|
||||||
|
call ErrExe('call setreg("=", ["1", "2"])')
|
||||||
|
call ErrExe('call setreg(1, ["", "", [], ""])')
|
||||||
|
endfun
|
||||||
|
:"
|
||||||
|
:call Test()
|
||||||
|
:"
|
||||||
|
:delfunction SetReg
|
||||||
|
:delfunction AppendRegContents
|
||||||
|
:delfunction ErrExe
|
||||||
|
:delfunction Test
|
||||||
|
:delcommand AR
|
||||||
|
:call garbagecollect(1)
|
||||||
|
:"
|
||||||
|
:/^start:/+1,$wq! test.out
|
||||||
|
:" vim: et ts=4 isk-=\: fmr=???,???
|
||||||
|
:call getchar()
|
||||||
|
:e test.out
|
||||||
|
:%d
|
||||||
|
|
||||||
:" function name not starting with a capital
|
:" function name not starting with a capital
|
||||||
:try
|
:try
|
||||||
|
Binary file not shown.
@ -416,14 +416,14 @@ static int included_patches[] = {
|
|||||||
//252 NA
|
//252 NA
|
||||||
251,
|
251,
|
||||||
//250 NA
|
//250 NA
|
||||||
//249,
|
249,
|
||||||
248,
|
248,
|
||||||
247,
|
247,
|
||||||
//246,
|
//246,
|
||||||
245,
|
245,
|
||||||
//244,
|
//244,
|
||||||
//243,
|
243,
|
||||||
//242,
|
242,
|
||||||
241,
|
241,
|
||||||
240,
|
240,
|
||||||
239,
|
239,
|
||||||
|
Loading…
Reference in New Issue
Block a user