blob: f0b5bfd45199ff6a7f432d000889f3dbd11e557e [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
30#ifdef FEAT_QUICKFIX
Bram Moolenaar217e1b82019-12-01 21:41:28 +010031 // never autowrite a "nofile" or "nowrite" buffer
Bram Moolenaar373154b2007-02-13 05:19:30 +000032 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +000033#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +000034 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +000035 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020036 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +000037 r = buf_write_all(buf, forceit);
38
Bram Moolenaar217e1b82019-12-01 21:41:28 +010039 // Writing may succeed but the buffer still changed, e.g., when there is a
40 // conversion error. We do want to return FAIL then.
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020041 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +000042 r = FAIL;
43 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +000044}
45
46/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +020047 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +000048 */
49 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010050autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000051{
52 buf_T *buf;
53
54 if (!(p_aw || p_awa) || !p_write)
55 return;
Bram Moolenaar29323592016-07-24 22:04:11 +020056 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +020057 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +000058 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020059 bufref_T bufref;
60
61 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +010062
Bram Moolenaar071d4272004-06-13 20:20:40 +000063 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +010064
Bram Moolenaar217e1b82019-12-01 21:41:28 +010065 // an autocommand may have deleted the buffer
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020066 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +000067 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +000068 }
69}
70
71/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +010072 * Return TRUE if buffer was changed and cannot be abandoned.
73 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +000074 */
Bram Moolenaar071d4272004-06-13 20:20:40 +000075 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010076check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +000077{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020078 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +020079 bufref_T bufref;
80
81 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +010082
Bram Moolenaar071d4272004-06-13 20:20:40 +000083 if ( !forceit
84 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +010085 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
86 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +000087 {
88#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
89 if ((p_confirm || cmdmod.confirm) && p_write)
90 {
91 buf_T *buf2;
92 int count = 0;
93
Bram Moolenaar45d3b142013-11-09 03:31:51 +010094 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +020095 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +000096 if (bufIsChanged(buf2)
97 && (buf2->b_ffname != NULL
98# ifdef FEAT_BROWSE
99 || cmdmod.browse
100# endif
101 ))
102 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200103 if (!bufref_valid(&bufref))
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100104 // Autocommand deleted buffer, oops! It's not changed now.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100106
Bram Moolenaar071d4272004-06-13 20:20:40 +0000107 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100108
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200109 if (!bufref_valid(&bufref))
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100110 // Autocommand deleted buffer, oops! It's not changed now.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000111 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112 return bufIsChanged(buf);
113 }
114#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100115 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +0200116 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100117 else
Bram Moolenaar7a760922018-02-19 23:10:02 +0100118 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119 return TRUE;
120 }
121 return FALSE;
122}
123
124#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
125
126#if defined(FEAT_BROWSE) || defined(PROTO)
127/*
128 * When wanting to write a file without a file name, ask the user for a name.
129 */
130 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100131browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000132{
133 if (buf->b_fname == NULL)
134 {
135 char_u *fname;
136
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000137 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
138 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139 if (fname != NULL)
140 {
141 if (setfname(buf, fname, NULL, TRUE) == OK)
142 buf->b_flags |= BF_NOTEDITED;
143 vim_free(fname);
144 }
145 }
146}
147#endif
148
149/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +0200150 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151 * Must check 'write' option first!
152 */
153 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100154dialog_changed(
155 buf_T *buf,
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100156 int checkall) // may abandon all changed buffers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157{
Bram Moolenaard9462e32011-04-11 21:35:11 +0200158 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 int ret;
160 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +0200161 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +0200163 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164 if (checkall)
165 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
166 else
167 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
168
Bram Moolenaar4ca41532019-05-09 21:48:37 +0200169 // Init ea pseudo-structure, this is needed for the check_overwrite()
170 // function.
Bram Moolenaara80faa82020-04-12 19:37:17 +0200171 CLEAR_FIELD(ea);
Bram Moolenaar8218f602012-04-25 17:32:18 +0200172
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173 if (ret == VIM_YES)
174 {
175#ifdef FEAT_BROWSE
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100176 // May get file name, when there is none
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177 browse_save_fname(buf);
178#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200179 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
180 buf->b_fname, buf->b_ffname, FALSE) == OK)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100181 // didn't hit Cancel
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182 (void)buf_write_all(buf, FALSE);
183 }
184 else if (ret == VIM_NO)
185 {
Bram Moolenaarc024b462019-06-08 18:07:21 +0200186 unchanged(buf, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187 }
188 else if (ret == VIM_ALL)
189 {
190 /*
191 * Write all modified files that can be written.
192 * Skip readonly buffers, these need to be confirmed
193 * individually.
194 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200195 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196 {
197 if (bufIsChanged(buf2)
198 && (buf2->b_ffname != NULL
199#ifdef FEAT_BROWSE
200 || cmdmod.browse
201#endif
202 )
203 && !buf2->b_p_ro)
204 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200205 bufref_T bufref;
206
207 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208#ifdef FEAT_BROWSE
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100209 // May get file name, when there is none
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 browse_save_fname(buf2);
211#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200212 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
213 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100214 // didn't hit Cancel
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100216
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100217 // an autocommand may have deleted the buffer
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200218 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000219 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 }
221 }
222 }
223 else if (ret == VIM_DISCARDALL)
224 {
225 /*
226 * mark all buffers as unchanged
227 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200228 FOR_ALL_BUFFERS(buf2)
Bram Moolenaarc024b462019-06-08 18:07:21 +0200229 unchanged(buf2, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000230 }
231}
232#endif
233
234/*
235 * Return TRUE if the buffer "buf" can be abandoned, either by making it
236 * hidden, autowriting it or unloading it.
237 */
238 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100239can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000240{
Bram Moolenaareb44a682017-08-03 22:44:55 +0200241 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000242 || !bufIsChanged(buf)
243 || buf->b_nwindows > 1
244 || autowrite(buf, forceit) == OK
245 || forceit);
246}
247
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100248/*
249 * Add a buffer number to "bufnrs", unless it's already there.
250 */
251 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100252add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100253{
254 int i;
255
256 for (i = 0; i < *bufnump; ++i)
257 if (bufnrs[i] == nr)
258 return;
259 bufnrs[*bufnump] = nr;
260 *bufnump = *bufnump + 1;
261}
262
Bram Moolenaar071d4272004-06-13 20:20:40 +0000263/*
264 * Return TRUE if any buffer was changed and cannot be abandoned.
265 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100266 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +0100267 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000268 */
269 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100270check_changed_any(
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100271 int hidden, // Only check hidden buffers
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100272 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000273{
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100274 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000275 buf_T *buf;
276 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100277 int i;
278 int bufnum = 0;
279 int bufcount = 0;
280 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100281 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000282 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000283
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100284 // Make a list of all buffers, with the most important ones first.
Bram Moolenaar29323592016-07-24 22:04:11 +0200285 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100286 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000287
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100288 if (bufcount == 0)
289 return FALSE;
290
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200291 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100292 if (bufnrs == NULL)
293 return FALSE;
294
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100295 // curbuf
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100296 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100297
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100298 // buffers in current tab
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100299 FOR_ALL_WINDOWS(wp)
300 if (wp->w_buffer != curbuf)
301 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
302
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100303 // buffers in other tabs
Bram Moolenaar29323592016-07-24 22:04:11 +0200304 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100305 if (tp != curtab)
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200306 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100307 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100308
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100309 // any other buffer
Bram Moolenaar29323592016-07-24 22:04:11 +0200310 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100311 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
312
313 for (i = 0; i < bufnum; ++i)
314 {
315 buf = buflist_findnr(bufnrs[i]);
316 if (buf == NULL)
317 continue;
318 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
319 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200320 bufref_T bufref;
321
322 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100323#ifdef FEAT_TERMINAL
324 if (term_job_running(buf->b_term))
325 {
326 if (term_try_stop_job(buf) == FAIL)
327 break;
328 }
329 else
330#endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100331 // Try auto-writing the buffer. If this fails but the buffer no
332 // longer exists it's not changed, that's OK.
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100333 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
334 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200335 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100336 break; // didn't save - still changes
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100337 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000338 }
339
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100340 if (i >= bufnum)
341 goto theend;
342
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100343 // Get here if "buf" cannot be abandoned.
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100344 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000345 exiting = FALSE;
346#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
347 /*
348 * When ":confirm" used, don't give an error message.
349 */
350 if (!(p_confirm || cmdmod.confirm))
351#endif
352 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100353 // There must be a wait_return for this message, do_buffer()
354 // may cause a redraw. But wait_return() is a no-op when vgetc()
355 // is busy (Quit used from window menu), then make sure we don't
356 // cause a scroll up.
Bram Moolenaar61660ea2006-04-07 21:40:07 +0000357 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358 {
359 msg_row = cmdline_row;
360 msg_col = 0;
361 msg_didout = FALSE;
362 }
Bram Moolenaareb44a682017-08-03 22:44:55 +0200363 if (
364#ifdef FEAT_TERMINAL
365 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100366 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +0200367 buf->b_fname)
368 :
369#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100370 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +0200371 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000372 {
373 save = no_wait_return;
374 no_wait_return = FALSE;
375 wait_return(FALSE);
376 no_wait_return = save;
377 }
378 }
379
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100380 // Try to find a window that contains the buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000381 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100382 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383 if (wp->w_buffer == buf)
384 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200385 bufref_T bufref;
386
387 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100388
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100389 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100390
Bram Moolenaarbdace832019-03-02 10:13:42 +0100391 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200392 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100393 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100394 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000395 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100396buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000397
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100398 // Open the changed buffer in the current window.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000399 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +0100400 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000401
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100402theend:
403 vim_free(bufnrs);
404 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405}
406
407/*
408 * return FAIL if there is no file name, OK if there is one
409 * give error message for FAIL
410 */
411 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100412check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000413{
414 if (curbuf->b_ffname == NULL)
415 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100416 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000417 return FAIL;
418 }
419 return OK;
420}
421
422/*
423 * flush the contents of a buffer, unless it has no file name
424 *
425 * return FAIL for failure, OK otherwise
426 */
427 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100428buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000429{
430 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432
433 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
434 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
435 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000436 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000437 {
Bram Moolenaar8820b482017-03-16 17:23:31 +0100438 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +0100439 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000440 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 return retval;
442}
443
444/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200445 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 */
447 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100448ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000449{
450 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000451 win_T *wp;
452 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +0100453 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100455#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000457#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000458 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200459#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +0200460 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200461 int qf_idx;
462#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463
Bram Moolenaar0106e3d2016-02-23 18:55:43 +0100464#ifndef FEAT_QUICKFIX
465 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
466 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
467 {
468 ex_ni(eap);
469 return;
470 }
471#endif
472
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100473#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000474 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200475 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100476 // Don't do syntax HL autocommands. Skipping the syntax file is a
477 // great speed improvement.
Bram Moolenaardcaf10e2005-01-21 11:55:25 +0000478 save_ei = au_event_disable(",Syntax");
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200479
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200480 FOR_ALL_BUFFERS(buf)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200481 buf->b_flags &= ~BF_SYN_SET;
482 buf = curbuf;
483 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000484#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200485#ifdef FEAT_CLIPBOARD
486 start_global_changes();
487#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488
489 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000490 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +0200491 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100492 || !check_changed(curbuf, CCGD_AW
493 | (eap->forceit ? CCGD_FORCEIT : 0)
494 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000495 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496 i = 0;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100497 // start at the eap->line1 argument/window/buffer
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000498 wp = firstwin;
499 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100500 switch (eap->cmdidx)
501 {
Bram Moolenaara162bc52015-01-07 16:54:21 +0100502 case CMD_windo:
503 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
504 i++;
505 break;
506 case CMD_tabdo:
507 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
508 i++;
509 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100510 case CMD_argdo:
511 i = eap->line1 - 1;
512 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100513 default:
514 break;
515 }
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100516 // set pcmark now
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200518 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100519 // Advance to the first listed buffer after "eap->line1".
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200520 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +0100521 || !buf->b_p_bl); buf = buf->b_next)
522 if (buf->b_fnum > eap->line2)
523 {
524 buf = NULL;
525 break;
526 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200527 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +0100528 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200529 }
530#ifdef FEAT_QUICKFIX
531 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
532 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
533 {
Bram Moolenaar25190db2019-05-04 15:05:28 +0200534 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200535 if (qf_size <= 0 || eap->line1 > qf_size)
536 buf = NULL;
537 else
538 {
539 ex_cc(eap);
540
541 buf = curbuf;
542 i = eap->line1 - 1;
543 if (eap->addr_count <= 0)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100544 // default is all the quickfix/location list entries
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200545 eap->line2 = qf_size;
546 }
547 }
548#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 else
550 setpcmark();
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100551 listcmd_busy = TRUE; // avoids setting pcmark below
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552
Bram Moolenaare25bb902015-02-27 20:33:37 +0100553 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 {
555 if (eap->cmdidx == CMD_argdo)
556 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100557 // go to argument "i"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558 if (i == ARGCOUNT)
559 break;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100560 // Don't call do_argfile() when already there, it will try
561 // reloading the file.
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000562 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000563 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100564 // Clear 'shm' to avoid that the file message overwrites
565 // any output from the command.
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000566 p_shm_save = vim_strsave(p_shm);
567 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000569 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
570 vim_free(p_shm_save);
571 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572 if (curwin->w_arg_idx != i)
573 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575 else if (eap->cmdidx == CMD_windo)
576 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100577 // go to window "wp"
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000578 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000580 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +0000581 if (curwin != wp)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100582 break; // something must be wrong
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000583 wp = curwin->w_next;
584 }
585 else if (eap->cmdidx == CMD_tabdo)
586 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100587 // go to window "tp"
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000588 if (!valid_tabpage(tp))
589 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200590 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000591 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000593 else if (eap->cmdidx == CMD_bufdo)
594 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100595 // Remember the number of the next listed buffer, in case
596 // ":bwipe" is used or autocommands do something strange.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 next_fnum = -1;
598 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
599 if (buf->b_p_bl)
600 {
601 next_fnum = buf->b_fnum;
602 break;
603 }
604 }
605
Bram Moolenaara162bc52015-01-07 16:54:21 +0100606 ++i;
607
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100608 // execute the command
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609 do_cmdline(eap->arg, eap->getline, eap->cookie,
610 DOCMD_VERBOSE + DOCMD_NOWAIT);
611
612 if (eap->cmdidx == CMD_bufdo)
613 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100614 // Done?
Bram Moolenaara162bc52015-01-07 16:54:21 +0100615 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000616 break;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100617 // Check if the buffer still exists.
Bram Moolenaar29323592016-07-24 22:04:11 +0200618 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619 if (buf->b_fnum == next_fnum)
620 break;
621 if (buf == NULL)
622 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000623
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100624 // Go to the next buffer. Clear 'shm' to avoid that the file
625 // message overwrites any output from the command.
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000626 p_shm_save = vim_strsave(p_shm);
627 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000629 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
630 vim_free(p_shm_save);
631
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100632 // If autocommands took us elsewhere, quit here.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 if (curbuf->b_fnum != next_fnum)
634 break;
635 }
636
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200637#ifdef FEAT_QUICKFIX
638 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
639 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
640 {
641 if (i >= qf_size || i >= eap->line2)
642 break;
643
644 qf_idx = qf_get_cur_idx(eap);
645
Bram Moolenaar14798ab2020-05-28 21:30:11 +0200646 // Clear 'shm' to avoid that the file message overwrites
647 // any output from the command.
648 p_shm_save = vim_strsave(p_shm);
649 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200650 ex_cnext(eap);
Bram Moolenaar14798ab2020-05-28 21:30:11 +0200651 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
652 vim_free(p_shm_save);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200653
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100654 // If jumping to the next quickfix entry fails, quit here
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200655 if (qf_get_cur_idx(eap) == qf_idx)
656 break;
657 }
658#endif
659
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660 if (eap->cmdidx == CMD_windo)
661 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100662 validate_cursor(); // cursor may have moved
Bram Moolenaar8a3bb562018-03-04 20:14:14 +0100663
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100664 // required when 'scrollbind' has been set
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665 if (curwin->w_p_scb)
666 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667 }
Bram Moolenaara162bc52015-01-07 16:54:21 +0100668
Bram Moolenaara162bc52015-01-07 16:54:21 +0100669 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
670 if (i+1 > eap->line2)
671 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100672 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
673 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000674 }
675 listcmd_busy = FALSE;
676 }
677
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100678#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000679 if (save_ei != NULL)
680 {
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200681 buf_T *bnext;
682 aco_save_T aco;
683
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000684 au_event_restore(save_ei);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200685
686 for (buf = firstbuf; buf != NULL; buf = bnext)
687 {
688 bnext = buf->b_next;
689 if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET))
690 {
691 buf->b_flags &= ~BF_SYN_SET;
692
693 // buffer was opened while Syntax autocommands were disabled,
694 // need to trigger them now.
695 if (buf == curbuf)
696 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000697 curbuf->b_fname, TRUE, curbuf);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200698 else
699 {
700 aucmd_prepbuf(&aco, buf);
701 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
702 buf->b_fname, TRUE, buf);
703 aucmd_restbuf(&aco);
704 }
705
706 // start over, in case autocommands messed things up.
707 bnext = firstbuf;
708 }
709 }
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000710 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200712#ifdef FEAT_CLIPBOARD
713 end_global_changes();
714#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715}
716
Bram Moolenaar071d4272004-06-13 20:20:40 +0000717#ifdef FEAT_EVAL
718/*
719 * ":compiler[!] {name}"
720 */
721 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100722ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000723{
724 char_u *buf;
725 char_u *old_cur_comp = NULL;
726 char_u *p;
727
728 if (*eap->arg == NUL)
729 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100730 // List all compiler scripts.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100732 // ) keep the indenter happy...
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733 }
734 else
735 {
Bram Moolenaar964b3742019-05-24 18:54:09 +0200736 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737 if (buf != NULL)
738 {
739 if (eap->forceit)
740 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100741 // ":compiler! {name}" sets global options
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 do_cmdline_cmd((char_u *)
743 "command -nargs=* CompilerSet set <args>");
744 }
745 else
746 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100747 // ":compiler! {name}" sets local options.
748 // To remain backwards compatible "current_compiler" is always
749 // used. A user's compiler plugin may set it, the distributed
750 // plugin will then skip the settings. Afterwards set
751 // "b:current_compiler" and restore "current_compiler".
752 // Explicitly prepend "g:" to make it work in a function.
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100753 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754 if (old_cur_comp != NULL)
755 old_cur_comp = vim_strsave(old_cur_comp);
756 do_cmdline_cmd((char_u *)
757 "command -nargs=* CompilerSet setlocal <args>");
758 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100759 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +0000760 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000761
762 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +0100763 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100764 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 vim_free(buf);
766
767 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
768
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100769 // Set "b:current_compiler" from "current_compiler".
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100770 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771 if (p != NULL)
772 set_internal_string_var((char_u *)"b:current_compiler", p);
773
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100774 // Restore "current_compiler" for ":compiler {name}".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 if (!eap->forceit)
776 {
777 if (old_cur_comp != NULL)
778 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100779 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 old_cur_comp);
781 vim_free(old_cur_comp);
782 }
783 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100784 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 }
786 }
787 }
788}
789#endif
790
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100791#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
792
793# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
794/*
795 * Detect Python 3 or 2, and initialize 'pyxversion'.
796 */
797 void
798init_pyxversion(void)
799{
800 if (p_pyx == 0)
801 {
802 if (python3_enabled(FALSE))
803 p_pyx = 3;
804 else if (python_enabled(FALSE))
805 p_pyx = 2;
806 }
807}
808# endif
809
810/*
811 * Does a file contain one of the following strings at the beginning of any
812 * line?
813 * "#!(any string)python2" => returns 2
814 * "#!(any string)python3" => returns 3
815 * "# requires python 2.x" => returns 2
816 * "# requires python 3.x" => returns 3
817 * otherwise return 0.
818 */
819 static int
820requires_py_version(char_u *filename)
821{
822 FILE *file;
823 int requires_py_version = 0;
824 int i, lines;
825
826 lines = (int)p_mls;
827 if (lines < 0)
828 lines = 5;
829
830 file = mch_fopen((char *)filename, "r");
831 if (file != NULL)
832 {
833 for (i = 0; i < lines; i++)
834 {
835 if (vim_fgets(IObuff, IOSIZE, file))
836 break;
837 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
838 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100839 // Check shebang.
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100840 if (strstr((char *)IObuff + 2, "python2") != NULL)
841 {
842 requires_py_version = 2;
843 break;
844 }
845 if (strstr((char *)IObuff + 2, "python3") != NULL)
846 {
847 requires_py_version = 3;
848 break;
849 }
850 }
851 IObuff[21] = '\0';
852 if (STRCMP("# requires python 2.x", IObuff) == 0)
853 {
854 requires_py_version = 2;
855 break;
856 }
857 if (STRCMP("# requires python 3.x", IObuff) == 0)
858 {
859 requires_py_version = 3;
860 break;
861 }
862 }
863 fclose(file);
864 }
865 return requires_py_version;
866}
867
868
869/*
870 * Source a python file using the requested python version.
871 */
872 static void
873source_pyx_file(exarg_T *eap, char_u *fname)
874{
875 exarg_T ex;
876 int v = requires_py_version(fname);
877
878# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
879 init_pyxversion();
880# endif
881 if (v == 0)
882 {
883# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100884 // user didn't choose a preference, 'pyx' is used
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100885 v = p_pyx;
886# elif defined(FEAT_PYTHON)
887 v = 2;
888# elif defined(FEAT_PYTHON3)
889 v = 3;
890# endif
891 }
892
893 /*
894 * now source, if required python version is not supported show
895 * unobtrusive message.
896 */
897 if (eap == NULL)
Bram Moolenaara80faa82020-04-12 19:37:17 +0200898 CLEAR_FIELD(ex);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100899 else
900 ex = *eap;
901 ex.arg = fname;
902 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
903
904 if (v == 2)
905 {
906# ifdef FEAT_PYTHON
907 ex_pyfile(&ex);
908# else
909 vim_snprintf((char *)IObuff, IOSIZE,
910 _("W20: Required python version 2.x not supported, ignoring file: %s"),
911 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +0100912 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100913# endif
914 return;
915 }
916 else
917 {
918# ifdef FEAT_PYTHON3
919 ex_py3file(&ex);
920# else
921 vim_snprintf((char *)IObuff, IOSIZE,
922 _("W21: Required python version 3.x not supported, ignoring file: %s"),
923 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +0100924 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100925# endif
926 return;
927 }
928}
929
930/*
931 * ":pyxfile {fname}"
932 */
933 void
934ex_pyxfile(exarg_T *eap)
935{
936 source_pyx_file(eap, eap->arg);
937}
938
939/*
940 * ":pyx"
941 */
942 void
943ex_pyx(exarg_T *eap)
944{
945# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
946 init_pyxversion();
947 if (p_pyx == 2)
948 ex_python(eap);
949 else
950 ex_py3(eap);
951# elif defined(FEAT_PYTHON)
952 ex_python(eap);
953# elif defined(FEAT_PYTHON3)
954 ex_py3(eap);
955# endif
956}
957
958/*
959 * ":pyxdo"
960 */
961 void
962ex_pyxdo(exarg_T *eap)
963{
964# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
965 init_pyxversion();
966 if (p_pyx == 2)
967 ex_pydo(eap);
968 else
969 ex_py3do(eap);
970# elif defined(FEAT_PYTHON)
971 ex_pydo(eap);
972# elif defined(FEAT_PYTHON3)
973 ex_py3do(eap);
974# endif
975}
976
977#endif
978
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000980 * ":checktime [buffer]"
981 */
982 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100983ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000984{
985 buf_T *buf;
986 int save_no_check_timestamps = no_check_timestamps;
987
988 no_check_timestamps = 0;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100989 if (eap->addr_count == 0) // default is all buffers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990 check_timestamps(FALSE);
991 else
992 {
993 buf = buflist_findnr((int)eap->line2);
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100994 if (buf != NULL) // cannot happen?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000995 (void)buf_check_timestamp(buf, FALSE);
996 }
997 no_check_timestamps = save_no_check_timestamps;
998}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999
Bram Moolenaar071d4272004-06-13 20:20:40 +00001000#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
1001 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001002# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001003 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001004get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001005{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001006 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001007
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001008 // Obtain the locale value from the libraries.
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001009 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001010
Bram Moolenaar4f974752019-02-17 17:44:42 +01001011# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001012 if (loc != NULL)
1013 {
1014 char_u *p;
1015
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001016 // setocale() returns something like "LC_COLLATE=<name>;LC_..." when
1017 // one of the values (e.g., LC_CTYPE) differs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001018 p = vim_strchr(loc, '=');
1019 if (p != NULL)
1020 {
1021 loc = ++p;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001022 while (*p != NUL) // remove trailing newline
Bram Moolenaar071d4272004-06-13 20:20:40 +00001023 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001024 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001025 {
1026 *p = NUL;
1027 break;
1028 }
1029 ++p;
1030 }
1031 }
1032 }
1033# endif
1034
1035 return loc;
1036}
1037#endif
1038
1039
Bram Moolenaar4f974752019-02-17 17:44:42 +01001040#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001041/*
1042 * On MS-Windows locale names are strings like "German_Germany.1252", but
1043 * gettext expects "de". Try to translate one into another here for a few
1044 * supported languages.
1045 */
1046 static char_u *
1047gettext_lang(char_u *name)
1048{
1049 int i;
1050 static char *(mtable[]) = {
1051 "afrikaans", "af",
1052 "czech", "cs",
1053 "dutch", "nl",
1054 "german", "de",
1055 "english_united kingdom", "en_GB",
1056 "spanish", "es",
1057 "french", "fr",
1058 "italian", "it",
1059 "japanese", "ja",
1060 "korean", "ko",
1061 "norwegian", "no",
1062 "polish", "pl",
1063 "russian", "ru",
1064 "slovak", "sk",
1065 "swedish", "sv",
1066 "ukrainian", "uk",
1067 "chinese_china", "zh_CN",
1068 "chinese_taiwan", "zh_TW",
1069 NULL};
1070
1071 for (i = 0; mtable[i] != NULL; i += 2)
1072 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001073 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074 return name;
1075}
1076#endif
1077
1078#if defined(FEAT_MULTI_LANG) || defined(PROTO)
1079/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01001080 * Return TRUE when "lang" starts with a valid language name.
1081 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
1082 */
1083 static int
1084is_valid_mess_lang(char_u *lang)
1085{
1086 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
1087}
1088
1089/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090 * Obtain the current messages language. Used to set the default for
1091 * 'helplang'. May return NULL or an empty string.
1092 */
1093 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001094get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095{
1096 char_u *p;
1097
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001098# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001100 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101# else
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001102 // This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
1103 // may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
1104 // and LC_MONETARY may be set differently for a Japanese working in the
1105 // US.
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001106 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107# endif
1108# else
1109 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01001110 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 {
1112 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01001113 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114 p = mch_getenv((char_u *)"LANG");
1115 }
1116# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01001117# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 p = gettext_lang(p);
1119# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01001120 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121}
1122#endif
1123
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001124// Complicated #if; matches with where get_mess_env() is used below.
Bram Moolenaardef9e822004-12-31 20:58:58 +00001125#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
1126 && defined(LC_MESSAGES))) \
1127 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00001128 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129/*
1130 * Get the language used for messages from the environment.
1131 */
1132 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001133get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134{
1135 char_u *p;
1136
1137 p = mch_getenv((char_u *)"LC_ALL");
1138 if (p == NULL || *p == NUL)
1139 {
1140 p = mch_getenv((char_u *)"LC_MESSAGES");
1141 if (p == NULL || *p == NUL)
1142 {
1143 p = mch_getenv((char_u *)"LANG");
1144 if (p != NULL && VIM_ISDIGIT(*p))
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001145 p = NULL; // ignore something like "1043"
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001146# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001147 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001148 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001149# endif
1150 }
1151 }
1152 return p;
1153}
1154#endif
1155
1156#if defined(FEAT_EVAL) || defined(PROTO)
1157
1158/*
1159 * Set the "v:lang" variable according to the current locale setting.
1160 * Also do "v:lc_time"and "v:ctype".
1161 */
1162 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001163set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001164{
1165 char_u *loc;
1166
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001167# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001168 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001169# else
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001170 // setlocale() not supported: use the default value
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171 loc = (char_u *)"C";
1172# endif
1173 set_vim_var_string(VV_CTYPE, loc, -1);
1174
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001175 // When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
1176 // back to LC_CTYPE if it's empty.
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001177# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001178 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001179# else
1180 loc = get_mess_env();
1181# endif
1182 set_vim_var_string(VV_LANG, loc, -1);
1183
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001184# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001185 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186# endif
1187 set_vim_var_string(VV_LC_TIME, loc, -1);
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +02001188
1189# ifdef HAVE_GET_LOCALE_VAL
1190 loc = get_locale_val(LC_COLLATE);
1191# else
1192 // setlocale() not supported: use the default value
1193 loc = (char_u *)"C";
1194# endif
1195 set_vim_var_string(VV_COLLATE, loc, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196}
1197#endif
1198
Bram Moolenaarec680282020-06-12 19:35:32 +02001199#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200/*
1201 * ":language": Set the language (locale).
1202 */
1203 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001204ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001205{
1206 char *loc;
1207 char_u *p;
1208 char_u *name;
1209 int what = LC_ALL;
1210 char *whatstr = "";
Bram Moolenaarec680282020-06-12 19:35:32 +02001211# ifdef LC_MESSAGES
1212# define VIM_LC_MESSAGES LC_MESSAGES
1213# else
1214# define VIM_LC_MESSAGES 6789
1215# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001216
1217 name = eap->arg;
1218
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001219 // Check for "messages {name}", "ctype {name}" or "time {name}" argument.
1220 // Allow abbreviation, but require at least 3 characters to avoid
1221 // confusion with a two letter language name "me" or "ct".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01001223 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224 {
1225 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
1226 {
1227 what = VIM_LC_MESSAGES;
1228 name = skipwhite(p);
1229 whatstr = "messages ";
1230 }
1231 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
1232 {
1233 what = LC_CTYPE;
1234 name = skipwhite(p);
1235 whatstr = "ctype ";
1236 }
1237 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
1238 {
1239 what = LC_TIME;
1240 name = skipwhite(p);
1241 whatstr = "time ";
1242 }
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +02001243 else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0)
1244 {
1245 what = LC_COLLATE;
1246 name = skipwhite(p);
1247 whatstr = "collate ";
1248 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249 }
1250
1251 if (*name == NUL)
1252 {
Bram Moolenaarec680282020-06-12 19:35:32 +02001253# ifndef LC_MESSAGES
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254 if (what == VIM_LC_MESSAGES)
1255 p = get_mess_env();
1256 else
Bram Moolenaarec680282020-06-12 19:35:32 +02001257# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258 p = (char_u *)setlocale(what, NULL);
1259 if (p == NULL || *p == NUL)
1260 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001261 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262 }
1263 else
1264 {
Bram Moolenaarec680282020-06-12 19:35:32 +02001265# ifndef LC_MESSAGES
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 if (what == VIM_LC_MESSAGES)
1267 loc = "";
1268 else
Bram Moolenaarec680282020-06-12 19:35:32 +02001269# endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001270 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271 loc = setlocale(what, (char *)name);
Bram Moolenaarec680282020-06-12 19:35:32 +02001272# if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001273 // Make sure strtod() uses a decimal point, not a comma.
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001274 setlocale(LC_NUMERIC, "C");
Bram Moolenaarec680282020-06-12 19:35:32 +02001275# endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001276 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001278 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001279 else
1280 {
Bram Moolenaarec680282020-06-12 19:35:32 +02001281# ifdef HAVE_NL_MSG_CAT_CNTR
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001282 // Need to do this for GNU gettext, otherwise cached translations
1283 // will be used again.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284 extern int _nl_msg_cat_cntr;
1285
1286 ++_nl_msg_cat_cntr;
Bram Moolenaarec680282020-06-12 19:35:32 +02001287# endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001288 // Reset $LC_ALL, otherwise it would overrule everything.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
1290
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +02001291 if (what != LC_TIME && what != LC_COLLATE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001293 // Tell gettext() what to translate to. It apparently doesn't
1294 // use the currently effective locale. Also do this when
1295 // FEAT_GETTEXT isn't defined, so that shell commands use this
1296 // value.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00001298 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001299 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02001300
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001301 // Clear $LANGUAGE because GNU gettext uses it.
Bram Moolenaare3a0b532013-06-28 20:36:30 +02001302 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01001303# ifdef MSWIN
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001304 // Apparently MS-Windows printf() may cause a crash when
1305 // we give it 8-bit text while it's expecting text in the
1306 // current locale. This call avoids that.
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00001307 setlocale(LC_CTYPE, "C");
1308# endif
1309 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310 if (what != LC_CTYPE)
1311 {
1312 char_u *mname;
Bram Moolenaarec680282020-06-12 19:35:32 +02001313# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001314 mname = gettext_lang(name);
Bram Moolenaarec680282020-06-12 19:35:32 +02001315# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001316 mname = name;
Bram Moolenaarec680282020-06-12 19:35:32 +02001317# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001318 vim_setenv((char_u *)"LC_MESSAGES", mname);
Bram Moolenaarec680282020-06-12 19:35:32 +02001319# ifdef FEAT_MULTI_LANG
Bram Moolenaar071d4272004-06-13 20:20:40 +00001320 set_helplang_default(mname);
Bram Moolenaarec680282020-06-12 19:35:32 +02001321# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001322 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001323 }
1324
1325# ifdef FEAT_EVAL
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +02001326 // Set v:lang, v:lc_time, v:collate and v:ctype to the final result.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001327 set_lang_var();
1328# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02001329# ifdef FEAT_TITLE
1330 maketitle();
1331# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332 }
1333 }
1334}
1335
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001336static char_u **locales = NULL; // Array of all available locales
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001337
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001338static int did_init_locales = FALSE;
1339
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001340/*
1341 * Return an array of strings for all available locales + NULL for the
1342 * last element. Return NULL in case of error.
1343 */
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001344 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001345find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001346{
1347 garray_T locales_ga;
1348 char_u *loc;
Bram Moolenaarec680282020-06-12 19:35:32 +02001349 char_u *locale_list;
1350# ifdef MSWIN
1351 size_t len = 0;
1352# endif
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001353
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001354 // Find all available locales by running command "locale -a". If this
1355 // doesn't work we won't have completion.
Bram Moolenaarec680282020-06-12 19:35:32 +02001356# ifndef MSWIN
1357 locale_list = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02001358 NULL, SHELL_SILENT, NULL);
Bram Moolenaarec680282020-06-12 19:35:32 +02001359# else
1360 // Find all available locales by examining the directories in
1361 // $VIMRUNTIME/lang/
1362 {
1363 int options = WILD_SILENT|WILD_USE_NL|WILD_KEEP_ALL;
1364 expand_T xpc;
1365 char_u *p;
1366
1367 ExpandInit(&xpc);
1368 xpc.xp_context = EXPAND_DIRECTORIES;
1369 locale_list = ExpandOne(&xpc, (char_u *)"$VIMRUNTIME/lang/*",
1370 NULL, options, WILD_ALL);
1371 ExpandCleanup(&xpc);
1372 if (locale_list == NULL)
1373 // Add a dummy input, that will be skipped lated but we need to
1374 // have something in locale_list so that the C locale is added at
1375 // the end.
1376 locale_list = vim_strsave((char_u *)".\n");
1377 p = locale_list;
1378 // find the last directory delimiter
1379 while (p != NULL && *p != NUL)
1380 {
1381 if (*p == '\n')
1382 break;
1383 if (*p == '\\')
1384 len = p - locale_list;
1385 p++;
1386 }
1387 }
1388# endif
1389 if (locale_list == NULL)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001390 return NULL;
1391 ga_init2(&locales_ga, sizeof(char_u *), 20);
1392
Bram Moolenaarec680282020-06-12 19:35:32 +02001393 // Transform locale_list string where each locale is separated by "\n"
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001394 // into an array of locale strings.
Bram Moolenaarec680282020-06-12 19:35:32 +02001395 loc = (char_u *)strtok((char *)locale_list, "\n");
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001396
1397 while (loc != NULL)
1398 {
Bram Moolenaarec680282020-06-12 19:35:32 +02001399 int ignore = FALSE;
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001400
Bram Moolenaarec680282020-06-12 19:35:32 +02001401# ifdef MSWIN
1402 if (len > 0)
1403 loc += len + 1;
1404 // skip locales with a dot (which indicates the charset)
1405 if (vim_strchr(loc, '.') != NULL)
1406 ignore = TRUE;
1407# endif
1408 if (!ignore)
1409 {
1410 if (ga_grow(&locales_ga, 1) == FAIL)
1411 break;
1412
1413 loc = vim_strsave(loc);
1414 if (loc == NULL)
1415 break;
1416
1417 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
1418 }
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001419 loc = (char_u *)strtok(NULL, "\n");
1420 }
Bram Moolenaarec680282020-06-12 19:35:32 +02001421
1422# ifdef MSWIN
1423 // Add the C locale
1424 if (ga_grow(&locales_ga, 1) == OK)
1425 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] =
1426 vim_strsave((char_u *)"C");
1427# endif
1428
1429 vim_free(locale_list);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001430 if (ga_grow(&locales_ga, 1) == FAIL)
1431 {
1432 ga_clear(&locales_ga);
1433 return NULL;
1434 }
1435 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
1436 return (char_u **)locales_ga.ga_data;
1437}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001438
1439/*
1440 * Lazy initialization of all available locales.
1441 */
1442 static void
1443init_locales(void)
1444{
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001445 if (!did_init_locales)
1446 {
1447 did_init_locales = TRUE;
1448 locales = find_locales();
1449 }
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001450}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001451
Bram Moolenaarec680282020-06-12 19:35:32 +02001452# if defined(EXITFREE) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001453 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001454free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001455{
1456 int i;
1457 if (locales != NULL)
1458 {
1459 for (i = 0; locales[i] != NULL; i++)
1460 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01001461 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001462 }
1463}
Bram Moolenaarec680282020-06-12 19:35:32 +02001464# endif
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001465
Bram Moolenaar071d4272004-06-13 20:20:40 +00001466/*
1467 * Function given to ExpandGeneric() to obtain the possible arguments of the
1468 * ":language" command.
1469 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001471get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001472{
1473 if (idx == 0)
1474 return (char_u *)"messages";
1475 if (idx == 1)
1476 return (char_u *)"ctype";
1477 if (idx == 2)
1478 return (char_u *)"time";
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +02001479 if (idx == 3)
1480 return (char_u *)"collate";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001481
1482 init_locales();
1483 if (locales == NULL)
1484 return NULL;
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +02001485 return locales[idx - 4];
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001486}
1487
1488/*
1489 * Function given to ExpandGeneric() to obtain the available locales.
1490 */
1491 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001492get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001493{
1494 init_locales();
1495 if (locales == NULL)
1496 return NULL;
1497 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001499
1500#endif