blob: bbaff391e4197650a41e19398e0ab8d7fb8bc287 [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.
171 vim_memset(&ea, 0, sizeof(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)
306 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
307 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
480 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
481 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
646 ex_cnext(eap);
647
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100648 // If jumping to the next quickfix entry fails, quit here
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200649 if (qf_get_cur_idx(eap) == qf_idx)
650 break;
651 }
652#endif
653
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654 if (eap->cmdidx == CMD_windo)
655 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100656 validate_cursor(); // cursor may have moved
Bram Moolenaar8a3bb562018-03-04 20:14:14 +0100657
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100658 // required when 'scrollbind' has been set
Bram Moolenaar071d4272004-06-13 20:20:40 +0000659 if (curwin->w_p_scb)
660 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661 }
Bram Moolenaara162bc52015-01-07 16:54:21 +0100662
Bram Moolenaara162bc52015-01-07 16:54:21 +0100663 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
664 if (i+1 > eap->line2)
665 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100666 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
667 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 }
669 listcmd_busy = FALSE;
670 }
671
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100672#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000673 if (save_ei != NULL)
674 {
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200675 buf_T *bnext;
676 aco_save_T aco;
677
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000678 au_event_restore(save_ei);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200679
680 for (buf = firstbuf; buf != NULL; buf = bnext)
681 {
682 bnext = buf->b_next;
683 if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET))
684 {
685 buf->b_flags &= ~BF_SYN_SET;
686
687 // buffer was opened while Syntax autocommands were disabled,
688 // need to trigger them now.
689 if (buf == curbuf)
690 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000691 curbuf->b_fname, TRUE, curbuf);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200692 else
693 {
694 aucmd_prepbuf(&aco, buf);
695 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
696 buf->b_fname, TRUE, buf);
697 aucmd_restbuf(&aco);
698 }
699
700 // start over, in case autocommands messed things up.
701 bnext = firstbuf;
702 }
703 }
Bram Moolenaar6ac54292005-02-02 23:07:25 +0000704 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200706#ifdef FEAT_CLIPBOARD
707 end_global_changes();
708#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709}
710
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711#ifdef FEAT_EVAL
712/*
713 * ":compiler[!] {name}"
714 */
715 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100716ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000717{
718 char_u *buf;
719 char_u *old_cur_comp = NULL;
720 char_u *p;
721
722 if (*eap->arg == NUL)
723 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100724 // List all compiler scripts.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100726 // ) keep the indenter happy...
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 }
728 else
729 {
Bram Moolenaar964b3742019-05-24 18:54:09 +0200730 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 if (buf != NULL)
732 {
733 if (eap->forceit)
734 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100735 // ":compiler! {name}" sets global options
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 do_cmdline_cmd((char_u *)
737 "command -nargs=* CompilerSet set <args>");
738 }
739 else
740 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100741 // ":compiler! {name}" sets local options.
742 // To remain backwards compatible "current_compiler" is always
743 // used. A user's compiler plugin may set it, the distributed
744 // plugin will then skip the settings. Afterwards set
745 // "b:current_compiler" and restore "current_compiler".
746 // Explicitly prepend "g:" to make it work in a function.
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100747 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 if (old_cur_comp != NULL)
749 old_cur_comp = vim_strsave(old_cur_comp);
750 do_cmdline_cmd((char_u *)
751 "command -nargs=* CompilerSet setlocal <args>");
752 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100753 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +0000754 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755
756 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +0100757 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100758 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 vim_free(buf);
760
761 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
762
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100763 // Set "b:current_compiler" from "current_compiler".
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100764 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 if (p != NULL)
766 set_internal_string_var((char_u *)"b:current_compiler", p);
767
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100768 // Restore "current_compiler" for ":compiler {name}".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 if (!eap->forceit)
770 {
771 if (old_cur_comp != NULL)
772 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100773 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 old_cur_comp);
775 vim_free(old_cur_comp);
776 }
777 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +0100778 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 }
780 }
781 }
782}
783#endif
784
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100785#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
786
787# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
788/*
789 * Detect Python 3 or 2, and initialize 'pyxversion'.
790 */
791 void
792init_pyxversion(void)
793{
794 if (p_pyx == 0)
795 {
796 if (python3_enabled(FALSE))
797 p_pyx = 3;
798 else if (python_enabled(FALSE))
799 p_pyx = 2;
800 }
801}
802# endif
803
804/*
805 * Does a file contain one of the following strings at the beginning of any
806 * line?
807 * "#!(any string)python2" => returns 2
808 * "#!(any string)python3" => returns 3
809 * "# requires python 2.x" => returns 2
810 * "# requires python 3.x" => returns 3
811 * otherwise return 0.
812 */
813 static int
814requires_py_version(char_u *filename)
815{
816 FILE *file;
817 int requires_py_version = 0;
818 int i, lines;
819
820 lines = (int)p_mls;
821 if (lines < 0)
822 lines = 5;
823
824 file = mch_fopen((char *)filename, "r");
825 if (file != NULL)
826 {
827 for (i = 0; i < lines; i++)
828 {
829 if (vim_fgets(IObuff, IOSIZE, file))
830 break;
831 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
832 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100833 // Check shebang.
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100834 if (strstr((char *)IObuff + 2, "python2") != NULL)
835 {
836 requires_py_version = 2;
837 break;
838 }
839 if (strstr((char *)IObuff + 2, "python3") != NULL)
840 {
841 requires_py_version = 3;
842 break;
843 }
844 }
845 IObuff[21] = '\0';
846 if (STRCMP("# requires python 2.x", IObuff) == 0)
847 {
848 requires_py_version = 2;
849 break;
850 }
851 if (STRCMP("# requires python 3.x", IObuff) == 0)
852 {
853 requires_py_version = 3;
854 break;
855 }
856 }
857 fclose(file);
858 }
859 return requires_py_version;
860}
861
862
863/*
864 * Source a python file using the requested python version.
865 */
866 static void
867source_pyx_file(exarg_T *eap, char_u *fname)
868{
869 exarg_T ex;
870 int v = requires_py_version(fname);
871
872# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
873 init_pyxversion();
874# endif
875 if (v == 0)
876 {
877# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100878 // user didn't choose a preference, 'pyx' is used
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100879 v = p_pyx;
880# elif defined(FEAT_PYTHON)
881 v = 2;
882# elif defined(FEAT_PYTHON3)
883 v = 3;
884# endif
885 }
886
887 /*
888 * now source, if required python version is not supported show
889 * unobtrusive message.
890 */
891 if (eap == NULL)
892 vim_memset(&ex, 0, sizeof(ex));
893 else
894 ex = *eap;
895 ex.arg = fname;
896 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
897
898 if (v == 2)
899 {
900# ifdef FEAT_PYTHON
901 ex_pyfile(&ex);
902# else
903 vim_snprintf((char *)IObuff, IOSIZE,
904 _("W20: Required python version 2.x not supported, ignoring file: %s"),
905 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +0100906 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100907# endif
908 return;
909 }
910 else
911 {
912# ifdef FEAT_PYTHON3
913 ex_py3file(&ex);
914# else
915 vim_snprintf((char *)IObuff, IOSIZE,
916 _("W21: Required python version 3.x not supported, ignoring file: %s"),
917 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +0100918 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100919# endif
920 return;
921 }
922}
923
924/*
925 * ":pyxfile {fname}"
926 */
927 void
928ex_pyxfile(exarg_T *eap)
929{
930 source_pyx_file(eap, eap->arg);
931}
932
933/*
934 * ":pyx"
935 */
936 void
937ex_pyx(exarg_T *eap)
938{
939# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
940 init_pyxversion();
941 if (p_pyx == 2)
942 ex_python(eap);
943 else
944 ex_py3(eap);
945# elif defined(FEAT_PYTHON)
946 ex_python(eap);
947# elif defined(FEAT_PYTHON3)
948 ex_py3(eap);
949# endif
950}
951
952/*
953 * ":pyxdo"
954 */
955 void
956ex_pyxdo(exarg_T *eap)
957{
958# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
959 init_pyxversion();
960 if (p_pyx == 2)
961 ex_pydo(eap);
962 else
963 ex_py3do(eap);
964# elif defined(FEAT_PYTHON)
965 ex_pydo(eap);
966# elif defined(FEAT_PYTHON3)
967 ex_py3do(eap);
968# endif
969}
970
971#endif
972
Bram Moolenaar071d4272004-06-13 20:20:40 +0000973/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000974 * ":checktime [buffer]"
975 */
976 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100977ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000978{
979 buf_T *buf;
980 int save_no_check_timestamps = no_check_timestamps;
981
982 no_check_timestamps = 0;
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100983 if (eap->addr_count == 0) // default is all buffers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000984 check_timestamps(FALSE);
985 else
986 {
987 buf = buflist_findnr((int)eap->line2);
Bram Moolenaar217e1b82019-12-01 21:41:28 +0100988 if (buf != NULL) // cannot happen?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000989 (void)buf_check_timestamp(buf, FALSE);
990 }
991 no_check_timestamps = save_no_check_timestamps;
992}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000993
Bram Moolenaar071d4272004-06-13 20:20:40 +0000994#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
995 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +0200996# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +0100997 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100998get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001000 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001002 // Obtain the locale value from the libraries.
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001003 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001004
Bram Moolenaar4f974752019-02-17 17:44:42 +01001005# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001006 if (loc != NULL)
1007 {
1008 char_u *p;
1009
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001010 // setocale() returns something like "LC_COLLATE=<name>;LC_..." when
1011 // one of the values (e.g., LC_CTYPE) differs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001012 p = vim_strchr(loc, '=');
1013 if (p != NULL)
1014 {
1015 loc = ++p;
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001016 while (*p != NUL) // remove trailing newline
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001018 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001019 {
1020 *p = NUL;
1021 break;
1022 }
1023 ++p;
1024 }
1025 }
1026 }
1027# endif
1028
1029 return loc;
1030}
1031#endif
1032
1033
Bram Moolenaar4f974752019-02-17 17:44:42 +01001034#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035/*
1036 * On MS-Windows locale names are strings like "German_Germany.1252", but
1037 * gettext expects "de". Try to translate one into another here for a few
1038 * supported languages.
1039 */
1040 static char_u *
1041gettext_lang(char_u *name)
1042{
1043 int i;
1044 static char *(mtable[]) = {
1045 "afrikaans", "af",
1046 "czech", "cs",
1047 "dutch", "nl",
1048 "german", "de",
1049 "english_united kingdom", "en_GB",
1050 "spanish", "es",
1051 "french", "fr",
1052 "italian", "it",
1053 "japanese", "ja",
1054 "korean", "ko",
1055 "norwegian", "no",
1056 "polish", "pl",
1057 "russian", "ru",
1058 "slovak", "sk",
1059 "swedish", "sv",
1060 "ukrainian", "uk",
1061 "chinese_china", "zh_CN",
1062 "chinese_taiwan", "zh_TW",
1063 NULL};
1064
1065 for (i = 0; mtable[i] != NULL; i += 2)
1066 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001067 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068 return name;
1069}
1070#endif
1071
1072#if defined(FEAT_MULTI_LANG) || defined(PROTO)
1073/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01001074 * Return TRUE when "lang" starts with a valid language name.
1075 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
1076 */
1077 static int
1078is_valid_mess_lang(char_u *lang)
1079{
1080 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
1081}
1082
1083/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001084 * Obtain the current messages language. Used to set the default for
1085 * 'helplang'. May return NULL or an empty string.
1086 */
1087 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001088get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001089{
1090 char_u *p;
1091
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001092# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001094 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095# else
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001096 // This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
1097 // may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
1098 // and LC_MONETARY may be set differently for a Japanese working in the
1099 // US.
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001100 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101# endif
1102# else
1103 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01001104 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105 {
1106 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01001107 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001108 p = mch_getenv((char_u *)"LANG");
1109 }
1110# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01001111# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 p = gettext_lang(p);
1113# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01001114 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001115}
1116#endif
1117
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001118// Complicated #if; matches with where get_mess_env() is used below.
Bram Moolenaardef9e822004-12-31 20:58:58 +00001119#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
1120 && defined(LC_MESSAGES))) \
1121 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00001122 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001123/*
1124 * Get the language used for messages from the environment.
1125 */
1126 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001127get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128{
1129 char_u *p;
1130
1131 p = mch_getenv((char_u *)"LC_ALL");
1132 if (p == NULL || *p == NUL)
1133 {
1134 p = mch_getenv((char_u *)"LC_MESSAGES");
1135 if (p == NULL || *p == NUL)
1136 {
1137 p = mch_getenv((char_u *)"LANG");
1138 if (p != NULL && VIM_ISDIGIT(*p))
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001139 p = NULL; // ignore something like "1043"
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001140# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001142 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143# endif
1144 }
1145 }
1146 return p;
1147}
1148#endif
1149
1150#if defined(FEAT_EVAL) || defined(PROTO)
1151
1152/*
1153 * Set the "v:lang" variable according to the current locale setting.
1154 * Also do "v:lc_time"and "v:ctype".
1155 */
1156 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001157set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158{
1159 char_u *loc;
1160
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001161# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001162 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163# else
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001164 // setlocale() not supported: use the default value
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 loc = (char_u *)"C";
1166# endif
1167 set_vim_var_string(VV_CTYPE, loc, -1);
1168
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001169 // When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
1170 // back to LC_CTYPE if it's empty.
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001171# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001172 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173# else
1174 loc = get_mess_env();
1175# endif
1176 set_vim_var_string(VV_LANG, loc, -1);
1177
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001178# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001179 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001180# endif
1181 set_vim_var_string(VV_LC_TIME, loc, -1);
1182}
1183#endif
1184
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01001185#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186/*
1187 * ":language": Set the language (locale).
1188 */
1189 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001190ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001191{
1192 char *loc;
1193 char_u *p;
1194 char_u *name;
1195 int what = LC_ALL;
1196 char *whatstr = "";
1197#ifdef LC_MESSAGES
1198# define VIM_LC_MESSAGES LC_MESSAGES
1199#else
1200# define VIM_LC_MESSAGES 6789
1201#endif
1202
1203 name = eap->arg;
1204
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001205 // Check for "messages {name}", "ctype {name}" or "time {name}" argument.
1206 // Allow abbreviation, but require at least 3 characters to avoid
1207 // confusion with a two letter language name "me" or "ct".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01001209 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210 {
1211 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
1212 {
1213 what = VIM_LC_MESSAGES;
1214 name = skipwhite(p);
1215 whatstr = "messages ";
1216 }
1217 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
1218 {
1219 what = LC_CTYPE;
1220 name = skipwhite(p);
1221 whatstr = "ctype ";
1222 }
1223 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
1224 {
1225 what = LC_TIME;
1226 name = skipwhite(p);
1227 whatstr = "time ";
1228 }
1229 }
1230
1231 if (*name == NUL)
1232 {
1233#ifndef LC_MESSAGES
1234 if (what == VIM_LC_MESSAGES)
1235 p = get_mess_env();
1236 else
1237#endif
1238 p = (char_u *)setlocale(what, NULL);
1239 if (p == NULL || *p == NUL)
1240 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001241 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242 }
1243 else
1244 {
1245#ifndef LC_MESSAGES
1246 if (what == VIM_LC_MESSAGES)
1247 loc = "";
1248 else
1249#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001250 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001252#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001253 // Make sure strtod() uses a decimal point, not a comma.
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001254 setlocale(LC_NUMERIC, "C");
1255#endif
1256 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001258 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259 else
1260 {
1261#ifdef HAVE_NL_MSG_CAT_CNTR
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001262 // Need to do this for GNU gettext, otherwise cached translations
1263 // will be used again.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264 extern int _nl_msg_cat_cntr;
1265
1266 ++_nl_msg_cat_cntr;
1267#endif
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001268 // Reset $LC_ALL, otherwise it would overrule everything.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
1270
1271 if (what != LC_TIME)
1272 {
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001273 // Tell gettext() what to translate to. It apparently doesn't
1274 // use the currently effective locale. Also do this when
1275 // FEAT_GETTEXT isn't defined, so that shell commands use this
1276 // value.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001277 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00001278 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001279 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02001280
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001281 // Clear $LANGUAGE because GNU gettext uses it.
Bram Moolenaare3a0b532013-06-28 20:36:30 +02001282 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01001283# ifdef MSWIN
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001284 // Apparently MS-Windows printf() may cause a crash when
1285 // we give it 8-bit text while it's expecting text in the
1286 // current locale. This call avoids that.
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00001287 setlocale(LC_CTYPE, "C");
1288# endif
1289 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001290 if (what != LC_CTYPE)
1291 {
1292 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01001293#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294 mname = gettext_lang(name);
1295#else
1296 mname = name;
1297#endif
1298 vim_setenv((char_u *)"LC_MESSAGES", mname);
1299#ifdef FEAT_MULTI_LANG
1300 set_helplang_default(mname);
1301#endif
1302 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001303 }
1304
1305# ifdef FEAT_EVAL
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001306 // Set v:lang, v:lc_time and v:ctype to the final result.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307 set_lang_var();
1308# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02001309# ifdef FEAT_TITLE
1310 maketitle();
1311# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001312 }
1313 }
1314}
1315
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001316static char_u **locales = NULL; // Array of all available locales
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001317
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001318# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001319static int did_init_locales = FALSE;
1320
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001321/*
1322 * Return an array of strings for all available locales + NULL for the
1323 * last element. Return NULL in case of error.
1324 */
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001325 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001326find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001327{
1328 garray_T locales_ga;
1329 char_u *loc;
1330
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001331 // Find all available locales by running command "locale -a". If this
1332 // doesn't work we won't have completion.
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001333 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02001334 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001335 if (locale_a == NULL)
1336 return NULL;
1337 ga_init2(&locales_ga, sizeof(char_u *), 20);
1338
Bram Moolenaar217e1b82019-12-01 21:41:28 +01001339 // Transform locale_a string where each locale is separated by "\n"
1340 // into an array of locale strings.
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001341 loc = (char_u *)strtok((char *)locale_a, "\n");
1342
1343 while (loc != NULL)
1344 {
1345 if (ga_grow(&locales_ga, 1) == FAIL)
1346 break;
1347 loc = vim_strsave(loc);
1348 if (loc == NULL)
1349 break;
1350
1351 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
1352 loc = (char_u *)strtok(NULL, "\n");
1353 }
1354 vim_free(locale_a);
1355 if (ga_grow(&locales_ga, 1) == FAIL)
1356 {
1357 ga_clear(&locales_ga);
1358 return NULL;
1359 }
1360 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
1361 return (char_u **)locales_ga.ga_data;
1362}
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001363# endif
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001364
1365/*
1366 * Lazy initialization of all available locales.
1367 */
1368 static void
1369init_locales(void)
1370{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001371# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001372 if (!did_init_locales)
1373 {
1374 did_init_locales = TRUE;
1375 locales = find_locales();
1376 }
1377# endif
1378}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001379
1380# if defined(EXITFREE) || defined(PROTO)
1381 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001382free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001383{
1384 int i;
1385 if (locales != NULL)
1386 {
1387 for (i = 0; locales[i] != NULL; i++)
1388 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01001389 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001390 }
1391}
1392# endif
1393
Bram Moolenaar071d4272004-06-13 20:20:40 +00001394/*
1395 * Function given to ExpandGeneric() to obtain the possible arguments of the
1396 * ":language" command.
1397 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001399get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001400{
1401 if (idx == 0)
1402 return (char_u *)"messages";
1403 if (idx == 1)
1404 return (char_u *)"ctype";
1405 if (idx == 2)
1406 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001407
1408 init_locales();
1409 if (locales == NULL)
1410 return NULL;
1411 return locales[idx - 3];
1412}
1413
1414/*
1415 * Function given to ExpandGeneric() to obtain the available locales.
1416 */
1417 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001418get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001419{
1420 init_locales();
1421 if (locales == NULL)
1422 return NULL;
1423 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001424}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425
1426#endif