1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar *
3071d4279SBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4071d4279SBram Moolenaar *
5071d4279SBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar */
9071d4279SBram Moolenaar
10071d4279SBram Moolenaar /*
11071d4279SBram Moolenaar * ui.c: functions that handle the user interface.
12071d4279SBram Moolenaar * 1. Keyboard input stuff, and a bit of windowing stuff. These are called
13071d4279SBram Moolenaar * before the machine specific stuff (mch_*) so that we can call the GUI
14071d4279SBram Moolenaar * stuff instead if the GUI is running.
1545fffdf1SBram Moolenaar * 2. Input buffer stuff.
16071d4279SBram Moolenaar */
17071d4279SBram Moolenaar
18071d4279SBram Moolenaar #include "vim.h"
19071d4279SBram Moolenaar
20071d4279SBram Moolenaar void
ui_write(char_u * s,int len,int console UNUSED)214c86830fSBram Moolenaar ui_write(char_u *s, int len, int console UNUSED)
22071d4279SBram Moolenaar {
23071d4279SBram Moolenaar #ifdef FEAT_GUI
244c86830fSBram Moolenaar if (gui.in_use && !gui.dying && !gui.starting
254c86830fSBram Moolenaar # ifndef NO_CONSOLE
264c86830fSBram Moolenaar && !console
274c86830fSBram Moolenaar # endif
284c86830fSBram Moolenaar )
29071d4279SBram Moolenaar {
30071d4279SBram Moolenaar gui_write(s, len);
31071d4279SBram Moolenaar if (p_wd)
32c9e649aeSBram Moolenaar gui_wait_for_chars(p_wd, typebuf.tb_change_cnt);
33071d4279SBram Moolenaar return;
34071d4279SBram Moolenaar }
35071d4279SBram Moolenaar #endif
36071d4279SBram Moolenaar #ifndef NO_CONSOLE
37e38eab22SBram Moolenaar // Don't output anything in silent mode ("ex -s") unless 'verbose' set
38071d4279SBram Moolenaar if (!(silent_mode && p_verbose == 0))
39071d4279SBram Moolenaar {
404f97475dSBram Moolenaar # if !defined(MSWIN)
41071d4279SBram Moolenaar char_u *tofree = NULL;
42071d4279SBram Moolenaar
43071d4279SBram Moolenaar if (output_conv.vc_type != CONV_NONE)
44071d4279SBram Moolenaar {
45e38eab22SBram Moolenaar // Convert characters from 'encoding' to 'termencoding'.
46071d4279SBram Moolenaar tofree = string_convert(&output_conv, s, &len);
47071d4279SBram Moolenaar if (tofree != NULL)
48071d4279SBram Moolenaar s = tofree;
49071d4279SBram Moolenaar }
50071d4279SBram Moolenaar # endif
51071d4279SBram Moolenaar
52071d4279SBram Moolenaar mch_write(s, len);
535ea79a25SBram Moolenaar # if defined(HAVE_FSYNC)
544c86830fSBram Moolenaar if (console && s[len - 1] == '\n')
555ea79a25SBram Moolenaar vim_fsync(1);
565ea79a25SBram Moolenaar # endif
57071d4279SBram Moolenaar
584f97475dSBram Moolenaar # if !defined(MSWIN)
59071d4279SBram Moolenaar if (output_conv.vc_type != CONV_NONE)
60071d4279SBram Moolenaar vim_free(tofree);
61071d4279SBram Moolenaar # endif
62071d4279SBram Moolenaar }
63071d4279SBram Moolenaar #endif
64071d4279SBram Moolenaar }
65071d4279SBram Moolenaar
664f97475dSBram Moolenaar #if defined(UNIX) || defined(VMS) || defined(PROTO) || defined(MSWIN)
67071d4279SBram Moolenaar /*
68071d4279SBram Moolenaar * When executing an external program, there may be some typed characters that
69071d4279SBram Moolenaar * are not consumed by it. Give them back to ui_inchar() and they are stored
70071d4279SBram Moolenaar * here for the next call.
71071d4279SBram Moolenaar */
72071d4279SBram Moolenaar static char_u *ta_str = NULL;
73e38eab22SBram Moolenaar static int ta_off; // offset for next char to use when ta_str != NULL
74e38eab22SBram Moolenaar static int ta_len; // length of ta_str when it's not NULL
75071d4279SBram Moolenaar
76071d4279SBram Moolenaar void
ui_inchar_undo(char_u * s,int len)77764b23c8SBram Moolenaar ui_inchar_undo(char_u *s, int len)
78071d4279SBram Moolenaar {
79071d4279SBram Moolenaar char_u *new;
80071d4279SBram Moolenaar int newlen;
81071d4279SBram Moolenaar
82071d4279SBram Moolenaar newlen = len;
83071d4279SBram Moolenaar if (ta_str != NULL)
84071d4279SBram Moolenaar newlen += ta_len - ta_off;
85071d4279SBram Moolenaar new = alloc(newlen);
86071d4279SBram Moolenaar if (new != NULL)
87071d4279SBram Moolenaar {
88071d4279SBram Moolenaar if (ta_str != NULL)
89071d4279SBram Moolenaar {
90071d4279SBram Moolenaar mch_memmove(new, ta_str + ta_off, (size_t)(ta_len - ta_off));
91071d4279SBram Moolenaar mch_memmove(new + ta_len - ta_off, s, (size_t)len);
92071d4279SBram Moolenaar vim_free(ta_str);
93071d4279SBram Moolenaar }
94071d4279SBram Moolenaar else
95071d4279SBram Moolenaar mch_memmove(new, s, (size_t)len);
96071d4279SBram Moolenaar ta_str = new;
97071d4279SBram Moolenaar ta_len = newlen;
98071d4279SBram Moolenaar ta_off = 0;
99071d4279SBram Moolenaar }
100071d4279SBram Moolenaar }
101071d4279SBram Moolenaar #endif
102071d4279SBram Moolenaar
103071d4279SBram Moolenaar /*
104b6101cf7SBram Moolenaar * ui_inchar(): low level input function.
105071d4279SBram Moolenaar * Get characters from the keyboard.
106071d4279SBram Moolenaar * Return the number of characters that are available.
107071d4279SBram Moolenaar * If "wtime" == 0 do not wait for characters.
108071d4279SBram Moolenaar * If "wtime" == -1 wait forever for characters.
109071d4279SBram Moolenaar * If "wtime" > 0 wait "wtime" milliseconds for a character.
110071d4279SBram Moolenaar *
111071d4279SBram Moolenaar * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into
112071d4279SBram Moolenaar * it. When typebuf.tb_change_cnt changes (e.g., when a message is received
113071d4279SBram Moolenaar * from a remote client) "buf" can no longer be used. "tb_change_cnt" is NULL
114071d4279SBram Moolenaar * otherwise.
115071d4279SBram Moolenaar */
116071d4279SBram Moolenaar int
ui_inchar(char_u * buf,int maxlen,long wtime,int tb_change_cnt)117764b23c8SBram Moolenaar ui_inchar(
118764b23c8SBram Moolenaar char_u *buf,
119764b23c8SBram Moolenaar int maxlen,
120e38eab22SBram Moolenaar long wtime, // don't use "time", MIPS cannot handle it
121764b23c8SBram Moolenaar int tb_change_cnt)
122071d4279SBram Moolenaar {
123071d4279SBram Moolenaar int retval = 0;
124071d4279SBram Moolenaar
125071d4279SBram Moolenaar #if defined(FEAT_GUI) && (defined(UNIX) || defined(VMS))
126071d4279SBram Moolenaar /*
127071d4279SBram Moolenaar * Use the typeahead if there is any.
128071d4279SBram Moolenaar */
129071d4279SBram Moolenaar if (ta_str != NULL)
130071d4279SBram Moolenaar {
131071d4279SBram Moolenaar if (maxlen >= ta_len - ta_off)
132071d4279SBram Moolenaar {
133071d4279SBram Moolenaar mch_memmove(buf, ta_str + ta_off, (size_t)ta_len);
134d23a8236SBram Moolenaar VIM_CLEAR(ta_str);
135071d4279SBram Moolenaar return ta_len;
136071d4279SBram Moolenaar }
137071d4279SBram Moolenaar mch_memmove(buf, ta_str + ta_off, (size_t)maxlen);
138071d4279SBram Moolenaar ta_off += maxlen;
139071d4279SBram Moolenaar return maxlen;
140071d4279SBram Moolenaar }
141071d4279SBram Moolenaar #endif
142071d4279SBram Moolenaar
14305159a0cSBram Moolenaar #ifdef FEAT_PROFILE
144b3656edcSBram Moolenaar if (do_profiling == PROF_YES && wtime != 0)
14505159a0cSBram Moolenaar prof_inchar_enter();
14605159a0cSBram Moolenaar #endif
14705159a0cSBram Moolenaar
148071d4279SBram Moolenaar #ifdef NO_CONSOLE_INPUT
149e38eab22SBram Moolenaar // Don't wait for character input when the window hasn't been opened yet.
150e38eab22SBram Moolenaar // Do try reading, this works when redirecting stdin from a file.
151e38eab22SBram Moolenaar // Must return something, otherwise we'll loop forever. If we run into
152e38eab22SBram Moolenaar // this very often we probably got stuck, exit Vim.
153071d4279SBram Moolenaar if (no_console_input())
154071d4279SBram Moolenaar {
155071d4279SBram Moolenaar static int count = 0;
156071d4279SBram Moolenaar
157071d4279SBram Moolenaar # ifndef NO_CONSOLE
1581341024eSBram Moolenaar retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt);
15943b604cdSBram Moolenaar if (retval > 0 || typebuf_changed(tb_change_cnt) || wtime >= 0)
16005159a0cSBram Moolenaar goto theend;
161071d4279SBram Moolenaar # endif
162071d4279SBram Moolenaar if (wtime == -1 && ++count == 1000)
163071d4279SBram Moolenaar read_error_exit();
164071d4279SBram Moolenaar buf[0] = CAR;
16505159a0cSBram Moolenaar retval = 1;
16605159a0cSBram Moolenaar goto theend;
167071d4279SBram Moolenaar }
168071d4279SBram Moolenaar #endif
169071d4279SBram Moolenaar
170e38eab22SBram Moolenaar // If we are going to wait for some time or block...
171c8da3119SBram Moolenaar if (wtime == -1 || wtime > 100L)
172c8da3119SBram Moolenaar {
173e38eab22SBram Moolenaar // ... allow signals to kill us.
174c8da3119SBram Moolenaar (void)vim_handle_signal(SIGNAL_UNBLOCK);
175c8da3119SBram Moolenaar
176e38eab22SBram Moolenaar // ... there is no need for CTRL-C to interrupt something, don't let
177e38eab22SBram Moolenaar // it set got_int when it was mapped.
17850008697SBram Moolenaar if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state())
179071d4279SBram Moolenaar ctrl_c_interrupts = FALSE;
180c8da3119SBram Moolenaar }
181071d4279SBram Moolenaar
182e40b9d47SBram Moolenaar /*
183e40b9d47SBram Moolenaar * Here we call gui_inchar() or mch_inchar(), the GUI or machine-dependent
184e40b9d47SBram Moolenaar * input function. The functionality they implement is like this:
185e40b9d47SBram Moolenaar *
186e40b9d47SBram Moolenaar * while (not timed out)
187e40b9d47SBram Moolenaar * {
188e40b9d47SBram Moolenaar * handle-resize;
189e40b9d47SBram Moolenaar * parse-queued-messages;
190e40b9d47SBram Moolenaar * if (waited for 'updatetime')
191e40b9d47SBram Moolenaar * trigger-cursorhold;
192e40b9d47SBram Moolenaar * ui_wait_for_chars_or_timer()
193e40b9d47SBram Moolenaar * if (character available)
194e40b9d47SBram Moolenaar * break;
195e40b9d47SBram Moolenaar * }
196e40b9d47SBram Moolenaar *
197e40b9d47SBram Moolenaar * ui_wait_for_chars_or_timer() does:
198e40b9d47SBram Moolenaar *
199e40b9d47SBram Moolenaar * while (not timed out)
200e40b9d47SBram Moolenaar * {
201e40b9d47SBram Moolenaar * if (any-timer-triggered)
202e40b9d47SBram Moolenaar * invoke-timer-callback;
203e40b9d47SBram Moolenaar * wait-for-character();
204e40b9d47SBram Moolenaar * if (character available)
205e40b9d47SBram Moolenaar * break;
206e40b9d47SBram Moolenaar * }
207e40b9d47SBram Moolenaar *
208e40b9d47SBram Moolenaar * wait-for-character() does:
209e40b9d47SBram Moolenaar * while (not timed out)
210e40b9d47SBram Moolenaar * {
211e40b9d47SBram Moolenaar * Wait for event;
212e40b9d47SBram Moolenaar * if (something on channel)
213e40b9d47SBram Moolenaar * read/write channel;
214e40b9d47SBram Moolenaar * else if (resized)
215e40b9d47SBram Moolenaar * handle_resize();
216e40b9d47SBram Moolenaar * else if (system event)
217e40b9d47SBram Moolenaar * deal-with-system-event;
218e40b9d47SBram Moolenaar * else if (character available)
219e40b9d47SBram Moolenaar * break;
220e40b9d47SBram Moolenaar * }
221e40b9d47SBram Moolenaar *
222e40b9d47SBram Moolenaar */
223e40b9d47SBram Moolenaar
224071d4279SBram Moolenaar #ifdef FEAT_GUI
225071d4279SBram Moolenaar if (gui.in_use)
226c9e649aeSBram Moolenaar retval = gui_inchar(buf, maxlen, wtime, tb_change_cnt);
227071d4279SBram Moolenaar #endif
228071d4279SBram Moolenaar #ifndef NO_CONSOLE
229071d4279SBram Moolenaar # ifdef FEAT_GUI
230071d4279SBram Moolenaar else
231071d4279SBram Moolenaar # endif
232071d4279SBram Moolenaar retval = mch_inchar(buf, maxlen, wtime, tb_change_cnt);
233c8da3119SBram Moolenaar #endif
234c8da3119SBram Moolenaar
23546c9c73dSBram Moolenaar if (wtime == -1 || wtime > 100L)
236e38eab22SBram Moolenaar // block SIGHUP et al.
237e759a7aaSBram Moolenaar (void)vim_handle_signal(SIGNAL_BLOCK);
238071d4279SBram Moolenaar
239071d4279SBram Moolenaar ctrl_c_interrupts = TRUE;
240071d4279SBram Moolenaar
24105159a0cSBram Moolenaar #ifdef NO_CONSOLE_INPUT
24205159a0cSBram Moolenaar theend:
24305159a0cSBram Moolenaar #endif
24405159a0cSBram Moolenaar #ifdef FEAT_PROFILE
245b3656edcSBram Moolenaar if (do_profiling == PROF_YES && wtime != 0)
24605159a0cSBram Moolenaar prof_inchar_exit();
24705159a0cSBram Moolenaar #endif
248071d4279SBram Moolenaar return retval;
249071d4279SBram Moolenaar }
250071d4279SBram Moolenaar
25195f0b6e5SBram Moolenaar #if defined(UNIX) || defined(VMS) || defined(FEAT_GUI) || defined(PROTO)
252e40b9d47SBram Moolenaar /*
253e40b9d47SBram Moolenaar * Common code for mch_inchar() and gui_inchar(): Wait for a while or
254e40b9d47SBram Moolenaar * indefinitely until characters are available, dealing with timers and
255e40b9d47SBram Moolenaar * messages on channels.
256e40b9d47SBram Moolenaar *
257e40b9d47SBram Moolenaar * "buf" may be NULL if the available characters are not to be returned, only
258e40b9d47SBram Moolenaar * check if they are available.
259e40b9d47SBram Moolenaar *
260e40b9d47SBram Moolenaar * Return the number of characters that are available.
261e40b9d47SBram Moolenaar * If "wtime" == 0 do not wait for characters.
262e40b9d47SBram Moolenaar * If "wtime" == n wait a short time for characters.
263e40b9d47SBram Moolenaar * If "wtime" == -1 wait forever for characters.
264e40b9d47SBram Moolenaar */
265e40b9d47SBram Moolenaar int
inchar_loop(char_u * buf,int maxlen,long wtime,int tb_change_cnt,int (* wait_func)(long wtime,int * interrupted,int ignore_input),int (* resize_func)(int check_only))266e40b9d47SBram Moolenaar inchar_loop(
267e40b9d47SBram Moolenaar char_u *buf,
268e40b9d47SBram Moolenaar int maxlen,
269e40b9d47SBram Moolenaar long wtime, // don't use "time", MIPS cannot handle it
270e40b9d47SBram Moolenaar int tb_change_cnt,
271e40b9d47SBram Moolenaar int (*wait_func)(long wtime, int *interrupted, int ignore_input),
272e40b9d47SBram Moolenaar int (*resize_func)(int check_only))
273e40b9d47SBram Moolenaar {
274e40b9d47SBram Moolenaar int len;
275e40b9d47SBram Moolenaar int interrupted = FALSE;
27612dfc9eeSBram Moolenaar int did_call_wait_func = FALSE;
277e40b9d47SBram Moolenaar int did_start_blocking = FALSE;
278e40b9d47SBram Moolenaar long wait_time;
279e40b9d47SBram Moolenaar long elapsed_time = 0;
280e40b9d47SBram Moolenaar #ifdef ELAPSED_FUNC
281e40b9d47SBram Moolenaar elapsed_T start_tv;
282e40b9d47SBram Moolenaar
283e40b9d47SBram Moolenaar ELAPSED_INIT(start_tv);
284e40b9d47SBram Moolenaar #endif
285e40b9d47SBram Moolenaar
286e38eab22SBram Moolenaar // repeat until we got a character or waited long enough
287e40b9d47SBram Moolenaar for (;;)
288e40b9d47SBram Moolenaar {
289e38eab22SBram Moolenaar // Check if window changed size while we were busy, perhaps the ":set
290e38eab22SBram Moolenaar // columns=99" command was used.
291e40b9d47SBram Moolenaar if (resize_func != NULL)
292e40b9d47SBram Moolenaar resize_func(FALSE);
293e40b9d47SBram Moolenaar
294e40b9d47SBram Moolenaar #ifdef MESSAGE_QUEUE
295e40b9d47SBram Moolenaar // Only process messages when waiting.
296e40b9d47SBram Moolenaar if (wtime != 0)
297e40b9d47SBram Moolenaar {
298e40b9d47SBram Moolenaar parse_queued_messages();
299e40b9d47SBram Moolenaar // If input was put directly in typeahead buffer bail out here.
300e40b9d47SBram Moolenaar if (typebuf_changed(tb_change_cnt))
301e40b9d47SBram Moolenaar return 0;
302e40b9d47SBram Moolenaar }
303e40b9d47SBram Moolenaar #endif
304e40b9d47SBram Moolenaar if (wtime < 0 && did_start_blocking)
305e40b9d47SBram Moolenaar // blocking and already waited for p_ut
306e40b9d47SBram Moolenaar wait_time = -1;
307e40b9d47SBram Moolenaar else
308e40b9d47SBram Moolenaar {
309e40b9d47SBram Moolenaar if (wtime >= 0)
310e40b9d47SBram Moolenaar wait_time = wtime;
311e40b9d47SBram Moolenaar else
312e40b9d47SBram Moolenaar // going to block after p_ut
313e40b9d47SBram Moolenaar wait_time = p_ut;
314e40b9d47SBram Moolenaar #ifdef ELAPSED_FUNC
315e40b9d47SBram Moolenaar elapsed_time = ELAPSED_FUNC(start_tv);
316e40b9d47SBram Moolenaar #endif
317e40b9d47SBram Moolenaar wait_time -= elapsed_time;
31812dfc9eeSBram Moolenaar
31912dfc9eeSBram Moolenaar // If the waiting time is now zero or less, we timed out. However,
32012dfc9eeSBram Moolenaar // loop at least once to check for characters and events. Matters
32112dfc9eeSBram Moolenaar // when "wtime" is zero.
32212dfc9eeSBram Moolenaar if (wait_time <= 0 && did_call_wait_func)
323e40b9d47SBram Moolenaar {
324e40b9d47SBram Moolenaar if (wtime >= 0)
325e40b9d47SBram Moolenaar // no character available within "wtime"
326e40b9d47SBram Moolenaar return 0;
327e40b9d47SBram Moolenaar
328e40b9d47SBram Moolenaar // No character available within 'updatetime'.
329e40b9d47SBram Moolenaar did_start_blocking = TRUE;
330e40b9d47SBram Moolenaar if (trigger_cursorhold() && maxlen >= 3
331e40b9d47SBram Moolenaar && !typebuf_changed(tb_change_cnt))
332e40b9d47SBram Moolenaar {
333e40b9d47SBram Moolenaar // Put K_CURSORHOLD in the input buffer or return it.
334e40b9d47SBram Moolenaar if (buf == NULL)
335e40b9d47SBram Moolenaar {
336e40b9d47SBram Moolenaar char_u ibuf[3];
337e40b9d47SBram Moolenaar
338e40b9d47SBram Moolenaar ibuf[0] = CSI;
339e40b9d47SBram Moolenaar ibuf[1] = KS_EXTRA;
340e40b9d47SBram Moolenaar ibuf[2] = (int)KE_CURSORHOLD;
341e40b9d47SBram Moolenaar add_to_input_buf(ibuf, 3);
342e40b9d47SBram Moolenaar }
343e40b9d47SBram Moolenaar else
344e40b9d47SBram Moolenaar {
345e40b9d47SBram Moolenaar buf[0] = K_SPECIAL;
346e40b9d47SBram Moolenaar buf[1] = KS_EXTRA;
347e40b9d47SBram Moolenaar buf[2] = (int)KE_CURSORHOLD;
348e40b9d47SBram Moolenaar }
349e40b9d47SBram Moolenaar return 3;
350e40b9d47SBram Moolenaar }
351e40b9d47SBram Moolenaar
352e40b9d47SBram Moolenaar // There is no character available within 'updatetime' seconds:
353e40b9d47SBram Moolenaar // flush all the swap files to disk. Also done when
354e40b9d47SBram Moolenaar // interrupted by SIGWINCH.
355e40b9d47SBram Moolenaar before_blocking();
356e40b9d47SBram Moolenaar continue;
357e40b9d47SBram Moolenaar }
358e40b9d47SBram Moolenaar }
359e40b9d47SBram Moolenaar
360e40b9d47SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
361e40b9d47SBram Moolenaar if (wait_time < 0 || wait_time > 100L)
362e40b9d47SBram Moolenaar {
363e40b9d47SBram Moolenaar // Checking if a job ended requires polling. Do this at least
364e40b9d47SBram Moolenaar // every 100 msec.
365e40b9d47SBram Moolenaar if (has_pending_job())
366e40b9d47SBram Moolenaar wait_time = 100L;
367e40b9d47SBram Moolenaar
368e40b9d47SBram Moolenaar // If there is readahead then parse_queued_messages() timed out and
369e40b9d47SBram Moolenaar // we should call it again soon.
370e40b9d47SBram Moolenaar if (channel_any_readahead())
371e40b9d47SBram Moolenaar wait_time = 10L;
372e40b9d47SBram Moolenaar }
373e40b9d47SBram Moolenaar #endif
374e40b9d47SBram Moolenaar #ifdef FEAT_BEVAL_GUI
375e40b9d47SBram Moolenaar if (p_beval && wait_time > 100L)
376e40b9d47SBram Moolenaar // The 'balloonexpr' may indirectly invoke a callback while waiting
377e40b9d47SBram Moolenaar // for a character, need to check often.
378e40b9d47SBram Moolenaar wait_time = 100L;
379e40b9d47SBram Moolenaar #endif
380e40b9d47SBram Moolenaar
381e40b9d47SBram Moolenaar // Wait for a character to be typed or another event, such as the winch
382e40b9d47SBram Moolenaar // signal or an event on the monitored file descriptors.
38312dfc9eeSBram Moolenaar did_call_wait_func = TRUE;
384e40b9d47SBram Moolenaar if (wait_func(wait_time, &interrupted, FALSE))
385e40b9d47SBram Moolenaar {
386e40b9d47SBram Moolenaar // If input was put directly in typeahead buffer bail out here.
387e40b9d47SBram Moolenaar if (typebuf_changed(tb_change_cnt))
388e40b9d47SBram Moolenaar return 0;
389e40b9d47SBram Moolenaar
390e40b9d47SBram Moolenaar // We might have something to return now.
391e40b9d47SBram Moolenaar if (buf == NULL)
392e40b9d47SBram Moolenaar // "buf" is NULL, we were just waiting, not actually getting
393e40b9d47SBram Moolenaar // input.
394e40b9d47SBram Moolenaar return input_available();
395e40b9d47SBram Moolenaar
396e40b9d47SBram Moolenaar len = read_from_input_buf(buf, (long)maxlen);
397e40b9d47SBram Moolenaar if (len > 0)
398e40b9d47SBram Moolenaar return len;
399e40b9d47SBram Moolenaar continue;
400e40b9d47SBram Moolenaar }
401e40b9d47SBram Moolenaar // Timed out or interrupted with no character available.
402e40b9d47SBram Moolenaar
403e40b9d47SBram Moolenaar #ifndef ELAPSED_FUNC
404e40b9d47SBram Moolenaar // estimate the elapsed time
405e40b9d47SBram Moolenaar elapsed_time += wait_time;
406e40b9d47SBram Moolenaar #endif
407e40b9d47SBram Moolenaar
408e40b9d47SBram Moolenaar if ((resize_func != NULL && resize_func(TRUE))
4093e9d4d85SBram Moolenaar #if defined(FEAT_CLIENTSERVER) && defined(UNIX)
410e40b9d47SBram Moolenaar || server_waiting()
411e40b9d47SBram Moolenaar #endif
412e40b9d47SBram Moolenaar #ifdef MESSAGE_QUEUE
413e40b9d47SBram Moolenaar || interrupted
414e40b9d47SBram Moolenaar #endif
415e40b9d47SBram Moolenaar || wait_time > 0
416e40b9d47SBram Moolenaar || (wtime < 0 && !did_start_blocking))
417e40b9d47SBram Moolenaar // no character available, but something to be done, keep going
418e40b9d47SBram Moolenaar continue;
419e40b9d47SBram Moolenaar
420e40b9d47SBram Moolenaar // no character available or interrupted, return zero
421e40b9d47SBram Moolenaar break;
422e40b9d47SBram Moolenaar }
423e40b9d47SBram Moolenaar return 0;
424e40b9d47SBram Moolenaar }
425e40b9d47SBram Moolenaar #endif
426e40b9d47SBram Moolenaar
427c46af534SBram Moolenaar #if defined(FEAT_TIMERS) || defined(PROTO)
428c9e649aeSBram Moolenaar /*
429c9e649aeSBram Moolenaar * Wait for a timer to fire or "wait_func" to return non-zero.
430c9e649aeSBram Moolenaar * Returns OK when something was read.
431c9e649aeSBram Moolenaar * Returns FAIL when it timed out or was interrupted.
432c9e649aeSBram Moolenaar */
433c9e649aeSBram Moolenaar int
ui_wait_for_chars_or_timer(long wtime,int (* wait_func)(long wtime,int * interrupted,int ignore_input),int * interrupted,int ignore_input)434c9e649aeSBram Moolenaar ui_wait_for_chars_or_timer(
435c9e649aeSBram Moolenaar long wtime,
436c9e649aeSBram Moolenaar int (*wait_func)(long wtime, int *interrupted, int ignore_input),
437c9e649aeSBram Moolenaar int *interrupted,
438c9e649aeSBram Moolenaar int ignore_input)
439c9e649aeSBram Moolenaar {
440c9e649aeSBram Moolenaar int due_time;
441c9e649aeSBram Moolenaar long remaining = wtime;
442c9e649aeSBram Moolenaar int tb_change_cnt = typebuf.tb_change_cnt;
443c46af534SBram Moolenaar # ifdef FEAT_JOB_CHANNEL
444e299bbdfSBram Moolenaar int brief_wait = FALSE;
445c46af534SBram Moolenaar # endif
446c9e649aeSBram Moolenaar
447c46af534SBram Moolenaar // When waiting very briefly don't trigger timers.
448c9e649aeSBram Moolenaar if (wtime >= 0 && wtime < 10L)
449c9e649aeSBram Moolenaar return wait_func(wtime, NULL, ignore_input);
450c9e649aeSBram Moolenaar
451c9e649aeSBram Moolenaar while (wtime < 0 || remaining > 0)
452c9e649aeSBram Moolenaar {
453c46af534SBram Moolenaar // Trigger timers and then get the time in wtime until the next one is
454c46af534SBram Moolenaar // due. Wait up to that time.
455c9e649aeSBram Moolenaar due_time = check_due_timer();
456c9e649aeSBram Moolenaar if (typebuf.tb_change_cnt != tb_change_cnt)
457c9e649aeSBram Moolenaar {
458e38eab22SBram Moolenaar // timer may have used feedkeys()
459c9e649aeSBram Moolenaar return FAIL;
460c9e649aeSBram Moolenaar }
461c9e649aeSBram Moolenaar if (due_time <= 0 || (wtime > 0 && due_time > remaining))
462c9e649aeSBram Moolenaar due_time = remaining;
46328e67e0cSBram Moolenaar # if defined(FEAT_JOB_CHANNEL) || defined(FEAT_SOUND_CANBERRA)
46428e67e0cSBram Moolenaar if ((due_time < 0 || due_time > 10L) && (
46528e67e0cSBram Moolenaar # if defined(FEAT_JOB_CHANNEL)
46628e67e0cSBram Moolenaar (
46728e67e0cSBram Moolenaar # if defined(FEAT_GUI)
46828e67e0cSBram Moolenaar !gui.in_use &&
469c46af534SBram Moolenaar # endif
47028e67e0cSBram Moolenaar (has_pending_job() || channel_any_readahead()))
47128e67e0cSBram Moolenaar # ifdef FEAT_SOUND_CANBERRA
47228e67e0cSBram Moolenaar ||
47328e67e0cSBram Moolenaar # endif
47428e67e0cSBram Moolenaar # endif
47528e67e0cSBram Moolenaar # ifdef FEAT_SOUND_CANBERRA
47628e67e0cSBram Moolenaar has_any_sound_callback()
47728e67e0cSBram Moolenaar # endif
47828e67e0cSBram Moolenaar ))
479c46af534SBram Moolenaar {
480c46af534SBram Moolenaar // There is a pending job or channel, should return soon in order
481c46af534SBram Moolenaar // to handle them ASAP. Do check for input briefly.
482c46af534SBram Moolenaar due_time = 10L;
4836cdce2a0SBram Moolenaar # ifdef FEAT_JOB_CHANNEL
484c46af534SBram Moolenaar brief_wait = TRUE;
4856cdce2a0SBram Moolenaar # endif
486c46af534SBram Moolenaar }
487c46af534SBram Moolenaar # endif
488c9e649aeSBram Moolenaar if (wait_func(due_time, interrupted, ignore_input))
489c9e649aeSBram Moolenaar return OK;
490c46af534SBram Moolenaar if ((interrupted != NULL && *interrupted)
491c46af534SBram Moolenaar # ifdef FEAT_JOB_CHANNEL
492c46af534SBram Moolenaar || brief_wait
493c46af534SBram Moolenaar # endif
494c46af534SBram Moolenaar )
495c46af534SBram Moolenaar // Nothing available, but need to return so that side effects get
496c46af534SBram Moolenaar // handled, such as handling a message on a channel.
497a338adcfSBram Moolenaar return FAIL;
498c9e649aeSBram Moolenaar if (wtime > 0)
499c9e649aeSBram Moolenaar remaining -= due_time;
500c9e649aeSBram Moolenaar }
501c9e649aeSBram Moolenaar return FAIL;
502c9e649aeSBram Moolenaar }
503c9e649aeSBram Moolenaar #endif
504c9e649aeSBram Moolenaar
505071d4279SBram Moolenaar /*
506c46af534SBram Moolenaar * Return non-zero if a character is available.
507071d4279SBram Moolenaar */
508071d4279SBram Moolenaar int
ui_char_avail(void)509764b23c8SBram Moolenaar ui_char_avail(void)
510071d4279SBram Moolenaar {
511071d4279SBram Moolenaar #ifdef FEAT_GUI
512071d4279SBram Moolenaar if (gui.in_use)
513071d4279SBram Moolenaar {
514071d4279SBram Moolenaar gui_mch_update();
515071d4279SBram Moolenaar return input_available();
516071d4279SBram Moolenaar }
517071d4279SBram Moolenaar #endif
518071d4279SBram Moolenaar #ifndef NO_CONSOLE
519071d4279SBram Moolenaar # ifdef NO_CONSOLE_INPUT
520071d4279SBram Moolenaar if (no_console_input())
521071d4279SBram Moolenaar return 0;
522071d4279SBram Moolenaar # endif
523071d4279SBram Moolenaar return mch_char_avail();
524071d4279SBram Moolenaar #else
525071d4279SBram Moolenaar return 0;
526071d4279SBram Moolenaar #endif
527071d4279SBram Moolenaar }
528071d4279SBram Moolenaar
529071d4279SBram Moolenaar /*
530071d4279SBram Moolenaar * Delay for the given number of milliseconds. If ignoreinput is FALSE then we
531071d4279SBram Moolenaar * cancel the delay if a key is hit.
532071d4279SBram Moolenaar */
533071d4279SBram Moolenaar void
ui_delay(long msec_arg,int ignoreinput)534b340baedSBram Moolenaar ui_delay(long msec_arg, int ignoreinput)
535071d4279SBram Moolenaar {
536b340baedSBram Moolenaar long msec = msec_arg;
537b340baedSBram Moolenaar
538b340baedSBram Moolenaar #ifdef FEAT_EVAL
539b340baedSBram Moolenaar if (ui_delay_for_testing > 0)
540b340baedSBram Moolenaar msec = ui_delay_for_testing;
541b340baedSBram Moolenaar #endif
542eda1da0cSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
543eda1da0cSBram Moolenaar ch_log(NULL, "ui_delay(%ld)", msec);
544eda1da0cSBram Moolenaar #endif
545071d4279SBram Moolenaar #ifdef FEAT_GUI
546071d4279SBram Moolenaar if (gui.in_use && !ignoreinput)
547c9e649aeSBram Moolenaar gui_wait_for_chars(msec, typebuf.tb_change_cnt);
548071d4279SBram Moolenaar else
549071d4279SBram Moolenaar #endif
5500981c872SBram Moolenaar mch_delay(msec, ignoreinput ? MCH_DELAY_IGNOREINPUT : 0);
551071d4279SBram Moolenaar }
552071d4279SBram Moolenaar
553071d4279SBram Moolenaar /*
554071d4279SBram Moolenaar * If the machine has job control, use it to suspend the program,
555071d4279SBram Moolenaar * otherwise fake it by starting a new shell.
556071d4279SBram Moolenaar * When running the GUI iconify the window.
557071d4279SBram Moolenaar */
558071d4279SBram Moolenaar void
ui_suspend(void)559764b23c8SBram Moolenaar ui_suspend(void)
560071d4279SBram Moolenaar {
561071d4279SBram Moolenaar #ifdef FEAT_GUI
562071d4279SBram Moolenaar if (gui.in_use)
563071d4279SBram Moolenaar {
564071d4279SBram Moolenaar gui_mch_iconify();
565071d4279SBram Moolenaar return;
566071d4279SBram Moolenaar }
567071d4279SBram Moolenaar #endif
568071d4279SBram Moolenaar mch_suspend();
569071d4279SBram Moolenaar }
570071d4279SBram Moolenaar
571041c7107SBram Moolenaar #if !defined(UNIX) || !defined(SIGTSTP) || defined(PROTO)
572071d4279SBram Moolenaar /*
573071d4279SBram Moolenaar * When the OS can't really suspend, call this function to start a shell.
574071d4279SBram Moolenaar * This is never called in the GUI.
575071d4279SBram Moolenaar */
576071d4279SBram Moolenaar void
suspend_shell(void)577764b23c8SBram Moolenaar suspend_shell(void)
578071d4279SBram Moolenaar {
579071d4279SBram Moolenaar if (*p_sh == NUL)
580f9e3e09fSBram Moolenaar emsg(_(e_shellempty));
581071d4279SBram Moolenaar else
582071d4279SBram Moolenaar {
58332526b3cSBram Moolenaar msg_puts(_("new shell started\n"));
584071d4279SBram Moolenaar do_shell(NULL, 0);
585071d4279SBram Moolenaar }
586071d4279SBram Moolenaar }
587071d4279SBram Moolenaar #endif
588071d4279SBram Moolenaar
589071d4279SBram Moolenaar /*
590071d4279SBram Moolenaar * Try to get the current Vim shell size. Put the result in Rows and Columns.
591071d4279SBram Moolenaar * Use the new sizes as defaults for 'columns' and 'lines'.
592071d4279SBram Moolenaar * Return OK when size could be determined, FAIL otherwise.
593071d4279SBram Moolenaar */
594071d4279SBram Moolenaar int
ui_get_shellsize(void)595764b23c8SBram Moolenaar ui_get_shellsize(void)
596071d4279SBram Moolenaar {
597071d4279SBram Moolenaar int retval;
598071d4279SBram Moolenaar
599071d4279SBram Moolenaar #ifdef FEAT_GUI
600071d4279SBram Moolenaar if (gui.in_use)
601071d4279SBram Moolenaar retval = gui_get_shellsize();
602071d4279SBram Moolenaar else
603071d4279SBram Moolenaar #endif
604071d4279SBram Moolenaar retval = mch_get_shellsize();
605071d4279SBram Moolenaar
606071d4279SBram Moolenaar check_shellsize();
607071d4279SBram Moolenaar
608e38eab22SBram Moolenaar // adjust the default for 'lines' and 'columns'
609071d4279SBram Moolenaar if (retval == OK)
610071d4279SBram Moolenaar {
611071d4279SBram Moolenaar set_number_default("lines", Rows);
612071d4279SBram Moolenaar set_number_default("columns", Columns);
613071d4279SBram Moolenaar }
614071d4279SBram Moolenaar return retval;
615071d4279SBram Moolenaar }
616071d4279SBram Moolenaar
617071d4279SBram Moolenaar /*
618071d4279SBram Moolenaar * Set the size of the Vim shell according to Rows and Columns, if possible.
619071d4279SBram Moolenaar * The gui_set_shellsize() or mch_set_shellsize() function will try to set the
620071d4279SBram Moolenaar * new size. If this is not possible, it will adjust Rows and Columns.
621071d4279SBram Moolenaar */
622071d4279SBram Moolenaar void
ui_set_shellsize(int mustset UNUSED)623764b23c8SBram Moolenaar ui_set_shellsize(
624e38eab22SBram Moolenaar int mustset UNUSED) // set by the user
625071d4279SBram Moolenaar {
626071d4279SBram Moolenaar #ifdef FEAT_GUI
627071d4279SBram Moolenaar if (gui.in_use)
6288968a311SBram Moolenaar gui_set_shellsize(mustset, TRUE, RESIZE_BOTH);
629071d4279SBram Moolenaar else
630071d4279SBram Moolenaar #endif
631071d4279SBram Moolenaar mch_set_shellsize();
632071d4279SBram Moolenaar }
633071d4279SBram Moolenaar
634071d4279SBram Moolenaar /*
635071d4279SBram Moolenaar * Called when Rows and/or Columns changed. Adjust scroll region and mouse
636071d4279SBram Moolenaar * region.
637071d4279SBram Moolenaar */
638071d4279SBram Moolenaar void
ui_new_shellsize(void)639764b23c8SBram Moolenaar ui_new_shellsize(void)
640071d4279SBram Moolenaar {
641071d4279SBram Moolenaar if (full_screen && !exiting)
642071d4279SBram Moolenaar {
643071d4279SBram Moolenaar #ifdef FEAT_GUI
644071d4279SBram Moolenaar if (gui.in_use)
645071d4279SBram Moolenaar gui_new_shellsize();
646071d4279SBram Moolenaar else
647071d4279SBram Moolenaar #endif
648071d4279SBram Moolenaar mch_new_shellsize();
649071d4279SBram Moolenaar }
650071d4279SBram Moolenaar }
651071d4279SBram Moolenaar
6526bc9305aSBram Moolenaar #if ((defined(FEAT_EVAL) || defined(FEAT_TERMINAL)) \
653fa1e90cdSBram Moolenaar && (defined(FEAT_GUI) \
65416c34c37SBram Moolenaar || defined(MSWIN) \
655fa1e90cdSBram Moolenaar || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)))) \
656fa1e90cdSBram Moolenaar || defined(PROTO)
657fa1e90cdSBram Moolenaar /*
658fa1e90cdSBram Moolenaar * Get the window position in pixels, if possible.
659fa1e90cdSBram Moolenaar * Return FAIL when not possible.
660fa1e90cdSBram Moolenaar */
661fa1e90cdSBram Moolenaar int
ui_get_winpos(int * x,int * y,varnumber_T timeout UNUSED)662bd67aac2SBram Moolenaar ui_get_winpos(int *x, int *y, varnumber_T timeout UNUSED)
663fa1e90cdSBram Moolenaar {
664fa1e90cdSBram Moolenaar # ifdef FEAT_GUI
665fa1e90cdSBram Moolenaar if (gui.in_use)
666fa1e90cdSBram Moolenaar return gui_mch_get_winpos(x, y);
667fa1e90cdSBram Moolenaar # endif
668afde13b6SBram Moolenaar # if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
66916c34c37SBram Moolenaar return mch_get_winpos(x, y);
67016c34c37SBram Moolenaar # else
671fa1e90cdSBram Moolenaar # if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
672fa1e90cdSBram Moolenaar return term_get_winpos(x, y, timeout);
6736bc9305aSBram Moolenaar # else
6746bc9305aSBram Moolenaar return FAIL;
675fa1e90cdSBram Moolenaar # endif
67616c34c37SBram Moolenaar # endif
677fa1e90cdSBram Moolenaar }
678fa1e90cdSBram Moolenaar #endif
679fa1e90cdSBram Moolenaar
680071d4279SBram Moolenaar void
ui_breakcheck(void)681764b23c8SBram Moolenaar ui_breakcheck(void)
682071d4279SBram Moolenaar {
683b9c31e71SBram Moolenaar ui_breakcheck_force(FALSE);
684b9c31e71SBram Moolenaar }
685b9c31e71SBram Moolenaar
686b9c31e71SBram Moolenaar /*
687b9c31e71SBram Moolenaar * When "force" is true also check when the terminal is not in raw mode.
688b9c31e71SBram Moolenaar * This is useful to read input on channels.
689b9c31e71SBram Moolenaar */
690b9c31e71SBram Moolenaar void
ui_breakcheck_force(int force)691b9c31e71SBram Moolenaar ui_breakcheck_force(int force)
692b9c31e71SBram Moolenaar {
69348d23bb4SBram Moolenaar static int recursive = FALSE;
69442335f50SBram Moolenaar int save_updating_screen = updating_screen;
695e3caa110SBram Moolenaar
69648d23bb4SBram Moolenaar // We could be called recursively if stderr is redirected, calling
69748d23bb4SBram Moolenaar // fill_input_buf() calls settmode() when stdin isn't a tty. settmode()
69848d23bb4SBram Moolenaar // calls vgetorpeek() which calls ui_breakcheck() again.
69948d23bb4SBram Moolenaar if (recursive)
70048d23bb4SBram Moolenaar return;
70148d23bb4SBram Moolenaar recursive = TRUE;
70248d23bb4SBram Moolenaar
70348d23bb4SBram Moolenaar // We do not want gui_resize_shell() to redraw the screen here.
704e3caa110SBram Moolenaar ++updating_screen;
705e3caa110SBram Moolenaar
706071d4279SBram Moolenaar #ifdef FEAT_GUI
707071d4279SBram Moolenaar if (gui.in_use)
708071d4279SBram Moolenaar gui_mch_update();
709071d4279SBram Moolenaar else
710071d4279SBram Moolenaar #endif
711b9c31e71SBram Moolenaar mch_breakcheck(force);
712e3caa110SBram Moolenaar
71342335f50SBram Moolenaar if (save_updating_screen)
71442335f50SBram Moolenaar updating_screen = TRUE;
7150cb8ac71SBram Moolenaar else
71668a4b04aSBram Moolenaar after_updating_screen(FALSE);
71748d23bb4SBram Moolenaar
71848d23bb4SBram Moolenaar recursive = FALSE;
719071d4279SBram Moolenaar }
720071d4279SBram Moolenaar
721e38eab22SBram Moolenaar //////////////////////////////////////////////////////////////////////////////
722e38eab22SBram Moolenaar // Functions that handle the input buffer.
723e38eab22SBram Moolenaar // This is used for any GUI version, and the unix terminal version.
724e38eab22SBram Moolenaar //
725e38eab22SBram Moolenaar // For Unix, the input characters are buffered to be able to check for a
726e38eab22SBram Moolenaar // CTRL-C. This should be done with signals, but I don't know how to do that
727e38eab22SBram Moolenaar // in a portable way for a tty in RAW mode.
728e38eab22SBram Moolenaar //
729e38eab22SBram Moolenaar // For the client-server code in the console the received keys are put in the
730e38eab22SBram Moolenaar // input buffer.
731071d4279SBram Moolenaar
732071d4279SBram Moolenaar #if defined(USE_INPUT_BUF) || defined(PROTO)
733071d4279SBram Moolenaar
734071d4279SBram Moolenaar /*
735071d4279SBram Moolenaar * Internal typeahead buffer. Includes extra space for long key code
736071d4279SBram Moolenaar * descriptions which would otherwise overflow. The buffer is considered full
737071d4279SBram Moolenaar * when only this extra space (or part of it) remains.
738071d4279SBram Moolenaar */
739bb1969b6SBram Moolenaar #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_CLIENTSERVER)
740071d4279SBram Moolenaar /*
741bb1969b6SBram Moolenaar * NetBeans stuffs debugger commands into the input buffer.
742071d4279SBram Moolenaar * This requires a larger buffer...
743071d4279SBram Moolenaar * (Madsen) Go with this for remote input as well ...
744071d4279SBram Moolenaar */
745071d4279SBram Moolenaar # define INBUFLEN 4096
746071d4279SBram Moolenaar #else
747071d4279SBram Moolenaar # define INBUFLEN 250
748071d4279SBram Moolenaar #endif
749071d4279SBram Moolenaar
750071d4279SBram Moolenaar static char_u inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
751e38eab22SBram Moolenaar static int inbufcount = 0; // number of chars in inbuf[]
752071d4279SBram Moolenaar
753071d4279SBram Moolenaar /*
754071d4279SBram Moolenaar * vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and
755071d4279SBram Moolenaar * trash_input_buf() are functions for manipulating the input buffer. These
756071d4279SBram Moolenaar * are used by the gui_* calls when a GUI is used to handle keyboard input.
757071d4279SBram Moolenaar */
758071d4279SBram Moolenaar
759071d4279SBram Moolenaar int
vim_is_input_buf_full(void)760764b23c8SBram Moolenaar vim_is_input_buf_full(void)
761071d4279SBram Moolenaar {
762071d4279SBram Moolenaar return (inbufcount >= INBUFLEN);
763071d4279SBram Moolenaar }
764071d4279SBram Moolenaar
765071d4279SBram Moolenaar int
vim_is_input_buf_empty(void)766764b23c8SBram Moolenaar vim_is_input_buf_empty(void)
767071d4279SBram Moolenaar {
768071d4279SBram Moolenaar return (inbufcount == 0);
769071d4279SBram Moolenaar }
770071d4279SBram Moolenaar
771071d4279SBram Moolenaar #if defined(FEAT_OLE) || defined(PROTO)
772071d4279SBram Moolenaar int
vim_free_in_input_buf(void)773764b23c8SBram Moolenaar vim_free_in_input_buf(void)
774071d4279SBram Moolenaar {
775071d4279SBram Moolenaar return (INBUFLEN - inbufcount);
776071d4279SBram Moolenaar }
777071d4279SBram Moolenaar #endif
778071d4279SBram Moolenaar
779241a8aaaSBram Moolenaar #if defined(FEAT_GUI_GTK) || defined(PROTO)
780071d4279SBram Moolenaar int
vim_used_in_input_buf(void)781764b23c8SBram Moolenaar vim_used_in_input_buf(void)
782071d4279SBram Moolenaar {
783071d4279SBram Moolenaar return inbufcount;
784071d4279SBram Moolenaar }
785071d4279SBram Moolenaar #endif
786071d4279SBram Moolenaar
787071d4279SBram Moolenaar /*
788071d4279SBram Moolenaar * Return the current contents of the input buffer and make it empty.
789071d4279SBram Moolenaar * The returned pointer must be passed to set_input_buf() later.
790071d4279SBram Moolenaar */
791071d4279SBram Moolenaar char_u *
get_input_buf(void)792764b23c8SBram Moolenaar get_input_buf(void)
793071d4279SBram Moolenaar {
794071d4279SBram Moolenaar garray_T *gap;
795071d4279SBram Moolenaar
796e38eab22SBram Moolenaar // We use a growarray to store the data pointer and the length.
797c799fe20SBram Moolenaar gap = ALLOC_ONE(garray_T);
798071d4279SBram Moolenaar if (gap != NULL)
799071d4279SBram Moolenaar {
800e38eab22SBram Moolenaar // Add one to avoid a zero size.
80118a4ba29SBram Moolenaar gap->ga_data = alloc(inbufcount + 1);
802071d4279SBram Moolenaar if (gap->ga_data != NULL)
803071d4279SBram Moolenaar mch_memmove(gap->ga_data, inbuf, (size_t)inbufcount);
804071d4279SBram Moolenaar gap->ga_len = inbufcount;
805071d4279SBram Moolenaar }
806071d4279SBram Moolenaar trash_input_buf();
807071d4279SBram Moolenaar return (char_u *)gap;
808071d4279SBram Moolenaar }
809071d4279SBram Moolenaar
810071d4279SBram Moolenaar /*
811071d4279SBram Moolenaar * Restore the input buffer with a pointer returned from get_input_buf().
812071d4279SBram Moolenaar * The allocated memory is freed, this only works once!
813c41badb7SBram Moolenaar * When "overwrite" is FALSE input typed later is kept.
814071d4279SBram Moolenaar */
815071d4279SBram Moolenaar void
set_input_buf(char_u * p,int overwrite)816c41badb7SBram Moolenaar set_input_buf(char_u *p, int overwrite)
817071d4279SBram Moolenaar {
818071d4279SBram Moolenaar garray_T *gap = (garray_T *)p;
819071d4279SBram Moolenaar
820071d4279SBram Moolenaar if (gap != NULL)
821071d4279SBram Moolenaar {
822071d4279SBram Moolenaar if (gap->ga_data != NULL)
823071d4279SBram Moolenaar {
824c41badb7SBram Moolenaar if (overwrite || inbufcount + gap->ga_len >= INBUFLEN)
825c41badb7SBram Moolenaar {
826071d4279SBram Moolenaar mch_memmove(inbuf, gap->ga_data, gap->ga_len);
827071d4279SBram Moolenaar inbufcount = gap->ga_len;
828c41badb7SBram Moolenaar }
829c41badb7SBram Moolenaar else
830c41badb7SBram Moolenaar {
831c41badb7SBram Moolenaar mch_memmove(inbuf + gap->ga_len, inbuf, inbufcount);
832c41badb7SBram Moolenaar mch_memmove(inbuf, gap->ga_data, gap->ga_len);
833c41badb7SBram Moolenaar inbufcount += gap->ga_len;
834c41badb7SBram Moolenaar }
835071d4279SBram Moolenaar vim_free(gap->ga_data);
836071d4279SBram Moolenaar }
837071d4279SBram Moolenaar vim_free(gap);
838071d4279SBram Moolenaar }
839071d4279SBram Moolenaar }
840071d4279SBram Moolenaar
841071d4279SBram Moolenaar /*
842071d4279SBram Moolenaar * Add the given bytes to the input buffer
843071d4279SBram Moolenaar * Special keys start with CSI. A real CSI must have been translated to
844071d4279SBram Moolenaar * CSI KS_EXTRA KE_CSI. K_SPECIAL doesn't require translation.
845071d4279SBram Moolenaar */
846071d4279SBram Moolenaar void
add_to_input_buf(char_u * s,int len)847764b23c8SBram Moolenaar add_to_input_buf(char_u *s, int len)
848071d4279SBram Moolenaar {
849071d4279SBram Moolenaar if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
850e38eab22SBram Moolenaar return; // Shouldn't ever happen!
851071d4279SBram Moolenaar
852071d4279SBram Moolenaar while (len--)
853071d4279SBram Moolenaar inbuf[inbufcount++] = *s++;
854071d4279SBram Moolenaar }
855071d4279SBram Moolenaar
856071d4279SBram Moolenaar /*
857071d4279SBram Moolenaar * Add "str[len]" to the input buffer while escaping CSI bytes.
858071d4279SBram Moolenaar */
859071d4279SBram Moolenaar void
add_to_input_buf_csi(char_u * str,int len)860071d4279SBram Moolenaar add_to_input_buf_csi(char_u *str, int len)
861071d4279SBram Moolenaar {
862071d4279SBram Moolenaar int i;
863071d4279SBram Moolenaar char_u buf[2];
864071d4279SBram Moolenaar
865071d4279SBram Moolenaar for (i = 0; i < len; ++i)
866071d4279SBram Moolenaar {
867071d4279SBram Moolenaar add_to_input_buf(str + i, 1);
868071d4279SBram Moolenaar if (str[i] == CSI)
869071d4279SBram Moolenaar {
870e38eab22SBram Moolenaar // Turn CSI into K_CSI.
871071d4279SBram Moolenaar buf[0] = KS_EXTRA;
872071d4279SBram Moolenaar buf[1] = (int)KE_CSI;
873071d4279SBram Moolenaar add_to_input_buf(buf, 2);
874071d4279SBram Moolenaar }
875071d4279SBram Moolenaar }
876071d4279SBram Moolenaar }
877071d4279SBram Moolenaar
878e38eab22SBram Moolenaar /*
879e38eab22SBram Moolenaar * Remove everything from the input buffer. Called when ^C is found.
880e38eab22SBram Moolenaar */
881071d4279SBram Moolenaar void
trash_input_buf(void)882764b23c8SBram Moolenaar trash_input_buf(void)
883071d4279SBram Moolenaar {
884071d4279SBram Moolenaar inbufcount = 0;
885071d4279SBram Moolenaar }
886071d4279SBram Moolenaar
887071d4279SBram Moolenaar /*
888071d4279SBram Moolenaar * Read as much data from the input buffer as possible up to maxlen, and store
889071d4279SBram Moolenaar * it in buf.
890071d4279SBram Moolenaar */
891071d4279SBram Moolenaar int
read_from_input_buf(char_u * buf,long maxlen)892764b23c8SBram Moolenaar read_from_input_buf(char_u *buf, long maxlen)
893071d4279SBram Moolenaar {
894e38eab22SBram Moolenaar if (inbufcount == 0) // if the buffer is empty, fill it
895071d4279SBram Moolenaar fill_input_buf(TRUE);
896071d4279SBram Moolenaar if (maxlen > inbufcount)
897071d4279SBram Moolenaar maxlen = inbufcount;
898071d4279SBram Moolenaar mch_memmove(buf, inbuf, (size_t)maxlen);
899071d4279SBram Moolenaar inbufcount -= maxlen;
900071d4279SBram Moolenaar if (inbufcount)
901071d4279SBram Moolenaar mch_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
902071d4279SBram Moolenaar return (int)maxlen;
903071d4279SBram Moolenaar }
904071d4279SBram Moolenaar
905071d4279SBram Moolenaar void
fill_input_buf(int exit_on_error UNUSED)906764b23c8SBram Moolenaar fill_input_buf(int exit_on_error UNUSED)
907071d4279SBram Moolenaar {
908d057301bSBram Moolenaar #if defined(UNIX) || defined(VMS) || defined(MACOS_X)
909071d4279SBram Moolenaar int len;
910071d4279SBram Moolenaar int try;
911071d4279SBram Moolenaar static int did_read_something = FALSE;
912e38eab22SBram Moolenaar static char_u *rest = NULL; // unconverted rest of previous read
913071d4279SBram Moolenaar static int restlen = 0;
914071d4279SBram Moolenaar int unconverted;
915071d4279SBram Moolenaar #endif
916071d4279SBram Moolenaar
917071d4279SBram Moolenaar #ifdef FEAT_GUI
91854ee775eSBram Moolenaar if (gui.in_use
91954ee775eSBram Moolenaar # ifdef NO_CONSOLE_INPUT
920e38eab22SBram Moolenaar // Don't use the GUI input when the window hasn't been opened yet.
921e38eab22SBram Moolenaar // We get here from ui_inchar() when we should try reading from stdin.
92254ee775eSBram Moolenaar && !no_console_input()
92354ee775eSBram Moolenaar # endif
92454ee775eSBram Moolenaar )
925071d4279SBram Moolenaar {
926071d4279SBram Moolenaar gui_mch_update();
927071d4279SBram Moolenaar return;
928071d4279SBram Moolenaar }
929071d4279SBram Moolenaar #endif
930d057301bSBram Moolenaar #if defined(UNIX) || defined(VMS) || defined(MACOS_X)
931071d4279SBram Moolenaar if (vim_is_input_buf_full())
932071d4279SBram Moolenaar return;
933071d4279SBram Moolenaar /*
934071d4279SBram Moolenaar * Fill_input_buf() is only called when we really need a character.
935071d4279SBram Moolenaar * If we can't get any, but there is some in the buffer, just return.
936071d4279SBram Moolenaar * If we can't get any, and there isn't any in the buffer, we give up and
937071d4279SBram Moolenaar * exit Vim.
938071d4279SBram Moolenaar */
939071d4279SBram Moolenaar if (rest != NULL)
940071d4279SBram Moolenaar {
941e38eab22SBram Moolenaar // Use remainder of previous call, starts with an invalid character
942e38eab22SBram Moolenaar // that may become valid when reading more.
943071d4279SBram Moolenaar if (restlen > INBUFLEN - inbufcount)
944071d4279SBram Moolenaar unconverted = INBUFLEN - inbufcount;
945071d4279SBram Moolenaar else
946071d4279SBram Moolenaar unconverted = restlen;
947071d4279SBram Moolenaar mch_memmove(inbuf + inbufcount, rest, unconverted);
948071d4279SBram Moolenaar if (unconverted == restlen)
949d23a8236SBram Moolenaar VIM_CLEAR(rest);
950071d4279SBram Moolenaar else
951071d4279SBram Moolenaar {
952071d4279SBram Moolenaar restlen -= unconverted;
953071d4279SBram Moolenaar mch_memmove(rest, rest + unconverted, restlen);
954071d4279SBram Moolenaar }
955071d4279SBram Moolenaar inbufcount += unconverted;
956071d4279SBram Moolenaar }
957071d4279SBram Moolenaar else
958071d4279SBram Moolenaar unconverted = 0;
959071d4279SBram Moolenaar
960e38eab22SBram Moolenaar len = 0; // to avoid gcc warning
961071d4279SBram Moolenaar for (try = 0; try < 100; ++try)
962071d4279SBram Moolenaar {
9634e601e3cSBram Moolenaar size_t readlen = (size_t)((INBUFLEN - inbufcount)
964264b74faSBram Moolenaar / input_conv.vc_factor);
9654e601e3cSBram Moolenaar # ifdef VMS
9664994373cSBram Moolenaar len = vms_read((char *)inbuf + inbufcount, readlen);
9674e601e3cSBram Moolenaar # else
9684e601e3cSBram Moolenaar len = read(read_cmd_fd, (char *)inbuf + inbufcount, readlen);
969071d4279SBram Moolenaar # endif
9707ca86fe8SBram Moolenaar # ifdef FEAT_JOB_CHANNEL
9717ca86fe8SBram Moolenaar if (len > 0)
9727ca86fe8SBram Moolenaar {
9737ca86fe8SBram Moolenaar inbuf[inbufcount + len] = NUL;
9747ca86fe8SBram Moolenaar ch_log(NULL, "raw key input: \"%s\"", inbuf + inbufcount);
9757ca86fe8SBram Moolenaar }
9767ca86fe8SBram Moolenaar # endif
9775313dcb7SBram Moolenaar
978071d4279SBram Moolenaar if (len > 0 || got_int)
979071d4279SBram Moolenaar break;
980071d4279SBram Moolenaar /*
981071d4279SBram Moolenaar * If reading stdin results in an error, continue reading stderr.
982071d4279SBram Moolenaar * This helps when using "foo | xargs vim".
983071d4279SBram Moolenaar */
984071d4279SBram Moolenaar if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0)
985071d4279SBram Moolenaar {
986071d4279SBram Moolenaar int m = cur_tmode;
987071d4279SBram Moolenaar
988e38eab22SBram Moolenaar // We probably set the wrong file descriptor to raw mode. Switch
989e38eab22SBram Moolenaar // back to cooked mode, use another descriptor and set the mode to
990e38eab22SBram Moolenaar // what it was.
991071d4279SBram Moolenaar settmode(TMODE_COOK);
992071d4279SBram Moolenaar #ifdef HAVE_DUP
993e38eab22SBram Moolenaar // Use stderr for stdin, also works for shell commands.
994071d4279SBram Moolenaar close(0);
99542335f50SBram Moolenaar vim_ignored = dup(2);
996071d4279SBram Moolenaar #else
997e38eab22SBram Moolenaar read_cmd_fd = 2; // read from stderr instead of stdin
998071d4279SBram Moolenaar #endif
999071d4279SBram Moolenaar settmode(m);
1000071d4279SBram Moolenaar }
1001071d4279SBram Moolenaar if (!exit_on_error)
1002071d4279SBram Moolenaar return;
1003071d4279SBram Moolenaar }
1004071d4279SBram Moolenaar if (len <= 0 && !got_int)
1005071d4279SBram Moolenaar read_error_exit();
1006071d4279SBram Moolenaar if (len > 0)
1007071d4279SBram Moolenaar did_read_something = TRUE;
1008071d4279SBram Moolenaar if (got_int)
1009071d4279SBram Moolenaar {
1010e38eab22SBram Moolenaar // Interrupted, pretend a CTRL-C was typed.
1011071d4279SBram Moolenaar inbuf[0] = 3;
1012071d4279SBram Moolenaar inbufcount = 1;
1013071d4279SBram Moolenaar }
1014071d4279SBram Moolenaar else
1015071d4279SBram Moolenaar {
1016071d4279SBram Moolenaar /*
1017071d4279SBram Moolenaar * May perform conversion on the input characters.
1018071d4279SBram Moolenaar * Include the unconverted rest of the previous call.
1019071d4279SBram Moolenaar * If there is an incomplete char at the end it is kept for the next
1020071d4279SBram Moolenaar * time, reading more bytes should make conversion possible.
1021071d4279SBram Moolenaar * Don't do this in the unlikely event that the input buffer is too
1022071d4279SBram Moolenaar * small ("rest" still contains more bytes).
1023071d4279SBram Moolenaar */
1024071d4279SBram Moolenaar if (input_conv.vc_type != CONV_NONE)
1025071d4279SBram Moolenaar {
1026071d4279SBram Moolenaar inbufcount -= unconverted;
1027071d4279SBram Moolenaar len = convert_input_safe(inbuf + inbufcount,
1028071d4279SBram Moolenaar len + unconverted, INBUFLEN - inbufcount,
1029071d4279SBram Moolenaar rest == NULL ? &rest : NULL, &restlen);
1030071d4279SBram Moolenaar }
1031071d4279SBram Moolenaar while (len-- > 0)
1032071d4279SBram Moolenaar {
1033339c1bdbSBram Moolenaar // If a CTRL-C was typed, remove it from the buffer and set
1034339c1bdbSBram Moolenaar // got_int. Also recognize CTRL-C with modifyOtherKeys set, in two
1035339c1bdbSBram Moolenaar // forms.
10369645e2d9SBram Moolenaar if (ctrl_c_interrupts && (inbuf[inbufcount] == 3
1037339c1bdbSBram Moolenaar || (len >= 10 && STRNCMP(inbuf + inbufcount,
103802faa944SBram Moolenaar "\033[27;5;99~", 10) == 0)
103902faa944SBram Moolenaar || (len >= 7 && STRNCMP(inbuf + inbufcount,
104002faa944SBram Moolenaar "\033[99;5u", 7) == 0)))
1041071d4279SBram Moolenaar {
1042e38eab22SBram Moolenaar // remove everything typed before the CTRL-C
1043071d4279SBram Moolenaar mch_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
1044071d4279SBram Moolenaar inbufcount = 0;
1045071d4279SBram Moolenaar got_int = TRUE;
1046071d4279SBram Moolenaar }
1047071d4279SBram Moolenaar ++inbufcount;
1048071d4279SBram Moolenaar }
1049071d4279SBram Moolenaar }
105074ee5e23SBram Moolenaar #endif // UNIX || VMS || MACOS_X
1051071d4279SBram Moolenaar }
105274ee5e23SBram Moolenaar #endif // USE_INPUT_BUF
1053071d4279SBram Moolenaar
1054071d4279SBram Moolenaar /*
1055071d4279SBram Moolenaar * Exit because of an input read error.
1056071d4279SBram Moolenaar */
1057071d4279SBram Moolenaar void
read_error_exit(void)1058764b23c8SBram Moolenaar read_error_exit(void)
1059071d4279SBram Moolenaar {
1060e38eab22SBram Moolenaar if (silent_mode) // Normal way to exit for "ex -s"
1061071d4279SBram Moolenaar getout(0);
1062071d4279SBram Moolenaar STRCPY(IObuff, _("Vim: Error reading input, exiting...\n"));
1063071d4279SBram Moolenaar preserve_exit();
1064071d4279SBram Moolenaar }
1065071d4279SBram Moolenaar
1066071d4279SBram Moolenaar #if defined(CURSOR_SHAPE) || defined(PROTO)
1067071d4279SBram Moolenaar /*
1068071d4279SBram Moolenaar * May update the shape of the cursor.
1069071d4279SBram Moolenaar */
1070071d4279SBram Moolenaar void
ui_cursor_shape_forced(int forced)10713cd43cccSBram Moolenaar ui_cursor_shape_forced(int forced)
1072071d4279SBram Moolenaar {
1073071d4279SBram Moolenaar # ifdef FEAT_GUI
1074071d4279SBram Moolenaar if (gui.in_use)
1075071d4279SBram Moolenaar gui_update_cursor_later();
1076293ee4d4SBram Moolenaar else
1077071d4279SBram Moolenaar # endif
10783cd43cccSBram Moolenaar term_cursor_mode(forced);
1079293ee4d4SBram Moolenaar
1080071d4279SBram Moolenaar # ifdef MCH_CURSOR_SHAPE
1081071d4279SBram Moolenaar mch_update_cursor();
1082071d4279SBram Moolenaar # endif
1083f5963f71SBram Moolenaar
1084f5963f71SBram Moolenaar # ifdef FEAT_CONCEAL
1085*ea042677SBram Moolenaar conceal_check_cursor_line(FALSE);
1086f5963f71SBram Moolenaar # endif
1087071d4279SBram Moolenaar }
10883cd43cccSBram Moolenaar
10893cd43cccSBram Moolenaar void
ui_cursor_shape(void)10903cd43cccSBram Moolenaar ui_cursor_shape(void)
10913cd43cccSBram Moolenaar {
10923cd43cccSBram Moolenaar ui_cursor_shape_forced(FALSE);
10933cd43cccSBram Moolenaar }
1094071d4279SBram Moolenaar #endif
1095071d4279SBram Moolenaar
1096071d4279SBram Moolenaar /*
1097071d4279SBram Moolenaar * Check bounds for column number
1098071d4279SBram Moolenaar */
1099071d4279SBram Moolenaar int
check_col(int col)1100764b23c8SBram Moolenaar check_col(int col)
1101071d4279SBram Moolenaar {
1102071d4279SBram Moolenaar if (col < 0)
1103071d4279SBram Moolenaar return 0;
1104071d4279SBram Moolenaar if (col >= (int)screen_Columns)
1105071d4279SBram Moolenaar return (int)screen_Columns - 1;
1106071d4279SBram Moolenaar return col;
1107071d4279SBram Moolenaar }
1108071d4279SBram Moolenaar
1109071d4279SBram Moolenaar /*
1110071d4279SBram Moolenaar * Check bounds for row number
1111071d4279SBram Moolenaar */
1112071d4279SBram Moolenaar int
check_row(int row)1113764b23c8SBram Moolenaar check_row(int row)
1114071d4279SBram Moolenaar {
1115071d4279SBram Moolenaar if (row < 0)
1116071d4279SBram Moolenaar return 0;
1117071d4279SBram Moolenaar if (row >= (int)screen_Rows)
1118071d4279SBram Moolenaar return (int)screen_Rows - 1;
1119071d4279SBram Moolenaar return row;
1120071d4279SBram Moolenaar }
1121071d4279SBram Moolenaar
1122071d4279SBram Moolenaar /*
1123071d4279SBram Moolenaar * Called when focus changed. Used for the GUI or for systems where this can
1124071d4279SBram Moolenaar * be done in the console (Win32).
1125071d4279SBram Moolenaar */
1126071d4279SBram Moolenaar void
ui_focus_change(int in_focus)1127764b23c8SBram Moolenaar ui_focus_change(
1128e38eab22SBram Moolenaar int in_focus) // TRUE if focus gained.
1129071d4279SBram Moolenaar {
1130071d4279SBram Moolenaar static time_t last_time = (time_t)0;
1131071d4279SBram Moolenaar int need_redraw = FALSE;
1132071d4279SBram Moolenaar
1133e38eab22SBram Moolenaar // When activated: Check if any file was modified outside of Vim.
1134e38eab22SBram Moolenaar // Only do this when not done within the last two seconds (could get
1135e38eab22SBram Moolenaar // several events in a row).
1136071d4279SBram Moolenaar if (in_focus && last_time + 2 < time(NULL))
1137071d4279SBram Moolenaar {
1138071d4279SBram Moolenaar need_redraw = check_timestamps(
1139071d4279SBram Moolenaar # ifdef FEAT_GUI
1140071d4279SBram Moolenaar gui.in_use
1141071d4279SBram Moolenaar # else
1142071d4279SBram Moolenaar FALSE
1143071d4279SBram Moolenaar # endif
1144071d4279SBram Moolenaar );
1145071d4279SBram Moolenaar last_time = time(NULL);
1146071d4279SBram Moolenaar }
1147071d4279SBram Moolenaar
1148071d4279SBram Moolenaar /*
1149071d4279SBram Moolenaar * Fire the focus gained/lost autocommand.
1150071d4279SBram Moolenaar */
1151071d4279SBram Moolenaar need_redraw |= apply_autocmds(in_focus ? EVENT_FOCUSGAINED
1152071d4279SBram Moolenaar : EVENT_FOCUSLOST, NULL, NULL, FALSE, curbuf);
1153071d4279SBram Moolenaar
1154071d4279SBram Moolenaar if (need_redraw)
1155071d4279SBram Moolenaar {
1156e38eab22SBram Moolenaar // Something was executed, make sure the cursor is put back where it
1157e38eab22SBram Moolenaar // belongs.
1158071d4279SBram Moolenaar need_wait_return = FALSE;
1159071d4279SBram Moolenaar
1160071d4279SBram Moolenaar if (State & CMDLINE)
1161071d4279SBram Moolenaar redrawcmdline();
1162071d4279SBram Moolenaar else if (State == HITRETURN || State == SETWSIZE || State == ASKMORE
1163071d4279SBram Moolenaar || State == EXTERNCMD || State == CONFIRM || exmode_active)
1164071d4279SBram Moolenaar repeat_message();
1165071d4279SBram Moolenaar else if ((State & NORMAL) || (State & INSERT))
1166071d4279SBram Moolenaar {
1167071d4279SBram Moolenaar if (must_redraw != 0)
1168071d4279SBram Moolenaar update_screen(0);
1169071d4279SBram Moolenaar setcursor();
1170071d4279SBram Moolenaar }
1171e38eab22SBram Moolenaar cursor_on(); // redrawing may have switched it off
1172a338adcfSBram Moolenaar out_flush_cursor(FALSE, TRUE);
1173071d4279SBram Moolenaar # ifdef FEAT_GUI
1174071d4279SBram Moolenaar if (gui.in_use)
1175071d4279SBram Moolenaar gui_update_scrollbars(FALSE);
1176071d4279SBram Moolenaar # endif
1177071d4279SBram Moolenaar }
1178071d4279SBram Moolenaar #ifdef FEAT_TITLE
1179e38eab22SBram Moolenaar // File may have been changed from 'readonly' to 'noreadonly'
1180071d4279SBram Moolenaar if (need_maketitle)
1181071d4279SBram Moolenaar maketitle();
1182071d4279SBram Moolenaar #endif
1183071d4279SBram Moolenaar }
1184071d4279SBram Moolenaar
1185f2bd8ef2SBram Moolenaar #if defined(HAVE_INPUT_METHOD) || defined(PROTO)
1186071d4279SBram Moolenaar /*
1187071d4279SBram Moolenaar * Save current Input Method status to specified place.
1188071d4279SBram Moolenaar */
1189071d4279SBram Moolenaar void
im_save_status(long * psave)1190764b23c8SBram Moolenaar im_save_status(long *psave)
1191071d4279SBram Moolenaar {
1192e38eab22SBram Moolenaar // Don't save when 'imdisable' is set or "xic" is NULL, IM is always
1193e38eab22SBram Moolenaar // disabled then (but might start later).
1194e38eab22SBram Moolenaar // Also don't save when inside a mapping, vgetc_im_active has not been set
1195e38eab22SBram Moolenaar // then.
1196e38eab22SBram Moolenaar // And don't save when the keys were stuffed (e.g., for a "." command).
1197e38eab22SBram Moolenaar // And don't save when the GUI is running but our window doesn't have
1198e38eab22SBram Moolenaar // input focus (e.g., when a find dialog is open).
1199071d4279SBram Moolenaar if (!p_imdisable && KeyTyped && !KeyStuffed
1200071d4279SBram Moolenaar # ifdef FEAT_XIM
1201071d4279SBram Moolenaar && xic != NULL
1202071d4279SBram Moolenaar # endif
1203071d4279SBram Moolenaar # ifdef FEAT_GUI
1204071d4279SBram Moolenaar && (!gui.in_use || gui.in_focus)
1205071d4279SBram Moolenaar # endif
1206071d4279SBram Moolenaar )
1207071d4279SBram Moolenaar {
1208e38eab22SBram Moolenaar // Do save when IM is on, or IM is off and saved status is on.
1209071d4279SBram Moolenaar if (vgetc_im_active)
1210071d4279SBram Moolenaar *psave = B_IMODE_IM;
1211071d4279SBram Moolenaar else if (*psave == B_IMODE_IM)
1212071d4279SBram Moolenaar *psave = B_IMODE_NONE;
1213071d4279SBram Moolenaar }
1214071d4279SBram Moolenaar }
1215071d4279SBram Moolenaar #endif
1216