0
0
mirror of https://github.com/vim/vim.git synced 2025-09-26 04:04:07 -04:00

updated for version 7.4.243

Problem:    Cannot use setreg() to add text that includes a NUL.
Solution:   Make setreg() accept a list.
This commit is contained in:
Bram Moolenaar
2014-04-02 22:17:10 +02:00
parent b7cb42bc38
commit 5a50c2255c
7 changed files with 358 additions and 92 deletions

View File

@@ -5368,6 +5368,8 @@ setqflist({list} [, {action}]) *setqflist()*
*setreg()* *setreg()*
setreg({regname}, {value} [,{options}]) setreg({regname}, {value} [,{options}])
Set the register {regname} to {value}. Set the register {regname} to {value}.
{value} may be any value returned by |getreg()|, including
a |List|.
If {options} contains "a" or {regname} is upper case, If {options} contains "a" or {regname} is upper case,
then the value is appended. then the value is appended.
{options} can also contain a register type specification: {options} can also contain a register type specification:
@@ -5380,10 +5382,15 @@ setreg({regname}, {value} [,{options}])
in the longest line (counting a <Tab> as 1 character). in the longest line (counting a <Tab> as 1 character).
If {options} contains no register settings, then the default If {options} contains no register settings, then the default
is to use character mode unless {value} ends in a <NL>. is to use character mode unless {value} ends in a <NL> for
Setting the '=' register is not possible, but you can use > string {value} and linewise mode for list {value}. Blockwise
:let @= = var_expr mode is never selected automatically.
< Returns zero for success, non-zero for failure. Returns zero for success, non-zero for failure.
*E883*
Note: you may not use |List| containing more then one item to
set search and expression registers. Lists containing no
items act like empty strings.
Examples: > Examples: >
:call setreg(v:register, @*) :call setreg(v:register, @*)
@@ -5391,8 +5398,11 @@ setreg({regname}, {value} [,{options}])
:call setreg('a', "1\n2\n3", 'b5') :call setreg('a', "1\n2\n3", 'b5')
< This example shows using the functions to save and restore a < This example shows using the functions to save and restore a
register. > register (note: you may not reliably restore register value
:let var_a = getreg('a', 1) without using the third argument to |getreg()| as without it
newlines are represented as newlines AND Nul bytes are
represented as newlines as well, see |NL-used-for-Nul|). >
:let var_a = getreg('a', 1, 1)
:let var_amode = getregtype('a') :let var_amode = getregtype('a')
.... ....
:call setreg('a', var_a, var_amode) :call setreg('a', var_a, var_amode)

View File

@@ -16790,8 +16790,6 @@ f_setreg(argvars, 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)
{ {
@@ -16822,10 +16820,44 @@ f_setreg(argvars, rettv)
} }
} }
strval = get_tv_string_chk(&argvars[1]); if (argvars[1].v_type == VAR_LIST)
if (strval != NULL) {
char_u **lstval;
char_u **curval;
int len = argvars[1].vval.v_list->lv_len;
listitem_T *li;
lstval = (char_u **)alloc(sizeof(char_u *) * (len + 1));
if (lstval == NULL)
return;
curval = lstval;
for (li = argvars[1].vval.v_list->lv_first; li != NULL;
li = li->li_next)
{
/* TODO: this may use a static buffer several times. */
strval = get_tv_string_chk(&li->li_tv);
if (strval == NULL)
{
vim_free(lstval);
return;
}
*curval++ = strval;
}
*curval++ = NULL;
write_reg_contents_lst(regname, lstval, -1,
append, yank_type, block_len);
vim_free(lstval);
}
else
{
strval = get_tv_string_chk(&argvars[1]);
if (strval == NULL)
return;
write_reg_contents_ex(regname, strval, -1, write_reg_contents_ex(regname, strval, -1,
append, yank_type, block_len); append, yank_type, block_len);
}
rettv->vval.v_number = 0; rettv->vval.v_number = 0;
} }

228
src/ops.c
View File

