blob: 99d23ec5dfa7289a645662ffb1f9ea5f4120f1b1 [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 Moolenaar8767f522016-07-01 17:17:39 +020038static buf_T *buflist_findname_stat(char_u *ffname, stat_T *st);
39static int otherfile_buf(buf_T *buf, char_u *ffname, stat_T *stp);
40static int buf_same_ino(buf_T *buf, stat_T *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 Moolenaarb25f9a92016-07-10 18:21:50 +020070/* Number of times free_buffer() was called. */
71static int buf_free_count = 0;
72
Bram Moolenaar071d4272004-06-13 20:20:40 +000073/*
Bram Moolenaar55debbe2010-05-23 23:34:36 +020074 * Open current buffer, that is: open the memfile and read the file into
75 * memory.
76 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +000077 */
78 int
Bram Moolenaar7454a062016-01-30 15:14:10 +010079open_buffer(
80 int read_stdin, /* read file from stdin */
81 exarg_T *eap, /* for forced 'ff' and 'fenc' or NULL */
82 int flags) /* extra flags for readfile() */
Bram Moolenaar071d4272004-06-13 20:20:40 +000083{
84 int retval = OK;
85#ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020086 bufref_T old_curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +000087#endif
Bram Moolenaar6d47df72013-02-17 15:45:37 +010088#ifdef FEAT_SYN_HL
89 long old_tw = curbuf->b_p_tw;
90#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000091
92 /*
93 * The 'readonly' flag is only set when BF_NEVERLOADED is being reset.
94 * When re-entering the same buffer, it should not change, because the
95 * user may have reset the flag by hand.
96 */
97 if (readonlymode && curbuf->b_ffname != NULL
98 && (curbuf->b_flags & BF_NEVERLOADED))
99 curbuf->b_p_ro = TRUE;
100
Bram Moolenaar4770d092006-01-12 23:22:24 +0000101 if (ml_open(curbuf) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102 {
103 /*
104 * There MUST be a memfile, otherwise we can't do anything
105 * If we can't create one for the current buffer, take another buffer
106 */
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100107 close_buffer(NULL, curbuf, 0, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108 for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
109 if (curbuf->b_ml.ml_mfp != NULL)
110 break;
111 /*
112 * if there is no memfile at all, exit
Bram Moolenaare37d50a2008-08-06 17:06:04 +0000113 * This is OK, since there are no changes to lose.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000114 */
115 if (curbuf == NULL)
116 {
117 EMSG(_("E82: Cannot allocate any buffer, exiting..."));
118 getout(2);
119 }
120 EMSG(_("E83: Cannot allocate buffer, using other one..."));
121 enter_buffer(curbuf);
Bram Moolenaar6d47df72013-02-17 15:45:37 +0100122#ifdef FEAT_SYN_HL
123 if (old_tw != curbuf->b_p_tw)
124 check_colorcolumn(curwin);
125#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000126 return FAIL;
127 }
128
129#ifdef FEAT_AUTOCMD
130 /* The autocommands in readfile() may change the buffer, but only AFTER
131 * reading the file. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200132 set_bufref(&old_curbuf, curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000133 modified_was_set = FALSE;
134#endif
135
136 /* mark cursor position as being invalid */
Bram Moolenaar89c0ea42010-02-24 16:58:36 +0100137 curwin->w_valid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138
139 if (curbuf->b_ffname != NULL
140#ifdef FEAT_NETBEANS_INTG
141 && netbeansReadFile
142#endif
143 )
144 {
Bram Moolenaar426dd022016-03-15 15:09:29 +0100145 int old_msg_silent = msg_silent;
146
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147#ifdef FEAT_NETBEANS_INTG
148 int oldFire = netbeansFireChanges;
149
150 netbeansFireChanges = 0;
151#endif
Bram Moolenaar426dd022016-03-15 15:09:29 +0100152 if (shortmess(SHM_FILEINFO))
153 msg_silent = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154 retval = readfile(curbuf->b_ffname, curbuf->b_fname,
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200155 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap,
156 flags | READ_NEW);
Bram Moolenaar426dd022016-03-15 15:09:29 +0100157 msg_silent = old_msg_silent;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158#ifdef FEAT_NETBEANS_INTG
159 netbeansFireChanges = oldFire;
160#endif
161 /* Help buffer is filtered. */
162 if (curbuf->b_help)
163 fix_help_buffer();
164 }
165 else if (read_stdin)
166 {
167 int save_bin = curbuf->b_p_bin;
168 linenr_T line_count;
169
170 /*
171 * First read the text in binary mode into the buffer.
172 * Then read from that same buffer and append at the end. This makes
173 * it possible to retry when 'fileformat' or 'fileencoding' was
174 * guessed wrong.
175 */
176 curbuf->b_p_bin = TRUE;
177 retval = readfile(NULL, NULL, (linenr_T)0,
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200178 (linenr_T)0, (linenr_T)MAXLNUM, NULL,
179 flags | (READ_NEW + READ_STDIN));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180 curbuf->b_p_bin = save_bin;
181 if (retval == OK)
182 {
183 line_count = curbuf->b_ml.ml_line_count;
184 retval = readfile(NULL, NULL, (linenr_T)line_count,
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200185 (linenr_T)0, (linenr_T)MAXLNUM, eap,
186 flags | READ_BUFFER);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187 if (retval == OK)
188 {
189 /* Delete the binary lines. */
190 while (--line_count >= 0)
191 ml_delete((linenr_T)1, FALSE);
192 }
193 else
194 {
195 /* Delete the converted lines. */
196 while (curbuf->b_ml.ml_line_count > line_count)
197 ml_delete(line_count, FALSE);
198 }
199 /* Put the cursor on the first line. */
200 curwin->w_cursor.lnum = 1;
201 curwin->w_cursor.col = 0;
Bram Moolenaar512e6b82007-06-19 13:36:52 +0000202
203 /* Set or reset 'modified' before executing autocommands, so that
204 * it can be changed there. */
205 if (!readonlymode && !bufempty())
206 changed();
207 else if (retval != FAIL)
208 unchanged(curbuf, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209#ifdef FEAT_AUTOCMD
210# ifdef FEAT_EVAL
211 apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE,
212 curbuf, &retval);
213# else
214 apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf);
215# endif
216#endif
217 }
218 }
219
220 /* if first time loading this buffer, init b_chartab[] */
221 if (curbuf->b_flags & BF_NEVERLOADED)
Bram Moolenaar6bcbcc52013-11-05 07:13:41 +0100222 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000223 (void)buf_init_chartab(curbuf, FALSE);
Bram Moolenaardce7c912013-11-05 17:40:52 +0100224#ifdef FEAT_CINDENT
Bram Moolenaar6bcbcc52013-11-05 07:13:41 +0100225 parse_cino(curbuf);
Bram Moolenaardce7c912013-11-05 17:40:52 +0100226#endif
Bram Moolenaar6bcbcc52013-11-05 07:13:41 +0100227 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228
229 /*
230 * Set/reset the Changed flag first, autocmds may change the buffer.
231 * Apply the automatic commands, before processing the modelines.
232 * So the modelines have priority over auto commands.
233 */
234 /* When reading stdin, the buffer contents always needs writing, so set
235 * the changed flag. Unless in readonly mode: "ls | gview -".
236 * When interrupted and 'cpoptions' contains 'i' set changed flag. */
Bram Moolenaar512e6b82007-06-19 13:36:52 +0000237 if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000238#ifdef FEAT_AUTOCMD
239 || modified_was_set /* ":set modified" used in autocmd */
240# ifdef FEAT_EVAL
241 || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
242# endif
243#endif
Bram Moolenaar512e6b82007-06-19 13:36:52 +0000244 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000245 changed();
Bram Moolenaar512e6b82007-06-19 13:36:52 +0000246 else if (retval != FAIL && !read_stdin)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000247 unchanged(curbuf, FALSE);
248 save_file_ff(curbuf); /* keep this fileformat */
249
250 /* require "!" to overwrite the file, because it wasn't read completely */
251#ifdef FEAT_EVAL
252 if (aborting())
253#else
254 if (got_int)
255#endif
256 curbuf->b_flags |= BF_READERR;
257
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000258#ifdef FEAT_FOLDING
259 /* Need to update automatic folding. Do this before the autocommands,
260 * they may use the fold info. */
261 foldUpdateAll(curwin);
262#endif
263
Bram Moolenaar071d4272004-06-13 20:20:40 +0000264#ifdef FEAT_AUTOCMD
265 /* need to set w_topline, unless some autocommand already did that. */
266 if (!(curwin->w_valid & VALID_TOPLINE))
267 {
268 curwin->w_topline = 1;
269# ifdef FEAT_DIFF
270 curwin->w_topfill = 0;
271# endif
272 }
273# ifdef FEAT_EVAL
274 apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, &retval);
275# else
276 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
277# endif
278#endif
279
280 if (retval != FAIL)
281 {
282#ifdef FEAT_AUTOCMD
283 /*
284 * The autocommands may have changed the current buffer. Apply the
285 * modelines to the correct buffer, if it still exists and is loaded.
286 */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200287 if (bufref_valid(&old_curbuf) && old_curbuf.br_buf->b_ml.ml_mfp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000288 {
289 aco_save_T aco;
290
291 /* Go to the buffer that was opened. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200292 aucmd_prepbuf(&aco, old_curbuf.br_buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000293#endif
Bram Moolenaara3227e22006-03-08 21:32:40 +0000294 do_modelines(0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED);
296
297#ifdef FEAT_AUTOCMD
298# ifdef FEAT_EVAL
299 apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf,
300 &retval);
301# else
302 apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
303# endif
304
305 /* restore curwin/curbuf and a few other things */
306 aucmd_restbuf(&aco);
307 }
308#endif
309 }
310
Bram Moolenaar071d4272004-06-13 20:20:40 +0000311 return retval;
312}
313
314/*
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200315 * Store "buf" in "bufref" and set the free count.
316 */
317 void
318set_bufref(bufref_T *bufref, buf_T *buf)
319{
320 bufref->br_buf = buf;
321 bufref->br_buf_free_count = buf_free_count;
322}
323
324/*
325 * Return TRUE if "bufref->br_buf" points to a valid buffer.
326 * Only goes through the buffer list if buf_free_count changed.
327 */
328 int
329bufref_valid(bufref_T *bufref)
330{
331 return bufref->br_buf_free_count == buf_free_count
332 ? TRUE : buf_valid(bufref->br_buf);
333}
334
335/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000336 * Return TRUE if "buf" points to a valid buffer (in the buffer list).
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200337 * This can be slow if there are many buffers, prefer using bufref_valid().
Bram Moolenaar071d4272004-06-13 20:20:40 +0000338 */
339 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100340buf_valid(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000341{
342 buf_T *bp;
343
Bram Moolenaar82404332016-07-10 17:00:38 +0200344 /* Assume that we more often have a recent buffer, start with the last
345 * one. */
346 for (bp = lastbuf; bp != NULL; bp = bp->b_prev)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 if (bp == buf)
348 return TRUE;
349 return FALSE;
350}
351
352/*
Bram Moolenaar480778b2016-07-14 22:09:39 +0200353 * A hash table used to quickly lookup a buffer by its number.
354 */
355static hashtab_T buf_hashtab;
356
357 static void
358buf_hashtab_add(buf_T *buf)
359{
360 sprintf((char *)buf->b_key, "%x", buf->b_fnum);
361 if (hash_add(&buf_hashtab, buf->b_key) == FAIL)
362 EMSG(_("E931: Buffer cannot be registered"));
363}
364
365 static void
366buf_hashtab_remove(buf_T *buf)
367{
368 hashitem_T *hi = hash_find(&buf_hashtab, buf->b_key);
369
370 if (!HASHITEM_EMPTY(hi))
371 hash_remove(&buf_hashtab, hi);
372}
373
374/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375 * Close the link to a buffer.
376 * "action" is used when there is no longer a window for the buffer.
377 * It can be:
378 * 0 buffer becomes hidden
379 * DOBUF_UNLOAD buffer is unloaded
380 * DOBUF_DELETE buffer is unloaded and removed from buffer list
381 * DOBUF_WIPE buffer is unloaded and really deleted
382 * When doing all but the first one on the current buffer, the caller should
383 * get a new buffer very soon!
384 *
385 * The 'bufhidden' option can force freeing and deleting.
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100386 *
387 * When "abort_if_last" is TRUE then do not close the buffer if autocommands
388 * cause there to be only one window with this buffer. e.g. when ":quit" is
389 * supposed to close the window but autocommands close all other windows.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390 */
391 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100392close_buffer(
393 win_T *win, /* if not NULL, set b_last_cursor */
394 buf_T *buf,
395 int action,
396 int abort_if_last UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000397{
398#ifdef FEAT_AUTOCMD
399 int is_curbuf;
Bram Moolenaar2660c0e2010-01-19 14:59:56 +0100400 int nwindows;
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200401 bufref_T bufref;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000402#endif
403 int unload_buf = (action != 0);
404 int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
405 int wipe_buf = (action == DOBUF_WIPE);
406
407#ifdef FEAT_QUICKFIX
408 /*
409 * Force unloading or deleting when 'bufhidden' says so.
410 * The caller must take care of NOT deleting/freeing when 'bufhidden' is
411 * "hide" (otherwise we could never free or delete a buffer).
412 */
413 if (buf->b_p_bh[0] == 'd') /* 'bufhidden' == "delete" */
414 {
415 del_buf = TRUE;
416 unload_buf = TRUE;
417 }
418 else if (buf->b_p_bh[0] == 'w') /* 'bufhidden' == "wipe" */
419 {
420 del_buf = TRUE;
421 unload_buf = TRUE;
422 wipe_buf = TRUE;
423 }
424 else if (buf->b_p_bh[0] == 'u') /* 'bufhidden' == "unload" */
425 unload_buf = TRUE;
426#endif
427
Bram Moolenaar3be85852014-06-12 14:01:31 +0200428 if (win != NULL
429#ifdef FEAT_WINDOWS
430 && win_valid(win) /* in case autocommands closed the window */
431#endif
432 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000433 {
434 /* Set b_last_cursor when closing the last window for the buffer.
435 * Remember the last cursor position and window options of the buffer.
436 * This used to be only for the current window, but then options like
437 * 'foldmethod' may be lost with a ":only" command. */
438 if (buf->b_nwindows == 1)
439 set_last_cursor(win);
440 buflist_setfpos(buf, win,
441 win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum,
442 win->w_cursor.col, TRUE);
443 }
444
445#ifdef FEAT_AUTOCMD
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200446 set_bufref(&bufref, buf);
447
Bram Moolenaar071d4272004-06-13 20:20:40 +0000448 /* When the buffer is no longer in a window, trigger BufWinLeave */
449 if (buf->b_nwindows == 1)
450 {
Bram Moolenaar362ce482012-06-06 19:02:45 +0200451 buf->b_closing = TRUE;
Bram Moolenaar82404332016-07-10 17:00:38 +0200452 if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
453 FALSE, buf)
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200454 && !bufref_valid(&bufref))
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100455 {
Bram Moolenaar362ce482012-06-06 19:02:45 +0200456 /* Autocommands deleted the buffer. */
457aucmd_abort:
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100458 EMSG(_(e_auabort));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459 return;
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100460 }
Bram Moolenaar362ce482012-06-06 19:02:45 +0200461 buf->b_closing = FALSE;
462 if (abort_if_last && one_window())
463 /* Autocommands made this the only window. */
464 goto aucmd_abort;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000465
466 /* When the buffer becomes hidden, but is not unloaded, trigger
467 * BufHidden */
468 if (!unload_buf)
469 {
Bram Moolenaar362ce482012-06-06 19:02:45 +0200470 buf->b_closing = TRUE;
Bram Moolenaar82404332016-07-10 17:00:38 +0200471 if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
472 FALSE, buf)
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200473 && !bufref_valid(&bufref))
Bram Moolenaar362ce482012-06-06 19:02:45 +0200474 /* Autocommands deleted the buffer. */
475 goto aucmd_abort;
476 buf->b_closing = FALSE;
477 if (abort_if_last && one_window())
478 /* Autocommands made this the only window. */
479 goto aucmd_abort;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000480 }
481# ifdef FEAT_EVAL
482 if (aborting()) /* autocmds may abort script processing */
483 return;
484# endif
485 }
486 nwindows = buf->b_nwindows;
487#endif
488
489 /* decrease the link count from windows (unless not in any window) */
490 if (buf->b_nwindows > 0)
491 --buf->b_nwindows;
492
493 /* Return when a window is displaying the buffer or when it's not
494 * unloaded. */
495 if (buf->b_nwindows > 0 || !unload_buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000497
498 /* Always remove the buffer when there is no file name. */
499 if (buf->b_ffname == NULL)
500 del_buf = TRUE;
501
502 /*
503 * Free all things allocated for this buffer.
504 * Also calls the "BufDelete" autocommands when del_buf is TRUE.
505 */
506#ifdef FEAT_AUTOCMD
507 /* Remember if we are closing the current buffer. Restore the number of
508 * windows, so that autocommands in buf_freeall() don't get confused. */
509 is_curbuf = (buf == curbuf);
510 buf->b_nwindows = nwindows;
511#endif
512
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200513 buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000514
515#ifdef FEAT_AUTOCMD
516 /* Autocommands may have deleted the buffer. */
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200517 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 return;
519# ifdef FEAT_EVAL
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000520 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 return;
522# endif
523
Bram Moolenaar071d4272004-06-13 20:20:40 +0000524 /*
525 * It's possible that autocommands change curbuf to the one being deleted.
526 * This might cause the previous curbuf to be deleted unexpectedly. But
527 * in some cases it's OK to delete the curbuf, because a new one is
528 * obtained anyway. Therefore only return if curbuf changed to the
529 * deleted buffer.
530 */
531 if (buf == curbuf && !is_curbuf)
532 return;
Bram Moolenaar30445cb2016-07-09 15:21:02 +0200533
534 if (
535#ifdef FEAT_WINDOWS
536 win_valid(win) &&
537#else
538 win != NULL &&
539#endif
540 win->w_buffer == buf)
541 win->w_buffer = NULL; /* make sure we don't use the buffer now */
542
543 /* Autocommands may have opened or closed windows for this buffer.
544 * Decrement the count for the close we do here. */
545 if (buf->b_nwindows > 0)
546 --buf->b_nwindows;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547#endif
548
Bram Moolenaar498efdb2006-09-05 14:31:54 +0000549 /* Change directories when the 'acd' option is set. */
550 DO_AUTOCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551
552 /*
553 * Remove the buffer from the list.
554 */
555 if (wipe_buf)
556 {
557#ifdef FEAT_SUN_WORKSHOP
558 if (usingSunWorkShop)
559 workshop_file_closed_lineno((char *)buf->b_ffname,
560 (int)buf->b_last_cursor.lnum);
561#endif
562 vim_free(buf->b_ffname);
563 vim_free(buf->b_sfname);
564 if (buf->b_prev == NULL)
565 firstbuf = buf->b_next;
566 else
567 buf->b_prev->b_next = buf->b_next;
568 if (buf->b_next == NULL)
569 lastbuf = buf->b_prev;
570 else
571 buf->b_next->b_prev = buf->b_prev;
572 free_buffer(buf);
573 }
574 else
575 {
576 if (del_buf)
577 {
578 /* Free all internal variables and reset option values, to make
579 * ":bdel" compatible with Vim 5.7. */
580 free_buffer_stuff(buf, TRUE);
581
582 /* Make it look like a new buffer. */
583 buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
584
585 /* Init the options when loaded again. */
586 buf->b_p_initialized = FALSE;
587 }
588 buf_clear_file(buf);
589 if (del_buf)
590 buf->b_p_bl = FALSE;
591 }
592}
593
594/*
595 * Make buffer not contain a file.
596 */
597 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100598buf_clear_file(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599{
600 buf->b_ml.ml_line_count = 1;
601 unchanged(buf, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602 buf->b_shortname = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 buf->b_p_eol = TRUE;
604 buf->b_start_eol = TRUE;
605#ifdef FEAT_MBYTE
606 buf->b_p_bomb = FALSE;
Bram Moolenaar83eb8852007-08-12 13:51:26 +0000607 buf->b_start_bomb = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608#endif
609 buf->b_ml.ml_mfp = NULL;
610 buf->b_ml.ml_flags = ML_EMPTY; /* empty buffer */
611#ifdef FEAT_NETBEANS_INTG
612 netbeans_deleted_all_lines(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613#endif
614}
615
616/*
617 * buf_freeall() - free all things allocated for a buffer that are related to
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200618 * the file. flags:
619 * BFA_DEL buffer is going to be deleted
620 * BFA_WIPE buffer is going to be wiped out
621 * BFA_KEEP_UNDO do not free undo information
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100624buf_freeall(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625{
626#ifdef FEAT_AUTOCMD
627 int is_curbuf = (buf == curbuf);
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200628 bufref_T bufref;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629
Bram Moolenaar362ce482012-06-06 19:02:45 +0200630 buf->b_closing = TRUE;
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200631 set_bufref(&bufref, buf);
Bram Moolenaarc67e8922016-05-24 16:07:40 +0200632 if (buf->b_ml.ml_mfp != NULL)
633 {
Bram Moolenaar82404332016-07-10 17:00:38 +0200634 if (apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname,
635 FALSE, buf)
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200636 && !bufref_valid(&bufref))
637 /* autocommands deleted the buffer */
Bram Moolenaarc67e8922016-05-24 16:07:40 +0200638 return;
639 }
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200640 if ((flags & BFA_DEL) && buf->b_p_bl)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 {
Bram Moolenaar82404332016-07-10 17:00:38 +0200642 if (apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname,
643 FALSE, buf)
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200644 && !bufref_valid(&bufref))
645 /* autocommands deleted the buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 return;
647 }
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200648 if (flags & BFA_WIPE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 {
Bram Moolenaar82404332016-07-10 17:00:38 +0200650 if (apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname,
651 FALSE, buf)
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200652 && !bufref_valid(&bufref))
653 /* autocommands deleted the buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654 return;
655 }
Bram Moolenaar362ce482012-06-06 19:02:45 +0200656 buf->b_closing = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000657# ifdef FEAT_EVAL
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000658 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000659 return;
660# endif
661
662 /*
663 * It's possible that autocommands change curbuf to the one being deleted.
664 * This might cause curbuf to be deleted unexpectedly. But in some cases
665 * it's OK to delete the curbuf, because a new one is obtained anyway.
666 * Therefore only return if curbuf changed to the deleted buffer.
667 */
668 if (buf == curbuf && !is_curbuf)
669 return;
670#endif
671#ifdef FEAT_DIFF
672 diff_buf_delete(buf); /* Can't use 'diff' for unloaded buffer. */
673#endif
Bram Moolenaara971b822011-09-14 14:43:25 +0200674#ifdef FEAT_SYN_HL
Bram Moolenaar89c71222011-11-30 15:40:56 +0100675 /* Remove any ownsyntax, unless exiting. */
676 if (firstwin != NULL && curwin->w_buffer == buf)
677 reset_synblock(curwin);
Bram Moolenaara971b822011-09-14 14:43:25 +0200678#endif
Bram Moolenaarb6799ac2007-05-10 16:44:05 +0000679
680#ifdef FEAT_FOLDING
681 /* No folds in an empty buffer. */
682# ifdef FEAT_WINDOWS
683 {
684 win_T *win;
685 tabpage_T *tp;
686
687 FOR_ALL_TAB_WINDOWS(tp, win)
688 if (win->w_buffer == buf)
689 clearFolding(win);
690 }
691# else
692 if (curwin->w_buffer == buf)
693 clearFolding(curwin);
694# endif
695#endif
696
Bram Moolenaar071d4272004-06-13 20:20:40 +0000697#ifdef FEAT_TCL
698 tcl_buffer_free(buf);
699#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700 ml_close(buf, TRUE); /* close and delete the memline/memfile */
701 buf->b_ml.ml_line_count = 0; /* no lines in buffer */
Bram Moolenaar59f931e2010-07-24 20:27:03 +0200702 if ((flags & BFA_KEEP_UNDO) == 0)
703 {
704 u_blockfree(buf); /* free the memory allocated for undo */
705 u_clearall(buf); /* reset all undo information */
706 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000707#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +0200708 syntax_clear(&buf->b_s); /* reset syntax info */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709#endif
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000710 buf->b_flags &= ~BF_READERR; /* a read error is no longer relevant */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711}
712
713/*
714 * Free a buffer structure and the things it contains related to the buffer
715 * itself (not the file, that must have been done already).
716 */
717 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100718free_buffer(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719{
Bram Moolenaarb25f9a92016-07-10 18:21:50 +0200720 ++buf_free_count;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000721 free_buffer_stuff(buf, TRUE);
Bram Moolenaar429fa852013-04-15 12:27:36 +0200722#ifdef FEAT_EVAL
723 unref_var_dict(buf->b_vars);
724#endif
Bram Moolenaar0ba04292010-07-14 23:23:17 +0200725#ifdef FEAT_LUA
726 lua_buffer_free(buf);
727#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000728#ifdef FEAT_MZSCHEME
729 mzscheme_buffer_free(buf);
730#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731#ifdef FEAT_PERL
732 perl_buf_free(buf);
733#endif
734#ifdef FEAT_PYTHON
735 python_buffer_free(buf);
736#endif
Bram Moolenaarbd5e15f2010-07-17 21:19:38 +0200737#ifdef FEAT_PYTHON3
738 python3_buffer_free(buf);
739#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740#ifdef FEAT_RUBY
741 ruby_buffer_free(buf);
742#endif
Bram Moolenaare0f76d02016-05-09 20:38:53 +0200743#ifdef FEAT_JOB_CHANNEL
744 channel_buffer_free(buf);
745#endif
Bram Moolenaar480778b2016-07-14 22:09:39 +0200746
747 buf_hashtab_remove(buf);
748
Bram Moolenaar9280e3f2016-07-14 23:03:19 +0200749#ifdef FEAT_AUTOCMD
750 aubuflocal_remove(buf);
751
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +0200752 if (autocmd_busy)
753 {
754 /* Do not free the buffer structure while autocommands are executing,
755 * it's still needed. Free it when autocmd_busy is reset. */
756 buf->b_next = au_pending_free_buf;
757 au_pending_free_buf = buf;
758 }
759 else
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +0000760#endif
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +0200761 vim_free(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762}
763
764/*
765 * Free stuff in the buffer for ":bdel" and when wiping out the buffer.
766 */
767 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100768free_buffer_stuff(
769 buf_T *buf,
770 int free_options) /* free options as well */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771{
772 if (free_options)
773 {
774 clear_wininfo(buf); /* including window-local options */
775 free_buf_options(buf, TRUE);
Bram Moolenaarbeca0552010-10-27 16:18:00 +0200776#ifdef FEAT_SPELL
777 ga_clear(&buf->b_s.b_langp);
778#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 }
780#ifdef FEAT_EVAL
Bram Moolenaar429fa852013-04-15 12:27:36 +0200781 vars_clear(&buf->b_vars->dv_hashtab); /* free all internal variables */
782 hash_init(&buf->b_vars->dv_hashtab);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783#endif
784#ifdef FEAT_USR_CMDS
785 uc_clear(&buf->b_ucmds); /* clear local user commands */
786#endif
787#ifdef FEAT_SIGNS
788 buf_delete_signs(buf); /* delete any signs */
789#endif
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +0000790#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200791 netbeans_file_killed(buf);
Bram Moolenaard7f8f5c2009-01-06 15:14:30 +0000792#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793#ifdef FEAT_LOCALMAP
794 map_clear_int(buf, MAP_ALL_MODES, TRUE, FALSE); /* clear local mappings */
795 map_clear_int(buf, MAP_ALL_MODES, TRUE, TRUE); /* clear local abbrevs */
796#endif
797#ifdef FEAT_MBYTE
798 vim_free(buf->b_start_fenc);
799 buf->b_start_fenc = NULL;
800#endif
801}
802
803/*
804 * Free the b_wininfo list for buffer "buf".
805 */
806 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100807clear_wininfo(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808{
809 wininfo_T *wip;
810
811 while (buf->b_wininfo != NULL)
812 {
813 wip = buf->b_wininfo;
814 buf->b_wininfo = wip->wi_next;
815 if (wip->wi_optset)
816 {
817 clear_winopt(&wip->wi_opt);
818#ifdef FEAT_FOLDING
819 deleteFoldRecurse(&wip->wi_folds);
820#endif
821 }
822 vim_free(wip);
823 }
824}
825
826#if defined(FEAT_LISTCMDS) || defined(PROTO)
827/*
828 * Go to another buffer. Handles the result of the ATTENTION dialog.
829 */
830 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100831goto_buffer(
832 exarg_T *eap,
833 int start,
834 int dir,
835 int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836{
Bram Moolenaare64ac772005-12-07 20:54:59 +0000837# if defined(FEAT_WINDOWS) && defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200838 bufref_T old_curbuf;
839
840 set_bufref(&old_curbuf, curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841
842 swap_exists_action = SEA_DIALOG;
843# endif
844 (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
845 start, dir, count, eap->forceit);
Bram Moolenaare64ac772005-12-07 20:54:59 +0000846# if defined(FEAT_WINDOWS) && defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
848 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000849# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
850 cleanup_T cs;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000851
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000852 /* Reset the error/interrupt/exception state here so that
853 * aborting() returns FALSE when closing a window. */
854 enter_cleanup(&cs);
855# endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000856
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000857 /* Quitting means closing the split window, nothing else. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000858 win_close(curwin, TRUE);
859 swap_exists_action = SEA_NONE;
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000860 swap_exists_did_quit = TRUE;
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000861
862# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
863 /* Restore the error/interrupt/exception state if not discarded by a
864 * new aborting error, interrupt, or uncaught exception. */
865 leave_cleanup(&cs);
866# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 }
868 else
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200869 handle_swap_exists(&old_curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870# endif
871}
872#endif
873
Bram Moolenaare64ac772005-12-07 20:54:59 +0000874#if defined(HAS_SWAP_EXISTS_ACTION) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875/*
876 * Handle the situation of swap_exists_action being set.
877 * It is allowed for "old_curbuf" to be NULL or invalid.
878 */
879 void
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200880handle_swap_exists(bufref_T *old_curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000881{
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000882# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
883 cleanup_T cs;
884# endif
Bram Moolenaar6d47df72013-02-17 15:45:37 +0100885#ifdef FEAT_SYN_HL
886 long old_tw = curbuf->b_p_tw;
887#endif
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200888 buf_T *buf;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000889
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890 if (swap_exists_action == SEA_QUIT)
891 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000892# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
893 /* Reset the error/interrupt/exception state here so that
894 * aborting() returns FALSE when closing a buffer. */
895 enter_cleanup(&cs);
896# endif
897
Bram Moolenaar071d4272004-06-13 20:20:40 +0000898 /* User selected Quit at ATTENTION prompt. Go back to previous
899 * buffer. If that buffer is gone or the same as the current one,
900 * open a new, empty buffer. */
901 swap_exists_action = SEA_NONE; /* don't want it again */
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000902 swap_exists_did_quit = TRUE;
Bram Moolenaar42ec6562012-02-22 14:58:37 +0100903 close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200904 if (old_curbuf == NULL || !bufref_valid(old_curbuf)
905 || old_curbuf->br_buf == curbuf)
906 buf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
907 else
908 buf = old_curbuf->br_buf;
909 if (buf != NULL)
Bram Moolenaar6d47df72013-02-17 15:45:37 +0100910 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200911 enter_buffer(buf);
Bram Moolenaar6d47df72013-02-17 15:45:37 +0100912#ifdef FEAT_SYN_HL
913 if (old_tw != curbuf->b_p_tw)
914 check_colorcolumn(curwin);
915#endif
916 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917 /* If "old_curbuf" is NULL we are in big trouble here... */
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000918
919# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
920 /* Restore the error/interrupt/exception state if not discarded by a
921 * new aborting error, interrupt, or uncaught exception. */
922 leave_cleanup(&cs);
923# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924 }
925 else if (swap_exists_action == SEA_RECOVER)
926 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000927# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
928 /* Reset the error/interrupt/exception state here so that
929 * aborting() returns FALSE when closing a buffer. */
930 enter_cleanup(&cs);
931# endif
932
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933 /* User selected Recover at ATTENTION prompt. */
934 msg_scroll = TRUE;
935 ml_recover();
936 MSG_PUTS("\n"); /* don't overwrite the last message */
937 cmdline_row = msg_row;
Bram Moolenaara3227e22006-03-08 21:32:40 +0000938 do_modelines(0);
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000939
940# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
941 /* Restore the error/interrupt/exception state if not discarded by a
942 * new aborting error, interrupt, or uncaught exception. */
943 leave_cleanup(&cs);
944# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000945 }
946 swap_exists_action = SEA_NONE;
947}
948#endif
949
950#if defined(FEAT_LISTCMDS) || defined(PROTO)
951/*
952 * do_bufdel() - delete or unload buffer(s)
953 *
954 * addr_count == 0: ":bdel" - delete current buffer
955 * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
956 * buffer "end_bnr", then any other arguments.
957 * addr_count == 2: ":N,N bdel" - delete buffers in range
958 *
959 * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
960 * DOBUF_DEL (":bdel")
961 *
962 * Returns error message or NULL
963 */
964 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100965do_bufdel(
966 int command,
967 char_u *arg, /* pointer to extra arguments */
968 int addr_count,
969 int start_bnr, /* first buffer number in a range */
970 int end_bnr, /* buffer nr or last buffer nr in a range */
971 int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000972{
973 int do_current = 0; /* delete current buffer? */
974 int deleted = 0; /* number of buffers deleted */
975 char_u *errormsg = NULL; /* return value */
976 int bnr; /* buffer number */
977 char_u *p;
978
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979 if (addr_count == 0)
980 {
981 (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
982 }
983 else
984 {
985 if (addr_count == 2)
986 {
987 if (*arg) /* both range and argument is not allowed */
988 return (char_u *)_(e_trailing);
989 bnr = start_bnr;
990 }
991 else /* addr_count == 1 */
992 bnr = end_bnr;
993
994 for ( ;!got_int; ui_breakcheck())
995 {
996 /*
997 * delete the current buffer last, otherwise when the
998 * current buffer is deleted, the next buffer becomes
999 * the current one and will be loaded, which may then
1000 * also be deleted, etc.
1001 */
1002 if (bnr == curbuf->b_fnum)
1003 do_current = bnr;
1004 else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
1005 forceit) == OK)
1006 ++deleted;
1007
1008 /*
1009 * find next buffer number to delete/unload
1010 */
1011 if (addr_count == 2)
1012 {
1013 if (++bnr > end_bnr)
1014 break;
1015 }
1016 else /* addr_count == 1 */
1017 {
1018 arg = skipwhite(arg);
1019 if (*arg == NUL)
1020 break;
1021 if (!VIM_ISDIGIT(*arg))
1022 {
1023 p = skiptowhite_esc(arg);
Bram Moolenaar0c279bb2013-03-19 14:25:54 +01001024 bnr = buflist_findpat(arg, p, command == DOBUF_WIPE,
1025 FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001026 if (bnr < 0) /* failed */
1027 break;
1028 arg = p;
1029 }
1030 else
1031 bnr = getdigits(&arg);
1032 }
1033 }
1034 if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
1035 FORWARD, do_current, forceit) == OK)
1036 ++deleted;
1037
1038 if (deleted == 0)
1039 {
1040 if (command == DOBUF_UNLOAD)
Bram Moolenaar51485f02005-06-04 21:55:20 +00001041 STRCPY(IObuff, _("E515: No buffers were unloaded"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001042 else if (command == DOBUF_DEL)
Bram Moolenaar51485f02005-06-04 21:55:20 +00001043 STRCPY(IObuff, _("E516: No buffers were deleted"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001044 else
Bram Moolenaar51485f02005-06-04 21:55:20 +00001045 STRCPY(IObuff, _("E517: No buffers were wiped out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 errormsg = IObuff;
1047 }
1048 else if (deleted >= p_report)
1049 {
1050 if (command == DOBUF_UNLOAD)
1051 {
1052 if (deleted == 1)
1053 MSG(_("1 buffer unloaded"));
1054 else
1055 smsg((char_u *)_("%d buffers unloaded"), deleted);
1056 }
1057 else if (command == DOBUF_DEL)
1058 {
1059 if (deleted == 1)
1060 MSG(_("1 buffer deleted"));
1061 else
1062 smsg((char_u *)_("%d buffers deleted"), deleted);
1063 }
1064 else
1065 {
1066 if (deleted == 1)
1067 MSG(_("1 buffer wiped out"));
1068 else
1069 smsg((char_u *)_("%d buffers wiped out"), deleted);
1070 }
1071 }
1072 }
1073
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074
1075 return errormsg;
1076}
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02001077#endif /* FEAT_LISTCMDS */
1078
1079#if defined(FEAT_LISTCMDS) || defined(FEAT_PYTHON) \
1080 || defined(FEAT_PYTHON3) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001082static int empty_curbuf(int close_others, int forceit, int action);
Bram Moolenaara02471e2014-01-10 16:43:14 +01001083
1084/*
1085 * Make the current buffer empty.
1086 * Used when it is wiped out and it's the last buffer.
1087 */
1088 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01001089empty_curbuf(
1090 int close_others,
1091 int forceit,
1092 int action)
Bram Moolenaara02471e2014-01-10 16:43:14 +01001093{
1094 int retval;
1095 buf_T *buf = curbuf;
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001096 bufref_T bufref;
Bram Moolenaara02471e2014-01-10 16:43:14 +01001097
1098 if (action == DOBUF_UNLOAD)
1099 {
1100 EMSG(_("E90: Cannot unload last buffer"));
1101 return FAIL;
1102 }
1103
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001104 set_bufref(&bufref, buf);
Bram Moolenaara02471e2014-01-10 16:43:14 +01001105#ifdef FEAT_WINDOWS
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001106 if (close_others)
1107 /* Close any other windows on this buffer, then make it empty. */
Bram Moolenaara02471e2014-01-10 16:43:14 +01001108 close_windows(buf, TRUE);
1109#endif
Bram Moolenaara02471e2014-01-10 16:43:14 +01001110
1111 setpcmark();
1112 retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
1113 forceit ? ECMD_FORCEIT : 0, curwin);
1114
1115 /*
1116 * do_ecmd() may create a new buffer, then we have to delete
1117 * the old one. But do_ecmd() may have done that already, check
1118 * if the buffer still exists.
1119 */
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001120 if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0)
Bram Moolenaara02471e2014-01-10 16:43:14 +01001121 close_buffer(NULL, buf, action, FALSE);
1122 if (!close_others)
1123 need_fileinfo = FALSE;
1124 return retval;
1125}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126/*
1127 * Implementation of the commands for the buffer list.
1128 *
1129 * action == DOBUF_GOTO go to specified buffer
1130 * action == DOBUF_SPLIT split window and go to specified buffer
1131 * action == DOBUF_UNLOAD unload specified buffer(s)
1132 * action == DOBUF_DEL delete specified buffer(s) from buffer list
1133 * action == DOBUF_WIPE delete specified buffer(s) really
1134 *
1135 * start == DOBUF_CURRENT go to "count" buffer from current buffer
1136 * start == DOBUF_FIRST go to "count" buffer from first buffer
1137 * start == DOBUF_LAST go to "count" buffer from last buffer
1138 * start == DOBUF_MOD go to "count" modified buffer from current buffer
1139 *
1140 * Return FAIL or OK.
1141 */
1142 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01001143do_buffer(
1144 int action,
1145 int start,
1146 int dir, /* FORWARD or BACKWARD */
1147 int count, /* buffer number or number of buffers */
1148 int forceit) /* TRUE for :...! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001149{
1150 buf_T *buf;
1151 buf_T *bp;
1152 int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
1153 || action == DOBUF_WIPE);
1154
1155 switch (start)
1156 {
1157 case DOBUF_FIRST: buf = firstbuf; break;
1158 case DOBUF_LAST: buf = lastbuf; break;
1159 default: buf = curbuf; break;
1160 }
1161 if (start == DOBUF_MOD) /* find next modified buffer */
1162 {
1163 while (count-- > 0)
1164 {
1165 do
1166 {
1167 buf = buf->b_next;
1168 if (buf == NULL)
1169 buf = firstbuf;
1170 }
1171 while (buf != curbuf && !bufIsChanged(buf));
1172 }
1173 if (!bufIsChanged(buf))
1174 {
1175 EMSG(_("E84: No modified buffer found"));
1176 return FAIL;
1177 }
1178 }
1179 else if (start == DOBUF_FIRST && count) /* find specified buffer number */
1180 {
1181 while (buf != NULL && buf->b_fnum != count)
1182 buf = buf->b_next;
1183 }
1184 else
1185 {
1186 bp = NULL;
1187 while (count > 0 || (!unload && !buf->b_p_bl && bp != buf))
1188 {
1189 /* remember the buffer where we start, we come back there when all
1190 * buffers are unlisted. */
1191 if (bp == NULL)
1192 bp = buf;
1193 if (dir == FORWARD)
1194 {
1195 buf = buf->b_next;
1196 if (buf == NULL)
1197 buf = firstbuf;
1198 }
1199 else
1200 {
1201 buf = buf->b_prev;
1202 if (buf == NULL)
1203 buf = lastbuf;
1204 }
1205 /* don't count unlisted buffers */
1206 if (unload || buf->b_p_bl)
1207 {
1208 --count;
1209 bp = NULL; /* use this buffer as new starting point */
1210 }
1211 if (bp == buf)
1212 {
1213 /* back where we started, didn't find anything. */
1214 EMSG(_("E85: There is no listed buffer"));
1215 return FAIL;
1216 }
1217 }
1218 }
1219
1220 if (buf == NULL) /* could not find it */
1221 {
1222 if (start == DOBUF_FIRST)
1223 {
1224 /* don't warn when deleting */
1225 if (!unload)
Bram Moolenaar3b3a9492015-01-27 18:44:16 +01001226 EMSGN(_(e_nobufnr), count);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227 }
1228 else if (dir == FORWARD)
1229 EMSG(_("E87: Cannot go beyond last buffer"));
1230 else
1231 EMSG(_("E88: Cannot go before first buffer"));
1232 return FAIL;
1233 }
1234
1235#ifdef FEAT_GUI
1236 need_mouse_correct = TRUE;
1237#endif
1238
1239#ifdef FEAT_LISTCMDS
1240 /*
1241 * delete buffer buf from memory and/or the list
1242 */
1243 if (unload)
1244 {
1245 int forward;
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001246# if defined(FEAT_AUTOCMD) || defined(FEAT_WINDOWS)
1247 bufref_T bufref;
1248
1249 set_bufref(&bufref, buf);
1250# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251
1252 /* When unloading or deleting a buffer that's already unloaded and
1253 * unlisted: fail silently. */
1254 if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl)
1255 return FAIL;
1256
1257 if (!forceit && bufIsChanged(buf))
1258 {
1259#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1260 if ((p_confirm || cmdmod.confirm) && p_write)
1261 {
1262 dialog_changed(buf, FALSE);
1263# ifdef FEAT_AUTOCMD
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001264 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 /* Autocommand deleted buffer, oops! It's not changed
1266 * now. */
1267 return FAIL;
1268# endif
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001269 /* If it's still changed fail silently, the dialog already
1270 * mentioned why it fails. */
1271 if (bufIsChanged(buf))
1272 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001274 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001275#endif
1276 {
1277 EMSGN(_("E89: No write since last change for buffer %ld (add ! to override)"),
1278 buf->b_fnum);
1279 return FAIL;
1280 }
1281 }
1282
1283 /*
1284 * If deleting the last (listed) buffer, make it empty.
1285 * The last (listed) buffer cannot be unloaded.
1286 */
1287 for (bp = firstbuf; bp != NULL; bp = bp->b_next)
1288 if (bp->b_p_bl && bp != buf)
1289 break;
1290 if (bp == NULL && buf == curbuf)
Bram Moolenaara02471e2014-01-10 16:43:14 +01001291 return empty_curbuf(TRUE, forceit, action);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292
1293#ifdef FEAT_WINDOWS
1294 /*
1295 * If the deleted buffer is the current one, close the current window
Bram Moolenaarf740b292006-02-16 22:11:02 +00001296 * (unless it's the only window). Repeat this so long as we end up in
1297 * a window with this buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001298 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001299 while (buf == curbuf
Bram Moolenaar362ce482012-06-06 19:02:45 +02001300# ifdef FEAT_AUTOCMD
1301 && !(curwin->w_closing || curwin->w_buffer->b_closing)
1302# endif
Bram Moolenaarf740b292006-02-16 22:11:02 +00001303 && (firstwin != lastwin || first_tabpage->tp_next != NULL))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02001304 {
1305 if (win_close(curwin, FALSE) == FAIL)
1306 break;
1307 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308#endif
1309
1310 /*
1311 * If the buffer to be deleted is not the current one, delete it here.
1312 */
1313 if (buf != curbuf)
1314 {
1315#ifdef FEAT_WINDOWS
Bram Moolenaarf740b292006-02-16 22:11:02 +00001316 close_windows(buf, FALSE);
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001317 if (buf != curbuf && bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001318#endif
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001319 if (buf->b_nwindows <= 0)
1320 close_buffer(NULL, buf, action, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321 return OK;
1322 }
1323
1324 /*
1325 * Deleting the current buffer: Need to find another buffer to go to.
Bram Moolenaara02471e2014-01-10 16:43:14 +01001326 * There should be another, otherwise it would have been handled
1327 * above. However, autocommands may have deleted all buffers.
Bram Moolenaar19ff9bf2016-07-10 19:03:57 +02001328 * First use au_new_curbuf.br_buf, if it is valid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001329 * Then prefer the buffer we most recently visited.
1330 * Else try to find one that is loaded, after the current buffer,
1331 * then before the current buffer.
1332 * Finally use any buffer.
1333 */
1334 buf = NULL; /* selected buffer */
1335 bp = NULL; /* used when no loaded buffer found */
1336#ifdef FEAT_AUTOCMD
Bram Moolenaar19ff9bf2016-07-10 19:03:57 +02001337 if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf))
1338 buf = au_new_curbuf.br_buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339# ifdef FEAT_JUMPLIST
1340 else
1341# endif
1342#endif
1343#ifdef FEAT_JUMPLIST
1344 if (curwin->w_jumplistlen > 0)
1345 {
1346 int jumpidx;
1347
1348 jumpidx = curwin->w_jumplistidx - 1;
1349 if (jumpidx < 0)
1350 jumpidx = curwin->w_jumplistlen - 1;
1351
1352 forward = jumpidx;
1353 while (jumpidx != curwin->w_jumplistidx)
1354 {
1355 buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
1356 if (buf != NULL)
1357 {
1358 if (buf == curbuf || !buf->b_p_bl)
1359 buf = NULL; /* skip current and unlisted bufs */
1360 else if (buf->b_ml.ml_mfp == NULL)
1361 {
1362 /* skip unloaded buf, but may keep it for later */
1363 if (bp == NULL)
1364 bp = buf;
1365 buf = NULL;
1366 }
1367 }
1368 if (buf != NULL) /* found a valid buffer: stop searching */
1369 break;
1370 /* advance to older entry in jump list */
1371 if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen)
1372 break;
1373 if (--jumpidx < 0)
1374 jumpidx = curwin->w_jumplistlen - 1;
1375 if (jumpidx == forward) /* List exhausted for sure */
1376 break;
1377 }
1378 }
1379#endif
1380
1381 if (buf == NULL) /* No previous buffer, Try 2'nd approach */
1382 {
1383 forward = TRUE;
1384 buf = curbuf->b_next;
1385 for (;;)
1386 {
1387 if (buf == NULL)
1388 {
1389 if (!forward) /* tried both directions */
1390 break;
1391 buf = curbuf->b_prev;
1392 forward = FALSE;
1393 continue;
1394 }
1395 /* in non-help buffer, try to skip help buffers, and vv */
1396 if (buf->b_help == curbuf->b_help && buf->b_p_bl)
1397 {
1398 if (buf->b_ml.ml_mfp != NULL) /* found loaded buffer */
1399 break;
1400 if (bp == NULL) /* remember unloaded buf for later */
1401 bp = buf;
1402 }
1403 if (forward)
1404 buf = buf->b_next;
1405 else
1406 buf = buf->b_prev;
1407 }
1408 }
1409 if (buf == NULL) /* No loaded buffer, use unloaded one */
1410 buf = bp;
1411 if (buf == NULL) /* No loaded buffer, find listed one */
1412 {
1413 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1414 if (buf->b_p_bl && buf != curbuf)
1415 break;
1416 }
1417 if (buf == NULL) /* Still no buffer, just take one */
1418 {
1419 if (curbuf->b_next != NULL)
1420 buf = curbuf->b_next;
1421 else
1422 buf = curbuf->b_prev;
1423 }
1424 }
1425
Bram Moolenaara02471e2014-01-10 16:43:14 +01001426 if (buf == NULL)
1427 {
1428 /* Autocommands must have wiped out all other buffers. Only option
1429 * now is to make the current buffer empty. */
1430 return empty_curbuf(FALSE, forceit, action);
1431 }
1432
Bram Moolenaar071d4272004-06-13 20:20:40 +00001433 /*
1434 * make buf current buffer
1435 */
1436 if (action == DOBUF_SPLIT) /* split window first */
1437 {
1438# ifdef FEAT_WINDOWS
Bram Moolenaarf2330482008-06-24 20:19:36 +00001439 /* If 'switchbuf' contains "useopen": jump to first window containing
1440 * "buf" if one exists */
1441 if ((swb_flags & SWB_USEOPEN) && buf_jump_open_win(buf))
Bram Moolenaar779b74b2006-04-10 14:55:34 +00001442 return OK;
Bram Moolenaar9381ab72008-11-12 11:52:19 +00001443 /* If 'switchbuf' contains "usetab": jump to first window in any tab
Bram Moolenaarf2330482008-06-24 20:19:36 +00001444 * page containing "buf" if one exists */
1445 if ((swb_flags & SWB_USETAB) && buf_jump_open_tab(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446 return OK;
1447 if (win_split(0, 0) == FAIL)
1448# endif
1449 return FAIL;
1450 }
1451#endif
1452
1453 /* go to current buffer - nothing to do */
1454 if (buf == curbuf)
1455 return OK;
1456
1457 /*
1458 * Check if the current buffer may be abandoned.
1459 */
1460 if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
1461 {
1462#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1463 if ((p_confirm || cmdmod.confirm) && p_write)
1464 {
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001465# ifdef FEAT_AUTOCMD
1466 bufref_T bufref;
1467
1468 set_bufref(&bufref, buf);
1469# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470 dialog_changed(curbuf, FALSE);
1471# ifdef FEAT_AUTOCMD
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001472 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473 /* Autocommand deleted buffer, oops! */
1474 return FAIL;
1475# endif
1476 }
1477 if (bufIsChanged(curbuf))
1478#endif
1479 {
1480 EMSG(_(e_nowrtmsg));
1481 return FAIL;
1482 }
1483 }
1484
1485 /* Go to the other buffer. */
1486 set_curbuf(buf, action);
1487
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001488#if defined(FEAT_LISTCMDS) \
1489 && (defined(FEAT_SCROLLBIND) || defined(FEAT_CURSORBIND))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001490 if (action == DOBUF_SPLIT)
Bram Moolenaar3368ea22010-09-21 16:56:35 +02001491 {
1492 RESET_BINDING(curwin); /* reset 'scrollbind' and 'cursorbind' */
1493 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001494#endif
1495
1496#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
1497 if (aborting()) /* autocmds may abort script processing */
1498 return FAIL;
1499#endif
1500
1501 return OK;
1502}
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02001503#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504
1505/*
1506 * Set current buffer to "buf". Executes autocommands and closes current
1507 * buffer. "action" tells how to close the current buffer:
1508 * DOBUF_GOTO free or hide it
1509 * DOBUF_SPLIT nothing
1510 * DOBUF_UNLOAD unload it
1511 * DOBUF_DEL delete it
1512 * DOBUF_WIPE wipe it out
1513 */
1514 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001515set_curbuf(buf_T *buf, int action)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001516{
1517 buf_T *prevbuf;
1518 int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
1519 || action == DOBUF_WIPE);
Bram Moolenaar6d47df72013-02-17 15:45:37 +01001520#ifdef FEAT_SYN_HL
1521 long old_tw = curbuf->b_p_tw;
1522#endif
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001523 bufref_T bufref;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001524
1525 setpcmark();
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001526 if (!cmdmod.keepalt)
1527 curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
Bram Moolenaar701f7af2008-11-15 13:12:07 +00001528 buflist_altfpos(curwin); /* remember curpos */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001529
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530 /* Don't restart Select mode after switching to another buffer. */
1531 VIsual_reselect = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001532
1533 /* close_windows() or apply_autocmds() may change curbuf */
1534 prevbuf = curbuf;
Bram Moolenaar453f37d2016-07-10 18:33:59 +02001535 set_bufref(&bufref, prevbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001536
1537#ifdef FEAT_AUTOCMD
Bram Moolenaar82404332016-07-10 17:00:38 +02001538 if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539# ifdef FEAT_EVAL
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001540 || (bufref_valid(&bufref) && !aborting()))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541# else
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001542 || bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001543# endif
1544#endif
1545 {
Bram Moolenaara971b822011-09-14 14:43:25 +02001546#ifdef FEAT_SYN_HL
1547 if (prevbuf == curwin->w_buffer)
1548 reset_synblock(curwin);
1549#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550#ifdef FEAT_WINDOWS
1551 if (unload)
Bram Moolenaarf740b292006-02-16 22:11:02 +00001552 close_windows(prevbuf, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001553#endif
1554#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001555 if (bufref_valid(&bufref) && !aborting())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001556#else
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001557 if (bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558#endif
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00001559 {
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001560#ifdef FEAT_WINDOWS
Bram Moolenaare25865a2012-07-06 16:22:02 +02001561 win_T *previouswin = curwin;
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001562#endif
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00001563 if (prevbuf == curbuf)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00001564 u_sync(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565 close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf,
1566 unload ? action : (action == DOBUF_GOTO
1567 && !P_HID(prevbuf)
Bram Moolenaar42ec6562012-02-22 14:58:37 +01001568 && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE);
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001569#ifdef FEAT_WINDOWS
Bram Moolenaare25865a2012-07-06 16:22:02 +02001570 if (curwin != previouswin && win_valid(previouswin))
Bram Moolenaar9e931222012-06-20 11:55:01 +02001571 /* autocommands changed curwin, Grr! */
Bram Moolenaare25865a2012-07-06 16:22:02 +02001572 curwin = previouswin;
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001573#endif
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00001574 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575 }
1576#ifdef FEAT_AUTOCMD
Bram Moolenaar5bd266c2008-09-01 15:33:17 +00001577 /* An autocommand may have deleted "buf", already entered it (e.g., when
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001578 * it did ":bunload") or aborted the script processing.
Bram Moolenaar9e931222012-06-20 11:55:01 +02001579 * If curwin->w_buffer is null, enter_buffer() will make it valid again */
1580 if ((buf_valid(buf) && buf != curbuf
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001581# ifdef FEAT_EVAL
Bram Moolenaar9e931222012-06-20 11:55:01 +02001582 && !aborting()
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001583# endif
1584# ifdef FEAT_WINDOWS
Bram Moolenaar9e931222012-06-20 11:55:01 +02001585 ) || curwin->w_buffer == NULL
Bram Moolenaar50a12b42012-06-20 17:54:38 +02001586# endif
Bram Moolenaar9e931222012-06-20 11:55:01 +02001587 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588#endif
Bram Moolenaar6d47df72013-02-17 15:45:37 +01001589 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590 enter_buffer(buf);
Bram Moolenaar6d47df72013-02-17 15:45:37 +01001591#ifdef FEAT_SYN_HL
1592 if (old_tw != curbuf->b_p_tw)
1593 check_colorcolumn(curwin);
1594#endif
1595 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596}
1597
1598/*
1599 * Enter a new current buffer.
Bram Moolenaar6d47df72013-02-17 15:45:37 +01001600 * Old curbuf must have been abandoned already! This also means "curbuf" may
1601 * be pointing to freed memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 */
1603 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001604enter_buffer(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605{
1606 /* Copy buffer and window local option values. Not for a help buffer. */
1607 buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
1608 if (!buf->b_help)
1609 get_winopts(buf);
1610#ifdef FEAT_FOLDING
1611 else
1612 /* Remove all folds in the window. */
1613 clearFolding(curwin);
1614 foldUpdateAll(curwin); /* update folds (later). */
1615#endif
1616
1617 /* Get the buffer in the current window. */
1618 curwin->w_buffer = buf;
1619 curbuf = buf;
1620 ++curbuf->b_nwindows;
1621
1622#ifdef FEAT_DIFF
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00001623 if (curwin->w_p_diff)
1624 diff_buf_add(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001625#endif
1626
Bram Moolenaara971b822011-09-14 14:43:25 +02001627#ifdef FEAT_SYN_HL
1628 curwin->w_s = &(buf->b_s);
1629#endif
1630
Bram Moolenaar071d4272004-06-13 20:20:40 +00001631 /* Cursor on first line by default. */
1632 curwin->w_cursor.lnum = 1;
1633 curwin->w_cursor.col = 0;
1634#ifdef FEAT_VIRTUALEDIT
1635 curwin->w_cursor.coladd = 0;
1636#endif
1637 curwin->w_set_curswant = TRUE;
Bram Moolenaard4153d42008-11-15 15:06:17 +00001638#ifdef FEAT_AUTOCMD
1639 curwin->w_topline_was_set = FALSE;
1640#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001641
Bram Moolenaar89c0ea42010-02-24 16:58:36 +01001642 /* mark cursor position as being invalid */
1643 curwin->w_valid = 0;
1644
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645 /* Make sure the buffer is loaded. */
1646 if (curbuf->b_ml.ml_mfp == NULL) /* need to load the file */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001647 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +00001648#ifdef FEAT_AUTOCMD
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001649 /* If there is no filetype, allow for detecting one. Esp. useful for
1650 * ":ball" used in a autocommand. If there already is a filetype we
1651 * might prefer to keep it. */
1652 if (*curbuf->b_p_ft == NUL)
1653 did_filetype = FALSE;
Bram Moolenaarc0197e22004-09-13 20:26:32 +00001654#endif
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001655
Bram Moolenaar59f931e2010-07-24 20:27:03 +02001656 open_buffer(FALSE, NULL, 0);
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001657 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001658 else
1659 {
Bram Moolenaar55b7cf82006-09-09 12:52:42 +00001660 if (!msg_silent)
1661 need_fileinfo = TRUE; /* display file info after redraw */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662 (void)buf_check_timestamp(curbuf, FALSE); /* check if file changed */
1663#ifdef FEAT_AUTOCMD
1664 curwin->w_topline = 1;
1665# ifdef FEAT_DIFF
1666 curwin->w_topfill = 0;
1667# endif
1668 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
1669 apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf);
1670#endif
1671 }
1672
1673 /* If autocommands did not change the cursor position, restore cursor lnum
1674 * and possibly cursor col. */
1675 if (curwin->w_cursor.lnum == 1 && inindent(0))
1676 buflist_getfpos();
1677
1678 check_arg_idx(curwin); /* check for valid arg_idx */
1679#ifdef FEAT_TITLE
1680 maketitle();
1681#endif
1682#ifdef FEAT_AUTOCMD
Bram Moolenaard4153d42008-11-15 15:06:17 +00001683 /* when autocmds didn't change it */
1684 if (curwin->w_topline == 1 && !curwin->w_topline_was_set)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685#endif
1686 scroll_cursor_halfway(FALSE); /* redisplay at correct position */
1687
Bram Moolenaar009b2592004-10-24 19:18:58 +00001688#ifdef FEAT_NETBEANS_INTG
1689 /* Send fileOpened event because we've changed buffers. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +02001690 netbeans_file_activated(curbuf);
Bram Moolenaar009b2592004-10-24 19:18:58 +00001691#endif
1692
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001693 /* Change directories when the 'acd' option is set. */
1694 DO_AUTOCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00001695
1696#ifdef FEAT_KEYMAP
1697 if (curbuf->b_kmap_state & KEYMAP_INIT)
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00001698 (void)keymap_init();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001699#endif
Bram Moolenaar706cdeb2007-05-06 21:55:31 +00001700#ifdef FEAT_SPELL
1701 /* May need to set the spell language. Can only do this after the buffer
1702 * has been properly setup. */
Bram Moolenaar860cae12010-06-05 23:22:07 +02001703 if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
1704 (void)did_set_spelllang(curwin);
Bram Moolenaar706cdeb2007-05-06 21:55:31 +00001705#endif
Bram Moolenaarab9c89b2016-07-03 17:47:26 +02001706#ifdef FEAT_VIMINFO
1707 curbuf->b_last_used = vim_time();
1708#endif
Bram Moolenaar706cdeb2007-05-06 21:55:31 +00001709
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710 redraw_later(NOT_VALID);
1711}
1712
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001713#if defined(FEAT_AUTOCHDIR) || defined(PROTO)
1714/*
1715 * Change to the directory of the current buffer.
Bram Moolenaar6bd364e2016-02-23 16:19:07 +01001716 * Don't do this while still starting up.
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001717 */
1718 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001719do_autochdir(void)
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001720{
Bram Moolenaar5c719942016-07-09 23:40:45 +02001721 if ((starting == 0 || test_autochdir)
Bram Moolenaar6bd364e2016-02-23 16:19:07 +01001722 && curbuf->b_ffname != NULL
1723 && vim_chdirfile(curbuf->b_ffname) == OK)
Bram Moolenaar498efdb2006-09-05 14:31:54 +00001724 shorten_fnames(TRUE);
1725}
1726#endif
1727
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728/*
1729 * functions for dealing with the buffer list
1730 */
1731
Bram Moolenaar480778b2016-07-14 22:09:39 +02001732static int top_file_num = 1; /* highest file number */
1733
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734/*
1735 * Add a file name to the buffer list. Return a pointer to the buffer.
1736 * If the same file name already exists return a pointer to that buffer.
1737 * If it does not exist, or if fname == NULL, a new entry is created.
1738 * If (flags & BLN_CURBUF) is TRUE, may use current buffer.
1739 * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list.
1740 * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer.
Bram Moolenaarb127cfd2016-05-29 16:24:50 +02001741 * If (flags & BLN_NEW) is TRUE, don't use an existing buffer.
Bram Moolenaar82404332016-07-10 17:00:38 +02001742 * If (flags & BLN_NOOPT) is TRUE, don't copy options from the current buffer
1743 * if the buffer already exists.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 * This is the ONLY way to create a new buffer.
1745 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001746 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01001747buflist_new(
1748 char_u *ffname, /* full path of fname or relative */
1749 char_u *sfname, /* short fname or NULL */
1750 linenr_T lnum, /* preferred cursor line */
1751 int flags) /* BLN_ defines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752{
1753 buf_T *buf;
1754#ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02001755 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756#endif
1757
Bram Moolenaar480778b2016-07-14 22:09:39 +02001758 if (top_file_num == 1)
1759 hash_init(&buf_hashtab);
1760
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 fname_expand(curbuf, &ffname, &sfname); /* will allocate ffname */
1762
1763 /*
1764 * If file name already exists in the list, update the entry.
1765 */
1766#ifdef UNIX
1767 /* On Unix we can use inode numbers when the file exists. Works better
1768 * for hard links. */
1769 if (sfname == NULL || mch_stat((char *)sfname, &st) < 0)
1770 st.st_dev = (dev_T)-1;
1771#endif
Bram Moolenaarb127cfd2016-05-29 16:24:50 +02001772 if (ffname != NULL && !(flags & (BLN_DUMMY | BLN_NEW)) && (buf =
Bram Moolenaar071d4272004-06-13 20:20:40 +00001773#ifdef UNIX
1774 buflist_findname_stat(ffname, &st)
1775#else
1776 buflist_findname(ffname)
1777#endif
1778 ) != NULL)
1779 {
1780 vim_free(ffname);
1781 if (lnum != 0)
1782 buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE);
Bram Moolenaar82404332016-07-10 17:00:38 +02001783
1784 if ((flags & BLN_NOOPT) == 0)
1785 /* copy the options now, if 'cpo' doesn't have 's' and not done
1786 * already */
1787 buf_copy_options(buf, 0);
1788
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789 if ((flags & BLN_LISTED) && !buf->b_p_bl)
1790 {
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001791#ifdef FEAT_AUTOCMD
1792 bufref_T bufref;
1793#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 buf->b_p_bl = TRUE;
1795#ifdef FEAT_AUTOCMD
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001796 set_bufref(&bufref, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 if (!(flags & BLN_DUMMY))
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001798 {
Bram Moolenaar82404332016-07-10 17:00:38 +02001799 if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001800 && !bufref_valid(&bufref))
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001801 return NULL;
1802 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803#endif
1804 }
1805 return buf;
1806 }
1807
1808 /*
1809 * If the current buffer has no name and no contents, use the current
1810 * buffer. Otherwise: Need to allocate a new buffer structure.
1811 *
1812 * This is the ONLY place where a new buffer structure is allocated!
Bram Moolenaar4770d092006-01-12 23:22:24 +00001813 * (A spell file buffer is allocated in spell.c, but that's not a normal
1814 * buffer.)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815 */
1816 buf = NULL;
1817 if ((flags & BLN_CURBUF)
1818 && curbuf != NULL
1819 && curbuf->b_ffname == NULL
1820 && curbuf->b_nwindows <= 1
1821 && (curbuf->b_ml.ml_mfp == NULL || bufempty()))
1822 {
1823 buf = curbuf;
1824#ifdef FEAT_AUTOCMD
1825 /* It's like this buffer is deleted. Watch out for autocommands that
1826 * change curbuf! If that happens, allocate a new buffer anyway. */
1827 if (curbuf->b_p_bl)
1828 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
1829 if (buf == curbuf)
1830 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
1831# ifdef FEAT_EVAL
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001832 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833 return NULL;
1834# endif
1835#endif
1836#ifdef FEAT_QUICKFIX
1837# ifdef FEAT_AUTOCMD
1838 if (buf == curbuf)
1839# endif
1840 {
1841 /* Make sure 'bufhidden' and 'buftype' are empty */
1842 clear_string_option(&buf->b_p_bh);
1843 clear_string_option(&buf->b_p_bt);
1844 }
1845#endif
1846 }
1847 if (buf != curbuf || curbuf == NULL)
1848 {
1849 buf = (buf_T *)alloc_clear((unsigned)sizeof(buf_T));
1850 if (buf == NULL)
1851 {
1852 vim_free(ffname);
1853 return NULL;
1854 }
Bram Moolenaar429fa852013-04-15 12:27:36 +02001855#ifdef FEAT_EVAL
1856 /* init b: variables */
1857 buf->b_vars = dict_alloc();
1858 if (buf->b_vars == NULL)
1859 {
1860 vim_free(ffname);
1861 vim_free(buf);
1862 return NULL;
1863 }
1864 init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
1865#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 }
1867
1868 if (ffname != NULL)
1869 {
1870 buf->b_ffname = ffname;
1871 buf->b_sfname = vim_strsave(sfname);
1872 }
1873
1874 clear_wininfo(buf);
1875 buf->b_wininfo = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
1876
1877 if ((ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL))
1878 || buf->b_wininfo == NULL)
1879 {
1880 vim_free(buf->b_ffname);
1881 buf->b_ffname = NULL;
1882 vim_free(buf->b_sfname);
1883 buf->b_sfname = NULL;
1884 if (buf != curbuf)
1885 free_buffer(buf);
1886 return NULL;
1887 }
1888
1889 if (buf == curbuf)
1890 {
1891 /* free all things allocated for this buffer */
Bram Moolenaar59f931e2010-07-24 20:27:03 +02001892 buf_freeall(buf, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 if (buf != curbuf) /* autocommands deleted the buffer! */
1894 return NULL;
1895#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001896 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897 return NULL;
1898#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 free_buffer_stuff(buf, FALSE); /* delete local variables et al. */
Bram Moolenaar0ac24e12012-11-20 12:16:58 +01001900
1901 /* Init the options. */
1902 buf->b_p_initialized = FALSE;
1903 buf_copy_options(buf, BCO_ENTER);
1904
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905#ifdef FEAT_KEYMAP
1906 /* need to reload lmaps and set b:keymap_name */
1907 curbuf->b_kmap_state |= KEYMAP_INIT;
1908#endif
1909 }
1910 else
1911 {
1912 /*
1913 * put new buffer at the end of the buffer list
1914 */
1915 buf->b_next = NULL;
1916 if (firstbuf == NULL) /* buffer list is empty */
1917 {
1918 buf->b_prev = NULL;
1919 firstbuf = buf;
1920 }
1921 else /* append new buffer at end of list */
1922 {
1923 lastbuf->b_next = buf;
1924 buf->b_prev = lastbuf;
1925 }
1926 lastbuf = buf;
1927
1928 buf->b_fnum = top_file_num++;
1929 if (top_file_num < 0) /* wrap around (may cause duplicates) */
1930 {
1931 EMSG(_("W14: Warning: List of file names overflow"));
1932 if (emsg_silent == 0)
1933 {
1934 out_flush();
1935 ui_delay(3000L, TRUE); /* make sure it is noticed */
1936 }
1937 top_file_num = 1;
1938 }
Bram Moolenaar480778b2016-07-14 22:09:39 +02001939 buf_hashtab_add(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940
1941 /*
1942 * Always copy the options from the current buffer.
1943 */
1944 buf_copy_options(buf, BCO_ALWAYS);
1945 }
1946
1947 buf->b_wininfo->wi_fpos.lnum = lnum;
1948 buf->b_wininfo->wi_win = curwin;
1949
Bram Moolenaar1fad5d42005-01-25 21:44:33 +00001950#ifdef FEAT_SYN_HL
Bram Moolenaar860cae12010-06-05 23:22:07 +02001951 hash_init(&buf->b_s.b_keywtab);
1952 hash_init(&buf->b_s.b_keywtab_ic);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953#endif
1954
1955 buf->b_fname = buf->b_sfname;
1956#ifdef UNIX
1957 if (st.st_dev == (dev_T)-1)
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00001958 buf->b_dev_valid = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 else
1960 {
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00001961 buf->b_dev_valid = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001962 buf->b_dev = st.st_dev;
1963 buf->b_ino = st.st_ino;
1964 }
1965#endif
1966 buf->b_u_synced = TRUE;
1967 buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED;
Bram Moolenaar81695252004-12-29 20:58:21 +00001968 if (flags & BLN_DUMMY)
1969 buf->b_flags |= BF_DUMMY;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970 buf_clear_file(buf);
1971 clrallmarks(buf); /* clear marks */
1972 fmarks_check_names(buf); /* check file marks for this file */
1973 buf->b_p_bl = (flags & BLN_LISTED) ? TRUE : FALSE; /* init 'buflisted' */
1974#ifdef FEAT_AUTOCMD
1975 if (!(flags & BLN_DUMMY))
1976 {
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001977 bufref_T bufref;
1978
Bram Moolenaar8da9bbf2015-02-27 19:34:56 +01001979 /* Tricky: these autocommands may change the buffer list. They could
1980 * also split the window with re-using the one empty buffer. This may
1981 * result in unexpectedly losing the empty buffer. */
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001982 set_bufref(&bufref, buf);
Bram Moolenaar82404332016-07-10 17:00:38 +02001983 if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf)
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001984 && !bufref_valid(&bufref))
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001985 return NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986 if (flags & BLN_LISTED)
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001987 {
Bram Moolenaar82404332016-07-10 17:00:38 +02001988 if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02001989 && !bufref_valid(&bufref))
Bram Moolenaar4c7ab1b2014-04-06 20:45:43 +02001990 return NULL;
1991 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992# ifdef FEAT_EVAL
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001993 if (aborting()) /* autocmds may abort script processing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001994 return NULL;
1995# endif
1996 }
1997#endif
1998
1999 return buf;
2000}
2001
2002/*
2003 * Free the memory for the options of a buffer.
2004 * If "free_p_ff" is TRUE also free 'fileformat', 'buftype' and
2005 * 'fileencoding'.
2006 */
2007 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002008free_buf_options(
2009 buf_T *buf,
2010 int free_p_ff)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002011{
2012 if (free_p_ff)
2013 {
2014#ifdef FEAT_MBYTE
2015 clear_string_option(&buf->b_p_fenc);
2016#endif
2017 clear_string_option(&buf->b_p_ff);
2018#ifdef FEAT_QUICKFIX
2019 clear_string_option(&buf->b_p_bh);
2020 clear_string_option(&buf->b_p_bt);
2021#endif
2022 }
2023#ifdef FEAT_FIND_ID
2024 clear_string_option(&buf->b_p_def);
2025 clear_string_option(&buf->b_p_inc);
2026# ifdef FEAT_EVAL
2027 clear_string_option(&buf->b_p_inex);
2028# endif
2029#endif
2030#if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
2031 clear_string_option(&buf->b_p_inde);
2032 clear_string_option(&buf->b_p_indk);
2033#endif
Bram Moolenaar371d5402006-03-20 21:47:49 +00002034#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
2035 clear_string_option(&buf->b_p_bexpr);
2036#endif
Bram Moolenaar49771f42010-07-20 17:32:38 +02002037#if defined(FEAT_CRYPT)
2038 clear_string_option(&buf->b_p_cm);
2039#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002040#if defined(FEAT_EVAL)
2041 clear_string_option(&buf->b_p_fex);
2042#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043#ifdef FEAT_CRYPT
2044 clear_string_option(&buf->b_p_key);
2045#endif
2046 clear_string_option(&buf->b_p_kp);
2047 clear_string_option(&buf->b_p_mps);
2048 clear_string_option(&buf->b_p_fo);
Bram Moolenaar86b68352004-12-27 21:59:20 +00002049 clear_string_option(&buf->b_p_flp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002050 clear_string_option(&buf->b_p_isk);
2051#ifdef FEAT_KEYMAP
2052 clear_string_option(&buf->b_p_keymap);
2053 ga_clear(&buf->b_kmap_ga);
2054#endif
2055#ifdef FEAT_COMMENTS
2056 clear_string_option(&buf->b_p_com);
2057#endif
2058#ifdef FEAT_FOLDING
2059 clear_string_option(&buf->b_p_cms);
2060#endif
2061 clear_string_option(&buf->b_p_nf);
2062#ifdef FEAT_SYN_HL
2063 clear_string_option(&buf->b_p_syn);
Bram Moolenaarb8060fe2016-01-19 22:29:28 +01002064 clear_string_option(&buf->b_s.b_syn_isk);
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00002065#endif
2066#ifdef FEAT_SPELL
Bram Moolenaar860cae12010-06-05 23:22:07 +02002067 clear_string_option(&buf->b_s.b_p_spc);
2068 clear_string_option(&buf->b_s.b_p_spf);
Bram Moolenaar473de612013-06-08 18:19:48 +02002069 vim_regfree(buf->b_s.b_cap_prog);
Bram Moolenaar860cae12010-06-05 23:22:07 +02002070 buf->b_s.b_cap_prog = NULL;
2071 clear_string_option(&buf->b_s.b_p_spl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072#endif
2073#ifdef FEAT_SEARCHPATH
2074 clear_string_option(&buf->b_p_sua);
2075#endif
2076#ifdef FEAT_AUTOCMD
2077 clear_string_option(&buf->b_p_ft);
2078#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002079#ifdef FEAT_CINDENT
2080 clear_string_option(&buf->b_p_cink);
2081 clear_string_option(&buf->b_p_cino);
2082#endif
2083#if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
2084 clear_string_option(&buf->b_p_cinw);
2085#endif
2086#ifdef FEAT_INS_EXPAND
2087 clear_string_option(&buf->b_p_cpt);
2088#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002089#ifdef FEAT_COMPL_FUNC
2090 clear_string_option(&buf->b_p_cfu);
Bram Moolenaare344bea2005-09-01 20:46:49 +00002091 clear_string_option(&buf->b_p_ofu);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002092#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093#ifdef FEAT_QUICKFIX
2094 clear_string_option(&buf->b_p_gp);
2095 clear_string_option(&buf->b_p_mp);
2096 clear_string_option(&buf->b_p_efm);
2097#endif
2098 clear_string_option(&buf->b_p_ep);
2099 clear_string_option(&buf->b_p_path);
2100 clear_string_option(&buf->b_p_tags);
Bram Moolenaar0f6562e2015-11-24 18:48:14 +01002101 clear_string_option(&buf->b_p_tc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102#ifdef FEAT_INS_EXPAND
2103 clear_string_option(&buf->b_p_dict);
2104 clear_string_option(&buf->b_p_tsr);
2105#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00002106#ifdef FEAT_TEXTOBJ
2107 clear_string_option(&buf->b_p_qe);
2108#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002109 buf->b_p_ar = -1;
Bram Moolenaarf5a2fd82013-11-06 05:26:15 +01002110 buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
Bram Moolenaaraf6c1312014-03-12 18:55:58 +01002111#ifdef FEAT_LISP
2112 clear_string_option(&buf->b_p_lw);
2113#endif
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02002114 clear_string_option(&buf->b_p_bkc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115}
2116
2117/*
2118 * get alternate file n
2119 * set linenr to lnum or altfpos.lnum if lnum == 0
2120 * also set cursor column to altfpos.col if 'startofline' is not set.
2121 * if (options & GETF_SETMARK) call setpcmark()
2122 * if (options & GETF_ALT) we are jumping to an alternate file.
2123 * if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping
2124 *
2125 * return FAIL for failure, OK for success
2126 */
2127 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002128buflist_getfile(
2129 int n,
2130 linenr_T lnum,
2131 int options,
2132 int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133{
2134 buf_T *buf;
2135#ifdef FEAT_WINDOWS
2136 win_T *wp = NULL;
2137#endif
2138 pos_T *fpos;
2139 colnr_T col;
2140
2141 buf = buflist_findnr(n);
2142 if (buf == NULL)
2143 {
2144 if ((options & GETF_ALT) && n == 0)
2145 EMSG(_(e_noalt));
2146 else
2147 EMSGN(_("E92: Buffer %ld not found"), n);
2148 return FAIL;
2149 }
2150
2151 /* if alternate file is the current buffer, nothing to do */
2152 if (buf == curbuf)
2153 return OK;
2154
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002155 if (text_locked())
Bram Moolenaar05a7bb32006-01-19 22:09:32 +00002156 {
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00002157 text_locked_msg();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002158 return FAIL;
Bram Moolenaar05a7bb32006-01-19 22:09:32 +00002159 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002160#ifdef FEAT_AUTOCMD
2161 if (curbuf_locked())
2162 return FAIL;
2163#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164
2165 /* altfpos may be changed by getfile(), get it now */
2166 if (lnum == 0)
2167 {
2168 fpos = buflist_findfpos(buf);
2169 lnum = fpos->lnum;
2170 col = fpos->col;
2171 }
2172 else
2173 col = 0;
2174
2175#ifdef FEAT_WINDOWS
2176 if (options & GETF_SWITCH)
2177 {
Bram Moolenaarf2330482008-06-24 20:19:36 +00002178 /* If 'switchbuf' contains "useopen": jump to first window containing
2179 * "buf" if one exists */
2180 if (swb_flags & SWB_USEOPEN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002181 wp = buf_jump_open_win(buf);
Bram Moolenaara594d772015-06-19 14:41:49 +02002182
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002183 /* If 'switchbuf' contains "usetab": jump to first window in any tab
Bram Moolenaarf2330482008-06-24 20:19:36 +00002184 * page containing "buf" if one exists */
2185 if (wp == NULL && (swb_flags & SWB_USETAB))
Bram Moolenaar779b74b2006-04-10 14:55:34 +00002186 wp = buf_jump_open_tab(buf);
Bram Moolenaara594d772015-06-19 14:41:49 +02002187
2188 /* If 'switchbuf' contains "split", "vsplit" or "newtab" and the
2189 * current buffer isn't empty: open new tab or window */
2190 if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB))
2191 && !bufempty())
Bram Moolenaar071d4272004-06-13 20:20:40 +00002192 {
Bram Moolenaara594d772015-06-19 14:41:49 +02002193 if (swb_flags & SWB_NEWTAB)
Bram Moolenaarf2330482008-06-24 20:19:36 +00002194 tabpage_new();
Bram Moolenaara594d772015-06-19 14:41:49 +02002195 else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0)
2196 == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197 return FAIL;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002198 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002199 }
2200 }
2201#endif
2202
2203 ++RedrawingDisabled;
2204 if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK),
2205 lnum, forceit) <= 0)
2206 {
2207 --RedrawingDisabled;
2208
2209 /* cursor is at to BOL and w_cursor.lnum is checked due to getfile() */
2210 if (!p_sol && col != 0)
2211 {
2212 curwin->w_cursor.col = col;
2213 check_cursor_col();
2214#ifdef FEAT_VIRTUALEDIT
2215 curwin->w_cursor.coladd = 0;
2216#endif
2217 curwin->w_set_curswant = TRUE;
2218 }
2219 return OK;
2220 }
2221 --RedrawingDisabled;
2222 return FAIL;
2223}
2224
2225/*
2226 * go to the last know line number for the current buffer
2227 */
2228 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002229buflist_getfpos(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002230{
2231 pos_T *fpos;
2232
2233 fpos = buflist_findfpos(curbuf);
2234
2235 curwin->w_cursor.lnum = fpos->lnum;
2236 check_cursor_lnum();
2237
2238 if (p_sol)
2239 curwin->w_cursor.col = 0;
2240 else
2241 {
2242 curwin->w_cursor.col = fpos->col;
2243 check_cursor_col();
2244#ifdef FEAT_VIRTUALEDIT
2245 curwin->w_cursor.coladd = 0;
2246#endif
2247 curwin->w_set_curswant = TRUE;
2248 }
2249}
2250
Bram Moolenaar81695252004-12-29 20:58:21 +00002251#if defined(FEAT_QUICKFIX) || defined(FEAT_EVAL) || defined(PROTO)
2252/*
2253 * Find file in buffer list by name (it has to be for the current window).
2254 * Returns NULL if not found.
2255 */
2256 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002257buflist_findname_exp(char_u *fname)
Bram Moolenaar81695252004-12-29 20:58:21 +00002258{
2259 char_u *ffname;
2260 buf_T *buf = NULL;
2261
2262 /* First make the name into a full path name */
2263 ffname = FullName_save(fname,
2264#ifdef UNIX
2265 TRUE /* force expansion, get rid of symbolic links */
2266#else
2267 FALSE
2268#endif
2269 );
2270 if (ffname != NULL)
2271 {
2272 buf = buflist_findname(ffname);
2273 vim_free(ffname);
2274 }
2275 return buf;
2276}
2277#endif
2278
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279/*
2280 * Find file in buffer list by name (it has to be for the current window).
2281 * "ffname" must have a full path.
Bram Moolenaar81695252004-12-29 20:58:21 +00002282 * Skips dummy buffers.
2283 * Returns NULL if not found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 */
2285 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002286buflist_findname(char_u *ffname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287{
2288#ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02002289 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002290
2291 if (mch_stat((char *)ffname, &st) < 0)
2292 st.st_dev = (dev_T)-1;
2293 return buflist_findname_stat(ffname, &st);
2294}
2295
2296/*
2297 * Same as buflist_findname(), but pass the stat structure to avoid getting it
2298 * twice for the same file.
Bram Moolenaar81695252004-12-29 20:58:21 +00002299 * Returns NULL if not found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300 */
2301 static buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002302buflist_findname_stat(
2303 char_u *ffname,
Bram Moolenaar8767f522016-07-01 17:17:39 +02002304 stat_T *stp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305{
2306#endif
2307 buf_T *buf;
2308
Bram Moolenaarea3f2e72016-07-10 20:27:32 +02002309 /* Start at the last buffer, expect to find a match sooner. */
2310 for (buf = lastbuf; buf != NULL; buf = buf->b_prev)
Bram Moolenaar81695252004-12-29 20:58:21 +00002311 if ((buf->b_flags & BF_DUMMY) == 0 && !otherfile_buf(buf, ffname
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312#ifdef UNIX
2313 , stp
2314#endif
2315 ))
2316 return buf;
2317 return NULL;
2318}
2319
Bram Moolenaar0c279bb2013-03-19 14:25:54 +01002320#if defined(FEAT_LISTCMDS) || defined(FEAT_EVAL) || defined(FEAT_PERL) \
2321 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322/*
2323 * Find file in buffer list by a regexp pattern.
2324 * Return fnum of the found buffer.
2325 * Return < 0 for error.
2326 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002328buflist_findpat(
2329 char_u *pattern,
2330 char_u *pattern_end, /* pointer to first char after pattern */
2331 int unlisted, /* find unlisted buffers */
2332 int diffmode UNUSED, /* find diff-mode buffers only */
2333 int curtab_only) /* find buffers in current tab only */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002334{
2335 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336 int match = -1;
2337 int find_listed;
2338 char_u *pat;
2339 char_u *patend;
2340 int attempt;
2341 char_u *p;
2342 int toggledollar;
2343
2344 if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
2345 {
2346 if (*pattern == '%')
2347 match = curbuf->b_fnum;
2348 else
2349 match = curwin->w_alt_fnum;
2350#ifdef FEAT_DIFF
2351 if (diffmode && !diff_mode_buf(buflist_findnr(match)))
2352 match = -1;
2353#endif
2354 }
2355
2356 /*
2357 * Try four ways of matching a listed buffer:
2358 * attempt == 0: without '^' or '$' (at any position)
Bram Moolenaarb6799ac2007-05-10 16:44:05 +00002359 * attempt == 1: with '^' at start (only at position 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 * attempt == 2: with '$' at end (only match at end)
2361 * attempt == 3: with '^' at start and '$' at end (only full match)
2362 * Repeat this for finding an unlisted buffer if there was no matching
2363 * listed buffer.
2364 */
2365 else
2366 {
2367 pat = file_pat_to_reg_pat(pattern, pattern_end, NULL, FALSE);
2368 if (pat == NULL)
2369 return -1;
2370 patend = pat + STRLEN(pat) - 1;
2371 toggledollar = (patend > pat && *patend == '$');
2372
2373 /* First try finding a listed buffer. If not found and "unlisted"
2374 * is TRUE, try finding an unlisted buffer. */
2375 find_listed = TRUE;
2376 for (;;)
2377 {
2378 for (attempt = 0; attempt <= 3; ++attempt)
2379 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002380 regmatch_T regmatch;
2381
Bram Moolenaar071d4272004-06-13 20:20:40 +00002382 /* may add '^' and '$' */
2383 if (toggledollar)
2384 *patend = (attempt < 2) ? NUL : '$'; /* add/remove '$' */
2385 p = pat;
2386 if (*p == '^' && !(attempt & 1)) /* add/remove '^' */
2387 ++p;
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002388 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2389 if (regmatch.regprog == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 {
2391 vim_free(pat);
2392 return -1;
2393 }
2394
Bram Moolenaarea3f2e72016-07-10 20:27:32 +02002395 for (buf = lastbuf; buf != NULL; buf = buf->b_prev)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002396 if (buf->b_p_bl == find_listed
2397#ifdef FEAT_DIFF
2398 && (!diffmode || diff_mode_buf(buf))
2399#endif
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002400 && buflist_match(&regmatch, buf, FALSE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002401 {
Bram Moolenaar0c279bb2013-03-19 14:25:54 +01002402 if (curtab_only)
2403 {
2404 /* Ignore the match if the buffer is not open in
2405 * the current tab. */
2406#ifdef FEAT_WINDOWS
2407 win_T *wp;
2408
2409 for (wp = firstwin; wp != NULL; wp = wp->w_next)
2410 if (wp->w_buffer == buf)
2411 break;
2412 if (wp == NULL)
2413 continue;
2414#else
2415 if (curwin->w_buffer != buf)
2416 continue;
2417#endif
2418 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002419 if (match >= 0) /* already found a match */
2420 {
2421 match = -2;
2422 break;
2423 }
2424 match = buf->b_fnum; /* remember first match */
2425 }
2426
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002427 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428 if (match >= 0) /* found one match */
2429 break;
2430 }
2431
2432 /* Only search for unlisted buffers if there was no match with
2433 * a listed buffer. */
2434 if (!unlisted || !find_listed || match != -1)
2435 break;
2436 find_listed = FALSE;
2437 }
2438
2439 vim_free(pat);
2440 }
2441
2442 if (match == -2)
2443 EMSG2(_("E93: More than one match for %s"), pattern);
2444 else if (match < 0)
2445 EMSG2(_("E94: No matching buffer for %s"), pattern);
2446 return match;
2447}
2448#endif
2449
2450#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2451
2452/*
2453 * Find all buffer names that match.
2454 * For command line expansion of ":buf" and ":sbuf".
2455 * Return OK if matches found, FAIL otherwise.
2456 */
2457 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002458ExpandBufnames(
2459 char_u *pat,
2460 int *num_file,
2461 char_u ***file,
2462 int options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463{
2464 int count = 0;
2465 buf_T *buf;
2466 int round;
2467 char_u *p;
2468 int attempt;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002469 char_u *patc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470
2471 *num_file = 0; /* return values in case of FAIL */
2472 *file = NULL;
2473
Bram Moolenaar05159a02005-02-26 23:04:13 +00002474 /* Make a copy of "pat" and change "^" to "\(^\|[\/]\)". */
2475 if (*pat == '^')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00002477 patc = alloc((unsigned)STRLEN(pat) + 11);
2478 if (patc == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002480 STRCPY(patc, "\\(^\\|[\\/]\\)");
2481 STRCPY(patc + 11, pat + 1);
2482 }
2483 else
2484 patc = pat;
2485
2486 /*
2487 * attempt == 0: try match with '\<', match at start of word
Bram Moolenaard8a4e562005-05-18 22:06:55 +00002488 * attempt == 1: try match without '\<', match anywhere
Bram Moolenaar05159a02005-02-26 23:04:13 +00002489 */
Bram Moolenaard8a4e562005-05-18 22:06:55 +00002490 for (attempt = 0; attempt <= 1; ++attempt)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002491 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002492 regmatch_T regmatch;
2493
Bram Moolenaard8a4e562005-05-18 22:06:55 +00002494 if (attempt > 0 && patc == pat)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002495 break; /* there was no anchor, no need to try again */
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002496 regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC);
2497 if (regmatch.regprog == NULL)
Bram Moolenaar05159a02005-02-26 23:04:13 +00002498 {
2499 if (patc != pat)
2500 vim_free(patc);
2501 return FAIL;
2502 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503
2504 /*
2505 * round == 1: Count the matches.
2506 * round == 2: Build the array to keep the matches.
2507 */
2508 for (round = 1; round <= 2; ++round)
2509 {
2510 count = 0;
2511 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2512 {
2513 if (!buf->b_p_bl) /* skip unlisted buffers */
2514 continue;
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002515 p = buflist_match(&regmatch, buf, p_wic);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516 if (p != NULL)
2517 {
2518 if (round == 1)
2519 ++count;
2520 else
2521 {
2522 if (options & WILD_HOME_REPLACE)
2523 p = home_replace_save(buf, p);
2524 else
2525 p = vim_strsave(p);
2526 (*file)[count++] = p;
2527 }
2528 }
2529 }
2530 if (count == 0) /* no match found, break here */
2531 break;
2532 if (round == 1)
2533 {
2534 *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
2535 if (*file == NULL)
2536 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002537 vim_regfree(regmatch.regprog);
Bram Moolenaar05159a02005-02-26 23:04:13 +00002538 if (patc != pat)
2539 vim_free(patc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002540 return FAIL;
2541 }
2542 }
2543 }
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002544 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545 if (count) /* match(es) found, break here */
2546 break;
2547 }
2548
Bram Moolenaar05159a02005-02-26 23:04:13 +00002549 if (patc != pat)
2550 vim_free(patc);
2551
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552 *num_file = count;
2553 return (count == 0 ? FAIL : OK);
2554}
2555
2556#endif /* FEAT_CMDL_COMPL */
2557
2558#ifdef HAVE_BUFLIST_MATCH
2559/*
2560 * Check for a match on the file name for buffer "buf" with regprog "prog".
2561 */
2562 static char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002563buflist_match(
2564 regmatch_T *rmp,
2565 buf_T *buf,
2566 int ignore_case) /* when TRUE ignore case, when FALSE use 'fic' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567{
2568 char_u *match;
2569
2570 /* First try the short file name, then the long file name. */
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002571 match = fname_match(rmp, buf->b_sfname, ignore_case);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 if (match == NULL)
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002573 match = fname_match(rmp, buf->b_ffname, ignore_case);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574
2575 return match;
2576}
2577
2578/*
2579 * Try matching the regexp in "prog" with file name "name".
2580 * Return "name" when there is a match, NULL when not.
2581 */
2582 static char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002583fname_match(
2584 regmatch_T *rmp,
2585 char_u *name,
2586 int ignore_case) /* when TRUE ignore case, when FALSE use 'fic' */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002587{
2588 char_u *match = NULL;
2589 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002590
2591 if (name != NULL)
2592 {
Bram Moolenaar4b9d6372014-09-23 14:24:40 +02002593 /* Ignore case when 'fileignorecase' or the argument is set. */
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002594 rmp->rm_ic = p_fic || ignore_case;
2595 if (vim_regexec(rmp, name, (colnr_T)0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596 match = name;
2597 else
2598 {
2599 /* Replace $(HOME) with '~' and try matching again. */
2600 p = home_replace_save(NULL, name);
Bram Moolenaardffa5b82014-11-19 16:38:07 +01002601 if (p != NULL && vim_regexec(rmp, p, (colnr_T)0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602 match = name;
2603 vim_free(p);
2604 }
2605 }
2606
2607 return match;
2608}
2609#endif
2610
2611/*
Bram Moolenaar480778b2016-07-14 22:09:39 +02002612 * Find a file in the buffer list by buffer number.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002613 */
2614 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002615buflist_findnr(int nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616{
Bram Moolenaar480778b2016-07-14 22:09:39 +02002617 char_u key[VIM_SIZEOF_INT * 2 + 1];
2618 hashitem_T *hi;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002619
2620 if (nr == 0)
2621 nr = curwin->w_alt_fnum;
Bram Moolenaar480778b2016-07-14 22:09:39 +02002622 sprintf((char *)key, "%x", nr);
2623 hi = hash_find(&buf_hashtab, key);
2624
2625 if (!HASHITEM_EMPTY(hi))
2626 return (buf_T *)(hi->hi_key
2627 - ((unsigned)(curbuf->b_key - (char_u *)curbuf)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 return NULL;
2629}
2630
2631/*
2632 * Get name of file 'n' in the buffer list.
2633 * When the file has no name an empty string is returned.
2634 * home_replace() is used to shorten the file name (used for marks).
2635 * Returns a pointer to allocated memory, of NULL when failed.
2636 */
2637 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002638buflist_nr2name(
2639 int n,
2640 int fullname,
2641 int helptail) /* for help buffers return tail only */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642{
2643 buf_T *buf;
2644
2645 buf = buflist_findnr(n);
2646 if (buf == NULL)
2647 return NULL;
2648 return home_replace_save(helptail ? buf : NULL,
2649 fullname ? buf->b_ffname : buf->b_fname);
2650}
2651
2652/*
2653 * Set the "lnum" and "col" for the buffer "buf" and the current window.
2654 * When "copy_options" is TRUE save the local window option values.
2655 * When "lnum" is 0 only do the options.
2656 */
2657 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002658buflist_setfpos(
2659 buf_T *buf,
2660 win_T *win,
2661 linenr_T lnum,
2662 colnr_T col,
2663 int copy_options)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002664{
2665 wininfo_T *wip;
2666
2667 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
2668 if (wip->wi_win == win)
2669 break;
2670 if (wip == NULL)
2671 {
2672 /* allocate a new entry */
2673 wip = (wininfo_T *)alloc_clear((unsigned)sizeof(wininfo_T));
2674 if (wip == NULL)
2675 return;
2676 wip->wi_win = win;
2677 if (lnum == 0) /* set lnum even when it's 0 */
2678 lnum = 1;
2679 }
2680 else
2681 {
2682 /* remove the entry from the list */
2683 if (wip->wi_prev)
2684 wip->wi_prev->wi_next = wip->wi_next;
2685 else
2686 buf->b_wininfo = wip->wi_next;
2687 if (wip->wi_next)
2688 wip->wi_next->wi_prev = wip->wi_prev;
2689 if (copy_options && wip->wi_optset)
2690 {
2691 clear_winopt(&wip->wi_opt);
2692#ifdef FEAT_FOLDING
2693 deleteFoldRecurse(&wip->wi_folds);
2694#endif
2695 }
2696 }
2697 if (lnum != 0)
2698 {
2699 wip->wi_fpos.lnum = lnum;
2700 wip->wi_fpos.col = col;
2701 }
2702 if (copy_options)
2703 {
2704 /* Save the window-specific option values. */
2705 copy_winopt(&win->w_onebuf_opt, &wip->wi_opt);
2706#ifdef FEAT_FOLDING
2707 wip->wi_fold_manual = win->w_fold_manual;
2708 cloneFoldGrowArray(&win->w_folds, &wip->wi_folds);
2709#endif
2710 wip->wi_optset = TRUE;
2711 }
2712
2713 /* insert the entry in front of the list */
2714 wip->wi_next = buf->b_wininfo;
2715 buf->b_wininfo = wip;
2716 wip->wi_prev = NULL;
2717 if (wip->wi_next)
2718 wip->wi_next->wi_prev = wip;
2719
2720 return;
2721}
2722
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002723#ifdef FEAT_DIFF
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002724static int wininfo_other_tab_diff(wininfo_T *wip);
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002725
2726/*
2727 * Return TRUE when "wip" has 'diff' set and the diff is only for another tab
2728 * page. That's because a diff is local to a tab page.
2729 */
2730 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002731wininfo_other_tab_diff(wininfo_T *wip)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002732{
2733 win_T *wp;
2734
2735 if (wip->wi_opt.wo_diff)
2736 {
2737 for (wp = firstwin; wp != NULL; wp = wp->w_next)
2738 /* return FALSE when it's a window in the current tab page, thus
2739 * the buffer was in diff mode here */
2740 if (wip->wi_win == wp)
2741 return FALSE;
2742 return TRUE;
2743 }
2744 return FALSE;
2745}
2746#endif
2747
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748/*
2749 * Find info for the current window in buffer "buf".
2750 * If not found, return the info for the most recently used window.
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002751 * When "skip_diff_buffer" is TRUE avoid windows with 'diff' set that is in
2752 * another tab page.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753 * Returns NULL when there isn't any info.
2754 */
2755 static wininfo_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002756find_wininfo(
2757 buf_T *buf,
2758 int skip_diff_buffer UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759{
2760 wininfo_T *wip;
2761
2762 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002763 if (wip->wi_win == curwin
2764#ifdef FEAT_DIFF
2765 && (!skip_diff_buffer || !wininfo_other_tab_diff(wip))
2766#endif
2767 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002768 break;
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002769
2770 /* If no wininfo for curwin, use the first in the list (that doesn't have
2771 * 'diff' set and is in another tab page). */
2772 if (wip == NULL)
2773 {
2774#ifdef FEAT_DIFF
2775 if (skip_diff_buffer)
2776 {
2777 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
2778 if (!wininfo_other_tab_diff(wip))
2779 break;
2780 }
2781 else
2782#endif
2783 wip = buf->b_wininfo;
2784 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785 return wip;
2786}
2787
2788/*
2789 * Reset the local window options to the values last used in this window.
2790 * If the buffer wasn't used in this window before, use the values from
2791 * the most recently used window. If the values were never set, use the
2792 * global values for the window.
2793 */
2794 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002795get_winopts(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796{
2797 wininfo_T *wip;
2798
2799 clear_winopt(&curwin->w_onebuf_opt);
2800#ifdef FEAT_FOLDING
2801 clearFolding(curwin);
2802#endif
2803
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002804 wip = find_wininfo(buf, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002805 if (wip != NULL && wip->wi_optset)
2806 {
2807 copy_winopt(&wip->wi_opt, &curwin->w_onebuf_opt);
2808#ifdef FEAT_FOLDING
2809 curwin->w_fold_manual = wip->wi_fold_manual;
2810 curwin->w_foldinvalid = TRUE;
2811 cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds);
2812#endif
2813 }
2814 else
2815 copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
2816
2817#ifdef FEAT_FOLDING
2818 /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */
2819 if (p_fdls >= 0)
2820 curwin->w_p_fdl = p_fdls;
2821#endif
Bram Moolenaar1701e402011-05-05 17:32:44 +02002822#ifdef FEAT_SYN_HL
2823 check_colorcolumn(curwin);
2824#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825}
2826
2827/*
2828 * Find the position (lnum and col) for the buffer 'buf' for the current
2829 * window.
2830 * Returns a pointer to no_position if no position is found.
2831 */
2832 pos_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01002833buflist_findfpos(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002834{
2835 wininfo_T *wip;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00002836 static pos_T no_position = INIT_POS_T(1, 0, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002838 wip = find_wininfo(buf, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002839 if (wip != NULL)
2840 return &(wip->wi_fpos);
2841 else
2842 return &no_position;
2843}
2844
2845/*
2846 * Find the lnum for the buffer 'buf' for the current window.
2847 */
2848 linenr_T
Bram Moolenaar7454a062016-01-30 15:14:10 +01002849buflist_findlnum(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002850{
2851 return buflist_findfpos(buf)->lnum;
2852}
2853
2854#if defined(FEAT_LISTCMDS) || defined(PROTO)
2855/*
2856 * List all know file names (for :files and :buffers command).
2857 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002859buflist_list(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860{
2861 buf_T *buf;
2862 int len;
2863 int i;
2864
2865 for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
2866 {
2867 /* skip unlisted buffers, unless ! was used */
Bram Moolenaard51cb702015-07-21 15:03:06 +02002868 if ((!buf->b_p_bl && !eap->forceit && !vim_strchr(eap->arg, 'u'))
2869 || (vim_strchr(eap->arg, 'u') && buf->b_p_bl)
2870 || (vim_strchr(eap->arg, '+')
2871 && ((buf->b_flags & BF_READERR) || !bufIsChanged(buf)))
2872 || (vim_strchr(eap->arg, 'a')
2873 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows == 0))
2874 || (vim_strchr(eap->arg, 'h')
2875 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows != 0))
2876 || (vim_strchr(eap->arg, '-') && buf->b_p_ma)
2877 || (vim_strchr(eap->arg, '=') && !buf->b_p_ro)
2878 || (vim_strchr(eap->arg, 'x') && !(buf->b_flags & BF_READERR))
2879 || (vim_strchr(eap->arg, '%') && buf != curbuf)
2880 || (vim_strchr(eap->arg, '#')
2881 && (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882 continue;
2883 msg_putchar('\n');
2884 if (buf_spname(buf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002885 vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886 else
2887 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
2888
Bram Moolenaar50cde822005-06-05 21:54:54 +00002889 len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002890 buf->b_fnum,
2891 buf->b_p_bl ? ' ' : 'u',
2892 buf == curbuf ? '%' :
2893 (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
2894 buf->b_ml.ml_mfp == NULL ? ' ' :
2895 (buf->b_nwindows == 0 ? 'h' : 'a'),
2896 !buf->b_p_ma ? '-' : (buf->b_p_ro ? '=' : ' '),
2897 (buf->b_flags & BF_READERR) ? 'x'
Bram Moolenaar51485f02005-06-04 21:55:20 +00002898 : (bufIsChanged(buf) ? '+' : ' '),
2899 NameBuff);
Bram Moolenaar507edf62016-01-10 20:54:17 +01002900 if (len > IOSIZE - 20)
2901 len = IOSIZE - 20;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902
2903 /* put "line 999" in column 40 or after the file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904 i = 40 - vim_strsize(IObuff);
2905 do
2906 {
2907 IObuff[len++] = ' ';
2908 } while (--i > 0 && len < IOSIZE - 18);
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00002909 vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
2910 _("line %ld"), buf == curbuf ? curwin->w_cursor.lnum
Bram Moolenaar9c13b352005-05-19 20:53:52 +00002911 : (long)buflist_findlnum(buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912 msg_outtrans(IObuff);
2913 out_flush(); /* output one line at a time */
2914 ui_breakcheck();
2915 }
2916}
2917#endif
2918
2919/*
2920 * Get file name and line number for file 'fnum'.
2921 * Used by DoOneCmd() for translating '%' and '#'.
2922 * Used by insert_reg() and cmdline_paste() for '#' register.
2923 * Return FAIL if not found, OK for success.
2924 */
2925 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002926buflist_name_nr(
2927 int fnum,
2928 char_u **fname,
2929 linenr_T *lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930{
2931 buf_T *buf;
2932
2933 buf = buflist_findnr(fnum);
2934 if (buf == NULL || buf->b_fname == NULL)
2935 return FAIL;
2936
2937 *fname = buf->b_fname;
2938 *lnum = buflist_findlnum(buf);
2939
2940 return OK;
2941}
2942
2943/*
2944 * Set the file name for "buf"' to 'ffname', short file name to 'sfname'.
2945 * The file name with the full path is also remembered, for when :cd is used.
2946 * Returns FAIL for failure (file name already in use by other buffer)
2947 * OK otherwise.
2948 */
2949 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002950setfname(
2951 buf_T *buf,
2952 char_u *ffname,
2953 char_u *sfname,
2954 int message) /* give message when buffer already exists */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955{
Bram Moolenaar81695252004-12-29 20:58:21 +00002956 buf_T *obuf = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957#ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02002958 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002959#endif
2960
2961 if (ffname == NULL || *ffname == NUL)
2962 {
2963 /* Removing the name. */
2964 vim_free(buf->b_ffname);
2965 vim_free(buf->b_sfname);
2966 buf->b_ffname = NULL;
2967 buf->b_sfname = NULL;
2968#ifdef UNIX
2969 st.st_dev = (dev_T)-1;
2970#endif
2971 }
2972 else
2973 {
2974 fname_expand(buf, &ffname, &sfname); /* will allocate ffname */
2975 if (ffname == NULL) /* out of memory */
2976 return FAIL;
2977
2978 /*
2979 * if the file name is already used in another buffer:
2980 * - if the buffer is loaded, fail
2981 * - if the buffer is not loaded, delete it from the list
2982 */
2983#ifdef UNIX
2984 if (mch_stat((char *)ffname, &st) < 0)
2985 st.st_dev = (dev_T)-1;
Bram Moolenaar81695252004-12-29 20:58:21 +00002986#endif
2987 if (!(buf->b_flags & BF_DUMMY))
2988#ifdef UNIX
2989 obuf = buflist_findname_stat(ffname, &st);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990#else
Bram Moolenaar81695252004-12-29 20:58:21 +00002991 obuf = buflist_findname(ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002992#endif
2993 if (obuf != NULL && obuf != buf)
2994 {
2995 if (obuf->b_ml.ml_mfp != NULL) /* it's loaded, fail */
2996 {
2997 if (message)
2998 EMSG(_("E95: Buffer with this name already exists"));
2999 vim_free(ffname);
3000 return FAIL;
3001 }
Bram Moolenaar42ec6562012-02-22 14:58:37 +01003002 /* delete from the list */
3003 close_buffer(NULL, obuf, DOBUF_WIPE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003004 }
3005 sfname = vim_strsave(sfname);
3006 if (ffname == NULL || sfname == NULL)
3007 {
3008 vim_free(sfname);
3009 vim_free(ffname);
3010 return FAIL;
3011 }
3012#ifdef USE_FNAME_CASE
3013# ifdef USE_LONG_FNAME
3014 if (USE_LONG_FNAME)
3015# endif
3016 fname_case(sfname, 0); /* set correct case for short file name */
3017#endif
3018 vim_free(buf->b_ffname);
3019 vim_free(buf->b_sfname);
3020 buf->b_ffname = ffname;
3021 buf->b_sfname = sfname;
3022 }
3023 buf->b_fname = buf->b_sfname;
3024#ifdef UNIX
3025 if (st.st_dev == (dev_T)-1)
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003026 buf->b_dev_valid = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003027 else
3028 {
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003029 buf->b_dev_valid = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030 buf->b_dev = st.st_dev;
3031 buf->b_ino = st.st_ino;
3032 }
3033#endif
3034
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035 buf->b_shortname = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036
3037 buf_name_changed(buf);
3038 return OK;
3039}
3040
3041/*
Bram Moolenaar86b68352004-12-27 21:59:20 +00003042 * Crude way of changing the name of a buffer. Use with care!
3043 * The name should be relative to the current directory.
3044 */
3045 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003046buf_set_name(int fnum, char_u *name)
Bram Moolenaar86b68352004-12-27 21:59:20 +00003047{
3048 buf_T *buf;
3049
3050 buf = buflist_findnr(fnum);
3051 if (buf != NULL)
3052 {
3053 vim_free(buf->b_sfname);
3054 vim_free(buf->b_ffname);
Bram Moolenaarf193fff2006-04-27 00:02:13 +00003055 buf->b_ffname = vim_strsave(name);
3056 buf->b_sfname = NULL;
3057 /* Allocate ffname and expand into full path. Also resolves .lnk
3058 * files on Win32. */
3059 fname_expand(buf, &buf->b_ffname, &buf->b_sfname);
Bram Moolenaar86b68352004-12-27 21:59:20 +00003060 buf->b_fname = buf->b_sfname;
3061 }
3062}
3063
3064/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065 * Take care of what needs to be done when the name of buffer "buf" has
3066 * changed.
3067 */
3068 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003069buf_name_changed(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070{
3071 /*
3072 * If the file name changed, also change the name of the swapfile
3073 */
3074 if (buf->b_ml.ml_mfp != NULL)
3075 ml_setname(buf);
3076
3077 if (curwin->w_buffer == buf)
3078 check_arg_idx(curwin); /* check file name for arg list */
3079#ifdef FEAT_TITLE
3080 maketitle(); /* set window title */
3081#endif
3082#ifdef FEAT_WINDOWS
3083 status_redraw_all(); /* status lines need to be redrawn */
3084#endif
3085 fmarks_check_names(buf); /* check named file marks */
3086 ml_timestamp(buf); /* reset timestamp */
3087}
3088
3089/*
3090 * set alternate file name for current window
3091 *
3092 * Used by do_one_cmd(), do_write() and do_ecmd().
3093 * Return the buffer.
3094 */
3095 buf_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +01003096setaltfname(
3097 char_u *ffname,
3098 char_u *sfname,
3099 linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100{
3101 buf_T *buf;
3102
3103 /* Create a buffer. 'buflisted' is not set if it's a new buffer */
3104 buf = buflist_new(ffname, sfname, lnum, 0);
Bram Moolenaard4755bb2004-09-02 19:12:26 +00003105 if (buf != NULL && !cmdmod.keepalt)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106 curwin->w_alt_fnum = buf->b_fnum;
3107 return buf;
3108}
3109
3110/*
3111 * Get alternate file name for current window.
3112 * Return NULL if there isn't any, and give error message if requested.
3113 */
3114 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01003115getaltfname(
3116 int errmsg) /* give error message */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003117{
3118 char_u *fname;
3119 linenr_T dummy;
3120
3121 if (buflist_name_nr(0, &fname, &dummy) == FAIL)
3122 {
3123 if (errmsg)
3124 EMSG(_(e_noalt));
3125 return NULL;
3126 }
3127 return fname;
3128}
3129
3130/*
3131 * Add a file name to the buflist and return its number.
3132 * Uses same flags as buflist_new(), except BLN_DUMMY.
3133 *
3134 * used by qf_init(), main() and doarglist()
3135 */
3136 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003137buflist_add(char_u *fname, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138{
3139 buf_T *buf;
3140
3141 buf = buflist_new(fname, NULL, (linenr_T)0, flags);
3142 if (buf != NULL)
3143 return buf->b_fnum;
3144 return 0;
3145}
3146
3147#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3148/*
3149 * Adjust slashes in file names. Called after 'shellslash' was set.
3150 */
3151 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003152buflist_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153{
3154 buf_T *bp;
3155
3156 for (bp = firstbuf; bp != NULL; bp = bp->b_next)
3157 {
3158 if (bp->b_ffname != NULL)
3159 slash_adjust(bp->b_ffname);
3160 if (bp->b_sfname != NULL)
3161 slash_adjust(bp->b_sfname);
3162 }
3163}
3164#endif
3165
3166/*
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003167 * Set alternate cursor position for the current buffer and window "win".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168 * Also save the local window option values.
3169 */
3170 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003171buflist_altfpos(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172{
Bram Moolenaar701f7af2008-11-15 13:12:07 +00003173 buflist_setfpos(curbuf, win, win->w_cursor.lnum, win->w_cursor.col, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174}
3175
3176/*
3177 * Return TRUE if 'ffname' is not the same file as current file.
3178 * Fname must have a full path (expanded by mch_FullName()).
3179 */
3180 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003181otherfile(char_u *ffname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003182{
3183 return otherfile_buf(curbuf, ffname
3184#ifdef UNIX
3185 , NULL
3186#endif
3187 );
3188}
3189
3190 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003191otherfile_buf(
3192 buf_T *buf,
3193 char_u *ffname
Bram Moolenaar071d4272004-06-13 20:20:40 +00003194#ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003195 , stat_T *stp
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196#endif
Bram Moolenaar7454a062016-01-30 15:14:10 +01003197 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198{
3199 /* no name is different */
3200 if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL)
3201 return TRUE;
3202 if (fnamecmp(ffname, buf->b_ffname) == 0)
3203 return FALSE;
3204#ifdef UNIX
3205 {
Bram Moolenaar8767f522016-07-01 17:17:39 +02003206 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003207
Bram Moolenaar8767f522016-07-01 17:17:39 +02003208 /* If no stat_T given, get it now */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209 if (stp == NULL)
3210 {
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003211 if (!buf->b_dev_valid || mch_stat((char *)ffname, &st) < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 st.st_dev = (dev_T)-1;
3213 stp = &st;
3214 }
3215 /* Use dev/ino to check if the files are the same, even when the names
3216 * are different (possible with links). Still need to compare the
3217 * name above, for when the file doesn't exist yet.
3218 * Problem: The dev/ino changes when a file is deleted (and created
3219 * again) and remains the same when renamed/moved. We don't want to
3220 * mch_stat() each buffer each time, that would be too slow. Get the
3221 * dev/ino again when they appear to match, but not when they appear
3222 * to be different: Could skip a buffer when it's actually the same
3223 * file. */
3224 if (buf_same_ino(buf, stp))
3225 {
3226 buf_setino(buf);
3227 if (buf_same_ino(buf, stp))
3228 return FALSE;
3229 }
3230 }
3231#endif
3232 return TRUE;
3233}
3234
3235#if defined(UNIX) || defined(PROTO)
3236/*
3237 * Set inode and device number for a buffer.
3238 * Must always be called when b_fname is changed!.
3239 */
3240 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003241buf_setino(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242{
Bram Moolenaar8767f522016-07-01 17:17:39 +02003243 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244
3245 if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0)
3246 {
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003247 buf->b_dev_valid = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248 buf->b_dev = st.st_dev;
3249 buf->b_ino = st.st_ino;
3250 }
3251 else
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003252 buf->b_dev_valid = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253}
3254
3255/*
3256 * Return TRUE if dev/ino in buffer "buf" matches with "stp".
3257 */
3258 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003259buf_same_ino(
3260 buf_T *buf,
Bram Moolenaar8767f522016-07-01 17:17:39 +02003261 stat_T *stp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262{
Bram Moolenaarf1726cc2009-05-13 18:48:16 +00003263 return (buf->b_dev_valid
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264 && stp->st_dev == buf->b_dev
3265 && stp->st_ino == buf->b_ino);
3266}
3267#endif
3268
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003269/*
3270 * Print info about the current buffer.
3271 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003273fileinfo(
3274 int fullname, /* when non-zero print full path */
3275 int shorthelp,
3276 int dont_truncate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003277{
3278 char_u *name;
3279 int n;
3280 char_u *p;
3281 char_u *buffer;
Bram Moolenaar9c13b352005-05-19 20:53:52 +00003282 size_t len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003283
3284 buffer = alloc(IOSIZE);
3285 if (buffer == NULL)
3286 return;
3287
3288 if (fullname > 1) /* 2 CTRL-G: include buffer number */
3289 {
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003290 vim_snprintf((char *)buffer, IOSIZE, "buf %d: ", curbuf->b_fnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291 p = buffer + STRLEN(buffer);
3292 }
3293 else
3294 p = buffer;
3295
3296 *p++ = '"';
3297 if (buf_spname(curbuf) != NULL)
Bram Moolenaarec3cfeb2012-10-03 17:12:47 +02003298 vim_strncpy(p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299 else
3300 {
3301 if (!fullname && curbuf->b_fname != NULL)
3302 name = curbuf->b_fname;
3303 else
3304 name = curbuf->b_ffname;
3305 home_replace(shorthelp ? curbuf : NULL, name, p,
3306 (int)(IOSIZE - (p - buffer)), TRUE);
3307 }
3308
Bram Moolenaara800b422010-06-27 01:15:55 +02003309 vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310 curbufIsChanged() ? (shortmess(SHM_MOD)
3311 ? " [+]" : _(" [Modified]")) : " ",
3312 (curbuf->b_flags & BF_NOTEDITED)
3313#ifdef FEAT_QUICKFIX
3314 && !bt_dontwrite(curbuf)
3315#endif
3316 ? _("[Not edited]") : "",
3317 (curbuf->b_flags & BF_NEW)
3318#ifdef FEAT_QUICKFIX
3319 && !bt_dontwrite(curbuf)
3320#endif
3321 ? _("[New file]") : "",
3322 (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "",
Bram Moolenaar23584032013-06-07 20:17:11 +02003323 curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]")
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 : _("[readonly]")) : "",
3325 (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK)
3326 || curbuf->b_p_ro) ?
3327 " " : "");
3328 /* With 32 bit longs and more than 21,474,836 lines multiplying by 100
3329 * causes an overflow, thus for large numbers divide instead. */
3330 if (curwin->w_cursor.lnum > 1000000L)
3331 n = (int)(((long)curwin->w_cursor.lnum) /
3332 ((long)curbuf->b_ml.ml_line_count / 100L));
3333 else
3334 n = (int)(((long)curwin->w_cursor.lnum * 100L) /
3335 (long)curbuf->b_ml.ml_line_count);
3336 if (curbuf->b_ml.ml_flags & ML_EMPTY)
3337 {
Bram Moolenaara800b422010-06-27 01:15:55 +02003338 vim_snprintf_add((char *)buffer, IOSIZE, "%s", _(no_lines_msg));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 }
3340#ifdef FEAT_CMDL_INFO
3341 else if (p_ru)
3342 {
3343 /* Current line and column are already on the screen -- webb */
3344 if (curbuf->b_ml.ml_line_count == 1)
Bram Moolenaara800b422010-06-27 01:15:55 +02003345 vim_snprintf_add((char *)buffer, IOSIZE, _("1 line --%d%%--"), n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346 else
Bram Moolenaara800b422010-06-27 01:15:55 +02003347 vim_snprintf_add((char *)buffer, IOSIZE, _("%ld lines --%d%%--"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003348 (long)curbuf->b_ml.ml_line_count, n);
3349 }
3350#endif
3351 else
3352 {
Bram Moolenaara800b422010-06-27 01:15:55 +02003353 vim_snprintf_add((char *)buffer, IOSIZE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354 _("line %ld of %ld --%d%%-- col "),
3355 (long)curwin->w_cursor.lnum,
3356 (long)curbuf->b_ml.ml_line_count,
3357 n);
3358 validate_virtcol();
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003359 len = STRLEN(buffer);
3360 col_print(buffer + len, IOSIZE - len,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003361 (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
3362 }
3363
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003364 (void)append_arg_number(curwin, buffer, IOSIZE, !shortmess(SHM_FILE));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003365
3366 if (dont_truncate)
3367 {
3368 /* Temporarily set msg_scroll to avoid the message being truncated.
3369 * First call msg_start() to get the message in the right place. */
3370 msg_start();
3371 n = msg_scroll;
3372 msg_scroll = TRUE;
3373 msg(buffer);
3374 msg_scroll = n;
3375 }
3376 else
3377 {
3378 p = msg_trunc_attr(buffer, FALSE, 0);
3379 if (restart_edit != 0 || (msg_scrolled && !need_wait_return))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380 /* Need to repeat the message after redrawing when:
3381 * - When restart_edit is set (otherwise there will be a delay
3382 * before redrawing).
3383 * - When the screen was scrolled but there is no wait-return
3384 * prompt. */
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003385 set_keep_msg(p, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003386 }
3387
3388 vim_free(buffer);
3389}
3390
3391 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003392col_print(
3393 char_u *buf,
3394 size_t buflen,
3395 int col,
3396 int vcol)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397{
3398 if (col == vcol)
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003399 vim_snprintf((char *)buf, buflen, "%d", col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003400 else
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003401 vim_snprintf((char *)buf, buflen, "%d-%d", col, vcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402}
3403
3404#if defined(FEAT_TITLE) || defined(PROTO)
3405/*
3406 * put file name in title bar of window and in icon title
3407 */
3408
3409static char_u *lasttitle = NULL;
3410static char_u *lasticon = NULL;
3411
3412 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003413maketitle(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414{
3415 char_u *p;
3416 char_u *t_str = NULL;
3417 char_u *i_name;
3418 char_u *i_str = NULL;
3419 int maxlen = 0;
3420 int len;
3421 int mustset;
3422 char_u buf[IOSIZE];
3423 int off;
3424
3425 if (!redrawing())
3426 {
3427 /* Postpone updating the title when 'lazyredraw' is set. */
3428 need_maketitle = TRUE;
3429 return;
3430 }
3431
3432 need_maketitle = FALSE;
Bram Moolenaarbed7bec2010-07-25 13:42:29 +02003433 if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003434 return;
3435
3436 if (p_title)
3437 {
3438 if (p_titlelen > 0)
3439 {
3440 maxlen = p_titlelen * Columns / 100;
3441 if (maxlen < 10)
3442 maxlen = 10;
3443 }
3444
3445 t_str = buf;
3446 if (*p_titlestring != NUL)
3447 {
3448#ifdef FEAT_STL_OPT
Bram Moolenaard3667a22006-03-16 21:35:52 +00003449 if (stl_syntax & STL_IN_TITLE)
3450 {
3451 int use_sandbox = FALSE;
3452 int save_called_emsg = called_emsg;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003453
3454# ifdef FEAT_EVAL
Bram Moolenaard3667a22006-03-16 21:35:52 +00003455 use_sandbox = was_set_insecurely((char_u *)"titlestring", 0);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003456# endif
Bram Moolenaard3667a22006-03-16 21:35:52 +00003457 called_emsg = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003458 build_stl_str_hl(curwin, t_str, sizeof(buf),
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003459 p_titlestring, use_sandbox,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003460 0, maxlen, NULL, NULL);
Bram Moolenaard3667a22006-03-16 21:35:52 +00003461 if (called_emsg)
3462 set_string_option_direct((char_u *)"titlestring", -1,
3463 (char_u *)"", OPT_FREE, SID_ERROR);
3464 called_emsg |= save_called_emsg;
3465 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466 else
3467#endif
3468 t_str = p_titlestring;
3469 }
3470 else
3471 {
3472 /* format: "fname + (path) (1 of 2) - VIM" */
3473
Bram Moolenaar2c666692012-09-05 13:30:40 +02003474#define SPACE_FOR_FNAME (IOSIZE - 100)
3475#define SPACE_FOR_DIR (IOSIZE - 20)
3476#define SPACE_FOR_ARGNR (IOSIZE - 10) /* at least room for " - VIM" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003477 if (curbuf->b_fname == NULL)
Bram Moolenaar2c666692012-09-05 13:30:40 +02003478 vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003479 else
3480 {
3481 p = transstr(gettail(curbuf->b_fname));
Bram Moolenaar2c666692012-09-05 13:30:40 +02003482 vim_strncpy(buf, p, SPACE_FOR_FNAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003483 vim_free(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 }
3485
3486 switch (bufIsChanged(curbuf)
3487 + (curbuf->b_p_ro * 2)
3488 + (!curbuf->b_p_ma * 4))
3489 {
3490 case 1: STRCAT(buf, " +"); break;
3491 case 2: STRCAT(buf, " ="); break;
3492 case 3: STRCAT(buf, " =+"); break;
3493 case 4:
3494 case 6: STRCAT(buf, " -"); break;
3495 case 5:
3496 case 7: STRCAT(buf, " -+"); break;
3497 }
3498
3499 if (curbuf->b_fname != NULL)
3500 {
3501 /* Get path of file, replace home dir with ~ */
3502 off = (int)STRLEN(buf);
3503 buf[off++] = ' ';
3504 buf[off++] = '(';
3505 home_replace(curbuf, curbuf->b_ffname,
Bram Moolenaar2c666692012-09-05 13:30:40 +02003506 buf + off, SPACE_FOR_DIR - off, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507#ifdef BACKSLASH_IN_FILENAME
3508 /* avoid "c:/name" to be reduced to "c" */
3509 if (isalpha(buf[off]) && buf[off + 1] == ':')
3510 off += 2;
3511#endif
3512 /* remove the file name */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003513 p = gettail_sep(buf + off);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514 if (p == buf + off)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003515 /* must be a help buffer */
Bram Moolenaarb6356332005-07-18 21:40:44 +00003516 vim_strncpy(buf + off, (char_u *)_("help"),
Bram Moolenaar2c666692012-09-05 13:30:40 +02003517 (size_t)(SPACE_FOR_DIR - off - 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 *p = NUL;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003520
Bram Moolenaar2c666692012-09-05 13:30:40 +02003521 /* Translate unprintable chars and concatenate. Keep some
3522 * room for the server name. When there is no room (very long
3523 * file name) use (...). */
3524 if (off < SPACE_FOR_DIR)
3525 {
3526 p = transstr(buf + off);
3527 vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off));
3528 vim_free(p);
3529 }
3530 else
3531 {
3532 vim_strncpy(buf + off, (char_u *)"...",
3533 (size_t)(SPACE_FOR_ARGNR - off));
3534 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003535 STRCAT(buf, ")");
3536 }
3537
Bram Moolenaar2c666692012-09-05 13:30:40 +02003538 append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003539
3540#if defined(FEAT_CLIENTSERVER)
3541 if (serverName != NULL)
3542 {
3543 STRCAT(buf, " - ");
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02003544 vim_strcat(buf, serverName, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003545 }
3546 else
3547#endif
3548 STRCAT(buf, " - VIM");
3549
3550 if (maxlen > 0)
3551 {
3552 /* make it shorter by removing a bit in the middle */
Bram Moolenaarf31b7642012-01-20 20:44:43 +01003553 if (vim_strsize(buf) > maxlen)
3554 trunc_string(buf, buf, maxlen, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555 }
3556 }
3557 }
3558 mustset = ti_change(t_str, &lasttitle);
3559
3560 if (p_icon)
3561 {
3562 i_str = buf;
3563 if (*p_iconstring != NUL)
3564 {
3565#ifdef FEAT_STL_OPT
Bram Moolenaard3667a22006-03-16 21:35:52 +00003566 if (stl_syntax & STL_IN_ICON)
3567 {
3568 int use_sandbox = FALSE;
3569 int save_called_emsg = called_emsg;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003570
3571# ifdef FEAT_EVAL
Bram Moolenaard3667a22006-03-16 21:35:52 +00003572 use_sandbox = was_set_insecurely((char_u *)"iconstring", 0);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003573# endif
Bram Moolenaard3667a22006-03-16 21:35:52 +00003574 called_emsg = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575 build_stl_str_hl(curwin, i_str, sizeof(buf),
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003576 p_iconstring, use_sandbox,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003577 0, 0, NULL, NULL);
Bram Moolenaard3667a22006-03-16 21:35:52 +00003578 if (called_emsg)
3579 set_string_option_direct((char_u *)"iconstring", -1,
3580 (char_u *)"", OPT_FREE, SID_ERROR);
3581 called_emsg |= save_called_emsg;
3582 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003583 else
3584#endif
3585 i_str = p_iconstring;
3586 }
3587 else
3588 {
3589 if (buf_spname(curbuf) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02003590 i_name = buf_spname(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591 else /* use file name only in icon */
3592 i_name = gettail(curbuf->b_ffname);
3593 *i_str = NUL;
3594 /* Truncate name at 100 bytes. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003595 len = (int)STRLEN(i_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003596 if (len > 100)
3597 {
3598 len -= 100;
3599#ifdef FEAT_MBYTE
3600 if (has_mbyte)
3601 len += (*mb_tail_off)(i_name, i_name + len) + 1;
3602#endif
3603 i_name += len;
3604 }
3605 STRCPY(i_str, i_name);
3606 trans_characters(i_str, IOSIZE);
3607 }
3608 }
3609
3610 mustset |= ti_change(i_str, &lasticon);
3611
3612 if (mustset)
3613 resettitle();
3614}
3615
3616/*
3617 * Used for title and icon: Check if "str" differs from "*last". Set "*last"
3618 * from "str" if it does.
3619 * Return TRUE when "*last" changed.
3620 */
3621 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003622ti_change(char_u *str, char_u **last)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003623{
3624 if ((str == NULL) != (*last == NULL)
3625 || (str != NULL && *last != NULL && STRCMP(str, *last) != 0))
3626 {
3627 vim_free(*last);
3628 if (str == NULL)
3629 *last = NULL;
3630 else
3631 *last = vim_strsave(str);
3632 return TRUE;
3633 }
3634 return FALSE;
3635}
3636
3637/*
3638 * Put current window title back (used after calling a shell)
3639 */
3640 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003641resettitle(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642{
3643 mch_settitle(lasttitle, lasticon);
3644}
Bram Moolenaarea408852005-06-25 22:49:46 +00003645
3646# if defined(EXITFREE) || defined(PROTO)
3647 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003648free_titles(void)
Bram Moolenaarea408852005-06-25 22:49:46 +00003649{
3650 vim_free(lasttitle);
3651 vim_free(lasticon);
3652}
3653# endif
3654
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655#endif /* FEAT_TITLE */
3656
Bram Moolenaarba6c0522006-02-25 21:45:02 +00003657#if defined(FEAT_STL_OPT) || defined(FEAT_GUI_TABLINE) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003658/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003659 * Build a string from the status line items in "fmt".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003660 * Return length of string in screen cells.
3661 *
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003662 * Normally works for window "wp", except when working for 'tabline' then it
3663 * is "curwin".
3664 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 * Items are drawn interspersed with the text that surrounds it
3666 * Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation
3667 * Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional
3668 *
3669 * If maxwidth is not zero, the string will be filled at any middle marker
3670 * or truncated if too long, fillchar is used for all whitespace.
3671 */
3672 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003673build_stl_str_hl(
3674 win_T *wp,
3675 char_u *out, /* buffer to write into != NameBuff */
3676 size_t outlen, /* length of out[] */
3677 char_u *fmt,
3678 int use_sandbox UNUSED, /* "fmt" was set insecurely, use sandbox */
3679 int fillchar,
3680 int maxwidth,
3681 struct stl_hlrec *hltab, /* return: HL attributes (can be NULL) */
3682 struct stl_hlrec *tabtab) /* return: tab page nrs (can be NULL) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683{
3684 char_u *p;
3685 char_u *s;
3686 char_u *t;
Bram Moolenaar567199b2013-04-24 16:52:36 +02003687 int byteval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003688#ifdef FEAT_EVAL
3689 win_T *o_curwin;
3690 buf_T *o_curbuf;
3691#endif
3692 int empty_line;
3693 colnr_T virtcol;
3694 long l;
3695 long n;
3696 int prevchar_isflag;
3697 int prevchar_isitem;
3698 int itemisflag;
3699 int fillable;
3700 char_u *str;
3701 long num;
3702 int width;
3703 int itemcnt;
3704 int curitem;
3705 int groupitem[STL_MAX_ITEM];
3706 int groupdepth;
3707 struct stl_item
3708 {
3709 char_u *start;
3710 int minwid;
3711 int maxwid;
3712 enum
3713 {
3714 Normal,
3715 Empty,
3716 Group,
3717 Middle,
3718 Highlight,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003719 TabPage,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720 Trunc
3721 } type;
3722 } item[STL_MAX_ITEM];
3723 int minwid;
3724 int maxwid;
3725 int zeropad;
3726 char_u base;
3727 char_u opt;
3728#define TMPLEN 70
3729 char_u tmp[TMPLEN];
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003730 char_u *usefmt = fmt;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003731 struct stl_hlrec *sp;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003732
3733#ifdef FEAT_EVAL
3734 /*
3735 * When the format starts with "%!" then evaluate it as an expression and
3736 * use the result as the actual format string.
3737 */
3738 if (fmt[0] == '%' && fmt[1] == '!')
3739 {
3740 usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox);
3741 if (usefmt == NULL)
Bram Moolenaar4100af72006-08-29 14:48:14 +00003742 usefmt = fmt;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003743 }
3744#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745
3746 if (fillchar == 0)
3747 fillchar = ' ';
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003748#ifdef FEAT_MBYTE
3749 /* Can't handle a multi-byte fill character yet. */
3750 else if (mb_char2len(fillchar) > 1)
3751 fillchar = '-';
3752#endif
3753
Bram Moolenaar567199b2013-04-24 16:52:36 +02003754 /* Get line & check if empty (cursorpos will show "0-1"). Note that
3755 * p will become invalid when getting another buffer line. */
3756 p = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE);
3757 empty_line = (*p == NUL);
3758
3759 /* Get the byte value now, in case we need it below. This is more
3760 * efficient than making a copy of the line. */
3761 if (wp->w_cursor.col > (colnr_T)STRLEN(p))
3762 byteval = 0;
3763 else
3764#ifdef FEAT_MBYTE
3765 byteval = (*mb_ptr2char)(p + wp->w_cursor.col);
3766#else
3767 byteval = p[wp->w_cursor.col];
3768#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769
3770 groupdepth = 0;
3771 p = out;
3772 curitem = 0;
3773 prevchar_isflag = TRUE;
3774 prevchar_isitem = FALSE;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003775 for (s = usefmt; *s; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003776 {
Bram Moolenaarb75d09d2011-02-15 14:24:46 +01003777 if (curitem == STL_MAX_ITEM)
3778 {
3779 /* There are too many items. Add the error code to the statusline
3780 * to give the user a hint about what went wrong. */
3781 if (p + 6 < out + outlen)
3782 {
3783 mch_memmove(p, " E541", (size_t)5);
3784 p += 5;
3785 }
3786 break;
3787 }
3788
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 if (*s != NUL && *s != '%')
3790 prevchar_isflag = prevchar_isitem = FALSE;
3791
3792 /*
3793 * Handle up to the next '%' or the end.
3794 */
3795 while (*s != NUL && *s != '%' && p + 1 < out + outlen)
3796 *p++ = *s++;
3797 if (*s == NUL || p + 1 >= out + outlen)
3798 break;
3799
3800 /*
3801 * Handle one '%' item.
3802 */
3803 s++;
Bram Moolenaar1d87f512011-02-01 21:55:01 +01003804 if (*s == NUL) /* ignore trailing % */
3805 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806 if (*s == '%')
3807 {
3808 if (p + 1 >= out + outlen)
3809 break;
3810 *p++ = *s++;
3811 prevchar_isflag = prevchar_isitem = FALSE;
3812 continue;
3813 }
3814 if (*s == STL_MIDDLEMARK)
3815 {
3816 s++;
3817 if (groupdepth > 0)
3818 continue;
3819 item[curitem].type = Middle;
3820 item[curitem++].start = p;
3821 continue;
3822 }
3823 if (*s == STL_TRUNCMARK)
3824 {
3825 s++;
3826 item[curitem].type = Trunc;
3827 item[curitem++].start = p;
3828 continue;
3829 }
3830 if (*s == ')')
3831 {
3832 s++;
3833 if (groupdepth < 1)
3834 continue;
3835 groupdepth--;
3836
3837 t = item[groupitem[groupdepth]].start;
3838 *p = NUL;
3839 l = vim_strsize(t);
3840 if (curitem > groupitem[groupdepth] + 1
3841 && item[groupitem[groupdepth]].minwid == 0)
3842 {
3843 /* remove group if all items are empty */
3844 for (n = groupitem[groupdepth] + 1; n < curitem; n++)
Bram Moolenaaraf6e36f2016-03-08 12:56:33 +01003845 if (item[n].type == Normal || item[n].type == Highlight)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003846 break;
3847 if (n == curitem)
3848 {
3849 p = t;
3850 l = 0;
3851 }
3852 }
3853 if (l > item[groupitem[groupdepth]].maxwid)
3854 {
3855 /* truncate, remove n bytes of text at the start */
3856#ifdef FEAT_MBYTE
3857 if (has_mbyte)
3858 {
3859 /* Find the first character that should be included. */
3860 n = 0;
3861 while (l >= item[groupitem[groupdepth]].maxwid)
3862 {
3863 l -= ptr2cells(t + n);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003864 n += (*mb_ptr2len)(t + n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003865 }
3866 }
3867 else
3868#endif
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003869 n = (long)(p - t) - item[groupitem[groupdepth]].maxwid + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003870
3871 *t = '<';
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003872 mch_memmove(t + 1, t + n, (size_t)(p - (t + n)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873 p = p - n + 1;
3874#ifdef FEAT_MBYTE
3875 /* Fill up space left over by half a double-wide char. */
3876 while (++l < item[groupitem[groupdepth]].minwid)
3877 *p++ = fillchar;
3878#endif
3879
3880 /* correct the start of the items for the truncation */
3881 for (l = groupitem[groupdepth] + 1; l < curitem; l++)
3882 {
3883 item[l].start -= n;
3884 if (item[l].start < t)
3885 item[l].start = t;
3886 }
3887 }
3888 else if (abs(item[groupitem[groupdepth]].minwid) > l)
3889 {
3890 /* fill */
3891 n = item[groupitem[groupdepth]].minwid;
3892 if (n < 0)
3893 {
3894 /* fill by appending characters */
3895 n = 0 - n;
3896 while (l++ < n && p + 1 < out + outlen)
3897 *p++ = fillchar;
3898 }
3899 else
3900 {
3901 /* fill by inserting characters */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00003902 mch_memmove(t + n - l, t, (size_t)(p - t));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003903 l = n - l;
3904 if (p + l >= out + outlen)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003905 l = (long)((out + outlen) - p - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906 p += l;
3907 for (n = groupitem[groupdepth] + 1; n < curitem; n++)
3908 item[n].start += l;
3909 for ( ; l > 0; l--)
3910 *t++ = fillchar;
3911 }
3912 }
3913 continue;
3914 }
3915 minwid = 0;
3916 maxwid = 9999;
3917 zeropad = FALSE;
3918 l = 1;
3919 if (*s == '0')
3920 {
3921 s++;
3922 zeropad = TRUE;
3923 }
3924 if (*s == '-')
3925 {
3926 s++;
3927 l = -1;
3928 }
3929 if (VIM_ISDIGIT(*s))
3930 {
3931 minwid = (int)getdigits(&s);
3932 if (minwid < 0) /* overflow */
3933 minwid = 0;
3934 }
Bram Moolenaar030f0df2006-02-21 22:02:53 +00003935 if (*s == STL_USER_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936 {
3937 item[curitem].type = Highlight;
3938 item[curitem].start = p;
3939 item[curitem].minwid = minwid > 9 ? 1 : minwid;
3940 s++;
3941 curitem++;
3942 continue;
3943 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003944 if (*s == STL_TABPAGENR || *s == STL_TABCLOSENR)
3945 {
3946 if (*s == STL_TABCLOSENR)
3947 {
3948 if (minwid == 0)
3949 {
3950 /* %X ends the close label, go back to the previously
3951 * define tab label nr. */
3952 for (n = curitem - 1; n >= 0; --n)
3953 if (item[n].type == TabPage && item[n].minwid >= 0)
3954 {
3955 minwid = item[n].minwid;
3956 break;
3957 }
3958 }
3959 else
3960 /* close nrs are stored as negative values */
3961 minwid = - minwid;
3962 }
3963 item[curitem].type = TabPage;
3964 item[curitem].start = p;
3965 item[curitem].minwid = minwid;
3966 s++;
3967 curitem++;
3968 continue;
3969 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970 if (*s == '.')
3971 {
3972 s++;
3973 if (VIM_ISDIGIT(*s))
3974 {
3975 maxwid = (int)getdigits(&s);
3976 if (maxwid <= 0) /* overflow */
3977 maxwid = 50;
3978 }
3979 }
3980 minwid = (minwid > 50 ? 50 : minwid) * l;
3981 if (*s == '(')
3982 {
3983 groupitem[groupdepth++] = curitem;
3984 item[curitem].type = Group;
3985 item[curitem].start = p;
3986 item[curitem].minwid = minwid;
3987 item[curitem].maxwid = maxwid;
3988 s++;
3989 curitem++;
3990 continue;
3991 }
3992 if (vim_strchr(STL_ALL, *s) == NULL)
3993 {
3994 s++;
3995 continue;
3996 }
3997 opt = *s++;
3998
3999 /* OK - now for the real work */
4000 base = 'D';
4001 itemisflag = FALSE;
4002 fillable = TRUE;
4003 num = -1;
4004 str = NULL;
4005 switch (opt)
4006 {
4007 case STL_FILEPATH:
4008 case STL_FULLPATH:
4009 case STL_FILENAME:
4010 fillable = FALSE; /* don't change ' ' to fillchar */
4011 if (buf_spname(wp->w_buffer) != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02004012 vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 else
4014 {
4015 t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004016 : wp->w_buffer->b_fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004017 home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE);
4018 }
4019 trans_characters(NameBuff, MAXPATHL);
4020 if (opt != STL_FILENAME)
4021 str = NameBuff;
4022 else
4023 str = gettail(NameBuff);
4024 break;
4025
4026 case STL_VIM_EXPR: /* '{' */
4027 itemisflag = TRUE;
4028 t = p;
4029 while (*s != '}' && *s != NUL && p + 1 < out + outlen)
4030 *p++ = *s++;
4031 if (*s != '}') /* missing '}' or out of space */
4032 break;
4033 s++;
4034 *p = 0;
4035 p = t;
4036
4037#ifdef FEAT_EVAL
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004038 vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 set_internal_string_var((char_u *)"actual_curbuf", tmp);
4040
4041 o_curbuf = curbuf;
4042 o_curwin = curwin;
4043 curwin = wp;
4044 curbuf = wp->w_buffer;
4045
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00004046 str = eval_to_string_safe(p, &t, use_sandbox);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004047
4048 curwin = o_curwin;
4049 curbuf = o_curbuf;
Bram Moolenaar01824652005-01-31 18:58:23 +00004050 do_unlet((char_u *)"g:actual_curbuf", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004051
4052 if (str != NULL && *str != 0)
4053 {
4054 if (*skipdigits(str) == NUL)
4055 {
4056 num = atoi((char *)str);
4057 vim_free(str);
4058 str = NULL;
4059 itemisflag = FALSE;
4060 }
4061 }
4062#endif
4063 break;
4064
4065 case STL_LINE:
4066 num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
4067 ? 0L : (long)(wp->w_cursor.lnum);
4068 break;
4069
4070 case STL_NUMLINES:
4071 num = wp->w_buffer->b_ml.ml_line_count;
4072 break;
4073
4074 case STL_COLUMN:
4075 num = !(State & INSERT) && empty_line
4076 ? 0 : (int)wp->w_cursor.col + 1;
4077 break;
4078
4079 case STL_VIRTCOL:
4080 case STL_VIRTCOL_ALT:
4081 /* In list mode virtcol needs to be recomputed */
4082 virtcol = wp->w_virtcol;
4083 if (wp->w_p_list && lcs_tab1 == NUL)
4084 {
4085 wp->w_p_list = FALSE;
4086 getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
4087 wp->w_p_list = TRUE;
4088 }
4089 ++virtcol;
4090 /* Don't display %V if it's the same as %c. */
4091 if (opt == STL_VIRTCOL_ALT
4092 && (virtcol == (colnr_T)(!(State & INSERT) && empty_line
4093 ? 0 : (int)wp->w_cursor.col + 1)))
4094 break;
4095 num = (long)virtcol;
4096 break;
4097
4098 case STL_PERCENTAGE:
4099 num = (int)(((long)wp->w_cursor.lnum * 100L) /
4100 (long)wp->w_buffer->b_ml.ml_line_count);
4101 break;
4102
4103 case STL_ALTPERCENT:
4104 str = tmp;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004105 get_rel_pos(wp, str, TMPLEN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106 break;
4107
4108 case STL_ARGLISTSTAT:
4109 fillable = FALSE;
4110 tmp[0] = 0;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004111 if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 str = tmp;
4113 break;
4114
4115 case STL_KEYMAP:
4116 fillable = FALSE;
4117 if (get_keymap_str(wp, tmp, TMPLEN))
4118 str = tmp;
4119 break;
4120 case STL_PAGENUM:
Bram Moolenaarbfb2d402006-03-03 22:50:42 +00004121#if defined(FEAT_PRINTER) || defined(FEAT_GUI_TABLINE)
Bram Moolenaarba6c0522006-02-25 21:45:02 +00004122 num = printer_page_num;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123#else
4124 num = 0;
4125#endif
4126 break;
4127
4128 case STL_BUFNO:
4129 num = wp->w_buffer->b_fnum;
4130 break;
4131
4132 case STL_OFFSET_X:
4133 base = 'X';
4134 case STL_OFFSET:
4135#ifdef FEAT_BYTEOFF
4136 l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL);
4137 num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ?
4138 0L : l + 1 + (!(State & INSERT) && empty_line ?
4139 0 : (int)wp->w_cursor.col);
4140#endif
4141 break;
4142
4143 case STL_BYTEVAL_X:
4144 base = 'X';
4145 case STL_BYTEVAL:
Bram Moolenaar567199b2013-04-24 16:52:36 +02004146 num = byteval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004147 if (num == NL)
4148 num = 0;
4149 else if (num == CAR && get_fileformat(wp->w_buffer) == EOL_MAC)
4150 num = NL;
4151 break;
4152
4153 case STL_ROFLAG:
4154 case STL_ROFLAG_ALT:
4155 itemisflag = TRUE;
4156 if (wp->w_buffer->b_p_ro)
Bram Moolenaar23584032013-06-07 20:17:11 +02004157 str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004158 break;
4159
4160 case STL_HELPFLAG:
4161 case STL_HELPFLAG_ALT:
4162 itemisflag = TRUE;
4163 if (wp->w_buffer->b_help)
4164 str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP"
Bram Moolenaar899dddf2006-03-26 21:06:50 +00004165 : _("[Help]"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004166 break;
4167
4168#ifdef FEAT_AUTOCMD
4169 case STL_FILETYPE:
4170 if (*wp->w_buffer->b_p_ft != NUL
4171 && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3)
4172 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00004173 vim_snprintf((char *)tmp, sizeof(tmp), "[%s]",
4174 wp->w_buffer->b_p_ft);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 str = tmp;
4176 }
4177 break;
4178
4179 case STL_FILETYPE_ALT:
4180 itemisflag = TRUE;
4181 if (*wp->w_buffer->b_p_ft != NUL
4182 && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2)
4183 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00004184 vim_snprintf((char *)tmp, sizeof(tmp), ",%s",
4185 wp->w_buffer->b_p_ft);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186 for (t = tmp; *t != 0; t++)
4187 *t = TOUPPER_LOC(*t);
4188 str = tmp;
4189 }
4190 break;
4191#endif
4192
4193#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
4194 case STL_PREVIEWFLAG:
4195 case STL_PREVIEWFLAG_ALT:
4196 itemisflag = TRUE;
4197 if (wp->w_p_pvw)
4198 str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV"
4199 : _("[Preview]"));
4200 break;
Bram Moolenaar7fd73202010-07-25 16:58:46 +02004201
4202 case STL_QUICKFIX:
4203 if (bt_quickfix(wp->w_buffer))
4204 str = (char_u *)(wp->w_llist_ref
4205 ? _(msg_loclist)
4206 : _(msg_qflist));
4207 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004208#endif
4209
4210 case STL_MODIFIED:
4211 case STL_MODIFIED_ALT:
4212 itemisflag = TRUE;
4213 switch ((opt == STL_MODIFIED_ALT)
4214 + bufIsChanged(wp->w_buffer) * 2
4215 + (!wp->w_buffer->b_p_ma) * 4)
4216 {
4217 case 2: str = (char_u *)"[+]"; break;
4218 case 3: str = (char_u *)",+"; break;
4219 case 4: str = (char_u *)"[-]"; break;
4220 case 5: str = (char_u *)",-"; break;
4221 case 6: str = (char_u *)"[+-]"; break;
4222 case 7: str = (char_u *)",+-"; break;
4223 }
4224 break;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00004225
4226 case STL_HIGHLIGHT:
4227 t = s;
4228 while (*s != '#' && *s != NUL)
4229 ++s;
4230 if (*s == '#')
4231 {
4232 item[curitem].type = Highlight;
4233 item[curitem].start = p;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004234 item[curitem].minwid = -syn_namen2id(t, (int)(s - t));
Bram Moolenaar030f0df2006-02-21 22:02:53 +00004235 curitem++;
4236 }
Bram Moolenaar11808222013-11-02 04:39:38 +01004237 if (*s != NUL)
4238 ++s;
Bram Moolenaar030f0df2006-02-21 22:02:53 +00004239 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004240 }
4241
4242 item[curitem].start = p;
4243 item[curitem].type = Normal;
4244 if (str != NULL && *str)
4245 {
4246 t = str;
4247 if (itemisflag)
4248 {
4249 if ((t[0] && t[1])
4250 && ((!prevchar_isitem && *t == ',')
4251 || (prevchar_isflag && *t == ' ')))
4252 t++;
4253 prevchar_isflag = TRUE;
4254 }
4255 l = vim_strsize(t);
4256 if (l > 0)
4257 prevchar_isitem = TRUE;
4258 if (l > maxwid)
4259 {
4260 while (l >= maxwid)
4261#ifdef FEAT_MBYTE
4262 if (has_mbyte)
4263 {
4264 l -= ptr2cells(t);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004265 t += (*mb_ptr2len)(t);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004266 }
4267 else
4268#endif
4269 l -= byte2cells(*t++);
4270 if (p + 1 >= out + outlen)
4271 break;
4272 *p++ = '<';
4273 }
4274 if (minwid > 0)
4275 {
4276 for (; l < minwid && p + 1 < out + outlen; l++)
4277 {
4278 /* Don't put a "-" in front of a digit. */
4279 if (l + 1 == minwid && fillchar == '-' && VIM_ISDIGIT(*t))
4280 *p++ = ' ';
4281 else
4282 *p++ = fillchar;
4283 }
4284 minwid = 0;
4285 }
4286 else
4287 minwid *= -1;
4288 while (*t && p + 1 < out + outlen)
4289 {
4290 *p++ = *t++;
4291 /* Change a space by fillchar, unless fillchar is '-' and a
4292 * digit follows. */
4293 if (fillable && p[-1] == ' '
4294 && (!VIM_ISDIGIT(*t) || fillchar != '-'))
4295 p[-1] = fillchar;
4296 }
4297 for (; l < minwid && p + 1 < out + outlen; l++)
4298 *p++ = fillchar;
4299 }
4300 else if (num >= 0)
4301 {
4302 int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16));
4303 char_u nstr[20];
4304
4305 if (p + 20 >= out + outlen)
4306 break; /* not sufficient space */
4307 prevchar_isitem = TRUE;
4308 t = nstr;
4309 if (opt == STL_VIRTCOL_ALT)
4310 {
4311 *t++ = '-';
4312 minwid--;
4313 }
4314 *t++ = '%';
4315 if (zeropad)
4316 *t++ = '0';
4317 *t++ = '*';
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004318 *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd');
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 *t = 0;
4320
4321 for (n = num, l = 1; n >= nbase; n /= nbase)
4322 l++;
4323 if (opt == STL_VIRTCOL_ALT)
4324 l++;
4325 if (l > maxwid)
4326 {
4327 l += 2;
4328 n = l - maxwid;
4329 while (l-- > maxwid)
4330 num /= nbase;
4331 *t++ = '>';
4332 *t++ = '%';
4333 *t = t[-3];
4334 *++t = 0;
Bram Moolenaar9c13b352005-05-19 20:53:52 +00004335 vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
4336 0, num, n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004337 }
4338 else
Bram Moolenaar9c13b352005-05-19 20:53:52 +00004339 vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
4340 minwid, num);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 p += STRLEN(p);
4342 }
4343 else
4344 item[curitem].type = Empty;
4345
4346 if (opt == STL_VIM_EXPR)
4347 vim_free(str);
4348
4349 if (num >= 0 || (!itemisflag && str && *str))
4350 prevchar_isflag = FALSE; /* Item not NULL, but not a flag */
4351 curitem++;
4352 }
4353 *p = NUL;
4354 itemcnt = curitem;
4355
Bram Moolenaar030f0df2006-02-21 22:02:53 +00004356#ifdef FEAT_EVAL
4357 if (usefmt != fmt)
4358 vim_free(usefmt);
4359#endif
4360
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 width = vim_strsize(out);
4362 if (maxwidth > 0 && width > maxwidth)
4363 {
Bram Moolenaar9381ab72008-11-12 11:52:19 +00004364 /* Result is too long, must truncate somewhere. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 l = 0;
4366 if (itemcnt == 0)
4367 s = out;
4368 else
4369 {
4370 for ( ; l < itemcnt; l++)
4371 if (item[l].type == Trunc)
4372 {
4373 /* Truncate at %< item. */
4374 s = item[l].start;
4375 break;
4376 }
4377 if (l == itemcnt)
4378 {
4379 /* No %< item, truncate first item. */
4380 s = item[0].start;
4381 l = 0;
4382 }
4383 }
4384
4385 if (width - vim_strsize(s) >= maxwidth)
4386 {
4387 /* Truncation mark is beyond max length */
4388#ifdef FEAT_MBYTE
4389 if (has_mbyte)
4390 {
4391 s = out;
4392 width = 0;
4393 for (;;)
4394 {
4395 width += ptr2cells(s);
4396 if (width >= maxwidth)
4397 break;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004398 s += (*mb_ptr2len)(s);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004399 }
4400 /* Fill up for half a double-wide character. */
4401 while (++width < maxwidth)
4402 *s++ = fillchar;
4403 }
4404 else
4405#endif
4406 s = out + maxwidth - 1;
4407 for (l = 0; l < itemcnt; l++)
4408 if (item[l].start > s)
4409 break;
4410 itemcnt = l;
4411 *s++ = '>';
4412 *s = 0;
4413 }
4414 else
4415 {
4416#ifdef FEAT_MBYTE
4417 if (has_mbyte)
4418 {
4419 n = 0;
4420 while (width >= maxwidth)
4421 {
4422 width -= ptr2cells(s + n);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004423 n += (*mb_ptr2len)(s + n);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424 }
4425 }
4426 else
4427#endif
4428 n = width - maxwidth + 1;
4429 p = s + n;
Bram Moolenaarf2330482008-06-24 20:19:36 +00004430 STRMOVE(s + 1, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004431 *s = '<';
4432
4433 /* Fill up for half a double-wide character. */
4434 while (++width < maxwidth)
4435 {
4436 s = s + STRLEN(s);
4437 *s++ = fillchar;
4438 *s = NUL;
4439 }
4440
4441 --n; /* count the '<' */
4442 for (; l < itemcnt; l++)
4443 {
4444 if (item[l].start - n >= s)
4445 item[l].start -= n;
4446 else
4447 item[l].start = s;
4448 }
4449 }
4450 width = maxwidth;
4451 }
4452 else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen)
4453 {
4454 /* Apply STL_MIDDLE if any */
4455 for (l = 0; l < itemcnt; l++)
4456 if (item[l].type == Middle)
4457 break;
4458 if (l < itemcnt)
4459 {
4460 p = item[l].start + maxwidth - width;
Bram Moolenaarf2330482008-06-24 20:19:36 +00004461 STRMOVE(p, item[l].start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004462 for (s = item[l].start; s < p; s++)
4463 *s = fillchar;
4464 for (l++; l < itemcnt; l++)
4465 item[l].start += maxwidth - width;
4466 width = maxwidth;
4467 }
4468 }
4469
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004470 /* Store the info about highlighting. */
4471 if (hltab != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004473 sp = hltab;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474 for (l = 0; l < itemcnt; l++)
4475 {
4476 if (item[l].type == Highlight)
4477 {
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004478 sp->start = item[l].start;
4479 sp->userhl = item[l].minwid;
4480 sp++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481 }
4482 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004483 sp->start = NULL;
4484 sp->userhl = 0;
4485 }
4486
4487 /* Store the info about tab pages labels. */
4488 if (tabtab != NULL)
4489 {
4490 sp = tabtab;
4491 for (l = 0; l < itemcnt; l++)
4492 {
4493 if (item[l].type == TabPage)
4494 {
4495 sp->start = item[l].start;
4496 sp->userhl = item[l].minwid;
4497 sp++;
4498 }
4499 }
4500 sp->start = NULL;
4501 sp->userhl = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502 }
4503
4504 return width;
4505}
4506#endif /* FEAT_STL_OPT */
4507
Bram Moolenaarba6c0522006-02-25 21:45:02 +00004508#if defined(FEAT_STL_OPT) || defined(FEAT_CMDL_INFO) \
4509 || defined(FEAT_GUI_TABLINE) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004510/*
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004511 * Get relative cursor position in window into "buf[buflen]", in the form 99%,
4512 * using "Top", "Bot" or "All" when appropriate.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004513 */
4514 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004515get_rel_pos(
4516 win_T *wp,
4517 char_u *buf,
4518 int buflen)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519{
4520 long above; /* number of lines above window */
4521 long below; /* number of lines below window */
4522
Bram Moolenaar0027c212015-01-07 13:31:52 +01004523 if (buflen < 3) /* need at least 3 chars for writing */
4524 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525 above = wp->w_topline - 1;
4526#ifdef FEAT_DIFF
4527 above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill;
Bram Moolenaar29bc9db2015-08-04 17:43:25 +02004528 if (wp->w_topline == 1 && wp->w_topfill >= 1)
4529 above = 0; /* All buffer lines are displayed and there is an
4530 * indication of filler lines, that can be considered
4531 * seeing all lines. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532#endif
4533 below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1;
4534 if (below <= 0)
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004535 vim_strncpy(buf, (char_u *)(above == 0 ? _("All") : _("Bot")),
4536 (size_t)(buflen - 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537 else if (above <= 0)
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004538 vim_strncpy(buf, (char_u *)_("Top"), (size_t)(buflen - 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 else
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004540 vim_snprintf((char *)buf, (size_t)buflen, "%2d%%", above > 1000000L
Bram Moolenaar071d4272004-06-13 20:20:40 +00004541 ? (int)(above / ((above + below) / 100L))
4542 : (int)(above * 100L / (above + below)));
4543}
4544#endif
4545
4546/*
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004547 * Append (file 2 of 8) to "buf[buflen]", if editing more than one file.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548 * Return TRUE if it was appended.
4549 */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004550 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01004551append_arg_number(
4552 win_T *wp,
4553 char_u *buf,
4554 int buflen,
4555 int add_file) /* Add "file" before the arg number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556{
4557 char_u *p;
4558
4559 if (ARGCOUNT <= 1) /* nothing to do */
4560 return FALSE;
4561
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004562 p = buf + STRLEN(buf); /* go to the end of the buffer */
4563 if (p - buf + 35 >= buflen) /* getting too long */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004564 return FALSE;
4565 *p++ = ' ';
4566 *p++ = '(';
4567 if (add_file)
4568 {
4569 STRCPY(p, "file ");
4570 p += 5;
4571 }
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00004572 vim_snprintf((char *)p, (size_t)(buflen - (p - buf)),
4573 wp->w_arg_idx_invalid ? "(%d) of %d)"
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574 : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT);
4575 return TRUE;
4576}
4577
4578/*
4579 * If fname is not a full path, make it a full path.
4580 * Returns pointer to allocated memory (NULL for failure).
4581 */
4582 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01004583fix_fname(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584{
4585 /*
4586 * Force expanding the path always for Unix, because symbolic links may
4587 * mess up the full path name, even though it starts with a '/'.
4588 * Also expand when there is ".." in the file name, try to remove it,
4589 * because "c:/src/../README" is equal to "c:/README".
Bram Moolenaar9b942202007-10-03 12:31:33 +00004590 * Similarly "c:/src//file" is equal to "c:/src/file".
Bram Moolenaar071d4272004-06-13 20:20:40 +00004591 * For MS-Windows also expand names like "longna~1" to "longname".
4592 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00004593#ifdef UNIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594 return FullName_save(fname, TRUE);
4595#else
Bram Moolenaar9b942202007-10-03 12:31:33 +00004596 if (!vim_isAbsName(fname)
4597 || strstr((char *)fname, "..") != NULL
4598 || strstr((char *)fname, "//") != NULL
4599# ifdef BACKSLASH_IN_FILENAME
4600 || strstr((char *)fname, "\\\\") != NULL
4601# endif
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004602# if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603 || vim_strchr(fname, '~') != NULL
Bram Moolenaar9b942202007-10-03 12:31:33 +00004604# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605 )
4606 return FullName_save(fname, FALSE);
4607
4608 fname = vim_strsave(fname);
4609
Bram Moolenaar9b942202007-10-03 12:31:33 +00004610# ifdef USE_FNAME_CASE
4611# ifdef USE_LONG_FNAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 if (USE_LONG_FNAME)
Bram Moolenaar9b942202007-10-03 12:31:33 +00004613# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 {
4615 if (fname != NULL)
4616 fname_case(fname, 0); /* set correct case for file name */
4617 }
Bram Moolenaar9b942202007-10-03 12:31:33 +00004618# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619
4620 return fname;
4621#endif
4622}
4623
4624/*
4625 * Make "ffname" a full file name, set "sfname" to "ffname" if not NULL.
4626 * "ffname" becomes a pointer to allocated memory (or NULL).
4627 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004628 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004629fname_expand(
4630 buf_T *buf UNUSED,
4631 char_u **ffname,
4632 char_u **sfname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004633{
4634 if (*ffname == NULL) /* if no file name given, nothing to do */
4635 return;
4636 if (*sfname == NULL) /* if no short file name given, use ffname */
4637 *sfname = *ffname;
4638 *ffname = fix_fname(*ffname); /* expand to full path */
4639
4640#ifdef FEAT_SHORTCUT
4641 if (!buf->b_p_bin)
4642 {
Bram Moolenaarf193fff2006-04-27 00:02:13 +00004643 char_u *rfname;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644
4645 /* If the file name is a shortcut file, use the file it links to. */
4646 rfname = mch_resolve_shortcut(*ffname);
Bram Moolenaarf193fff2006-04-27 00:02:13 +00004647 if (rfname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004648 {
4649 vim_free(*ffname);
4650 *ffname = rfname;
4651 *sfname = rfname;
4652 }
4653 }
4654#endif
4655}
4656
4657/*
4658 * Get the file name for an argument list entry.
4659 */
4660 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01004661alist_name(aentry_T *aep)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004662{
4663 buf_T *bp;
4664
4665 /* Use the name from the associated buffer if it exists. */
4666 bp = buflist_findnr(aep->ae_fnum);
Bram Moolenaar84212822006-11-07 21:59:47 +00004667 if (bp == NULL || bp->b_fname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004668 return aep->ae_fname;
4669 return bp->b_fname;
4670}
4671
4672#if defined(FEAT_WINDOWS) || defined(PROTO)
4673/*
4674 * do_arg_all(): Open up to 'count' windows, one for each argument.
4675 */
4676 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004677do_arg_all(
4678 int count,
4679 int forceit, /* hide buffers in current windows */
4680 int keep_tabs) /* keep current tabs, for ":tab drop file" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681{
4682 int i;
4683 win_T *wp, *wpnext;
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004684 char_u *opened; /* Array of weight for which args are open:
4685 * 0: not opened
4686 * 1: opened in other tab
4687 * 2: opened in curtab
4688 * 3: opened in curtab and curwin
4689 */
Bram Moolenaard089d9b2007-09-30 12:02:55 +00004690 int opened_len; /* length of opened[] */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004691 int use_firstwin = FALSE; /* use first window for arglist */
4692 int split_ret = OK;
4693 int p_ea_save;
4694 alist_T *alist; /* argument list to be used */
4695 buf_T *buf;
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004696 tabpage_T *tpnext;
4697 int had_tab = cmdmod.tab;
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004698 win_T *old_curwin, *last_curwin;
4699 tabpage_T *old_curtab, *last_curtab;
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004700 win_T *new_curwin = NULL;
4701 tabpage_T *new_curtab = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702
4703 if (ARGCOUNT <= 0)
4704 {
4705 /* Don't give an error message. We don't want it when the ":all"
4706 * command is in the .vimrc. */
4707 return;
4708 }
4709 setpcmark();
4710
4711 opened_len = ARGCOUNT;
4712 opened = alloc_clear((unsigned)opened_len);
4713 if (opened == NULL)
4714 return;
4715
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004716 /* Autocommands may do anything to the argument list. Make sure it's not
4717 * freed while we are working here by "locking" it. We still have to
4718 * watch out for its size to be changed. */
4719 alist = curwin->w_alist;
4720 ++alist->al_refcount;
4721
4722 old_curwin = curwin;
4723 old_curtab = curtab;
4724
Bram Moolenaar44a2f922016-03-19 22:11:51 +01004725# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004726 need_mouse_correct = TRUE;
Bram Moolenaar44a2f922016-03-19 22:11:51 +01004727# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728
4729 /*
4730 * Try closing all windows that are not in the argument list.
4731 * Also close windows that are not full width;
4732 * When 'hidden' or "forceit" set the buffer becomes hidden.
4733 * Windows that have a changed buffer and can't be hidden won't be closed.
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004734 * When the ":tab" modifier was used do this for all tab pages.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 */
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004736 if (had_tab > 0)
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004737 goto_tabpage_tp(first_tabpage, TRUE, TRUE);
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004738 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004740 tpnext = curtab->tp_next;
4741 for (wp = firstwin; wp != NULL; wp = wpnext)
4742 {
4743 wpnext = wp->w_next;
4744 buf = wp->w_buffer;
4745 if (buf->b_ffname == NULL
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004746 || (!keep_tabs && buf->b_nwindows > 1)
Bram Moolenaar44a2f922016-03-19 22:11:51 +01004747 || wp->w_width != Columns)
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004748 i = opened_len;
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004749 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004751 /* check if the buffer in this window is in the arglist */
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004752 for (i = 0; i < opened_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004753 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004754 if (i < alist->al_ga.ga_len
4755 && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum
4756 || fullpathcmp(alist_name(&AARGLIST(alist)[i]),
4757 buf->b_ffname, TRUE) & FPC_SAME))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004758 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004759 int weight = 1;
4760
4761 if (old_curtab == curtab)
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004762 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004763 ++weight;
4764 if (old_curwin == wp)
4765 ++weight;
4766 }
4767
4768 if (weight > (int)opened[i])
4769 {
4770 opened[i] = (char_u)weight;
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004771 if (i == 0)
4772 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004773 if (new_curwin != NULL)
4774 new_curwin->w_arg_idx = opened_len;
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004775 new_curwin = wp;
4776 new_curtab = curtab;
4777 }
4778 }
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004779 else if (keep_tabs)
4780 i = opened_len;
4781
4782 if (wp->w_alist != alist)
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004783 {
4784 /* Use the current argument list for all windows
4785 * containing a file from it. */
4786 alist_unlink(wp->w_alist);
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004787 wp->w_alist = alist;
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004788 ++wp->w_alist->al_refcount;
4789 }
4790 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004791 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792 }
4793 }
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004794 wp->w_arg_idx = i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004796 if (i == opened_len && !keep_tabs)/* close this window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004798 if (P_HID(buf) || forceit || buf->b_nwindows > 1
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004799 || !bufIsChanged(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004800 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004801 /* If the buffer was changed, and we would like to hide it,
4802 * try autowriting. */
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004803 if (!P_HID(buf) && buf->b_nwindows <= 1
4804 && bufIsChanged(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805 {
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02004806#ifdef FEAT_AUTOCMD
4807 bufref_T bufref;
4808
4809 set_bufref(&bufref, buf);
4810#endif
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004811 (void)autowrite(buf, FALSE);
4812#ifdef FEAT_AUTOCMD
4813 /* check if autocommands removed the window */
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02004814 if (!win_valid(wp) || !bufref_valid(&bufref))
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004815 {
4816 wpnext = firstwin; /* start all over... */
4817 continue;
4818 }
4819#endif
4820 }
4821#ifdef FEAT_WINDOWS
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004822 /* don't close last window */
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004823 if (firstwin == lastwin
4824 && (first_tabpage->tp_next == NULL || !had_tab))
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004825#endif
4826 use_firstwin = TRUE;
4827#ifdef FEAT_WINDOWS
4828 else
4829 {
4830 win_close(wp, !P_HID(buf) && !bufIsChanged(buf));
4831# ifdef FEAT_AUTOCMD
4832 /* check if autocommands removed the next window */
4833 if (!win_valid(wpnext))
4834 wpnext = firstwin; /* start all over... */
4835# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004836 }
4837#endif
4838 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839 }
4840 }
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004841
4842 /* Without the ":tab" modifier only do the current tab page. */
4843 if (had_tab == 0 || tpnext == NULL)
4844 break;
4845
4846# ifdef FEAT_AUTOCMD
4847 /* check if autocommands removed the next tab page */
4848 if (!valid_tabpage(tpnext))
4849 tpnext = first_tabpage; /* start all over...*/
4850# endif
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004851 goto_tabpage_tp(tpnext, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004852 }
4853
4854 /*
4855 * Open a window for files in the argument list that don't have one.
4856 * ARGCOUNT may change while doing this, because of autocommands.
4857 */
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004858 if (count > opened_len || count <= 0)
4859 count = opened_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004860
4861#ifdef FEAT_AUTOCMD
4862 /* Don't execute Win/Buf Enter/Leave autocommands here. */
4863 ++autocmd_no_enter;
4864 ++autocmd_no_leave;
4865#endif
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004866 last_curwin = curwin;
4867 last_curtab = curtab;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004868 win_enter(lastwin, FALSE);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004869#ifdef FEAT_WINDOWS
4870 /* ":drop all" should re-use an empty window to avoid "--remote-tab"
4871 * leaving an empty tab page when executed locally. */
4872 if (keep_tabs && bufempty() && curbuf->b_nwindows == 1
4873 && curbuf->b_ffname == NULL && !curbuf->b_changed)
4874 use_firstwin = TRUE;
4875#endif
4876
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004877 for (i = 0; i < count && i < opened_len && !got_int; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004878 {
4879 if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1)
4880 arg_had_last = TRUE;
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004881 if (opened[i] > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004882 {
4883 /* Move the already present window to below the current window */
4884 if (curwin->w_arg_idx != i)
4885 {
4886 for (wpnext = firstwin; wpnext != NULL; wpnext = wpnext->w_next)
4887 {
4888 if (wpnext->w_arg_idx == i)
4889 {
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004890 if (keep_tabs)
4891 {
4892 new_curwin = wpnext;
4893 new_curtab = curtab;
4894 }
4895 else
4896 win_move_after(wpnext, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897 break;
4898 }
4899 }
4900 }
4901 }
4902 else if (split_ret == OK)
4903 {
4904 if (!use_firstwin) /* split current window */
4905 {
4906 p_ea_save = p_ea;
4907 p_ea = TRUE; /* use space from all windows */
4908 split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
4909 p_ea = p_ea_save;
4910 if (split_ret == FAIL)
4911 continue;
4912 }
4913#ifdef FEAT_AUTOCMD
4914 else /* first window: do autocmd for leaving this buffer */
4915 --autocmd_no_leave;
4916#endif
4917
4918 /*
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004919 * edit file "i"
Bram Moolenaar071d4272004-06-13 20:20:40 +00004920 */
4921 curwin->w_arg_idx = i;
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004922 if (i == 0)
4923 {
4924 new_curwin = curwin;
4925 new_curtab = curtab;
4926 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927 (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL,
4928 ECMD_ONE,
4929 ((P_HID(curwin->w_buffer)
4930 || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0)
Bram Moolenaar701f7af2008-11-15 13:12:07 +00004931 + ECMD_OLDBUF, curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004932#ifdef FEAT_AUTOCMD
4933 if (use_firstwin)
4934 ++autocmd_no_leave;
4935#endif
4936 use_firstwin = FALSE;
4937 }
4938 ui_breakcheck();
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004939
4940 /* When ":tab" was used open a new tab for a new window repeatedly. */
4941 if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
4942 cmdmod.tab = 9999;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943 }
4944
4945 /* Remove the "lock" on the argument list. */
4946 alist_unlink(alist);
4947
4948#ifdef FEAT_AUTOCMD
4949 --autocmd_no_enter;
4950#endif
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004951 /* restore last referenced tabpage's curwin */
4952 if (last_curtab != new_curtab)
4953 {
4954 if (valid_tabpage(last_curtab))
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004955 goto_tabpage_tp(last_curtab, TRUE, TRUE);
Bram Moolenaar52379ea2012-02-22 19:13:08 +01004956 if (win_valid(last_curwin))
4957 win_enter(last_curwin, FALSE);
4958 }
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004959 /* to window with first arg */
4960 if (valid_tabpage(new_curtab))
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004961 goto_tabpage_tp(new_curtab, TRUE, TRUE);
Bram Moolenaar8ee89262006-03-11 21:16:47 +00004962 if (win_valid(new_curwin))
4963 win_enter(new_curwin, FALSE);
4964
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965#ifdef FEAT_AUTOCMD
4966 --autocmd_no_leave;
4967#endif
4968 vim_free(opened);
4969}
4970
4971# if defined(FEAT_LISTCMDS) || defined(PROTO)
4972/*
4973 * Open a window for a number of buffers.
4974 */
4975 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004976ex_buffer_all(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977{
4978 buf_T *buf;
4979 win_T *wp, *wpnext;
4980 int split_ret = OK;
4981 int p_ea_save;
4982 int open_wins = 0;
4983 int r;
4984 int count; /* Maximum number of windows to open. */
4985 int all; /* When TRUE also load inactive buffers. */
Bram Moolenaare1438bb2006-03-01 22:01:55 +00004986#ifdef FEAT_WINDOWS
4987 int had_tab = cmdmod.tab;
4988 tabpage_T *tpnext;
4989#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004990
4991 if (eap->addr_count == 0) /* make as many windows as possible */
4992 count = 9999;
4993 else
4994 count = eap->line2; /* make as many windows as specified */
4995 if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide)
4996 all = FALSE;
4997 else
4998 all = TRUE;
4999
5000 setpcmark();
5001
5002#ifdef FEAT_GUI
5003 need_mouse_correct = TRUE;
5004#endif
5005
5006 /*
5007 * Close superfluous windows (two windows for the same buffer).
5008 * Also close windows that are not full-width.
5009 */
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005010#ifdef FEAT_WINDOWS
5011 if (had_tab > 0)
Bram Moolenaar49e649f2013-05-06 04:50:35 +02005012 goto_tabpage_tp(first_tabpage, TRUE, TRUE);
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005013 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005014 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005015#endif
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005016 tpnext = curtab->tp_next;
5017 for (wp = firstwin; wp != NULL; wp = wpnext)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005018 {
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005019 wpnext = wp->w_next;
Bram Moolenaarbfb2d402006-03-03 22:50:42 +00005020 if ((wp->w_buffer->b_nwindows > 1
Bram Moolenaar44a2f922016-03-19 22:11:51 +01005021#ifdef FEAT_WINDOWS
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005022 || ((cmdmod.split & WSP_VERT)
5023 ? wp->w_height + wp->w_status_height < Rows - p_ch
Bram Moolenaarbfb2d402006-03-03 22:50:42 +00005024 - tabline_height()
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005025 : wp->w_width != Columns)
Bram Moolenaarb475fb92006-03-02 22:40:52 +00005026 || (had_tab > 0 && wp != firstwin)
5027#endif
Bram Moolenaar362ce482012-06-06 19:02:45 +02005028 ) && firstwin != lastwin
5029#ifdef FEAT_AUTOCMD
5030 && !(wp->w_closing || wp->w_buffer->b_closing)
5031#endif
5032 )
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005033 {
5034 win_close(wp, FALSE);
5035#ifdef FEAT_AUTOCMD
5036 wpnext = firstwin; /* just in case an autocommand does
5037 something strange with windows */
Bram Moolenaarb475fb92006-03-02 22:40:52 +00005038 tpnext = first_tabpage; /* start all over...*/
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005039 open_wins = 0;
5040#endif
5041 }
5042 else
5043 ++open_wins;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005044 }
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005045
5046#ifdef FEAT_WINDOWS
5047 /* Without the ":tab" modifier only do the current tab page. */
5048 if (had_tab == 0 || tpnext == NULL)
5049 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02005050 goto_tabpage_tp(tpnext, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051 }
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005052#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053
5054 /*
5055 * Go through the buffer list. When a buffer doesn't have a window yet,
5056 * open one. Otherwise move the window to the right position.
5057 * Watch out for autocommands that delete buffers or windows!
5058 */
5059#ifdef FEAT_AUTOCMD
5060 /* Don't execute Win/Buf Enter/Leave autocommands here. */
5061 ++autocmd_no_enter;
5062#endif
5063 win_enter(lastwin, FALSE);
5064#ifdef FEAT_AUTOCMD
5065 ++autocmd_no_leave;
5066#endif
5067 for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next)
5068 {
5069 /* Check if this buffer needs a window */
5070 if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl)
5071 continue;
5072
Bram Moolenaarb475fb92006-03-02 22:40:52 +00005073#ifdef FEAT_WINDOWS
5074 if (had_tab != 0)
5075 {
5076 /* With the ":tab" modifier don't move the window. */
5077 if (buf->b_nwindows > 0)
5078 wp = lastwin; /* buffer has a window, skip it */
5079 else
5080 wp = NULL;
5081 }
5082 else
5083#endif
5084 {
5085 /* Check if this buffer already has a window */
5086 for (wp = firstwin; wp != NULL; wp = wp->w_next)
5087 if (wp->w_buffer == buf)
5088 break;
5089 /* If the buffer already has a window, move it */
5090 if (wp != NULL)
5091 win_move_after(wp, curwin);
5092 }
5093
5094 if (wp == NULL && split_ret == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005095 {
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02005096#ifdef FEAT_AUTOCMD
5097 bufref_T bufref;
5098
5099 set_bufref(&bufref, buf);
5100#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 /* Split the window and put the buffer in it */
5102 p_ea_save = p_ea;
5103 p_ea = TRUE; /* use space from all windows */
5104 split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
5105 ++open_wins;
5106 p_ea = p_ea_save;
5107 if (split_ret == FAIL)
5108 continue;
5109
5110 /* Open the buffer in this window. */
Bram Moolenaare64ac772005-12-07 20:54:59 +00005111#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005112 swap_exists_action = SEA_DIALOG;
5113#endif
5114 set_curbuf(buf, DOBUF_GOTO);
5115#ifdef FEAT_AUTOCMD
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02005116 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005117 {
Bram Moolenaarb25f9a92016-07-10 18:21:50 +02005118 /* autocommands deleted the buffer!!! */
Bram Moolenaare64ac772005-12-07 20:54:59 +00005119#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005120 swap_exists_action = SEA_NONE;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005121# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005122 break;
5123 }
5124#endif
Bram Moolenaare64ac772005-12-07 20:54:59 +00005125#if defined(HAS_SWAP_EXISTS_ACTION)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005126 if (swap_exists_action == SEA_QUIT)
5127 {
Bram Moolenaarc0197e22004-09-13 20:26:32 +00005128# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
5129 cleanup_T cs;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005130
Bram Moolenaarc0197e22004-09-13 20:26:32 +00005131 /* Reset the error/interrupt/exception state here so that
5132 * aborting() returns FALSE when closing a window. */
5133 enter_cleanup(&cs);
5134# endif
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005135
Bram Moolenaarc0197e22004-09-13 20:26:32 +00005136 /* User selected Quit at ATTENTION prompt; close this window. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005137 win_close(curwin, TRUE);
5138 --open_wins;
5139 swap_exists_action = SEA_NONE;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005140 swap_exists_did_quit = TRUE;
Bram Moolenaarc0197e22004-09-13 20:26:32 +00005141
5142# if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
5143 /* Restore the error/interrupt/exception state if not
5144 * discarded by a new aborting error, interrupt, or uncaught
5145 * exception. */
5146 leave_cleanup(&cs);
5147# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005148 }
5149 else
5150 handle_swap_exists(NULL);
5151#endif
5152 }
5153
5154 ui_breakcheck();
5155 if (got_int)
5156 {
5157 (void)vgetc(); /* only break the file loading, not the rest */
5158 break;
5159 }
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00005160#ifdef FEAT_EVAL
5161 /* Autocommands deleted the buffer or aborted script processing!!! */
5162 if (aborting())
5163 break;
5164#endif
Bram Moolenaare1438bb2006-03-01 22:01:55 +00005165#ifdef FEAT_WINDOWS
5166 /* When ":tab" was used open a new tab for a new window repeatedly. */
5167 if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
5168 cmdmod.tab = 9999;
5169#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005170 }
5171#ifdef FEAT_AUTOCMD
5172 --autocmd_no_enter;
5173#endif
5174 win_enter(firstwin, FALSE); /* back to first window */
5175#ifdef FEAT_AUTOCMD
5176 --autocmd_no_leave;
5177#endif
5178
5179 /*
5180 * Close superfluous windows.
5181 */
5182 for (wp = lastwin; open_wins > count; )
5183 {
5184 r = (P_HID(wp->w_buffer) || !bufIsChanged(wp->w_buffer)
5185 || autowrite(wp->w_buffer, FALSE) == OK);
5186#ifdef FEAT_AUTOCMD
5187 if (!win_valid(wp))
5188 {
5189 /* BufWrite Autocommands made the window invalid, start over */
5190 wp = lastwin;
5191 }
5192 else
5193#endif
5194 if (r)
5195 {
5196 win_close(wp, !P_HID(wp->w_buffer));
5197 --open_wins;
5198 wp = lastwin;
5199 }
5200 else
5201 {
5202 wp = wp->w_prev;
5203 if (wp == NULL)
5204 break;
5205 }
5206 }
5207}
5208# endif /* FEAT_LISTCMDS */
5209
5210#endif /* FEAT_WINDOWS */
5211
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01005212static int chk_modeline(linenr_T, int);
Bram Moolenaara3227e22006-03-08 21:32:40 +00005213
Bram Moolenaar071d4272004-06-13 20:20:40 +00005214/*
5215 * do_modelines() - process mode lines for the current file
5216 *
Bram Moolenaara3227e22006-03-08 21:32:40 +00005217 * "flags" can be:
5218 * OPT_WINONLY only set options local to window
5219 * OPT_NOWIN don't set options local to window
5220 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 * Returns immediately if the "ml" option isn't set.
5222 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005223 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005224do_modelines(int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005225{
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00005226 linenr_T lnum;
5227 int nmlines;
5228 static int entered = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005229
5230 if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
5231 return;
5232
5233 /* Disallow recursive entry here. Can happen when executing a modeline
5234 * triggers an autocommand, which reloads modelines with a ":do". */
5235 if (entered)
5236 return;
5237
5238 ++entered;
5239 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
5240 ++lnum)
Bram Moolenaara3227e22006-03-08 21:32:40 +00005241 if (chk_modeline(lnum, flags) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005242 nmlines = 0;
5243
5244 for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines
5245 && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
Bram Moolenaara3227e22006-03-08 21:32:40 +00005246 if (chk_modeline(lnum, flags) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247 nmlines = 0;
5248 --entered;
5249}
5250
5251#include "version.h" /* for version number */
5252
5253/*
5254 * chk_modeline() - check a single line for a mode string
5255 * Return FAIL if an error encountered.
5256 */
5257 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005258chk_modeline(
5259 linenr_T lnum,
5260 int flags) /* Same as for do_modelines(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005261{
5262 char_u *s;
5263 char_u *e;
5264 char_u *linecopy; /* local copy of any modeline found */
5265 int prev;
5266 int vers;
5267 int end;
5268 int retval = OK;
5269 char_u *save_sourcing_name;
5270 linenr_T save_sourcing_lnum;
5271#ifdef FEAT_EVAL
5272 scid_T save_SID;
5273#endif
5274
5275 prev = -1;
5276 for (s = ml_get(lnum); *s != NUL; ++s)
5277 {
5278 if (prev == -1 || vim_isspace(prev))
5279 {
5280 if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0)
5281 || STRNCMP(s, "vi:", (size_t)3) == 0)
5282 break;
Bram Moolenaarc14621e2013-06-26 20:04:35 +02005283 /* Accept both "vim" and "Vim". */
5284 if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm')
Bram Moolenaar071d4272004-06-13 20:20:40 +00005285 {
5286 if (s[3] == '<' || s[3] == '=' || s[3] == '>')
5287 e = s + 4;
5288 else
5289 e = s + 3;
5290 vers = getdigits(&e);
5291 if (*e == ':'
Bram Moolenaar630a7302013-06-29 15:07:22 +02005292 && (s[0] != 'V'
5293 || STRNCMP(skipwhite(e + 1), "set", 3) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005294 && (s[3] == ':'
5295 || (VIM_VERSION_100 >= vers && isdigit(s[3]))
5296 || (VIM_VERSION_100 < vers && s[3] == '<')
5297 || (VIM_VERSION_100 > vers && s[3] == '>')
5298 || (VIM_VERSION_100 == vers && s[3] == '=')))
5299 break;
5300 }
5301 }
5302 prev = *s;
5303 }
5304
5305 if (*s)
5306 {
5307 do /* skip over "ex:", "vi:" or "vim:" */
5308 ++s;
5309 while (s[-1] != ':');
5310
5311 s = linecopy = vim_strsave(s); /* copy the line, it will change */
5312 if (linecopy == NULL)
5313 return FAIL;
5314
5315 save_sourcing_lnum = sourcing_lnum;
5316 save_sourcing_name = sourcing_name;
5317 sourcing_lnum = lnum; /* prepare for emsg() */
5318 sourcing_name = (char_u *)"modelines";
5319
5320 end = FALSE;
5321 while (end == FALSE)
5322 {
5323 s = skipwhite(s);
5324 if (*s == NUL)
5325 break;
5326
5327 /*
5328 * Find end of set command: ':' or end of line.
5329 * Skip over "\:", replacing it with ":".
5330 */
5331 for (e = s; *e != ':' && *e != NUL; ++e)
5332 if (e[0] == '\\' && e[1] == ':')
Bram Moolenaarf2330482008-06-24 20:19:36 +00005333 STRMOVE(e, e + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005334 if (*e == NUL)
5335 end = TRUE;
5336
5337 /*
5338 * If there is a "set" command, require a terminating ':' and
5339 * ignore the stuff after the ':'.
5340 * "vi:set opt opt opt: foo" -- foo not interpreted
5341 * "vi:opt opt opt: foo" -- foo interpreted
5342 * Accept "se" for compatibility with Elvis.
5343 */
5344 if (STRNCMP(s, "set ", (size_t)4) == 0
5345 || STRNCMP(s, "se ", (size_t)3) == 0)
5346 {
5347 if (*e != ':') /* no terminating ':'? */
5348 break;
5349 end = TRUE;
5350 s = vim_strchr(s, ' ') + 1;
5351 }
5352 *e = NUL; /* truncate the set command */
5353
5354 if (*s != NUL) /* skip over an empty "::" */
5355 {
5356#ifdef FEAT_EVAL
5357 save_SID = current_SID;
5358 current_SID = SID_MODELINE;
5359#endif
Bram Moolenaara3227e22006-03-08 21:32:40 +00005360 retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005361#ifdef FEAT_EVAL
5362 current_SID = save_SID;
5363#endif
5364 if (retval == FAIL) /* stop if error found */
5365 break;
5366 }
5367 s = e + 1; /* advance to next part */
5368 }
5369
5370 sourcing_lnum = save_sourcing_lnum;
5371 sourcing_name = save_sourcing_name;
5372
5373 vim_free(linecopy);
5374 }
5375 return retval;
5376}
5377
Bram Moolenaar91d8e0c2008-03-12 11:23:53 +00005378#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005379 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005380read_viminfo_bufferlist(
5381 vir_T *virp,
5382 int writing)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005383{
5384 char_u *tab;
5385 linenr_T lnum;
5386 colnr_T col;
5387 buf_T *buf;
5388 char_u *sfname;
5389 char_u *xline;
5390
5391 /* Handle long line and escaped characters. */
5392 xline = viminfo_readstring(virp, 1, FALSE);
5393
5394 /* don't read in if there are files on the command-line or if writing: */
5395 if (xline != NULL && !writing && ARGCOUNT == 0
5396 && find_viminfo_parameter('%') != NULL)
5397 {
5398 /* Format is: <fname> Tab <lnum> Tab <col>.
5399 * Watch out for a Tab in the file name, work from the end. */
5400 lnum = 0;
5401 col = 0;
5402 tab = vim_strrchr(xline, '\t');
5403 if (tab != NULL)
5404 {
5405 *tab++ = '\0';
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005406 col = (colnr_T)atoi((char *)tab);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407 tab = vim_strrchr(xline, '\t');
5408 if (tab != NULL)
5409 {
5410 *tab++ = '\0';
5411 lnum = atol((char *)tab);
5412 }
5413 }
5414
5415 /* Expand "~/" in the file name at "line + 1" to a full path.
5416 * Then try shortening it by comparing with the current directory */
5417 expand_env(xline, NameBuff, MAXPATHL);
Bram Moolenaard089d9b2007-09-30 12:02:55 +00005418 sfname = shorten_fname1(NameBuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005419
5420 buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
5421 if (buf != NULL) /* just in case... */
5422 {
5423 buf->b_last_cursor.lnum = lnum;
5424 buf->b_last_cursor.col = col;
5425 buflist_setfpos(buf, curwin, lnum, col, FALSE);
5426 }
5427 }
5428 vim_free(xline);
5429
5430 return viminfo_readline(virp);
5431}
5432
5433 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005434write_viminfo_bufferlist(FILE *fp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005435{
5436 buf_T *buf;
5437#ifdef FEAT_WINDOWS
5438 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00005439 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005440#endif
5441 char_u *line;
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00005442 int max_buffers;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005443
5444 if (find_viminfo_parameter('%') == NULL)
5445 return;
5446
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00005447 /* Without a number -1 is returned: do all buffers. */
5448 max_buffers = get_viminfo_parameter('%');
5449
Bram Moolenaar071d4272004-06-13 20:20:40 +00005450 /* Allocate room for the file name, lnum and col. */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005451#define LINE_BUF_LEN (MAXPATHL + 40)
5452 line = alloc(LINE_BUF_LEN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005453 if (line == NULL)
5454 return;
5455
5456#ifdef FEAT_WINDOWS
Bram Moolenaarf740b292006-02-16 22:11:02 +00005457 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005458 set_last_cursor(win);
5459#else
5460 set_last_cursor(curwin);
5461#endif
5462
Bram Moolenaar2f1e0502010-08-13 11:18:02 +02005463 fputs(_("\n# Buffer list:\n"), fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005464 for (buf = firstbuf; buf != NULL ; buf = buf->b_next)
5465 {
5466 if (buf->b_fname == NULL
5467 || !buf->b_p_bl
5468#ifdef FEAT_QUICKFIX
5469 || bt_quickfix(buf)
5470#endif
5471 || removable(buf->b_ffname))
5472 continue;
5473
Bram Moolenaar15d0a8c2004-09-06 17:44:46 +00005474 if (max_buffers-- == 0)
5475 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005476 putc('%', fp);
5477 home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
Bram Moolenaara800b422010-06-27 01:15:55 +02005478 vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%ld\t%d",
Bram Moolenaar071d4272004-06-13 20:20:40 +00005479 (long)buf->b_last_cursor.lnum,
5480 buf->b_last_cursor.col);
5481 viminfo_writestring(fp, line);
5482 }
5483 vim_free(line);
5484}
5485#endif
5486
5487
5488/*
5489 * Return special buffer name.
5490 * Returns NULL when the buffer has a normal file name.
5491 */
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005492 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01005493buf_spname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005494{
5495#if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)
5496 if (bt_quickfix(buf))
Bram Moolenaar28c258f2006-01-25 22:02:51 +00005497 {
Bram Moolenaar4a3aef72013-07-17 19:12:57 +02005498 win_T *win;
Bram Moolenaar91d8e0c2008-03-12 11:23:53 +00005499 tabpage_T *tp;
Bram Moolenaar28c258f2006-01-25 22:02:51 +00005500
5501 /*
5502 * For location list window, w_llist_ref points to the location list.
5503 * For quickfix window, w_llist_ref is NULL.
5504 */
Bram Moolenaar4a3aef72013-07-17 19:12:57 +02005505 if (find_win_for_buf(buf, &win, &tp) == OK && win->w_llist_ref != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005506 return (char_u *)_(msg_loclist);
Bram Moolenaar28c258f2006-01-25 22:02:51 +00005507 else
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005508 return (char_u *)_(msg_qflist);
Bram Moolenaar28c258f2006-01-25 22:02:51 +00005509 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005510#endif
5511#ifdef FEAT_QUICKFIX
5512 /* There is no _file_ when 'buftype' is "nofile", b_sfname
5513 * contains the name as specified by the user */
5514 if (bt_nofile(buf))
5515 {
5516 if (buf->b_sfname != NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005517 return buf->b_sfname;
5518 return (char_u *)_("[Scratch]");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005519 }
5520#endif
5521 if (buf->b_fname == NULL)
Bram Moolenaare1704ba2012-10-03 18:25:00 +02005522 return (char_u *)_("[No Name]");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005523 return NULL;
5524}
5525
Bram Moolenaar4a3aef72013-07-17 19:12:57 +02005526#if (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)) \
5527 || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
5528 || defined(PROTO)
5529/*
5530 * Find a window for buffer "buf".
5531 * If found OK is returned and "wp" and "tp" are set to the window and tabpage.
5532 * If not found FAIL is returned.
5533 */
5534 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005535find_win_for_buf(
5536 buf_T *buf,
5537 win_T **wp,
5538 tabpage_T **tp)
Bram Moolenaar4a3aef72013-07-17 19:12:57 +02005539{
5540 FOR_ALL_TAB_WINDOWS(*tp, *wp)
5541 if ((*wp)->w_buffer == buf)
5542 goto win_found;
5543 return FAIL;
5544win_found:
5545 return OK;
5546}
5547#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005548
5549#if defined(FEAT_SIGNS) || defined(PROTO)
5550/*
5551 * Insert the sign into the signlist.
5552 */
5553 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005554insert_sign(
5555 buf_T *buf, /* buffer to store sign in */
5556 signlist_T *prev, /* previous sign entry */
5557 signlist_T *next, /* next sign entry */
5558 int id, /* sign ID */
5559 linenr_T lnum, /* line number which gets the mark */
5560 int typenr) /* typenr of sign we are adding */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005561{
5562 signlist_T *newsign;
5563
5564 newsign = (signlist_T *)lalloc((long_u)sizeof(signlist_T), FALSE);
5565 if (newsign != NULL)
5566 {
5567 newsign->id = id;
5568 newsign->lnum = lnum;
5569 newsign->typenr = typenr;
5570 newsign->next = next;
5571#ifdef FEAT_NETBEANS_INTG
5572 newsign->prev = prev;
5573 if (next != NULL)
5574 next->prev = newsign;
5575#endif
5576
5577 if (prev == NULL)
5578 {
5579 /* When adding first sign need to redraw the windows to create the
5580 * column for signs. */
5581 if (buf->b_signlist == NULL)
5582 {
5583 redraw_buf_later(buf, NOT_VALID);
5584 changed_cline_bef_curs();
5585 }
5586
5587 /* first sign in signlist */
5588 buf->b_signlist = newsign;
Bram Moolenaar3b7b8362015-03-20 18:11:48 +01005589#ifdef FEAT_NETBEANS_INTG
5590 if (netbeans_active())
5591 buf->b_has_sign_column = TRUE;
5592#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005593 }
5594 else
5595 prev->next = newsign;
5596 }
5597}
5598
5599/*
5600 * Add the sign into the signlist. Find the right spot to do it though.
5601 */
5602 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005603buf_addsign(
5604 buf_T *buf, /* buffer to store sign in */
5605 int id, /* sign ID */
5606 linenr_T lnum, /* line number which gets the mark */
5607 int typenr) /* typenr of sign we are adding */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005608{
5609 signlist_T *sign; /* a sign in the signlist */
5610 signlist_T *prev; /* the previous sign */
5611
5612 prev = NULL;
5613 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5614 {
5615 if (lnum == sign->lnum && id == sign->id)
5616 {
5617 sign->typenr = typenr;
5618 return;
5619 }
5620 else if (
5621#ifndef FEAT_NETBEANS_INTG /* keep signs sorted by lnum */
5622 id < 0 &&
5623#endif
5624 lnum < sign->lnum)
5625 {
5626#ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */
5627 /* XXX - GRP: Is this because of sign slide problem? Or is it
5628 * really needed? Or is it because we allow multiple signs per
5629 * line? If so, should I add that feature to FEAT_SIGNS?
5630 */
5631 while (prev != NULL && prev->lnum == lnum)
5632 prev = prev->prev;
5633 if (prev == NULL)
5634 sign = buf->b_signlist;
5635 else
5636 sign = prev->next;
5637#endif
5638 insert_sign(buf, prev, sign, id, lnum, typenr);
5639 return;
5640 }
5641 prev = sign;
5642 }
5643#ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */
5644 /* XXX - GRP: See previous comment */
5645 while (prev != NULL && prev->lnum == lnum)
5646 prev = prev->prev;
5647 if (prev == NULL)
5648 sign = buf->b_signlist;
5649 else
5650 sign = prev->next;
5651#endif
5652 insert_sign(buf, prev, sign, id, lnum, typenr);
5653
5654 return;
5655}
5656
Bram Moolenaar0d3d5e02014-05-07 16:35:08 +02005657/*
5658 * For an existing, placed sign "markId" change the type to "typenr".
5659 * Returns the line number of the sign, or zero if the sign is not found.
5660 */
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005661 linenr_T
Bram Moolenaar7454a062016-01-30 15:14:10 +01005662buf_change_sign_type(
5663 buf_T *buf, /* buffer to store sign in */
5664 int markId, /* sign ID */
5665 int typenr) /* typenr of sign we are adding */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005666{
5667 signlist_T *sign; /* a sign in the signlist */
5668
5669 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5670 {
5671 if (sign->id == markId)
5672 {
5673 sign->typenr = typenr;
5674 return sign->lnum;
5675 }
5676 }
5677
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005678 return (linenr_T)0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005679}
5680
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00005681 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005682buf_getsigntype(
5683 buf_T *buf,
5684 linenr_T lnum,
5685 int type) /* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005686{
5687 signlist_T *sign; /* a sign in a b_signlist */
5688
5689 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5690 if (sign->lnum == lnum
5691 && (type == SIGN_ANY
5692# ifdef FEAT_SIGN_ICONS
5693 || (type == SIGN_ICON
5694 && sign_get_image(sign->typenr) != NULL)
5695# endif
5696 || (type == SIGN_TEXT
5697 && sign_get_text(sign->typenr) != NULL)
5698 || (type == SIGN_LINEHL
5699 && sign_get_attr(sign->typenr, TRUE) != 0)))
5700 return sign->typenr;
5701 return 0;
5702}
5703
5704
5705 linenr_T
Bram Moolenaar7454a062016-01-30 15:14:10 +01005706buf_delsign(
5707 buf_T *buf, /* buffer sign is stored in */
5708 int id) /* sign id */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005709{
5710 signlist_T **lastp; /* pointer to pointer to current sign */
5711 signlist_T *sign; /* a sign in a b_signlist */
5712 signlist_T *next; /* the next sign in a b_signlist */
5713 linenr_T lnum; /* line number whose sign was deleted */
5714
5715 lastp = &buf->b_signlist;
5716 lnum = 0;
5717 for (sign = buf->b_signlist; sign != NULL; sign = next)
5718 {
5719 next = sign->next;
5720 if (sign->id == id)
5721 {
5722 *lastp = next;
5723#ifdef FEAT_NETBEANS_INTG
5724 if (next != NULL)
5725 next->prev = sign->prev;
5726#endif
5727 lnum = sign->lnum;
5728 vim_free(sign);
5729 break;
5730 }
5731 else
5732 lastp = &sign->next;
5733 }
5734
5735 /* When deleted the last sign need to redraw the windows to remove the
5736 * sign column. */
5737 if (buf->b_signlist == NULL)
5738 {
5739 redraw_buf_later(buf, NOT_VALID);
5740 changed_cline_bef_curs();
5741 }
5742
5743 return lnum;
5744}
5745
5746
5747/*
5748 * Find the line number of the sign with the requested id. If the sign does
5749 * not exist, return 0 as the line number. This will still let the correct file
5750 * get loaded.
5751 */
5752 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005753buf_findsign(
5754 buf_T *buf, /* buffer to store sign in */
5755 int id) /* sign ID */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005756{
5757 signlist_T *sign; /* a sign in the signlist */
5758
5759 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5760 if (sign->id == id)
5761 return sign->lnum;
5762
5763 return 0;
5764}
5765
5766 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005767buf_findsign_id(
5768 buf_T *buf, /* buffer whose sign we are searching for */
5769 linenr_T lnum) /* line number of sign */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005770{
5771 signlist_T *sign; /* a sign in the signlist */
5772
5773 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5774 if (sign->lnum == lnum)
5775 return sign->id;
5776
5777 return 0;
5778}
5779
5780
5781# if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
5782/* see if a given type of sign exists on a specific line */
5783 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005784buf_findsigntype_id(
5785 buf_T *buf, /* buffer whose sign we are searching for */
5786 linenr_T lnum, /* line number of sign */
5787 int typenr) /* sign type number */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005788{
5789 signlist_T *sign; /* a sign in the signlist */
5790
5791 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5792 if (sign->lnum == lnum && sign->typenr == typenr)
5793 return sign->id;
5794
5795 return 0;
5796}
5797
5798
5799# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
5800/* return the number of icons on the given line */
5801 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005802buf_signcount(buf_T *buf, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005803{
5804 signlist_T *sign; /* a sign in the signlist */
5805 int count = 0;
5806
5807 for (sign = buf->b_signlist; sign != NULL; sign = sign->next)
5808 if (sign->lnum == lnum)
5809 if (sign_get_image(sign->typenr) != NULL)
5810 count++;
5811
5812 return count;
5813}
5814# endif /* FEAT_SIGN_ICONS */
5815# endif /* FEAT_NETBEANS_INTG */
5816
5817
5818/*
5819 * Delete signs in buffer "buf".
5820 */
Bram Moolenaarf65e5662012-07-10 15:18:22 +02005821 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005822buf_delete_signs(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005823{
5824 signlist_T *next;
5825
Bram Moolenaar0d3d5e02014-05-07 16:35:08 +02005826 /* When deleting the last sign need to redraw the windows to remove the
Bram Moolenaar4e036c92014-07-16 16:30:28 +02005827 * sign column. Not when curwin is NULL (this means we're exiting). */
5828 if (buf->b_signlist != NULL && curwin != NULL)
Bram Moolenaar0d3d5e02014-05-07 16:35:08 +02005829 {
5830 redraw_buf_later(buf, NOT_VALID);
5831 changed_cline_bef_curs();
5832 }
5833
Bram Moolenaar071d4272004-06-13 20:20:40 +00005834 while (buf->b_signlist != NULL)
5835 {
5836 next = buf->b_signlist->next;
5837 vim_free(buf->b_signlist);
5838 buf->b_signlist = next;
5839 }
5840}
5841
5842/*
5843 * Delete all signs in all buffers.
5844 */
5845 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005846buf_delete_all_signs(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005847{
5848 buf_T *buf; /* buffer we are checking for signs */
5849
5850 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
5851 if (buf->b_signlist != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005852 buf_delete_signs(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005853}
5854
5855/*
5856 * List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers.
5857 */
5858 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005859sign_list_placed(buf_T *rbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005860{
5861 buf_T *buf;
5862 signlist_T *p;
5863 char lbuf[BUFSIZ];
5864
5865 MSG_PUTS_TITLE(_("\n--- Signs ---"));
5866 msg_putchar('\n');
5867 if (rbuf == NULL)
5868 buf = firstbuf;
5869 else
5870 buf = rbuf;
Bram Moolenaar1c0b03e2012-03-16 14:32:15 +01005871 while (buf != NULL && !got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005872 {
5873 if (buf->b_signlist != NULL)
5874 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00005875 vim_snprintf(lbuf, BUFSIZ, _("Signs for %s:"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005876 MSG_PUTS_ATTR(lbuf, hl_attr(HLF_D));
5877 msg_putchar('\n');
5878 }
Bram Moolenaar1c0b03e2012-03-16 14:32:15 +01005879 for (p = buf->b_signlist; p != NULL && !got_int; p = p->next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005880 {
Bram Moolenaar9c13b352005-05-19 20:53:52 +00005881 vim_snprintf(lbuf, BUFSIZ, _(" line=%ld id=%d name=%s"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00005882 (long)p->lnum, p->id, sign_typenr2name(p->typenr));
5883 MSG_PUTS(lbuf);
5884 msg_putchar('\n');
5885 }
5886 if (rbuf != NULL)
5887 break;
5888 buf = buf->b_next;
5889 }
5890}
5891
5892/*
5893 * Adjust a placed sign for inserted/deleted lines.
5894 */
5895 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005896sign_mark_adjust(
5897 linenr_T line1,
5898 linenr_T line2,
5899 long amount,
5900 long amount_after)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005901{
5902 signlist_T *sign; /* a sign in a b_signlist */
5903
5904 for (sign = curbuf->b_signlist; sign != NULL; sign = sign->next)
5905 {
5906 if (sign->lnum >= line1 && sign->lnum <= line2)
5907 {
5908 if (amount == MAXLNUM)
5909 sign->lnum = line1;
5910 else
5911 sign->lnum += amount;
5912 }
5913 else if (sign->lnum > line2)
5914 sign->lnum += amount_after;
5915 }
5916}
5917#endif /* FEAT_SIGNS */
5918
5919/*
5920 * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed.
5921 */
5922 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005923set_buflisted(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005924{
5925 if (on != curbuf->b_p_bl)
5926 {
5927 curbuf->b_p_bl = on;
5928#ifdef FEAT_AUTOCMD
5929 if (on)
5930 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
5931 else
5932 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
5933#endif
5934 }
5935}
5936
5937/*
5938 * Read the file for "buf" again and check if the contents changed.
5939 * Return TRUE if it changed or this could not be checked.
5940 */
5941 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005942buf_contents_changed(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005943{
5944 buf_T *newbuf;
5945 int differ = TRUE;
5946 linenr_T lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005947 aco_save_T aco;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005948 exarg_T ea;
5949
5950 /* Allocate a buffer without putting it in the buffer list. */
5951 newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
5952 if (newbuf == NULL)
5953 return TRUE;
5954
5955 /* Force the 'fileencoding' and 'fileformat' to be equal. */
5956 if (prep_exarg(&ea, buf) == FAIL)
5957 {
5958 wipe_buffer(newbuf, FALSE);
5959 return TRUE;
5960 }
5961
Bram Moolenaar071d4272004-06-13 20:20:40 +00005962 /* set curwin/curbuf to buf and save a few things */
5963 aucmd_prepbuf(&aco, newbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964
Bram Moolenaar4770d092006-01-12 23:22:24 +00005965 if (ml_open(curbuf) == OK
Bram Moolenaar071d4272004-06-13 20:20:40 +00005966 && readfile(buf->b_ffname, buf->b_fname,
5967 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
5968 &ea, READ_NEW | READ_DUMMY) == OK)
5969 {
5970 /* compare the two files line by line */
5971 if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count)
5972 {
5973 differ = FALSE;
5974 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
5975 if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0)
5976 {
5977 differ = TRUE;
5978 break;
5979 }
5980 }
5981 }
5982 vim_free(ea.cmd);
5983
Bram Moolenaar071d4272004-06-13 20:20:40 +00005984 /* restore curwin/curbuf and a few other things */
5985 aucmd_restbuf(&aco);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005986
5987 if (curbuf != newbuf) /* safety check */
5988 wipe_buffer(newbuf, FALSE);
5989
5990 return differ;
5991}
5992
5993/*
5994 * Wipe out a buffer and decrement the last buffer number if it was used for
5995 * this buffer. Call this to wipe out a temp buffer that does not contain any
5996 * marks.
5997 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005998 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005999wipe_buffer(
6000 buf_T *buf,
6001 int aucmd UNUSED) /* When TRUE trigger autocommands. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006002{
6003 if (buf->b_fnum == top_file_num - 1)
6004 --top_file_num;
6005
6006#ifdef FEAT_AUTOCMD
6007 if (!aucmd) /* Don't trigger BufDelete autocommands here. */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00006008 block_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006009#endif
Bram Moolenaar42ec6562012-02-22 14:58:37 +01006010 close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006011#ifdef FEAT_AUTOCMD
6012 if (!aucmd)
Bram Moolenaar78ab3312007-09-29 12:16:41 +00006013 unblock_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006014#endif
6015}