blob: 625ab8fb252cf8001ca793d2deba8116ff4ccb36 [file] [log] [blame]
Bram Moolenaar261f3462019-09-07 15:45:32 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalbuffer.c: Buffer related builtin functions
12 */
13
14#include "vim.h"
15
16#if defined(FEAT_EVAL) || defined(PROTO)
17/*
18 * Mark references in functions of buffers.
19 */
20 int
21set_ref_in_buffers(int copyID)
22{
23 int abort = FALSE;
24 buf_T *bp;
25
26 FOR_ALL_BUFFERS(bp)
27 {
28 listener_T *lnr;
Bram Moolenaar261f3462019-09-07 15:45:32 +020029
30 for (lnr = bp->b_listener; !abort && lnr != NULL; lnr = lnr->lr_next)
Yegappan Lakshmanan6ae8fae2021-12-12 16:26:44 +000031 abort = abort || set_ref_in_callback(&lnr->lr_callback, copyID);
Bram Moolenaar261f3462019-09-07 15:45:32 +020032# ifdef FEAT_JOB_CHANNEL
Yegappan Lakshmanan6ae8fae2021-12-12 16:26:44 +000033 if (!abort)
34 abort = abort || set_ref_in_callback(&bp->b_prompt_callback, copyID);
35 if (!abort)
36 abort = abort || set_ref_in_callback(&bp->b_prompt_interrupt, copyID);
Bram Moolenaar261f3462019-09-07 15:45:32 +020037# endif
Yegappan Lakshmanan6ae8fae2021-12-12 16:26:44 +000038#ifdef FEAT_COMPL_FUNC
39 if (!abort)
40 abort = abort || set_ref_in_callback(&bp->b_cfu_cb, copyID);
41 if (!abort)
42 abort = abort || set_ref_in_callback(&bp->b_ofu_cb, copyID);
43 if (!abort)
44 abort = abort || set_ref_in_callback(&bp->b_tsrfu_cb, copyID);
45#endif
46 if (!abort)
47 abort = abort || set_ref_in_callback(&bp->b_tfu_cb, copyID);
Bram Moolenaar261f3462019-09-07 15:45:32 +020048 if (abort)
49 break;
50 }
51 return abort;
52}
53
54 buf_T *
55buflist_find_by_name(char_u *name, int curtab_only)
56{
57 int save_magic;
58 char_u *save_cpo;
59 buf_T *buf;
60
61 // Ignore 'magic' and 'cpoptions' here to make scripts portable
62 save_magic = p_magic;
63 p_magic = TRUE;
64 save_cpo = p_cpo;
Bram Moolenaare5a2dc82021-01-03 19:52:05 +010065 p_cpo = empty_option;
Bram Moolenaar261f3462019-09-07 15:45:32 +020066
67 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
68 TRUE, FALSE, curtab_only));
69
70 p_magic = save_magic;
71 p_cpo = save_cpo;
72 return buf;
73}
74
75/*
76 * Find a buffer by number or exact name.
77 */
78 buf_T *
79find_buffer(typval_T *avar)
80{
81 buf_T *buf = NULL;
82
83 if (avar->v_type == VAR_NUMBER)
84 buf = buflist_findnr((int)avar->vval.v_number);
Bram Moolenaar7b45d462021-03-27 19:09:02 +010085 else if (in_vim9script() && check_for_string_arg(avar, 0) == FAIL)
86 return NULL;
Bram Moolenaar261f3462019-09-07 15:45:32 +020087 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
88 {
89 buf = buflist_findname_exp(avar->vval.v_string);
90 if (buf == NULL)
91 {
92 // No full path name match, try a match with a URL or a "nofile"
93 // buffer, these don't use the full path.
94 FOR_ALL_BUFFERS(buf)
95 if (buf->b_fname != NULL
Bram Moolenaar6d4b2f52022-08-25 15:11:15 +010096 && (path_with_url(buf->b_fname) || bt_nofilename(buf))
Bram Moolenaar261f3462019-09-07 15:45:32 +020097 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
98 break;
99 }
100 }
101 return buf;
102}
103
104/*
105 * If there is a window for "curbuf", make it the current window.
106 */
107 static void
108find_win_for_curbuf(void)
109{
110 wininfo_T *wip;
111
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200112 FOR_ALL_BUF_WININFO(curbuf, wip)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200113 {
114 if (wip->wi_win != NULL)
115 {
116 curwin = wip->wi_win;
117 break;
118 }
119 }
120}
121
122/*
Bram Moolenaar34453202021-01-31 13:08:38 +0100123 * Set line or list of lines in buffer "buf" to "lines".
124 * Any type is allowed and converted to a string.
Bram Moolenaar261f3462019-09-07 15:45:32 +0200125 */
126 static void
127set_buffer_lines(
128 buf_T *buf,
129 linenr_T lnum_arg,
130 int append,
131 typval_T *lines,
132 typval_T *rettv)
133{
134 linenr_T lnum = lnum_arg + (append ? 1 : 0);
135 char_u *line = NULL;
136 list_T *l = NULL;
137 listitem_T *li = NULL;
138 long added = 0;
139 linenr_T append_lnum;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200140 win_T *curwin_save = NULL;
Bram Moolenaarc934bfa2022-11-19 13:59:43 +0000141 aco_save_T aco;
142 int using_aco = FALSE;
Bram Moolenaar0ad00a72022-05-22 11:59:25 +0100143 int save_VIsual_active = VIsual_active;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200144
145 // When using the current buffer ml_mfp will be set if needed. Useful when
146 // setline() is used on startup. For other buffers the buffer must be
147 // loaded.
Bram Moolenaarc934bfa2022-11-19 13:59:43 +0000148 int is_curbuf = buf == curbuf;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200149 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
150 {
151 rettv->vval.v_number = 1; // FAIL
Bram Moolenaar8dac2ac2021-12-27 20:57:06 +0000152 if (in_vim9script() && lnum < 1)
153 semsg(_(e_invalid_line_number_nr), lnum_arg);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200154 return;
155 }
156
157 if (!is_curbuf)
158 {
Bram Moolenaarc934bfa2022-11-19 13:59:43 +0000159 // Set "curbuf" to the buffer being changed. Then make sure there is a
160 // window for it to handle any side effects.
Bram Moolenaar0ad00a72022-05-22 11:59:25 +0100161 VIsual_active = FALSE;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200162 curwin_save = curwin;
163 curbuf = buf;
Bram Moolenaarc934bfa2022-11-19 13:59:43 +0000164 find_win_for_curbuf(); // simplest: find existing window for "buf"
165
166 if (curwin->w_buffer != buf)
167 {
168 // No existing window for this buffer. It is dangerous to have
169 // curwin->w_buffer differ from "curbuf", use the autocmd window.
170 curbuf = curwin->w_buffer;
171 aucmd_prepbuf(&aco, buf);
172 using_aco = TRUE;
173 }
Bram Moolenaar261f3462019-09-07 15:45:32 +0200174 }
175
176 if (append)
177 // appendbufline() uses the line number below which we insert
178 append_lnum = lnum - 1;
179 else
180 // setbufline() uses the line number above which we insert, we only
181 // append if it's below the last line
182 append_lnum = curbuf->b_ml.ml_line_count;
183
184 if (lines->v_type == VAR_LIST)
185 {
186 l = lines->vval.v_list;
Bram Moolenaarad48e6c2020-04-21 22:19:45 +0200187 if (l == NULL || list_len(l) == 0)
188 {
Bram Moolenaarcd9c8d42022-11-05 23:46:43 +0000189 // not appending anything always succeeds
Bram Moolenaarad48e6c2020-04-21 22:19:45 +0200190 goto done;
191 }
Bram Moolenaar7e9f3512020-05-13 22:44:22 +0200192 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200193 li = l->lv_first;
194 }
195 else
Bram Moolenaar34453202021-01-31 13:08:38 +0100196 line = typval_tostring(lines, FALSE);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200197
198 // default result is zero == OK
199 for (;;)
200 {
201 if (l != NULL)
202 {
203 // list argument, get next string
204 if (li == NULL)
205 break;
Bram Moolenaar34453202021-01-31 13:08:38 +0100206 vim_free(line);
207 line = typval_tostring(&li->li_tv, FALSE);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200208 li = li->li_next;
209 }
210
211 rettv->vval.v_number = 1; // FAIL
212 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
213 break;
214
215 // When coming here from Insert mode, sync undo, so that this can be
216 // undone separately from what was previously inserted.
217 if (u_sync_once == 2)
218 {
219 u_sync_once = 1; // notify that u_sync() was called
220 u_sync(TRUE);
221 }
222
223 if (!append && lnum <= curbuf->b_ml.ml_line_count)
224 {
225 // Existing line, replace it.
226 // Removes any existing text properties.
227 if (u_savesub(lnum) == OK && ml_replace_len(
228 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
229 {
230 changed_bytes(lnum, 0);
231 if (is_curbuf && lnum == curwin->w_cursor.lnum)
232 check_cursor_col();
233 rettv->vval.v_number = 0; // OK
234 }
235 }
236 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
237 {
238 // append the line
239 ++added;
240 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
241 rettv->vval.v_number = 0; // OK
242 }
243
244 if (l == NULL) // only one string argument
245 break;
246 ++lnum;
247 }
Bram Moolenaar34453202021-01-31 13:08:38 +0100248 vim_free(line);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200249
250 if (added > 0)
251 {
252 win_T *wp;
253 tabpage_T *tp;
254
255 appended_lines_mark(append_lnum, added);
256
257 // Only adjust the cursor for buffers other than the current, unless it
258 // is the current window. For curbuf and other windows it has been
259 // done in mark_adjust_internal().
260 FOR_ALL_TAB_WINDOWS(tp, wp)
261 if (wp->w_buffer == buf
262 && (wp->w_buffer != curbuf || wp == curwin)
263 && wp->w_cursor.lnum > append_lnum)
264 wp->w_cursor.lnum += added;
265 check_cursor_col();
Bram Moolenaar58a3cae2022-09-08 13:43:10 +0100266
267 // Only update the window view if w_buffer matches curbuf, otherwise
268 // the computations will be wrong.
269 if (curwin->w_buffer == curbuf)
270 update_topline();
Bram Moolenaar261f3462019-09-07 15:45:32 +0200271 }
272
Bram Moolenaarad48e6c2020-04-21 22:19:45 +0200273done:
Bram Moolenaar261f3462019-09-07 15:45:32 +0200274 if (!is_curbuf)
275 {
Bram Moolenaarc934bfa2022-11-19 13:59:43 +0000276 if (using_aco)
277 {
278 aucmd_restbuf(&aco);
279 }
280 else
281 {
282 curwin = curwin_save;
283 curbuf = curwin->w_buffer;
284 }
Bram Moolenaar0ad00a72022-05-22 11:59:25 +0100285 VIsual_active = save_VIsual_active;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200286 }
287}
288
289/*
290 * "append(lnum, string/list)" function
291 */
292 void
293f_append(typval_T *argvars, typval_T *rettv)
294{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200295 linenr_T lnum;
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000296 int did_emsg_before = did_emsg;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200297
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200298 if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
299 return;
300
301 lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000302 if (did_emsg == did_emsg_before)
303 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200304}
305
306/*
Yegappan Lakshmanan4a155042021-07-30 21:32:45 +0200307 * Set or append lines to a buffer.
Bram Moolenaar261f3462019-09-07 15:45:32 +0200308 */
Yegappan Lakshmanan4a155042021-07-30 21:32:45 +0200309 static void
310buf_set_append_line(typval_T *argvars, typval_T *rettv, int append)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200311{
312 linenr_T lnum;
313 buf_T *buf;
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000314 int did_emsg_before = did_emsg;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200315
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200316 if (in_vim9script()
317 && (check_for_buffer_arg(argvars, 0) == FAIL
318 || check_for_lnum_arg(argvars, 1) == FAIL
319 || check_for_string_or_number_or_list_arg(argvars, 2) == FAIL))
320 return;
321
Bram Moolenaar261f3462019-09-07 15:45:32 +0200322 buf = tv_get_buf(&argvars[0], FALSE);
323 if (buf == NULL)
324 rettv->vval.v_number = 1; // FAIL
325 else
326 {
327 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000328 if (did_emsg == did_emsg_before)
329 set_buffer_lines(buf, lnum, append, &argvars[2], rettv);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200330 }
331}
332
333/*
Yegappan Lakshmanan4a155042021-07-30 21:32:45 +0200334 * "appendbufline(buf, lnum, string/list)" function
335 */
336 void
337f_appendbufline(typval_T *argvars, typval_T *rettv)
338{
339 buf_set_append_line(argvars, rettv, TRUE);
340}
341
342/*
Bram Moolenaar261f3462019-09-07 15:45:32 +0200343 * "bufadd(expr)" function
344 */
345 void
346f_bufadd(typval_T *argvars, typval_T *rettv)
347{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200348 char_u *name;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200349
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200350 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
351 return;
352
353 name = tv_get_string(&argvars[0]);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200354 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
355}
356
357/*
358 * "bufexists(expr)" function
359 */
360 void
361f_bufexists(typval_T *argvars, typval_T *rettv)
362{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200363 if (in_vim9script() && check_for_buffer_arg(argvars, 0) == FAIL)
364 return;
365
Bram Moolenaar261f3462019-09-07 15:45:32 +0200366 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
367}
368
369/*
370 * "buflisted(expr)" function
371 */
372 void
373f_buflisted(typval_T *argvars, typval_T *rettv)
374{
375 buf_T *buf;
376
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200377 if (in_vim9script() && check_for_buffer_arg(argvars, 0) == FAIL)
378 return;
379
Bram Moolenaar261f3462019-09-07 15:45:32 +0200380 buf = find_buffer(&argvars[0]);
381 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
382}
383
384/*
385 * "bufload(expr)" function
386 */
387 void
388f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
389{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200390 buf_T *buf;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200391
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200392 if (in_vim9script() && check_for_buffer_arg(argvars, 0) == FAIL)
393 return;
394
395 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200396 if (buf != NULL)
397 buffer_ensure_loaded(buf);
398}
399
400/*
401 * "bufloaded(expr)" function
402 */
403 void
404f_bufloaded(typval_T *argvars, typval_T *rettv)
405{
406 buf_T *buf;
407
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200408 if (in_vim9script() && check_for_buffer_arg(argvars, 0) == FAIL)
409 return;
410
Bram Moolenaar261f3462019-09-07 15:45:32 +0200411 buf = find_buffer(&argvars[0]);
412 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
413}
414
415/*
416 * "bufname(expr)" function
417 */
418 void
419f_bufname(typval_T *argvars, typval_T *rettv)
420{
421 buf_T *buf;
Bram Moolenaar02aaad92020-08-30 21:26:57 +0200422 typval_T *tv = &argvars[0];
Bram Moolenaar261f3462019-09-07 15:45:32 +0200423
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200424 if (in_vim9script() && check_for_opt_buffer_arg(argvars, 0) == FAIL)
425 return;
426
Bram Moolenaar02aaad92020-08-30 21:26:57 +0200427 if (tv->v_type == VAR_UNKNOWN)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200428 buf = curbuf;
429 else
Bram Moolenaar3767e3a2020-09-01 23:06:01 +0200430 buf = tv_get_buf_from_arg(tv);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200431 rettv->v_type = VAR_STRING;
432 if (buf != NULL && buf->b_fname != NULL)
433 rettv->vval.v_string = vim_strsave(buf->b_fname);
434 else
435 rettv->vval.v_string = NULL;
436}
437
438/*
439 * "bufnr(expr)" function
440 */
441 void
442f_bufnr(typval_T *argvars, typval_T *rettv)
443{
444 buf_T *buf;
445 int error = FALSE;
446 char_u *name;
447
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200448 if (in_vim9script()
Yegappan Lakshmanancd917202021-07-21 19:09:09 +0200449 && (check_for_opt_buffer_arg(argvars, 0) == FAIL
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200450 || (argvars[0].v_type != VAR_UNKNOWN
451 && check_for_opt_bool_arg(argvars, 1) == FAIL)))
452 return;
453
Bram Moolenaar261f3462019-09-07 15:45:32 +0200454 if (argvars[0].v_type == VAR_UNKNOWN)
455 buf = curbuf;
456 else
Bram Moolenaar3767e3a2020-09-01 23:06:01 +0200457 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200458
459 // If the buffer isn't found and the second argument is not zero create a
460 // new buffer.
461 if (buf == NULL
462 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaarfe136c92020-09-04 18:35:26 +0200463 && tv_get_bool_chk(&argvars[1], &error) != 0
Bram Moolenaar261f3462019-09-07 15:45:32 +0200464 && !error
465 && (name = tv_get_string_chk(&argvars[0])) != NULL
466 && !error)
467 buf = buflist_new(name, NULL, (linenr_T)1, 0);
468
469 if (buf != NULL)
470 rettv->vval.v_number = buf->b_fnum;
471 else
472 rettv->vval.v_number = -1;
473}
474
475 static void
476buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
477{
478 win_T *wp;
479 int winnr = 0;
480 buf_T *buf;
481
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200482 if (in_vim9script() && check_for_buffer_arg(argvars, 0) == FAIL)
483 return;
484
Bram Moolenaar3767e3a2020-09-01 23:06:01 +0200485 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200486 FOR_ALL_WINDOWS(wp)
487 {
488 ++winnr;
489 if (wp->w_buffer == buf)
490 break;
491 }
492 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200493}
494
495/*
496 * "bufwinid(nr)" function
497 */
498 void
499f_bufwinid(typval_T *argvars, typval_T *rettv)
500{
501 buf_win_common(argvars, rettv, FALSE);
502}
503
504/*
505 * "bufwinnr(nr)" function
506 */
507 void
508f_bufwinnr(typval_T *argvars, typval_T *rettv)
509{
510 buf_win_common(argvars, rettv, TRUE);
511}
512
513/*
514 * "deletebufline()" function
515 */
516 void
517f_deletebufline(typval_T *argvars, typval_T *rettv)
518{
519 buf_T *buf;
520 linenr_T first, last;
521 linenr_T lnum;
522 long count;
523 int is_curbuf;
524 buf_T *curbuf_save = NULL;
525 win_T *curwin_save = NULL;
526 tabpage_T *tp;
527 win_T *wp;
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000528 int did_emsg_before = did_emsg;
LemonBoy9b2edfd2022-05-22 15:35:53 +0100529 int save_VIsual_active = VIsual_active;
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000530
531 rettv->vval.v_number = 1; // FAIL by default
Bram Moolenaar261f3462019-09-07 15:45:32 +0200532
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200533 if (in_vim9script()
534 && (check_for_buffer_arg(argvars, 0) == FAIL
535 || check_for_lnum_arg(argvars, 1) == FAIL
536 || check_for_opt_lnum_arg(argvars, 2) == FAIL))
537 return;
538
Bram Moolenaar261f3462019-09-07 15:45:32 +0200539 buf = tv_get_buf(&argvars[0], FALSE);
540 if (buf == NULL)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200541 return;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200542 is_curbuf = buf == curbuf;
543
544 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000545 if (did_emsg > did_emsg_before)
546 return;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200547 if (argvars[2].v_type != VAR_UNKNOWN)
548 last = tv_get_lnum_buf(&argvars[2], buf);
549 else
550 last = first;
551
552 if (buf->b_ml.ml_mfp == NULL || first < 1
553 || first > buf->b_ml.ml_line_count || last < first)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200554 return;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200555
zeertzjq7af3ee22022-11-06 22:26:05 +0000556 // After this don't use "return", goto "cleanup"!
Bram Moolenaar261f3462019-09-07 15:45:32 +0200557 if (!is_curbuf)
558 {
LemonBoy9b2edfd2022-05-22 15:35:53 +0100559 VIsual_active = FALSE;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200560 curbuf_save = curbuf;
561 curwin_save = curwin;
562 curbuf = buf;
563 find_win_for_curbuf();
564 }
565 if (last > curbuf->b_ml.ml_line_count)
566 last = curbuf->b_ml.ml_line_count;
567 count = last - first + 1;
568
569 // When coming here from Insert mode, sync undo, so that this can be
570 // undone separately from what was previously inserted.
571 if (u_sync_once == 2)
572 {
573 u_sync_once = 1; // notify that u_sync() was called
574 u_sync(TRUE);
575 }
576
577 if (u_save(first - 1, last + 1) == FAIL)
zeertzjq7af3ee22022-11-06 22:26:05 +0000578 goto cleanup;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200579
zeertzjq7af3ee22022-11-06 22:26:05 +0000580 for (lnum = first; lnum <= last; ++lnum)
581 ml_delete_flags(first, ML_DEL_MESSAGE);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200582
zeertzjq7af3ee22022-11-06 22:26:05 +0000583 FOR_ALL_TAB_WINDOWS(tp, wp)
584 if (wp->w_buffer == buf)
585 {
586 if (wp->w_cursor.lnum > last)
587 wp->w_cursor.lnum -= count;
588 else if (wp->w_cursor.lnum > first)
589 wp->w_cursor.lnum = first;
590 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
591 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
592 wp->w_valid = 0;
593 if (wp->w_cursor.lnum <= wp->w_topline)
594 wp->w_topline = 1;
595 }
596 check_cursor_col();
597 deleted_lines_mark(first, count);
598 rettv->vval.v_number = 0; // OK
599
600cleanup:
Bram Moolenaar261f3462019-09-07 15:45:32 +0200601 if (!is_curbuf)
602 {
603 curbuf = curbuf_save;
604 curwin = curwin_save;
LemonBoy9b2edfd2022-05-22 15:35:53 +0100605 VIsual_active = save_VIsual_active;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200606 }
607}
608
609/*
610 * Returns buffer options, variables and other attributes in a dictionary.
611 */
612 static dict_T *
613get_buffer_info(buf_T *buf)
614{
615 dict_T *dict;
616 tabpage_T *tp;
617 win_T *wp;
618 list_T *windows;
619
620 dict = dict_alloc();
621 if (dict == NULL)
622 return NULL;
623
624 dict_add_number(dict, "bufnr", buf->b_fnum);
625 dict_add_string(dict, "name", buf->b_ffname);
626 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
627 : buflist_findlnum(buf));
Bram Moolenaara9e96792019-12-17 22:40:15 +0100628 dict_add_number(dict, "linecount", buf->b_ml.ml_line_count);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200629 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
630 dict_add_number(dict, "listed", buf->b_p_bl);
631 dict_add_number(dict, "changed", bufIsChanged(buf));
632 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
633 dict_add_number(dict, "hidden",
634 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
635
636 // Get a reference to buffer variables
637 dict_add_dict(dict, "variables", buf->b_vars);
638
639 // List of windows displaying this buffer
640 windows = list_alloc();
641 if (windows != NULL)
642 {
643 FOR_ALL_TAB_WINDOWS(tp, wp)
644 if (wp->w_buffer == buf)
645 list_append_number(windows, (varnumber_T)wp->w_id);
646 dict_add_list(dict, "windows", windows);
647 }
648
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100649#ifdef FEAT_PROP_POPUP
Bram Moolenaar261f3462019-09-07 15:45:32 +0200650 // List of popup windows displaying this buffer
651 windows = list_alloc();
652 if (windows != NULL)
653 {
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200654 FOR_ALL_POPUPWINS(wp)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200655 if (wp->w_buffer == buf)
656 list_append_number(windows, (varnumber_T)wp->w_id);
657 FOR_ALL_TABPAGES(tp)
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200658 FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200659 if (wp->w_buffer == buf)
660 list_append_number(windows, (varnumber_T)wp->w_id);
661
662 dict_add_list(dict, "popups", windows);
663 }
664#endif
665
666#ifdef FEAT_SIGNS
667 if (buf->b_signlist != NULL)
668 {
669 // List of signs placed in this buffer
670 list_T *signs = list_alloc();
671 if (signs != NULL)
672 {
673 get_buffer_signs(buf, signs);
674 dict_add_list(dict, "signs", signs);
675 }
676 }
677#endif
678
Bram Moolenaar52410572019-10-27 05:12:45 +0100679#ifdef FEAT_VIMINFO
680 dict_add_number(dict, "lastused", buf->b_last_used);
681#endif
682
Bram Moolenaar261f3462019-09-07 15:45:32 +0200683 return dict;
684}
685
686/*
687 * "getbufinfo()" function
688 */
689 void
690f_getbufinfo(typval_T *argvars, typval_T *rettv)
691{
692 buf_T *buf = NULL;
693 buf_T *argbuf = NULL;
694 dict_T *d;
695 int filtered = FALSE;
696 int sel_buflisted = FALSE;
697 int sel_bufloaded = FALSE;
698 int sel_bufmodified = FALSE;
699
Bram Moolenaar93a10962022-06-16 11:42:09 +0100700 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200701 return;
702
Yegappan Lakshmanancd917202021-07-21 19:09:09 +0200703 if (in_vim9script()
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200704 && check_for_opt_buffer_or_dict_arg(argvars, 0) == FAIL)
Yegappan Lakshmanancd917202021-07-21 19:09:09 +0200705 return;
706
Bram Moolenaar261f3462019-09-07 15:45:32 +0200707 // List of all the buffers or selected buffers
708 if (argvars[0].v_type == VAR_DICT)
709 {
710 dict_T *sel_d = argvars[0].vval.v_dict;
711
712 if (sel_d != NULL)
713 {
Bram Moolenaar261f3462019-09-07 15:45:32 +0200714 filtered = TRUE;
Bram Moolenaard61efa52022-07-23 09:52:04 +0100715 sel_buflisted = dict_get_bool(sel_d, "buflisted", FALSE);
716 sel_bufloaded = dict_get_bool(sel_d, "bufloaded", FALSE);
717 sel_bufmodified = dict_get_bool(sel_d, "bufmodified",
Bram Moolenaar036c2cf2020-09-05 17:37:07 +0200718 FALSE);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200719 }
720 }
721 else if (argvars[0].v_type != VAR_UNKNOWN)
722 {
723 // Information about one buffer. Argument specifies the buffer
Bram Moolenaar3767e3a2020-09-01 23:06:01 +0200724 argbuf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200725 if (argbuf == NULL)
726 return;
727 }
728
729 // Return information about all the buffers or a specified buffer
730 FOR_ALL_BUFFERS(buf)
731 {
732 if (argbuf != NULL && argbuf != buf)
733 continue;
734 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
735 || (sel_buflisted && !buf->b_p_bl)
736 || (sel_bufmodified && !buf->b_changed)))
737 continue;
738
739 d = get_buffer_info(buf);
740 if (d != NULL)
741 list_append_dict(rettv->vval.v_list, d);
742 if (argbuf != NULL)
743 return;
744 }
745}
746
747/*
748 * Get line or list of lines from buffer "buf" into "rettv".
749 * Return a range (from start to end) of lines in rettv from the specified
750 * buffer.
751 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
752 */
753 static void
754get_buffer_lines(
755 buf_T *buf,
756 linenr_T start,
757 linenr_T end,
758 int retlist,
759 typval_T *rettv)
760{
761 char_u *p;
762
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100763 if (retlist)
764 {
765 if (rettv_list_alloc(rettv) == FAIL)
766 return;
767 }
768 else
769 {
770 rettv->v_type = VAR_STRING;
771 rettv->vval.v_string = NULL;
772 }
Bram Moolenaar261f3462019-09-07 15:45:32 +0200773
774 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
775 return;
776
777 if (!retlist)
778 {
779 if (start >= 1 && start <= buf->b_ml.ml_line_count)
780 p = ml_get_buf(buf, start, FALSE);
781 else
782 p = (char_u *)"";
783 rettv->vval.v_string = vim_strsave(p);
784 }
785 else
786 {
787 if (end < start)
788 return;
789
790 if (start < 1)
791 start = 1;
792 if (end > buf->b_ml.ml_line_count)
793 end = buf->b_ml.ml_line_count;
794 while (start <= end)
795 if (list_append_string(rettv->vval.v_list,
796 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
797 break;
798 }
799}
800
801/*
802 * "getbufline()" function
803 */
804 void
805f_getbufline(typval_T *argvars, typval_T *rettv)
806{
Bram Moolenaare6e70a12020-10-22 18:23:38 +0200807 linenr_T lnum = 1;
808 linenr_T end = 1;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200809 buf_T *buf;
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000810 int did_emsg_before = did_emsg;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200811
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200812 if (in_vim9script()
813 && (check_for_buffer_arg(argvars, 0) == FAIL
814 || check_for_lnum_arg(argvars, 1) == FAIL
815 || check_for_opt_lnum_arg(argvars, 2) == FAIL))
816 return;
817
Bram Moolenaar3767e3a2020-09-01 23:06:01 +0200818 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaare6e70a12020-10-22 18:23:38 +0200819 if (buf != NULL)
820 {
821 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000822 if (did_emsg > did_emsg_before)
823 return;
Bram Moolenaare6e70a12020-10-22 18:23:38 +0200824 if (argvars[2].v_type == VAR_UNKNOWN)
825 end = lnum;
826 else
827 end = tv_get_lnum_buf(&argvars[2], buf);
828 }
Bram Moolenaar261f3462019-09-07 15:45:32 +0200829
830 get_buffer_lines(buf, lnum, end, TRUE, rettv);
831}
832
833/*
834 * "getline(lnum, [end])" function
835 */
836 void
837f_getline(typval_T *argvars, typval_T *rettv)
838{
839 linenr_T lnum;
840 linenr_T end;
841 int retlist;
842
Yegappan Lakshmanancd917202021-07-21 19:09:09 +0200843 if (in_vim9script()
844 && (check_for_lnum_arg(argvars, 0) == FAIL
845 || check_for_opt_lnum_arg(argvars, 1) == FAIL))
846 return;
847
Bram Moolenaar261f3462019-09-07 15:45:32 +0200848 lnum = tv_get_lnum(argvars);
849 if (argvars[1].v_type == VAR_UNKNOWN)
850 {
851 end = 0;
852 retlist = FALSE;
853 }
854 else
855 {
856 end = tv_get_lnum(&argvars[1]);
857 retlist = TRUE;
858 }
859
860 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
861}
862
863/*
864 * "setbufline()" function
865 */
866 void
867f_setbufline(typval_T *argvars, typval_T *rettv)
868{
Yegappan Lakshmanan4a155042021-07-30 21:32:45 +0200869 buf_set_append_line(argvars, rettv, FALSE);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200870}
871
872/*
873 * "setline()" function
874 */
875 void
876f_setline(typval_T *argvars, typval_T *rettv)
877{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200878 linenr_T lnum;
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000879 int did_emsg_before = did_emsg;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200880
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200881 if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
882 return;
883
884 lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar8b6256f2021-12-28 11:24:49 +0000885 if (did_emsg == did_emsg_before)
886 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200887}
888#endif // FEAT_EVAL
889
Dominique Pelle748b3082022-01-08 12:41:16 +0000890#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200891/*
892 * Make "buf" the current buffer. restore_buffer() MUST be called to undo.
893 * No autocommands will be executed. Use aucmd_prepbuf() if there are any.
894 */
895 void
896switch_buffer(bufref_T *save_curbuf, buf_T *buf)
897{
898 block_autocmds();
Bram Moolenaar3e0107e2021-01-02 13:53:59 +0100899#ifdef FEAT_FOLDING
900 ++disable_fold_update;
901#endif
Bram Moolenaar261f3462019-09-07 15:45:32 +0200902 set_bufref(save_curbuf, curbuf);
903 --curbuf->b_nwindows;
904 curbuf = buf;
905 curwin->w_buffer = buf;
906 ++curbuf->b_nwindows;
907}
908
909/*
910 * Restore the current buffer after using switch_buffer().
911 */
912 void
913restore_buffer(bufref_T *save_curbuf)
914{
915 unblock_autocmds();
Bram Moolenaar3e0107e2021-01-02 13:53:59 +0100916#ifdef FEAT_FOLDING
917 --disable_fold_update;
918#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +0100919 // Check for valid buffer, just in case.
Bram Moolenaar261f3462019-09-07 15:45:32 +0200920 if (bufref_valid(save_curbuf))
921 {
922 --curbuf->b_nwindows;
923 curwin->w_buffer = save_curbuf->br_buf;
924 curbuf = save_curbuf->br_buf;
925 ++curbuf->b_nwindows;
926 }
927}
928
929/*
930 * Find a window for buffer "buf".
931 * If found OK is returned and "wp" and "tp" are set to the window and tabpage.
932 * If not found FAIL is returned.
933 */
934 static int
935find_win_for_buf(
936 buf_T *buf,
937 win_T **wp,
938 tabpage_T **tp)
939{
940 FOR_ALL_TAB_WINDOWS(*tp, *wp)
941 if ((*wp)->w_buffer == buf)
942 return OK;
943 return FAIL;
944}
945
946/*
947 * Find a window that contains "buf" and switch to it.
948 * If there is no such window, use the current window and change "curbuf".
949 * Caller must initialize save_curbuf to NULL.
950 * restore_win_for_buf() MUST be called later!
951 */
952 void
953switch_to_win_for_buf(
Bram Moolenaar18f47402022-01-06 13:24:51 +0000954 buf_T *buf,
955 switchwin_T *switchwin,
956 bufref_T *save_curbuf)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200957{
958 win_T *wp;
959 tabpage_T *tp;
960
961 if (find_win_for_buf(buf, &wp, &tp) == FAIL)
962 switch_buffer(save_curbuf, buf);
Bram Moolenaar18f47402022-01-06 13:24:51 +0000963 else if (switch_win(switchwin, wp, tp, TRUE) == FAIL)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200964 {
Bram Moolenaar18f47402022-01-06 13:24:51 +0000965 restore_win(switchwin, TRUE);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200966 switch_buffer(save_curbuf, buf);
967 }
968}
969
970 void
971restore_win_for_buf(
Bram Moolenaar18f47402022-01-06 13:24:51 +0000972 switchwin_T *switchwin,
973 bufref_T *save_curbuf)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200974{
975 if (save_curbuf->br_buf == NULL)
Bram Moolenaar18f47402022-01-06 13:24:51 +0000976 restore_win(switchwin, TRUE);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200977 else
978 restore_buffer(save_curbuf);
979}
980#endif