summaryrefslogtreecommitdiffstats
path: root/src/getchar.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-09-15 21:00:54 +0200
committerBram Moolenaar <Bram@vim.org>2019-09-15 21:00:54 +0200
commit9c658c9eacbd97e2c071f652a0155f71db94c0f3 (patch)
tree2f321ccf7e6576d1b9a4a0df27d913702b2cc1f4 /src/getchar.c
parent248fdb33320641804afed4bdf5dc5cddb1cf64f5 (diff)
patch 8.1.2042: the evalfunc.c file is too bigv8.1.2042
Problem: The evalfunc.c file is too big. Solution: Move getchar() and parse_queued_messages() to getchar.c.
Diffstat (limited to 'src/getchar.c')
-rw-r--r--src/getchar.c200
1 files changed, 199 insertions, 1 deletions
diff --git a/src/getchar.c b/src/getchar.c
index eeb33420bc..32e35504ff 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -1901,6 +1901,205 @@ char_avail(void)
return (retval != NUL);
}
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * "getchar()" function
+ */
+ void
+f_getchar(typval_T *argvars, typval_T *rettv)
+{
+ varnumber_T n;
+ int error = FALSE;
+
+#ifdef MESSAGE_QUEUE
+ // vpeekc() used to check for messages, but that caused problems, invoking
+ // a callback where it was not expected. Some plugins use getchar(1) in a
+ // loop to await a message, therefore make sure we check for messages here.
+ parse_queued_messages();
+#endif
+
+ /* Position the cursor. Needed after a message that ends in a space. */
+ windgoto(msg_row, msg_col);
+
+ ++no_mapping;
+ ++allow_keys;
+ for (;;)
+ {
+ if (argvars[0].v_type == VAR_UNKNOWN)
+ /* getchar(): blocking wait. */
+ n = plain_vgetc();
+ else if (tv_get_number_chk(&argvars[0], &error) == 1)
+ /* getchar(1): only check if char avail */
+ n = vpeekc_any();
+ else if (error || vpeekc_any() == NUL)
+ /* illegal argument or getchar(0) and no char avail: return zero */
+ n = 0;
+ else
+ /* getchar(0) and char avail: return char */
+ n = plain_vgetc();
+
+ if (n == K_IGNORE)
+ continue;
+ break;
+ }
+ --no_mapping;
+ --allow_keys;
+
+ set_vim_var_nr(VV_MOUSE_WIN, 0);
+ set_vim_var_nr(VV_MOUSE_WINID, 0);
+ set_vim_var_nr(VV_MOUSE_LNUM, 0);
+ set_vim_var_nr(VV_MOUSE_COL, 0);
+
+ rettv->vval.v_number = n;
+ if (IS_SPECIAL(n) || mod_mask != 0)
+ {
+ char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
+ int i = 0;
+
+ /* Turn a special key into three bytes, plus modifier. */
+ if (mod_mask != 0)
+ {
+ temp[i++] = K_SPECIAL;
+ temp[i++] = KS_MODIFIER;
+ temp[i++] = mod_mask;
+ }
+ if (IS_SPECIAL(n))
+ {
+ temp[i++] = K_SPECIAL;
+ temp[i++] = K_SECOND(n);
+ temp[i++] = K_THIRD(n);
+ }
+ else if (has_mbyte)
+ i += (*mb_char2bytes)(n, temp + i);
+ else
+ temp[i++] = n;
+ temp[i++] = NUL;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave(temp);
+
+#ifdef FEAT_MOUSE
+ if (is_mouse_key(n))
+ {
+ int row = mouse_row;
+ int col = mouse_col;
+ win_T *win;
+ linenr_T lnum;
+ win_T *wp;
+ int winnr = 1;
+
+ if (row >= 0 && col >= 0)
+ {
+ /* Find the window at the mouse coordinates and compute the
+ * text position. */
+ win = mouse_find_win(&row, &col, FIND_POPUP);
+ if (win == NULL)
+ return;
+ (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
+# ifdef FEAT_TEXT_PROP
+ if (WIN_IS_POPUP(win))
+ winnr = 0;
+ else
+# endif
+ for (wp = firstwin; wp != win && wp != NULL;
+ wp = wp->w_next)
+ ++winnr;
+ set_vim_var_nr(VV_MOUSE_WIN, winnr);
+ set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
+ set_vim_var_nr(VV_MOUSE_LNUM, lnum);
+ set_vim_var_nr(VV_MOUSE_COL, col + 1);
+ }
+ }
+#endif
+ }
+}
+
+/*
+ * "getcharmod()" function
+ */
+ void
+f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
+{
+ rettv->vval.v_number = mod_mask;
+}
+#endif // FEAT_EVAL
+
+#if defined(MESSAGE_QUEUE) || defined(PROTO)
+# define MAX_REPEAT_PARSE 8
+
+/*
+ * Process messages that have been queued for netbeans or clientserver.
+ * Also check if any jobs have ended.
+ * These functions can call arbitrary vimscript and should only be called when
+ * it is safe to do so.
+ */
+ void
+parse_queued_messages(void)
+{
+ int old_curwin_id = curwin->w_id;
+ int old_curbuf_fnum = curbuf->b_fnum;
+ int i;
+ int save_may_garbage_collect = may_garbage_collect;
+
+ // Do not handle messages while redrawing, because it may cause buffers to
+ // change or be wiped while they are being redrawn.
+ if (updating_screen)
+ return;
+
+ // may_garbage_collect is set in main_loop() to do garbage collection when
+ // blocking to wait on a character. We don't want that while parsing
+ // messages, a callback may invoke vgetc() while lists and dicts are in use
+ // in the call stack.
+ may_garbage_collect = FALSE;
+
+ // Loop when a job ended, but don't keep looping forever.
+ for (i = 0; i < MAX_REPEAT_PARSE; ++i)
+ {
+ // For Win32 mch_breakcheck() does not check for input, do it here.
+# if defined(MSWIN) && defined(FEAT_JOB_CHANNEL)
+ channel_handle_events(FALSE);
+# endif
+
+# ifdef FEAT_NETBEANS_INTG
+ // Process the queued netbeans messages.
+ netbeans_parse_messages();
+# endif
+# ifdef FEAT_JOB_CHANNEL
+ // Write any buffer lines still to be written.
+ channel_write_any_lines();
+
+ // Process the messages queued on channels.
+ channel_parse_messages();
+# endif
+# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
+ // Process the queued clientserver messages.
+ server_parse_messages();
+# endif
+# ifdef FEAT_JOB_CHANNEL
+ // Check if any jobs have ended. If so, repeat the above to handle
+ // changes, e.g. stdin may have been closed.
+ if (job_check_ended())
+ continue;
+# endif
+# ifdef FEAT_TERMINAL
+ free_unused_terminals();
+# endif
+# ifdef FEAT_SOUND_CANBERRA
+ if (has_sound_callback_in_queue())
+ invoke_sound_callback();
+# endif
+ break;
+ }
+
+ may_garbage_collect = save_may_garbage_collect;
+
+ // If the current window or buffer changed we need to bail out of the
+ // waiting loop. E.g. when a job exit callback closes the terminal window.
+ if (curwin->w_id != old_curwin_id || curbuf->b_fnum != old_curbuf_fnum)
+ ins_char_typebuf(K_IGNORE);
+}
+#endif
+
+
typedef enum {
map_result_fail, // failed, break loop
map_result_get, // get a character from typeahead
@@ -3016,7 +3215,6 @@ inchar(
#endif
)
{
-
#ifdef MESSAGE_QUEUE
parse_queued_messages();
#endif