blob: a75bfc11c0c96958dc8ba476072f72509fde3d93 [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;
167 int empty_buf = buf->b_fname == NULL ? TRUE : FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +0200169 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170 if (checkall)
171 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
172 else
173 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
174
Bram Moolenaar4ca41532019-05-09 21:48:37 +0200175 // Init ea pseudo-structure, this is needed for the check_overwrite()
176 // function.
Bram Moolenaara80faa82020-04-12 19:37:17 +0200177 CLEAR_FIELD(ea);
Bram Moolenaar8218f602012-04-25 17:32:18 +0200178
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 if (ret == VIM_YES)
180 {
181#ifdef FEAT_BROWSE
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100182 // May get file name, when there is none
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183 browse_save_fname(buf);
184#endif
glepnirdf461152024-04-04 22:23:29 +0200185 if (empty_buf)
186 buf_set_name(buf->b_fnum, (char_u *)"Untitled");
187
188 if (check_overwrite(&ea, buf, buf->b_fname, buf->b_ffname, FALSE) == OK)
189 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100190 // didn't hit Cancel
glepnirdf461152024-04-04 22:23:29 +0200191 if (buf_write_all(buf, FALSE) == OK)
192 return;
193 }
194
195 // restore to empty when write failed
196 if (empty_buf)
197 {
198 vim_free(buf->b_fname);
199 buf->b_fname = NULL;
200 vim_free(buf->b_ffname);
201 buf->b_ffname = NULL;
202 vim_free(buf->b_sfname);
203 buf->b_sfname = NULL;
204 unchanged(buf, TRUE, FALSE);
205 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000206 }
207 else if (ret == VIM_NO)
208 {
Bram Moolenaarc024b462019-06-08 18:07:21 +0200209 unchanged(buf, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 }
211 else if (ret == VIM_ALL)
212 {
213 /*
214 * Write all modified files that can be written.
215 * Skip readonly buffers, these need to be confirmed
216 * individually.
217 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200218 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000219 {
220 if (bufIsChanged(buf2)
221 && (buf2->b_ffname != NULL
222#ifdef FEAT_BROWSE
Bram Moolenaare1004402020-10-24 20:49:43 +0200223 || (cmdmod.cmod_flags & CMOD_BROWSE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224#endif
225 )
Yee Cheng Chin15b314f2022-10-09 18:53:32 +0100226 && !bt_dontwrite(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227 && !buf2->b_p_ro)
228 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200229 bufref_T bufref;
230
231 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232#ifdef FEAT_BROWSE
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100233 // May get file name, when there is none
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234 browse_save_fname(buf2);
235#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200236 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
237 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100238 // didn't hit Cancel
Bram Moolenaar071d4272004-06-13 20:20:40 +0000239 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100240
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100241 // an autocommand may have deleted the buffer
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200242 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 }
245 }
246 }
247 else if (ret == VIM_DISCARDALL)
248 {
249 /*
250 * mark all buffers as unchanged
251 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200252 FOR_ALL_BUFFERS(buf2)
Bram Moolenaarc024b462019-06-08 18:07:21 +0200253 unchanged(buf2, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000254 }
255}
256#endif
257
258/*
259 * Return TRUE if the buffer "buf" can be abandoned, either by making it
260 * hidden, autowriting it or unloading it.
261 */
262 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100263can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000264{
Bram Moolenaareb44a682017-08-03 22:44:55 +0200265 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000266 || !bufIsChanged(buf)
267 || buf->b_nwindows > 1
268 || autowrite(buf, forceit) == OK
269 || forceit);
270}
271
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100272/*
273 * Add a buffer number to "bufnrs", unless it's already there.
274 */
275 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100276add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100277{
278 int i;
279
280 for (i = 0; i < *bufnump; ++i)
281 if (bufnrs[i] == nr)
282 return;
283 bufnrs[*bufnump] = nr;
284 *bufnump = *bufnump + 1;
285}
286
Bram Moolenaar071d4272004-06-13 20:20:40 +0000287/*
288 * Return TRUE if any buffer was changed and cannot be abandoned.
289 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100290 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +0100291 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000292 */
293 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100294check_changed_any(
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100295 int hidden, // Only check hidden buffers
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100296 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000297{
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100298 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000299 buf_T *buf;
300 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100301 int i;
302 int bufnum = 0;
303 int bufcount = 0;
304 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100305 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100308 // Make a list of all buffers, with the most important ones first.
Bram Moolenaar29323592016-07-24 22:04:11 +0200309 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100310 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000311
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100312 if (bufcount == 0)
313 return FALSE;
314
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200315 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100316 if (bufnrs == NULL)
317 return FALSE;
318
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100319 // curbuf
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100320 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100321
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100322 // buffers in current tab
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100323 FOR_ALL_WINDOWS(wp)
324 if (wp->w_buffer != curbuf)
325 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
326
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100327 // buffers in other tabs
Bram Moolenaar29323592016-07-24 22:04:11 +0200328 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100329 if (tp != curtab)
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200330 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100331 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100332
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100333 // any other buffer
Bram Moolenaar29323592016-07-24 22:04:11 +0200334 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100335 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
336
337 for (i = 0; i < bufnum; ++i)
338 {
339 buf = buflist_findnr(bufnrs[i]);
340 if (buf == NULL)
341 continue;
342 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
343 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200344 bufref_T bufref;
345
346 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100347#ifdef FEAT_TERMINAL
348 if (term_job_running(buf->b_term))
349 {
350 if (term_try_stop_job(buf) == FAIL)
351 break;
352 }
353 else
354#endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100355 // Try auto-writing the buffer. If this fails but the buffer no
356 // longer exists it's not changed, that's OK.
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100357 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
358 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200359 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100360 break; // didn't save - still changes
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100361 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000362 }
363
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100364 if (i >= bufnum)
365 goto theend;
366
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100367 // Get here if "buf" cannot be abandoned.
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100368 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000369 exiting = FALSE;
370#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
371 /*
372 * When ":confirm" used, don't give an error message.
373 */
Bram Moolenaare1004402020-10-24 20:49:43 +0200374 if (!(p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375#endif
376 {
Bram Moolenaar13608d82022-08-29 15:06:50 +0100377 // There must be a wait_return() for this message, do_buffer()
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100378 // may cause a redraw. But wait_return() is a no-op when vgetc()
379 // is busy (Quit used from window menu), then make sure we don't
380 // cause a scroll up.
Bram Moolenaar61660ea2006-04-07 21:40:07 +0000381 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000382 {
383 msg_row = cmdline_row;
384 msg_col = 0;
385 msg_didout = FALSE;
386 }
Bram Moolenaareb44a682017-08-03 22:44:55 +0200387 if (
388#ifdef FEAT_TERMINAL
389 term_job_running(buf->b_term)
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000390 ? semsg(_(e_job_still_running_in_buffer_str), buf->b_fname)
Bram Moolenaareb44a682017-08-03 22:44:55 +0200391 :
392#endif
Bram Moolenaar1a992222021-12-31 17:25:48 +0000393 semsg(_(e_no_write_since_last_change_for_buffer_str),
Bram Moolenaare1704ba2012-10-03 18:25:00 +0200394 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000395 {
396 save = no_wait_return;
397 no_wait_return = FALSE;
398 wait_return(FALSE);
399 no_wait_return = save;
400 }
401 }
402
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100403 // Try to find a window that contains the buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100405 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406 if (wp->w_buffer == buf)
407 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200408 bufref_T bufref;
409
410 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100411
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100412 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100413
Bram Moolenaarbdace832019-03-02 10:13:42 +0100414 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200415 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100416 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100417 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100419buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100421 // Open the changed buffer in the current window.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +0100423 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100425theend:
426 vim_free(bufnrs);
427 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428}
429
430/*
431 * return FAIL if there is no file name, OK if there is one
432 * give error message for FAIL
433 */
434 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100435check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000436{
437 if (curbuf->b_ffname == NULL)
438 {
Bram Moolenaare29a27f2021-07-20 21:07:36 +0200439 emsg(_(e_no_file_name));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440 return FAIL;
441 }
442 return OK;
443}
444
445/*
446 * flush the contents of a buffer, unless it has no file name
447 *
448 * return FAIL for failure, OK otherwise
449 */
450 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100451buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452{
453 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000455
456 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
457 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
458 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000460 {
Bram Moolenaar8820b482017-03-16 17:23:31 +0100461 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +0100462 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000463 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000464 return retval;
465}
466
467/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200468 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000469 */
470 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100471ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000472{
473 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000474 win_T *wp;
475 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +0100476 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 int next_fnum = 0;
Colin Kennedy21570352024-03-03 16:16:47 +0100478
479 if (curwin->w_p_wfb)
480 {
Sean Dewar4bb505e2024-03-05 20:39:07 +0100481 if ((eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) &&
482 !eap->forceit)
483 {
484 // Disallow :ldo if 'winfixbuf' is applied
485 emsg(_(e_winfixbuf_cannot_go_to_buffer));
486 return;
487 }
Colin Kennedy21570352024-03-03 16:16:47 +0100488
Sean Dewar4bb505e2024-03-05 20:39:07 +0100489 if (win_valid(prevwin) && !prevwin->w_p_wfb)
Sean Dewar4bb505e2024-03-05 20:39:07 +0100490 // 'winfixbuf' is set; attempt to change to a window without it.
491 win_goto(prevwin);
Sean Dewar4bb505e2024-03-05 20:39:07 +0100492 if (curwin->w_p_wfb)
493 {
494 // Split the window, which will be 'nowinfixbuf', and set curwin to
495 // that
Sean Dewar769eb2d2024-03-07 21:37:50 +0100496 (void)win_split(0, 0);
Sean Dewar4bb505e2024-03-05 20:39:07 +0100497
498 if (curwin->w_p_wfb)
499 {
500 // Autocommands set 'winfixbuf' or sent us to another window
Sean Dewar769eb2d2024-03-07 21:37:50 +0100501 // with it set, or we failed to split the window. Give up.
Sean Dewar4bb505e2024-03-05 20:39:07 +0100502 emsg(_(e_winfixbuf_cannot_go_to_buffer));
503 return;
504 }
505 }
Colin Kennedy21570352024-03-03 16:16:47 +0100506 }
507
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100508#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510#endif
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200511#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +0200512 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200513 int qf_idx;
514#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000515
Bram Moolenaar0106e3d2016-02-23 18:55:43 +0100516#ifndef FEAT_QUICKFIX
517 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
518 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
519 {
520 ex_ni(eap);
521 return;
522 }
523#endif
524
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100525#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000526 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200527 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100528 // Don't do syntax HL autocommands. Skipping the syntax file is a
529 // great speed improvement.
Bram Moolenaardcaf10e2005-01-21 11:55:25 +0000530 save_ei = au_event_disable(",Syntax");
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200531
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200532 FOR_ALL_BUFFERS(buf)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200533 buf->b_flags &= ~BF_SYN_SET;
534 buf = curbuf;
535 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200537#ifdef FEAT_CLIPBOARD
538 start_global_changes();
539#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540
541 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000542 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +0200543 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100544 || !check_changed(curbuf, CCGD_AW
545 | (eap->forceit ? CCGD_FORCEIT : 0)
546 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548 i = 0;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100549 // start at the eap->line1 argument/window/buffer
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000550 wp = firstwin;
551 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100552 switch (eap->cmdidx)
553 {
Bram Moolenaara162bc52015-01-07 16:54:21 +0100554 case CMD_windo:
555 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
556 i++;
557 break;
558 case CMD_tabdo:
Bram Moolenaarc9471b12023-05-09 15:00:00 +0100559 for ( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
Bram Moolenaara162bc52015-01-07 16:54:21 +0100560 i++;
561 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100562 case CMD_argdo:
563 i = eap->line1 - 1;
564 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100565 default:
566 break;
567 }
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100568 // set pcmark now
Bram Moolenaar071d4272004-06-13 20:20:40 +0000569 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200570 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100571 // Advance to the first listed buffer after "eap->line1".
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200572 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +0100573 || !buf->b_p_bl); buf = buf->b_next)
574 if (buf->b_fnum > eap->line2)
575 {
576 buf = NULL;
577 break;
578 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200579 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +0100580 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200581 }
582#ifdef FEAT_QUICKFIX
583 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
584 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
585 {
Bram Moolenaar25190db2019-05-04 15:05:28 +0200586 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200587 if (qf_size <= 0 || eap->line1 > qf_size)
588 buf = NULL;
589 else
590 {
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000591 save_clear_shm_value();
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200592 ex_cc(eap);
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000593 restore_shm_value();
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200594
595 buf = curbuf;
596 i = eap->line1 - 1;
597 if (eap->addr_count <= 0)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100598 // default is all the quickfix/location list entries
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200599 eap->line2 = qf_size;
600 }
601 }
602#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 else
604 setpcmark();
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100605 listcmd_busy = TRUE; // avoids setting pcmark below
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606
Bram Moolenaare25bb902015-02-27 20:33:37 +0100607 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608 {
609 if (eap->cmdidx == CMD_argdo)
610 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100611 // go to argument "i"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612 if (i == ARGCOUNT)
613 break;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100614 // Don't call do_argfile() when already there, it will try
615 // reloading the file.
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000616 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000617 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100618 // Clear 'shm' to avoid that the file message overwrites
619 // any output from the command.
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000620 save_clear_shm_value();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000621 do_argfile(eap, i);
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000622 restore_shm_value();
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000623 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 if (curwin->w_arg_idx != i)
625 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 else if (eap->cmdidx == CMD_windo)
628 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100629 // go to window "wp"
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000630 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000632 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +0000633 if (curwin != wp)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100634 break; // something must be wrong
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000635 wp = curwin->w_next;
636 }
637 else if (eap->cmdidx == CMD_tabdo)
638 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100639 // go to window "tp"
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000640 if (!valid_tabpage(tp))
641 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200642 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000643 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645 else if (eap->cmdidx == CMD_bufdo)
646 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100647 // Remember the number of the next listed buffer, in case
648 // ":bwipe" is used or autocommands do something strange.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 next_fnum = -1;
650 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
651 if (buf->b_p_bl)
652 {
653 next_fnum = buf->b_fnum;
654 break;
655 }
656 }
657
Bram Moolenaara162bc52015-01-07 16:54:21 +0100658 ++i;
659
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100660 // execute the command
Zoltan Arpadffy6fdb6282023-12-19 20:53:07 +0100661 do_cmdline(eap->arg, eap->ea_getline, eap->cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662 DOCMD_VERBOSE + DOCMD_NOWAIT);
663
664 if (eap->cmdidx == CMD_bufdo)
665 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100666 // Done?
Bram Moolenaara162bc52015-01-07 16:54:21 +0100667 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 break;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100669 // Check if the buffer still exists.
Bram Moolenaar29323592016-07-24 22:04:11 +0200670 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000671 if (buf->b_fnum == next_fnum)
672 break;
673 if (buf == NULL)
674 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000675
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100676 // Go to the next buffer. Clear 'shm' to avoid that the file
677 // message overwrites any output from the command.
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000678 save_clear_shm_value();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000680 restore_shm_value();
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000681
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100682 // If autocommands took us elsewhere, quit here.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683 if (curbuf->b_fnum != next_fnum)
684 break;
685 }
686
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200687#ifdef FEAT_QUICKFIX
688 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
689 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
690 {
691 if (i >= qf_size || i >= eap->line2)
692 break;
693
694 qf_idx = qf_get_cur_idx(eap);
695
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000696 save_clear_shm_value();
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200697 ex_cnext(eap);
Christian Brabandt9aee8ec2022-12-16 16:41:23 +0000698 restore_shm_value();
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200699
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100700 // If jumping to the next quickfix entry fails, quit here
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200701 if (qf_get_cur_idx(eap) == qf_idx)
702 break;
703 }
704#endif
705
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706 if (eap->cmdidx == CMD_windo)
707 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100708 validate_cursor(); // cursor may have moved
Bram Moolenaar8a3bb562018-03-04 20:14:14 +0100709
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100710 // required when 'scrollbind' has been set
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711 if (curwin->w_p_scb)
712 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713 }
Bram Moolenaara162bc52015-01-07 16:54:21 +0100714
Bram Moolenaara162bc52015-01-07 16:54:21 +0100715 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
716 if (i+1 > eap->line2)
717 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100718 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
719 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720 }
721 listcmd_busy = FALSE;
722 }
723
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100724#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000725 if (save_ei != NULL)
726 {
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200727 buf_T *bnext;
728 aco_save_T aco;
729
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000730 au_event_restore(save_ei);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200731
732 for (buf = firstbuf; buf != NULL; buf = bnext)
733 {
734 bnext = buf->b_next;
735 if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET))
736 {
737 buf->b_flags &= ~BF_SYN_SET;
738
739 // buffer was opened while Syntax autocommands were disabled,
740 // need to trigger them now.
741 if (buf == curbuf)
742 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000743 curbuf->b_fname, TRUE, curbuf);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200744 else
745 {
746 aucmd_prepbuf(&aco, buf);
Bram Moolenaare76062c2022-11-28 18:51:43 +0000747 if (curbuf == buf)
748 {
749 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200750 buf->b_fname, TRUE, buf);
Bram Moolenaare76062c2022-11-28 18:51:43 +0000751 aucmd_restbuf(&aco);
752 }
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200753 }
754
755 // start over, in case autocommands messed things up.
756 bnext = firstbuf;
757 }
758 }
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000759 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200761#ifdef FEAT_CLIPBOARD
762 end_global_changes();
763#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764}
765
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766#ifdef FEAT_EVAL
767/*
768 * ":compiler[!] {name}"
769 */
770 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100771ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772{
773 char_u *buf;
774 char_u *old_cur_comp = NULL;
775 char_u *p;
776
777 if (*eap->arg == NUL)
778 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100779 // List all compiler scripts.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100781 // ) keep the indenter happy...
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000782 return;
783 }
784
785 buf = alloc(STRLEN(eap->arg) + 14);
786 if (buf == NULL)
787 return;
788
789 if (eap->forceit)
790 {
791 // ":compiler! {name}" sets global options
792 do_cmdline_cmd((char_u *)
793 "command -nargs=* CompilerSet set <args>");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794 }
795 else
796 {
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000797 // ":compiler! {name}" sets local options.
798 // To remain backwards compatible "current_compiler" is always
799 // used. A user's compiler plugin may set it, the distributed
800 // plugin will then skip the settings. Afterwards set
801 // "b:current_compiler" and restore "current_compiler".
802 // Explicitly prepend "g:" to make it work in a function.
803 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
804 if (old_cur_comp != NULL)
805 old_cur_comp = vim_strsave(old_cur_comp);
806 do_cmdline_cmd((char_u *)
807 "command -nargs=* -keepscript CompilerSet setlocal <args>");
808 }
809 do_unlet((char_u *)"g:current_compiler", TRUE);
810 do_unlet((char_u *)"b:current_compiler", TRUE);
811
812 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
813 if (source_runtime(buf, DIP_ALL) == FAIL)
814 semsg(_(e_compiler_not_supported_str), eap->arg);
815 vim_free(buf);
816
817 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
818
819 // Set "b:current_compiler" from "current_compiler".
820 p = get_var_value((char_u *)"g:current_compiler");
821 if (p != NULL)
822 set_internal_string_var((char_u *)"b:current_compiler", p);
823
824 // Restore "current_compiler" for ":compiler {name}".
825 if (!eap->forceit)
826 {
827 if (old_cur_comp != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828 {
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000829 set_internal_string_var((char_u *)"g:current_compiler",
830 old_cur_comp);
831 vim_free(old_cur_comp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 }
Yegappan Lakshmananed0c1d52022-12-30 18:07:46 +0000833 else
834 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 }
836}
837#endif
838
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100839#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
840
841# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
842/*
843 * Detect Python 3 or 2, and initialize 'pyxversion'.
844 */
845 void
846init_pyxversion(void)
847{
848 if (p_pyx == 0)
849 {
850 if (python3_enabled(FALSE))
851 p_pyx = 3;
852 else if (python_enabled(FALSE))
853 p_pyx = 2;
854 }
855}
856# endif
857
858/*
859 * Does a file contain one of the following strings at the beginning of any
860 * line?
861 * "#!(any string)python2" => returns 2
862 * "#!(any string)python3" => returns 3
863 * "# requires python 2.x" => returns 2
864 * "# requires python 3.x" => returns 3
865 * otherwise return 0.
866 */
867 static int
868requires_py_version(char_u *filename)
869{
870 FILE *file;
871 int requires_py_version = 0;
872 int i, lines;
873
874 lines = (int)p_mls;
875 if (lines < 0)
876 lines = 5;
877
878 file = mch_fopen((char *)filename, "r");
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000879 if (file == NULL)
880 return 0;
881
882 for (i = 0; i < lines; i++)
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100883 {
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000884 if (vim_fgets(IObuff, IOSIZE, file))
885 break;
886 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100887 {
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000888 // Check shebang.
889 if (strstr((char *)IObuff + 2, "python2") != NULL)
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100890 {
891 requires_py_version = 2;
892 break;
893 }
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000894 if (strstr((char *)IObuff + 2, "python3") != NULL)
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100895 {
896 requires_py_version = 3;
897 break;
898 }
899 }
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000900 IObuff[21] = '\0';
901 if (STRCMP("# requires python 2.x", IObuff) == 0)
902 {
903 requires_py_version = 2;
904 break;
905 }
906 if (STRCMP("# requires python 3.x", IObuff) == 0)
907 {
908 requires_py_version = 3;
909 break;
910 }
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100911 }
Yegappan Lakshmanan1cfb14a2023-01-09 19:04:23 +0000912 fclose(file);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100913 return requires_py_version;
914}
915
916
917/*
918 * Source a python file using the requested python version.
919 */
920 static void
921source_pyx_file(exarg_T *eap, char_u *fname)
922{
923 exarg_T ex;
924 int v = requires_py_version(fname);
925
926# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
927 init_pyxversion();
928# endif
929 if (v == 0)
930 {
931# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100932 // user didn't choose a preference, 'pyx' is used
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100933 v = p_pyx;
934# elif defined(FEAT_PYTHON)
935 v = 2;
936# elif defined(FEAT_PYTHON3)
937 v = 3;
938# endif
939 }
940
941 /*
942 * now source, if required python version is not supported show
943 * unobtrusive message.
944 */
945 if (eap == NULL)
Bram Moolenaara80faa82020-04-12 19:37:17 +0200946 CLEAR_FIELD(ex);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100947 else
948 ex = *eap;
949 ex.arg = fname;
950 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
951
952 if (v == 2)
953 {
954# ifdef FEAT_PYTHON
955 ex_pyfile(&ex);
956# else
957 vim_snprintf((char *)IObuff, IOSIZE,
958 _("W20: Required python version 2.x not supported, ignoring file: %s"),
959 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +0100960 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100961# endif
962 return;
963 }
964 else
965 {
966# ifdef FEAT_PYTHON3
967 ex_py3file(&ex);
968# else
969 vim_snprintf((char *)IObuff, IOSIZE,
970 _("W21: Required python version 3.x not supported, ignoring file: %s"),
971 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +0100972 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100973# endif
974 return;
975 }
976}
977
978/*
979 * ":pyxfile {fname}"
980 */
981 void
982ex_pyxfile(exarg_T *eap)
983{
984 source_pyx_file(eap, eap->arg);
985}
986
987/*
988 * ":pyx"
989 */
990 void
991ex_pyx(exarg_T *eap)
992{
993# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
994 init_pyxversion();
995 if (p_pyx == 2)
996 ex_python(eap);
997 else
998 ex_py3(eap);
999# elif defined(FEAT_PYTHON)
1000 ex_python(eap);
1001# elif defined(FEAT_PYTHON3)
1002 ex_py3(eap);
1003# endif
1004}
1005
1006/*
1007 * ":pyxdo"
1008 */
1009 void
1010ex_pyxdo(exarg_T *eap)
1011{
1012# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1013 init_pyxversion();
1014 if (p_pyx == 2)
1015 ex_pydo(eap);
1016 else
1017 ex_py3do(eap);
1018# elif defined(FEAT_PYTHON)
1019 ex_pydo(eap);
1020# elif defined(FEAT_PYTHON3)
1021 ex_py3do(eap);
1022# endif
1023}
1024
1025#endif
1026
Bram Moolenaar071d4272004-06-13 20:20:40 +00001027/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001028 * ":checktime [buffer]"
1029 */
1030 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001031ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001032{
1033 buf_T *buf;
1034 int save_no_check_timestamps = no_check_timestamps;
1035
1036 no_check_timestamps = 0;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001037 if (eap->addr_count == 0) // default is all buffers
Bram Moolenaar071d4272004-06-13 20:20:40 +00001038 check_timestamps(FALSE);
1039 else
1040 {
1041 buf = buflist_findnr((int)eap->line2);
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001042 if (buf != NULL) // cannot happen?
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 (void)buf_check_timestamp(buf, FALSE);
1044 }
1045 no_check_timestamps = save_no_check_timestamps;
1046}