blob: e884f55dd76ea8c666e3df1261f945ff7d9744ec [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
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 * buffer.c: functions for dealing with the buffer structure
12 */
13
14/*
15 * The buffer list is a double linked list of all buffers.
16 * Each buffer can be in one of these states:
17 * never loaded: BF_NEVERLOADED is set, only the file name is valid
18 * not loaded: b_ml.ml_mfp == NULL, no memfile allocated
19 * hidden: b_nwindows == 0, loaded but not displayed in a window
20 * normal: loaded and displayed in a window
21 *
22 * Instead of storing file names all over the place, each file name is
23 * stored in the buffer list. It can be referenced by a number.
24 *
25 * The current implementation remembers all file names ever used.
26 */
27
Bram Moolenaar071d4272004-06-13 20:20:40 +000028#include "vim.h"
29
30#if defined(FEAT_CMDL_COMPL) || defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL)
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010031static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case);
Bram Moolenaar071d4272004-06-13 20:20:40 +000032# define HAVE_BUFLIST_MATCH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010033static char_u *fname_match(regmatch_T *rmp, char_u *name, int ignore_case);
Bram Moolenaar071d4272004-06-13 20:20:40 +000034#endif
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010035static void buflist_setfpos(buf_T *buf, win_T *win, linenr_T lnum, colnr_T col, int copy_options);
36static wininfo_T *find_wininfo(buf_T *buf, int skip_diff_buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +000037#ifdef UNIX
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010038static buf_T *buflist_findname_stat(char_u *ffname, struct stat *st);
39static int otherfile_buf(buf_T *buf, char_u *ffname, struct stat *stp);
40static int buf_same_ino(buf_T *buf, struct stat *stp);
Bram Moolenaar071d4272004-06-13 20:20:40 +000041#else
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010042static int otherfile_buf(buf_T *buf, char_u *ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +000043#endif
44#ifdef FEAT_TITLE
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010045static int ti_change(char_u *str, char_u **last);
Bram Moolenaar071d4272004-06-13 20:20:40 +000046#endif
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010047static int append_arg_number(win_T *wp, char_u *buf, int buflen, int add_file);
48static void free_buffer(buf_T *);
49static void free_buffer_stuff(buf_T *buf, int free_options);
50static void clear_wininfo(buf_T *buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +000051
52#ifdef UNIX
53# define dev_T dev_t
54#else
55# define dev_T unsigned
56#endif
57
58#if defined(FEAT_SIGNS)
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010059static void insert_sign(buf_T *buf, signlist_T *prev, signlist_T *next, int id, linenr_T lnum, int typenr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000060#endif
61
Bram Moolenaar7fd73202010-07-25 16:58:46 +020062#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
63static char *msg_loclist = N_("[Location List]");
64static char *msg_qflist = N_("[Quickfix List]");
65#endif
Bram Moolenaar42ec6562012-02-22 14:58:37 +010066#ifdef FEAT_AUTOCMD
67static char *e_auabort = N_("E855: Autocommands caused command to abort");
68#endif
Bram Moolenaar7fd73202010-07-25 16:58:46 +020069
Bram Moolenaar071d4272004-06-13 20:20:40 +000070/*
Bram Moolenaar55debbe2010-05-23 23:34:36 +020071 * Open current buffer, that is: open the memfile and read the file into
72 * memory.
73 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +000074 */
75 int
Bram Moolenaar7454a062016-01-30 15:14:10 +010076open_buffer(
77 int read_stdin, /* read file from stdin */
78 exarg_T *eap, /* for forced 'ff' and 'fenc' or NULL */
79 int flags) /* extra flags for readfile() */
Bram Moolenaar071d4272004-06-13 20:20:40 +000080{
81 int retval = OK;
82#ifdef FEAT_AUTOCMD
83 buf_T *old_curbuf;
84#endif
Bram Moolenaar6d47df72013-02-17 15:45:37 +010085#ifdef FEAT_SYN_HL
86 long old_tw = curbuf->b_p_tw;
87#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000088
89 /*
90 * The 'readonly' flag is only set when BF_NEVERLOADED is being reset.
91 * When re-entering the same buffer, it should not change, because the
92 * user may have reset the flag by hand.
93 */
94 if (readonlymode && curbuf->b_ffname != NULL
95 && (curbuf->b_flags & BF_NEVERLOADED))
96 curbuf->b_p_ro = TRUE;
97
Bram Moolenaar4770d092006-01-12 23:22:24 +000098 if (ml_open(curbuf) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +000099 {
100 /*
101 * There MUST be a memfile, otherwise we can't do anything
102 * If we can't create one for the current buffer, take another buffer
103 */
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100104 close_buffer(NULL, curbuf, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105 for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
106 if (curbuf->b_ml.ml_mfp != NULL)
107 break;
108 /*
109 * if there is no memfile at all, exit
Bram Moolenaare37d50a2008-08-06 17:06:04 +0000110 * This is OK, since there are no changes to lose.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000111 */
112 if (curbuf == NULL)
113 {
114 EMSG(_("E82: Cannot allocate any buffer, exiting..."));
115 getout(2);
116 }
117 EMSG(_("E83: Cannot allocate buffer, using other one..."));
118 enter_buffer(curbuf);
Bram Moolenaar6d47df72013-02-17 15:45:37 +0100119#ifdef FEAT_SYN_HL
120 if (old_tw != curbuf->b_p_tw)
121 check_colorcolumn(curwin);
122#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000123 return FAIL;
124 }
125
126#ifdef FEAT_AUTOCMD
127 /* The autocommands in readfile() may change the buffer, but only AFTER
128 * reading the file. */
129 old_curbuf = curbuf;
130 modified_was_set = FALSE;
131#endif
132
133 /* mark cursor position as being invalid */
Bram Moolenaar89c0ea42010-02-24 16:58:36 +0100134 curwin->w_valid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135
136 if (curbuf->b_ffname != NULL
137#ifdef FEAT_NETBEANS_INTG
138 && netbeansReadFile
139#endif
140 )
141 {
Bram Moolenaar426dd022016-03-15 15:09:29 +0100142 int old_msg_silent = msg_silent;
143
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144#ifdef FEAT_NETBEANS_INTG
145 int oldFire = netbeansFireChanges;
146
147 netbeansFireChanges = 0;
148#endif
Bram Moolenaar426dd022016-03-15 15:09:29 +0100149 if (shortmess(SHM_FILEINFO))
150 msg_silent = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151 retval = readfile(curbuf->b_ffname, curbuf->b_fname,
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200152 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap,
153 flags | READ_NEW);
Bram Moolenaar426dd022016-03-15 15:09:29 +0100154 msg_silent = old_msg_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000155#ifdef FEAT_NETBEANS_INTG
156 netbeansFireChanges = oldFire;
157#endif
158 /* Help buffer is filtered. */
159 if (curbuf->b_help)
160 fix_help_buffer();
161 }
162 else if (read_stdin)
163 {
164 int save_bin = curbuf->b_p_bin;
165 linenr_T line_count;
166
167 /*
168 * First read the text in binary mode into the buffer.
169 * Then read from that same buffer and append at the end. This makes
170 * it possible to retry when 'fileformat' or 'fileencoding' was
171 * guessed wrong.
172 */
173 curbuf->b_p_bin = TRUE;
174 retval = readfile(NULL, NULL, (linenr_T)0,
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200175 (linenr_T)0, (linenr_T)MAXLNUM, NULL,
176 flags | (READ_NEW + READ_STDIN));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177 curbuf->b_p_bin = save_bin;
178 if (retval == OK)
179 {
180 line_count = curbuf->b_ml.ml_line_count;
181 retval = readfile(NULL, NULL, (linenr_T)line_count,
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200182 (linenr_T)0, (linenr_T)MAXLNUM, eap,
183 flags | READ_BUFFER);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184 if (retval == OK)
185 {
186 /* Delete the binary lines. */
187 while (--line_count >= 0)
188 ml_delete((linenr_T)1, FALSE);
189 }
190 else
191 {
192 /* Delete the converted lines. */
193 while (curbuf->b_ml.ml_line_count > line_count)
194 ml_delete(line_count, FALSE);
195 }
196 /* Put the cursor on the first line. */
197 curwin->w_cursor.lnum = 1;
198 curwin->w_cursor.col = 0;
Bram Moolenaar512e6b82007-06-19 13:36:52 +0000199
200 /* Set or reset 'modified' before executing autocommands, so that
201 * it can be changed there. */
202 if (!readonlymode && !bufempty())
203 changed();
204 else if (retval != FAIL)
205 unchanged(curbuf, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000206#ifdef FEAT_AUTOCMD
207# ifdef FEAT_EVAL
208 apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE,
209 curbuf, &retval);
210# else
211 apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf);
212# endif
213#endif
214 }
215 }
216
217 /* if first time loading this buffer, init b_chartab[] */
218 if (curbuf->b_flags & BF_NEVERLOADED)
Bram Moolenaar6bcbcc52013-11-05 07:13:41 +0100219 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 (void)buf_init_chartab(curbuf, FALSE);
Bram Moolenaardce7c912013-11-05 17:40:52 +0100221#ifdef FEAT_CINDENT
Bram Moolenaar6bcbcc52013-11-05 07:13:41 +0100222 parse_cino(curbuf);
Bram Moolenaardce7c912013-11-05 17:40:52 +0100223#endif
Bram Moolenaar6bcbcc52013-11-05 07:13:41 +0100224 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000225
226 /*
227 * Set/reset the Changed flag first, autocmds may change the buffer.
228 * Apply the automatic commands, before processing the modelines.
229 * So the modelines have priority over auto commands.
230 */
231 /* When reading stdin, the buffer contents always needs writing, so set
232 * the changed flag. Unless in readonly mode: "ls | gview -".
233 * When interrupted and 'cpoptions' contains 'i' set changed flag. */
Bram Moolenaar512e6b82007-06-19 13:36:52 +0000234 if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000235#ifdef FEAT_AUTOCMD
236 || modified_was_set /* ":set modified" used in autocmd */
237# ifdef FEAT_EVAL
238 || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
239# endif
240#endif
Bram Moolenaar512e6b82007-06-19 13:36:52 +0000241 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000242 changed();
Bram Moolenaar512e6b82007-06-19 13:36:52 +0000243 else if (retval != FAIL && !read_stdin)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 unchanged(curbuf, FALSE);
245 save_file_ff(curbuf); /* keep this fileformat */
246
247 /* require "!" to overwrite the file, because it wasn't read completely */
248#ifdef FEAT_EVAL
249 if (aborting())
250#else
251 if (got_int)
252#endif
253 curbuf->b_flags |= BF_READERR;
254
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000255#ifdef FEAT_FOLDING
256 /* Need to update automatic folding. Do this before the autocommands,
257 * they may use the fold info. */
258 foldUpdateAll(curwin);
259#endif
260
Bram Moolenaar071d4272004-06-13 20:20:40 +0000261#ifdef FEAT_AUTOCMD
262 /* need to set w_topline, unless some autocommand already did that. */
263 if (!(curwin->w_valid & VALID_TOPLINE))
264 {
265 curwin->w_topline = 1;
266# ifdef FEAT_DIFF
267 curwin->w_topfill = 0;
268# endif
269 }
270# ifdef FEAT_EVAL
271 apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, &retval);
272# else
273 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
274# endif
275#endif
276
277 if (retval != FAIL)
278 {
279#ifdef FEAT_AUTOCMD
280 /*
281 * The autocommands may have changed the current buffer. Apply the
282 * modelines to the correct buffer, if it still exists and is loaded.
283 */
284 if (buf_valid(old_curbuf) && old_curbuf->b_ml.ml_mfp != NULL)
285 {
286 aco_save_T aco;
287
288 /* Go to the buffer that was opened. */
289 aucmd_prepbuf(&aco, old_curbuf);
290#endif
Bram Moolenaara3227e22006-03-08 21:32:40 +0000291 do_modelines(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000292 curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED);
293
294#ifdef FEAT_AUTOCMD
295# ifdef FEAT_EVAL
296 apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf,
297 &retval);
298# else
299 apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
300# endif
301
302 /* restore curwin/curbuf and a few other things */
303 aucmd_restbuf(&aco);
304 }
305#endif
306 }
307
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308 return retval;
309}
310
311/*
312 * Return TRUE if "buf" points to a valid buffer (in the buffer list).
313 */
314 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100315buf_valid(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000316{
317 buf_T *bp;
318
319 for (bp = firstbuf; bp != NULL; bp = bp->b_next)
320 if (bp == buf)
321 return TRUE;
322 return FALSE;
323}
324
325/*
326 * Close the link to a buffer.
327 * "action" is used when there is no longer a window for the buffer.
328 * It can be:
329 * 0 buffer becomes hidden
330 * DOBUF_UNLOAD buffer is unloaded
331 * DOBUF_DELETE buffer is unloaded and removed from buffer list
332 * DOBUF_WIPE buffer is unloaded and really deleted
333 * When doing all but the first one on the current buffer, the caller should
334 * get a new buffer very soon!
335 *
336 * The 'bufhidden' option can force freeing and deleting.
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100337 *
338 * When "abort_if_last" is TRUE then do not close the buffer if autocommands
339 * cause there to be only one window with this buffer. e.g. when ":quit" is
340 * supposed to close the window but autocommands close all other windows.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000341 */
342 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100343close_buffer(
344 win_T *win, /* if not NULL, set b_last_cursor */
345 buf_T *buf,
346 int action,
347 int abort_if_last UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000348{
349#ifdef FEAT_AUTOCMD
350 int is_curbuf;
Bram Moolenaar2660c0e2010-01-19 14:59:56 +0100351 int nwindows;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352#endif
353 int unload_buf = (action != 0);
354 int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
355 int wipe_buf = (action == DOBUF_WIPE);
356
357#ifdef FEAT_QUICKFIX
358 /*
359 * Force unloading or deleting when 'bufhidden' says so.
360 * The caller must take care of NOT deleting/freeing when 'bufhidden' is
361 * "hide" (otherwise we could never free or delete a buffer).
362 */
363 if (buf->b_p_bh[0] == 'd') /* 'bufhidden' == "delete" */
364 {
365 del_buf = TRUE;
366 unload_buf = TRUE;
367 }
368 else if (buf->b_p_bh[0] == 'w') /* 'bufhidden' == "wipe" */
369 {
370 del_buf = TRUE;
371 unload_buf = TRUE;
372 wipe_buf = TRUE;
373 }
374 else if (buf->b_p_bh[0] == 'u') /* 'bufhidden' == "unload" */
375 unload_buf = TRUE;
376#endif
377
Bram Moolenaar3be85852014-06-12 14:01:31 +0200378 if (win != NULL
379#ifdef FEAT_WINDOWS
380 && win_valid(win) /* in case autocommands closed the window */
381#endif
382 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383 {
384 /* Set b_last_cursor when closing the last window for the buffer.
385 * Remember the last cursor position and window options of the buffer.
386 * This used to be only for the current window, but then options like
387 * 'foldmethod' may be lost with a ":only" command. */
388 if (buf->b_nwindows == 1)
389 set_last_cursor(win);
390 buflist_setfpos(buf, win,
391 win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum,
392 win->w_cursor.col, TRUE);
393 }
394
395#ifdef FEAT_AUTOCMD
396 /* When the buffer is no longer in a window, trigger BufWinLeave */
397 if (buf->b_nwindows == 1)
398 {
Bram Moolenaar362ce482012-06-06 19:02:45 +0200399 buf->b_closing = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000400 apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
401 FALSE, buf);
Bram Moolenaar362ce482012-06-06 19:02:45 +0200402 if (!buf_valid(buf))
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100403 {
Bram Moolenaar362ce482012-06-06 19:02:45 +0200404 /* Autocommands deleted the buffer. */
405aucmd_abort:
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100406 EMSG(_(e_auabort));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407 return;
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100408 }
Bram Moolenaar362ce482012-06-06 19:02:45 +0200409 buf->b_closing = FALSE;
410 if (abort_if_last && one_window())
411 /* Autocommands made this the only window. */
412 goto aucmd_abort;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000413
414 /* When the buffer becomes hidden, but is not unloaded, trigger
415 * BufHidden */
416 if (!unload_buf)
417 {
Bram Moolenaar362ce482012-06-06 19:02:45 +0200418 buf->b_closing = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419 apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
420 FALSE, buf);
Bram Moolenaar362ce482012-06-06 19:02:45 +0200421 if (!buf_valid(buf))
422 /* Autocommands deleted the buffer. */
423 goto aucmd_abort;
424 buf->b_closing = FALSE;
425 if (abort_if_last && one_window())
426 /* Autocommands made this the only window. */
427 goto aucmd_abort;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428 }
429# ifdef FEAT_EVAL
430 if (aborting()) /* autocmds may abort script processing */
431 return;
432# endif
433 }
434 nwindows = buf->b_nwindows;
435#endif
436
437 /* decrease the link count from windows (unless not in any window) */
438 if (buf->b_nwindows > 0)
439 --buf->b_nwindows;
440
441 /* Return when a window is displaying the buffer or when it's not
442 * unloaded. */
443 if (buf->b_nwindows > 0 || !unload_buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445
446 /* Always remove the buffer when there is no file name. */
447 if (buf->b_ffname == NULL)
448 del_buf = TRUE;
449
450 /*
451 * Free all things allocated for this buffer.
452 * Also calls the "BufDelete" autocommands when del_buf is TRUE.
453 */
454#ifdef FEAT_AUTOCMD
455 /* Remember if we are closing the current buffer. Restore the number of
456 * windows, so that autocommands in buf_freeall() don't get confused. */
457 is_curbuf = (buf == curbuf);
458 buf->b_nwindows = nwindows;
459#endif
460
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200461 buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0));
Bram Moolenaarddab3322011-09-14 17:50:14 +0200462 if (
463#ifdef FEAT_WINDOWS
464 win_valid(win) &&
Bram Moolenaar83bac4c2011-12-30 13:39:10 +0100465#else
466 win != NULL &&
Bram Moolenaarddab3322011-09-14 17:50:14 +0200467#endif
468 win->w_buffer == buf)
Bram Moolenaara971b822011-09-14 14:43:25 +0200469 win->w_buffer = NULL; /* make sure we don't use the buffer now */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470
471#ifdef FEAT_AUTOCMD
472 /* Autocommands may have deleted the buffer. */
473 if (!buf_valid(buf))
474 return;
475# ifdef FEAT_EVAL
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000476 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 return;
478# endif
479
480 /* Autocommands may have opened or closed windows for this buffer.
481 * Decrement the count for the close we do here. */
482 if (buf->b_nwindows > 0)
483 --buf->b_nwindows;
484
485 /*
486 * It's possible that autocommands change curbuf to the one being deleted.
487 * This might cause the previous curbuf to be deleted unexpectedly. But
488 * in some cases it's OK to delete the curbuf, because a new one is
489 * obtained anyway. Therefore only return if curbuf changed to the
490 * deleted buffer.
491 */
492 if (buf == curbuf && !is_curbuf)
493 return;
494#endif
495
Bram Moolenaar498efdb2006-09-05 14:31:54 +0000496 /* Change directories when the 'acd' option is set. */
497 DO_AUTOCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498
499 /*
500 * Remove the buffer from the list.
501 */
502 if (wipe_buf)
503 {
504#ifdef FEAT_SUN_WORKSHOP
505 if (usingSunWorkShop)
506 workshop_file_closed_lineno((char *)buf->b_ffname,
507 (int)buf->b_last_cursor.lnum);
508#endif
509 vim_free(buf->b_ffname);
510 vim_free(buf->b_sfname);
511 if (buf->b_prev == NULL)
512 firstbuf = buf->b_next;
513 else
514 buf->b_prev->b_next = buf->b_next;
515 if (buf->b_next == NULL)
516 lastbuf = buf->b_prev;
517 else
518 buf->b_next->b_prev = buf->b_prev;
519 free_buffer(buf);
520 }
521 else
522 {
523 if (del_buf)
524 {
525 /* Free all internal variables and reset option values, to make
526 * ":bdel" compatible with Vim 5.7. */
527 free_buffer_stuff(buf, TRUE);
528
529 /* Make it look like a new buffer. */
530 buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
531
532 /* Init the options when loaded again. */
533 buf->b_p_initialized = FALSE;
534 }
535 buf_clear_file(buf);
536 if (del_buf)
537 buf->b_p_bl = FALSE;
538 }
539}
540
541/*
542 * Make buffer not contain a file.
543 */
544 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100545buf_clear_file(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546{
547 buf->b_ml.ml_line_count = 1;
548 unchanged(buf, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 buf->b_shortname = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 buf->b_p_eol = TRUE;
551 buf->b_start_eol = TRUE;
552#ifdef FEAT_MBYTE
553 buf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000554 buf->b_start_bomb = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555#endif
556 buf->b_ml.ml_mfp = NULL;
557 buf->b_ml.ml_flags = ML_EMPTY; /* empty buffer */
558#ifdef FEAT_NETBEANS_INTG
559 netbeans_deleted_all_lines(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560#endif
561}
562
563/*
564 * buf_freeall() - free all things allocated for a buffer that are related to
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200565 * the file. flags:
566 * BFA_DEL buffer is going to be deleted
567 * BFA_WIPE buffer is going to be wiped out
568 * BFA_KEEP_UNDO do not free undo information
Bram Moolenaar071d4272004-06-13 20:20:40 +0000569 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100571buf_freeall(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572{
573#ifdef FEAT_AUTOCMD
574 int is_curbuf = (buf == curbuf);
575
Bram Moolenaar362ce482012-06-06 19:02:45 +0200576 buf->b_closing = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577 apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, FALSE, buf);
578 if (!buf_valid(buf)) /* autocommands may delete the buffer */
579 return;
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200580 if ((flags & BFA_DEL) && buf->b_p_bl)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000581 {
582 apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname, FALSE, buf);
583 if (!buf_valid(buf)) /* autocommands may delete the buffer */
584 return;
585 }
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200586 if (flags & BFA_WIPE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000587 {
588 apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname,
589 FALSE, buf);
590 if (!buf_valid(buf)) /* autocommands may delete the buffer */
591 return;
592 }
Bram Moolenaar362ce482012-06-06 19:02:45 +0200593 buf->b_closing = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594# ifdef FEAT_EVAL
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000595 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 return;
597# endif
598
599 /*
600 * It's possible that autocommands change curbuf to the one being deleted.
601 * This might cause curbuf to be deleted unexpectedly. But in some cases
602 * it's OK to delete the curbuf, because a new one is obtained anyway.
603 * Therefore only return if curbuf changed to the deleted buffer.
604 */
605 if (buf == curbuf && !is_curbuf)
606 return;
607#endif
608#ifdef FEAT_DIFF
609 diff_buf_delete(buf); /* Can't use 'diff' for unloaded buffer. */
610#endif
Bram Moolenaara971b822011-09-14 14:43:25 +0200611#ifdef FEAT_SYN_HL
Bram Moolenaar89c71222011-11-30 15:40:56 +0100612 /* Remove any ownsyntax, unless exiting. */
613 if (firstwin != NULL && curwin->w_buffer == buf)
614 reset_synblock(curwin);
Bram Moolenaara971b822011-09-14 14:43:25 +0200615#endif
Bram Moolenaarb6799ac2007-05-10 16:44:05 +0000616
617#ifdef FEAT_FOLDING
618 /* No folds in an empty buffer. */
619# ifdef FEAT_WINDOWS
620 {
621 win_T *win;
622 tabpage_T *tp;
623
624 FOR_ALL_TAB_WINDOWS(tp, win)
625 if (win->w_buffer == buf)
626 clearFolding(win);
627 }
628# else
629 if (curwin->w_buffer == buf)
630 clearFolding(curwin);
631# endif
632#endif
633
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634#ifdef FEAT_TCL
635 tcl_buffer_free(buf);
636#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 ml_close(buf, TRUE); /* close and delete the memline/memfile */
638 buf->b_ml.ml_line_count = 0; /* no lines in buffer */
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200639 if ((flags & BFA_KEEP_UNDO) == 0)
640 {
641 u_blockfree(buf); /* free the memory allocated for undo */
642 u_clearall(buf); /* reset all undo information */
643 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +0200645 syntax_clear(&buf->b_s); /* reset syntax info */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646#endif
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000647 buf->b_flags &= ~BF_READERR; /* a read error is no longer relevant */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000648}
649
650/*
651 * Free a buffer structure and the things it contains related to the buffer
652 * itself (not the file, that must have been done already).
653 */
654 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100655free_buffer(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656{
657 free_buffer_stuff(buf, TRUE);
Bram Moolenaar429fa852013-04-15 12:27:36 +0200658#ifdef FEAT_EVAL
659 unref_var_dict(buf->b_vars);
660#endif
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200661#ifdef FEAT_LUA
662 lua_buffer_free(buf);
663#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000664#ifdef FEAT_MZSCHEME
665 mzscheme_buffer_free(buf);
666#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667#ifdef FEAT_PERL
668 perl_buf_free(buf);
669#endif
670#ifdef FEAT_PYTHON
671 python_buffer_free(buf);
672#endif
Bram Moolenaarbd5e15f2010-07-17 21:19:38 +0200673#ifdef FEAT_PYTHON3
674 python3_buffer_free(buf);
675#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000676#ifdef FEAT_RUBY
677 ruby_buffer_free(buf);
678#endif
Bram Moolenaare0f76d02016-05-09 20:38:53 +0200679#ifdef FEAT_JOB_CHANNEL
680 channel_buffer_free(buf);
681#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +0000682#ifdef FEAT_AUTOCMD
683 aubuflocal_remove(buf);
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +0200684 if (autocmd_busy)
685 {
686 /* Do not free the buffer structure while autocommands are executing,
687 * it's still needed. Free it when autocmd_busy is reset. */
688 buf->b_next = au_pending_free_buf;
689 au_pending_free_buf = buf;
690 }
691 else
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +0000692#endif
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +0200693 vim_free(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000694}
695
696/*
697 * Free stuff in the buffer for ":bdel" and when wiping out the buffer.
698 */
699 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100700free_buffer_stuff(
701 buf_T *buf,
702 int free_options) /* free options as well */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000703{
704 if (free_options)
705 {
706 clear_wininfo(buf); /* including window-local options */
707 free_buf_options(buf, TRUE);
Bram Moolenaarbeca0552010-10-27 16:18:00 +0200708#ifdef FEAT_SPELL
709 ga_clear(&buf->b_s.b_langp);
710#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711 }
712#ifdef FEAT_EVAL
Bram Moolenaar429fa852013-04-15 12:27:36 +0200713 vars_clear(&buf->b_vars->dv_hashtab); /* free all internal variables */
714 hash_init(&buf->b_vars->dv_hashtab);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715#endif
716#ifdef FEAT_USR_CMDS
717 uc_clear(&buf->b_ucmds); /* clear local user commands */
718#endif
719#ifdef FEAT_SIGNS
720 buf_delete_signs(buf); /* delete any signs */
721#endif
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +0000722#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200723 netbeans_file_killed(buf);
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +0000724#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725#ifdef FEAT_LOCALMAP
726 map_clear_int(buf, MAP_ALL_MODES, TRUE, FALSE); /* clear local mappings */
727 map_clear_int(buf, MAP_ALL_MODES, TRUE, TRUE); /* clear local abbrevs */
728#endif
729#ifdef FEAT_MBYTE
730 vim_free(buf->b_start_fenc);
731 buf->b_start_fenc = NULL;
732#endif
733}
734
735/*
736 * Free the b_wininfo list for buffer "buf".
737 */
738 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100739clear_wininfo(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740{
741 wininfo_T *wip;
742
743 while (buf->b_wininfo != NULL)
744 {
745 wip = buf->b_wininfo;
746 buf->b_wininfo = wip->wi_next;
747 if (wip->wi_optset)
748 {
749 clear_winopt(&wip->wi_opt);
750#ifdef FEAT_FOLDING
751 deleteFoldRecurse(&wip->wi_folds);
752#endif
753 }
754 vim_free(wip);
755 }
756}
757
758#if defined(FEAT_LISTCMDS) || defined(PROTO)
759/*
760 * Go to another buffer. Handles the result of the ATTENTION dialog.
761 */
762 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100763goto_buffer(
764 exarg_T *eap,
765 int start,
766 int dir,
767 int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768{
Bram Moolenaare64ac772005-12-07 20:54:59 +0000769# if defined(FEAT_WINDOWS) && defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000770 buf_T *old_curbuf = curbuf;
771
772 swap_exists_action = SEA_DIALOG;
773# endif
774 (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
775 start, dir, count, eap->forceit);
Bram Moolenaare64ac772005-12-07 20:54:59 +0000776# if defined(FEAT_WINDOWS) && defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
778 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000779# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
780 cleanup_T cs;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000781
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000782 /* Reset the error/interrupt/exception state here so that
783 * aborting() returns FALSE when closing a window. */
784 enter_cleanup(&cs);
785# endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000786
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000787 /* Quitting means closing the split window, nothing else. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000788 win_close(curwin, TRUE);
789 swap_exists_action = SEA_NONE;
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000790 swap_exists_did_quit = TRUE;
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000791
792# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
793 /* Restore the error/interrupt/exception state if not discarded by a
794 * new aborting error, interrupt, or uncaught exception. */
795 leave_cleanup(&cs);
796# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000797 }
798 else
799 handle_swap_exists(old_curbuf);
800# endif
801}
802#endif
803
Bram Moolenaare64ac772005-12-07 20:54:59 +0000804#if defined(HAS_SWAP_EXISTS_ACTION) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805/*
806 * Handle the situation of swap_exists_action being set.
807 * It is allowed for "old_curbuf" to be NULL or invalid.
808 */
809 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100810handle_swap_exists(buf_T *old_curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811{
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000812# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
813 cleanup_T cs;
814# endif
Bram Moolenaar6d47df72013-02-17 15:45:37 +0100815#ifdef FEAT_SYN_HL
816 long old_tw = curbuf->b_p_tw;
817#endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000818
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 if (swap_exists_action == SEA_QUIT)
820 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000821# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
822 /* Reset the error/interrupt/exception state here so that
823 * aborting() returns FALSE when closing a buffer. */
824 enter_cleanup(&cs);
825# endif
826
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827 /* User selected Quit at ATTENTION prompt. Go back to previous
828 * buffer. If that buffer is gone or the same as the current one,
829 * open a new, empty buffer. */
830 swap_exists_action = SEA_NONE; /* don't want it again */
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000831 swap_exists_did_quit = TRUE;
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100832 close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000833 if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000834 old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 if (old_curbuf != NULL)
Bram Moolenaar6d47df72013-02-17 15:45:37 +0100836 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 enter_buffer(old_curbuf);
Bram Moolenaar6d47df72013-02-17 15:45:37 +0100838#ifdef FEAT_SYN_HL
839 if (old_tw != curbuf->b_p_tw)
840 check_colorcolumn(curwin);
841#endif
842 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 /* If "old_curbuf" is NULL we are in big trouble here... */
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000844
845# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
846 /* Restore the error/interrupt/exception state if not discarded by a
847 * new aborting error, interrupt, or uncaught exception. */
848 leave_cleanup(&cs);
849# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850 }
851 else if (swap_exists_action == SEA_RECOVER)
852 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000853# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
854 /* Reset the error/interrupt/exception state here so that
855 * aborting() returns FALSE when closing a buffer. */
856 enter_cleanup(&cs);
857# endif
858
Bram Moolenaar071d4272004-06-13 20:20:40 +0000859 /* User selected Recover at ATTENTION prompt. */
860 msg_scroll = TRUE;
861 ml_recover();
862 MSG_PUTS("\n"); /* don't overwrite the last message */
863 cmdline_row = msg_row;
Bram Moolenaara3227e22006-03-08 21:32:40 +0000864 do_modelines(0);
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000865
866# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
867 /* Restore the error/interrupt/exception state if not discarded by a
868 * new aborting error, interrupt, or uncaught exception. */
869 leave_cleanup(&cs);
870# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000871 }
872 swap_exists_action = SEA_NONE;
873}
874#endif
875
876#if defined(FEAT_LISTCMDS) || defined(PROTO)
877/*
878 * do_bufdel() - delete or unload buffer(s)
879 *
880 * addr_count == 0: ":bdel" - delete current buffer
881 * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
882 * buffer "end_bnr", then any other arguments.
883 * addr_count == 2: ":N,N bdel" - delete buffers in range
884 *
885 * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
886 * DOBUF_DEL (":bdel")
887 *
888 * Returns error message or NULL
889 */
890 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100891do_bufdel(
892 int command,
893 char_u *arg, /* pointer to extra arguments */
894 int addr_count,
895 int start_bnr, /* first buffer number in a range */
896 int end_bnr, /* buffer nr or last buffer nr in a range */
897 int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000898{
899 int do_current = 0; /* delete current buffer? */
900 int deleted = 0; /* number of buffers deleted */
901 char_u *errormsg = NULL; /* return value */
902 int bnr; /* buffer number */
903 char_u *p;
904
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 if (addr_count == 0)
906 {
907 (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
908 }
909 else
910 {
911 if (addr_count == 2)
912 {
913 if (*arg) /* both range and argument is not allowed */
914 return (char_u *)_(e_trailing);
915 bnr = start_bnr;
916 }
917 else /* addr_count == 1 */
918 bnr = end_bnr;
919
920 for ( ;!got_int; ui_breakcheck())
921 {
922 /*
923 * delete the current buffer last, otherwise when the
924 * current buffer is deleted, the next buffer becomes
925 * the current one and will be loaded, which may then
926 * also be deleted, etc.
927 */
928 if (bnr == curbuf->b_fnum)
929 do_current = bnr;
930 else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
931 forceit) == OK)
932 ++deleted;
933
934 /*
935 * find next buffer number to delete/unload
936 */
937 if (addr_count == 2)
938 {
939 if (++bnr > end_bnr)
940 break;
941 }
942 else /* addr_count == 1 */
943 {
944 arg = skipwhite(arg);
945 if (*arg == NUL)
946 break;
947 if (!VIM_ISDIGIT(*arg))
948 {
949 p = skiptowhite_esc(arg);
Bram Moolenaar0c279bb2013-03-19 14:25:54 +0100950 bnr = buflist_findpat(arg, p, command == DOBUF_WIPE,
951 FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952 if (bnr < 0) /* failed */
953 break;
954 arg = p;
955 }
956 else
957 bnr = getdigits(&arg);
958 }
959 }
960 if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
961 FORWARD, do_current, forceit) == OK)
962 ++deleted;
963
964 if (deleted == 0)
965 {
966 if (command == DOBUF_UNLOAD)
Bram Moolenaar51485f02005-06-04 21:55:20 +0000967 STRCPY(IObuff, _("E515: No buffers were unloaded"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000968 else if (command == DOBUF_DEL)
Bram Moolenaar51485f02005-06-04 21:55:20 +0000969 STRCPY(IObuff, _("E516: No buffers were deleted"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000970 else
Bram Moolenaar51485f02005-06-04 21:55:20 +0000971 STRCPY(IObuff, _("E517: No buffers were wiped out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000972 errormsg = IObuff;
973 }
974 else if (deleted >= p_report)
975 {
976 if (command == DOBUF_UNLOAD)
977 {
978 if (deleted == 1)
979 MSG(_("1 buffer unloaded"));
980 else
981 smsg((char_u *)_("%d buffers unloaded"), deleted);
982 }
983 else if (command == DOBUF_DEL)
984 {
985 if (deleted == 1)
986 MSG(_("1 buffer deleted"));
987 else
988 smsg((char_u *)_("%d buffers deleted"), deleted);
989 }
990 else
991 {
992 if (deleted == 1)
993 MSG(_("1 buffer wiped out"));
994 else
995 smsg((char_u *)_("%d buffers wiped out"), deleted);
996 }
997 }
998 }
999
Bram Moolenaar071d4272004-06-13 20:20:40 +00001000
1001 return errormsg;
1002}
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02001003#endif /* FEAT_LISTCMDS */
1004
1005#if defined(FEAT_LISTCMDS) || defined(FEAT_PYTHON) \
1006 || defined(FEAT_PYTHON3) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001007
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001008static int empty_curbuf(int close_others, int forceit, int action);
Bram Moolenaara02471e2014-01-10 16:43:14 +01001009
1010/*
1011 * Make the current buffer empty.
1012 * Used when it is wiped out and it's the last buffer.
1013 */
1014 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01001015empty_curbuf(
1016 int close_others,
1017 int forceit,
1018 int action)
Bram Moolenaara02471e2014-01-10 16:43:14 +01001019{
1020 int retval;
1021 buf_T *buf = curbuf;
1022
1023 if (action == DOBUF_UNLOAD)
1024 {
1025 EMSG(_("E90: Cannot unload last buffer"));
1026 return FAIL;
1027 }
1028
1029 if (close_others)
1030 {
1031 /* Close any other windows on this buffer, then make it empty. */
1032#ifdef FEAT_WINDOWS
1033 close_windows(buf, TRUE);
1034#endif
1035 }
1036
1037 setpcmark();
1038 retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
1039 forceit ? ECMD_FORCEIT : 0, curwin);
1040
1041 /*
1042 * do_ecmd() may create a new buffer, then we have to delete
1043 * the old one. But do_ecmd() may have done that already, check
1044 * if the buffer still exists.
1045 */
1046 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
1047 close_buffer(NULL, buf, action, FALSE);
1048 if (!close_others)
1049 need_fileinfo = FALSE;
1050 return retval;
1051}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052/*
1053 * Implementation of the commands for the buffer list.
1054 *
1055 * action == DOBUF_GOTO go to specified buffer
1056 * action == DOBUF_SPLIT split window and go to specified buffer
1057 * action == DOBUF_UNLOAD unload specified buffer(s)
1058 * action == DOBUF_DEL delete specified buffer(s) from buffer list
1059 * action == DOBUF_WIPE delete specified buffer(s) really
1060 *
1061 * start == DOBUF_CURRENT go to "count" buffer from current buffer
1062 * start == DOBUF_FIRST go to "count" buffer from first buffer
1063 * start == DOBUF_LAST go to "count" buffer from last buffer
1064 * start == DOBUF_MOD go to "count" modified buffer from current buffer
1065 *
1066 * Return FAIL or OK.
1067 */
1068 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01001069do_buffer(
1070 int action,
1071 int start,
1072 int dir, /* FORWARD or BACKWARD */
1073 int count, /* buffer number or number of buffers */
1074 int forceit) /* TRUE for :...! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075{
1076 buf_T *buf;
1077 buf_T *bp;
1078 int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
1079 || action == DOBUF_WIPE);
1080
1081 switch (start)
1082 {
1083 case DOBUF_FIRST: buf = firstbuf; break;
1084 case DOBUF_LAST: buf = lastbuf; break;
1085 default: buf = curbuf; break;
1086 }
1087 if (start == DOBUF_MOD) /* find next modified buffer */
1088 {
1089 while (count-- > 0)
1090 {
1091 do
1092 {
1093 buf = buf->b_next;
1094 if (buf == NULL)
1095 buf = firstbuf;
1096 }
1097 while (buf != curbuf && !bufIsChanged(buf));
1098 }
1099 if (!bufIsChanged(buf))
1100 {
1101 EMSG(_("E84: No modified buffer found"));
1102 return FAIL;
1103 }
1104 }
1105 else if (start == DOBUF_FIRST && count) /* find specified buffer number */
1106 {
1107 while (buf != NULL && buf->b_fnum != count)
1108 buf = buf->b_next;
1109 }
1110 else
1111 {
1112 bp = NULL;
1113 while (count > 0 || (!unload && !buf->b_p_bl && bp != buf))
1114 {
1115 /* remember the buffer where we start, we come back there when all
1116 * buffers are unlisted. */
1117 if (bp == NULL)
1118 bp = buf;
1119 if (dir == FORWARD)
1120 {
1121 buf = buf->b_next;
1122 if (buf == NULL)
1123 buf = firstbuf;
1124 }
1125 else
1126 {
1127 buf = buf->b_prev;
1128 if (buf == NULL)
1129 buf = lastbuf;
1130 }
1131 /* don't count unlisted buffers */
1132 if (unload || buf->b_p_bl)
1133 {
1134 --count;
1135 bp = NULL; /* use this buffer as new starting point */
1136 }
1137 if (bp == buf)
1138 {
1139 /* back where we started, didn't find anything. */
1140 EMSG(_("E85: There is no listed buffer"));
1141 return FAIL;
1142 }
1143 }
1144 }
1145
1146 if (buf == NULL) /* could not find it */
1147 {
1148 if (start == DOBUF_FIRST)
1149 {
1150 /* don't warn when deleting */
1151 if (!unload)
Bram Moolenaar3b3a9492015-01-27 18:44:16 +01001152 EMSGN(_(e_nobufnr), count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 }
1154 else if (dir == FORWARD)
1155 EMSG(_("E87: Cannot go beyond last buffer"));
1156 else
1157 EMSG(_("E88: Cannot go before first buffer"));
1158 return FAIL;
1159 }
1160
1161#ifdef FEAT_GUI
1162 need_mouse_correct = TRUE;
1163#endif
1164
1165#ifdef FEAT_LISTCMDS
1166 /*
1167 * delete buffer buf from memory and/or the list
1168 */
1169 if (unload)
1170 {
1171 int forward;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172
1173 /* When unloading or deleting a buffer that's already unloaded and
1174 * unlisted: fail silently. */
1175 if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
1176 return FAIL;
1177
1178 if (!forceit && bufIsChanged(buf))
1179 {
1180#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1181 if ((p_confirm || cmdmod.confirm) && p_write)
1182 {
1183 dialog_changed(buf, FALSE);
1184# ifdef FEAT_AUTOCMD
1185 if (!buf_valid(buf))
1186 /* Autocommand deleted buffer, oops! It's not changed
1187 * now. */
1188 return FAIL;
1189# endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001190 /* If it's still changed fail silently, the dialog already
1191 * mentioned why it fails. */
1192 if (bufIsChanged(buf))
1193 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001194 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001195 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196#endif
1197 {
1198 EMSGN(_("E89: No write since last change for buffer %ld (add ! to override)"),
1199 buf->b_fnum);
1200 return FAIL;
1201 }
1202 }
1203
1204 /*
1205 * If deleting the last (listed) buffer, make it empty.
1206 * The last (listed) buffer cannot be unloaded.
1207 */
1208 for (bp = firstbuf; bp != NULL; bp = bp->b_next)
1209 if (bp->b_p_bl && bp != buf)
1210 break;
1211 if (bp == NULL && buf == curbuf)
Bram Moolenaara02471e2014-01-10 16:43:14 +01001212 return empty_curbuf(TRUE, forceit, action);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001213
1214#ifdef FEAT_WINDOWS
1215 /*
1216 * If the deleted buffer is the current one, close the current window
Bram Moolenaarf740b292006-02-16 22:11:02 +00001217 * (unless it's the only window). Repeat this so long as we end up in
1218 * a window with this buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001219 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001220 while (buf == curbuf
Bram Moolenaar362ce482012-06-06 19:02:45 +02001221# ifdef FEAT_AUTOCMD
1222 && !(curwin->w_closing || curwin->w_buffer->b_closing)
1223# endif
Bram Moolenaarf740b292006-02-16 22:11:02 +00001224 && (firstwin != lastwin || first_tabpage->tp_next != NULL))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02001225 {
1226 if (win_close(curwin, FALSE) == FAIL)
1227 break;
1228 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229#endif
1230
1231 /*
1232 * If the buffer to be deleted is not the current one, delete it here.
1233 */
1234 if (buf != curbuf)
1235 {
1236#ifdef FEAT_WINDOWS
Bram Moolenaarf740b292006-02-16 22:11:02 +00001237 close_windows(buf, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238#endif
1239 if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
Bram Moolenaar42ec6562012-02-22 14:58:37 +01001240 close_buffer(NULL, buf, action, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241 return OK;
1242 }
1243
1244 /*
1245 * Deleting the current buffer: Need to find another buffer to go to.
Bram Moolenaara02471e2014-01-10 16:43:14 +01001246 * There should be another, otherwise it would have been handled
1247 * above. However, autocommands may have deleted all buffers.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248 * First use au_new_curbuf, if it is valid.
1249 * Then prefer the buffer we most recently visited.
1250 * Else try to find one that is loaded, after the current buffer,
1251 * then before the current buffer.
1252 * Finally use any buffer.
1253 */
1254 buf = NULL; /* selected buffer */
1255 bp = NULL; /* used when no loaded buffer found */
1256#ifdef FEAT_AUTOCMD
1257 if (au_new_curbuf != NULL && buf_valid(au_new_curbuf))
1258 buf = au_new_curbuf;
1259# ifdef FEAT_JUMPLIST
1260 else
1261# endif
1262#endif
1263#ifdef FEAT_JUMPLIST
1264 if (curwin->w_jumplistlen > 0)
1265 {
1266 int jumpidx;
1267
1268 jumpidx = curwin->w_jumplistidx - 1;
1269 if (jumpidx < 0)
1270 jumpidx = curwin->w_jumplistlen - 1;
1271
1272 forward = jumpidx;
1273 while (jumpidx != curwin->w_jumplistidx)
1274 {
1275 buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
1276 if (buf != NULL)
1277 {
1278 if (buf == curbuf || !buf->b_p_bl)
1279 buf = NULL; /* skip current and unlisted bufs */
1280 else if (buf->b_ml.ml_mfp == NULL)
1281 {
1282 /* skip unloaded buf, but may keep it for later */
1283 if (bp == NULL)
1284 bp = buf;
1285 buf = NULL;
1286 }
1287 }
1288 if (buf != NULL) /* found a valid buffer: stop searching */
1289 break;
1290 /* advance to older entry in jump list */
1291 if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen)
1292 break;
1293 if (--jumpidx < 0)
1294 jumpidx = curwin->w_jumplistlen - 1;
1295 if (jumpidx == forward) /* List exhausted for sure */
1296 break;
1297 }
1298 }
1299#endif
1300
1301 if (buf == NULL) /* No previous buffer, Try 2'nd approach */
1302 {
1303 forward = TRUE;
1304 buf = curbuf->b_next;
1305 for (;;)
1306 {
1307 if (buf == NULL)
1308 {
1309 if (!forward) /* tried both directions */
1310 break;
1311 buf = curbuf->b_prev;
1312 forward = FALSE;
1313 continue;
1314 }
1315 /* in non-help buffer, try to skip help buffers, and vv */
1316 if (buf->b_help == curbuf->b_help && buf->b_p_bl)
1317 {
1318 if (buf->b_ml.ml_mfp != NULL) /* found loaded buffer */
1319 break;
1320 if (bp == NULL) /* remember unloaded buf for later */
1321 bp = buf;
1322 }
1323 if (forward)
1324 buf = buf->b_next;
1325 else
1326 buf = buf->b_prev;
1327 }
1328 }
1329 if (buf == NULL) /* No loaded buffer, use unloaded one */
1330 buf = bp;
1331 if (buf == NULL) /* No loaded buffer, find listed one */
1332 {
1333 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1334 if (buf->b_p_bl && buf != curbuf)
1335 break;
1336 }
1337 if (buf == NULL) /* Still no buffer, just take one */
1338 {
1339 if (curbuf->b_next != NULL)
1340 buf = curbuf->b_next;
1341 else
1342 buf = curbuf->b_prev;
1343 }
1344 }
1345
Bram Moolenaara02471e2014-01-10 16:43:14 +01001346 if (buf == NULL)
1347 {
1348 /* Autocommands must have wiped out all other buffers. Only option
1349 * now is to make the current buffer empty. */
1350 return empty_curbuf(FALSE, forceit, action);
1351 }
1352
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353 /*
1354 * make buf current buffer
1355 */
1356 if (action == DOBUF_SPLIT) /* split window first */
1357 {
1358# ifdef FEAT_WINDOWS
Bram Moolenaarf2330482008-06-24 20:19:36 +00001359 /* If 'switchbuf' contains "useopen": jump to first window containing
1360 * "buf" if one exists */
1361 if ((swb_flags & SWB_USEOPEN) && buf_jump_open_win(buf))
Bram Moolenaar779b74b2006-04-10 14:55:34 +00001362 return OK;
Bram Moolenaar9381ab72008-11-12 11:52:19 +00001363 /* If 'switchbuf' contains "usetab": jump to first window in any tab
Bram Moolenaarf2330482008-06-24 20:19:36 +00001364 * page containing "buf" if one exists */
1365 if ((swb_flags & SWB_USETAB) && buf_jump_open_tab(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001366 return OK;
1367 if (win_split(0, 0) == FAIL)
1368# endif
1369 return FAIL;
1370 }
1371#endif
1372
1373 /* go to current buffer - nothing to do */
1374 if (buf == curbuf)
1375 return OK;
1376
1377 /*
1378 * Check if the current buffer may be abandoned.
1379 */
1380 if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
1381 {
1382#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1383 if ((p_confirm || cmdmod.confirm) && p_write)
1384 {
1385 dialog_changed(curbuf, FALSE);
1386# ifdef FEAT_AUTOCMD
1387 if (!buf_valid(buf))
1388 /* Autocommand deleted buffer, oops! */
1389 return FAIL;
1390# endif
1391 }
1392 if (bufIsChanged(curbuf))
1393#endif
1394 {
1395 EMSG(_(e_nowrtmsg));
1396 return FAIL;
1397 }
1398 }
1399
1400 /* Go to the other buffer. */
1401 set_curbuf(buf, action);
1402
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001403#if defined(FEAT_LISTCMDS) \
1404 && (defined(FEAT_SCROLLBIND) || defined(FEAT_CURSORBIND))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001405 if (action == DOBUF_SPLIT)
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001406 {
1407 RESET_BINDING(curwin); /* reset 'scrollbind' and 'cursorbind' */
1408 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001409#endif
1410
1411#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1412 if (aborting()) /* autocmds may abort script processing */
1413 return FAIL;
1414#endif
1415
1416 return OK;
1417}
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02001418#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419
1420/*
1421 * Set current buffer to "buf". Executes autocommands and closes current
1422 * buffer. "action" tells how to close the current buffer:
1423 * DOBUF_GOTO free or hide it
1424 * DOBUF_SPLIT nothing
1425 * DOBUF_UNLOAD unload it
1426 * DOBUF_DEL delete it
1427 * DOBUF_WIPE wipe it out
1428 */
1429 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001430set_curbuf(buf_T *buf, int action)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001431{
1432 buf_T *prevbuf;
1433 int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
1434 || action == DOBUF_WIPE);
Bram Moolenaar6d47df72013-02-17 15:45:37 +01001435#ifdef FEAT_SYN_HL
1436 long old_tw = curbuf->b_p_tw;
1437#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001438
1439 setpcmark();
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001440 if (!cmdmod.keepalt)
1441 curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001442 buflist_altfpos(curwin); /* remember curpos */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001443
Bram Moolenaar071d4272004-06-13 20:20:40 +00001444 /* Don't restart Select mode after switching to another buffer. */
1445 VIsual_reselect = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446
1447 /* close_windows() or apply_autocmds() may change curbuf */
1448 prevbuf = curbuf;
1449
1450#ifdef FEAT_AUTOCMD
1451 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
1452# ifdef FEAT_EVAL
1453 if (buf_valid(prevbuf) && !aborting())
1454# else
1455 if (buf_valid(prevbuf))
1456# endif
1457#endif
1458 {
Bram Moolenaara971b822011-09-14 14:43:25 +02001459#ifdef FEAT_SYN_HL
1460 if (prevbuf == curwin->w_buffer)
1461 reset_synblock(curwin);
1462#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001463#ifdef FEAT_WINDOWS
1464 if (unload)
Bram Moolenaarf740b292006-02-16 22:11:02 +00001465 close_windows(prevbuf, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001466#endif
1467#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1468 if (buf_valid(prevbuf) && !aborting())
1469#else
1470 if (buf_valid(prevbuf))
1471#endif
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00001472 {
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001473#ifdef FEAT_WINDOWS
Bram Moolenaare25865a2012-07-06 16:22:02 +02001474 win_T *previouswin = curwin;
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001475#endif
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00001476 if (prevbuf == curbuf)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00001477 u_sync(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001478 close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
1479 unload ? action : (action == DOBUF_GOTO
1480 && !P_HID(prevbuf)
Bram Moolenaar42ec6562012-02-22 14:58:37 +01001481 && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE);
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001482#ifdef FEAT_WINDOWS
Bram Moolenaare25865a2012-07-06 16:22:02 +02001483 if (curwin != previouswin && win_valid(previouswin))
Bram Moolenaar9e931222012-06-20 11:55:01 +02001484 /* autocommands changed curwin, Grr! */
Bram Moolenaare25865a2012-07-06 16:22:02 +02001485 curwin = previouswin;
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001486#endif
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00001487 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001488 }
1489#ifdef FEAT_AUTOCMD
Bram Moolenaar5bd266c2008-09-01 15:33:17 +00001490 /* An autocommand may have deleted "buf", already entered it (e.g., when
Bram Moolenaar9e931222012-06-20 11:55:01 +02001491 * it did ":bunload") or aborted the script processing!
1492 * If curwin->w_buffer is null, enter_buffer() will make it valid again */
1493 if ((buf_valid(buf) && buf != curbuf
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001494# ifdef FEAT_EVAL
Bram Moolenaar9e931222012-06-20 11:55:01 +02001495 && !aborting()
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001496# endif
1497# ifdef FEAT_WINDOWS
Bram Moolenaar9e931222012-06-20 11:55:01 +02001498 ) || curwin->w_buffer == NULL
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001499# endif
Bram Moolenaar9e931222012-06-20 11:55:01 +02001500 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001501#endif
Bram Moolenaar6d47df72013-02-17 15:45:37 +01001502 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001503 enter_buffer(buf);
Bram Moolenaar6d47df72013-02-17 15:45:37 +01001504#ifdef FEAT_SYN_HL
1505 if (old_tw != curbuf->b_p_tw)
1506 check_colorcolumn(curwin);
1507#endif
1508 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001509}
1510
1511/*
1512 * Enter a new current buffer.
Bram Moolenaar6d47df72013-02-17 15:45:37 +01001513 * Old curbuf must have been abandoned already! This also means "curbuf" may
1514 * be pointing to freed memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001515 */
1516 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001517enter_buffer(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001518{
1519 /* Copy buffer and window local option values. Not for a help buffer. */
1520 buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
1521 if (!buf->b_help)
1522 get_winopts(buf);
1523#ifdef FEAT_FOLDING
1524 else
1525 /* Remove all folds in the window. */
1526 clearFolding(curwin);
1527 foldUpdateAll(curwin); /* update folds (later). */
1528#endif
1529
1530 /* Get the buffer in the current window. */
1531 curwin->w_buffer = buf;
1532 curbuf = buf;
1533 ++curbuf->b_nwindows;
1534
1535#ifdef FEAT_DIFF
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00001536 if (curwin->w_p_diff)
1537 diff_buf_add(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001538#endif
1539
Bram Moolenaara971b822011-09-14 14:43:25 +02001540#ifdef FEAT_SYN_HL
1541 curwin->w_s = &(buf->b_s);
1542#endif
1543
Bram Moolenaar071d4272004-06-13 20:20:40 +00001544 /* Cursor on first line by default. */
1545 curwin->w_cursor.lnum = 1;
1546 curwin->w_cursor.col = 0;
1547#ifdef FEAT_VIRTUALEDIT
1548 curwin->w_cursor.coladd = 0;
1549#endif
1550 curwin->w_set_curswant = TRUE;
Bram Moolenaard4153d42008-11-15 15:06:17 +00001551#ifdef FEAT_AUTOCMD
1552 curwin->w_topline_was_set = FALSE;
1553#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001554
Bram Moolenaar89c0ea42010-02-24 16:58:36 +01001555 /* mark cursor position as being invalid */
1556 curwin->w_valid = 0;
1557
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558 /* Make sure the buffer is loaded. */
1559 if (curbuf->b_ml.ml_mfp == NULL) /* need to load the file */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001560 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +00001561#ifdef FEAT_AUTOCMD
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001562 /* If there is no filetype, allow for detecting one. Esp. useful for
1563 * ":ball" used in a autocommand. If there already is a filetype we
1564 * might prefer to keep it. */
1565 if (*curbuf->b_p_ft == NUL)
1566 did_filetype = FALSE;
Bram Moolenaarc0197e22004-09-13 20:26:32 +00001567#endif
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001568
Bram Moolenaar59f931e2010-07-24 20:27:03 +02001569 open_buffer(FALSE, NULL, 0);
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001570 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571 else
1572 {
Bram Moolenaar55b7cf82006-09-09 12:52:42 +00001573 if (!msg_silent)
1574 need_fileinfo = TRUE; /* display file info after redraw */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575 (void)buf_check_timestamp(curbuf, FALSE); /* check if file changed */
1576#ifdef FEAT_AUTOCMD
1577 curwin->w_topline = 1;
1578# ifdef FEAT_DIFF
1579 curwin->w_topfill = 0;
1580# endif
1581 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
1582 apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
1583#endif
1584 }
1585
1586 /* If autocommands did not change the cursor position, restore cursor lnum
1587 * and possibly cursor col. */
1588 if (curwin->w_cursor.lnum == 1 && inindent(0))
1589 buflist_getfpos();
1590
1591 check_arg_idx(curwin); /* check for valid arg_idx */
1592#ifdef FEAT_TITLE
1593 maketitle();
1594#endif
1595#ifdef FEAT_AUTOCMD
Bram Moolenaard4153d42008-11-15 15:06:17 +00001596 /* when autocmds didn't change it */
1597 if (curwin->w_topline == 1 && !curwin->w_topline_was_set)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001598#endif
1599 scroll_cursor_halfway(FALSE); /* redisplay at correct position */
1600
Bram Moolenaar009b2592004-10-24 19:18:58 +00001601#ifdef FEAT_NETBEANS_INTG
1602 /* Send fileOpened event because we've changed buffers. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +02001603 netbeans_file_activated(curbuf);
Bram Moolenaar009b2592004-10-24 19:18:58 +00001604#endif
1605
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001606 /* Change directories when the 'acd' option is set. */
1607 DO_AUTOCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608
1609#ifdef FEAT_KEYMAP
1610 if (curbuf->b_kmap_state & KEYMAP_INIT)
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00001611 (void)keymap_init();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001612#endif
Bram Moolenaar706cdeb2007-05-06 21:55:31 +00001613#ifdef FEAT_SPELL
1614 /* May need to set the spell language. Can only do this after the buffer
1615 * has been properly setup. */
Bram Moolenaar860cae12010-06-05 23:22:07 +02001616 if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
1617 (void)did_set_spelllang(curwin);
Bram Moolenaar706cdeb2007-05-06 21:55:31 +00001618#endif
1619
Bram Moolenaar071d4272004-06-13 20:20:40 +00001620 redraw_later(NOT_VALID);
1621}
1622
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001623#if defined(FEAT_AUTOCHDIR) || defined(PROTO)
1624/*
1625 * Change to the directory of the current buffer.
Bram Moolenaar6bd364e2016-02-23 16:19:07 +01001626 * Don't do this while still starting up.
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001627 */
1628 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001629do_autochdir(void)
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001630{
Bram Moolenaar6bd364e2016-02-23 16:19:07 +01001631 if (starting == 0
1632 && curbuf->b_ffname != NULL
1633 && vim_chdirfile(curbuf->b_ffname) == OK)
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001634 shorten_fnames(TRUE);
1635}
1636#endif
1637
Bram Moolenaar071d4272004-06-13 20:20:40 +00001638/*
1639 * functions for dealing with the buffer list
1640 */
1641
1642/*
1643 * Add a file name to the buffer list. Return a pointer to the buffer.
1644 * If the same file name already exists return a pointer to that buffer.
1645 * If it does not exist, or if fname == NULL, a new entry is created.
1646 * If (flags & BLN_CURBUF) is TRUE, may use current buffer.
1647 * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list.
1648 * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001649 * This is the ONLY way to create a new buffer.
1650 */
1651static int top_file_num = 1; /* highest file number */
1652
1653 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01001654buflist_new(
1655 char_u *ffname, /* full path of fname or relative */
1656 char_u *sfname, /* short fname or NULL */
1657 linenr_T lnum, /* preferred cursor line */
1658 int flags) /* BLN_ defines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001659{
1660 buf_T *buf;
1661#ifdef UNIX
1662 struct stat st;
1663#endif
1664
1665 fname_expand(curbuf, &ffname, &sfname); /* will allocate ffname */
1666
1667 /*
1668 * If file name already exists in the list, update the entry.
1669 */
1670#ifdef UNIX
1671 /* On Unix we can use inode numbers when the file exists. Works better
1672 * for hard links. */
1673 if (sfname == NULL || mch_stat((char *)sfname, &st) < 0)
1674 st.st_dev = (dev_T)-1;
1675#endif
1676 if (ffname != NULL && !(flags & BLN_DUMMY) && (buf =
1677#ifdef UNIX
1678 buflist_findname_stat(ffname, &st)
1679#else
1680 buflist_findname(ffname)
1681#endif
1682 ) != NULL)
1683 {
1684 vim_free(ffname);
1685 if (lnum != 0)
1686 buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE);
1687 /* copy the options now, if 'cpo' doesn't have 's' and not done
1688 * already */
1689 buf_copy_options(buf, 0);
1690 if ((flags & BLN_LISTED) && !buf->b_p_bl)
1691 {
1692 buf->b_p_bl = TRUE;
1693#ifdef FEAT_AUTOCMD
1694 if (!(flags & BLN_DUMMY))
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001695 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001697 if (!buf_valid(buf))
1698 return NULL;
1699 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001700#endif
1701 }
1702 return buf;
1703 }
1704
1705 /*
1706 * If the current buffer has no name and no contents, use the current
1707 * buffer. Otherwise: Need to allocate a new buffer structure.
1708 *
1709 * This is the ONLY place where a new buffer structure is allocated!
Bram Moolenaar4770d092006-01-12 23:22:24 +00001710 * (A spell file buffer is allocated in spell.c, but that's not a normal
1711 * buffer.)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001712 */
1713 buf = NULL;
1714 if ((flags & BLN_CURBUF)
1715 && curbuf != NULL
1716 && curbuf->b_ffname == NULL
1717 && curbuf->b_nwindows <= 1
1718 && (curbuf->b_ml.ml_mfp == NULL || bufempty()))
1719 {
1720 buf = curbuf;
1721#ifdef FEAT_AUTOCMD
1722 /* It's like this buffer is deleted. Watch out for autocommands that
1723 * change curbuf! If that happens, allocate a new buffer anyway. */
1724 if (curbuf->b_p_bl)
1725 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
1726 if (buf == curbuf)
1727 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
1728# ifdef FEAT_EVAL
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001729 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001730 return NULL;
1731# endif
1732#endif
1733#ifdef FEAT_QUICKFIX
1734# ifdef FEAT_AUTOCMD
1735 if (buf == curbuf)
1736# endif
1737 {
1738 /* Make sure 'bufhidden' and 'buftype' are empty */
1739 clear_string_option(&buf->b_p_bh);
1740 clear_string_option(&buf->b_p_bt);
1741 }
1742#endif
1743 }
1744 if (buf != curbuf || curbuf == NULL)
1745 {
1746 buf = (buf_T *)alloc_clear((unsigned)sizeof(buf_T));
1747 if (buf == NULL)
1748 {
1749 vim_free(ffname);
1750 return NULL;
1751 }
Bram Moolenaar429fa852013-04-15 12:27:36 +02001752#ifdef FEAT_EVAL
1753 /* init b: variables */
1754 buf->b_vars = dict_alloc();
1755 if (buf->b_vars == NULL)
1756 {
1757 vim_free(ffname);
1758 vim_free(buf);
1759 return NULL;
1760 }
1761 init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
1762#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 }
1764
1765 if (ffname != NULL)
1766 {
1767 buf->b_ffname = ffname;
1768 buf->b_sfname = vim_strsave(sfname);
1769 }
1770
1771 clear_wininfo(buf);
1772 buf->b_wininfo = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
1773
1774 if ((ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL))
1775 || buf->b_wininfo == NULL)
1776 {
1777 vim_free(buf->b_ffname);
1778 buf->b_ffname = NULL;
1779 vim_free(buf->b_sfname);
1780 buf->b_sfname = NULL;
1781 if (buf != curbuf)
1782 free_buffer(buf);
1783 return NULL;
1784 }
1785
1786 if (buf == curbuf)
1787 {
1788 /* free all things allocated for this buffer */
Bram Moolenaar59f931e2010-07-24 20:27:03 +02001789 buf_freeall(buf, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001790 if (buf != curbuf) /* autocommands deleted the buffer! */
1791 return NULL;
1792#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001793 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 return NULL;
1795#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796 free_buffer_stuff(buf, FALSE); /* delete local variables et al. */
Bram Moolenaar0ac24e12012-11-20 12:16:58 +01001797
1798 /* Init the options. */
1799 buf->b_p_initialized = FALSE;
1800 buf_copy_options(buf, BCO_ENTER);
1801
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802#ifdef FEAT_KEYMAP
1803 /* need to reload lmaps and set b:keymap_name */
1804 curbuf->b_kmap_state |= KEYMAP_INIT;
1805#endif
1806 }
1807 else
1808 {
1809 /*
1810 * put new buffer at the end of the buffer list
1811 */
1812 buf->b_next = NULL;
1813 if (firstbuf == NULL) /* buffer list is empty */
1814 {
1815 buf->b_prev = NULL;
1816 firstbuf = buf;
1817 }
1818 else /* append new buffer at end of list */
1819 {
1820 lastbuf->b_next = buf;
1821 buf->b_prev = lastbuf;
1822 }
1823 lastbuf = buf;
1824
1825 buf->b_fnum = top_file_num++;
1826 if (top_file_num < 0) /* wrap around (may cause duplicates) */
1827 {
1828 EMSG(_("W14: Warning: List of file names overflow"));
1829 if (emsg_silent == 0)
1830 {
1831 out_flush();
1832 ui_delay(3000L, TRUE); /* make sure it is noticed */
1833 }
1834 top_file_num = 1;
1835 }
1836
1837 /*
1838 * Always copy the options from the current buffer.
1839 */
1840 buf_copy_options(buf, BCO_ALWAYS);
1841 }
1842
1843 buf->b_wininfo->wi_fpos.lnum = lnum;
1844 buf->b_wininfo->wi_win = curwin;
1845
Bram Moolenaar1fad5d42005-01-25 21:44:33 +00001846#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +02001847 hash_init(&buf->b_s.b_keywtab);
1848 hash_init(&buf->b_s.b_keywtab_ic);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849#endif
1850
1851 buf->b_fname = buf->b_sfname;
1852#ifdef UNIX
1853 if (st.st_dev == (dev_T)-1)
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00001854 buf->b_dev_valid = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001855 else
1856 {
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00001857 buf->b_dev_valid = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001858 buf->b_dev = st.st_dev;
1859 buf->b_ino = st.st_ino;
1860 }
1861#endif
1862 buf->b_u_synced = TRUE;
1863 buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
Bram Moolenaar81695252004-12-29 20:58:21 +00001864 if (flags & BLN_DUMMY)
1865 buf->b_flags |= BF_DUMMY;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 buf_clear_file(buf);
1867 clrallmarks(buf); /* clear marks */
1868 fmarks_check_names(buf); /* check file marks for this file */
1869 buf->b_p_bl = (flags & BLN_LISTED) ? TRUE : FALSE; /* init 'buflisted' */
1870#ifdef FEAT_AUTOCMD
1871 if (!(flags & BLN_DUMMY))
1872 {
Bram Moolenaar8da9bbf2015-02-27 19:34:56 +01001873 /* Tricky: these autocommands may change the buffer list. They could
1874 * also split the window with re-using the one empty buffer. This may
1875 * result in unexpectedly losing the empty buffer. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf);
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001877 if (!buf_valid(buf))
1878 return NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879 if (flags & BLN_LISTED)
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001880 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001882 if (!buf_valid(buf))
1883 return NULL;
1884 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001885# ifdef FEAT_EVAL
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001886 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 return NULL;
1888# endif
1889 }
1890#endif
1891
1892 return buf;
1893}
1894
1895/*
1896 * Free the memory for the options of a buffer.
1897 * If "free_p_ff" is TRUE also free 'fileformat', 'buftype' and
1898 * 'fileencoding'.
1899 */
1900 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001901free_buf_options(
1902 buf_T *buf,
1903 int free_p_ff)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904{
1905 if (free_p_ff)
1906 {
1907#ifdef FEAT_MBYTE
1908 clear_string_option(&buf->b_p_fenc);
1909#endif
1910 clear_string_option(&buf->b_p_ff);
1911#ifdef FEAT_QUICKFIX
1912 clear_string_option(&buf->b_p_bh);
1913 clear_string_option(&buf->b_p_bt);
1914#endif
1915 }
1916#ifdef FEAT_FIND_ID
1917 clear_string_option(&buf->b_p_def);
1918 clear_string_option(&buf->b_p_inc);
1919# ifdef FEAT_EVAL
1920 clear_string_option(&buf->b_p_inex);
1921# endif
1922#endif
1923#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
1924 clear_string_option(&buf->b_p_inde);
1925 clear_string_option(&buf->b_p_indk);
1926#endif
Bram Moolenaar371d5402006-03-20 21:47:49 +00001927#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
1928 clear_string_option(&buf->b_p_bexpr);
1929#endif
Bram Moolenaar49771f42010-07-20 17:32:38 +02001930#if defined(FEAT_CRYPT)
1931 clear_string_option(&buf->b_p_cm);
1932#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001933#if defined(FEAT_EVAL)
1934 clear_string_option(&buf->b_p_fex);
1935#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936#ifdef FEAT_CRYPT
1937 clear_string_option(&buf->b_p_key);
1938#endif
1939 clear_string_option(&buf->b_p_kp);
1940 clear_string_option(&buf->b_p_mps);
1941 clear_string_option(&buf->b_p_fo);
Bram Moolenaar86b68352004-12-27 21:59:20 +00001942 clear_string_option(&buf->b_p_flp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943 clear_string_option(&buf->b_p_isk);
1944#ifdef FEAT_KEYMAP
1945 clear_string_option(&buf->b_p_keymap);
1946 ga_clear(&buf->b_kmap_ga);
1947#endif
1948#ifdef FEAT_COMMENTS
1949 clear_string_option(&buf->b_p_com);
1950#endif
1951#ifdef FEAT_FOLDING
1952 clear_string_option(&buf->b_p_cms);
1953#endif
1954 clear_string_option(&buf->b_p_nf);
1955#ifdef FEAT_SYN_HL
1956 clear_string_option(&buf->b_p_syn);
Bram Moolenaarb8060fe2016-01-19 22:29:28 +01001957 clear_string_option(&buf->b_s.b_syn_isk);
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00001958#endif
1959#ifdef FEAT_SPELL
Bram Moolenaar860cae12010-06-05 23:22:07 +02001960 clear_string_option(&buf->b_s.b_p_spc);
1961 clear_string_option(&buf->b_s.b_p_spf);
Bram Moolenaar473de612013-06-08 18:19:48 +02001962 vim_regfree(buf->b_s.b_cap_prog);
Bram Moolenaar860cae12010-06-05 23:22:07 +02001963 buf->b_s.b_cap_prog = NULL;
1964 clear_string_option(&buf->b_s.b_p_spl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965#endif
1966#ifdef FEAT_SEARCHPATH
1967 clear_string_option(&buf->b_p_sua);
1968#endif
1969#ifdef FEAT_AUTOCMD
1970 clear_string_option(&buf->b_p_ft);
1971#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001972#ifdef FEAT_CINDENT
1973 clear_string_option(&buf->b_p_cink);
1974 clear_string_option(&buf->b_p_cino);
1975#endif
1976#if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
1977 clear_string_option(&buf->b_p_cinw);
1978#endif
1979#ifdef FEAT_INS_EXPAND
1980 clear_string_option(&buf->b_p_cpt);
1981#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001982#ifdef FEAT_COMPL_FUNC
1983 clear_string_option(&buf->b_p_cfu);
Bram Moolenaare344bea2005-09-01 20:46:49 +00001984 clear_string_option(&buf->b_p_ofu);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001985#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986#ifdef FEAT_QUICKFIX
1987 clear_string_option(&buf->b_p_gp);
1988 clear_string_option(&buf->b_p_mp);
1989 clear_string_option(&buf->b_p_efm);
1990#endif
1991 clear_string_option(&buf->b_p_ep);
1992 clear_string_option(&buf->b_p_path);
1993 clear_string_option(&buf->b_p_tags);
Bram Moolenaar0f6562e2015-11-24 18:48:14 +01001994 clear_string_option(&buf->b_p_tc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995#ifdef FEAT_INS_EXPAND
1996 clear_string_option(&buf->b_p_dict);
1997 clear_string_option(&buf->b_p_tsr);
1998#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001999#ifdef FEAT_TEXTOBJ
2000 clear_string_option(&buf->b_p_qe);
2001#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002002 buf->b_p_ar = -1;
Bram Moolenaarf5a2fd82013-11-06 05:26:15 +01002003 buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
Bram Moolenaaraf6c1312014-03-12 18:55:58 +01002004#ifdef FEAT_LISP
2005 clear_string_option(&buf->b_p_lw);
2006#endif
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02002007 clear_string_option(&buf->b_p_bkc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002008}
2009
2010/*
2011 * get alternate file n
2012 * set linenr to lnum or altfpos.lnum if lnum == 0
2013 * also set cursor column to altfpos.col if 'startofline' is not set.
2014 * if (options & GETF_SETMARK) call setpcmark()
2015 * if (options & GETF_ALT) we are jumping to an alternate file.
2016 * if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping
2017 *
2018 * return FAIL for failure, OK for success
2019 */
2020 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002021buflist_getfile(
2022 int n,
2023 linenr_T lnum,
2024 int options,
2025 int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026{
2027 buf_T *buf;
2028#ifdef FEAT_WINDOWS
2029 win_T *wp = NULL;
2030#endif
2031 pos_T *fpos;
2032 colnr_T col;
2033
2034 buf = buflist_findnr(n);
2035 if (buf == NULL)
2036 {
2037 if ((options & GETF_ALT) && n == 0)
2038 EMSG(_(e_noalt));
2039 else
2040 EMSGN(_("E92: Buffer %ld not found"), n);
2041 return FAIL;
2042 }
2043
2044 /* if alternate file is the current buffer, nothing to do */
2045 if (buf == curbuf)
2046 return OK;
2047
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002048 if (text_locked())
Bram Moolenaar05a7bb32006-01-19 22:09:32 +00002049 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002050 text_locked_msg();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002051 return FAIL;
Bram Moolenaar05a7bb32006-01-19 22:09:32 +00002052 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002053#ifdef FEAT_AUTOCMD
2054 if (curbuf_locked())
2055 return FAIL;
2056#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057
2058 /* altfpos may be changed by getfile(), get it now */
2059 if (lnum == 0)
2060 {
2061 fpos = buflist_findfpos(buf);
2062 lnum = fpos->lnum;
2063 col = fpos->col;
2064 }
2065 else
2066 col = 0;
2067
2068#ifdef FEAT_WINDOWS
2069 if (options & GETF_SWITCH)
2070 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002071 /* If 'switchbuf' contains "useopen": jump to first window containing
2072 * "buf" if one exists */
2073 if (swb_flags & SWB_USEOPEN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074 wp = buf_jump_open_win(buf);
Bram Moolenaara594d772015-06-19 14:41:49 +02002075
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002076 /* If 'switchbuf' contains "usetab": jump to first window in any tab
Bram Moolenaarf2330482008-06-24 20:19:36 +00002077 * page containing "buf" if one exists */
2078 if (wp == NULL && (swb_flags & SWB_USETAB))
Bram Moolenaar779b74b2006-04-10 14:55:34 +00002079 wp = buf_jump_open_tab(buf);
Bram Moolenaara594d772015-06-19 14:41:49 +02002080
2081 /* If 'switchbuf' contains "split", "vsplit" or "newtab" and the
2082 * current buffer isn't empty: open new tab or window */
2083 if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB))
2084 && !bufempty())
Bram Moolenaar071d4272004-06-13 20:20:40 +00002085 {
Bram Moolenaara594d772015-06-19 14:41:49 +02002086 if (swb_flags & SWB_NEWTAB)
Bram Moolenaarf2330482008-06-24 20:19:36 +00002087 tabpage_new();
Bram Moolenaara594d772015-06-19 14:41:49 +02002088 else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0)
2089 == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002090 return FAIL;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002091 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092 }
2093 }
2094#endif
2095
2096 ++RedrawingDisabled;
2097 if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK),
2098 lnum, forceit) <= 0)
2099 {
2100 --RedrawingDisabled;
2101
2102 /* cursor is at to BOL and w_cursor.lnum is checked due to getfile() */
2103 if (!p_sol && col != 0)
2104 {
2105 curwin->w_cursor.col = col;
2106 check_cursor_col();
2107#ifdef FEAT_VIRTUALEDIT
2108 curwin->w_cursor.coladd = 0;
2109#endif
2110 curwin->w_set_curswant = TRUE;
2111 }
2112 return OK;
2113 }
2114 --RedrawingDisabled;
2115 return FAIL;
2116}
2117
2118/*
2119 * go to the last know line number for the current buffer
2120 */
2121 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002122buflist_getfpos(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002123{
2124 pos_T *fpos;
2125
2126 fpos = buflist_findfpos(curbuf);
2127
2128 curwin->w_cursor.lnum = fpos->lnum;
2129 check_cursor_lnum();
2130
2131 if (p_sol)
2132 curwin->w_cursor.col = 0;
2133 else
2134 {
2135 curwin->w_cursor.col = fpos->col;
2136 check_cursor_col();
2137#ifdef FEAT_VIRTUALEDIT
2138 curwin->w_cursor.coladd = 0;
2139#endif
2140 curwin->w_set_curswant = TRUE;
2141 }
2142}
2143
Bram Moolenaar81695252004-12-29 20:58:21 +00002144#if defined(FEAT_QUICKFIX) || defined(FEAT_EVAL) || defined(PROTO)
2145/*
2146 * Find file in buffer list by name (it has to be for the current window).
2147 * Returns NULL if not found.
2148 */
2149 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002150buflist_findname_exp(char_u *fname)
Bram Moolenaar81695252004-12-29 20:58:21 +00002151{
2152 char_u *ffname;
2153 buf_T *buf = NULL;
2154
2155 /* First make the name into a full path name */
2156 ffname = FullName_save(fname,
2157#ifdef UNIX
2158 TRUE /* force expansion, get rid of symbolic links */
2159#else
2160 FALSE
2161#endif
2162 );
2163 if (ffname != NULL)
2164 {
2165 buf = buflist_findname(ffname);
2166 vim_free(ffname);
2167 }
2168 return buf;
2169}
2170#endif
2171
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172/*
2173 * Find file in buffer list by name (it has to be for the current window).
2174 * "ffname" must have a full path.
Bram Moolenaar81695252004-12-29 20:58:21 +00002175 * Skips dummy buffers.
2176 * Returns NULL if not found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002177 */
2178 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002179buflist_findname(char_u *ffname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180{
2181#ifdef UNIX
2182 struct stat st;
2183
2184 if (mch_stat((char *)ffname, &st) < 0)
2185 st.st_dev = (dev_T)-1;
2186 return buflist_findname_stat(ffname, &st);
2187}
2188
2189/*
2190 * Same as buflist_findname(), but pass the stat structure to avoid getting it
2191 * twice for the same file.
Bram Moolenaar81695252004-12-29 20:58:21 +00002192 * Returns NULL if not found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193 */
2194 static buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002195buflist_findname_stat(
2196 char_u *ffname,
2197 struct stat *stp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002198{
2199#endif
2200 buf_T *buf;
2201
2202 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
Bram Moolenaar81695252004-12-29 20:58:21 +00002203 if ((buf->b_flags & BF_DUMMY) == 0 && !otherfile_buf(buf, ffname
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204#ifdef UNIX
2205 , stp
2206#endif
2207 ))
2208 return buf;
2209 return NULL;
2210}
2211
Bram Moolenaar0c279bb2013-03-19 14:25:54 +01002212#if defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL) \
2213 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002214/*
2215 * Find file in buffer list by a regexp pattern.
2216 * Return fnum of the found buffer.
2217 * Return < 0 for error.
2218 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002219 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002220buflist_findpat(
2221 char_u *pattern,
2222 char_u *pattern_end, /* pointer to first char after pattern */
2223 int unlisted, /* find unlisted buffers */
2224 int diffmode UNUSED, /* find diff-mode buffers only */
2225 int curtab_only) /* find buffers in current tab only */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226{
2227 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228 int match = -1;
2229 int find_listed;
2230 char_u *pat;
2231 char_u *patend;
2232 int attempt;
2233 char_u *p;
2234 int toggledollar;
2235
2236 if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
2237 {
2238 if (*pattern == '%')
2239 match = curbuf->b_fnum;
2240 else
2241 match = curwin->w_alt_fnum;
2242#ifdef FEAT_DIFF
2243 if (diffmode && !diff_mode_buf(buflist_findnr(match)))
2244 match = -1;
2245#endif
2246 }
2247
2248 /*
2249 * Try four ways of matching a listed buffer:
2250 * attempt == 0: without '^' or '$' (at any position)
Bram Moolenaarb6799ac2007-05-10 16:44:05 +00002251 * attempt == 1: with '^' at start (only at position 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 * attempt == 2: with '$' at end (only match at end)
2253 * attempt == 3: with '^' at start and '$' at end (only full match)
2254 * Repeat this for finding an unlisted buffer if there was no matching
2255 * listed buffer.
2256 */
2257 else
2258 {
2259 pat = file_pat_to_reg_pat(pattern, pattern_end, NULL, FALSE);
2260 if (pat == NULL)
2261 return -1;
2262 patend = pat + STRLEN(pat) - 1;
2263 toggledollar = (patend > pat && *patend == '$');
2264
2265 /* First try finding a listed buffer. If not found and "unlisted"
2266 * is TRUE, try finding an unlisted buffer. */
2267 find_listed = TRUE;
2268 for (;;)
2269 {
2270 for (attempt = 0; attempt <= 3; ++attempt)
2271 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002272 regmatch_T regmatch;
2273
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 /* may add '^' and '$' */
2275 if (toggledollar)
2276 *patend = (attempt < 2) ? NUL : '$'; /* add/remove '$' */
2277 p = pat;
2278 if (*p == '^' && !(attempt & 1)) /* add/remove '^' */
2279 ++p;
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002280 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2281 if (regmatch.regprog == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 {
2283 vim_free(pat);
2284 return -1;
2285 }
2286
2287 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2288 if (buf->b_p_bl == find_listed
2289#ifdef FEAT_DIFF
2290 && (!diffmode || diff_mode_buf(buf))
2291#endif
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002292 && buflist_match(&regmatch, buf, FALSE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293 {
Bram Moolenaar0c279bb2013-03-19 14:25:54 +01002294 if (curtab_only)
2295 {
2296 /* Ignore the match if the buffer is not open in
2297 * the current tab. */
2298#ifdef FEAT_WINDOWS
2299 win_T *wp;
2300
2301 for (wp = firstwin; wp != NULL; wp = wp->w_next)
2302 if (wp->w_buffer == buf)
2303 break;
2304 if (wp == NULL)
2305 continue;
2306#else
2307 if (curwin->w_buffer != buf)
2308 continue;
2309#endif
2310 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002311 if (match >= 0) /* already found a match */
2312 {
2313 match = -2;
2314 break;
2315 }
2316 match = buf->b_fnum; /* remember first match */
2317 }
2318
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002319 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 if (match >= 0) /* found one match */
2321 break;
2322 }
2323
2324 /* Only search for unlisted buffers if there was no match with
2325 * a listed buffer. */
2326 if (!unlisted || !find_listed || match != -1)
2327 break;
2328 find_listed = FALSE;
2329 }
2330
2331 vim_free(pat);
2332 }
2333
2334 if (match == -2)
2335 EMSG2(_("E93: More than one match for %s"), pattern);
2336 else if (match < 0)
2337 EMSG2(_("E94: No matching buffer for %s"), pattern);
2338 return match;
2339}
2340#endif
2341
2342#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2343
2344/*
2345 * Find all buffer names that match.
2346 * For command line expansion of ":buf" and ":sbuf".
2347 * Return OK if matches found, FAIL otherwise.
2348 */
2349 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002350ExpandBufnames(
2351 char_u *pat,
2352 int *num_file,
2353 char_u ***file,
2354 int options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355{
2356 int count = 0;
2357 buf_T *buf;
2358 int round;
2359 char_u *p;
2360 int attempt;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002361 char_u *patc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362
2363 *num_file = 0; /* return values in case of FAIL */
2364 *file = NULL;
2365
Bram Moolenaar05159a02005-02-26 23:04:13 +00002366 /* Make a copy of "pat" and change "^" to "\(^\|[\/]\)". */
2367 if (*pat == '^')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00002369 patc = alloc((unsigned)STRLEN(pat) + 11);
2370 if (patc == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002371 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002372 STRCPY(patc, "\\(^\\|[\\/]\\)");
2373 STRCPY(patc + 11, pat + 1);
2374 }
2375 else
2376 patc = pat;
2377
2378 /*
2379 * attempt == 0: try match with '\<', match at start of word
Bram Moolenaard8a4e562005-05-18 22:06:55 +00002380 * attempt == 1: try match without '\<', match anywhere
Bram Moolenaar05159a02005-02-26 23:04:13 +00002381 */
Bram Moolenaard8a4e562005-05-18 22:06:55 +00002382 for (attempt = 0; attempt <= 1; ++attempt)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002383 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002384 regmatch_T regmatch;
2385
Bram Moolenaard8a4e562005-05-18 22:06:55 +00002386 if (attempt > 0 && patc == pat)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002387 break; /* there was no anchor, no need to try again */
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002388 regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC);
2389 if (regmatch.regprog == NULL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002390 {
2391 if (patc != pat)
2392 vim_free(patc);
2393 return FAIL;
2394 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395
2396 /*
2397 * round == 1: Count the matches.
2398 * round == 2: Build the array to keep the matches.
2399 */
2400 for (round = 1; round <= 2; ++round)
2401 {
2402 count = 0;
2403 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2404 {
2405 if (!buf->b_p_bl) /* skip unlisted buffers */
2406 continue;
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002407 p = buflist_match(&regmatch, buf, p_wic);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002408 if (p != NULL)
2409 {
2410 if (round == 1)
2411 ++count;
2412 else
2413 {
2414 if (options & WILD_HOME_REPLACE)
2415 p = home_replace_save(buf, p);
2416 else
2417 p = vim_strsave(p);
2418 (*file)[count++] = p;
2419 }
2420 }
2421 }
2422 if (count == 0) /* no match found, break here */
2423 break;
2424 if (round == 1)
2425 {
2426 *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
2427 if (*file == NULL)
2428 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002429 vim_regfree(regmatch.regprog);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002430 if (patc != pat)
2431 vim_free(patc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 return FAIL;
2433 }
2434 }
2435 }
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002436 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437 if (count) /* match(es) found, break here */
2438 break;
2439 }
2440
Bram Moolenaar05159a02005-02-26 23:04:13 +00002441 if (patc != pat)
2442 vim_free(patc);
2443
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444 *num_file = count;
2445 return (count == 0 ? FAIL : OK);
2446}
2447
2448#endif /* FEAT_CMDL_COMPL */
2449
2450#ifdef HAVE_BUFLIST_MATCH
2451/*
2452 * Check for a match on the file name for buffer "buf" with regprog "prog".
2453 */
2454 static char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002455buflist_match(
2456 regmatch_T *rmp,
2457 buf_T *buf,
2458 int ignore_case) /* when TRUE ignore case, when FALSE use 'fic' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459{
2460 char_u *match;
2461
2462 /* First try the short file name, then the long file name. */
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002463 match = fname_match(rmp, buf->b_sfname, ignore_case);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 if (match == NULL)
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002465 match = fname_match(rmp, buf->b_ffname, ignore_case);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466
2467 return match;
2468}
2469
2470/*
2471 * Try matching the regexp in "prog" with file name "name".
2472 * Return "name" when there is a match, NULL when not.
2473 */
2474 static char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002475fname_match(
2476 regmatch_T *rmp,
2477 char_u *name,
2478 int ignore_case) /* when TRUE ignore case, when FALSE use 'fic' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479{
2480 char_u *match = NULL;
2481 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482
2483 if (name != NULL)
2484 {
Bram Moolenaar4b9d6372014-09-23 14:24:40 +02002485 /* Ignore case when 'fileignorecase' or the argument is set. */
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002486 rmp->rm_ic = p_fic || ignore_case;
2487 if (vim_regexec(rmp, name, (colnr_T)0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488 match = name;
2489 else
2490 {
2491 /* Replace $(HOME) with '~' and try matching again. */
2492 p = home_replace_save(NULL, name);
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002493 if (p != NULL && vim_regexec(rmp, p, (colnr_T)0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002494 match = name;
2495 vim_free(p);
2496 }
2497 }
2498
2499 return match;
2500}
2501#endif
2502
2503/*
2504 * find file in buffer list by number
2505 */
2506 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002507buflist_findnr(int nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508{
2509 buf_T *buf;
2510
2511 if (nr == 0)
2512 nr = curwin->w_alt_fnum;
2513 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2514 if (buf->b_fnum == nr)
2515 return (buf);
2516 return NULL;
2517}
2518
2519/*
2520 * Get name of file 'n' in the buffer list.
2521 * When the file has no name an empty string is returned.
2522 * home_replace() is used to shorten the file name (used for marks).
2523 * Returns a pointer to allocated memory, of NULL when failed.
2524 */
2525 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002526buflist_nr2name(
2527 int n,
2528 int fullname,
2529 int helptail) /* for help buffers return tail only */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002530{
2531 buf_T *buf;
2532
2533 buf = buflist_findnr(n);
2534 if (buf == NULL)
2535 return NULL;
2536 return home_replace_save(helptail ? buf : NULL,
2537 fullname ? buf->b_ffname : buf->b_fname);
2538}
2539
2540/*
2541 * Set the "lnum" and "col" for the buffer "buf" and the current window.
2542 * When "copy_options" is TRUE save the local window option values.
2543 * When "lnum" is 0 only do the options.
2544 */
2545 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002546buflist_setfpos(
2547 buf_T *buf,
2548 win_T *win,
2549 linenr_T lnum,
2550 colnr_T col,
2551 int copy_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552{
2553 wininfo_T *wip;
2554
2555 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
2556 if (wip->wi_win == win)
2557 break;
2558 if (wip == NULL)
2559 {
2560 /* allocate a new entry */
2561 wip = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
2562 if (wip == NULL)
2563 return;
2564 wip->wi_win = win;
2565 if (lnum == 0) /* set lnum even when it's 0 */
2566 lnum = 1;
2567 }
2568 else
2569 {
2570 /* remove the entry from the list */
2571 if (wip->wi_prev)
2572 wip->wi_prev->wi_next = wip->wi_next;
2573 else
2574 buf->b_wininfo = wip->wi_next;
2575 if (wip->wi_next)
2576 wip->wi_next->wi_prev = wip->wi_prev;
2577 if (copy_options && wip->wi_optset)
2578 {
2579 clear_winopt(&wip->wi_opt);
2580#ifdef FEAT_FOLDING
2581 deleteFoldRecurse(&wip->wi_folds);
2582#endif
2583 }
2584 }
2585 if (lnum != 0)
2586 {
2587 wip->wi_fpos.lnum = lnum;
2588 wip->wi_fpos.col = col;
2589 }
2590 if (copy_options)
2591 {
2592 /* Save the window-specific option values. */
2593 copy_winopt(&win->w_onebuf_opt, &wip->wi_opt);
2594#ifdef FEAT_FOLDING
2595 wip->wi_fold_manual = win->w_fold_manual;
2596 cloneFoldGrowArray(&win->w_folds, &wip->wi_folds);
2597#endif
2598 wip->wi_optset = TRUE;
2599 }
2600
2601 /* insert the entry in front of the list */
2602 wip->wi_next = buf->b_wininfo;
2603 buf->b_wininfo = wip;
2604 wip->wi_prev = NULL;
2605 if (wip->wi_next)
2606 wip->wi_next->wi_prev = wip;
2607
2608 return;
2609}
2610
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002611#ifdef FEAT_DIFF
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002612static int wininfo_other_tab_diff(wininfo_T *wip);
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002613
2614/*
2615 * Return TRUE when "wip" has 'diff' set and the diff is only for another tab
2616 * page. That's because a diff is local to a tab page.
2617 */
2618 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002619wininfo_other_tab_diff(wininfo_T *wip)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002620{
2621 win_T *wp;
2622
2623 if (wip->wi_opt.wo_diff)
2624 {
2625 for (wp = firstwin; wp != NULL; wp = wp->w_next)
2626 /* return FALSE when it's a window in the current tab page, thus
2627 * the buffer was in diff mode here */
2628 if (wip->wi_win == wp)
2629 return FALSE;
2630 return TRUE;
2631 }
2632 return FALSE;
2633}
2634#endif
2635
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636/*
2637 * Find info for the current window in buffer "buf".
2638 * If not found, return the info for the most recently used window.
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002639 * When "skip_diff_buffer" is TRUE avoid windows with 'diff' set that is in
2640 * another tab page.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641 * Returns NULL when there isn't any info.
2642 */
2643 static wininfo_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002644find_wininfo(
2645 buf_T *buf,
2646 int skip_diff_buffer UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647{
2648 wininfo_T *wip;
2649
2650 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002651 if (wip->wi_win == curwin
2652#ifdef FEAT_DIFF
2653 && (!skip_diff_buffer || !wininfo_other_tab_diff(wip))
2654#endif
2655 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656 break;
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002657
2658 /* If no wininfo for curwin, use the first in the list (that doesn't have
2659 * 'diff' set and is in another tab page). */
2660 if (wip == NULL)
2661 {
2662#ifdef FEAT_DIFF
2663 if (skip_diff_buffer)
2664 {
2665 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
2666 if (!wininfo_other_tab_diff(wip))
2667 break;
2668 }
2669 else
2670#endif
2671 wip = buf->b_wininfo;
2672 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673 return wip;
2674}
2675
2676/*
2677 * Reset the local window options to the values last used in this window.
2678 * If the buffer wasn't used in this window before, use the values from
2679 * the most recently used window. If the values were never set, use the
2680 * global values for the window.
2681 */
2682 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002683get_winopts(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684{
2685 wininfo_T *wip;
2686
2687 clear_winopt(&curwin->w_onebuf_opt);
2688#ifdef FEAT_FOLDING
2689 clearFolding(curwin);
2690#endif
2691
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002692 wip = find_wininfo(buf, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 if (wip != NULL && wip->wi_optset)
2694 {
2695 copy_winopt(&wip->wi_opt, &curwin->w_onebuf_opt);
2696#ifdef FEAT_FOLDING
2697 curwin->w_fold_manual = wip->wi_fold_manual;
2698 curwin->w_foldinvalid = TRUE;
2699 cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds);
2700#endif
2701 }
2702 else
2703 copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
2704
2705#ifdef FEAT_FOLDING
2706 /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */
2707 if (p_fdls >= 0)
2708 curwin->w_p_fdl = p_fdls;
2709#endif
Bram Moolenaar1701e402011-05-05 17:32:44 +02002710#ifdef FEAT_SYN_HL
2711 check_colorcolumn(curwin);
2712#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713}
2714
2715/*
2716 * Find the position (lnum and col) for the buffer 'buf' for the current
2717 * window.
2718 * Returns a pointer to no_position if no position is found.
2719 */
2720 pos_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002721buflist_findfpos(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722{
2723 wininfo_T *wip;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00002724 static pos_T no_position = INIT_POS_T(1, 0, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002726 wip = find_wininfo(buf, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 if (wip != NULL)
2728 return &(wip->wi_fpos);
2729 else
2730 return &no_position;
2731}
2732
2733/*
2734 * Find the lnum for the buffer 'buf' for the current window.
2735 */
2736 linenr_T
Bram Moolenaar7454a062016-01-30 15:14:10 +01002737buflist_findlnum(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002738{
2739 return buflist_findfpos(buf)->lnum;
2740}
2741
2742#if defined(FEAT_LISTCMDS) || defined(PROTO)
2743/*
2744 * List all know file names (for :files and :buffers command).
2745 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002747buflist_list(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748{
2749 buf_T *buf;
2750 int len;
2751 int i;
2752
2753 for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
2754 {
2755 /* skip unlisted buffers, unless ! was used */
Bram Moolenaard51cb702015-07-21 15:03:06 +02002756 if ((!buf->b_p_bl && !eap->forceit && !vim_strchr(eap->arg, 'u'))
2757 || (vim_strchr(eap->arg, 'u') && buf->b_p_bl)
2758 || (vim_strchr(eap->arg, '+')
2759 && ((buf->b_flags & BF_READERR) || !bufIsChanged(buf)))
2760 || (vim_strchr(eap->arg, 'a')
2761 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows == 0))
2762 || (vim_strchr(eap->arg, 'h')
2763 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows != 0))
2764 || (vim_strchr(eap->arg, '-') && buf->b_p_ma)
2765 || (vim_strchr(eap->arg, '=') && !buf->b_p_ro)
2766 || (vim_strchr(eap->arg, 'x') && !(buf->b_flags & BF_READERR))
2767 || (vim_strchr(eap->arg, '%') && buf != curbuf)
2768 || (vim_strchr(eap->arg, '#')
2769 && (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002770 continue;
2771 msg_putchar('\n');
2772 if (buf_spname(buf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002773 vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002774 else
2775 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
2776
Bram Moolenaar50cde822005-06-05 21:54:54 +00002777 len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002778 buf->b_fnum,
2779 buf->b_p_bl ? ' ' : 'u',
2780 buf == curbuf ? '%' :
2781 (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
2782 buf->b_ml.ml_mfp == NULL ? ' ' :
2783 (buf->b_nwindows == 0 ? 'h' : 'a'),
2784 !buf->b_p_ma ? '-' : (buf->b_p_ro ? '=' : ' '),
2785 (buf->b_flags & BF_READERR) ? 'x'
Bram Moolenaar51485f02005-06-04 21:55:20 +00002786 : (bufIsChanged(buf) ? '+' : ' '),
2787 NameBuff);
Bram Moolenaar507edf62016-01-10 20:54:17 +01002788 if (len > IOSIZE - 20)
2789 len = IOSIZE - 20;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002790
2791 /* put "line 999" in column 40 or after the file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792 i = 40 - vim_strsize(IObuff);
2793 do
2794 {
2795 IObuff[len++] = ' ';
2796 } while (--i > 0 && len < IOSIZE - 18);
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00002797 vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
2798 _("line %ld"), buf == curbuf ? curwin->w_cursor.lnum
Bram Moolenaar9c13b352005-05-19 20:53:52 +00002799 : (long)buflist_findlnum(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002800 msg_outtrans(IObuff);
2801 out_flush(); /* output one line at a time */
2802 ui_breakcheck();
2803 }
2804}
2805#endif
2806
2807/*
2808 * Get file name and line number for file 'fnum'.
2809 * Used by DoOneCmd() for translating '%' and '#'.
2810 * Used by insert_reg() and cmdline_paste() for '#' register.
2811 * Return FAIL if not found, OK for success.
2812 */
2813 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002814buflist_name_nr(
2815 int fnum,
2816 char_u **fname,
2817 linenr_T *lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002818{
2819 buf_T *buf;
2820
2821 buf = buflist_findnr(fnum);
2822 if (buf == NULL || buf->b_fname == NULL)
2823 return FAIL;
2824
2825 *fname = buf->b_fname;
2826 *lnum = buflist_findlnum(buf);
2827
2828 return OK;
2829}
2830
2831/*
2832 * Set the file name for "buf"' to 'ffname', short file name to 'sfname'.
2833 * The file name with the full path is also remembered, for when :cd is used.
2834 * Returns FAIL for failure (file name already in use by other buffer)
2835 * OK otherwise.
2836 */
2837 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002838setfname(
2839 buf_T *buf,
2840 char_u *ffname,
2841 char_u *sfname,
2842 int message) /* give message when buffer already exists */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002843{
Bram Moolenaar81695252004-12-29 20:58:21 +00002844 buf_T *obuf = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002845#ifdef UNIX
2846 struct stat st;
2847#endif
2848
2849 if (ffname == NULL || *ffname == NUL)
2850 {
2851 /* Removing the name. */
2852 vim_free(buf->b_ffname);
2853 vim_free(buf->b_sfname);
2854 buf->b_ffname = NULL;
2855 buf->b_sfname = NULL;
2856#ifdef UNIX
2857 st.st_dev = (dev_T)-1;
2858#endif
2859 }
2860 else
2861 {
2862 fname_expand(buf, &ffname, &sfname); /* will allocate ffname */
2863 if (ffname == NULL) /* out of memory */
2864 return FAIL;
2865
2866 /*
2867 * if the file name is already used in another buffer:
2868 * - if the buffer is loaded, fail
2869 * - if the buffer is not loaded, delete it from the list
2870 */
2871#ifdef UNIX
2872 if (mch_stat((char *)ffname, &st) < 0)
2873 st.st_dev = (dev_T)-1;
Bram Moolenaar81695252004-12-29 20:58:21 +00002874#endif
2875 if (!(buf->b_flags & BF_DUMMY))
2876#ifdef UNIX
2877 obuf = buflist_findname_stat(ffname, &st);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002878#else
Bram Moolenaar81695252004-12-29 20:58:21 +00002879 obuf = buflist_findname(ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002880#endif
2881 if (obuf != NULL && obuf != buf)
2882 {
2883 if (obuf->b_ml.ml_mfp != NULL) /* it's loaded, fail */
2884 {
2885 if (message)
2886 EMSG(_("E95: Buffer with this name already exists"));
2887 vim_free(ffname);
2888 return FAIL;
2889 }
Bram Moolenaar42ec6562012-02-22 14:58:37 +01002890 /* delete from the list */
2891 close_buffer(NULL, obuf, DOBUF_WIPE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892 }
2893 sfname = vim_strsave(sfname);
2894 if (ffname == NULL || sfname == NULL)
2895 {
2896 vim_free(sfname);
2897 vim_free(ffname);
2898 return FAIL;
2899 }
2900#ifdef USE_FNAME_CASE
2901# ifdef USE_LONG_FNAME
2902 if (USE_LONG_FNAME)
2903# endif
2904 fname_case(sfname, 0); /* set correct case for short file name */
2905#endif
2906 vim_free(buf->b_ffname);
2907 vim_free(buf->b_sfname);
2908 buf->b_ffname = ffname;
2909 buf->b_sfname = sfname;
2910 }
2911 buf->b_fname = buf->b_sfname;
2912#ifdef UNIX
2913 if (st.st_dev == (dev_T)-1)
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00002914 buf->b_dev_valid = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915 else
2916 {
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00002917 buf->b_dev_valid = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918 buf->b_dev = st.st_dev;
2919 buf->b_ino = st.st_ino;
2920 }
2921#endif
2922
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 buf->b_shortname = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924
2925 buf_name_changed(buf);
2926 return OK;
2927}
2928
2929/*
Bram Moolenaar86b68352004-12-27 21:59:20 +00002930 * Crude way of changing the name of a buffer. Use with care!
2931 * The name should be relative to the current directory.
2932 */
2933 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002934buf_set_name(int fnum, char_u *name)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002935{
2936 buf_T *buf;
2937
2938 buf = buflist_findnr(fnum);
2939 if (buf != NULL)
2940 {
2941 vim_free(buf->b_sfname);
2942 vim_free(buf->b_ffname);
Bram Moolenaarf193fff2006-04-27 00:02:13 +00002943 buf->b_ffname = vim_strsave(name);
2944 buf->b_sfname = NULL;
2945 /* Allocate ffname and expand into full path. Also resolves .lnk
2946 * files on Win32. */
2947 fname_expand(buf, &buf->b_ffname, &buf->b_sfname);
Bram Moolenaar86b68352004-12-27 21:59:20 +00002948 buf->b_fname = buf->b_sfname;
2949 }
2950}
2951
2952/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953 * Take care of what needs to be done when the name of buffer "buf" has
2954 * changed.
2955 */
2956 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002957buf_name_changed(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958{
2959 /*
2960 * If the file name changed, also change the name of the swapfile
2961 */
2962 if (buf->b_ml.ml_mfp != NULL)
2963 ml_setname(buf);
2964
2965 if (curwin->w_buffer == buf)
2966 check_arg_idx(curwin); /* check file name for arg list */
2967#ifdef FEAT_TITLE
2968 maketitle(); /* set window title */
2969#endif
2970#ifdef FEAT_WINDOWS
2971 status_redraw_all(); /* status lines need to be redrawn */
2972#endif
2973 fmarks_check_names(buf); /* check named file marks */
2974 ml_timestamp(buf); /* reset timestamp */
2975}
2976
2977/*
2978 * set alternate file name for current window
2979 *
2980 * Used by do_one_cmd(), do_write() and do_ecmd().
2981 * Return the buffer.
2982 */
2983 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002984setaltfname(
2985 char_u *ffname,
2986 char_u *sfname,
2987 linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002988{
2989 buf_T *buf;
2990
2991 /* Create a buffer. 'buflisted' is not set if it's a new buffer */
2992 buf = buflist_new(ffname, sfname, lnum, 0);
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002993 if (buf != NULL && !cmdmod.keepalt)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002994 curwin->w_alt_fnum = buf->b_fnum;
2995 return buf;
2996}
2997
2998/*
2999 * Get alternate file name for current window.
3000 * Return NULL if there isn't any, and give error message if requested.
3001 */
3002 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01003003getaltfname(
3004 int errmsg) /* give error message */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005{
3006 char_u *fname;
3007 linenr_T dummy;
3008
3009 if (buflist_name_nr(0, &fname, &dummy) == FAIL)
3010 {
3011 if (errmsg)
3012 EMSG(_(e_noalt));
3013 return NULL;
3014 }
3015 return fname;
3016}
3017
3018/*
3019 * Add a file name to the buflist and return its number.
3020 * Uses same flags as buflist_new(), except BLN_DUMMY.
3021 *
3022 * used by qf_init(), main() and doarglist()
3023 */
3024 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003025buflist_add(char_u *fname, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026{
3027 buf_T *buf;
3028
3029 buf = buflist_new(fname, NULL, (linenr_T)0, flags);
3030 if (buf != NULL)
3031 return buf->b_fnum;
3032 return 0;
3033}
3034
3035#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3036/*
3037 * Adjust slashes in file names. Called after 'shellslash' was set.
3038 */
3039 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003040buflist_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041{
3042 buf_T *bp;
3043
3044 for (bp = firstbuf; bp != NULL; bp = bp->b_next)
3045 {
3046 if (bp->b_ffname != NULL)
3047 slash_adjust(bp->b_ffname);
3048 if (bp->b_sfname != NULL)
3049 slash_adjust(bp->b_sfname);
3050 }
3051}
3052#endif
3053
3054/*
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003055 * Set alternate cursor position for the current buffer and window "win".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056 * Also save the local window option values.
3057 */
3058 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003059buflist_altfpos(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060{
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003061 buflist_setfpos(curbuf, win, win->w_cursor.lnum, win->w_cursor.col, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062}
3063
3064/*
3065 * Return TRUE if 'ffname' is not the same file as current file.
3066 * Fname must have a full path (expanded by mch_FullName()).
3067 */
3068 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003069otherfile(char_u *ffname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070{
3071 return otherfile_buf(curbuf, ffname
3072#ifdef UNIX
3073 , NULL
3074#endif
3075 );
3076}
3077
3078 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003079otherfile_buf(
3080 buf_T *buf,
3081 char_u *ffname
Bram Moolenaar071d4272004-06-13 20:20:40 +00003082#ifdef UNIX
Bram Moolenaar7454a062016-01-30 15:14:10 +01003083 , struct stat *stp
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084#endif
Bram Moolenaar7454a062016-01-30 15:14:10 +01003085 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086{
3087 /* no name is different */
3088 if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL)
3089 return TRUE;
3090 if (fnamecmp(ffname, buf->b_ffname) == 0)
3091 return FALSE;
3092#ifdef UNIX
3093 {
3094 struct stat st;
3095
3096 /* If no struct stat given, get it now */
3097 if (stp == NULL)
3098 {
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003099 if (!buf->b_dev_valid || mch_stat((char *)ffname, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100 st.st_dev = (dev_T)-1;
3101 stp = &st;
3102 }
3103 /* Use dev/ino to check if the files are the same, even when the names
3104 * are different (possible with links). Still need to compare the
3105 * name above, for when the file doesn't exist yet.
3106 * Problem: The dev/ino changes when a file is deleted (and created
3107 * again) and remains the same when renamed/moved. We don't want to
3108 * mch_stat() each buffer each time, that would be too slow. Get the
3109 * dev/ino again when they appear to match, but not when they appear
3110 * to be different: Could skip a buffer when it's actually the same
3111 * file. */
3112 if (buf_same_ino(buf, stp))
3113 {
3114 buf_setino(buf);
3115 if (buf_same_ino(buf, stp))
3116 return FALSE;
3117 }
3118 }
3119#endif
3120 return TRUE;
3121}
3122
3123#if defined(UNIX) || defined(PROTO)
3124/*
3125 * Set inode and device number for a buffer.
3126 * Must always be called when b_fname is changed!.
3127 */
3128 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003129buf_setino(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130{
3131 struct stat st;
3132
3133 if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0)
3134 {
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003135 buf->b_dev_valid = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 buf->b_dev = st.st_dev;
3137 buf->b_ino = st.st_ino;
3138 }
3139 else
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003140 buf->b_dev_valid = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141}
3142
3143/*
3144 * Return TRUE if dev/ino in buffer "buf" matches with "stp".
3145 */
3146 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003147buf_same_ino(
3148 buf_T *buf,
3149 struct stat *stp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150{
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003151 return (buf->b_dev_valid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152 && stp->st_dev == buf->b_dev
3153 && stp->st_ino == buf->b_ino);
3154}
3155#endif
3156
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003157/*
3158 * Print info about the current buffer.
3159 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003160 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003161fileinfo(
3162 int fullname, /* when non-zero print full path */
3163 int shorthelp,
3164 int dont_truncate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165{
3166 char_u *name;
3167 int n;
3168 char_u *p;
3169 char_u *buffer;
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003170 size_t len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003171
3172 buffer = alloc(IOSIZE);
3173 if (buffer == NULL)
3174 return;
3175
3176 if (fullname > 1) /* 2 CTRL-G: include buffer number */
3177 {
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003178 vim_snprintf((char *)buffer, IOSIZE, "buf %d: ", curbuf->b_fnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179 p = buffer + STRLEN(buffer);
3180 }
3181 else
3182 p = buffer;
3183
3184 *p++ = '"';
3185 if (buf_spname(curbuf) != NULL)
Bram Moolenaarec3cfeb2012-10-03 17:12:47 +02003186 vim_strncpy(p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187 else
3188 {
3189 if (!fullname && curbuf->b_fname != NULL)
3190 name = curbuf->b_fname;
3191 else
3192 name = curbuf->b_ffname;
3193 home_replace(shorthelp ? curbuf : NULL, name, p,
3194 (int)(IOSIZE - (p - buffer)), TRUE);
3195 }
3196
Bram Moolenaara800b422010-06-27 01:15:55 +02003197 vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198 curbufIsChanged() ? (shortmess(SHM_MOD)
3199 ? " [+]" : _(" [Modified]")) : " ",
3200 (curbuf->b_flags & BF_NOTEDITED)
3201#ifdef FEAT_QUICKFIX
3202 && !bt_dontwrite(curbuf)
3203#endif
3204 ? _("[Not edited]") : "",
3205 (curbuf->b_flags & BF_NEW)
3206#ifdef FEAT_QUICKFIX
3207 && !bt_dontwrite(curbuf)
3208#endif
3209 ? _("[New file]") : "",
3210 (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "",
Bram Moolenaar23584032013-06-07 20:17:11 +02003211 curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]")
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 : _("[readonly]")) : "",
3213 (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK)
3214 || curbuf->b_p_ro) ?
3215 " " : "");
3216 /* With 32 bit longs and more than 21,474,836 lines multiplying by 100
3217 * causes an overflow, thus for large numbers divide instead. */
3218 if (curwin->w_cursor.lnum > 1000000L)
3219 n = (int)(((long)curwin->w_cursor.lnum) /
3220 ((long)curbuf->b_ml.ml_line_count / 100L));
3221 else
3222 n = (int)(((long)curwin->w_cursor.lnum * 100L) /
3223 (long)curbuf->b_ml.ml_line_count);
3224 if (curbuf->b_ml.ml_flags & ML_EMPTY)
3225 {
Bram Moolenaara800b422010-06-27 01:15:55 +02003226 vim_snprintf_add((char *)buffer, IOSIZE, "%s", _(no_lines_msg));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 }
3228#ifdef FEAT_CMDL_INFO
3229 else if (p_ru)
3230 {
3231 /* Current line and column are already on the screen -- webb */
3232 if (curbuf->b_ml.ml_line_count == 1)
Bram Moolenaara800b422010-06-27 01:15:55 +02003233 vim_snprintf_add((char *)buffer, IOSIZE, _("1 line --%d%%--"), n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003234 else
Bram Moolenaara800b422010-06-27 01:15:55 +02003235 vim_snprintf_add((char *)buffer, IOSIZE, _("%ld lines --%d%%--"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236 (long)curbuf->b_ml.ml_line_count, n);
3237 }
3238#endif
3239 else
3240 {
Bram Moolenaara800b422010-06-27 01:15:55 +02003241 vim_snprintf_add((char *)buffer, IOSIZE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242 _("line %ld of %ld --%d%%-- col "),
3243 (long)curwin->w_cursor.lnum,
3244 (long)curbuf->b_ml.ml_line_count,
3245 n);
3246 validate_virtcol();
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003247 len = STRLEN(buffer);
3248 col_print(buffer + len, IOSIZE - len,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249 (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
3250 }
3251
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003252 (void)append_arg_number(curwin, buffer, IOSIZE, !shortmess(SHM_FILE));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253
3254 if (dont_truncate)
3255 {
3256 /* Temporarily set msg_scroll to avoid the message being truncated.
3257 * First call msg_start() to get the message in the right place. */
3258 msg_start();
3259 n = msg_scroll;
3260 msg_scroll = TRUE;
3261 msg(buffer);
3262 msg_scroll = n;
3263 }
3264 else
3265 {
3266 p = msg_trunc_attr(buffer, FALSE, 0);
3267 if (restart_edit != 0 || (msg_scrolled && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268 /* Need to repeat the message after redrawing when:
3269 * - When restart_edit is set (otherwise there will be a delay
3270 * before redrawing).
3271 * - When the screen was scrolled but there is no wait-return
3272 * prompt. */
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003273 set_keep_msg(p, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003274 }
3275
3276 vim_free(buffer);
3277}
3278
3279 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003280col_print(
3281 char_u *buf,
3282 size_t buflen,
3283 int col,
3284 int vcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285{
3286 if (col == vcol)
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003287 vim_snprintf((char *)buf, buflen, "%d", col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 else
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003289 vim_snprintf((char *)buf, buflen, "%d-%d", col, vcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290}
3291
3292#if defined(FEAT_TITLE) || defined(PROTO)
3293/*
3294 * put file name in title bar of window and in icon title
3295 */
3296
3297static char_u *lasttitle = NULL;
3298static char_u *lasticon = NULL;
3299
3300 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003301maketitle(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302{
3303 char_u *p;
3304 char_u *t_str = NULL;
3305 char_u *i_name;
3306 char_u *i_str = NULL;
3307 int maxlen = 0;
3308 int len;
3309 int mustset;
3310 char_u buf[IOSIZE];
3311 int off;
3312
3313 if (!redrawing())
3314 {
3315 /* Postpone updating the title when 'lazyredraw' is set. */
3316 need_maketitle = TRUE;
3317 return;
3318 }
3319
3320 need_maketitle = FALSE;
Bram Moolenaarbed7bec2010-07-25 13:42:29 +02003321 if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322 return;
3323
3324 if (p_title)
3325 {
3326 if (p_titlelen > 0)
3327 {
3328 maxlen = p_titlelen * Columns / 100;
3329 if (maxlen < 10)
3330 maxlen = 10;
3331 }
3332
3333 t_str = buf;
3334 if (*p_titlestring != NUL)
3335 {
3336#ifdef FEAT_STL_OPT
Bram Moolenaard3667a22006-03-16 21:35:52 +00003337 if (stl_syntax & STL_IN_TITLE)
3338 {
3339 int use_sandbox = FALSE;
3340 int save_called_emsg = called_emsg;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003341
3342# ifdef FEAT_EVAL
Bram Moolenaard3667a22006-03-16 21:35:52 +00003343 use_sandbox = was_set_insecurely((char_u *)"titlestring", 0);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003344# endif
Bram Moolenaard3667a22006-03-16 21:35:52 +00003345 called_emsg = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346 build_stl_str_hl(curwin, t_str, sizeof(buf),
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003347 p_titlestring, use_sandbox,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003348 0, maxlen, NULL, NULL);
Bram Moolenaard3667a22006-03-16 21:35:52 +00003349 if (called_emsg)
3350 set_string_option_direct((char_u *)"titlestring", -1,
3351 (char_u *)"", OPT_FREE, SID_ERROR);
3352 called_emsg |= save_called_emsg;
3353 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354 else
3355#endif
3356 t_str = p_titlestring;
3357 }
3358 else
3359 {
3360 /* format: "fname + (path) (1 of 2) - VIM" */
3361
Bram Moolenaar2c666692012-09-05 13:30:40 +02003362#define SPACE_FOR_FNAME (IOSIZE - 100)
3363#define SPACE_FOR_DIR (IOSIZE - 20)
3364#define SPACE_FOR_ARGNR (IOSIZE - 10) /* at least room for " - VIM" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003365 if (curbuf->b_fname == NULL)
Bram Moolenaar2c666692012-09-05 13:30:40 +02003366 vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003367 else
3368 {
3369 p = transstr(gettail(curbuf->b_fname));
Bram Moolenaar2c666692012-09-05 13:30:40 +02003370 vim_strncpy(buf, p, SPACE_FOR_FNAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371 vim_free(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 }
3373
3374 switch (bufIsChanged(curbuf)
3375 + (curbuf->b_p_ro * 2)
3376 + (!curbuf->b_p_ma * 4))
3377 {
3378 case 1: STRCAT(buf, " +"); break;
3379 case 2: STRCAT(buf, " ="); break;
3380 case 3: STRCAT(buf, " =+"); break;
3381 case 4:
3382 case 6: STRCAT(buf, " -"); break;
3383 case 5:
3384 case 7: STRCAT(buf, " -+"); break;
3385 }
3386
3387 if (curbuf->b_fname != NULL)
3388 {
3389 /* Get path of file, replace home dir with ~ */
3390 off = (int)STRLEN(buf);
3391 buf[off++] = ' ';
3392 buf[off++] = '(';
3393 home_replace(curbuf, curbuf->b_ffname,
Bram Moolenaar2c666692012-09-05 13:30:40 +02003394 buf + off, SPACE_FOR_DIR - off, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395#ifdef BACKSLASH_IN_FILENAME
3396 /* avoid "c:/name" to be reduced to "c" */
3397 if (isalpha(buf[off]) && buf[off + 1] == ':')
3398 off += 2;
3399#endif
3400 /* remove the file name */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003401 p = gettail_sep(buf + off);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402 if (p == buf + off)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003403 /* must be a help buffer */
Bram Moolenaarb6356332005-07-18 21:40:44 +00003404 vim_strncpy(buf + off, (char_u *)_("help"),
Bram Moolenaar2c666692012-09-05 13:30:40 +02003405 (size_t)(SPACE_FOR_DIR - off - 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003407 *p = NUL;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003408
Bram Moolenaar2c666692012-09-05 13:30:40 +02003409 /* Translate unprintable chars and concatenate. Keep some
3410 * room for the server name. When there is no room (very long
3411 * file name) use (...). */
3412 if (off < SPACE_FOR_DIR)
3413 {
3414 p = transstr(buf + off);
3415 vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off));
3416 vim_free(p);
3417 }
3418 else
3419 {
3420 vim_strncpy(buf + off, (char_u *)"...",
3421 (size_t)(SPACE_FOR_ARGNR - off));
3422 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003423 STRCAT(buf, ")");
3424 }
3425
Bram Moolenaar2c666692012-09-05 13:30:40 +02003426 append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427
3428#if defined(FEAT_CLIENTSERVER)
3429 if (serverName != NULL)
3430 {
3431 STRCAT(buf, " - ");
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02003432 vim_strcat(buf, serverName, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433 }
3434 else
3435#endif
3436 STRCAT(buf, " - VIM");
3437
3438 if (maxlen > 0)
3439 {
3440 /* make it shorter by removing a bit in the middle */
Bram Moolenaarf31b7642012-01-20 20:44:43 +01003441 if (vim_strsize(buf) > maxlen)
3442 trunc_string(buf, buf, maxlen, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003443 }
3444 }
3445 }
3446 mustset = ti_change(t_str, &lasttitle);
3447
3448 if (p_icon)
3449 {
3450 i_str = buf;
3451 if (*p_iconstring != NUL)
3452 {
3453#ifdef FEAT_STL_OPT
Bram Moolenaard3667a22006-03-16 21:35:52 +00003454 if (stl_syntax & STL_IN_ICON)
3455 {
3456 int use_sandbox = FALSE;
3457 int save_called_emsg = called_emsg;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003458
3459# ifdef FEAT_EVAL
Bram Moolenaard3667a22006-03-16 21:35:52 +00003460 use_sandbox = was_set_insecurely((char_u *)"iconstring", 0);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003461# endif
Bram Moolenaard3667a22006-03-16 21:35:52 +00003462 called_emsg = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463 build_stl_str_hl(curwin, i_str, sizeof(buf),
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003464 p_iconstring, use_sandbox,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003465 0, 0, NULL, NULL);
Bram Moolenaard3667a22006-03-16 21:35:52 +00003466 if (called_emsg)
3467 set_string_option_direct((char_u *)"iconstring", -1,
3468 (char_u *)"", OPT_FREE, SID_ERROR);
3469 called_emsg |= save_called_emsg;
3470 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 else
3472#endif
3473 i_str = p_iconstring;
3474 }
3475 else
3476 {
3477 if (buf_spname(curbuf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02003478 i_name = buf_spname(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003479 else /* use file name only in icon */
3480 i_name = gettail(curbuf->b_ffname);
3481 *i_str = NUL;
3482 /* Truncate name at 100 bytes. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003483 len = (int)STRLEN(i_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 if (len > 100)
3485 {
3486 len -= 100;
3487#ifdef FEAT_MBYTE
3488 if (has_mbyte)
3489 len += (*mb_tail_off)(i_name, i_name + len) + 1;
3490#endif
3491 i_name += len;
3492 }
3493 STRCPY(i_str, i_name);
3494 trans_characters(i_str, IOSIZE);
3495 }
3496 }
3497
3498 mustset |= ti_change(i_str, &lasticon);
3499
3500 if (mustset)
3501 resettitle();
3502}
3503
3504/*
3505 * Used for title and icon: Check if "str" differs from "*last". Set "*last"
3506 * from "str" if it does.
3507 * Return TRUE when "*last" changed.
3508 */
3509 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003510ti_change(char_u *str, char_u **last)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511{
3512 if ((str == NULL) != (*last == NULL)
3513 || (str != NULL && *last != NULL && STRCMP(str, *last) != 0))
3514 {
3515 vim_free(*last);
3516 if (str == NULL)
3517 *last = NULL;
3518 else
3519 *last = vim_strsave(str);
3520 return TRUE;
3521 }
3522 return FALSE;
3523}
3524
3525/*
3526 * Put current window title back (used after calling a shell)
3527 */
3528 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003529resettitle(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530{
3531 mch_settitle(lasttitle, lasticon);
3532}
Bram Moolenaarea408852005-06-25 22:49:46 +00003533
3534# if defined(EXITFREE) || defined(PROTO)
3535 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003536free_titles(void)
Bram Moolenaarea408852005-06-25 22:49:46 +00003537{
3538 vim_free(lasttitle);
3539 vim_free(lasticon);
3540}
3541# endif
3542
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543#endif /* FEAT_TITLE */
3544
Bram Moolenaarba6c0522006-02-25 21:45:02 +00003545#if defined(FEAT_STL_OPT) || defined(FEAT_GUI_TABLINE) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003547 * Build a string from the status line items in "fmt".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548 * Return length of string in screen cells.
3549 *
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003550 * Normally works for window "wp", except when working for 'tabline' then it
3551 * is "curwin".
3552 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553 * Items are drawn interspersed with the text that surrounds it
3554 * Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation
3555 * Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional
3556 *
3557 * If maxwidth is not zero, the string will be filled at any middle marker
3558 * or truncated if too long, fillchar is used for all whitespace.
3559 */
3560 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003561build_stl_str_hl(
3562 win_T *wp,
3563 char_u *out, /* buffer to write into != NameBuff */
3564 size_t outlen, /* length of out[] */
3565 char_u *fmt,
3566 int use_sandbox UNUSED, /* "fmt" was set insecurely, use sandbox */
3567 int fillchar,
3568 int maxwidth,
3569 struct stl_hlrec *hltab, /* return: HL attributes (can be NULL) */
3570 struct stl_hlrec *tabtab) /* return: tab page nrs (can be NULL) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571{
3572 char_u *p;
3573 char_u *s;
3574 char_u *t;
Bram Moolenaar567199b2013-04-24 16:52:36 +02003575 int byteval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003576#ifdef FEAT_EVAL
3577 win_T *o_curwin;
3578 buf_T *o_curbuf;
3579#endif
3580 int empty_line;
3581 colnr_T virtcol;
3582 long l;
3583 long n;
3584 int prevchar_isflag;
3585 int prevchar_isitem;
3586 int itemisflag;
3587 int fillable;
3588 char_u *str;
3589 long num;
3590 int width;
3591 int itemcnt;
3592 int curitem;
3593 int groupitem[STL_MAX_ITEM];
3594 int groupdepth;
3595 struct stl_item
3596 {
3597 char_u *start;
3598 int minwid;
3599 int maxwid;
3600 enum
3601 {
3602 Normal,
3603 Empty,
3604 Group,
3605 Middle,
3606 Highlight,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003607 TabPage,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608 Trunc
3609 } type;
3610 } item[STL_MAX_ITEM];
3611 int minwid;
3612 int maxwid;
3613 int zeropad;
3614 char_u base;
3615 char_u opt;
3616#define TMPLEN 70
3617 char_u tmp[TMPLEN];
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003618 char_u *usefmt = fmt;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003619 struct stl_hlrec *sp;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003620
3621#ifdef FEAT_EVAL
3622 /*
3623 * When the format starts with "%!" then evaluate it as an expression and
3624 * use the result as the actual format string.
3625 */
3626 if (fmt[0] == '%' && fmt[1] == '!')
3627 {
3628 usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox);
3629 if (usefmt == NULL)
Bram Moolenaar4100af72006-08-29 14:48:14 +00003630 usefmt = fmt;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003631 }
3632#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003633
3634 if (fillchar == 0)
3635 fillchar = ' ';
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003636#ifdef FEAT_MBYTE
3637 /* Can't handle a multi-byte fill character yet. */
3638 else if (mb_char2len(fillchar) > 1)
3639 fillchar = '-';
3640#endif
3641
Bram Moolenaar567199b2013-04-24 16:52:36 +02003642 /* Get line & check if empty (cursorpos will show "0-1"). Note that
3643 * p will become invalid when getting another buffer line. */
3644 p = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE);
3645 empty_line = (*p == NUL);
3646
3647 /* Get the byte value now, in case we need it below. This is more
3648 * efficient than making a copy of the line. */
3649 if (wp->w_cursor.col > (colnr_T)STRLEN(p))
3650 byteval = 0;
3651 else
3652#ifdef FEAT_MBYTE
3653 byteval = (*mb_ptr2char)(p + wp->w_cursor.col);
3654#else
3655 byteval = p[wp->w_cursor.col];
3656#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003657
3658 groupdepth = 0;
3659 p = out;
3660 curitem = 0;
3661 prevchar_isflag = TRUE;
3662 prevchar_isitem = FALSE;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003663 for (s = usefmt; *s; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003664 {
Bram Moolenaarb75d09d2011-02-15 14:24:46 +01003665 if (curitem == STL_MAX_ITEM)
3666 {
3667 /* There are too many items. Add the error code to the statusline
3668 * to give the user a hint about what went wrong. */
3669 if (p + 6 < out + outlen)
3670 {
3671 mch_memmove(p, " E541", (size_t)5);
3672 p += 5;
3673 }
3674 break;
3675 }
3676
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677 if (*s != NUL && *s != '%')
3678 prevchar_isflag = prevchar_isitem = FALSE;
3679
3680 /*
3681 * Handle up to the next '%' or the end.
3682 */
3683 while (*s != NUL && *s != '%' && p + 1 < out + outlen)
3684 *p++ = *s++;
3685 if (*s == NUL || p + 1 >= out + outlen)
3686 break;
3687
3688 /*
3689 * Handle one '%' item.
3690 */
3691 s++;
Bram Moolenaar1d87f512011-02-01 21:55:01 +01003692 if (*s == NUL) /* ignore trailing % */
3693 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003694 if (*s == '%')
3695 {
3696 if (p + 1 >= out + outlen)
3697 break;
3698 *p++ = *s++;
3699 prevchar_isflag = prevchar_isitem = FALSE;
3700 continue;
3701 }
3702 if (*s == STL_MIDDLEMARK)
3703 {
3704 s++;
3705 if (groupdepth > 0)
3706 continue;
3707 item[curitem].type = Middle;
3708 item[curitem++].start = p;
3709 continue;
3710 }
3711 if (*s == STL_TRUNCMARK)
3712 {
3713 s++;
3714 item[curitem].type = Trunc;
3715 item[curitem++].start = p;
3716 continue;
3717 }
3718 if (*s == ')')
3719 {
3720 s++;
3721 if (groupdepth < 1)
3722 continue;
3723 groupdepth--;
3724
3725 t = item[groupitem[groupdepth]].start;
3726 *p = NUL;
3727 l = vim_strsize(t);
3728 if (curitem > groupitem[groupdepth] + 1
3729 && item[groupitem[groupdepth]].minwid == 0)
3730 {
3731 /* remove group if all items are empty */
3732 for (n = groupitem[groupdepth] + 1; n < curitem; n++)
Bram Moolenaaraf6e36f2016-03-08 12:56:33 +01003733 if (item[n].type == Normal || item[n].type == Highlight)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734 break;
3735 if (n == curitem)
3736 {
3737 p = t;
3738 l = 0;
3739 }
3740 }
3741 if (l > item[groupitem[groupdepth]].maxwid)
3742 {
3743 /* truncate, remove n bytes of text at the start */
3744#ifdef FEAT_MBYTE
3745 if (has_mbyte)
3746 {
3747 /* Find the first character that should be included. */
3748 n = 0;
3749 while (l >= item[groupitem[groupdepth]].maxwid)
3750 {
3751 l -= ptr2cells(t + n);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003752 n += (*mb_ptr2len)(t + n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753 }
3754 }
3755 else
3756#endif
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003757 n = (long)(p - t) - item[groupitem[groupdepth]].maxwid + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758
3759 *t = '<';
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003760 mch_memmove(t + 1, t + n, (size_t)(p - (t + n)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003761 p = p - n + 1;
3762#ifdef FEAT_MBYTE
3763 /* Fill up space left over by half a double-wide char. */
3764 while (++l < item[groupitem[groupdepth]].minwid)
3765 *p++ = fillchar;
3766#endif
3767
3768 /* correct the start of the items for the truncation */
3769 for (l = groupitem[groupdepth] + 1; l < curitem; l++)
3770 {
3771 item[l].start -= n;
3772 if (item[l].start < t)
3773 item[l].start = t;
3774 }
3775 }
3776 else if (abs(item[groupitem[groupdepth]].minwid) > l)
3777 {
3778 /* fill */
3779 n = item[groupitem[groupdepth]].minwid;
3780 if (n < 0)
3781 {
3782 /* fill by appending characters */
3783 n = 0 - n;
3784 while (l++ < n && p + 1 < out + outlen)
3785 *p++ = fillchar;
3786 }
3787 else
3788 {
3789 /* fill by inserting characters */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003790 mch_memmove(t + n - l, t, (size_t)(p - t));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003791 l = n - l;
3792 if (p + l >= out + outlen)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003793 l = (long)((out + outlen) - p - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 p += l;
3795 for (n = groupitem[groupdepth] + 1; n < curitem; n++)
3796 item[n].start += l;
3797 for ( ; l > 0; l--)
3798 *t++ = fillchar;
3799 }
3800 }
3801 continue;
3802 }
3803 minwid = 0;
3804 maxwid = 9999;
3805 zeropad = FALSE;
3806 l = 1;
3807 if (*s == '0')
3808 {
3809 s++;
3810 zeropad = TRUE;
3811 }
3812 if (*s == '-')
3813 {
3814 s++;
3815 l = -1;
3816 }
3817 if (VIM_ISDIGIT(*s))
3818 {
3819 minwid = (int)getdigits(&s);
3820 if (minwid < 0) /* overflow */
3821 minwid = 0;
3822 }
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003823 if (*s == STL_USER_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003824 {
3825 item[curitem].type = Highlight;
3826 item[curitem].start = p;
3827 item[curitem].minwid = minwid > 9 ? 1 : minwid;
3828 s++;
3829 curitem++;
3830 continue;
3831 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003832 if (*s == STL_TABPAGENR || *s == STL_TABCLOSENR)
3833 {
3834 if (*s == STL_TABCLOSENR)
3835 {
3836 if (minwid == 0)
3837 {
3838 /* %X ends the close label, go back to the previously
3839 * define tab label nr. */
3840 for (n = curitem - 1; n >= 0; --n)
3841 if (item[n].type == TabPage && item[n].minwid >= 0)
3842 {
3843 minwid = item[n].minwid;
3844 break;
3845 }
3846 }
3847 else
3848 /* close nrs are stored as negative values */
3849 minwid = - minwid;
3850 }
3851 item[curitem].type = TabPage;
3852 item[curitem].start = p;
3853 item[curitem].minwid = minwid;
3854 s++;
3855 curitem++;
3856 continue;
3857 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858 if (*s == '.')
3859 {
3860 s++;
3861 if (VIM_ISDIGIT(*s))
3862 {
3863 maxwid = (int)getdigits(&s);
3864 if (maxwid <= 0) /* overflow */
3865 maxwid = 50;
3866 }
3867 }
3868 minwid = (minwid > 50 ? 50 : minwid) * l;
3869 if (*s == '(')
3870 {
3871 groupitem[groupdepth++] = curitem;
3872 item[curitem].type = Group;
3873 item[curitem].start = p;
3874 item[curitem].minwid = minwid;
3875 item[curitem].maxwid = maxwid;
3876 s++;
3877 curitem++;
3878 continue;
3879 }
3880 if (vim_strchr(STL_ALL, *s) == NULL)
3881 {
3882 s++;
3883 continue;
3884 }
3885 opt = *s++;
3886
3887 /* OK - now for the real work */
3888 base = 'D';
3889 itemisflag = FALSE;
3890 fillable = TRUE;
3891 num = -1;
3892 str = NULL;
3893 switch (opt)
3894 {
3895 case STL_FILEPATH:
3896 case STL_FULLPATH:
3897 case STL_FILENAME:
3898 fillable = FALSE; /* don't change ' ' to fillchar */
3899 if (buf_spname(wp->w_buffer) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02003900 vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 else
3902 {
3903 t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003904 : wp->w_buffer->b_fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905 home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE);
3906 }
3907 trans_characters(NameBuff, MAXPATHL);
3908 if (opt != STL_FILENAME)
3909 str = NameBuff;
3910 else
3911 str = gettail(NameBuff);
3912 break;
3913
3914 case STL_VIM_EXPR: /* '{' */
3915 itemisflag = TRUE;
3916 t = p;
3917 while (*s != '}' && *s != NUL && p + 1 < out + outlen)
3918 *p++ = *s++;
3919 if (*s != '}') /* missing '}' or out of space */
3920 break;
3921 s++;
3922 *p = 0;
3923 p = t;
3924
3925#ifdef FEAT_EVAL
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003926 vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927 set_internal_string_var((char_u *)"actual_curbuf", tmp);
3928
3929 o_curbuf = curbuf;
3930 o_curwin = curwin;
3931 curwin = wp;
3932 curbuf = wp->w_buffer;
3933
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003934 str = eval_to_string_safe(p, &t, use_sandbox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003935
3936 curwin = o_curwin;
3937 curbuf = o_curbuf;
Bram Moolenaar01824652005-01-31 18:58:23 +00003938 do_unlet((char_u *)"g:actual_curbuf", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003939
3940 if (str != NULL && *str != 0)
3941 {
3942 if (*skipdigits(str) == NUL)
3943 {
3944 num = atoi((char *)str);
3945 vim_free(str);
3946 str = NULL;
3947 itemisflag = FALSE;
3948 }
3949 }
3950#endif
3951 break;
3952
3953 case STL_LINE:
3954 num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
3955 ? 0L : (long)(wp->w_cursor.lnum);
3956 break;
3957
3958 case STL_NUMLINES:
3959 num = wp->w_buffer->b_ml.ml_line_count;
3960 break;
3961
3962 case STL_COLUMN:
3963 num = !(State & INSERT) && empty_line
3964 ? 0 : (int)wp->w_cursor.col + 1;
3965 break;
3966
3967 case STL_VIRTCOL:
3968 case STL_VIRTCOL_ALT:
3969 /* In list mode virtcol needs to be recomputed */
3970 virtcol = wp->w_virtcol;
3971 if (wp->w_p_list && lcs_tab1 == NUL)
3972 {
3973 wp->w_p_list = FALSE;
3974 getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
3975 wp->w_p_list = TRUE;
3976 }
3977 ++virtcol;
3978 /* Don't display %V if it's the same as %c. */
3979 if (opt == STL_VIRTCOL_ALT
3980 && (virtcol == (colnr_T)(!(State & INSERT) && empty_line
3981 ? 0 : (int)wp->w_cursor.col + 1)))
3982 break;
3983 num = (long)virtcol;
3984 break;
3985
3986 case STL_PERCENTAGE:
3987 num = (int)(((long)wp->w_cursor.lnum * 100L) /
3988 (long)wp->w_buffer->b_ml.ml_line_count);
3989 break;
3990
3991 case STL_ALTPERCENT:
3992 str = tmp;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003993 get_rel_pos(wp, str, TMPLEN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994 break;
3995
3996 case STL_ARGLISTSTAT:
3997 fillable = FALSE;
3998 tmp[0] = 0;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003999 if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 str = tmp;
4001 break;
4002
4003 case STL_KEYMAP:
4004 fillable = FALSE;
4005 if (get_keymap_str(wp, tmp, TMPLEN))
4006 str = tmp;
4007 break;
4008 case STL_PAGENUM:
Bram Moolenaarbfb2d402006-03-03 22:50:42 +00004009#if defined(FEAT_PRINTER) || defined(FEAT_GUI_TABLINE)
Bram Moolenaarba6c0522006-02-25 21:45:02 +00004010 num = printer_page_num;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004011#else
4012 num = 0;
4013#endif
4014 break;
4015
4016 case STL_BUFNO:
4017 num = wp->w_buffer->b_fnum;
4018 break;
4019
4020 case STL_OFFSET_X:
4021 base = 'X';
4022 case STL_OFFSET:
4023#ifdef FEAT_BYTEOFF
4024 l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL);
4025 num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ?
4026 0L : l + 1 + (!(State & INSERT) && empty_line ?
4027 0 : (int)wp->w_cursor.col);
4028#endif
4029 break;
4030
4031 case STL_BYTEVAL_X:
4032 base = 'X';
4033 case STL_BYTEVAL:
Bram Moolenaar567199b2013-04-24 16:52:36 +02004034 num = byteval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004035 if (num == NL)
4036 num = 0;
4037 else if (num == CAR && get_fileformat(wp->w_buffer) == EOL_MAC)
4038 num = NL;
4039 break;
4040
4041 case STL_ROFLAG:
4042 case STL_ROFLAG_ALT:
4043 itemisflag = TRUE;
4044 if (wp->w_buffer->b_p_ro)
Bram Moolenaar23584032013-06-07 20:17:11 +02004045 str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004046 break;
4047
4048 case STL_HELPFLAG:
4049 case STL_HELPFLAG_ALT:
4050 itemisflag = TRUE;
4051 if (wp->w_buffer->b_help)
4052 str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP"
Bram Moolenaar899dddf2006-03-26 21:06:50 +00004053 : _("[Help]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 break;
4055
4056#ifdef FEAT_AUTOCMD
4057 case STL_FILETYPE:
4058 if (*wp->w_buffer->b_p_ft != NUL
4059 && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3)
4060 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00004061 vim_snprintf((char *)tmp, sizeof(tmp), "[%s]",
4062 wp->w_buffer->b_p_ft);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063 str = tmp;
4064 }
4065 break;
4066
4067 case STL_FILETYPE_ALT:
4068 itemisflag = TRUE;
4069 if (*wp->w_buffer->b_p_ft != NUL
4070 && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2)
4071 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00004072 vim_snprintf((char *)tmp, sizeof(tmp), ",%s",
4073 wp->w_buffer->b_p_ft);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074 for (t = tmp; *t != 0; t++)
4075 *t = TOUPPER_LOC(*t);
4076 str = tmp;
4077 }
4078 break;
4079#endif
4080
4081#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
4082 case STL_PREVIEWFLAG:
4083 case STL_PREVIEWFLAG_ALT:
4084 itemisflag = TRUE;
4085 if (wp->w_p_pvw)
4086 str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV"
4087 : _("[Preview]"));
4088 break;
Bram Moolenaar7fd73202010-07-25 16:58:46 +02004089
4090 case STL_QUICKFIX:
4091 if (bt_quickfix(wp->w_buffer))
4092 str = (char_u *)(wp->w_llist_ref
4093 ? _(msg_loclist)
4094 : _(msg_qflist));
4095 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096#endif
4097
4098 case STL_MODIFIED:
4099 case STL_MODIFIED_ALT:
4100 itemisflag = TRUE;
4101 switch ((opt == STL_MODIFIED_ALT)
4102 + bufIsChanged(wp->w_buffer) * 2
4103 + (!wp->w_buffer->b_p_ma) * 4)
4104 {
4105 case 2: str = (char_u *)"[+]"; break;
4106 case 3: str = (char_u *)",+"; break;
4107 case 4: str = (char_u *)"[-]"; break;
4108 case 5: str = (char_u *)",-"; break;
4109 case 6: str = (char_u *)"[+-]"; break;
4110 case 7: str = (char_u *)",+-"; break;
4111 }
4112 break;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00004113
4114 case STL_HIGHLIGHT:
4115 t = s;
4116 while (*s != '#' && *s != NUL)
4117 ++s;
4118 if (*s == '#')
4119 {
4120 item[curitem].type = Highlight;
4121 item[curitem].start = p;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004122 item[curitem].minwid = -syn_namen2id(t, (int)(s - t));
Bram Moolenaar030f0df2006-02-21 22:02:53 +00004123 curitem++;
4124 }
Bram Moolenaar11808222013-11-02 04:39:38 +01004125 if (*s != NUL)
4126 ++s;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00004127 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128 }
4129
4130 item[curitem].start = p;
4131 item[curitem].type = Normal;
4132 if (str != NULL && *str)
4133 {
4134 t = str;
4135 if (itemisflag)
4136 {
4137 if ((t[0] && t[1])
4138 && ((!prevchar_isitem && *t == ',')
4139 || (prevchar_isflag && *t == ' ')))
4140 t++;
4141 prevchar_isflag = TRUE;
4142 }
4143 l = vim_strsize(t);
4144 if (l > 0)
4145 prevchar_isitem = TRUE;
4146 if (l > maxwid)
4147 {
4148 while (l >= maxwid)
4149#ifdef FEAT_MBYTE
4150 if (has_mbyte)
4151 {
4152 l -= ptr2cells(t);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004153 t += (*mb_ptr2len)(t);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 }
4155 else
4156#endif
4157 l -= byte2cells(*t++);
4158 if (p + 1 >= out + outlen)
4159 break;
4160 *p++ = '<';
4161 }
4162 if (minwid > 0)
4163 {
4164 for (; l < minwid && p + 1 < out + outlen; l++)
4165 {
4166 /* Don't put a "-" in front of a digit. */
4167 if (l + 1 == minwid && fillchar == '-' && VIM_ISDIGIT(*t))
4168 *p++ = ' ';
4169 else
4170 *p++ = fillchar;
4171 }
4172 minwid = 0;
4173 }
4174 else
4175 minwid *= -1;
4176 while (*t && p + 1 < out + outlen)
4177 {
4178 *p++ = *t++;
4179 /* Change a space by fillchar, unless fillchar is '-' and a
4180 * digit follows. */
4181 if (fillable && p[-1] == ' '
4182 && (!VIM_ISDIGIT(*t) || fillchar != '-'))
4183 p[-1] = fillchar;
4184 }
4185 for (; l < minwid && p + 1 < out + outlen; l++)
4186 *p++ = fillchar;
4187 }
4188 else if (num >= 0)
4189 {
4190 int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16));
4191 char_u nstr[20];
4192
4193 if (p + 20 >= out + outlen)
4194 break; /* not sufficient space */
4195 prevchar_isitem = TRUE;
4196 t = nstr;
4197 if (opt == STL_VIRTCOL_ALT)
4198 {
4199 *t++ = '-';
4200 minwid--;
4201 }
4202 *t++ = '%';
4203 if (zeropad)
4204 *t++ = '0';
4205 *t++ = '*';
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004206 *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd');
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207 *t = 0;
4208
4209 for (n = num, l = 1; n >= nbase; n /= nbase)
4210 l++;
4211 if (opt == STL_VIRTCOL_ALT)
4212 l++;
4213 if (l > maxwid)
4214 {
4215 l += 2;
4216 n = l - maxwid;
4217 while (l-- > maxwid)
4218 num /= nbase;
4219 *t++ = '>';
4220 *t++ = '%';
4221 *t = t[-3];
4222 *++t = 0;
Bram Moolenaar9c13b352005-05-19 20:53:52 +00004223 vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
4224 0, num, n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225 }
4226 else
Bram Moolenaar9c13b352005-05-19 20:53:52 +00004227 vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
4228 minwid, num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229 p += STRLEN(p);
4230 }
4231 else
4232 item[curitem].type = Empty;
4233
4234 if (opt == STL_VIM_EXPR)
4235 vim_free(str);
4236
4237 if (num >= 0 || (!itemisflag && str && *str))
4238 prevchar_isflag = FALSE; /* Item not NULL, but not a flag */
4239 curitem++;
4240 }
4241 *p = NUL;
4242 itemcnt = curitem;
4243
Bram Moolenaar030f0df2006-02-21 22:02:53 +00004244#ifdef FEAT_EVAL
4245 if (usefmt != fmt)
4246 vim_free(usefmt);
4247#endif
4248
Bram Moolenaar071d4272004-06-13 20:20:40 +00004249 width = vim_strsize(out);
4250 if (maxwidth > 0 && width > maxwidth)
4251 {
Bram Moolenaar9381ab72008-11-12 11:52:19 +00004252 /* Result is too long, must truncate somewhere. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253 l = 0;
4254 if (itemcnt == 0)
4255 s = out;
4256 else
4257 {
4258 for ( ; l < itemcnt; l++)
4259 if (item[l].type == Trunc)
4260 {
4261 /* Truncate at %< item. */
4262 s = item[l].start;
4263 break;
4264 }
4265 if (l == itemcnt)
4266 {
4267 /* No %< item, truncate first item. */
4268 s = item[0].start;
4269 l = 0;
4270 }
4271 }
4272
4273 if (width - vim_strsize(s) >= maxwidth)
4274 {
4275 /* Truncation mark is beyond max length */
4276#ifdef FEAT_MBYTE
4277 if (has_mbyte)
4278 {
4279 s = out;
4280 width = 0;
4281 for (;;)
4282 {
4283 width += ptr2cells(s);
4284 if (width >= maxwidth)
4285 break;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004286 s += (*mb_ptr2len)(s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287 }
4288 /* Fill up for half a double-wide character. */
4289 while (++width < maxwidth)
4290 *s++ = fillchar;
4291 }
4292 else
4293#endif
4294 s = out + maxwidth - 1;
4295 for (l = 0; l < itemcnt; l++)
4296 if (item[l].start > s)
4297 break;
4298 itemcnt = l;
4299 *s++ = '>';
4300 *s = 0;
4301 }
4302 else
4303 {
4304#ifdef FEAT_MBYTE
4305 if (has_mbyte)
4306 {
4307 n = 0;
4308 while (width >= maxwidth)
4309 {
4310 width -= ptr2cells(s + n);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004311 n += (*mb_ptr2len)(s + n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312 }
4313 }
4314 else
4315#endif
4316 n = width - maxwidth + 1;
4317 p = s + n;
Bram Moolenaarf2330482008-06-24 20:19:36 +00004318 STRMOVE(s + 1, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 *s = '<';
4320
4321 /* Fill up for half a double-wide character. */
4322 while (++width < maxwidth)
4323 {
4324 s = s + STRLEN(s);
4325 *s++ = fillchar;
4326 *s = NUL;
4327 }
4328
4329 --n; /* count the '<' */
4330 for (; l < itemcnt; l++)
4331 {
4332 if (item[l].start - n >= s)
4333 item[l].start -= n;
4334 else
4335 item[l].start = s;
4336 }
4337 }
4338 width = maxwidth;
4339 }
4340 else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen)
4341 {
4342 /* Apply STL_MIDDLE if any */
4343 for (l = 0; l < itemcnt; l++)
4344 if (item[l].type == Middle)
4345 break;
4346 if (l < itemcnt)
4347 {
4348 p = item[l].start + maxwidth - width;
Bram Moolenaarf2330482008-06-24 20:19:36 +00004349 STRMOVE(p, item[l].start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350 for (s = item[l].start; s < p; s++)
4351 *s = fillchar;
4352 for (l++; l < itemcnt; l++)
4353 item[l].start += maxwidth - width;
4354 width = maxwidth;
4355 }
4356 }
4357
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004358 /* Store the info about highlighting. */
4359 if (hltab != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004361 sp = hltab;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362 for (l = 0; l < itemcnt; l++)
4363 {
4364 if (item[l].type == Highlight)
4365 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004366 sp->start = item[l].start;
4367 sp->userhl = item[l].minwid;
4368 sp++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 }
4370 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004371 sp->start = NULL;
4372 sp->userhl = 0;
4373 }
4374
4375 /* Store the info about tab pages labels. */
4376 if (tabtab != NULL)
4377 {
4378 sp = tabtab;
4379 for (l = 0; l < itemcnt; l++)
4380 {
4381 if (item[l].type == TabPage)
4382 {
4383 sp->start = item[l].start;
4384 sp->userhl = item[l].minwid;
4385 sp++;
4386 }
4387 }
4388 sp->start = NULL;
4389 sp->userhl = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004390 }
4391
4392 return width;
4393}
4394#endif /* FEAT_STL_OPT */
4395
Bram Moolenaarba6c0522006-02-25 21:45:02 +00004396#if defined(FEAT_STL_OPT) || defined(FEAT_CMDL_INFO) \
4397 || defined(FEAT_GUI_TABLINE) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004398/*
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004399 * Get relative cursor position in window into "buf[buflen]", in the form 99%,
4400 * using "Top", "Bot" or "All" when appropriate.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004401 */
4402 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004403get_rel_pos(
4404 win_T *wp,
4405 char_u *buf,
4406 int buflen)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004407{
4408 long above; /* number of lines above window */
4409 long below; /* number of lines below window */
4410
Bram Moolenaar0027c212015-01-07 13:31:52 +01004411 if (buflen < 3) /* need at least 3 chars for writing */
4412 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004413 above = wp->w_topline - 1;
4414#ifdef FEAT_DIFF
4415 above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill;
Bram Moolenaar29bc9db2015-08-04 17:43:25 +02004416 if (wp->w_topline == 1 && wp->w_topfill >= 1)
4417 above = 0; /* All buffer lines are displayed and there is an
4418 * indication of filler lines, that can be considered
4419 * seeing all lines. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420#endif
4421 below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1;
4422 if (below <= 0)
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004423 vim_strncpy(buf, (char_u *)(above == 0 ? _("All") : _("Bot")),
4424 (size_t)(buflen - 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004425 else if (above <= 0)
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004426 vim_strncpy(buf, (char_u *)_("Top"), (size_t)(buflen - 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004427 else
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004428 vim_snprintf((char *)buf, (size_t)buflen, "%2d%%", above > 1000000L
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429 ? (int)(above / ((above + below) / 100L))
4430 : (int)(above * 100L / (above + below)));
4431}
4432#endif
4433
4434/*
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004435 * Append (file 2 of 8) to "buf[buflen]", if editing more than one file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004436 * Return TRUE if it was appended.
4437 */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004438 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01004439append_arg_number(
4440 win_T *wp,
4441 char_u *buf,
4442 int buflen,
4443 int add_file) /* Add "file" before the arg number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004444{
4445 char_u *p;
4446
4447 if (ARGCOUNT <= 1) /* nothing to do */
4448 return FALSE;
4449
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004450 p = buf + STRLEN(buf); /* go to the end of the buffer */
4451 if (p - buf + 35 >= buflen) /* getting too long */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004452 return FALSE;
4453 *p++ = ' ';
4454 *p++ = '(';
4455 if (add_file)
4456 {
4457 STRCPY(p, "file ");
4458 p += 5;
4459 }
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004460 vim_snprintf((char *)p, (size_t)(buflen - (p - buf)),
4461 wp->w_arg_idx_invalid ? "(%d) of %d)"
Bram Moolenaar071d4272004-06-13 20:20:40 +00004462 : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT);
4463 return TRUE;
4464}
4465
4466/*
4467 * If fname is not a full path, make it a full path.
4468 * Returns pointer to allocated memory (NULL for failure).
4469 */
4470 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01004471fix_fname(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472{
4473 /*
4474 * Force expanding the path always for Unix, because symbolic links may
4475 * mess up the full path name, even though it starts with a '/'.
4476 * Also expand when there is ".." in the file name, try to remove it,
4477 * because "c:/src/../README" is equal to "c:/README".
Bram Moolenaar9b942202007-10-03 12:31:33 +00004478 * Similarly "c:/src//file" is equal to "c:/src/file".
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479 * For MS-Windows also expand names like "longna~1" to "longname".
4480 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00004481#ifdef UNIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482 return FullName_save(fname, TRUE);
4483#else
Bram Moolenaar9b942202007-10-03 12:31:33 +00004484 if (!vim_isAbsName(fname)
4485 || strstr((char *)fname, "..") != NULL
4486 || strstr((char *)fname, "//") != NULL
4487# ifdef BACKSLASH_IN_FILENAME
4488 || strstr((char *)fname, "\\\\") != NULL
4489# endif
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004490# if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 || vim_strchr(fname, '~') != NULL
Bram Moolenaar9b942202007-10-03 12:31:33 +00004492# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493 )
4494 return FullName_save(fname, FALSE);
4495
4496 fname = vim_strsave(fname);
4497
Bram Moolenaar9b942202007-10-03 12:31:33 +00004498# ifdef USE_FNAME_CASE
4499# ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00004500 if (USE_LONG_FNAME)
Bram Moolenaar9b942202007-10-03 12:31:33 +00004501# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502 {
4503 if (fname != NULL)
4504 fname_case(fname, 0); /* set correct case for file name */
4505 }
Bram Moolenaar9b942202007-10-03 12:31:33 +00004506# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507
4508 return fname;
4509#endif
4510}
4511
4512/*
4513 * Make "ffname" a full file name, set "sfname" to "ffname" if not NULL.
4514 * "ffname" becomes a pointer to allocated memory (or NULL).
4515 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004517fname_expand(
4518 buf_T *buf UNUSED,
4519 char_u **ffname,
4520 char_u **sfname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004521{
4522 if (*ffname == NULL) /* if no file name given, nothing to do */
4523 return;
4524 if (*sfname == NULL) /* if no short file name given, use ffname */
4525 *sfname = *ffname;
4526 *ffname = fix_fname(*ffname); /* expand to full path */
4527
4528#ifdef FEAT_SHORTCUT
4529 if (!buf->b_p_bin)
4530 {
Bram Moolenaarf193fff2006-04-27 00:02:13 +00004531 char_u *rfname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532
4533 /* If the file name is a shortcut file, use the file it links to. */
4534 rfname = mch_resolve_shortcut(*ffname);
Bram Moolenaarf193fff2006-04-27 00:02:13 +00004535 if (rfname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536 {
4537 vim_free(*ffname);
4538 *ffname = rfname;
4539 *sfname = rfname;
4540 }
4541 }
4542#endif
4543}
4544
4545/*
4546 * Get the file name for an argument list entry.
4547 */
4548 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01004549alist_name(aentry_T *aep)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550{
4551 buf_T *bp;
4552
4553 /* Use the name from the associated buffer if it exists. */
4554 bp = buflist_findnr(aep->ae_fnum);
Bram Moolenaar84212822006-11-07 21:59:47 +00004555 if (bp == NULL || bp->b_fname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556 return aep->ae_fname;
4557 return bp->b_fname;
4558}
4559
4560#if defined(FEAT_WINDOWS) || defined(PROTO)
4561/*
4562 * do_arg_all(): Open up to 'count' windows, one for each argument.
4563 */
4564 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004565do_arg_all(
4566 int count,
4567 int forceit, /* hide buffers in current windows */
4568 int keep_tabs) /* keep current tabs, for ":tab drop file" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004569{
4570 int i;
4571 win_T *wp, *wpnext;
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004572 char_u *opened; /* Array of weight for which args are open:
4573 * 0: not opened
4574 * 1: opened in other tab
4575 * 2: opened in curtab
4576 * 3: opened in curtab and curwin
4577 */
Bram Moolenaard089d9b2007-09-30 12:02:55 +00004578 int opened_len; /* length of opened[] */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004579 int use_firstwin = FALSE; /* use first window for arglist */
4580 int split_ret = OK;
4581 int p_ea_save;
4582 alist_T *alist; /* argument list to be used */
4583 buf_T *buf;
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004584 tabpage_T *tpnext;
4585 int had_tab = cmdmod.tab;
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004586 win_T *old_curwin, *last_curwin;
4587 tabpage_T *old_curtab, *last_curtab;
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004588 win_T *new_curwin = NULL;
4589 tabpage_T *new_curtab = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004590
4591 if (ARGCOUNT <= 0)
4592 {
4593 /* Don't give an error message. We don't want it when the ":all"
4594 * command is in the .vimrc. */
4595 return;
4596 }
4597 setpcmark();
4598
4599 opened_len = ARGCOUNT;
4600 opened = alloc_clear((unsigned)opened_len);
4601 if (opened == NULL)
4602 return;
4603
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004604 /* Autocommands may do anything to the argument list. Make sure it's not
4605 * freed while we are working here by "locking" it. We still have to
4606 * watch out for its size to be changed. */
4607 alist = curwin->w_alist;
4608 ++alist->al_refcount;
4609
4610 old_curwin = curwin;
4611 old_curtab = curtab;
4612
Bram Moolenaar44a2f922016-03-19 22:11:51 +01004613# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 need_mouse_correct = TRUE;
Bram Moolenaar44a2f922016-03-19 22:11:51 +01004615# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616
4617 /*
4618 * Try closing all windows that are not in the argument list.
4619 * Also close windows that are not full width;
4620 * When 'hidden' or "forceit" set the buffer becomes hidden.
4621 * Windows that have a changed buffer and can't be hidden won't be closed.
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004622 * When the ":tab" modifier was used do this for all tab pages.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 */
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004624 if (had_tab > 0)
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004625 goto_tabpage_tp(first_tabpage, TRUE, TRUE);
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004626 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004628 tpnext = curtab->tp_next;
4629 for (wp = firstwin; wp != NULL; wp = wpnext)
4630 {
4631 wpnext = wp->w_next;
4632 buf = wp->w_buffer;
4633 if (buf->b_ffname == NULL
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004634 || (!keep_tabs && buf->b_nwindows > 1)
Bram Moolenaar44a2f922016-03-19 22:11:51 +01004635 || wp->w_width != Columns)
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004636 i = opened_len;
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004637 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004639 /* check if the buffer in this window is in the arglist */
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004640 for (i = 0; i < opened_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004641 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004642 if (i < alist->al_ga.ga_len
4643 && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum
4644 || fullpathcmp(alist_name(&AARGLIST(alist)[i]),
4645 buf->b_ffname, TRUE) & FPC_SAME))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004647 int weight = 1;
4648
4649 if (old_curtab == curtab)
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004650 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004651 ++weight;
4652 if (old_curwin == wp)
4653 ++weight;
4654 }
4655
4656 if (weight > (int)opened[i])
4657 {
4658 opened[i] = (char_u)weight;
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004659 if (i == 0)
4660 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004661 if (new_curwin != NULL)
4662 new_curwin->w_arg_idx = opened_len;
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004663 new_curwin = wp;
4664 new_curtab = curtab;
4665 }
4666 }
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004667 else if (keep_tabs)
4668 i = opened_len;
4669
4670 if (wp->w_alist != alist)
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004671 {
4672 /* Use the current argument list for all windows
4673 * containing a file from it. */
4674 alist_unlink(wp->w_alist);
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004675 wp->w_alist = alist;
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004676 ++wp->w_alist->al_refcount;
4677 }
4678 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004679 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004680 }
4681 }
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004682 wp->w_arg_idx = i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004684 if (i == opened_len && !keep_tabs)/* close this window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004685 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004686 if (P_HID(buf) || forceit || buf->b_nwindows > 1
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004687 || !bufIsChanged(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004688 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004689 /* If the buffer was changed, and we would like to hide it,
4690 * try autowriting. */
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004691 if (!P_HID(buf) && buf->b_nwindows <= 1
4692 && bufIsChanged(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004694 (void)autowrite(buf, FALSE);
4695#ifdef FEAT_AUTOCMD
4696 /* check if autocommands removed the window */
4697 if (!win_valid(wp) || !buf_valid(buf))
4698 {
4699 wpnext = firstwin; /* start all over... */
4700 continue;
4701 }
4702#endif
4703 }
4704#ifdef FEAT_WINDOWS
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004705 /* don't close last window */
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004706 if (firstwin == lastwin
4707 && (first_tabpage->tp_next == NULL || !had_tab))
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004708#endif
4709 use_firstwin = TRUE;
4710#ifdef FEAT_WINDOWS
4711 else
4712 {
4713 win_close(wp, !P_HID(buf) && !bufIsChanged(buf));
4714# ifdef FEAT_AUTOCMD
4715 /* check if autocommands removed the next window */
4716 if (!win_valid(wpnext))
4717 wpnext = firstwin; /* start all over... */
4718# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719 }
4720#endif
4721 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004722 }
4723 }
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004724
4725 /* Without the ":tab" modifier only do the current tab page. */
4726 if (had_tab == 0 || tpnext == NULL)
4727 break;
4728
4729# ifdef FEAT_AUTOCMD
4730 /* check if autocommands removed the next tab page */
4731 if (!valid_tabpage(tpnext))
4732 tpnext = first_tabpage; /* start all over...*/
4733# endif
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004734 goto_tabpage_tp(tpnext, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 }
4736
4737 /*
4738 * Open a window for files in the argument list that don't have one.
4739 * ARGCOUNT may change while doing this, because of autocommands.
4740 */
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004741 if (count > opened_len || count <= 0)
4742 count = opened_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004743
4744#ifdef FEAT_AUTOCMD
4745 /* Don't execute Win/Buf Enter/Leave autocommands here. */
4746 ++autocmd_no_enter;
4747 ++autocmd_no_leave;
4748#endif
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004749 last_curwin = curwin;
4750 last_curtab = curtab;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004751 win_enter(lastwin, FALSE);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004752#ifdef FEAT_WINDOWS
4753 /* ":drop all" should re-use an empty window to avoid "--remote-tab"
4754 * leaving an empty tab page when executed locally. */
4755 if (keep_tabs && bufempty() && curbuf->b_nwindows == 1
4756 && curbuf->b_ffname == NULL && !curbuf->b_changed)
4757 use_firstwin = TRUE;
4758#endif
4759
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004760 for (i = 0; i < count && i < opened_len && !got_int; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004761 {
4762 if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1)
4763 arg_had_last = TRUE;
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004764 if (opened[i] > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004765 {
4766 /* Move the already present window to below the current window */
4767 if (curwin->w_arg_idx != i)
4768 {
4769 for (wpnext = firstwin; wpnext != NULL; wpnext = wpnext->w_next)
4770 {
4771 if (wpnext->w_arg_idx == i)
4772 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004773 if (keep_tabs)
4774 {
4775 new_curwin = wpnext;
4776 new_curtab = curtab;
4777 }
4778 else
4779 win_move_after(wpnext, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004780 break;
4781 }
4782 }
4783 }
4784 }
4785 else if (split_ret == OK)
4786 {
4787 if (!use_firstwin) /* split current window */
4788 {
4789 p_ea_save = p_ea;
4790 p_ea = TRUE; /* use space from all windows */
4791 split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
4792 p_ea = p_ea_save;
4793 if (split_ret == FAIL)
4794 continue;
4795 }
4796#ifdef FEAT_AUTOCMD
4797 else /* first window: do autocmd for leaving this buffer */
4798 --autocmd_no_leave;
4799#endif
4800
4801 /*
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004802 * edit file "i"
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803 */
4804 curwin->w_arg_idx = i;
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004805 if (i == 0)
4806 {
4807 new_curwin = curwin;
4808 new_curtab = curtab;
4809 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810 (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL,
4811 ECMD_ONE,
4812 ((P_HID(curwin->w_buffer)
4813 || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00004814 + ECMD_OLDBUF, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815#ifdef FEAT_AUTOCMD
4816 if (use_firstwin)
4817 ++autocmd_no_leave;
4818#endif
4819 use_firstwin = FALSE;
4820 }
4821 ui_breakcheck();
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004822
4823 /* When ":tab" was used open a new tab for a new window repeatedly. */
4824 if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
4825 cmdmod.tab = 9999;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004826 }
4827
4828 /* Remove the "lock" on the argument list. */
4829 alist_unlink(alist);
4830
4831#ifdef FEAT_AUTOCMD
4832 --autocmd_no_enter;
4833#endif
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004834 /* restore last referenced tabpage's curwin */
4835 if (last_curtab != new_curtab)
4836 {
4837 if (valid_tabpage(last_curtab))
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004838 goto_tabpage_tp(last_curtab, TRUE, TRUE);
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004839 if (win_valid(last_curwin))
4840 win_enter(last_curwin, FALSE);
4841 }
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004842 /* to window with first arg */
4843 if (valid_tabpage(new_curtab))
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004844 goto_tabpage_tp(new_curtab, TRUE, TRUE);
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004845 if (win_valid(new_curwin))
4846 win_enter(new_curwin, FALSE);
4847
Bram Moolenaar071d4272004-06-13 20:20:40 +00004848#ifdef FEAT_AUTOCMD
4849 --autocmd_no_leave;
4850#endif
4851 vim_free(opened);
4852}
4853
4854# if defined(FEAT_LISTCMDS) || defined(PROTO)
4855/*
4856 * Open a window for a number of buffers.
4857 */
4858 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004859ex_buffer_all(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004860{
4861 buf_T *buf;
4862 win_T *wp, *wpnext;
4863 int split_ret = OK;
4864 int p_ea_save;
4865 int open_wins = 0;
4866 int r;
4867 int count; /* Maximum number of windows to open. */
4868 int all; /* When TRUE also load inactive buffers. */
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004869#ifdef FEAT_WINDOWS
4870 int had_tab = cmdmod.tab;
4871 tabpage_T *tpnext;
4872#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004873
4874 if (eap->addr_count == 0) /* make as many windows as possible */
4875 count = 9999;
4876 else
4877 count = eap->line2; /* make as many windows as specified */
4878 if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide)
4879 all = FALSE;
4880 else
4881 all = TRUE;
4882
4883 setpcmark();
4884
4885#ifdef FEAT_GUI
4886 need_mouse_correct = TRUE;
4887#endif
4888
4889 /*
4890 * Close superfluous windows (two windows for the same buffer).
4891 * Also close windows that are not full-width.
4892 */
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004893#ifdef FEAT_WINDOWS
4894 if (had_tab > 0)
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004895 goto_tabpage_tp(first_tabpage, TRUE, TRUE);
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004896 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898#endif
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004899 tpnext = curtab->tp_next;
4900 for (wp = firstwin; wp != NULL; wp = wpnext)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004902 wpnext = wp->w_next;
Bram Moolenaarbfb2d402006-03-03 22:50:42 +00004903 if ((wp->w_buffer->b_nwindows > 1
Bram Moolenaar44a2f922016-03-19 22:11:51 +01004904#ifdef FEAT_WINDOWS
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004905 || ((cmdmod.split & WSP_VERT)
4906 ? wp->w_height + wp->w_status_height < Rows - p_ch
Bram Moolenaarbfb2d402006-03-03 22:50:42 +00004907 - tabline_height()
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004908 : wp->w_width != Columns)
Bram Moolenaarb475fb92006-03-02 22:40:52 +00004909 || (had_tab > 0 && wp != firstwin)
4910#endif
Bram Moolenaar362ce482012-06-06 19:02:45 +02004911 ) && firstwin != lastwin
4912#ifdef FEAT_AUTOCMD
4913 && !(wp->w_closing || wp->w_buffer->b_closing)
4914#endif
4915 )
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004916 {
4917 win_close(wp, FALSE);
4918#ifdef FEAT_AUTOCMD
4919 wpnext = firstwin; /* just in case an autocommand does
4920 something strange with windows */
Bram Moolenaarb475fb92006-03-02 22:40:52 +00004921 tpnext = first_tabpage; /* start all over...*/
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004922 open_wins = 0;
4923#endif
4924 }
4925 else
4926 ++open_wins;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927 }
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004928
4929#ifdef FEAT_WINDOWS
4930 /* Without the ":tab" modifier only do the current tab page. */
4931 if (had_tab == 0 || tpnext == NULL)
4932 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004933 goto_tabpage_tp(tpnext, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934 }
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004935#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004936
4937 /*
4938 * Go through the buffer list. When a buffer doesn't have a window yet,
4939 * open one. Otherwise move the window to the right position.
4940 * Watch out for autocommands that delete buffers or windows!
4941 */
4942#ifdef FEAT_AUTOCMD
4943 /* Don't execute Win/Buf Enter/Leave autocommands here. */
4944 ++autocmd_no_enter;
4945#endif
4946 win_enter(lastwin, FALSE);
4947#ifdef FEAT_AUTOCMD
4948 ++autocmd_no_leave;
4949#endif
4950 for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next)
4951 {
4952 /* Check if this buffer needs a window */
4953 if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl)
4954 continue;
4955
Bram Moolenaarb475fb92006-03-02 22:40:52 +00004956#ifdef FEAT_WINDOWS
4957 if (had_tab != 0)
4958 {
4959 /* With the ":tab" modifier don't move the window. */
4960 if (buf->b_nwindows > 0)
4961 wp = lastwin; /* buffer has a window, skip it */
4962 else
4963 wp = NULL;
4964 }
4965 else
4966#endif
4967 {
4968 /* Check if this buffer already has a window */
4969 for (wp = firstwin; wp != NULL; wp = wp->w_next)
4970 if (wp->w_buffer == buf)
4971 break;
4972 /* If the buffer already has a window, move it */
4973 if (wp != NULL)
4974 win_move_after(wp, curwin);
4975 }
4976
4977 if (wp == NULL && split_ret == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004978 {
4979 /* Split the window and put the buffer in it */
4980 p_ea_save = p_ea;
4981 p_ea = TRUE; /* use space from all windows */
4982 split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
4983 ++open_wins;
4984 p_ea = p_ea_save;
4985 if (split_ret == FAIL)
4986 continue;
4987
4988 /* Open the buffer in this window. */
Bram Moolenaare64ac772005-12-07 20:54:59 +00004989#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004990 swap_exists_action = SEA_DIALOG;
4991#endif
4992 set_curbuf(buf, DOBUF_GOTO);
4993#ifdef FEAT_AUTOCMD
Bram Moolenaar071d4272004-06-13 20:20:40 +00004994 if (!buf_valid(buf)) /* autocommands deleted the buffer!!! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004995 {
Bram Moolenaare64ac772005-12-07 20:54:59 +00004996#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004997 swap_exists_action = SEA_NONE;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00004998# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999 break;
5000 }
5001#endif
Bram Moolenaare64ac772005-12-07 20:54:59 +00005002#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005003 if (swap_exists_action == SEA_QUIT)
5004 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +00005005# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
5006 cleanup_T cs;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005007
Bram Moolenaarc0197e22004-09-13 20:26:32 +00005008 /* Reset the error/interrupt/exception state here so that
5009 * aborting() returns FALSE when closing a window. */
5010 enter_cleanup(&cs);
5011# endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005012
Bram Moolenaarc0197e22004-09-13 20:26:32 +00005013 /* User selected Quit at ATTENTION prompt; close this window. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005014 win_close(curwin, TRUE);
5015 --open_wins;
5016 swap_exists_action = SEA_NONE;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005017 swap_exists_did_quit = TRUE;
Bram Moolenaarc0197e22004-09-13 20:26:32 +00005018
5019# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
5020 /* Restore the error/interrupt/exception state if not
5021 * discarded by a new aborting error, interrupt, or uncaught
5022 * exception. */
5023 leave_cleanup(&cs);
5024# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025 }
5026 else
5027 handle_swap_exists(NULL);
5028#endif
5029 }
5030
5031 ui_breakcheck();
5032 if (got_int)
5033 {
5034 (void)vgetc(); /* only break the file loading, not the rest */
5035 break;
5036 }
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005037#ifdef FEAT_EVAL
5038 /* Autocommands deleted the buffer or aborted script processing!!! */
5039 if (aborting())
5040 break;
5041#endif
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005042#ifdef FEAT_WINDOWS
5043 /* When ":tab" was used open a new tab for a new window repeatedly. */
5044 if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
5045 cmdmod.tab = 9999;
5046#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047 }
5048#ifdef FEAT_AUTOCMD
5049 --autocmd_no_enter;
5050#endif
5051 win_enter(firstwin, FALSE); /* back to first window */
5052#ifdef FEAT_AUTOCMD
5053 --autocmd_no_leave;
5054#endif
5055
5056 /*
5057 * Close superfluous windows.
5058 */
5059 for (wp = lastwin; open_wins > count; )
5060 {
5061 r = (P_HID(wp->w_buffer) || !bufIsChanged(wp->w_buffer)
5062 || autowrite(wp->w_buffer, FALSE) == OK);
5063#ifdef FEAT_AUTOCMD
5064 if (!win_valid(wp))
5065 {
5066 /* BufWrite Autocommands made the window invalid, start over */
5067 wp = lastwin;
5068 }
5069 else
5070#endif
5071 if (r)
5072 {
5073 win_close(wp, !P_HID(wp->w_buffer));
5074 --open_wins;
5075 wp = lastwin;
5076 }
5077 else
5078 {
5079 wp = wp->w_prev;
5080 if (wp == NULL)
5081 break;
5082 }
5083 }
5084}
5085# endif /* FEAT_LISTCMDS */
5086
5087#endif /* FEAT_WINDOWS */
5088
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01005089static int chk_modeline(linenr_T, int);
Bram Moolenaara3227e22006-03-08 21:32:40 +00005090
Bram Moolenaar071d4272004-06-13 20:20:40 +00005091/*
5092 * do_modelines() - process mode lines for the current file
5093 *
Bram Moolenaara3227e22006-03-08 21:32:40 +00005094 * "flags" can be:
5095 * OPT_WINONLY only set options local to window
5096 * OPT_NOWIN don't set options local to window
5097 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098 * Returns immediately if the "ml" option isn't set.
5099 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005100 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005101do_modelines(int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005102{
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00005103 linenr_T lnum;
5104 int nmlines;
5105 static int entered = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005106
5107 if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
5108 return;
5109
5110 /* Disallow recursive entry here. Can happen when executing a modeline
5111 * triggers an autocommand, which reloads modelines with a ":do". */
5112 if (entered)
5113 return;
5114
5115 ++entered;
5116 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
5117 ++lnum)
Bram Moolenaara3227e22006-03-08 21:32:40 +00005118 if (chk_modeline(lnum, flags) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005119 nmlines = 0;
5120
5121 for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines
5122 && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
Bram Moolenaara3227e22006-03-08 21:32:40 +00005123 if (chk_modeline(lnum, flags) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124 nmlines = 0;
5125 --entered;
5126}
5127
5128#include "version.h" /* for version number */
5129
5130/*
5131 * chk_modeline() - check a single line for a mode string
5132 * Return FAIL if an error encountered.
5133 */
5134 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005135chk_modeline(
5136 linenr_T lnum,
5137 int flags) /* Same as for do_modelines(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005138{
5139 char_u *s;
5140 char_u *e;
5141 char_u *linecopy; /* local copy of any modeline found */
5142 int prev;
5143 int vers;
5144 int end;
5145 int retval = OK;
5146 char_u *save_sourcing_name;
5147 linenr_T save_sourcing_lnum;
5148#ifdef FEAT_EVAL
5149 scid_T save_SID;
5150#endif
5151
5152 prev = -1;
5153 for (s = ml_get(lnum); *s != NUL; ++s)
5154 {
5155 if (prev == -1 || vim_isspace(prev))
5156 {
5157 if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0)
5158 || STRNCMP(s, "vi:", (size_t)3) == 0)
5159 break;
Bram Moolenaarc14621e2013-06-26 20:04:35 +02005160 /* Accept both "vim" and "Vim". */
5161 if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm')
Bram Moolenaar071d4272004-06-13 20:20:40 +00005162 {
5163 if (s[3] == '<' || s[3] == '=' || s[3] == '>')
5164 e = s + 4;
5165 else
5166 e = s + 3;
5167 vers = getdigits(&e);
5168 if (*e == ':'
Bram Moolenaar630a7302013-06-29 15:07:22 +02005169 && (s[0] != 'V'
5170 || STRNCMP(skipwhite(e + 1), "set", 3) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005171 && (s[3] == ':'
5172 || (VIM_VERSION_100 >= vers && isdigit(s[3]))
5173 || (VIM_VERSION_100 < vers && s[3] == '<')
5174 || (VIM_VERSION_100 > vers && s[3] == '>')
5175 || (VIM_VERSION_100 == vers && s[3] == '=')))
5176 break;
5177 }
5178 }
5179 prev = *s;
5180 }
5181
5182 if (*s)
5183 {
5184 do /* skip over "ex:", "vi:" or "vim:" */
5185 ++s;
5186 while (s[-1] != ':');
5187
5188 s = linecopy = vim_strsave(s); /* copy the line, it will change */
5189 if (linecopy == NULL)
5190 return FAIL;
5191
5192 save_sourcing_lnum = sourcing_lnum;
5193 save_sourcing_name = sourcing_name;
5194 sourcing_lnum = lnum; /* prepare for emsg() */
5195 sourcing_name = (char_u *)"modelines";
5196
5197 end = FALSE;
5198 while (end == FALSE)
5199 {
5200 s = skipwhite(s);
5201 if (*s == NUL)
5202 break;
5203
5204 /*
5205 * Find end of set command: ':' or end of line.
5206 * Skip over "\:", replacing it with ":".
5207 */
5208 for (e = s; *e != ':' && *e != NUL; ++e)
5209 if (e[0] == '\\' && e[1] == ':')
Bram Moolenaarf2330482008-06-24 20:19:36 +00005210 STRMOVE(e, e + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211 if (*e == NUL)
5212 end = TRUE;
5213
5214 /*
5215 * If there is a "set" command, require a terminating ':' and
5216 * ignore the stuff after the ':'.
5217 * "vi:set opt opt opt: foo" -- foo not interpreted
5218 * "vi:opt opt opt: foo" -- foo interpreted
5219 * Accept "se" for compatibility with Elvis.
5220 */
5221 if (STRNCMP(s, "set ", (size_t)4) == 0
5222 || STRNCMP(s, "se ", (size_t)3) == 0)
5223 {
5224 if (*e != ':') /* no terminating ':'? */
5225 break;
5226 end = TRUE;
5227 s = vim_strchr(s, ' ') + 1;
5228 }
5229 *e = NUL; /* truncate the set command */
5230
5231 if (*s != NUL) /* skip over an empty "::" */
5232 {
5233#ifdef FEAT_EVAL
5234 save_SID = current_SID;
5235 current_SID = SID_MODELINE;
5236#endif
Bram Moolenaara3227e22006-03-08 21:32:40 +00005237 retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005238#ifdef FEAT_EVAL
5239 current_SID = save_SID;
5240#endif
5241 if (retval == FAIL) /* stop if error found */
5242 break;
5243 }
5244 s = e + 1; /* advance to next part */
5245 }
5246
5247 sourcing_lnum = save_sourcing_lnum;
5248 sourcing_name = save_sourcing_name;
5249
5250 vim_free(linecopy);
5251 }
5252 return retval;
5253}
5254
Bram Moolenaar91d8e0c2008-03-12 11:23:53 +00005255#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005256 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005257read_viminfo_bufferlist(
5258 vir_T *virp,
5259 int writing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260{
5261 char_u *tab;
5262 linenr_T lnum;
5263 colnr_T col;
5264 buf_T *buf;
5265 char_u *sfname;
5266 char_u *xline;
5267
5268 /* Handle long line and escaped characters. */
5269 xline = viminfo_readstring(virp, 1, FALSE);
5270
5271 /* don't read in if there are files on the command-line or if writing: */
5272 if (xline != NULL && !writing && ARGCOUNT == 0
5273 && find_viminfo_parameter('%') != NULL)
5274 {
5275 /* Format is: <fname> Tab <lnum> Tab <col>.
5276 * Watch out for a Tab in the file name, work from the end. */
5277 lnum = 0;
5278 col = 0;
5279 tab = vim_strrchr(xline, '\t');
5280 if (tab != NULL)
5281 {
5282 *tab++ = '\0';
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005283 col = (colnr_T)atoi((char *)tab);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005284 tab = vim_strrchr(xline, '\t');
5285 if (tab != NULL)
5286 {
5287 *tab++ = '\0';
5288 lnum = atol((char *)tab);
5289 }
5290 }
5291
5292 /* Expand "~/" in the file name at "line + 1" to a full path.
5293 * Then try shortening it by comparing with the current directory */
5294 expand_env(xline, NameBuff, MAXPATHL);
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005295 sfname = shorten_fname1(NameBuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005296
5297 buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
5298 if (buf != NULL) /* just in case... */
5299 {
5300 buf->b_last_cursor.lnum = lnum;
5301 buf->b_last_cursor.col = col;
5302 buflist_setfpos(buf, curwin, lnum, col, FALSE);
5303 }
5304 }
5305 vim_free(xline);
5306
5307 return viminfo_readline(virp);
5308}
5309
5310 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005311write_viminfo_bufferlist(FILE *fp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005312{
5313 buf_T *buf;
5314#ifdef FEAT_WINDOWS
5315 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00005316 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005317#endif
5318 char_u *line;
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00005319 int max_buffers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005320
5321 if (find_viminfo_parameter('%') == NULL)
5322 return;
5323
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00005324 /* Without a number -1 is returned: do all buffers. */
5325 max_buffers = get_viminfo_parameter('%');
5326
Bram Moolenaar071d4272004-06-13 20:20:40 +00005327 /* Allocate room for the file name, lnum and col. */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005328#define LINE_BUF_LEN (MAXPATHL + 40)
5329 line = alloc(LINE_BUF_LEN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005330 if (line == NULL)
5331 return;
5332
5333#ifdef FEAT_WINDOWS
Bram Moolenaarf740b292006-02-16 22:11:02 +00005334 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005335 set_last_cursor(win);
5336#else
5337 set_last_cursor(curwin);
5338#endif
5339
Bram Moolenaar2f1e0502010-08-13 11:18:02 +02005340 fputs(_("\n# Buffer list:\n"), fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005341 for (buf = firstbuf; buf != NULL ; buf = buf->b_next)
5342 {
5343 if (buf->b_fname == NULL
5344 || !buf->b_p_bl
5345#ifdef FEAT_QUICKFIX
5346 || bt_quickfix(buf)
5347#endif
5348 || removable(buf->b_ffname))
5349 continue;
5350
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00005351 if (max_buffers-- == 0)
5352 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005353 putc('%', fp);
5354 home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
Bram Moolenaara800b422010-06-27 01:15:55 +02005355 vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%ld\t%d",
Bram Moolenaar071d4272004-06-13 20:20:40 +00005356 (long)buf->b_last_cursor.lnum,
5357 buf->b_last_cursor.col);
5358 viminfo_writestring(fp, line);
5359 }
5360 vim_free(line);
5361}
5362#endif
5363
5364
5365/*
5366 * Return special buffer name.
5367 * Returns NULL when the buffer has a normal file name.
5368 */
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005369 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01005370buf_spname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005371{
5372#if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)
5373 if (bt_quickfix(buf))
Bram Moolenaar28c258f2006-01-25 22:02:51 +00005374 {
Bram Moolenaar4a3aef72013-07-17 19:12:57 +02005375 win_T *win;
Bram Moolenaar91d8e0c2008-03-12 11:23:53 +00005376 tabpage_T *tp;
Bram Moolenaar28c258f2006-01-25 22:02:51 +00005377
5378 /*
5379 * For location list window, w_llist_ref points to the location list.
5380 * For quickfix window, w_llist_ref is NULL.
5381 */
Bram Moolenaar4a3aef72013-07-17 19:12:57 +02005382 if (find_win_for_buf(buf, &win, &tp) == OK && win->w_llist_ref != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005383 return (char_u *)_(msg_loclist);
Bram Moolenaar28c258f2006-01-25 22:02:51 +00005384 else
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005385 return (char_u *)_(msg_qflist);
Bram Moolenaar28c258f2006-01-25 22:02:51 +00005386 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005387#endif
5388#ifdef FEAT_QUICKFIX
5389 /* There is no _file_ when 'buftype' is "nofile", b_sfname
5390 * contains the name as specified by the user */
5391 if (bt_nofile(buf))
5392 {
5393 if (buf->b_sfname != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005394 return buf->b_sfname;
5395 return (char_u *)_("[Scratch]");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005396 }
5397#endif
5398 if (buf->b_fname == NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005399 return (char_u *)_("[No Name]");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005400 return NULL;
5401}
5402
Bram Moolenaar4a3aef72013-07-17 19:12:57 +02005403#if (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)) \
5404 || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
5405 || defined(PROTO)
5406/*
5407 * Find a window for buffer "buf".
5408 * If found OK is returned and "wp" and "tp" are set to the window and tabpage.
5409 * If not found FAIL is returned.
5410 */
5411 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005412find_win_for_buf(
5413 buf_T *buf,
5414 win_T **wp,
5415 tabpage_T **tp)
Bram Moolenaar4a3aef72013-07-17 19:12:57 +02005416{
5417 FOR_ALL_TAB_WINDOWS(*tp, *wp)
5418 if ((*wp)->w_buffer == buf)
5419 goto win_found;
5420 return FAIL;
5421win_found:
5422 return OK;
5423}
5424#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005425
5426#if defined(FEAT_SIGNS) || defined(PROTO)
5427/*
5428 * Insert the sign into the signlist.
5429 */
5430 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005431insert_sign(
5432 buf_T *buf, /* buffer to store sign in */
5433 signlist_T *prev, /* previous sign entry */
5434 signlist_T *next, /* next sign entry */
5435 int id, /* sign ID */
5436 linenr_T lnum, /* line number which gets the mark */
5437 int typenr) /* typenr of sign we are adding */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005438{
5439 signlist_T *newsign;
5440
5441 newsign = (signlist_T *)lalloc((long_u)sizeof(signlist_T), FALSE);
5442 if (newsign != NULL)
5443 {
5444 newsign->id = id;
5445 newsign->lnum = lnum;
5446 newsign->typenr = typenr;
5447 newsign->next = next;
5448#ifdef FEAT_NETBEANS_INTG
5449 newsign->prev = prev;
5450 if (next != NULL)
5451 next->prev = newsign;
5452#endif
5453
5454 if (prev == NULL)
5455 {
5456 /* When adding first sign need to redraw the windows to create the
5457 * column for signs. */
5458 if (buf->b_signlist == NULL)
5459 {
5460 redraw_buf_later(buf, NOT_VALID);
5461 changed_cline_bef_curs();
5462 }
5463
5464 /* first sign in signlist */
5465 buf->b_signlist = newsign;
Bram Moolenaar3b7b8362015-03-20 18:11:48 +01005466#ifdef FEAT_NETBEANS_INTG
5467 if (netbeans_active())
5468 buf->b_has_sign_column = TRUE;
5469#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005470 }
5471 else
5472 prev->next = newsign;
5473 }
5474}
5475
5476/*
5477 * Add the sign into the signlist. Find the right spot to do it though.
5478 */
5479 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005480buf_addsign(
5481 buf_T *buf, /* buffer to store sign in */
5482 int id, /* sign ID */
5483 linenr_T lnum, /* line number which gets the mark */
5484 int typenr) /* typenr of sign we are adding */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005485{
5486 signlist_T *sign; /* a sign in the signlist */
5487 signlist_T *prev; /* the previous sign */
5488
5489 prev = NULL;
5490 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5491 {
5492 if (lnum == sign->lnum && id == sign->id)
5493 {
5494 sign->typenr = typenr;
5495 return;
5496 }
5497 else if (
5498#ifndef FEAT_NETBEANS_INTG /* keep signs sorted by lnum */
5499 id < 0 &&
5500#endif
5501 lnum < sign->lnum)
5502 {
5503#ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */
5504 /* XXX - GRP: Is this because of sign slide problem? Or is it
5505 * really needed? Or is it because we allow multiple signs per
5506 * line? If so, should I add that feature to FEAT_SIGNS?
5507 */
5508 while (prev != NULL && prev->lnum == lnum)
5509 prev = prev->prev;
5510 if (prev == NULL)
5511 sign = buf->b_signlist;
5512 else
5513 sign = prev->next;
5514#endif
5515 insert_sign(buf, prev, sign, id, lnum, typenr);
5516 return;
5517 }
5518 prev = sign;
5519 }
5520#ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */
5521 /* XXX - GRP: See previous comment */
5522 while (prev != NULL && prev->lnum == lnum)
5523 prev = prev->prev;
5524 if (prev == NULL)
5525 sign = buf->b_signlist;
5526 else
5527 sign = prev->next;
5528#endif
5529 insert_sign(buf, prev, sign, id, lnum, typenr);
5530
5531 return;
5532}
5533
Bram Moolenaar0d3d5e02014-05-07 16:35:08 +02005534/*
5535 * For an existing, placed sign "markId" change the type to "typenr".
5536 * Returns the line number of the sign, or zero if the sign is not found.
5537 */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005538 linenr_T
Bram Moolenaar7454a062016-01-30 15:14:10 +01005539buf_change_sign_type(
5540 buf_T *buf, /* buffer to store sign in */
5541 int markId, /* sign ID */
5542 int typenr) /* typenr of sign we are adding */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005543{
5544 signlist_T *sign; /* a sign in the signlist */
5545
5546 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5547 {
5548 if (sign->id == markId)
5549 {
5550 sign->typenr = typenr;
5551 return sign->lnum;
5552 }
5553 }
5554
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005555 return (linenr_T)0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005556}
5557
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005558 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005559buf_getsigntype(
5560 buf_T *buf,
5561 linenr_T lnum,
5562 int type) /* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005563{
5564 signlist_T *sign; /* a sign in a b_signlist */
5565
5566 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5567 if (sign->lnum == lnum
5568 && (type == SIGN_ANY
5569# ifdef FEAT_SIGN_ICONS
5570 || (type == SIGN_ICON
5571 && sign_get_image(sign->typenr) != NULL)
5572# endif
5573 || (type == SIGN_TEXT
5574 && sign_get_text(sign->typenr) != NULL)
5575 || (type == SIGN_LINEHL
5576 && sign_get_attr(sign->typenr, TRUE) != 0)))
5577 return sign->typenr;
5578 return 0;
5579}
5580
5581
5582 linenr_T
Bram Moolenaar7454a062016-01-30 15:14:10 +01005583buf_delsign(
5584 buf_T *buf, /* buffer sign is stored in */
5585 int id) /* sign id */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005586{
5587 signlist_T **lastp; /* pointer to pointer to current sign */
5588 signlist_T *sign; /* a sign in a b_signlist */
5589 signlist_T *next; /* the next sign in a b_signlist */
5590 linenr_T lnum; /* line number whose sign was deleted */
5591
5592 lastp = &buf->b_signlist;
5593 lnum = 0;
5594 for (sign = buf->b_signlist; sign != NULL; sign = next)
5595 {
5596 next = sign->next;
5597 if (sign->id == id)
5598 {
5599 *lastp = next;
5600#ifdef FEAT_NETBEANS_INTG
5601 if (next != NULL)
5602 next->prev = sign->prev;
5603#endif
5604 lnum = sign->lnum;
5605 vim_free(sign);
5606 break;
5607 }
5608 else
5609 lastp = &sign->next;
5610 }
5611
5612 /* When deleted the last sign need to redraw the windows to remove the
5613 * sign column. */
5614 if (buf->b_signlist == NULL)
5615 {
5616 redraw_buf_later(buf, NOT_VALID);
5617 changed_cline_bef_curs();
5618 }
5619
5620 return lnum;
5621}
5622
5623
5624/*
5625 * Find the line number of the sign with the requested id. If the sign does
5626 * not exist, return 0 as the line number. This will still let the correct file
5627 * get loaded.
5628 */
5629 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005630buf_findsign(
5631 buf_T *buf, /* buffer to store sign in */
5632 int id) /* sign ID */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005633{
5634 signlist_T *sign; /* a sign in the signlist */
5635
5636 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5637 if (sign->id == id)
5638 return sign->lnum;
5639
5640 return 0;
5641}
5642
5643 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005644buf_findsign_id(
5645 buf_T *buf, /* buffer whose sign we are searching for */
5646 linenr_T lnum) /* line number of sign */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005647{
5648 signlist_T *sign; /* a sign in the signlist */
5649
5650 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5651 if (sign->lnum == lnum)
5652 return sign->id;
5653
5654 return 0;
5655}
5656
5657
5658# if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
5659/* see if a given type of sign exists on a specific line */
5660 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005661buf_findsigntype_id(
5662 buf_T *buf, /* buffer whose sign we are searching for */
5663 linenr_T lnum, /* line number of sign */
5664 int typenr) /* sign type number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005665{
5666 signlist_T *sign; /* a sign in the signlist */
5667
5668 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5669 if (sign->lnum == lnum && sign->typenr == typenr)
5670 return sign->id;
5671
5672 return 0;
5673}
5674
5675
5676# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
5677/* return the number of icons on the given line */
5678 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005679buf_signcount(buf_T *buf, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005680{
5681 signlist_T *sign; /* a sign in the signlist */
5682 int count = 0;
5683
5684 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5685 if (sign->lnum == lnum)
5686 if (sign_get_image(sign->typenr) != NULL)
5687 count++;
5688
5689 return count;
5690}
5691# endif /* FEAT_SIGN_ICONS */
5692# endif /* FEAT_NETBEANS_INTG */
5693
5694
5695/*
5696 * Delete signs in buffer "buf".
5697 */
Bram Moolenaarf65e5662012-07-10 15:18:22 +02005698 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005699buf_delete_signs(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005700{
5701 signlist_T *next;
5702
Bram Moolenaar0d3d5e02014-05-07 16:35:08 +02005703 /* When deleting the last sign need to redraw the windows to remove the
Bram Moolenaar4e036c92014-07-16 16:30:28 +02005704 * sign column. Not when curwin is NULL (this means we're exiting). */
5705 if (buf->b_signlist != NULL && curwin != NULL)
Bram Moolenaar0d3d5e02014-05-07 16:35:08 +02005706 {
5707 redraw_buf_later(buf, NOT_VALID);
5708 changed_cline_bef_curs();
5709 }
5710
Bram Moolenaar071d4272004-06-13 20:20:40 +00005711 while (buf->b_signlist != NULL)
5712 {
5713 next = buf->b_signlist->next;
5714 vim_free(buf->b_signlist);
5715 buf->b_signlist = next;
5716 }
5717}
5718
5719/*
5720 * Delete all signs in all buffers.
5721 */
5722 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005723buf_delete_all_signs(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005724{
5725 buf_T *buf; /* buffer we are checking for signs */
5726
5727 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
5728 if (buf->b_signlist != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005729 buf_delete_signs(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005730}
5731
5732/*
5733 * List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers.
5734 */
5735 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005736sign_list_placed(buf_T *rbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005737{
5738 buf_T *buf;
5739 signlist_T *p;
5740 char lbuf[BUFSIZ];
5741
5742 MSG_PUTS_TITLE(_("\n--- Signs ---"));
5743 msg_putchar('\n');
5744 if (rbuf == NULL)
5745 buf = firstbuf;
5746 else
5747 buf = rbuf;
Bram Moolenaar1c0b03e2012-03-16 14:32:15 +01005748 while (buf != NULL && !got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005749 {
5750 if (buf->b_signlist != NULL)
5751 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00005752 vim_snprintf(lbuf, BUFSIZ, _("Signs for %s:"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005753 MSG_PUTS_ATTR(lbuf, hl_attr(HLF_D));
5754 msg_putchar('\n');
5755 }
Bram Moolenaar1c0b03e2012-03-16 14:32:15 +01005756 for (p = buf->b_signlist; p != NULL && !got_int; p = p->next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005757 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00005758 vim_snprintf(lbuf, BUFSIZ, _(" line=%ld id=%d name=%s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005759 (long)p->lnum, p->id, sign_typenr2name(p->typenr));
5760 MSG_PUTS(lbuf);
5761 msg_putchar('\n');
5762 }
5763 if (rbuf != NULL)
5764 break;
5765 buf = buf->b_next;
5766 }
5767}
5768
5769/*
5770 * Adjust a placed sign for inserted/deleted lines.
5771 */
5772 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005773sign_mark_adjust(
5774 linenr_T line1,
5775 linenr_T line2,
5776 long amount,
5777 long amount_after)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005778{
5779 signlist_T *sign; /* a sign in a b_signlist */
5780
5781 for (sign = curbuf->b_signlist; sign != NULL; sign = sign->next)
5782 {
5783 if (sign->lnum >= line1 && sign->lnum <= line2)
5784 {
5785 if (amount == MAXLNUM)
5786 sign->lnum = line1;
5787 else
5788 sign->lnum += amount;
5789 }
5790 else if (sign->lnum > line2)
5791 sign->lnum += amount_after;
5792 }
5793}
5794#endif /* FEAT_SIGNS */
5795
5796/*
5797 * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed.
5798 */
5799 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005800set_buflisted(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005801{
5802 if (on != curbuf->b_p_bl)
5803 {
5804 curbuf->b_p_bl = on;
5805#ifdef FEAT_AUTOCMD
5806 if (on)
5807 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
5808 else
5809 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
5810#endif
5811 }
5812}
5813
5814/*
5815 * Read the file for "buf" again and check if the contents changed.
5816 * Return TRUE if it changed or this could not be checked.
5817 */
5818 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005819buf_contents_changed(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005820{
5821 buf_T *newbuf;
5822 int differ = TRUE;
5823 linenr_T lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005824 aco_save_T aco;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005825 exarg_T ea;
5826
5827 /* Allocate a buffer without putting it in the buffer list. */
5828 newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
5829 if (newbuf == NULL)
5830 return TRUE;
5831
5832 /* Force the 'fileencoding' and 'fileformat' to be equal. */
5833 if (prep_exarg(&ea, buf) == FAIL)
5834 {
5835 wipe_buffer(newbuf, FALSE);
5836 return TRUE;
5837 }
5838
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839 /* set curwin/curbuf to buf and save a few things */
5840 aucmd_prepbuf(&aco, newbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005841
Bram Moolenaar4770d092006-01-12 23:22:24 +00005842 if (ml_open(curbuf) == OK
Bram Moolenaar071d4272004-06-13 20:20:40 +00005843 && readfile(buf->b_ffname, buf->b_fname,
5844 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
5845 &ea, READ_NEW | READ_DUMMY) == OK)
5846 {
5847 /* compare the two files line by line */
5848 if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count)
5849 {
5850 differ = FALSE;
5851 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
5852 if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0)
5853 {
5854 differ = TRUE;
5855 break;
5856 }
5857 }
5858 }
5859 vim_free(ea.cmd);
5860
Bram Moolenaar071d4272004-06-13 20:20:40 +00005861 /* restore curwin/curbuf and a few other things */
5862 aucmd_restbuf(&aco);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005863
5864 if (curbuf != newbuf) /* safety check */
5865 wipe_buffer(newbuf, FALSE);
5866
5867 return differ;
5868}
5869
5870/*
5871 * Wipe out a buffer and decrement the last buffer number if it was used for
5872 * this buffer. Call this to wipe out a temp buffer that does not contain any
5873 * marks.
5874 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005875 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005876wipe_buffer(
5877 buf_T *buf,
5878 int aucmd UNUSED) /* When TRUE trigger autocommands. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005879{
5880 if (buf->b_fnum == top_file_num - 1)
5881 --top_file_num;
5882
5883#ifdef FEAT_AUTOCMD
5884 if (!aucmd) /* Don't trigger BufDelete autocommands here. */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00005885 block_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005886#endif
Bram Moolenaar42ec6562012-02-22 14:58:37 +01005887 close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005888#ifdef FEAT_AUTOCMD
5889 if (!aucmd)
Bram Moolenaar78ab3312007-09-29 12:16:41 +00005890 unblock_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005891#endif
5892}