Patch 8.2.0997

148 views
Skip to first unread message

Bram Moolenaar

unread,
Jun 17, 2020, 3:48:07 PM6/17/20
to vim...@googlegroups.com

Patch 8.2.0997
Problem: Cannot execute a register containing line continuation.
Solution: Concatenate lines where needed. (Yegappan Lakshmanan,
closes #6272)
Files: runtime/doc/repeat.txt, src/register.c,
src/testdir/test_registers.vim


*** ../vim-8.2.0996/runtime/doc/repeat.txt 2019-12-17 21:27:14.690319902 +0100
--- runtime/doc/repeat.txt 2020-06-17 21:43:51.089410095 +0200
***************
*** 158,163 ****
--- 163,173 ----
result of evaluating the expression is executed as an
Ex command.
Mappings are not recognized in these commands.
+ When the |line-continuation| character (\) is present
+ at the beginning of a line in a linewise register,
+ then it is combined with the previous line. This is
+ useful for yanking and executing parts of a Vim
+ script.
Future: Will execute the register for each line in the
address range.

*** ../vim-8.2.0996/src/register.c 2020-06-12 22:59:07.270097188 +0200
--- src/register.c 2020-06-17 21:43:51.089410095 +0200
***************
*** 474,479 ****
--- 474,546 ----
}

/*
+ * When executing a register as a series of ex-commands, if the
+ * line-continuation character is used for a line, then join it with one or
+ * more previous lines. Note that lines are processed backwards starting from
+ * the last line in the register.
+ *
+ * Arguments:
+ * lines - list of lines in the register
+ * idx - index of the line starting with \ or "\. Join this line with all the
+ * immediate predecessor lines that start with a \ and the first line
+ * that doesn't start with a \. Lines that start with a comment "\
+ * character are ignored.
+ *
+ * Returns the concatenated line. The index of the line that should be
+ * processed next is returned in idx.
+ */
+ static char_u *
+ execreg_line_continuation(char_u **lines, long *idx)
+ {
+ garray_T ga;
+ long i = *idx;
+ char_u *p;
+ int cmd_start;
+ int cmd_end = i;
+ int j;
+ char_u *str;
+
+ ga_init2(&ga, (int)sizeof(char_u), 400);
+
+ // search backwards to find the first line of this command.
+ // Any line not starting with \ or "\ is the start of the
+ // command.
+ while (--i > 0)
+ {
+ p = skipwhite(lines[i]);
+ if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' '))
+ break;
+ }
+ cmd_start = i;
+
+ // join all the lines
+ ga_concat(&ga, lines[cmd_start]);
+ for (j = cmd_start + 1; j <= cmd_end; j++)
+ {
+ p = skipwhite(lines[j]);
+ if (*p == '\\')
+ {
+ // Adjust the growsize to the current length to
+ // speed up concatenating many lines.
+ if (ga.ga_len > 400)
+ {
+ if (ga.ga_len > 8000)
+ ga.ga_growsize = 8000;
+ else
+ ga.ga_growsize = ga.ga_len;
+ }
+ ga_concat(&ga, p + 1);
+ }
+ }
+ ga_append(&ga, NUL);
+ str = vim_strsave(ga.ga_data);
+ ga_clear(&ga);
+
+ *idx = i;
+ return str;
+ }
+
+ /*
* Execute a yank register: copy it into the stuff buffer.
*
* Return FAIL for failure, OK otherwise.
***************
*** 579,584 ****
--- 646,653 ----
for (i = y_current->y_size; --i >= 0; )
{
char_u *escaped;
+ char_u *str;
+ int free_str = FALSE;

// insert NL between lines and after last line if type is MLINE
if (y_current->y_type == MLINE || i < y_current->y_size - 1
***************
*** 587,593 ****
if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
return FAIL;
}
! escaped = vim_strsave_escape_csi(y_current->y_array[i]);
if (escaped == NULL)
return FAIL;
retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
--- 656,678 ----
if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
return FAIL;
}
!
! // Handle line-continuation for :@<register>
! str = y_current->y_array[i];
! if (colon && i > 0)
! {
! p = skipwhite(str);
! if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))
! {
! str = execreg_line_continuation(y_current->y_array, &i);
! if (str == NULL)
! return FAIL;
! free_str = TRUE;
! }
! }
! escaped = vim_strsave_escape_csi(str);
! if (free_str)
! vim_free(str);
if (escaped == NULL)
return FAIL;
retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
*** ../vim-8.2.0996/src/testdir/test_registers.vim 2020-06-07 21:31:14.778405833 +0200
--- src/testdir/test_registers.vim 2020-06-17 21:43:51.089410095 +0200
***************
*** 557,560 ****
--- 557,636 ----
bwipe!
endfunc

+ " Test for executing the contents of a register as an Ex command with line
+ " continuation.
+ func Test_execute_reg_as_ex_cmd()
+ " Line continuation with just two lines
+ let code =<< trim END
+ let l = [
+ \ 1]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1], l)
+
+ " Line continuation with more than two lines
+ let code =<< trim END
+ let l = [
+ \ 1,
+ \ 2,
+ \ 3]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2, 3], l)
+
+ " use comments interspersed with code
+ let code =<< trim END
+ let l = [
+ "\ one
+ \ 1,
+ "\ two
+ \ 2,
+ "\ three
+ \ 3]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2, 3], l)
+
+ " use line continuation in the middle
+ let code =<< trim END
+ let a = "one"
+ let l = [
+ \ 1,
+ \ 2]
+ let b = "two"
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2], l)
+ call assert_equal("one", a)
+ call assert_equal("two", b)
+
+ " only one line with a \
+ let @r = "\\let l = 1"
+ call assert_fails('@r', 'E10:')
+
+ " only one line with a "\
+ let @r = ' "\ let i = 1'
+ @r
+ call assert_false(exists('i'))
+
+ " first line also begins with a \
+ let @r = "\\let l = [\n\\ 1]"
+ call assert_fails('@r', 'E10:')
+
+ " Test with a large number of lines
+ let @r = "let str = \n"
+ let @r ..= repeat(" \\ 'abcdefghijklmnopqrstuvwxyz' ..\n", 312)
+ let @r ..= ' \ ""'
+ @r
+ call assert_equal(repeat('abcdefghijklmnopqrstuvwxyz', 312), str)
+ endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.0996/src/version.c 2020-06-17 21:41:31.973819210 +0200
--- src/version.c 2020-06-17 21:45:29.945120090 +0200
***************
*** 756,757 ****
--- 756,759 ----
{ /* Add new patch number below this line */
+ /**/
+ 997,
/**/

--
GUEST: He's killed the best man!
SECOND GUEST: (holding a limp WOMAN) He's killed my auntie.
FATHER: No, please! This is supposed to be a happy occasion! Let's
not bicker and argue about who killed who ...
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages