From 5fdca47962fac359e616ef8c6dee3a793cb08168 Mon Sep 17 00:00:00 2001 From: Scott Prager Date: Wed, 3 Sep 2014 01:02:47 -0400 Subject: [PATCH] vim-patch:7.4.243 Problem: Cannot use setreg() to add text that includes a NUL. Solution: Make setreg() accept a list. https://code.google.com/p/vim/source/detail?r=v7-4-243 --- src/nvim/eval.c | 33 ++++- src/nvim/ops.c | 238 +++++++++++++++++++++------------- src/nvim/testdir/test_eval.in | 145 +++++++++++++++++++++ src/nvim/testdir/test_eval.ok | Bin 432 -> 10307 bytes src/nvim/version.c | 2 +- 5 files changed, 322 insertions(+), 96 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 815df19476..2e2871abc5 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -13328,7 +13328,6 @@ static void f_setreg(typval_T *argvars, typval_T *rettv) int regname; char_u *strregname; char_u *stropt; - char_u *strval; int append; char_u yank_type; long block_len; @@ -13345,8 +13344,6 @@ static void f_setreg(typval_T *argvars, typval_T *rettv) regname = *strregname; if (regname == 0 || regname == '@') regname = '"'; - else if (regname == '=') - return; if (argvars[2].v_type != VAR_UNKNOWN) { stropt = get_tv_string_chk(&argvars[2]); @@ -13374,10 +13371,32 @@ static void f_setreg(typval_T *argvars, typval_T *rettv) } } - strval = get_tv_string_chk(&argvars[1]); - if (strval != NULL) - write_reg_contents_ex(regname, strval, -1, - append, yank_type, block_len); + if (argvars[1].v_type == VAR_LIST) { + int len = argvars[1].vval.v_list->lv_len; + char_u **lstval = xmalloc(sizeof(char_u *) * (len + 1)); + char_u **curval = lstval; + + for (listitem_T *li = argvars[1].vval.v_list->lv_first; + li != NULL; + li = li->li_next) { + char_u *strval = get_tv_string_chk(&li->li_tv); + if (strval == NULL) { + free(lstval); + return; + } + *curval++ = strval; + } + *curval++ = NULL; + + write_reg_contents_lst(regname, lstval, -1, append, yank_type, block_len); + 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; } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 82036b1fec..1fa8d15303 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -4762,17 +4762,77 @@ void *get_reg_contents(int regname, int flags) 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` /// /// @see write_reg_contents_ex -void write_reg_contents(int name, - const char_u *str, - ssize_t len, +void write_reg_contents(int name, const char_u *str, ssize_t len, int must_append) { 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` /// /// If `str` ends in '\n' or '\r', use linewise, otherwise use @@ -4799,8 +4859,6 @@ void write_reg_contents_ex(int name, int yank_type, long block_len) { - struct yankreg *old_y_previous, *old_y_current; - if (len < 0) { len = (ssize_t) STRLEN(str); } @@ -4834,29 +4892,16 @@ void write_reg_contents_ex(int name, return; } - if (!valid_yank_reg(name, TRUE)) { /* check for valid reg name */ - emsg_invreg(name); + if (name == '_') { // black hole: nothing to do return; } - if (name == '_') /* black hole: nothing to do */ - return; - - /* 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(); - 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; + 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, str, len, block_len, false); + finish_write_reg(name, old_y_previous, old_y_current); } /// str_to_reg - Put a string into a register. @@ -4868,97 +4913,114 @@ void write_reg_contents_ex(int name, /// @param str string to put in register /// @param len length of the string /// @param blocklen width of visual block -static void str_to_reg(struct yankreg *y_ptr, - int yank_type, - const char_u *str, - long len, - long blocklen) +/// @param str_list True if str is `char_u **`. +static void str_to_reg(struct yankreg *y_ptr, int yank_type, const char_u *str, + long len, long blocklen, bool str_list) { int type; /* MCHAR, MLINE or MBLOCK */ 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; - if (yank_type == MAUTO) - 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); - else + } 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 */ } - /* - * Allocate an array to hold the pointers to the new register lines. - * If the register was not empty, move the existing lines to the new array. - */ - pp = xcalloc((y_ptr->y_size + newlines), sizeof(char_u *)); - for (lnum = 0; lnum < y_ptr->y_size; ++lnum) + // Count the number of lines within the string + size_t newlines = 0; + if (str_list) { + for (char_u **ss = (char_u **) str; *ss != NULL; ++ss) { + newlines++; + } + } else { + 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 + } + } + + // Allocate an array to hold the pointers to the new register lines. + // If the register was not empty, move the existing lines to the new array. + char_u **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; - /* - * Find the end of each line and save it into the array. - */ - for (start = 0; start < len + extraline; start += i + 1) { - // Let i represent the length of one line. - const char_u *p = str + start; - i = (char_u *)xmemscan(p, '\n', len - start) - p; - if (i > maxlen) - maxlen = i; - if (append) { - --lnum; - extra = (int)STRLEN(y_ptr->y_array[lnum]); - } else - extra = 0; - 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]); - if (i) - 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; + // 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) { + int i = STRLEN(*ss); + pp[lnum] = vim_strnsave(*ss, i); + if (i > maxlen) { + maxlen = i; + } + } + } else { + for (start = 0; start < len + extraline; start += i + 1) { + // Let i represent the length of one line. + const char_u *p = str + start; + i = (char_u *)xmemscan(p, '\n', len - start) - p; + if (i > maxlen) { + maxlen = i; + } + if (append) { + --lnum; + extra = (int)STRLEN(y_ptr->y_array[lnum]); + } else { + extra = 0; + } + char_u *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]); + } + if (i) { + 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 } - append = FALSE; /* only first line is appended */ } y_ptr->y_type = type; y_ptr->y_size = lnum; - if (type == MBLOCK) + if (type == MBLOCK) { y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen); - else + } else { y_ptr->y_width = 0; + } } void clear_oparg(oparg_T *oap) diff --git a/src/nvim/testdir/test_eval.in b/src/nvim/testdir/test_eval.in index a29fefc3b6..176e62b9cc 100644 --- a/src/nvim/testdir/test_eval.in +++ b/src/nvim/testdir/test_eval.in @@ -1,7 +1,152 @@ +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 :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() +: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\" +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', "\") +call SetReg('g', 'abcG', 'b10') +call SetReg('h', 'abcH', "\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', "\") +call setreg('g', 'abcG2', 'b10') +call setreg('h', 'abcH2', "\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 +:" +: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 :try diff --git a/src/nvim/testdir/test_eval.ok b/src/nvim/testdir/test_eval.ok index 63b91564424f4eda93efaceb8e17f2eeefa2e9b2..7fe5f1bd1b2745600d74f4bb8a86e7fa1391f607 100644 GIT binary patch literal 10307 zcmc&)NpBNL6!zH?*PKhf1f-zE3p0>W4!s#7Auf!#M02p6CRj3dWIHe@n*Tm;?S8La z?KlwvB;3`tyzhH!RXM)Dzwd`dxeeQLv)y!i=VANfwhZ6?3g0G+yYf6trnB(;>KGo! z|GYQ}<-fPw_t}?yxWzTfRGY{wbyBCMi>;dZ@@}LF??B1ig>0~pXg-y9# zmp7s}^be%x`SIlVB%s0xK4-@-x|0}OA_^v+sO|1vTy!r`&;d90L%m+!{-73W&+?`l&P&VkKp6Ew@j2xez0OLA_kt;^-FWe_VBV`EcOC0K*K)v%&wp*dzMWHSQ z>Jrqs6bx51E(PJzBiL?5xFj|DA-TORm)G;iKxZ}aR28; zH?RR1$|ogl!!VFlwIY);rUp9F-M!_nuunVGufV5N+u8N!hGsY zMn@08C@LaFlt_U@3MFDzIU;*zDUm{m6m3MRAW|YOhy;PyRH0<(z@~si7v6b~ScN=M z0)0&Bb2rfFI0duDRiKSy8}k@xjy1&0B4@Ncv(#u~`BY?4C0n8(S6vC)nJnCz#B7#*!h6SsLU{N5Fa(L&^ z$USnK)wuH8I06_MMLfKLjA4%q=(v9PSZ=p?++ED!?!7NiClEq(2Tz8_|H!c}ekmR5 zF%Bl$>w4k_luI&fgb)@v0!kSOovSA>=iGFt!Gtp{Qe#BSoDQ+!k^@TvVP%Ykw$^*9 zKXGMB9%ouCKcHG=O|7mKDaZ9K7u8B3nq3)5j@YO8@jv^lKnH)D#;LQB&=?@!MGeY1;AL?BU;nxAR--B`wIA;NkN|{1yQhf zs#p=if~VoTiw-Pi5*<^fh4G=4?dT7CBF_jc8|v;0VZyYa%hP&brrHYPicbR|z|+FI zN3`-GZVD}xkNCh0%@GJGCd8|JaDf5Zr;42*+IZTIolHa#q4+ISLxf|h;^l&h878Ec zVOWLNp=*V56>l7N@y(G;nPNl(I$l=edt?<%6fBw&F8Y`~iLw=E&2Y6R4Q$?Mvq zQu-omrG5B}cg1HgP#_sDAWML6`xiFNROz7N zxK5L~C22q?9T_SV8-_bc^mM7>3fLim(X|PPYz`#dZ39hn6!e`|Ny7 zJYxX{u@-11;?sp{m^4$gOBO)nXtJvQkQS`J+fV+C?kAdeWB^sP^R>JYZsnPB7LEt-{qH_>~@hh5-jE$fS13DHQGreZYh zpLyeOS8X1CSC8=(fSwuBCU{#cSC-#W@zh4O9@F2F3+x(1S2J?IB3?XFQgy zLhuq)u3qf+ej~ZFN3^5qgm-$CbQS>O`=MB`SL;o;__v(h(KofT$zoCe7U9$U>vQaR zabEQMZ_dMq)i#vN)!hwva(#36wOqp2x}R6;@cC{z+k!{WWo?VZ{)_HU7kLr}Ct-LJ zMh)4o&%@uVRroqt{&*VMD>y0*oX|gqXXoJ#f4dRh!#CPtvI&#$al3|&Hib{Z{eKM^ zeU*{V$!3!^5IjT@=y?S}Wi0r3LcP--Na=%SUefE=L-ZXb>Fs2@E!WFNvIh7u87N(@ z!K6RJ5+Y%?T5c!vW!QdS1&D#KtF`>1rNtP%i{FP08ejDQ9{;0bdp)oJK1==&vv~-= literal 432 zcmb`E!D_=W5Jd0#iov~Dr$#P>qGKU}+)M6Td*iCulF_c)fPX#~ZAwG0IW02`v&-9K z80*sF-xFe$qV sUAOf(#7`PR2g?0Ca#X=-1$q4eXqq^7W?2@8p0%Cxl;lxZ*I~Bi0y1Qev;Y7A diff --git a/src/nvim/version.c b/src/nvim/version.c index 5a0d8d9d74..722a725df2 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -422,7 +422,7 @@ static int included_patches[] = { //246, 245, //244, - //243, + 243, 242, 241, 240,