blob: ce30b8d397c00f9eb7f76603afdf80a6daea3301 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaar071d4272004-06-13 20:20:40 +000017/*
18 * If 'autowrite' option set, try to write the file.
19 * Careful: autocommands may make "buf" invalid!
20 *
21 * return FAIL for failure, OK otherwise
22 */
23 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010024autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +000025{
Bram Moolenaar373154b2007-02-13 05:19:30 +000026 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020027 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +000028
Bram Moolenaar071d4272004-06-13 20:20:40 +000029 if (!(p_aw || p_awa) || !p_write
Bram Moolenaar217e1b82019-12-01 21:41:28 +010030 // never autowrite a "nofile" or "nowrite" buffer
Bram Moolenaar373154b2007-02-13 05:19:30 +000031 || bt_dontwrite(buf)
Bram Moolenaar373154b2007-02-13 05:19:30 +000032 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +000033 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020034 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +000035 r = buf_write_all(buf, forceit);
36
Bram Moolenaar217e1b82019-12-01 21:41:28 +010037 // Writing may succeed but the buffer still changed, e.g., when there is a
38 // conversion error. We do want to return FAIL then.
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020039 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +000040 r = FAIL;
41 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +000042}
43
44/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +020045 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +000046 */
47 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010048autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000049{
50 buf_T *buf;
51
52 if (!(p_aw || p_awa) || !p_write)
53 return;
Bram Moolenaar29323592016-07-24 22:04:11 +020054 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +020055 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +000056 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020057 bufref_T bufref;
58
59 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +010060
Bram Moolenaar071d4272004-06-13 20:20:40 +000061 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +010062
Bram Moolenaar217e1b82019-12-01 21:41:28 +010063 // an autocommand may have deleted the buffer
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020064 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +000065 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +000066 }
67}
68
69/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +010070 * Return TRUE if buffer was changed and cannot be abandoned.
71 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +000072 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000073 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010074check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +000075{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020076 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020077 bufref_T bufref;
78
79 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +010080
Bram Moolenaar071d4272004-06-13 20:20:40 +000081 if ( !forceit
82 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +010083 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
84 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +000085 {
86#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
Bram Moolenaare1004402020-10-24 20:49:43 +020087 if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
Bram Moolenaar071d4272004-06-13 20:20:40 +000088 {
Yee Cheng Chin15b314f2022-10-09 18:53:32 +010089# ifdef FEAT_TERMINAL
90 if (term_job_running(buf->b_term))
91 {
92 return term_confirm_stop(buf) == FAIL;
93 }
94# endif
95
Bram Moolenaar071d4272004-06-13 20:20:40 +000096 buf_T *buf2;
97 int count = 0;
98
Bram Moolenaar45d3b142013-11-09 03:31:51 +010099 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +0200100 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101 if (bufIsChanged(buf2)
102 && (buf2->b_ffname != NULL
103# ifdef FEAT_BROWSE
Bram Moolenaare1004402020-10-24 20:49:43 +0200104 || (cmdmod.cmod_flags & CMOD_BROWSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105# endif
106 ))
107 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200108 if (!bufref_valid(&bufref))
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100109 // Autocommand deleted buffer, oops! It's not changed now.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100111
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100113
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200114 if (!bufref_valid(&bufref))
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100115 // Autocommand deleted buffer, oops! It's not changed now.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000117 return bufIsChanged(buf);
118 }
119#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100120 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +0200121 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100122 else
Bram Moolenaar7a760922018-02-19 23:10:02 +0100123 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000124 return TRUE;
125 }
126 return FALSE;
127}
128
129#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
130
131#if defined(FEAT_BROWSE) || defined(PROTO)
132/*
133 * When wanting to write a file without a file name, ask the user for a name.
134 */
135 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100136browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000137{
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000138 if (buf->b_fname != NULL)
139 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000141 char_u *fname;
142
143 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
144 NULL, NULL, NULL, NULL, buf);
145 if (fname == NULL)
146 return;
147
148 if (setfname(buf, fname, NULL, TRUE) == OK)
149 buf->b_flags |= BF_NOTEDITED;
150 vim_free(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151}
152#endif
153
154/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +0200155 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156 * Must check 'write' option first!
157 */
158 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100159dialog_changed(
160 buf_T *buf,
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100161 int checkall) // may abandon all changed buffers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162{
Bram Moolenaard9462e32011-04-11 21:35:11 +0200163 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164 int ret;
165 buf_T *buf2;
glepnirdf461152024-04-04 22:23:29 +0200166 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +0200168 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169 if (checkall)
170 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
171 else
172 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
173
Bram Moolenaar4ca41532019-05-09 21:48:37 +0200174 // Init ea pseudo-structure, this is needed for the check_overwrite()
175 // function.
Bram Moolenaara80faa82020-04-12 19:37:17 +0200176 CLEAR_FIELD(ea);
Bram Moolenaar8218f602012-04-25 17:32:18 +0200177
Bram Moolenaar071d4272004-06-13 20:20:40 +0000178 if (ret == VIM_YES)
179 {
zeertzjqc20bdf12024-04-05 20:02:55 +0200180 int empty_bufname;
181
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182#ifdef FEAT_BROWSE
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100183 // May get file name, when there is none
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184 browse_save_fname(buf);
185#endif
zeertzjqc20bdf12024-04-05 20:02:55 +0200186 empty_bufname = buf->b_fname == NULL ? TRUE : FALSE;
187 if (empty_bufname)
glepnirdf461152024-04-04 22:23:29 +0200188 buf_set_name(buf->b_fnum, (char_u *)"Untitled");
189
190 if (check_overwrite(&ea, buf, buf->b_fname, buf->b_ffname, FALSE) == OK)
191 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100192 // didn't hit Cancel
glepnirdf461152024-04-04 22:23:29 +0200193 if (buf_write_all(buf, FALSE) == OK)
194 return;
195 }
196
197 // restore to empty when write failed
zeertzjqc20bdf12024-04-05 20:02:55 +0200198 if (empty_bufname)
glepnirdf461152024-04-04 22:23:29 +0200199 {
zeertzjqc20bdf12024-04-05 20:02:55 +0200200 VIM_CLEAR(buf->b_fname);
201 VIM_CLEAR(buf->b_ffname);
202 VIM_CLEAR(buf->b_sfname);
glepnirdf461152024-04-04 22:23:29 +0200203 unchanged(buf, TRUE, FALSE);
204 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205 }
206 else if (ret == VIM_NO)
207 {
Bram Moolenaarc024b462019-06-08 18:07:21 +0200208 unchanged(buf, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209 }
210 else if (ret == VIM_ALL)
211 {
212 /*
213 * Write all modified files that can be written.
214 * Skip readonly buffers, these need to be confirmed
215 * individually.
216 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200217 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218 {
219 if (bufIsChanged(buf2)
220 && (buf2->b_ffname != NULL
221#ifdef FEAT_BROWSE
Bram Moolenaare1004402020-10-24 20:49:43 +0200222 || (cmdmod.cmod_flags & CMOD_BROWSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000223#endif
224 )
Yee Cheng Chin15b314f2022-10-09 18:53:32 +0100225 && !bt_dontwrite(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000226 && !buf2->b_p_ro)
227 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200228 bufref_T bufref;
229
230 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231#ifdef FEAT_BROWSE
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100232 // May get file name, when there is none
Bram Moolenaar071d4272004-06-13 20:20:40 +0000233 browse_save_fname(buf2);
234#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200235 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
236 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100237 // didn't hit Cancel
Bram Moolenaar071d4272004-06-13 20:20:40 +0000238 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100239
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100240 // an autocommand may have deleted the buffer
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200241 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000242 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243 }
244 }
245 }
246 else if (ret == VIM_DISCARDALL)
247 {
248 /*
249 * mark all buffers as unchanged
250 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200251 FOR_ALL_BUFFERS(buf2)
Bram Moolenaarc024b462019-06-08 18:07:21 +0200252 unchanged(buf2, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000253 }
254}
255#endif
256
257/*
258 * Return TRUE if the buffer "buf" can be abandoned, either by making it
259 * hidden, autowriting it or unloading it.
260 */
261 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100262can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000263{
Bram Moolenaareb44a682017-08-03 22:44:55 +0200264 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265 || !bufIsChanged(buf)
266 || buf->b_nwindows > 1
267 || autowrite(buf, forceit) == OK
268 || forceit);
269}
270
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100271/*
272 * Add a buffer number to "bufnrs", unless it's already there.
273 */
274 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100275add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100276{
277 int i;
278
279 for (i = 0; i < *bufnump; ++i)
280 if (bufnrs[i] == nr)
281 return;
282 bufnrs[*bufnump] = nr;
283 *bufnump = *bufnump + 1;
284}
285
Bram Moolenaar071d4272004-06-13 20:20:40 +0000286/*
287 * Return TRUE if any buffer was changed and cannot be abandoned.
288 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100289 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +0100290 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000291 */
292 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100293check_changed_any(
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100294 int hidden, // Only check hidden buffers
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100295 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296{
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100297 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298 buf_T *buf;
299 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100300 int i;
301 int bufnum = 0;
302 int bufcount = 0;
303 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100304 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100307 // Make a list of all buffers, with the most important ones first.
Bram Moolenaar29323592016-07-24 22:04:11 +0200308 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100309 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100311 if (bufcount == 0)
312 return FALSE;
313
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200314 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100315 if (bufnrs == NULL)
316 return FALSE;
317
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100318 // curbuf
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100319 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100320
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100321 // buffers in current tab
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100322 FOR_ALL_WINDOWS(wp)
323 if (wp->w_buffer != curbuf)
324 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
325
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100326 // buffers in other tabs
Bram Moolenaar29323592016-07-24 22:04:11 +0200327 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100328 if (tp != curtab)
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200329 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100330 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100331
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100332 // any other buffer
Bram Moolenaar29323592016-07-24 22:04:11 +0200333 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100334 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
335
336 for (i = 0; i < bufnum; ++i)
337 {
338 buf = buflist_findnr(bufnrs[i]);
339 if (buf == NULL)
340 continue;
341 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
342 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200343 bufref_T bufref;
344
345 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100346#ifdef FEAT_TERMINAL
347 if (term_job_running(buf->b_term))
348 {
349 if (term_try_stop_job(buf) == FAIL)
350 break;
351 }
352 else
353#endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100354 // Try auto-writing the buffer. If this fails but the buffer no
355 // longer exists it's not changed, that's OK.
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100356 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
357 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200358 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100359 break; // didn't save - still changes
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100360 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000361 }
362
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100363 if (i >= bufnum)
364 goto theend;
365
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100366 // Get here if "buf" cannot be abandoned.
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100367 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368 exiting = FALSE;
369#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
370 /*
371 * When ":confirm" used, don't give an error message.
372 */
Bram Moolenaare1004402020-10-24 20:49:43 +0200373 if (!(p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374#endif
375 {
Bram Moolenaar13608d82022-08-29 15:06:50 +0100376 // There must be a wait_return() for this message, do_buffer()
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100377 // may cause a redraw. But wait_return() is a no-op when vgetc()
378 // is busy (Quit used from window menu), then make sure we don't
379 // cause a scroll up.
Bram Moolenaar61660ea2006-04-07 21:40:07 +0000380 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000381 {
382 msg_row = cmdline_row;
383 msg_col = 0;
384 msg_didout = FALSE;
385 }
Bram Moolenaareb44a682017-08-03 22:44:55 +0200386 if (
387#ifdef FEAT_TERMINAL
388 term_job_running(buf->b_term)
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000389 ? semsg(_(e_job_still_running_in_buffer_str), buf->b_fname)
Bram Moolenaareb44a682017-08-03 22:44:55 +0200390 :
391#endif
Bram Moolenaar1a992222021-12-31 17:25:48 +0000392 semsg(_(e_no_write_since_last_change_for_buffer_str),
Bram Moolenaare1704ba2012-10-03 18:25:00 +0200393 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000394 {
395 save = no_wait_return;
396 no_wait_return = FALSE;
397 wait_return(FALSE);
398 no_wait_return = save;
399 }
400 }
401
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100402 // Try to find a window that contains the buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100404 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405 if (wp->w_buffer == buf)
406 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200407 bufref_T bufref;
408
409 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100410
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100411 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100412
Bram Moolenaarbdace832019-03-02 10:13:42 +0100413 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200414 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100415 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100416 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000417 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100418buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100420 // Open the changed buffer in the current window.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000421 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +0100422 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100424theend:
425 vim_free(bufnrs);
426 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427}
428
429/*
430 * return FAIL if there is no file name, OK if there is one
431 * give error message for FAIL
432 */
433 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100434check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000435{
436 if (curbuf->b_ffname == NULL)
437 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200438 emsg(_(e_no_file_name));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 return FAIL;
440 }
441 return OK;
442}
443
444/*
445 * flush the contents of a buffer, unless it has no file name
446 *
447 * return FAIL for failure, OK otherwise
448 */
449 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100450buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000451{
452 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454
455 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
456 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
457 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000459 {
Bram Moolenaar8820b482017-03-16 17:23:31 +0100460 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +0100461 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463 return retval;
464}
465
466/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200467 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000468 */
469 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100470ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000471{
472 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000473 win_T *wp;
474 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +0100475 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000476 int next_fnum = 0;
Colin Kennedy21570352024-03-03 16:16:47 +0100477
478 if (curwin->w_p_wfb)
479 {
Sean Dewar4bb505e2024-03-05 20:39:07 +0100480 if ((eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) &&
481 !eap->forceit)
482 {
483 // Disallow :ldo if 'winfixbuf' is applied
484 emsg(_(e_winfixbuf_cannot_go_to_buffer));
485 return;
486 }
Colin Kennedy21570352024-03-03 16:16:47 +0100487
Sean Dewar4bb505e2024-03-05 20:39:07 +0100488 if (win_valid(prevwin) && !prevwin->w_p_wfb)
Sean Dewar4bb505e2024-03-05 20:39:07 +0100489 // 'winfixbuf' is set; attempt to change to a window without it.
490 win_goto(prevwin);
Sean Dewar4bb505e2024-03-05 20:39:07 +0100491 if (curwin->w_p_wfb)
492 {
493 // Split the window, which will be 'nowinfixbuf', and set curwin to
494 // that
Sean Dewar769eb2d2024-03-07 21:37:50 +0100495 (void)win_split(0, 0);
Sean Dewar4bb505e2024-03-05 20:39:07 +0100496
497 if (curwin->w_p_wfb)
498 {
499 // Autocommands set 'winfixbuf' or sent us to another window
Sean Dewar769eb2d2024-03-07 21:37:50 +0100500 // with it set, or we failed to split the window. Give up.
Sean Dewar4bb505e2024-03-05 20:39:07 +0100501 emsg(_(e_winfixbuf_cannot_go_to_buffer));
502 return;
503 }
504 }
Colin Kennedy21570352024-03-03 16:16:47 +0100505 }
506
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100507#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509#endif
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200510#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +0200511 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200512 int qf_idx;
513#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000514
Bram Moolenaar0106e3d2016-02-23 18:55:43 +0100515#ifndef FEAT_QUICKFIX
516 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
517 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
518 {
519 ex_ni(eap);
520 return;
521 }
522#endif
523
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100524#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000525 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200526 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100527 // Don't do syntax HL autocommands. Skipping the syntax file is a
528 // great speed improvement.
Bram Moolenaardcaf10e2005-01-21 11:55:25 +0000529 save_ei = au_event_disable(",Syntax");
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200530
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200531 FOR_ALL_BUFFERS(buf)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200532 buf->b_flags &= ~BF_SYN_SET;
533 buf = curbuf;
534 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200536#ifdef FEAT_CLIPBOARD
537 start_global_changes();
538#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539
540 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000541 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +0200542 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100543 || !check_changed(curbuf, CCGD_AW
544 | (eap->forceit ? CCGD_FORCEIT : 0)
545 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547 i = 0;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100548 // start at the eap->line1 argument/window/buffer
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000549 wp = firstwin;
550 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100551 switch (eap->cmdidx)
552 {
Bram Moolenaara162bc52015-01-07 16:54:21 +0100553 case CMD_windo:
554 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
555 i++;
556 break;
557 case CMD_tabdo:
Bram Moolenaarc9471b12023-05-09 15:00:00 +0100558 for ( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
Bram Moolenaara162bc52015-01-07 16:54:21 +0100559 i++;
560 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100561 case CMD_argdo:
562 i = eap->line1 - 1;
563 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100564 default:
565 break;
566 }
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100567 // set pcmark now
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200569 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100570 // Advance to the first listed buffer after "eap->line1".
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200571 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +0100572 || !buf->b_p_bl); buf = buf->b_next)
573 if (buf->b_fnum > eap->line2)
574 {
575 buf = NULL;
576 break;
577 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200578 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +0100579 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200580 }
581#ifdef FEAT_QUICKFIX
582 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
583 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
584 {
Bram Moolenaar25190db2019-05-04 15:05:28 +0200585 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200586 if (qf_size <= 0 || eap->line1 > qf_size)
587 buf = NULL;
588 else
589 {
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000590 save_clear_shm_value();
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200591 ex_cc(eap);
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000592 restore_shm_value();
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200593
594 buf = curbuf;
595 i = eap->line1 - 1;
596 if (eap->addr_count <= 0)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100597 // default is all the quickfix/location list entries
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200598 eap->line2 = qf_size;
599 }
600 }
601#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602 else
603 setpcmark();
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100604 listcmd_busy = TRUE; // avoids setting pcmark below
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605
Bram Moolenaare25bb902015-02-27 20:33:37 +0100606 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607 {
608 if (eap->cmdidx == CMD_argdo)
609 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100610 // go to argument "i"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 if (i == ARGCOUNT)
612 break;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100613 // Don't call do_argfile() when already there, it will try
614 // reloading the file.
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000615 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000616 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100617 // Clear 'shm' to avoid that the file message overwrites
618 // any output from the command.
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000619 save_clear_shm_value();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620 do_argfile(eap, i);
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000621 restore_shm_value();
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000622 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623 if (curwin->w_arg_idx != i)
624 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626 else if (eap->cmdidx == CMD_windo)
627 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100628 // go to window "wp"
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000629 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000631 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +0000632 if (curwin != wp)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100633 break; // something must be wrong
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000634 wp = curwin->w_next;
635 }
636 else if (eap->cmdidx == CMD_tabdo)
637 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100638 // go to window "tp"
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000639 if (!valid_tabpage(tp))
640 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200641 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000642 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 else if (eap->cmdidx == CMD_bufdo)
645 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100646 // Remember the number of the next listed buffer, in case
647 // ":bwipe" is used or autocommands do something strange.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000648 next_fnum = -1;
649 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
650 if (buf->b_p_bl)
651 {
652 next_fnum = buf->b_fnum;
653 break;
654 }
655 }
656
Bram Moolenaara162bc52015-01-07 16:54:21 +0100657 ++i;
658
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100659 // execute the command
Zoltan Arpadffy6fdb6282023-12-19 20:53:07 +0100660 do_cmdline(eap->arg, eap->ea_getline, eap->cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661 DOCMD_VERBOSE + DOCMD_NOWAIT);
662
663 if (eap->cmdidx == CMD_bufdo)
664 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100665 // Done?
Bram Moolenaara162bc52015-01-07 16:54:21 +0100666 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667 break;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100668 // Check if the buffer still exists.
Bram Moolenaar29323592016-07-24 22:04:11 +0200669 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000670 if (buf->b_fnum == next_fnum)
671 break;
672 if (buf == NULL)
673 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000674
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100675 // Go to the next buffer. Clear 'shm' to avoid that the file
676 // message overwrites any output from the command.
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000677 save_clear_shm_value();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000679 restore_shm_value();
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000680
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100681 // If autocommands took us elsewhere, quit here.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682 if (curbuf->b_fnum != next_fnum)
683 break;
684 }
685
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200686#ifdef FEAT_QUICKFIX
687 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
688 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
689 {
690 if (i >= qf_size || i >= eap->line2)
691 break;
692
693 qf_idx = qf_get_cur_idx(eap);
694
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000695 save_clear_shm_value();
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200696 ex_cnext(eap);
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000697 restore_shm_value();
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200698
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100699 // If jumping to the next quickfix entry fails, quit here
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200700 if (qf_get_cur_idx(eap) == qf_idx)
701 break;
702 }
703#endif
704
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705 if (eap->cmdidx == CMD_windo)
706 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100707 validate_cursor(); // cursor may have moved
Bram Moolenaar8a3bb562018-03-04 20:14:14 +0100708
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100709 // required when 'scrollbind' has been set
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 if (curwin->w_p_scb)
711 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000712 }
Bram Moolenaara162bc52015-01-07 16:54:21 +0100713
Bram Moolenaara162bc52015-01-07 16:54:21 +0100714 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
715 if (i+1 > eap->line2)
716 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100717 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
718 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 }
720 listcmd_busy = FALSE;
721 }
722
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100723#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000724 if (save_ei != NULL)
725 {
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200726 buf_T *bnext;
727 aco_save_T aco;
728
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000729 au_event_restore(save_ei);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200730
731 for (buf = firstbuf; buf != NULL; buf = bnext)
732 {
733 bnext = buf->b_next;
734 if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET))
735 {
736 buf->b_flags &= ~BF_SYN_SET;
737
738 // buffer was opened while Syntax autocommands were disabled,
739 // need to trigger them now.
740 if (buf == curbuf)
741 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000742 curbuf->b_fname, TRUE, curbuf);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200743 else
744 {
745 aucmd_prepbuf(&aco, buf);
Bram Moolenaare76062c2022-11-28 18:51:43 +0000746 if (curbuf == buf)
747 {
748 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200749 buf->b_fname, TRUE, buf);
Bram Moolenaare76062c2022-11-28 18:51:43 +0000750 aucmd_restbuf(&aco);
751 }
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200752 }
753
754 // start over, in case autocommands messed things up.
755 bnext = firstbuf;
756 }
757 }
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000758 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200760#ifdef FEAT_CLIPBOARD
761 end_global_changes();
762#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763}
764
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765#ifdef FEAT_EVAL
766/*
767 * ":compiler[!] {name}"
768 */
769 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100770ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771{
772 char_u *buf;
773 char_u *old_cur_comp = NULL;
774 char_u *p;
775
776 if (*eap->arg == NUL)
777 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100778 // List all compiler scripts.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100780 // ) keep the indenter happy...
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000781 return;
782 }
783
784 buf = alloc(STRLEN(eap->arg) + 14);
785 if (buf == NULL)
786 return;
787
788 if (eap->forceit)
789 {
790 // ":compiler! {name}" sets global options
791 do_cmdline_cmd((char_u *)
792 "command -nargs=* CompilerSet set <args>");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793 }
794 else
795 {
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000796 // ":compiler! {name}" sets local options.
797 // To remain backwards compatible "current_compiler" is always
798 // used. A user's compiler plugin may set it, the distributed
799 // plugin will then skip the settings. Afterwards set
800 // "b:current_compiler" and restore "current_compiler".
801 // Explicitly prepend "g:" to make it work in a function.
802 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
803 if (old_cur_comp != NULL)
804 old_cur_comp = vim_strsave(old_cur_comp);
805 do_cmdline_cmd((char_u *)
806 "command -nargs=* -keepscript CompilerSet setlocal <args>");
807 }
808 do_unlet((char_u *)"g:current_compiler", TRUE);
809 do_unlet((char_u *)"b:current_compiler", TRUE);
810
811 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
812 if (source_runtime(buf, DIP_ALL) == FAIL)
813 semsg(_(e_compiler_not_supported_str), eap->arg);
814 vim_free(buf);
815
816 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
817
818 // Set "b:current_compiler" from "current_compiler".
819 p = get_var_value((char_u *)"g:current_compiler");
820 if (p != NULL)
821 set_internal_string_var((char_u *)"b:current_compiler", p);
822
823 // Restore "current_compiler" for ":compiler {name}".
824 if (!eap->forceit)
825 {
826 if (old_cur_comp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827 {
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000828 set_internal_string_var((char_u *)"g:current_compiler",
829 old_cur_comp);
830 vim_free(old_cur_comp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000831 }
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000832 else
833 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000834 }
835}
836#endif
837
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100838#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
839
840# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
841/*
842 * Detect Python 3 or 2, and initialize 'pyxversion'.
843 */
844 void
845init_pyxversion(void)
846{
847 if (p_pyx == 0)
848 {
849 if (python3_enabled(FALSE))
850 p_pyx = 3;
851 else if (python_enabled(FALSE))
852 p_pyx = 2;
853 }
854}
855# endif
856
857/*
858 * Does a file contain one of the following strings at the beginning of any
859 * line?
860 * "#!(any string)python2" => returns 2
861 * "#!(any string)python3" => returns 3
862 * "# requires python 2.x" => returns 2
863 * "# requires python 3.x" => returns 3
864 * otherwise return 0.
865 */
866 static int
867requires_py_version(char_u *filename)
868{
869 FILE *file;
870 int requires_py_version = 0;
871 int i, lines;
872
873 lines = (int)p_mls;
874 if (lines < 0)
875 lines = 5;
876
877 file = mch_fopen((char *)filename, "r");
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000878 if (file == NULL)
879 return 0;
880
881 for (i = 0; i < lines; i++)
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100882 {
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000883 if (vim_fgets(IObuff, IOSIZE, file))
884 break;
885 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100886 {
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000887 // Check shebang.
888 if (strstr((char *)IObuff + 2, "python2") != NULL)
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100889 {
890 requires_py_version = 2;
891 break;
892 }
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000893 if (strstr((char *)IObuff + 2, "python3") != NULL)
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100894 {
895 requires_py_version = 3;
896 break;
897 }
898 }
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000899 IObuff[21] = '\0';
900 if (STRCMP("# requires python 2.x", IObuff) == 0)
901 {
902 requires_py_version = 2;
903 break;
904 }
905 if (STRCMP("# requires python 3.x", IObuff) == 0)
906 {
907 requires_py_version = 3;
908 break;
909 }
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100910 }
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000911 fclose(file);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100912 return requires_py_version;
913}
914
915
916/*
917 * Source a python file using the requested python version.
918 */
919 static void
920source_pyx_file(exarg_T *eap, char_u *fname)
921{
922 exarg_T ex;
923 int v = requires_py_version(fname);
924
925# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
926 init_pyxversion();
927# endif
928 if (v == 0)
929 {
930# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100931 // user didn't choose a preference, 'pyx' is used
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100932 v = p_pyx;
933# elif defined(FEAT_PYTHON)
934 v = 2;
935# elif defined(FEAT_PYTHON3)
936 v = 3;
937# endif
938 }
939
940 /*
941 * now source, if required python version is not supported show
942 * unobtrusive message.
943 */
944 if (eap == NULL)
Bram Moolenaara80faa82020-04-12 19:37:17 +0200945 CLEAR_FIELD(ex);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100946 else
947 ex = *eap;
948 ex.arg = fname;
949 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
950
951 if (v == 2)
952 {
953# ifdef FEAT_PYTHON
954 ex_pyfile(&ex);
955# else
956 vim_snprintf((char *)IObuff, IOSIZE,
957 _("W20: Required python version 2.x not supported, ignoring file: %s"),
958 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +0100959 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100960# endif
961 return;
962 }
963 else
964 {
965# ifdef FEAT_PYTHON3
966 ex_py3file(&ex);
967# else
968 vim_snprintf((char *)IObuff, IOSIZE,
969 _("W21: Required python version 3.x not supported, ignoring file: %s"),
970 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +0100971 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100972# endif
973 return;
974 }
975}
976
977/*
978 * ":pyxfile {fname}"
979 */
980 void
981ex_pyxfile(exarg_T *eap)
982{
983 source_pyx_file(eap, eap->arg);
984}
985
986/*
987 * ":pyx"
988 */
989 void
990ex_pyx(exarg_T *eap)
991{
992# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
993 init_pyxversion();
994 if (p_pyx == 2)
995 ex_python(eap);
996 else
997 ex_py3(eap);
998# elif defined(FEAT_PYTHON)
999 ex_python(eap);
1000# elif defined(FEAT_PYTHON3)
1001 ex_py3(eap);
1002# endif
1003}
1004
1005/*
1006 * ":pyxdo"
1007 */
1008 void
1009ex_pyxdo(exarg_T *eap)
1010{
1011# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1012 init_pyxversion();
1013 if (p_pyx == 2)
1014 ex_pydo(eap);
1015 else
1016 ex_py3do(eap);
1017# elif defined(FEAT_PYTHON)
1018 ex_pydo(eap);
1019# elif defined(FEAT_PYTHON3)
1020 ex_py3do(eap);
1021# endif
1022}
1023
1024#endif
1025
Bram Moolenaar071d4272004-06-13 20:20:40 +00001026/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001027 * ":checktime [buffer]"
1028 */
1029 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001030ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031{
1032 buf_T *buf;
1033 int save_no_check_timestamps = no_check_timestamps;
1034
1035 no_check_timestamps = 0;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001036 if (eap->addr_count == 0) // default is all buffers
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037 check_timestamps(FALSE);
1038 else
1039 {
1040 buf = buflist_findnr((int)eap->line2);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001041 if (buf != NULL) // cannot happen?
Bram Moolenaar071d4272004-06-13 20:20:40 +00001042 (void)buf_check_timestamp(buf, FALSE);
1043 }
1044 no_check_timestamps = save_no_check_timestamps;
1045}