blob: 81f2c8f5b99dac8ac19955e48ad2c8dfbf27fd49 [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#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar975b5272016-03-15 23:10:59 +010018# if defined(FEAT_TIMERS) || defined(PROTO)
19static timer_T *first_timer = NULL;
Bram Moolenaar75537a92016-09-05 22:45:28 +020020static long last_timer_id = 0;
Bram Moolenaar975b5272016-03-15 23:10:59 +010021
Bram Moolenaar2f106582019-05-08 21:59:25 +020022/*
23 * Return time left until "due". Negative if past "due".
24 */
Bram Moolenaar56bc8e22018-05-10 18:05:56 +020025 long
Bram Moolenaar51b0f372017-11-18 18:52:04 +010026proftime_time_left(proftime_T *due, proftime_T *now)
Bram Moolenaara8e93d62017-09-18 21:50:47 +020027{
Bram Moolenaar4f974752019-02-17 17:44:42 +010028# ifdef MSWIN
Bram Moolenaara8e93d62017-09-18 21:50:47 +020029 LARGE_INTEGER fr;
30
Bram Moolenaar51b0f372017-11-18 18:52:04 +010031 if (now->QuadPart > due->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +020032 return 0;
33 QueryPerformanceFrequency(&fr);
Bram Moolenaar51b0f372017-11-18 18:52:04 +010034 return (long)(((double)(due->QuadPart - now->QuadPart)
Bram Moolenaara8e93d62017-09-18 21:50:47 +020035 / (double)fr.QuadPart) * 1000);
36# else
Bram Moolenaar51b0f372017-11-18 18:52:04 +010037 if (now->tv_sec > due->tv_sec)
Bram Moolenaara8e93d62017-09-18 21:50:47 +020038 return 0;
Bram Moolenaar51b0f372017-11-18 18:52:04 +010039 return (due->tv_sec - now->tv_sec) * 1000
40 + (due->tv_usec - now->tv_usec) / 1000;
Bram Moolenaara8e93d62017-09-18 21:50:47 +020041# endif
42}
Bram Moolenaar417ccd72016-09-01 21:26:20 +020043
Bram Moolenaar975b5272016-03-15 23:10:59 +010044/*
45 * Insert a timer in the list of timers.
46 */
47 static void
48insert_timer(timer_T *timer)
49{
50 timer->tr_next = first_timer;
51 timer->tr_prev = NULL;
52 if (first_timer != NULL)
53 first_timer->tr_prev = timer;
54 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +020055 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +010056}
57
58/*
59 * Take a timer out of the list of timers.
60 */
61 static void
62remove_timer(timer_T *timer)
63{
64 if (timer->tr_prev == NULL)
65 first_timer = timer->tr_next;
66 else
67 timer->tr_prev->tr_next = timer->tr_next;
68 if (timer->tr_next != NULL)
69 timer->tr_next->tr_prev = timer->tr_prev;
70}
71
72 static void
73free_timer(timer_T *timer)
74{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020075 free_callback(&timer->tr_callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020076 vim_free(timer);
Bram Moolenaar975b5272016-03-15 23:10:59 +010077}
78
79/*
80 * Create a timer and return it. NULL if out of memory.
81 * Caller should set the callback.
82 */
83 timer_T *
84create_timer(long msec, int repeat)
85{
Bram Moolenaarc799fe22019-05-28 23:08:19 +020086 timer_T *timer = ALLOC_CLEAR_ONE(timer_T);
Bram Moolenaaree39ef02016-09-10 19:17:42 +020087 long prev_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +010088
89 if (timer == NULL)
90 return NULL;
Bram Moolenaaree39ef02016-09-10 19:17:42 +020091 if (++last_timer_id <= prev_id)
Bram Moolenaar75537a92016-09-05 22:45:28 +020092 /* Overflow! Might cause duplicates... */
93 last_timer_id = 0;
94 timer->tr_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +010095 insert_timer(timer);
96 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +010097 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020098 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +010099
100 profile_setlimit(msec, &timer->tr_due);
101 return timer;
102}
103
104/*
105 * Invoke the callback of "timer".
106 */
107 static void
108timer_callback(timer_T *timer)
109{
110 typval_T rettv;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100111 typval_T argv[2];
112
113 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200114 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100115 argv[1].v_type = VAR_UNKNOWN;
116
Bram Moolenaarc6538bc2019-08-03 18:17:11 +0200117 call_callback(&timer->tr_callback, -1, &rettv, 1, argv);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100118 clear_tv(&rettv);
119}
120
121/*
122 * Call timers that are due.
123 * Return the time in msec until the next timer is due.
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200124 * Returns -1 if there are no pending timers.
Bram Moolenaar975b5272016-03-15 23:10:59 +0100125 */
126 long
Bram Moolenaarcf089462016-06-12 21:18:43 +0200127check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100128{
129 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200130 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100131 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +0100132 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100133 proftime_T now;
134 int did_one = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200135 int need_update_screen = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200136 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100137
Bram Moolenaarc577d812017-07-08 22:37:34 +0200138 /* Don't run any timers while exiting or dealing with an error. */
139 if (exiting || aborting())
Bram Moolenaarc4f83382017-07-07 14:50:44 +0200140 return next_due;
141
Bram Moolenaar75537a92016-09-05 22:45:28 +0200142 profile_start(&now);
143 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100144 {
Bram Moolenaar75537a92016-09-05 22:45:28 +0200145 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +0200146
Bram Moolenaar75537a92016-09-05 22:45:28 +0200147 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
148 continue;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100149 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200150 if (this_due <= 1)
151 {
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200152 /* Save and restore a lot of flags, because the timer fires while
153 * waiting for a character, which might be halfway a command. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200154 int save_timer_busy = timer_busy;
155 int save_vgetc_busy = vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200156 int save_did_emsg = did_emsg;
157 int save_called_emsg = called_emsg;
Bram Moolenaar7d491c42019-06-25 06:28:02 +0200158 int save_must_redraw = must_redraw;
159 int save_trylevel = trylevel;
Bram Moolenaare723c422017-09-06 23:40:10 +0200160 int save_did_throw = did_throw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200161 int save_ex_pressedreturn = get_pressedreturn();
Bram Moolenaare96a2492019-06-25 04:12:16 +0200162 int save_may_garbage_collect = may_garbage_collect;
Bram Moolenaare723c422017-09-06 23:40:10 +0200163 except_T *save_current_exception = current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200164 vimvars_save_T vvsave;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200165
Bram Moolenaare723c422017-09-06 23:40:10 +0200166 /* Create a scope for running the timer callback, ignoring most of
167 * the current scope, such as being inside a try/catch. */
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200168 timer_busy = timer_busy > 0 || vgetc_busy > 0;
169 vgetc_busy = 0;
Bram Moolenaarc577d812017-07-08 22:37:34 +0200170 called_emsg = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200171 did_emsg = FALSE;
172 did_uncaught_emsg = FALSE;
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200173 must_redraw = 0;
Bram Moolenaare723c422017-09-06 23:40:10 +0200174 trylevel = 0;
175 did_throw = FALSE;
176 current_exception = NULL;
Bram Moolenaare96a2492019-06-25 04:12:16 +0200177 may_garbage_collect = FALSE;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200178 save_vimvars(&vvsave);
Bram Moolenaare96a2492019-06-25 04:12:16 +0200179
Bram Moolenaar75537a92016-09-05 22:45:28 +0200180 timer->tr_firing = TRUE;
181 timer_callback(timer);
182 timer->tr_firing = FALSE;
Bram Moolenaare723c422017-09-06 23:40:10 +0200183
Bram Moolenaar75537a92016-09-05 22:45:28 +0200184 timer_next = timer->tr_next;
185 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +0200186 timer_busy = save_timer_busy;
187 vgetc_busy = save_vgetc_busy;
Bram Moolenaare723c422017-09-06 23:40:10 +0200188 if (did_uncaught_emsg)
Bram Moolenaarc577d812017-07-08 22:37:34 +0200189 ++timer->tr_emsg_count;
Bram Moolenaare723c422017-09-06 23:40:10 +0200190 did_emsg = save_did_emsg;
191 called_emsg = save_called_emsg;
192 trylevel = save_trylevel;
193 did_throw = save_did_throw;
194 current_exception = save_current_exception;
Bram Moolenaarb0f42ba2018-05-12 15:38:26 +0200195 restore_vimvars(&vvsave);
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200196 if (must_redraw != 0)
197 need_update_screen = TRUE;
198 must_redraw = must_redraw > save_must_redraw
199 ? must_redraw : save_must_redraw;
Bram Moolenaarf5291f32017-09-14 22:55:37 +0200200 set_pressedreturn(save_ex_pressedreturn);
Bram Moolenaare96a2492019-06-25 04:12:16 +0200201 may_garbage_collect = save_may_garbage_collect;
Bram Moolenaar75537a92016-09-05 22:45:28 +0200202
203 /* Only fire the timer again if it repeats and stop_timer() wasn't
204 * called while inside the callback (tr_id == -1). */
Bram Moolenaarc577d812017-07-08 22:37:34 +0200205 if (timer->tr_repeat != 0 && timer->tr_id != -1
206 && timer->tr_emsg_count < 3)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200207 {
208 profile_setlimit(timer->tr_interval, &timer->tr_due);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100209 this_due = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaar75537a92016-09-05 22:45:28 +0200210 if (this_due < 1)
211 this_due = 1;
212 if (timer->tr_repeat > 0)
213 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100214 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200215 else
216 {
217 this_due = -1;
218 remove_timer(timer);
219 free_timer(timer);
220 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100221 }
Bram Moolenaar75537a92016-09-05 22:45:28 +0200222 if (this_due > 0 && (next_due == -1 || next_due > this_due))
223 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100224 }
225
226 if (did_one)
Bram Moolenaar02e177d2017-08-26 23:43:28 +0200227 redraw_after_callback(need_update_screen);
Bram Moolenaar975b5272016-03-15 23:10:59 +0100228
Bram Moolenaarc3719bd2017-11-18 22:13:31 +0100229#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100230 if (bevalexpr_due_set)
231 {
232 this_due = proftime_time_left(&bevalexpr_due, &now);
233 if (this_due <= 1)
234 {
235 bevalexpr_due_set = FALSE;
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100236 if (balloonEval == NULL)
237 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200238 balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100239 balloonEvalForTerm = TRUE;
240 }
241 if (balloonEval != NULL)
Bram Moolenaar2f106582019-05-08 21:59:25 +0200242 {
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100243 general_beval_cb(balloonEval, 0);
Bram Moolenaar2f106582019-05-08 21:59:25 +0200244 setcursor();
245 out_flush();
246 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100247 }
Bram Moolenaar1c17ffa2018-04-24 15:19:04 +0200248 else if (next_due == -1 || next_due > this_due)
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100249 next_due = this_due;
250 }
251#endif
Bram Moolenaar56bc8e22018-05-10 18:05:56 +0200252#ifdef FEAT_TERMINAL
253 /* Some terminal windows may need their buffer updated. */
254 next_due = term_check_timers(next_due, &now);
255#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100256
Bram Moolenaar75537a92016-09-05 22:45:28 +0200257 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100258}
259
260/*
261 * Find a timer by ID. Returns NULL if not found;
262 */
Bram Moolenaar840d16f2019-09-10 21:27:18 +0200263 static timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +0200264find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +0100265{
266 timer_T *timer;
267
Bram Moolenaar75537a92016-09-05 22:45:28 +0200268 if (id >= 0)
269 {
270 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
271 if (timer->tr_id == id)
272 return timer;
273 }
274 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +0100275}
276
277
278/*
279 * Stop a timer and delete it.
280 */
281 void
282stop_timer(timer_T *timer)
283{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200284 if (timer->tr_firing)
285 /* Free the timer after the callback returns. */
286 timer->tr_id = -1;
287 else
288 {
289 remove_timer(timer);
290 free_timer(timer);
291 }
Bram Moolenaar975b5272016-03-15 23:10:59 +0100292}
Bram Moolenaare3188e22016-05-31 21:13:04 +0200293
Bram Moolenaar840d16f2019-09-10 21:27:18 +0200294 static void
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200295stop_all_timers(void)
296{
Bram Moolenaar75537a92016-09-05 22:45:28 +0200297 timer_T *timer;
298 timer_T *timer_next;
299
300 for (timer = first_timer; timer != NULL; timer = timer_next)
301 {
302 timer_next = timer->tr_next;
303 stop_timer(timer);
304 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200305}
306
Bram Moolenaar840d16f2019-09-10 21:27:18 +0200307 static void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200308add_timer_info(typval_T *rettv, timer_T *timer)
309{
310 list_T *list = rettv->vval.v_list;
311 dict_T *dict = dict_alloc();
312 dictitem_T *di;
313 long remaining;
314 proftime_T now;
315
316 if (dict == NULL)
317 return;
318 list_append_dict(list, dict);
319
Bram Moolenaare0be1672018-07-08 16:50:37 +0200320 dict_add_number(dict, "id", timer->tr_id);
321 dict_add_number(dict, "time", (long)timer->tr_interval);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200322
323 profile_start(&now);
Bram Moolenaar51b0f372017-11-18 18:52:04 +0100324 remaining = proftime_time_left(&timer->tr_due, &now);
Bram Moolenaare0be1672018-07-08 16:50:37 +0200325 dict_add_number(dict, "remaining", (long)remaining);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200326
Bram Moolenaare0be1672018-07-08 16:50:37 +0200327 dict_add_number(dict, "repeat",
328 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
329 dict_add_number(dict, "paused", (long)(timer->tr_paused));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200330
331 di = dictitem_alloc((char_u *)"callback");
332 if (di != NULL)
333 {
334 if (dict_add(dict, di) == FAIL)
335 vim_free(di);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200336 else
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200337 put_callback(&timer->tr_callback, &di->di_tv);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200338 }
339}
340
Bram Moolenaar840d16f2019-09-10 21:27:18 +0200341 static void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200342add_timer_info_all(typval_T *rettv)
343{
344 timer_T *timer;
345
346 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +0200347 if (timer->tr_id != -1)
348 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200349}
350
Bram Moolenaare3188e22016-05-31 21:13:04 +0200351/*
352 * Mark references in partials of timers.
353 */
354 int
355set_ref_in_timer(int copyID)
356{
357 int abort = FALSE;
358 timer_T *timer;
359 typval_T tv;
360
Bram Moolenaar75a1a942019-06-20 03:45:36 +0200361 for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
Bram Moolenaare3188e22016-05-31 21:13:04 +0200362 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200363 if (timer->tr_callback.cb_partial != NULL)
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200364 {
365 tv.v_type = VAR_PARTIAL;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200366 tv.vval.v_partial = timer->tr_callback.cb_partial;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200367 }
368 else
369 {
370 tv.v_type = VAR_FUNC;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +0200371 tv.vval.v_string = timer->tr_callback.cb_name;
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +0200372 }
Bram Moolenaare3188e22016-05-31 21:13:04 +0200373 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
374 }
375 return abort;
376}
Bram Moolenaar623e2632016-07-30 22:47:56 +0200377
Bram Moolenaaraf7645d2019-09-05 22:33:28 +0200378# if defined(EXITFREE) || defined(PROTO)
Bram Moolenaar623e2632016-07-30 22:47:56 +0200379 void
380timer_free_all()
381{
382 timer_T *timer;
383
384 while (first_timer != NULL)
385 {
386 timer = first_timer;
387 remove_timer(timer);
388 free_timer(timer);
389 }
390}
Bram Moolenaar975b5272016-03-15 23:10:59 +0100391# endif
392
Bram Moolenaaraf7645d2019-09-05 22:33:28 +0200393/*
394 * "timer_info([timer])" function
395 */
396 void
397f_timer_info(typval_T *argvars, typval_T *rettv)
398{
399 timer_T *timer = NULL;
400
401 if (rettv_list_alloc(rettv) != OK)
402 return;
403 if (argvars[0].v_type != VAR_UNKNOWN)
404 {
405 if (argvars[0].v_type != VAR_NUMBER)
406 emsg(_(e_number_exp));
407 else
408 {
409 timer = find_timer((int)tv_get_number(&argvars[0]));
410 if (timer != NULL)
411 add_timer_info(rettv, timer);
412 }
413 }
414 else
415 add_timer_info_all(rettv);
416}
417
418/*
419 * "timer_pause(timer, paused)" function
420 */
421 void
422f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
423{
424 timer_T *timer = NULL;
425 int paused = (int)tv_get_number(&argvars[1]);
426
427 if (argvars[0].v_type != VAR_NUMBER)
428 emsg(_(e_number_exp));
429 else
430 {
431 timer = find_timer((int)tv_get_number(&argvars[0]));
432 if (timer != NULL)
433 timer->tr_paused = paused;
434 }
435}
436
437/*
438 * "timer_start(time, callback [, options])" function
439 */
440 void
441f_timer_start(typval_T *argvars, typval_T *rettv)
442{
443 long msec = (long)tv_get_number(&argvars[0]);
444 timer_T *timer;
445 int repeat = 0;
446 callback_T callback;
447 dict_T *dict;
448
449 rettv->vval.v_number = -1;
450 if (check_secure())
451 return;
452 if (argvars[2].v_type != VAR_UNKNOWN)
453 {
454 if (argvars[2].v_type != VAR_DICT
455 || (dict = argvars[2].vval.v_dict) == NULL)
456 {
457 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
458 return;
459 }
460 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
461 repeat = dict_get_number(dict, (char_u *)"repeat");
462 }
463
464 callback = get_callback(&argvars[1]);
465 if (callback.cb_name == NULL)
466 return;
467
468 timer = create_timer(msec, repeat);
469 if (timer == NULL)
470 free_callback(&callback);
471 else
472 {
473 set_callback(&timer->tr_callback, &callback);
474 rettv->vval.v_number = (varnumber_T)timer->tr_id;
475 }
476}
477
478/*
479 * "timer_stop(timer)" function
480 */
481 void
482f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
483{
484 timer_T *timer;
485
486 if (argvars[0].v_type != VAR_NUMBER)
487 {
488 emsg(_(e_number_exp));
489 return;
490 }
491 timer = find_timer((int)tv_get_number(&argvars[0]));
492 if (timer != NULL)
493 stop_timer(timer);
494}
495
496/*
497 * "timer_stopall()" function
498 */
499 void
500f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
501{
502 stop_all_timers();
503}
504
505# endif // FEAT_TIMERS
506
507#endif // FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508
509/*
510 * If 'autowrite' option set, try to write the file.
511 * Careful: autocommands may make "buf" invalid!
512 *
513 * return FAIL for failure, OK otherwise
514 */
515 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100516autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517{
Bram Moolenaar373154b2007-02-13 05:19:30 +0000518 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200519 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +0000520
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 if (!(p_aw || p_awa) || !p_write
522#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +0000523 /* never autowrite a "nofile" or "nowrite" buffer */
524 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000525#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +0000526 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000527 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200528 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +0000529 r = buf_write_all(buf, forceit);
530
531 /* Writing may succeed but the buffer still changed, e.g., when there is a
532 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200533 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +0000534 r = FAIL;
535 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536}
537
538/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +0200539 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540 */
541 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100542autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543{
544 buf_T *buf;
545
546 if (!(p_aw || p_awa) || !p_write)
547 return;
Bram Moolenaar29323592016-07-24 22:04:11 +0200548 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +0200549 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200551 bufref_T bufref;
552
553 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100554
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100556
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200558 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000559 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560 }
561}
562
563/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100564 * Return TRUE if buffer was changed and cannot be abandoned.
565 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100568check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000569{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200570 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200571 bufref_T bufref;
572
573 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100574
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575 if ( !forceit
576 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100577 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
578 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 {
580#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
581 if ((p_confirm || cmdmod.confirm) && p_write)
582 {
583 buf_T *buf2;
584 int count = 0;
585
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100586 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +0200587 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000588 if (bufIsChanged(buf2)
589 && (buf2->b_ffname != NULL
590# ifdef FEAT_BROWSE
591 || cmdmod.browse
592# endif
593 ))
594 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200595 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 /* Autocommand deleted buffer, oops! It's not changed now. */
597 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100598
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100600
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200601 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602 /* Autocommand deleted buffer, oops! It's not changed now. */
603 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000604 return bufIsChanged(buf);
605 }
606#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100607 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +0200608 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100609 else
Bram Moolenaar7a760922018-02-19 23:10:02 +0100610 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000611 return TRUE;
612 }
613 return FALSE;
614}
615
616#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
617
618#if defined(FEAT_BROWSE) || defined(PROTO)
619/*
620 * When wanting to write a file without a file name, ask the user for a name.
621 */
622 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100623browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624{
625 if (buf->b_fname == NULL)
626 {
627 char_u *fname;
628
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000629 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
630 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (fname != NULL)
632 {
633 if (setfname(buf, fname, NULL, TRUE) == OK)
634 buf->b_flags |= BF_NOTEDITED;
635 vim_free(fname);
636 }
637 }
638}
639#endif
640
641/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +0200642 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 * Must check 'write' option first!
644 */
645 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100646dialog_changed(
647 buf_T *buf,
648 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649{
Bram Moolenaard9462e32011-04-11 21:35:11 +0200650 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 int ret;
652 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +0200653 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +0200655 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656 if (checkall)
657 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
658 else
659 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
660
Bram Moolenaar4ca41532019-05-09 21:48:37 +0200661 // Init ea pseudo-structure, this is needed for the check_overwrite()
662 // function.
663 vim_memset(&ea, 0, sizeof(ea));
Bram Moolenaar8218f602012-04-25 17:32:18 +0200664
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665 if (ret == VIM_YES)
666 {
667#ifdef FEAT_BROWSE
668 /* May get file name, when there is none */
669 browse_save_fname(buf);
670#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200671 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
672 buf->b_fname, buf->b_ffname, FALSE) == OK)
673 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000674 (void)buf_write_all(buf, FALSE);
675 }
676 else if (ret == VIM_NO)
677 {
Bram Moolenaarc024b462019-06-08 18:07:21 +0200678 unchanged(buf, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679 }
680 else if (ret == VIM_ALL)
681 {
682 /*
683 * Write all modified files that can be written.
684 * Skip readonly buffers, these need to be confirmed
685 * individually.
686 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200687 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000688 {
689 if (bufIsChanged(buf2)
690 && (buf2->b_ffname != NULL
691#ifdef FEAT_BROWSE
692 || cmdmod.browse
693#endif
694 )
695 && !buf2->b_p_ro)
696 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200697 bufref_T bufref;
698
699 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700#ifdef FEAT_BROWSE
701 /* May get file name, when there is none */
702 browse_save_fname(buf2);
703#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200704 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
705 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
706 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000707 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100708
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200710 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000712 }
713 }
714 }
715 else if (ret == VIM_DISCARDALL)
716 {
717 /*
718 * mark all buffers as unchanged
719 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200720 FOR_ALL_BUFFERS(buf2)
Bram Moolenaarc024b462019-06-08 18:07:21 +0200721 unchanged(buf2, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000722 }
723}
724#endif
725
726/*
727 * Return TRUE if the buffer "buf" can be abandoned, either by making it
728 * hidden, autowriting it or unloading it.
729 */
730 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100731can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732{
Bram Moolenaareb44a682017-08-03 22:44:55 +0200733 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 || !bufIsChanged(buf)
735 || buf->b_nwindows > 1
736 || autowrite(buf, forceit) == OK
737 || forceit);
738}
739
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100740/*
741 * Add a buffer number to "bufnrs", unless it's already there.
742 */
743 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100744add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100745{
746 int i;
747
748 for (i = 0; i < *bufnump; ++i)
749 if (bufnrs[i] == nr)
750 return;
751 bufnrs[*bufnump] = nr;
752 *bufnump = *bufnump + 1;
753}
754
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755/*
756 * Return TRUE if any buffer was changed and cannot be abandoned.
757 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100758 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +0100759 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760 */
761 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100762check_changed_any(
763 int hidden, /* Only check hidden buffers */
764 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765{
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100766 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000767 buf_T *buf;
768 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100769 int i;
770 int bufnum = 0;
771 int bufcount = 0;
772 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100773 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100776 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +0200777 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100778 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100780 if (bufcount == 0)
781 return FALSE;
782
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200783 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100784 if (bufnrs == NULL)
785 return FALSE;
786
787 /* curbuf */
788 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100789
790 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100791 FOR_ALL_WINDOWS(wp)
792 if (wp->w_buffer != curbuf)
793 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
794
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100795 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +0200796 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100797 if (tp != curtab)
798 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
799 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100800
801 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +0200802 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100803 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
804
805 for (i = 0; i < bufnum; ++i)
806 {
807 buf = buflist_findnr(bufnrs[i]);
808 if (buf == NULL)
809 continue;
810 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
811 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200812 bufref_T bufref;
813
814 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100815#ifdef FEAT_TERMINAL
816 if (term_job_running(buf->b_term))
817 {
818 if (term_try_stop_job(buf) == FAIL)
819 break;
820 }
821 else
822#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100823 /* Try auto-writing the buffer. If this fails but the buffer no
Bram Moolenaar558ca4a2019-04-04 18:15:38 +0200824 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100825 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
826 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200827 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100828 break; /* didn't save - still changes */
829 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 }
831
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100832 if (i >= bufnum)
833 goto theend;
834
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100835 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100836 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 exiting = FALSE;
838#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
839 /*
840 * When ":confirm" used, don't give an error message.
841 */
842 if (!(p_confirm || cmdmod.confirm))
843#endif
844 {
845 /* There must be a wait_return for this message, do_buffer()
846 * may cause a redraw. But wait_return() is a no-op when vgetc()
847 * is busy (Quit used from window menu), then make sure we don't
848 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +0000849 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850 {
851 msg_row = cmdline_row;
852 msg_col = 0;
853 msg_didout = FALSE;
854 }
Bram Moolenaareb44a682017-08-03 22:44:55 +0200855 if (
856#ifdef FEAT_TERMINAL
857 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100858 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +0200859 buf->b_fname)
860 :
861#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100862 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +0200863 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864 {
865 save = no_wait_return;
866 no_wait_return = FALSE;
867 wait_return(FALSE);
868 no_wait_return = save;
869 }
870 }
871
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 /* Try to find a window that contains the buffer. */
873 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100874 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875 if (wp->w_buffer == buf)
876 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200877 bufref_T bufref;
878
879 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100880
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100881 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100882
Bram Moolenaarbdace832019-03-02 10:13:42 +0100883 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200884 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100885 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100886 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100888buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889
890 /* Open the changed buffer in the current window. */
891 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +0100892 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100894theend:
895 vim_free(bufnrs);
896 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897}
898
899/*
900 * return FAIL if there is no file name, OK if there is one
901 * give error message for FAIL
902 */
903 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100904check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905{
906 if (curbuf->b_ffname == NULL)
907 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100908 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 return FAIL;
910 }
911 return OK;
912}
913
914/*
915 * flush the contents of a buffer, unless it has no file name
916 *
917 * return FAIL for failure, OK otherwise
918 */
919 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100920buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000921{
922 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924
925 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
926 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
927 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000929 {
Bram Moolenaar8820b482017-03-16 17:23:31 +0100930 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +0100931 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000932 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933 return retval;
934}
935
936/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200937 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000938 */
939 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100940ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000941{
942 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000943 win_T *wp;
944 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +0100945 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100947#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000948 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000949#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000950 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200951#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +0200952 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200953 int qf_idx;
954#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000955
Bram Moolenaar0106e3d2016-02-23 18:55:43 +0100956#ifndef FEAT_QUICKFIX
957 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
958 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
959 {
960 ex_ni(eap);
961 return;
962 }
963#endif
964
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100965#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000966 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200967 {
Bram Moolenaardcaf10e2005-01-21 11:55:25 +0000968 /* Don't do syntax HL autocommands. Skipping the syntax file is a
969 * great speed improvement. */
970 save_ei = au_event_disable(",Syntax");
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200971
972 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
973 buf->b_flags &= ~BF_SYN_SET;
974 buf = curbuf;
975 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000976#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200977#ifdef FEAT_CLIPBOARD
978 start_global_changes();
979#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000980
981 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000982 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +0200983 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100984 || !check_changed(curbuf, CCGD_AW
985 | (eap->forceit ? CCGD_FORCEIT : 0)
986 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000987 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100989 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000990 wp = firstwin;
991 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100992 switch (eap->cmdidx)
993 {
Bram Moolenaara162bc52015-01-07 16:54:21 +0100994 case CMD_windo:
995 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
996 i++;
997 break;
998 case CMD_tabdo:
999 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
1000 i++;
1001 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001002 case CMD_argdo:
1003 i = eap->line1 - 1;
1004 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001005 default:
1006 break;
1007 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008 /* set pcmark now */
1009 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001010 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01001011 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001012 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01001013 || !buf->b_p_bl); buf = buf->b_next)
1014 if (buf->b_fnum > eap->line2)
1015 {
1016 buf = NULL;
1017 break;
1018 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001019 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01001020 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001021 }
1022#ifdef FEAT_QUICKFIX
1023 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1024 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1025 {
Bram Moolenaar25190db2019-05-04 15:05:28 +02001026 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001027 if (qf_size <= 0 || eap->line1 > qf_size)
1028 buf = NULL;
1029 else
1030 {
1031 ex_cc(eap);
1032
1033 buf = curbuf;
1034 i = eap->line1 - 1;
1035 if (eap->addr_count <= 0)
1036 /* default is all the quickfix/location list entries */
1037 eap->line2 = qf_size;
1038 }
1039 }
1040#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001041 else
1042 setpcmark();
1043 listcmd_busy = TRUE; /* avoids setting pcmark below */
1044
Bram Moolenaare25bb902015-02-27 20:33:37 +01001045 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 {
1047 if (eap->cmdidx == CMD_argdo)
1048 {
1049 /* go to argument "i" */
1050 if (i == ARGCOUNT)
1051 break;
1052 /* Don't call do_argfile() when already there, it will try
1053 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00001054 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001055 {
1056 /* Clear 'shm' to avoid that the file message overwrites
1057 * any output from the command. */
1058 p_shm_save = vim_strsave(p_shm);
1059 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001060 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001061 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1062 vim_free(p_shm_save);
1063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064 if (curwin->w_arg_idx != i)
1065 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001067 else if (eap->cmdidx == CMD_windo)
1068 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001069 /* go to window "wp" */
1070 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001071 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001072 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00001073 if (curwin != wp)
1074 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001075 wp = curwin->w_next;
1076 }
1077 else if (eap->cmdidx == CMD_tabdo)
1078 {
1079 /* go to window "tp" */
1080 if (!valid_tabpage(tp))
1081 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02001082 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001083 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001084 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085 else if (eap->cmdidx == CMD_bufdo)
1086 {
1087 /* Remember the number of the next listed buffer, in case
1088 * ":bwipe" is used or autocommands do something strange. */
1089 next_fnum = -1;
1090 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
1091 if (buf->b_p_bl)
1092 {
1093 next_fnum = buf->b_fnum;
1094 break;
1095 }
1096 }
1097
Bram Moolenaara162bc52015-01-07 16:54:21 +01001098 ++i;
1099
Bram Moolenaar071d4272004-06-13 20:20:40 +00001100 /* execute the command */
1101 do_cmdline(eap->arg, eap->getline, eap->cookie,
1102 DOCMD_VERBOSE + DOCMD_NOWAIT);
1103
1104 if (eap->cmdidx == CMD_bufdo)
1105 {
1106 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01001107 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001108 break;
1109 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001110 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 if (buf->b_fnum == next_fnum)
1112 break;
1113 if (buf == NULL)
1114 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001115
1116 /* Go to the next buffer. Clear 'shm' to avoid that the file
1117 * message overwrites any output from the command. */
1118 p_shm_save = vim_strsave(p_shm);
1119 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001120 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001121 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1122 vim_free(p_shm_save);
1123
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001124 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125 if (curbuf->b_fnum != next_fnum)
1126 break;
1127 }
1128
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001129#ifdef FEAT_QUICKFIX
1130 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1131 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1132 {
1133 if (i >= qf_size || i >= eap->line2)
1134 break;
1135
1136 qf_idx = qf_get_cur_idx(eap);
1137
1138 ex_cnext(eap);
1139
1140 /* If jumping to the next quickfix entry fails, quit here */
1141 if (qf_get_cur_idx(eap) == qf_idx)
1142 break;
1143 }
1144#endif
1145
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146 if (eap->cmdidx == CMD_windo)
1147 {
1148 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01001149
Bram Moolenaar071d4272004-06-13 20:20:40 +00001150 /* required when 'scrollbind' has been set */
1151 if (curwin->w_p_scb)
1152 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01001154
Bram Moolenaara162bc52015-01-07 16:54:21 +01001155 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
1156 if (i+1 > eap->line2)
1157 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001158 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
1159 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160 }
1161 listcmd_busy = FALSE;
1162 }
1163
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001164#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001165 if (save_ei != NULL)
1166 {
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001167 buf_T *bnext;
1168 aco_save_T aco;
1169
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001170 au_event_restore(save_ei);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001171
1172 for (buf = firstbuf; buf != NULL; buf = bnext)
1173 {
1174 bnext = buf->b_next;
1175 if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET))
1176 {
1177 buf->b_flags &= ~BF_SYN_SET;
1178
1179 // buffer was opened while Syntax autocommands were disabled,
1180 // need to trigger them now.
1181 if (buf == curbuf)
1182 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001183 curbuf->b_fname, TRUE, curbuf);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001184 else
1185 {
1186 aucmd_prepbuf(&aco, buf);
1187 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
1188 buf->b_fname, TRUE, buf);
1189 aucmd_restbuf(&aco);
1190 }
1191
1192 // start over, in case autocommands messed things up.
1193 bnext = firstbuf;
1194 }
1195 }
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001196 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02001198#ifdef FEAT_CLIPBOARD
1199 end_global_changes();
1200#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201}
1202
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203#ifdef FEAT_EVAL
1204/*
1205 * ":compiler[!] {name}"
1206 */
1207 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001208ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209{
1210 char_u *buf;
1211 char_u *old_cur_comp = NULL;
1212 char_u *p;
1213
1214 if (*eap->arg == NUL)
1215 {
1216 /* List all compiler scripts. */
1217 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
1218 /* ) keep the indenter happy... */
1219 }
1220 else
1221 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02001222 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223 if (buf != NULL)
1224 {
1225 if (eap->forceit)
1226 {
1227 /* ":compiler! {name}" sets global options */
1228 do_cmdline_cmd((char_u *)
1229 "command -nargs=* CompilerSet set <args>");
1230 }
1231 else
1232 {
1233 /* ":compiler! {name}" sets local options.
1234 * To remain backwards compatible "current_compiler" is always
1235 * used. A user's compiler plugin may set it, the distributed
1236 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001237 * "b:current_compiler" and restore "current_compiler".
1238 * Explicitly prepend "g:" to make it work in a function. */
1239 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240 if (old_cur_comp != NULL)
1241 old_cur_comp = vim_strsave(old_cur_comp);
1242 do_cmdline_cmd((char_u *)
1243 "command -nargs=* CompilerSet setlocal <args>");
1244 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001245 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00001246 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001247
1248 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001249 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001250 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251 vim_free(buf);
1252
1253 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
1254
1255 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001256 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257 if (p != NULL)
1258 set_internal_string_var((char_u *)"b:current_compiler", p);
1259
1260 /* Restore "current_compiler" for ":compiler {name}". */
1261 if (!eap->forceit)
1262 {
1263 if (old_cur_comp != NULL)
1264 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001265 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266 old_cur_comp);
1267 vim_free(old_cur_comp);
1268 }
1269 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001270 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271 }
1272 }
1273 }
1274}
1275#endif
1276
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001277#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
1278
1279# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
1280/*
1281 * Detect Python 3 or 2, and initialize 'pyxversion'.
1282 */
1283 void
1284init_pyxversion(void)
1285{
1286 if (p_pyx == 0)
1287 {
1288 if (python3_enabled(FALSE))
1289 p_pyx = 3;
1290 else if (python_enabled(FALSE))
1291 p_pyx = 2;
1292 }
1293}
1294# endif
1295
1296/*
1297 * Does a file contain one of the following strings at the beginning of any
1298 * line?
1299 * "#!(any string)python2" => returns 2
1300 * "#!(any string)python3" => returns 3
1301 * "# requires python 2.x" => returns 2
1302 * "# requires python 3.x" => returns 3
1303 * otherwise return 0.
1304 */
1305 static int
1306requires_py_version(char_u *filename)
1307{
1308 FILE *file;
1309 int requires_py_version = 0;
1310 int i, lines;
1311
1312 lines = (int)p_mls;
1313 if (lines < 0)
1314 lines = 5;
1315
1316 file = mch_fopen((char *)filename, "r");
1317 if (file != NULL)
1318 {
1319 for (i = 0; i < lines; i++)
1320 {
1321 if (vim_fgets(IObuff, IOSIZE, file))
1322 break;
1323 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
1324 {
1325 /* Check shebang. */
1326 if (strstr((char *)IObuff + 2, "python2") != NULL)
1327 {
1328 requires_py_version = 2;
1329 break;
1330 }
1331 if (strstr((char *)IObuff + 2, "python3") != NULL)
1332 {
1333 requires_py_version = 3;
1334 break;
1335 }
1336 }
1337 IObuff[21] = '\0';
1338 if (STRCMP("# requires python 2.x", IObuff) == 0)
1339 {
1340 requires_py_version = 2;
1341 break;
1342 }
1343 if (STRCMP("# requires python 3.x", IObuff) == 0)
1344 {
1345 requires_py_version = 3;
1346 break;
1347 }
1348 }
1349 fclose(file);
1350 }
1351 return requires_py_version;
1352}
1353
1354
1355/*
1356 * Source a python file using the requested python version.
1357 */
1358 static void
1359source_pyx_file(exarg_T *eap, char_u *fname)
1360{
1361 exarg_T ex;
1362 int v = requires_py_version(fname);
1363
1364# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1365 init_pyxversion();
1366# endif
1367 if (v == 0)
1368 {
1369# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1370 /* user didn't choose a preference, 'pyx' is used */
1371 v = p_pyx;
1372# elif defined(FEAT_PYTHON)
1373 v = 2;
1374# elif defined(FEAT_PYTHON3)
1375 v = 3;
1376# endif
1377 }
1378
1379 /*
1380 * now source, if required python version is not supported show
1381 * unobtrusive message.
1382 */
1383 if (eap == NULL)
1384 vim_memset(&ex, 0, sizeof(ex));
1385 else
1386 ex = *eap;
1387 ex.arg = fname;
1388 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
1389
1390 if (v == 2)
1391 {
1392# ifdef FEAT_PYTHON
1393 ex_pyfile(&ex);
1394# else
1395 vim_snprintf((char *)IObuff, IOSIZE,
1396 _("W20: Required python version 2.x not supported, ignoring file: %s"),
1397 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01001398 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001399# endif
1400 return;
1401 }
1402 else
1403 {
1404# ifdef FEAT_PYTHON3
1405 ex_py3file(&ex);
1406# else
1407 vim_snprintf((char *)IObuff, IOSIZE,
1408 _("W21: Required python version 3.x not supported, ignoring file: %s"),
1409 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01001410 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001411# endif
1412 return;
1413 }
1414}
1415
1416/*
1417 * ":pyxfile {fname}"
1418 */
1419 void
1420ex_pyxfile(exarg_T *eap)
1421{
1422 source_pyx_file(eap, eap->arg);
1423}
1424
1425/*
1426 * ":pyx"
1427 */
1428 void
1429ex_pyx(exarg_T *eap)
1430{
1431# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1432 init_pyxversion();
1433 if (p_pyx == 2)
1434 ex_python(eap);
1435 else
1436 ex_py3(eap);
1437# elif defined(FEAT_PYTHON)
1438 ex_python(eap);
1439# elif defined(FEAT_PYTHON3)
1440 ex_py3(eap);
1441# endif
1442}
1443
1444/*
1445 * ":pyxdo"
1446 */
1447 void
1448ex_pyxdo(exarg_T *eap)
1449{
1450# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1451 init_pyxversion();
1452 if (p_pyx == 2)
1453 ex_pydo(eap);
1454 else
1455 ex_py3do(eap);
1456# elif defined(FEAT_PYTHON)
1457 ex_pydo(eap);
1458# elif defined(FEAT_PYTHON3)
1459 ex_py3do(eap);
1460# endif
1461}
1462
1463#endif
1464
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001466 * ":checktime [buffer]"
1467 */
1468 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001469ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470{
1471 buf_T *buf;
1472 int save_no_check_timestamps = no_check_timestamps;
1473
1474 no_check_timestamps = 0;
1475 if (eap->addr_count == 0) /* default is all buffers */
1476 check_timestamps(FALSE);
1477 else
1478 {
1479 buf = buflist_findnr((int)eap->line2);
1480 if (buf != NULL) /* cannot happen? */
1481 (void)buf_check_timestamp(buf, FALSE);
1482 }
1483 no_check_timestamps = save_no_check_timestamps;
1484}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001485
Bram Moolenaar071d4272004-06-13 20:20:40 +00001486#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
1487 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001488# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001489 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001490get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001491{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001492 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001493
Bram Moolenaar48e330a2016-02-23 14:53:34 +01001494 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001495 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001496
Bram Moolenaar4f974752019-02-17 17:44:42 +01001497# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498 if (loc != NULL)
1499 {
1500 char_u *p;
1501
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001502 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
1503 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001504 p = vim_strchr(loc, '=');
1505 if (p != NULL)
1506 {
1507 loc = ++p;
1508 while (*p != NUL) /* remove trailing newline */
1509 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001510 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001511 {
1512 *p = NUL;
1513 break;
1514 }
1515 ++p;
1516 }
1517 }
1518 }
1519# endif
1520
1521 return loc;
1522}
1523#endif
1524
1525
Bram Moolenaar4f974752019-02-17 17:44:42 +01001526#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527/*
1528 * On MS-Windows locale names are strings like "German_Germany.1252", but
1529 * gettext expects "de". Try to translate one into another here for a few
1530 * supported languages.
1531 */
1532 static char_u *
1533gettext_lang(char_u *name)
1534{
1535 int i;
1536 static char *(mtable[]) = {
1537 "afrikaans", "af",
1538 "czech", "cs",
1539 "dutch", "nl",
1540 "german", "de",
1541 "english_united kingdom", "en_GB",
1542 "spanish", "es",
1543 "french", "fr",
1544 "italian", "it",
1545 "japanese", "ja",
1546 "korean", "ko",
1547 "norwegian", "no",
1548 "polish", "pl",
1549 "russian", "ru",
1550 "slovak", "sk",
1551 "swedish", "sv",
1552 "ukrainian", "uk",
1553 "chinese_china", "zh_CN",
1554 "chinese_taiwan", "zh_TW",
1555 NULL};
1556
1557 for (i = 0; mtable[i] != NULL; i += 2)
1558 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001559 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560 return name;
1561}
1562#endif
1563
1564#if defined(FEAT_MULTI_LANG) || defined(PROTO)
1565/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01001566 * Return TRUE when "lang" starts with a valid language name.
1567 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
1568 */
1569 static int
1570is_valid_mess_lang(char_u *lang)
1571{
1572 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
1573}
1574
1575/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576 * Obtain the current messages language. Used to set the default for
1577 * 'helplang'. May return NULL or an empty string.
1578 */
1579 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001580get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001581{
1582 char_u *p;
1583
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001584# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001585# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001586 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001587# else
1588 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001589 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
1590 * and LC_MONETARY may be set differently for a Japanese working in the
1591 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001592 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593# endif
1594# else
1595 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01001596 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001597 {
1598 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01001599 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001600 p = mch_getenv((char_u *)"LANG");
1601 }
1602# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01001603# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001604 p = gettext_lang(p);
1605# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01001606 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001607}
1608#endif
1609
Bram Moolenaardef9e822004-12-31 20:58:58 +00001610/* Complicated #if; matches with where get_mess_env() is used below. */
1611#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
1612 && defined(LC_MESSAGES))) \
1613 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00001614 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615/*
1616 * Get the language used for messages from the environment.
1617 */
1618 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001619get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001620{
1621 char_u *p;
1622
1623 p = mch_getenv((char_u *)"LC_ALL");
1624 if (p == NULL || *p == NUL)
1625 {
1626 p = mch_getenv((char_u *)"LC_MESSAGES");
1627 if (p == NULL || *p == NUL)
1628 {
1629 p = mch_getenv((char_u *)"LANG");
1630 if (p != NULL && VIM_ISDIGIT(*p))
1631 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001632# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001634 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001635# endif
1636 }
1637 }
1638 return p;
1639}
1640#endif
1641
1642#if defined(FEAT_EVAL) || defined(PROTO)
1643
1644/*
1645 * Set the "v:lang" variable according to the current locale setting.
1646 * Also do "v:lc_time"and "v:ctype".
1647 */
1648 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001649set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650{
1651 char_u *loc;
1652
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001653# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001654 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001655# else
1656 /* setlocale() not supported: use the default value */
1657 loc = (char_u *)"C";
1658# endif
1659 set_vim_var_string(VV_CTYPE, loc, -1);
1660
1661 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
1662 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001663# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001664 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001665# else
1666 loc = get_mess_env();
1667# endif
1668 set_vim_var_string(VV_LANG, loc, -1);
1669
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001670# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001671 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672# endif
1673 set_vim_var_string(VV_LC_TIME, loc, -1);
1674}
1675#endif
1676
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01001677#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678/*
1679 * ":language": Set the language (locale).
1680 */
1681 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001682ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001683{
1684 char *loc;
1685 char_u *p;
1686 char_u *name;
1687 int what = LC_ALL;
1688 char *whatstr = "";
1689#ifdef LC_MESSAGES
1690# define VIM_LC_MESSAGES LC_MESSAGES
1691#else
1692# define VIM_LC_MESSAGES 6789
1693#endif
1694
1695 name = eap->arg;
1696
1697 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
1698 * Allow abbreviation, but require at least 3 characters to avoid
1699 * confusion with a two letter language name "me" or "ct". */
1700 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01001701 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001702 {
1703 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
1704 {
1705 what = VIM_LC_MESSAGES;
1706 name = skipwhite(p);
1707 whatstr = "messages ";
1708 }
1709 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
1710 {
1711 what = LC_CTYPE;
1712 name = skipwhite(p);
1713 whatstr = "ctype ";
1714 }
1715 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
1716 {
1717 what = LC_TIME;
1718 name = skipwhite(p);
1719 whatstr = "time ";
1720 }
1721 }
1722
1723 if (*name == NUL)
1724 {
1725#ifndef LC_MESSAGES
1726 if (what == VIM_LC_MESSAGES)
1727 p = get_mess_env();
1728 else
1729#endif
1730 p = (char_u *)setlocale(what, NULL);
1731 if (p == NULL || *p == NUL)
1732 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001733 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 }
1735 else
1736 {
1737#ifndef LC_MESSAGES
1738 if (what == VIM_LC_MESSAGES)
1739 loc = "";
1740 else
1741#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001742 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001744#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
1745 /* Make sure strtod() uses a decimal point, not a comma. */
1746 setlocale(LC_NUMERIC, "C");
1747#endif
1748 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001750 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001751 else
1752 {
1753#ifdef HAVE_NL_MSG_CAT_CNTR
1754 /* Need to do this for GNU gettext, otherwise cached translations
1755 * will be used again. */
1756 extern int _nl_msg_cat_cntr;
1757
1758 ++_nl_msg_cat_cntr;
1759#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00001760 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001761 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
1762
1763 if (what != LC_TIME)
1764 {
1765 /* Tell gettext() what to translate to. It apparently doesn't
1766 * use the currently effective locale. Also do this when
1767 * FEAT_GETTEXT isn't defined, so that shell commands use this
1768 * value. */
1769 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00001770 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001771 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02001772
1773 /* Clear $LANGUAGE because GNU gettext uses it. */
1774 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01001775# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00001776 /* Apparently MS-Windows printf() may cause a crash when
1777 * we give it 8-bit text while it's expecting text in the
1778 * current locale. This call avoids that. */
1779 setlocale(LC_CTYPE, "C");
1780# endif
1781 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001782 if (what != LC_CTYPE)
1783 {
1784 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01001785#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786 mname = gettext_lang(name);
1787#else
1788 mname = name;
1789#endif
1790 vim_setenv((char_u *)"LC_MESSAGES", mname);
1791#ifdef FEAT_MULTI_LANG
1792 set_helplang_default(mname);
1793#endif
1794 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795 }
1796
1797# ifdef FEAT_EVAL
1798 /* Set v:lang, v:lc_time and v:ctype to the final result. */
1799 set_lang_var();
1800# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02001801# ifdef FEAT_TITLE
1802 maketitle();
1803# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001804 }
1805 }
1806}
1807
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001808static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001809
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001810# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001811static int did_init_locales = FALSE;
1812
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001813/*
1814 * Return an array of strings for all available locales + NULL for the
1815 * last element. Return NULL in case of error.
1816 */
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001817 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001818find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001819{
1820 garray_T locales_ga;
1821 char_u *loc;
1822
1823 /* Find all available locales by running command "locale -a". If this
1824 * doesn't work we won't have completion. */
1825 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02001826 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001827 if (locale_a == NULL)
1828 return NULL;
1829 ga_init2(&locales_ga, sizeof(char_u *), 20);
1830
1831 /* Transform locale_a string where each locale is separated by "\n"
1832 * into an array of locale strings. */
1833 loc = (char_u *)strtok((char *)locale_a, "\n");
1834
1835 while (loc != NULL)
1836 {
1837 if (ga_grow(&locales_ga, 1) == FAIL)
1838 break;
1839 loc = vim_strsave(loc);
1840 if (loc == NULL)
1841 break;
1842
1843 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
1844 loc = (char_u *)strtok(NULL, "\n");
1845 }
1846 vim_free(locale_a);
1847 if (ga_grow(&locales_ga, 1) == FAIL)
1848 {
1849 ga_clear(&locales_ga);
1850 return NULL;
1851 }
1852 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
1853 return (char_u **)locales_ga.ga_data;
1854}
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001855# endif
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001856
1857/*
1858 * Lazy initialization of all available locales.
1859 */
1860 static void
1861init_locales(void)
1862{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001863# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001864 if (!did_init_locales)
1865 {
1866 did_init_locales = TRUE;
1867 locales = find_locales();
1868 }
1869# endif
1870}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001871
1872# if defined(EXITFREE) || defined(PROTO)
1873 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001874free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001875{
1876 int i;
1877 if (locales != NULL)
1878 {
1879 for (i = 0; locales[i] != NULL; i++)
1880 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01001881 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001882 }
1883}
1884# endif
1885
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886/*
1887 * Function given to ExpandGeneric() to obtain the possible arguments of the
1888 * ":language" command.
1889 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001891get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892{
1893 if (idx == 0)
1894 return (char_u *)"messages";
1895 if (idx == 1)
1896 return (char_u *)"ctype";
1897 if (idx == 2)
1898 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001899
1900 init_locales();
1901 if (locales == NULL)
1902 return NULL;
1903 return locales[idx - 3];
1904}
1905
1906/*
1907 * Function given to ExpandGeneric() to obtain the available locales.
1908 */
1909 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001910get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001911{
1912 init_locales();
1913 if (locales == NULL)
1914 return NULL;
1915 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001916}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001917
1918#endif