diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2019-06-25 02:36:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-25 02:36:07 +0200 |
commit | 79450f2da97e352676516d63521c18fbac46186b (patch) | |
tree | 67f808bbb479d5c0ae737f079587530a4774a583 /src/nvim/eval.c | |
parent | 8cd87af8d67bd97f1897f527994e4d81cb39e286 (diff) | |
parent | d0e1417254099eb8f8bee066e84d5a49246e737f (diff) | |
download | rneovim-79450f2da97e352676516d63521c18fbac46186b.tar.gz rneovim-79450f2da97e352676516d63521c18fbac46186b.tar.bz2 rneovim-79450f2da97e352676516d63521c18fbac46186b.zip |
Merge #10250 from blueyed/vim-8.0.1039
vim-patch:8.0.{10{39,53,55},1274}: cannot change a line in not current buffer
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 178 |
1 files changed, 118 insertions, 60 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b57d0326d6..cd2888883b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -14957,6 +14957,123 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } +/// 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) +{ + 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; + + const char *line = NULL; + + if (lines->v_type == VAR_LIST) { + l = lines->vval.v_list; + li = tv_list_first(l); + } else { + line = tv_get_string_chk(lines); + } + + // Default result is zero == OK. + for (;; ) { + if (lines->v_type == VAR_LIST) { + // List argument, get next string. + if (li == NULL) { + break; + } + line = tv_get_string_chk(TV_LIST_ITEM_TV(li)); + li = TV_LIST_ITEM_NEXT(l, li); + } + + rettv->vval.v_number = 1; // FAIL + if (line == NULL || lnum < 1 || 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, (char_u *)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, (char_u *)line, 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 f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + linenr_T lnum; + buf_T *buf; + + buf = tv_get_buf(&argvars[0], false); + if (buf == NULL) { + rettv->vval.v_number = 1; // FAIL + } else { + lnum = tv_get_lnum_buf(&argvars[1], buf); + + set_buffer_lines(buf, lnum, &argvars[2], rettv); + } +} + /* * "setbufvar()" function */ @@ -15089,67 +15206,8 @@ static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - list_T *l = NULL; - listitem_T *li = NULL; - long added = 0; - linenr_T lcount = curbuf->b_ml.ml_line_count; - linenr_T lnum = tv_get_lnum(&argvars[0]); - const char *line = NULL; - if (argvars[1].v_type == VAR_LIST) { - l = argvars[1].vval.v_list; - li = tv_list_first(l); - } else { - line = tv_get_string_chk(&argvars[1]); - } - - // Default result is zero == OK. - for (;; ) { - if (argvars[1].v_type == VAR_LIST) { - // List argument, get next string. - if (li == NULL) { - break; - } - line = tv_get_string_chk(TV_LIST_ITEM_TV(li)); - li = TV_LIST_ITEM_NEXT(l, li); - } - - rettv->vval.v_number = 1; // FAIL - if (line == NULL || lnum < 1 || 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, (char_u *)line, true) == OK) { - changed_bytes(lnum, 0); - if (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, (char_u *)line, 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); + set_buffer_lines(curbuf, lnum, &argvars[1], rettv); } /// Create quickfix/location list from VimL values |