blob: e2c87bd6f6f3b8680785eebf8fee72450e18a677 [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 */
263 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 Moolenaar8e97bd72016-08-06 22:05:07 +0200294 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
307 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
341 void
342add_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
378# if defined(EXITFREE) || defined(PROTO)
379 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}
391# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +0100392# endif
393
Bram Moolenaar071d4272004-06-13 20:20:40 +0000394#endif
395
396/*
397 * If 'autowrite' option set, try to write the file.
398 * Careful: autocommands may make "buf" invalid!
399 *
400 * return FAIL for failure, OK otherwise
401 */
402 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100403autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404{
Bram Moolenaar373154b2007-02-13 05:19:30 +0000405 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200406 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +0000407
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 if (!(p_aw || p_awa) || !p_write
409#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +0000410 /* never autowrite a "nofile" or "nowrite" buffer */
411 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +0000413 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000414 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200415 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +0000416 r = buf_write_all(buf, forceit);
417
418 /* Writing may succeed but the buffer still changed, e.g., when there is a
419 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200420 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +0000421 r = FAIL;
422 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423}
424
425/*
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +0200426 * Flush all buffers, except the ones that are readonly or are never written.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427 */
428 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100429autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430{
431 buf_T *buf;
432
433 if (!(p_aw || p_awa) || !p_write)
434 return;
Bram Moolenaar29323592016-07-24 22:04:11 +0200435 FOR_ALL_BUFFERS(buf)
Bram Moolenaar8c9e7b02018-08-30 13:07:17 +0200436 if (bufIsChanged(buf) && !buf->b_p_ro && !bt_dontwrite(buf))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200438 bufref_T bufref;
439
440 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100441
Bram Moolenaar071d4272004-06-13 20:20:40 +0000442 (void)buf_write_all(buf, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100443
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200445 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 buf = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000447 }
448}
449
450/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100451 * Return TRUE if buffer was changed and cannot be abandoned.
452 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100455check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200457 int forceit = (flags & CCGD_FORCEIT);
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200458 bufref_T bufref;
459
460 set_bufref(&bufref, buf);
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100461
Bram Moolenaar071d4272004-06-13 20:20:40 +0000462 if ( !forceit
463 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100464 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
465 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466 {
467#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
468 if ((p_confirm || cmdmod.confirm) && p_write)
469 {
470 buf_T *buf2;
471 int count = 0;
472
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100473 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +0200474 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000475 if (bufIsChanged(buf2)
476 && (buf2->b_ffname != NULL
477# ifdef FEAT_BROWSE
478 || cmdmod.browse
479# endif
480 ))
481 ++count;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200482 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000483 /* Autocommand deleted buffer, oops! It's not changed now. */
484 return FALSE;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100485
Bram Moolenaar071d4272004-06-13 20:20:40 +0000486 dialog_changed(buf, count > 1);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100487
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200488 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000489 /* Autocommand deleted buffer, oops! It's not changed now. */
490 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 return bufIsChanged(buf);
492 }
493#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100494 if (flags & CCGD_EXCMD)
Bram Moolenaarf5be7cd2017-08-17 16:55:13 +0200495 no_write_message();
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100496 else
Bram Moolenaar7a760922018-02-19 23:10:02 +0100497 no_write_message_nobang(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 return TRUE;
499 }
500 return FALSE;
501}
502
503#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
504
505#if defined(FEAT_BROWSE) || defined(PROTO)
506/*
507 * When wanting to write a file without a file name, ask the user for a name.
508 */
509 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100510browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511{
512 if (buf->b_fname == NULL)
513 {
514 char_u *fname;
515
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000516 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
517 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 if (fname != NULL)
519 {
520 if (setfname(buf, fname, NULL, TRUE) == OK)
521 buf->b_flags |= BF_NOTEDITED;
522 vim_free(fname);
523 }
524 }
525}
526#endif
527
528/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +0200529 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 * Must check 'write' option first!
531 */
532 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100533dialog_changed(
534 buf_T *buf,
535 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536{
Bram Moolenaard9462e32011-04-11 21:35:11 +0200537 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000538 int ret;
539 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +0200540 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541
Bram Moolenaar3f9a1ff2017-08-21 22:06:02 +0200542 dialog_msg(buff, _("Save changes to \"%s\"?"), buf->b_fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543 if (checkall)
544 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
545 else
546 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
547
Bram Moolenaar4ca41532019-05-09 21:48:37 +0200548 // Init ea pseudo-structure, this is needed for the check_overwrite()
549 // function.
550 vim_memset(&ea, 0, sizeof(ea));
Bram Moolenaar8218f602012-04-25 17:32:18 +0200551
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552 if (ret == VIM_YES)
553 {
554#ifdef FEAT_BROWSE
555 /* May get file name, when there is none */
556 browse_save_fname(buf);
557#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200558 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
559 buf->b_fname, buf->b_ffname, FALSE) == OK)
560 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561 (void)buf_write_all(buf, FALSE);
562 }
563 else if (ret == VIM_NO)
564 {
Bram Moolenaarc024b462019-06-08 18:07:21 +0200565 unchanged(buf, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 }
567 else if (ret == VIM_ALL)
568 {
569 /*
570 * Write all modified files that can be written.
571 * Skip readonly buffers, these need to be confirmed
572 * individually.
573 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200574 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575 {
576 if (bufIsChanged(buf2)
577 && (buf2->b_ffname != NULL
578#ifdef FEAT_BROWSE
579 || cmdmod.browse
580#endif
581 )
582 && !buf2->b_p_ro)
583 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200584 bufref_T bufref;
585
586 set_bufref(&bufref, buf2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000587#ifdef FEAT_BROWSE
588 /* May get file name, when there is none */
589 browse_save_fname(buf2);
590#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +0200591 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
592 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
593 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 (void)buf_write_all(buf2, FALSE);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100595
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200597 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000598 buf2 = firstbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599 }
600 }
601 }
602 else if (ret == VIM_DISCARDALL)
603 {
604 /*
605 * mark all buffers as unchanged
606 */
Bram Moolenaar29323592016-07-24 22:04:11 +0200607 FOR_ALL_BUFFERS(buf2)
Bram Moolenaarc024b462019-06-08 18:07:21 +0200608 unchanged(buf2, TRUE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609 }
610}
611#endif
612
613/*
614 * Return TRUE if the buffer "buf" can be abandoned, either by making it
615 * hidden, autowriting it or unloading it.
616 */
617 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100618can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619{
Bram Moolenaareb44a682017-08-03 22:44:55 +0200620 return ( buf_hide(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000621 || !bufIsChanged(buf)
622 || buf->b_nwindows > 1
623 || autowrite(buf, forceit) == OK
624 || forceit);
625}
626
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100627/*
628 * Add a buffer number to "bufnrs", unless it's already there.
629 */
630 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100631add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100632{
633 int i;
634
635 for (i = 0; i < *bufnump; ++i)
636 if (bufnrs[i] == nr)
637 return;
638 bufnrs[*bufnump] = nr;
639 *bufnump = *bufnump + 1;
640}
641
Bram Moolenaar071d4272004-06-13 20:20:40 +0000642/*
643 * Return TRUE if any buffer was changed and cannot be abandoned.
644 * That changed buffer becomes the current buffer.
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100645 * When "unload" is TRUE the current buffer is unloaded instead of making it
Bram Moolenaar027387f2016-01-02 22:25:52 +0100646 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 */
648 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100649check_changed_any(
650 int hidden, /* Only check hidden buffers */
651 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652{
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100653 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654 buf_T *buf;
655 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100656 int i;
657 int bufnum = 0;
658 int bufcount = 0;
659 int *bufnrs;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100660 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100663 /* Make a list of all buffers, with the most important ones first. */
Bram Moolenaar29323592016-07-24 22:04:11 +0200664 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100665 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100667 if (bufcount == 0)
668 return FALSE;
669
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200670 bufnrs = ALLOC_MULT(int, bufcount);
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100671 if (bufnrs == NULL)
672 return FALSE;
673
674 /* curbuf */
675 bufnrs[bufnum++] = curbuf->b_fnum;
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100676
677 /* buffers in current tab */
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100678 FOR_ALL_WINDOWS(wp)
679 if (wp->w_buffer != curbuf)
680 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
681
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100682 /* buffers in other tabs */
Bram Moolenaar29323592016-07-24 22:04:11 +0200683 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100684 if (tp != curtab)
685 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
686 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100687
688 /* any other buffer */
Bram Moolenaar29323592016-07-24 22:04:11 +0200689 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100690 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
691
692 for (i = 0; i < bufnum; ++i)
693 {
694 buf = buflist_findnr(bufnrs[i]);
695 if (buf == NULL)
696 continue;
697 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
698 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200699 bufref_T bufref;
700
701 set_bufref(&bufref, buf);
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100702#ifdef FEAT_TERMINAL
703 if (term_job_running(buf->b_term))
704 {
705 if (term_try_stop_job(buf) == FAIL)
706 break;
707 }
708 else
709#endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100710 /* Try auto-writing the buffer. If this fails but the buffer no
Bram Moolenaar558ca4a2019-04-04 18:15:38 +0200711 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100712 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
713 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200714 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100715 break; /* didn't save - still changes */
716 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000717 }
718
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100719 if (i >= bufnum)
720 goto theend;
721
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100722 /* Get here if "buf" cannot be abandoned. */
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100723 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724 exiting = FALSE;
725#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
726 /*
727 * When ":confirm" used, don't give an error message.
728 */
729 if (!(p_confirm || cmdmod.confirm))
730#endif
731 {
732 /* There must be a wait_return for this message, do_buffer()
733 * may cause a redraw. But wait_return() is a no-op when vgetc()
734 * is busy (Quit used from window menu), then make sure we don't
735 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +0000736 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737 {
738 msg_row = cmdline_row;
739 msg_col = 0;
740 msg_didout = FALSE;
741 }
Bram Moolenaareb44a682017-08-03 22:44:55 +0200742 if (
743#ifdef FEAT_TERMINAL
744 term_job_running(buf->b_term)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100745 ? semsg(_("E947: Job still running in buffer \"%s\""),
Bram Moolenaareb44a682017-08-03 22:44:55 +0200746 buf->b_fname)
747 :
748#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100749 semsg(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +0200750 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000751 {
752 save = no_wait_return;
753 no_wait_return = FALSE;
754 wait_return(FALSE);
755 no_wait_return = save;
756 }
757 }
758
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 /* Try to find a window that contains the buffer. */
760 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100761 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762 if (wp->w_buffer == buf)
763 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200764 bufref_T bufref;
765
766 set_bufref(&bufref, buf);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100767
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100768 goto_tabpage_win(tp, wp);
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100769
Bram Moolenaarbdace832019-03-02 10:13:42 +0100770 // Paranoia: did autocmd wipe out the buffer with changes?
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +0200771 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100772 goto theend;
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100773 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100775buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776
777 /* Open the changed buffer in the current window. */
778 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +0100779 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780
Bram Moolenaar970a1b82012-03-23 18:39:18 +0100781theend:
782 vim_free(bufnrs);
783 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784}
785
786/*
787 * return FAIL if there is no file name, OK if there is one
788 * give error message for FAIL
789 */
790 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100791check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792{
793 if (curbuf->b_ffname == NULL)
794 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100795 emsg(_(e_noname));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796 return FAIL;
797 }
798 return OK;
799}
800
801/*
802 * flush the contents of a buffer, unless it has no file name
803 *
804 * return FAIL for failure, OK otherwise
805 */
806 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100807buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808{
809 int retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811
812 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
813 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
814 FALSE, forceit, TRUE, FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000816 {
Bram Moolenaar8820b482017-03-16 17:23:31 +0100817 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar32526b32019-01-19 17:43:09 +0100818 msg(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000819 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820 return retval;
821}
822
823/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200824 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000825 */
826 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100827ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828{
829 int i;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000830 win_T *wp;
831 tabpage_T *tp;
Bram Moolenaare25bb902015-02-27 20:33:37 +0100832 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000833 int next_fnum = 0;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100834#if defined(FEAT_SYN_HL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000837 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200838#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +0200839 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200840 int qf_idx;
841#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842
Bram Moolenaar0106e3d2016-02-23 18:55:43 +0100843#ifndef FEAT_QUICKFIX
844 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
845 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
846 {
847 ex_ni(eap);
848 return;
849 }
850#endif
851
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100852#if defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000853 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200854 {
Bram Moolenaardcaf10e2005-01-21 11:55:25 +0000855 /* Don't do syntax HL autocommands. Skipping the syntax file is a
856 * great speed improvement. */
857 save_ei = au_event_disable(",Syntax");
Bram Moolenaarc7f1e402019-08-03 13:29:46 +0200858
859 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
860 buf->b_flags &= ~BF_SYN_SET;
861 buf = curbuf;
862 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +0200864#ifdef FEAT_CLIPBOARD
865 start_global_changes();
866#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867
868 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000869 || eap->cmdidx == CMD_tabdo
Bram Moolenaareb44a682017-08-03 22:44:55 +0200870 || buf_hide(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +0100871 || !check_changed(curbuf, CCGD_AW
872 | (eap->forceit ? CCGD_FORCEIT : 0)
873 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100876 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000877 wp = firstwin;
878 tp = first_tabpage;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100879 switch (eap->cmdidx)
880 {
Bram Moolenaara162bc52015-01-07 16:54:21 +0100881 case CMD_windo:
882 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
883 i++;
884 break;
885 case CMD_tabdo:
886 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
887 i++;
888 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100889 case CMD_argdo:
890 i = eap->line1 - 1;
891 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +0100892 default:
893 break;
894 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 /* set pcmark now */
896 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200897 {
Bram Moolenaare25bb902015-02-27 20:33:37 +0100898 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200899 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +0100900 || !buf->b_p_bl); buf = buf->b_next)
901 if (buf->b_fnum > eap->line2)
902 {
903 buf = NULL;
904 break;
905 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200906 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +0100907 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200908 }
909#ifdef FEAT_QUICKFIX
910 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
911 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
912 {
Bram Moolenaar25190db2019-05-04 15:05:28 +0200913 qf_size = qf_get_valid_size(eap);
Bram Moolenaaraa23b372015-09-08 18:46:31 +0200914 if (qf_size <= 0 || eap->line1 > qf_size)
915 buf = NULL;
916 else
917 {
918 ex_cc(eap);
919
920 buf = curbuf;
921 i = eap->line1 - 1;
922 if (eap->addr_count <= 0)
923 /* default is all the quickfix/location list entries */
924 eap->line2 = qf_size;
925 }
926 }
927#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928 else
929 setpcmark();
930 listcmd_busy = TRUE; /* avoids setting pcmark below */
931
Bram Moolenaare25bb902015-02-27 20:33:37 +0100932 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933 {
934 if (eap->cmdidx == CMD_argdo)
935 {
936 /* go to argument "i" */
937 if (i == ARGCOUNT)
938 break;
939 /* Don't call do_argfile() when already there, it will try
940 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +0000941 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000942 {
943 /* Clear 'shm' to avoid that the file message overwrites
944 * any output from the command. */
945 p_shm_save = vim_strsave(p_shm);
946 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000947 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000948 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
949 vim_free(p_shm_save);
950 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000951 if (curwin->w_arg_idx != i)
952 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000953 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954 else if (eap->cmdidx == CMD_windo)
955 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000956 /* go to window "wp" */
957 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000958 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000959 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +0000960 if (curwin != wp)
961 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000962 wp = curwin->w_next;
963 }
964 else if (eap->cmdidx == CMD_tabdo)
965 {
966 /* go to window "tp" */
967 if (!valid_tabpage(tp))
968 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200969 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +0000970 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000972 else if (eap->cmdidx == CMD_bufdo)
973 {
974 /* Remember the number of the next listed buffer, in case
975 * ":bwipe" is used or autocommands do something strange. */
976 next_fnum = -1;
977 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
978 if (buf->b_p_bl)
979 {
980 next_fnum = buf->b_fnum;
981 break;
982 }
983 }
984
Bram Moolenaara162bc52015-01-07 16:54:21 +0100985 ++i;
986
Bram Moolenaar071d4272004-06-13 20:20:40 +0000987 /* execute the command */
988 do_cmdline(eap->arg, eap->getline, eap->cookie,
989 DOCMD_VERBOSE + DOCMD_NOWAIT);
990
991 if (eap->cmdidx == CMD_bufdo)
992 {
993 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +0100994 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000995 break;
996 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +0200997 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000998 if (buf->b_fnum == next_fnum)
999 break;
1000 if (buf == NULL)
1001 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001002
1003 /* Go to the next buffer. Clear 'shm' to avoid that the file
1004 * message overwrites any output from the command. */
1005 p_shm_save = vim_strsave(p_shm);
1006 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001007 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001008 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
1009 vim_free(p_shm_save);
1010
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001011 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001012 if (curbuf->b_fnum != next_fnum)
1013 break;
1014 }
1015
Bram Moolenaaraa23b372015-09-08 18:46:31 +02001016#ifdef FEAT_QUICKFIX
1017 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
1018 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
1019 {
1020 if (i >= qf_size || i >= eap->line2)
1021 break;
1022
1023 qf_idx = qf_get_cur_idx(eap);
1024
1025 ex_cnext(eap);
1026
1027 /* If jumping to the next quickfix entry fails, quit here */
1028 if (qf_get_cur_idx(eap) == qf_idx)
1029 break;
1030 }
1031#endif
1032
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033 if (eap->cmdidx == CMD_windo)
1034 {
1035 validate_cursor(); /* cursor may have moved */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01001036
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037 /* required when 'scrollbind' has been set */
1038 if (curwin->w_p_scb)
1039 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01001041
Bram Moolenaara162bc52015-01-07 16:54:21 +01001042 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
1043 if (i+1 > eap->line2)
1044 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01001045 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
1046 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001047 }
1048 listcmd_busy = FALSE;
1049 }
1050
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001051#if defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001052 if (save_ei != NULL)
1053 {
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001054 buf_T *bnext;
1055 aco_save_T aco;
1056
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001057 au_event_restore(save_ei);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001058
1059 for (buf = firstbuf; buf != NULL; buf = bnext)
1060 {
1061 bnext = buf->b_next;
1062 if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET))
1063 {
1064 buf->b_flags &= ~BF_SYN_SET;
1065
1066 // buffer was opened while Syntax autocommands were disabled,
1067 // need to trigger them now.
1068 if (buf == curbuf)
1069 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001070 curbuf->b_fname, TRUE, curbuf);
Bram Moolenaarc7f1e402019-08-03 13:29:46 +02001071 else
1072 {
1073 aucmd_prepbuf(&aco, buf);
1074 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
1075 buf->b_fname, TRUE, buf);
1076 aucmd_restbuf(&aco);
1077 }
1078
1079 // start over, in case autocommands messed things up.
1080 bnext = firstbuf;
1081 }
1082 }
Bram Moolenaar6ac54292005-02-02 23:07:25 +00001083 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001084#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02001085#ifdef FEAT_CLIPBOARD
1086 end_global_changes();
1087#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001088}
1089
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090#ifdef FEAT_EVAL
1091/*
1092 * ":compiler[!] {name}"
1093 */
1094 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001095ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001096{
1097 char_u *buf;
1098 char_u *old_cur_comp = NULL;
1099 char_u *p;
1100
1101 if (*eap->arg == NUL)
1102 {
1103 /* List all compiler scripts. */
1104 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
1105 /* ) keep the indenter happy... */
1106 }
1107 else
1108 {
Bram Moolenaar964b3742019-05-24 18:54:09 +02001109 buf = alloc(STRLEN(eap->arg) + 14);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 if (buf != NULL)
1111 {
1112 if (eap->forceit)
1113 {
1114 /* ":compiler! {name}" sets global options */
1115 do_cmdline_cmd((char_u *)
1116 "command -nargs=* CompilerSet set <args>");
1117 }
1118 else
1119 {
1120 /* ":compiler! {name}" sets local options.
1121 * To remain backwards compatible "current_compiler" is always
1122 * used. A user's compiler plugin may set it, the distributed
1123 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001124 * "b:current_compiler" and restore "current_compiler".
1125 * Explicitly prepend "g:" to make it work in a function. */
1126 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127 if (old_cur_comp != NULL)
1128 old_cur_comp = vim_strsave(old_cur_comp);
1129 do_cmdline_cmd((char_u *)
1130 "command -nargs=* CompilerSet setlocal <args>");
1131 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001132 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00001133 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134
1135 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001136 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001137 semsg(_("E666: compiler not supported: %s"), eap->arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001138 vim_free(buf);
1139
1140 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
1141
1142 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001143 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001144 if (p != NULL)
1145 set_internal_string_var((char_u *)"b:current_compiler", p);
1146
1147 /* Restore "current_compiler" for ":compiler {name}". */
1148 if (!eap->forceit)
1149 {
1150 if (old_cur_comp != NULL)
1151 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001152 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001153 old_cur_comp);
1154 vim_free(old_cur_comp);
1155 }
1156 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01001157 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158 }
1159 }
1160 }
1161}
1162#endif
1163
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001164#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
1165
1166# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
1167/*
1168 * Detect Python 3 or 2, and initialize 'pyxversion'.
1169 */
1170 void
1171init_pyxversion(void)
1172{
1173 if (p_pyx == 0)
1174 {
1175 if (python3_enabled(FALSE))
1176 p_pyx = 3;
1177 else if (python_enabled(FALSE))
1178 p_pyx = 2;
1179 }
1180}
1181# endif
1182
1183/*
1184 * Does a file contain one of the following strings at the beginning of any
1185 * line?
1186 * "#!(any string)python2" => returns 2
1187 * "#!(any string)python3" => returns 3
1188 * "# requires python 2.x" => returns 2
1189 * "# requires python 3.x" => returns 3
1190 * otherwise return 0.
1191 */
1192 static int
1193requires_py_version(char_u *filename)
1194{
1195 FILE *file;
1196 int requires_py_version = 0;
1197 int i, lines;
1198
1199 lines = (int)p_mls;
1200 if (lines < 0)
1201 lines = 5;
1202
1203 file = mch_fopen((char *)filename, "r");
1204 if (file != NULL)
1205 {
1206 for (i = 0; i < lines; i++)
1207 {
1208 if (vim_fgets(IObuff, IOSIZE, file))
1209 break;
1210 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
1211 {
1212 /* Check shebang. */
1213 if (strstr((char *)IObuff + 2, "python2") != NULL)
1214 {
1215 requires_py_version = 2;
1216 break;
1217 }
1218 if (strstr((char *)IObuff + 2, "python3") != NULL)
1219 {
1220 requires_py_version = 3;
1221 break;
1222 }
1223 }
1224 IObuff[21] = '\0';
1225 if (STRCMP("# requires python 2.x", IObuff) == 0)
1226 {
1227 requires_py_version = 2;
1228 break;
1229 }
1230 if (STRCMP("# requires python 3.x", IObuff) == 0)
1231 {
1232 requires_py_version = 3;
1233 break;
1234 }
1235 }
1236 fclose(file);
1237 }
1238 return requires_py_version;
1239}
1240
1241
1242/*
1243 * Source a python file using the requested python version.
1244 */
1245 static void
1246source_pyx_file(exarg_T *eap, char_u *fname)
1247{
1248 exarg_T ex;
1249 int v = requires_py_version(fname);
1250
1251# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1252 init_pyxversion();
1253# endif
1254 if (v == 0)
1255 {
1256# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1257 /* user didn't choose a preference, 'pyx' is used */
1258 v = p_pyx;
1259# elif defined(FEAT_PYTHON)
1260 v = 2;
1261# elif defined(FEAT_PYTHON3)
1262 v = 3;
1263# endif
1264 }
1265
1266 /*
1267 * now source, if required python version is not supported show
1268 * unobtrusive message.
1269 */
1270 if (eap == NULL)
1271 vim_memset(&ex, 0, sizeof(ex));
1272 else
1273 ex = *eap;
1274 ex.arg = fname;
1275 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
1276
1277 if (v == 2)
1278 {
1279# ifdef FEAT_PYTHON
1280 ex_pyfile(&ex);
1281# else
1282 vim_snprintf((char *)IObuff, IOSIZE,
1283 _("W20: Required python version 2.x not supported, ignoring file: %s"),
1284 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01001285 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001286# endif
1287 return;
1288 }
1289 else
1290 {
1291# ifdef FEAT_PYTHON3
1292 ex_py3file(&ex);
1293# else
1294 vim_snprintf((char *)IObuff, IOSIZE,
1295 _("W21: Required python version 3.x not supported, ignoring file: %s"),
1296 fname);
Bram Moolenaar32526b32019-01-19 17:43:09 +01001297 msg((char *)IObuff);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001298# endif
1299 return;
1300 }
1301}
1302
1303/*
1304 * ":pyxfile {fname}"
1305 */
1306 void
1307ex_pyxfile(exarg_T *eap)
1308{
1309 source_pyx_file(eap, eap->arg);
1310}
1311
1312/*
1313 * ":pyx"
1314 */
1315 void
1316ex_pyx(exarg_T *eap)
1317{
1318# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1319 init_pyxversion();
1320 if (p_pyx == 2)
1321 ex_python(eap);
1322 else
1323 ex_py3(eap);
1324# elif defined(FEAT_PYTHON)
1325 ex_python(eap);
1326# elif defined(FEAT_PYTHON3)
1327 ex_py3(eap);
1328# endif
1329}
1330
1331/*
1332 * ":pyxdo"
1333 */
1334 void
1335ex_pyxdo(exarg_T *eap)
1336{
1337# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
1338 init_pyxversion();
1339 if (p_pyx == 2)
1340 ex_pydo(eap);
1341 else
1342 ex_py3do(eap);
1343# elif defined(FEAT_PYTHON)
1344 ex_pydo(eap);
1345# elif defined(FEAT_PYTHON3)
1346 ex_py3do(eap);
1347# endif
1348}
1349
1350#endif
1351
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353 * ":checktime [buffer]"
1354 */
1355 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001356ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001357{
1358 buf_T *buf;
1359 int save_no_check_timestamps = no_check_timestamps;
1360
1361 no_check_timestamps = 0;
1362 if (eap->addr_count == 0) /* default is all buffers */
1363 check_timestamps(FALSE);
1364 else
1365 {
1366 buf = buflist_findnr((int)eap->line2);
1367 if (buf != NULL) /* cannot happen? */
1368 (void)buf_check_timestamp(buf, FALSE);
1369 }
1370 no_check_timestamps = save_no_check_timestamps;
1371}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001372
Bram Moolenaar071d4272004-06-13 20:20:40 +00001373#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
1374 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001375# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001376 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001377get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001378{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001379 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001380
Bram Moolenaar48e330a2016-02-23 14:53:34 +01001381 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001382 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383
Bram Moolenaar4f974752019-02-17 17:44:42 +01001384# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001385 if (loc != NULL)
1386 {
1387 char_u *p;
1388
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001389 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
1390 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001391 p = vim_strchr(loc, '=');
1392 if (p != NULL)
1393 {
1394 loc = ++p;
1395 while (*p != NUL) /* remove trailing newline */
1396 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001397 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398 {
1399 *p = NUL;
1400 break;
1401 }
1402 ++p;
1403 }
1404 }
1405 }
1406# endif
1407
1408 return loc;
1409}
1410#endif
1411
1412
Bram Moolenaar4f974752019-02-17 17:44:42 +01001413#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001414/*
1415 * On MS-Windows locale names are strings like "German_Germany.1252", but
1416 * gettext expects "de". Try to translate one into another here for a few
1417 * supported languages.
1418 */
1419 static char_u *
1420gettext_lang(char_u *name)
1421{
1422 int i;
1423 static char *(mtable[]) = {
1424 "afrikaans", "af",
1425 "czech", "cs",
1426 "dutch", "nl",
1427 "german", "de",
1428 "english_united kingdom", "en_GB",
1429 "spanish", "es",
1430 "french", "fr",
1431 "italian", "it",
1432 "japanese", "ja",
1433 "korean", "ko",
1434 "norwegian", "no",
1435 "polish", "pl",
1436 "russian", "ru",
1437 "slovak", "sk",
1438 "swedish", "sv",
1439 "ukrainian", "uk",
1440 "chinese_china", "zh_CN",
1441 "chinese_taiwan", "zh_TW",
1442 NULL};
1443
1444 for (i = 0; mtable[i] != NULL; i += 2)
1445 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001446 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001447 return name;
1448}
1449#endif
1450
1451#if defined(FEAT_MULTI_LANG) || defined(PROTO)
1452/*
Bram Moolenaar389ab712018-11-05 20:25:52 +01001453 * Return TRUE when "lang" starts with a valid language name.
1454 * Rejects NULL, empty string, "C", "C.UTF-8" and others.
1455 */
1456 static int
1457is_valid_mess_lang(char_u *lang)
1458{
1459 return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
1460}
1461
1462/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001463 * Obtain the current messages language. Used to set the default for
1464 * 'helplang'. May return NULL or an empty string.
1465 */
1466 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001467get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468{
1469 char_u *p;
1470
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001471# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001472# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001473 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001474# else
1475 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001476 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
1477 * and LC_MONETARY may be set differently for a Japanese working in the
1478 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001479 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001480# endif
1481# else
1482 p = mch_getenv((char_u *)"LC_ALL");
Bram Moolenaar389ab712018-11-05 20:25:52 +01001483 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001484 {
1485 p = mch_getenv((char_u *)"LC_MESSAGES");
Bram Moolenaar389ab712018-11-05 20:25:52 +01001486 if (!is_valid_mess_lang(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001487 p = mch_getenv((char_u *)"LANG");
1488 }
1489# endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01001490# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001491 p = gettext_lang(p);
1492# endif
Bram Moolenaar389ab712018-11-05 20:25:52 +01001493 return is_valid_mess_lang(p) ? p : NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001494}
1495#endif
1496
Bram Moolenaardef9e822004-12-31 20:58:58 +00001497/* Complicated #if; matches with where get_mess_env() is used below. */
1498#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
1499 && defined(LC_MESSAGES))) \
1500 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
Bram Moolenaardef9e822004-12-31 20:58:58 +00001501 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001502/*
1503 * Get the language used for messages from the environment.
1504 */
1505 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001506get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507{
1508 char_u *p;
1509
1510 p = mch_getenv((char_u *)"LC_ALL");
1511 if (p == NULL || *p == NUL)
1512 {
1513 p = mch_getenv((char_u *)"LC_MESSAGES");
1514 if (p == NULL || *p == NUL)
1515 {
1516 p = mch_getenv((char_u *)"LANG");
1517 if (p != NULL && VIM_ISDIGIT(*p))
1518 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001519# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001521 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001522# endif
1523 }
1524 }
1525 return p;
1526}
1527#endif
1528
1529#if defined(FEAT_EVAL) || defined(PROTO)
1530
1531/*
1532 * Set the "v:lang" variable according to the current locale setting.
1533 * Also do "v:lc_time"and "v:ctype".
1534 */
1535 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001536set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001537{
1538 char_u *loc;
1539
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001540# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001541 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001542# else
1543 /* setlocale() not supported: use the default value */
1544 loc = (char_u *)"C";
1545# endif
1546 set_vim_var_string(VV_CTYPE, loc, -1);
1547
1548 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
1549 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001550# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001551 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001552# else
1553 loc = get_mess_env();
1554# endif
1555 set_vim_var_string(VV_LANG, loc, -1);
1556
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02001557# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01001558 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559# endif
1560 set_vim_var_string(VV_LC_TIME, loc, -1);
1561}
1562#endif
1563
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01001564#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565/*
1566 * ":language": Set the language (locale).
1567 */
1568 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001569ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001570{
1571 char *loc;
1572 char_u *p;
1573 char_u *name;
1574 int what = LC_ALL;
1575 char *whatstr = "";
1576#ifdef LC_MESSAGES
1577# define VIM_LC_MESSAGES LC_MESSAGES
1578#else
1579# define VIM_LC_MESSAGES 6789
1580#endif
1581
1582 name = eap->arg;
1583
1584 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
1585 * Allow abbreviation, but require at least 3 characters to avoid
1586 * confusion with a two letter language name "me" or "ct". */
1587 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01001588 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589 {
1590 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
1591 {
1592 what = VIM_LC_MESSAGES;
1593 name = skipwhite(p);
1594 whatstr = "messages ";
1595 }
1596 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
1597 {
1598 what = LC_CTYPE;
1599 name = skipwhite(p);
1600 whatstr = "ctype ";
1601 }
1602 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
1603 {
1604 what = LC_TIME;
1605 name = skipwhite(p);
1606 whatstr = "time ";
1607 }
1608 }
1609
1610 if (*name == NUL)
1611 {
1612#ifndef LC_MESSAGES
1613 if (what == VIM_LC_MESSAGES)
1614 p = get_mess_env();
1615 else
1616#endif
1617 p = (char_u *)setlocale(what, NULL);
1618 if (p == NULL || *p == NUL)
1619 p = (char_u *)"Unknown";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001620 smsg(_("Current %slanguage: \"%s\""), whatstr, p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 }
1622 else
1623 {
1624#ifndef LC_MESSAGES
1625 if (what == VIM_LC_MESSAGES)
1626 loc = "";
1627 else
1628#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001629 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001630 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00001631#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
1632 /* Make sure strtod() uses a decimal point, not a comma. */
1633 setlocale(LC_NUMERIC, "C");
1634#endif
1635 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636 if (loc == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001637 semsg(_("E197: Cannot set language to \"%s\""), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001638 else
1639 {
1640#ifdef HAVE_NL_MSG_CAT_CNTR
1641 /* Need to do this for GNU gettext, otherwise cached translations
1642 * will be used again. */
1643 extern int _nl_msg_cat_cntr;
1644
1645 ++_nl_msg_cat_cntr;
1646#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00001647 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
1649
1650 if (what != LC_TIME)
1651 {
1652 /* Tell gettext() what to translate to. It apparently doesn't
1653 * use the currently effective locale. Also do this when
1654 * FEAT_GETTEXT isn't defined, so that shell commands use this
1655 * value. */
1656 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00001657 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001658 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02001659
1660 /* Clear $LANGUAGE because GNU gettext uses it. */
1661 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar4f974752019-02-17 17:44:42 +01001662# ifdef MSWIN
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00001663 /* Apparently MS-Windows printf() may cause a crash when
1664 * we give it 8-bit text while it's expecting text in the
1665 * current locale. This call avoids that. */
1666 setlocale(LC_CTYPE, "C");
1667# endif
1668 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001669 if (what != LC_CTYPE)
1670 {
1671 char_u *mname;
Bram Moolenaar4f974752019-02-17 17:44:42 +01001672#ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001673 mname = gettext_lang(name);
1674#else
1675 mname = name;
1676#endif
1677 vim_setenv((char_u *)"LC_MESSAGES", mname);
1678#ifdef FEAT_MULTI_LANG
1679 set_helplang_default(mname);
1680#endif
1681 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682 }
1683
1684# ifdef FEAT_EVAL
1685 /* Set v:lang, v:lc_time and v:ctype to the final result. */
1686 set_lang_var();
1687# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02001688# ifdef FEAT_TITLE
1689 maketitle();
1690# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691 }
1692 }
1693}
1694
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001695static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001696
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001697# ifndef MSWIN
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001698static int did_init_locales = FALSE;
1699
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001700/*
1701 * Return an array of strings for all available locales + NULL for the
1702 * last element. Return NULL in case of error.
1703 */
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001704 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001705find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001706{
1707 garray_T locales_ga;
1708 char_u *loc;
1709
1710 /* Find all available locales by running command "locale -a". If this
1711 * doesn't work we won't have completion. */
1712 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02001713 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001714 if (locale_a == NULL)
1715 return NULL;
1716 ga_init2(&locales_ga, sizeof(char_u *), 20);
1717
1718 /* Transform locale_a string where each locale is separated by "\n"
1719 * into an array of locale strings. */
1720 loc = (char_u *)strtok((char *)locale_a, "\n");
1721
1722 while (loc != NULL)
1723 {
1724 if (ga_grow(&locales_ga, 1) == FAIL)
1725 break;
1726 loc = vim_strsave(loc);
1727 if (loc == NULL)
1728 break;
1729
1730 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
1731 loc = (char_u *)strtok(NULL, "\n");
1732 }
1733 vim_free(locale_a);
1734 if (ga_grow(&locales_ga, 1) == FAIL)
1735 {
1736 ga_clear(&locales_ga);
1737 return NULL;
1738 }
1739 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
1740 return (char_u **)locales_ga.ga_data;
1741}
Bram Moolenaar0a52df52019-08-18 22:26:31 +02001742# endif
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001743
1744/*
1745 * Lazy initialization of all available locales.
1746 */
1747 static void
1748init_locales(void)
1749{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001750# ifndef MSWIN
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01001751 if (!did_init_locales)
1752 {
1753 did_init_locales = TRUE;
1754 locales = find_locales();
1755 }
1756# endif
1757}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001758
1759# if defined(EXITFREE) || defined(PROTO)
1760 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001761free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001762{
1763 int i;
1764 if (locales != NULL)
1765 {
1766 for (i = 0; locales[i] != NULL; i++)
1767 vim_free(locales[i]);
Bram Moolenaard23a8232018-02-10 18:45:26 +01001768 VIM_CLEAR(locales);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001769 }
1770}
1771# endif
1772
Bram Moolenaar071d4272004-06-13 20:20:40 +00001773/*
1774 * Function given to ExpandGeneric() to obtain the possible arguments of the
1775 * ":language" command.
1776 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001778get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779{
1780 if (idx == 0)
1781 return (char_u *)"messages";
1782 if (idx == 1)
1783 return (char_u *)"ctype";
1784 if (idx == 2)
1785 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001786
1787 init_locales();
1788 if (locales == NULL)
1789 return NULL;
1790 return locales[idx - 3];
1791}
1792
1793/*
1794 * Function given to ExpandGeneric() to obtain the available locales.
1795 */
1796 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001797get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001798{
1799 init_locales();
1800 if (locales == NULL)
1801 return NULL;
1802 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001804
1805#endif