Patch 8.1.0037
Problem: Cannot easily append lines to another buffer.
Solution: Add appendbufline().
Files: runtime/doc/eval.txt, src/evalfunc.c,
src/testdir/test_bufline.vim, src/testdir/test_edit.vim
*** ../vim-8.1.0036/runtime/doc/eval.txt 2018-06-03 14:42:17.824505143
+0200
--- runtime/doc/eval.txt 2018-06-06 20:58:47.732807369 +0200
***************
*** 2560,2565 ****
--- 2560,2580 ----
0 for success. Example: >
:let failed = append(line('$'), "# THE END")
:let failed = append(0, ["Chapter 1", "the beginning"])
+
+ appendbufline({expr}, {lnum}, {text}) *appendbufline()*
+ Like |append()| but append the text in buffer {expr}.
+
+ For the use of {expr}, see |bufname()|.
+
+ {lnum} is used like with |append()|. Note that using |line()|
+ would use the current buffer, not the one appending to.
+ Use "$" to append at the end of the buffer.
+
+ On success 0 is returned, on failure 1 is returned.
+
+ If {expr} is not a valid buffer or {lnum} is not valid, an
+ error message is given. Example: >
+ :let failed = appendbufline(13, 0, "# THE START")
<
*argc()*
argc() The result is the number of files in the argument list
of the
*** ../vim-8.1.0036/src/evalfunc.c 2018-06-03 14:42:17.844505109 +0200
--- src/evalfunc.c 2018-06-06 20:58:47.740807362 +0200
***************
*** 40,45 ****
--- 40,46 ----
static void f_add(typval_T *argvars, typval_T *rettv);
static void f_and(typval_T *argvars, typval_T *rettv);
static void f_append(typval_T *argvars, typval_T *rettv);
+ static void f_appendbufline(typval_T *argvars, typval_T *rettv);
static void f_argc(typval_T *argvars, typval_T *rettv);
static void f_argidx(typval_T *argvars, typval_T *rettv);
static void f_arglistid(typval_T *argvars, typval_T *rettv);
***************
*** 487,492 ****
--- 488,494 ----
{"add", 2, 2, f_add},
{"and", 2, 2, f_and},
{"append", 2, 2, f_append},
+ {"appendbufline", 3, 3, f_appendbufline},
{"argc", 0, 0, f_argc},
{"argidx", 0, 0, f_argidx},
{"arglistid", 0, 2, f_arglistid},
***************
*** 1192,1261 ****
}
/*
! * "append(lnum, string/list)" function
*/
static void
! f_append(typval_T *argvars, typval_T *rettv)
{
! long lnum;
! char_u *line;
list_T *l = NULL;
listitem_T *li = NULL;
- typval_T *tv;
long added = 0;
! /* When coming here from Insert mode, sync undo, so that this can be
! * undone separately from what was previously inserted. */
! if (u_sync_once == 2)
{
! u_sync_once = 1; /* notify that u_sync() was called */
! u_sync(TRUE);
}
! lnum = get_tv_lnum(argvars);
! if (lnum >= 0
! && lnum <= curbuf->b_ml.ml_line_count
! && u_save(lnum, lnum + 1) == OK)
{
! if (argvars[1].v_type == VAR_LIST)
! {
! l = argvars[1].vval.v_list;
! if (l == NULL)
! return;
! li = l->lv_first;
! }
! for (;;)
{
! if (l == NULL)
! tv = &argvars[1]; /* append a string */
! else if (li == NULL)
! break; /* end of list */
! else
! tv = &li->li_tv; /* append item from list */
! line = get_tv_string_chk(tv);
! if (line == NULL) /* type error */
{
! rettv->vval.v_number = 1; /* Failed */
break;
}
! ml_append(lnum + added, line, (colnr_T)0, FALSE);
! ++added;
! if (l == NULL)
break;
li = li->li_next;
}
! appended_lines_mark(lnum, added);
! if (curwin->w_cursor.lnum > lnum)
! curwin->w_cursor.lnum += added;
#ifdef FEAT_JOB_CHANNEL
if (bt_prompt(curbuf) && (State & INSERT))
// show the line with the prompt
update_topline();
#endif
}
else
! rettv->vval.v_number = 1; /* Failed */
}
/*
--- 1194,1378 ----
}
/*
! * Get the lnum from the first argument.
! * Also accepts "$", then "buf" is used.
! * Returns 0 on error.
! */
! static linenr_T
! get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
! {
! if (argvars[0].v_type == VAR_STRING
! && argvars[0].vval.v_string != NULL
! && argvars[0].vval.v_string[0] == '$'
! && buf != NULL)
! return buf->b_ml.ml_line_count;
! return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
! }
!
! /*
! * Set line or list of lines in buffer "buf".
*/
static void
! set_buffer_lines(
! buf_T *buf,
! linenr_T lnum_arg,
! int append,
! typval_T *lines,
! typval_T *rettv)
{
! linenr_T lnum = lnum_arg + (append ? 1 : 0);
! char_u *line = NULL;
list_T *l = NULL;
listitem_T *li = NULL;
long added = 0;
+ linenr_T append_lnum;
+ buf_T *curbuf_save = NULL;
+ win_T *curwin_save = NULL;
+ int is_curbuf = buf == curbuf;
! /* When using the current buffer ml_mfp will be set if needed. Useful
when
! * setline() is used on startup. For other buffers the buffer must be
! * loaded. */
! if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
{
! rettv->vval.v_number = 1; /* FAIL */
! return;
}
! if (!is_curbuf)
{
! wininfo_T *wip;
!
! curbuf_save = curbuf;
! curwin_save = curwin;
! curbuf = buf;
! for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
{
! if (wip->wi_win != NULL)
{
! curwin = wip->wi_win;
break;
}
! }
! }
!
! if (append)
! // appendbufline() uses the line number below which we insert
! append_lnum = lnum - 1;
! else
! // setbufline() uses the line number above which we insert, we only
! // append if it's below the last line
! append_lnum = curbuf->b_ml.ml_line_count;
!
! if (lines->v_type == VAR_LIST)
! {
! l = lines->vval.v_list;
! li = l->lv_first;
! }
! else
! line = get_tv_string_chk(lines);
!
! /* default result is zero == OK */
! for (;;)
! {
! if (l != NULL)
! {
! /* list argument, get next string */
! if (li == NULL)
break;
+ line = get_tv_string_chk(&li->li_tv);
li = li->li_next;
}
! rettv->vval.v_number = 1; /* FAIL */
! if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
! break;
!
! /* When coming here from Insert mode, sync undo, so that this can be
! * undone separately from what was previously inserted. */
! if (u_sync_once == 2)
! {
! u_sync_once = 1; /* notify that u_sync() was called */
! u_sync(TRUE);
! }
!
! if (!append && lnum <= curbuf->b_ml.ml_line_count)
! {
! /* existing line, replace it */
! if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
! {
! changed_bytes(lnum, 0);
! if (is_curbuf && lnum == curwin->w_cursor.lnum)
! check_cursor_col();
! rettv->vval.v_number = 0; /* OK */
! }
! }
! else if (added > 0 || u_save(lnum - 1, lnum) == OK)
! {
! /* append the line */
! ++added;
! if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
! rettv->vval.v_number = 0; /* OK */
! }
!
! if (l == NULL) /* only one string argument */
! break;
! ++lnum;
! }
!
! if (added > 0)
! {
! win_T *wp;
! tabpage_T *tp;
!
! appended_lines_mark(append_lnum, added);
! FOR_ALL_TAB_WINDOWS(tp, wp)
! if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
! wp->w_cursor.lnum += added;
! check_cursor_col();
!
#ifdef FEAT_JOB_CHANNEL
if (bt_prompt(curbuf) && (State & INSERT))
// show the line with the prompt
update_topline();
#endif
}
+
+ if (!is_curbuf)
+ {
+ curbuf = curbuf_save;
+ curwin = curwin_save;
+ }
+ }
+
+ /*
+ * "append(lnum, string/list)" function
+ */
+ static void
+ f_append(typval_T *argvars, typval_T *rettv)
+ {
+ linenr_T lnum = get_tv_lnum(&argvars[0]);
+
+ set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
+ }
+
+ /*
+ * "appendbufline(buf, lnum, string/list)" function
+ */
+ static void
+ f_appendbufline(typval_T *argvars, typval_T *rettv)
+ {
+ linenr_T lnum;
+ buf_T *buf;
+
+ buf = get_buf_tv(&argvars[0], FALSE);
+ if (buf == NULL)
+ rettv->vval.v_number = 1; /* FAIL */
else
! {
! lnum = get_tv_lnum_buf(&argvars[1], buf);
! set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
! }
}
/*
***************
*** 4276,4297 ****
}
/*
- * Get the lnum from the first argument.
- * Also accepts "$", then "buf" is used.
- * Returns 0 on error.
- */
- static linenr_T
- get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
- {
- if (argvars[0].v_type == VAR_STRING
- && argvars[0].vval.v_string != NULL
- && argvars[0].vval.v_string[0] == '$'
- && buf != NULL)
- return buf->b_ml.ml_line_count;
- return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
- }
-
- /*
* "getbufline()" function
*/
static void
--- 4393,4398 ----
***************
*** 10226,10340 ****
}
/*
- * Set line or list of lines in buffer "buf".
- */
- static void
- set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
- {
- char_u *line = NULL;
- list_T *l = NULL;
- listitem_T *li = NULL;
- long added = 0;
- linenr_T lcount;
- buf_T *curbuf_save = NULL;
- win_T *curwin_save = NULL;
- int is_curbuf = buf == curbuf;
-
- /* When using the current buffer ml_mfp will be set if needed. Useful
when
- * setline() is used on startup. For other buffers the buffer must be
- * loaded. */
- if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
- {
- rettv->vval.v_number = 1; /* FAIL */
- return;
- }
-
- if (!is_curbuf)
- {
- wininfo_T *wip;
-
- curbuf_save = curbuf;
- curwin_save = curwin;
- curbuf = buf;
- for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
- {
- if (wip->wi_win != NULL)
- {
- curwin = wip->wi_win;
- break;
- }
- }
- }
-
- lcount = curbuf->b_ml.ml_line_count;
-
- if (lines->v_type == VAR_LIST)
- {
- l = lines->vval.v_list;
- li = l->lv_first;
- }
- else
- line = get_tv_string_chk(lines);
-
- /* default result is zero == OK */
- for (;;)
- {
- if (l != NULL)
- {
- /* list argument, get next string */
- if (li == NULL)
- break;
- line = get_tv_string_chk(&li->li_tv);
- li = li->li_next;
- }
-
- rettv->vval.v_number = 1; /* FAIL */
- if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
- break;
-
- /* When coming here from Insert mode, sync undo, so that this can be
- * undone separately from what was previously inserted. */
- if (u_sync_once == 2)
- {
- u_sync_once = 1; /* notify that u_sync() was called */
- u_sync(TRUE);
- }
-
- if (lnum <= curbuf->b_ml.ml_line_count)
- {
- /* existing line, replace it */
- if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
- {
- changed_bytes(lnum, 0);
- if (is_curbuf && lnum == curwin->w_cursor.lnum)
- check_cursor_col();
- rettv->vval.v_number = 0; /* OK */
- }
- }
- else if (added > 0 || u_save(lnum - 1, lnum) == OK)
- {
- /* lnum is one past the last line, append the line */
- ++added;
- if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
- rettv->vval.v_number = 0; /* OK */
- }
-
- if (l == NULL) /* only one string argument */
- break;
- ++lnum;
- }
-
- if (added > 0)
- appended_lines_mark(lcount, added);
-
- if (!is_curbuf)
- {
- curbuf = curbuf_save;
- curwin = curwin_save;
- }
- }
-
- /*
* "setbufline()" function
*/
static void
--- 10327,10332 ----
***************
*** 10351,10358 ****
else
{
lnum = get_tv_lnum_buf(&argvars[1], buf);
!
! set_buffer_lines(buf, lnum, &argvars[2], rettv);
}
}
--- 10343,10349 ----
else
{
lnum = get_tv_lnum_buf(&argvars[1], buf);
! set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
}
}
***************
*** 10512,10518 ****
{
linenr_T lnum = get_tv_lnum(&argvars[0]);
! set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
}
static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T
*action_arg, typval_T *what_arg, typval_T *rettv);
--- 10503,10509 ----
{
linenr_T lnum = get_tv_lnum(&argvars[0]);
! set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
}
static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T
*action_arg, typval_T *what_arg, typval_T *rettv);
*** ../vim-8.1.0036/src/testdir/test_bufline.vim 2017-11-06
21:26:52.000000000 +0100
--- src/testdir/test_bufline.vim 2018-06-06 20:58:47.740807362 +0200
***************
*** 1,4 ****
! " Tests for setbufline() and getbufline()
source shared.vim
--- 1,4 ----
! " Tests for setbufline(), getbufline(), appendbufline()
source shared.vim
***************
*** 65,67 ****
--- 65,92 ----
call delete('Xscript')
call delete('Xtest')
endfunc
+
+ func Test_appendbufline()
+ new
+ let b = bufnr('%')
+ hide
+ call assert_equal(0, appendbufline(b, 0, ['foo', 'bar']))
+ call assert_equal(['foo'], getbufline(b, 1))
+ call assert_equal(['bar'], getbufline(b, 2))
+ call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+ exe "bd!" b
+ call assert_equal([], getbufline(b, 1, 2))
+
+ split Xtest
+ call setline(1, ['a', 'b', 'c'])
+ let b = bufnr('%')
+ wincmd w
+ call assert_equal(1, appendbufline(b, 4, ['x']))
+ call assert_equal(1, appendbufline(1234, 1, ['x']))
+ call assert_equal(0, appendbufline(b, 3, ['d', 'e']))
+ call assert_equal(['c'], getbufline(b, 3))
+ call assert_equal(['d'], getbufline(b, 4))
+ call assert_equal(['e'], getbufline(b, 5))
+ call assert_equal([], getbufline(b, 6))
+ exe "bwipe! " . b
+ endfunc
*** ../vim-8.1.0036/src/testdir/test_edit.vim 2018-06-04 20:34:07.607373577
+0200
--- src/testdir/test_edit.vim 2018-06-06 20:58:47.740807362 +0200
***************
*** 527,533 ****
" Tab in completion mode
let path=expand("%:p:h")
new
! call setline(1, [path."/", ''])
call feedkeys("Arunt\<c-x>\<c-f>\<tab>\<cr>\<esc>", 'tnix')
call assert_match('runtest\.vim', getline(1))
%d
--- 527,533 ----
" Tab in completion mode
let path=expand("%:p:h")
new
! call setline(1, [path. "/", ''])
call feedkeys("Arunt\<c-x>\<c-f>\<tab>\<cr>\<esc>", 'tnix')
call assert_match('runtest\.vim', getline(1))
%d
*** ../vim-8.1.0036/src/version.c 2018-06-06 18:02:31.402773772 +0200
--- src/version.c 2018-06-06 21:00:46.040701324 +0200
***************
*** 763,764 ****
--- 763,766 ----
{ /* Add new patch number below this line */
+ /**/
+ 37,
/**/
--
How To Keep A Healthy Level Of Insanity:
16. Have your coworkers address you by your wrestling name, Rock Hard Kim.
/// Bram Moolenaar -- [email protected] -- 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 ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.