@@ -113,7 +113,7 @@ static char_u *skip_comment __ARGS((char_u *line, int process, int include_space
#endif #endif
static void block_prep __ARGS((oparg_T *oap, struct block_def *, linenr_T, int)); static void block_prep __ARGS((oparg_T *oap, struct block_def *, linenr_T, int));
#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL) #if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
static void str_to_reg __ARGS((struct yankreg *y_ptr, int type, char_u *str, long len, long blocklen)); static void str_to_reg __ARGS((struct yankreg *y_ptr, int type, char_u *str, long len, long blocklen, int str_list));
#endif #endif
static int ends_in_white __ARGS((linenr_T lnum)); static int ends_in_white __ARGS((linenr_T lnum));
#ifdef FEAT_COMMENTS #ifdef FEAT_COMMENTS
@@ -6005,7 +6005,7 @@ clip_yank_selection(type, str, len, cbd)
clip_free_selection(cbd); clip_free_selection(cbd);
str_to_reg(y_ptr, type, str, len, 0L); str_to_reg(y_ptr, type, str, len, 0L, FALSE);
} }
/* /*
@@ -6113,7 +6113,7 @@ dnd_yank_drag_data(str, len)
curr = y_current; curr = y_current;
y_current = &y_regs[TILDE_REGISTER]; y_current = &y_regs[TILDE_REGISTER];
free_yank_all(); free_yank_all();
str_to_reg(y_current, MCHAR, str, len, 0L); str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
y_current = curr; y_current = curr;
} }
#endif #endif
@@ -6308,6 +6308,47 @@ get_reg_contents(regname, flags)
return retval; return retval;
} }
static int
init_write_reg(name, old_y_previous, old_y_current, must_append, yank_type)
int name;
struct yankreg **old_y_previous;
struct yankreg **old_y_current;
int must_append;
int *yank_type UNUSED;
{
if (!valid_yank_reg(name, TRUE)) /* check for valid reg name */
{
emsg_invreg(name);
return FAIL;
}
/* 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 OK;
}
static void
finish_write_reg(name, old_y_previous, old_y_current)
int name;
struct yankreg *old_y_previous;
struct yankreg *old_y_current;
{
# ifdef FEAT_CLIPBOARD
/* Send text of clipboard register to the clipboard. */
may_set_selection();
# endif
/* ':let @" = "val"' should change the meaning of the "" register */
if (name != '"')
y_previous = old_y_previous;
y_current = old_y_current;
}
/* /*
* Store string "str" in register "name". * Store string "str" in register "name".
* "maxlen" is the maximum number of bytes to use, -1 for all bytes. * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
@@ -6327,6 +6368,51 @@ write_reg_contents(name, str, maxlen, must_append)
write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L); write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
} }
void
write_reg_contents_lst(name, strings, maxlen, must_append, yank_type, block_len)
int name;
char_u **strings;
int maxlen UNUSED;
int must_append;
int yank_type;
long block_len;
{
struct yankreg *old_y_previous, *old_y_current;
if (name == '/'
#ifdef FEAT_EVAL
|| name == '='
#endif
)
{
char_u *s;
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;
}
else
s = strings[0];
write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
return;
}
if (name == '_') /* black hole: nothing to do */
return;
if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
&yank_type) == FAIL)
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);
}
void void
write_reg_contents_ex(name, str, maxlen, must_append, yank_type, block_len) write_reg_contents_ex(name, str, maxlen, must_append, yank_type, block_len)
int name; int name;
@@ -6364,40 +6450,22 @@ write_reg_contents_ex(name, str, maxlen, must_append, yank_type, block_len)
s = concat_str(get_expr_line_src(), p); s = concat_str(get_expr_line_src(), p);
vim_free(p); vim_free(p);
p = s; p = s;
} }
set_expr_line(p); set_expr_line(p);
return; return;
} }
#endif #endif
if (!valid_yank_reg(name, TRUE)) /* check for valid reg name */
{
emsg_invreg(name);
return;
}
if (name == '_') /* black hole: nothing to do */ if (name == '_') /* black hole: nothing to do */
return; return;
/* Don't want to change the current (unnamed) register */ if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
old_y_previous = y_previous; &yank_type) == FAIL)
old_y_current = y_current; return;
get_yank_register(name, TRUE); str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
if (!y_append && !must_append)
free_yank_all();
str_to_reg(y_current, yank_type, str, len, block_len);
# ifdef FEAT_CLIPBOARD finish_write_reg(name, old_y_previous, old_y_current);
/* Send text of clipboard register to the clipboard. */
may_set_selection();
# endif
/* ':let @" = "val"' should change the meaning of the "" register */
if (name != '"')
y_previous = old_y_previous;
y_current = old_y_current;
} }
#endif /* FEAT_EVAL */ #endif /* FEAT_EVAL */
@@ -6407,12 +6475,13 @@ write_reg_contents_ex(name, str, maxlen, must_append, yank_type, block_len)
* is appended. * is appended.
*/ */
static void static void
str_to_reg(y_ptr, yank_type, str, len, blocklen) str_to_reg(y_ptr, yank_type, str, len, blocklen, str_list)
struct yankreg *y_ptr; /* pointer to yank register */ struct yankreg *y_ptr; /* pointer to yank register */
int yank_type; /* MCHAR, MLINE, MBLOCK, MAUTO */ int yank_type; /* MCHAR, MLINE, MBLOCK, MAUTO */
char_u *str; /* string to put in register */ char_u *str; /* string to put in register */
long len; /* length of string */ long len; /* length of string */
long blocklen; /* width of Visual block */ long blocklen; /* width of Visual block */
int str_list; /* TRUE if str is char_u ** */
{ {
int type; /* MCHAR, MLINE or MBLOCK */ int type; /* MCHAR, MLINE or MBLOCK */
int lnum; int lnum;
@@ -6423,6 +6492,7 @@ str_to_reg(y_ptr, yank_type, str, len, blocklen)
int extraline = 0; /* extra line at the end */ int extraline = 0; /* extra line at the end */
int append = FALSE; /* append to last line in register */ int append = FALSE; /* append to last line in register */
char_u *s; char_u *s;
char_u **ss;
char_u **pp; char_u **pp;
long maxlen; long maxlen;
@@ -6430,7 +6500,8 @@ str_to_reg(y_ptr, yank_type, str, len, blocklen)
y_ptr->y_size = 0; y_ptr->y_size = 0;
if (yank_type == MAUTO) if (yank_type == MAUTO)
type = ((len > 0 && (str[len - 1] == NL || str[len - 1] == CAR)) type = ((str_list || (len > 0 && (str[len - 1] == NL
|| str[len - 1] == CAR)))
? MLINE : MCHAR); ? MLINE : MCHAR);
else else
type = yank_type; type = yank_type;
@@ -6439,18 +6510,26 @@ str_to_reg(y_ptr, yank_type, str, len, blocklen)
* Count the number of lines within the string * Count the number of lines within the string
*/ */
newlines = 0; newlines = 0;
for (i = 0; i < len; i++) if (str_list)
if (str[i] == '\n') {
for (ss = (char_u **) str; *ss != NULL; ++ss)
++newlines; ++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) else
{ {
append = TRUE; for (i = 0; i < len; i++)
--newlines; /* uncount newline when appending first line */ 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 */
}
} }
/* /*
@@ -6470,40 +6549,53 @@ str_to_reg(y_ptr, yank_type, str, len, blocklen)
/* /*
* Find the end of each line and save it into the array. * Find the end of each line and save it into the array.
*/ */
for (start = 0; start < len + extraline; start += i + 1) if (str_list)
{ {
for (i = start; i < len; ++i) /* find the end of the line */ for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
if (str[i] == '\n') {
i = STRLEN(*ss);
pp[lnum] = vim_strnsave(*ss, i);
if (i > maxlen)
maxlen = i;
}
}
else
{
for (start = 0; start < len + extraline; start += i + 1)
{
for (i = start; i < len; ++i) /* find the end of the line */
if (str[i] == '\n')
break;
i -= start; /* i is now length of line */
if (i > maxlen)
maxlen = i;
if (append)
{
--lnum;
extra = (int)STRLEN(y_ptr->y_array[lnum]);
}
else
extra = 0;
s = alloc((unsigned)(i + extra + 1));
if (s == NULL)
break; break;
i -= start; /* i is now length of line */ if (extra)
if (i > maxlen) mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
maxlen = i; if (append)
if (append) vim_free(y_ptr->y_array[lnum]);
{ if (i)
--lnum; mch_memmove(s + extra, str + start, (size_t)i);
extra = (int)STRLEN(y_ptr->y_array[lnum]); extra += i;
s[extra] = NUL;
y_ptr->y_array[lnum++] = s;
while (--extra >= 0)
{
if (*s == NUL)
*s = '\n'; /* replace NUL with newline */
++s;
}
append = FALSE; /* only first line is appended */
} }
else
extra = 0;
s = alloc((unsigned)(i + extra + 1));
if (s == NULL)
break;
if (extra)
mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
if (append)
vim_free(y_ptr->y_array[lnum]);
if (i)
mch_memmove(s + extra, str + start, (size_t)i);
extra += i;
s[extra] = NUL;
y_ptr->y_array[lnum++] = s;
while (--extra >= 0)
{
if (*s == NUL)
*s = '\n'; /* replace NUL with newline */
++s;
}
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;

View File

@@ -56,6 +56,7 @@ char_u get_reg_type __ARGS((int regname, long *reglen));
char_u *get_reg_contents __ARGS((int regname, int flags)); char_u *get_reg_contents __ARGS((int regname, int flags));
void write_reg_contents __ARGS((int name, char_u *str, int maxlen, int must_append)); void write_reg_contents __ARGS((int name, char_u *str, int maxlen, int must_append));
void write_reg_contents_ex __ARGS((int name, char_u *str, int maxlen, int must_append, int yank_type, long block_len)); void write_reg_contents_ex __ARGS((int name, char_u *str, int maxlen, int must_append, int yank_type, long block_len));
void write_reg_contents_lst __ARGS((int name, char_u **strings, int maxlen, int must_append, int yank_type, long block_len));
void clear_oparg __ARGS((oparg_T *oap)); void clear_oparg __ARGS((oparg_T *oap));
void cursor_pos_info __ARGS((void)); void cursor_pos_info __ARGS((void));
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -1,21 +1,150 @@
Test for various eval features. 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 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'])
$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
:" :"
:" test getreg() :call Test()
/^one
"ay3j:$put =string(getreg('a'))
:$put =string(getreg('a', 1, 1))
:" :"
:/^result/,$w! test.out :delfunction SetReg
:qa! :delfunction AppendRegContents
:delfunction ErrExe
:delfunction Test
:delcommand AR
:call garbagecollect(1)
:"
:/^start:/+1,$wq! test.out
:" vim: et ts=4 isk-=\: fmr=???,???
:call getchar()
ENDTEST ENDTEST
one start:
two
three
four
five
result

Binary file not shown.

View File

@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
243,
/**/ /**/
242, 242,
/**/ /**/