0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 7.4.1886

Problem:    When waiting for a character is interrupted by receiving channel
            data and the first character of a mapping was typed, the mapping
            times out. (Ramel Eshed)
Solution:   When dealing with channel data don't return from mch_inchar().
This commit is contained in:
Bram Moolenaar 2016-06-04 13:32:35 +02:00
parent 1aa07bdead
commit cda7764d8e
4 changed files with 70 additions and 37 deletions

View File

@ -129,6 +129,7 @@ static int vgetorpeek(int);
static void map_free(mapblock_T **); static void map_free(mapblock_T **);
static void validate_maphash(void); static void validate_maphash(void);
static void showmap(mapblock_T *mp, int local); static void showmap(mapblock_T *mp, int local);
static int inchar(char_u *buf, int maxlen, long wait_time, int tb_change_cnt);
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
static char_u *eval_map_expr(char_u *str, int c); static char_u *eval_map_expr(char_u *str, int c);
#endif #endif
@ -2941,7 +2942,7 @@ vgetorpeek(int advance)
* Return the number of obtained characters. * Return the number of obtained characters.
* Return -1 when end of input script reached. * Return -1 when end of input script reached.
*/ */
int static int
inchar( inchar(
char_u *buf, char_u *buf,
int maxlen, int maxlen,

View File

@ -175,12 +175,12 @@ typedef int waitstatus;
#endif #endif
static pid_t wait4pid(pid_t, waitstatus *); static pid_t wait4pid(pid_t, waitstatus *);
static int WaitForChar(long); static int WaitForChar(long msec, int *interrupted);
static int WaitForCharOrMouse(long, int *break_loop); static int WaitForCharOrMouse(long msec, int *interrupted);
#if defined(__BEOS__) || defined(VMS) #if defined(__BEOS__) || defined(VMS)
int RealWaitForChar(int, long, int *, int *break_loop); int RealWaitForChar(int, long, int *, int *interrupted);
#else #else
static int RealWaitForChar(int, long, int *, int *break_loop); static int RealWaitForChar(int, long, int *, int *interrupted);
#endif #endif
#ifdef FEAT_XCLIPBOARD #ifdef FEAT_XCLIPBOARD
@ -385,6 +385,7 @@ mch_inchar(
int tb_change_cnt) int tb_change_cnt)
{ {
int len; int len;
int interrupted = FALSE;
#ifdef MESSAGE_QUEUE #ifdef MESSAGE_QUEUE
parse_queued_messages(); parse_queued_messages();
@ -397,20 +398,31 @@ mch_inchar(
if (wtime >= 0) if (wtime >= 0)
{ {
while (!WaitForChar(wtime)) /* no character available */ /* TODO: when looping reduce wtime by the elapsed time. */
while (!WaitForChar(wtime, &interrupted))
{ {
/* no character available */
if (do_resize) if (do_resize)
{
handle_resize(); handle_resize();
continue;
}
#ifdef FEAT_CLIENTSERVER #ifdef FEAT_CLIENTSERVER
else if (!server_waiting()) if (server_waiting())
#else {
else parse_queued_messages();
continue;
}
#endif
#ifdef MESSAGE_QUEUE
if (interrupted)
{
parse_queued_messages();
continue;
}
#endif #endif
/* return if not interrupted by resize or server */ /* return if not interrupted by resize or server */
return 0; return 0;
#ifdef MESSAGE_QUEUE
parse_queued_messages();
#endif
} }
} }
else /* wtime == -1 */ else /* wtime == -1 */
@ -420,8 +432,9 @@ mch_inchar(
* flush all the swap files to disk. * flush all the swap files to disk.
* Also done when interrupted by SIGWINCH. * Also done when interrupted by SIGWINCH.
*/ */
if (!WaitForChar(p_ut)) if (!WaitForChar(p_ut, &interrupted))
{ {
/* TODO: if interrupted is set loop to wait the remaining time. */
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
if (trigger_cursorhold() && maxlen >= 3 if (trigger_cursorhold() && maxlen >= 3
&& !typebuf_changed(tb_change_cnt)) && !typebuf_changed(tb_change_cnt))
@ -436,7 +449,8 @@ mch_inchar(
} }
} }
for (;;) /* repeat until we got a character */ /* repeat until we got a character */
for (;;)
{ {
long wtime_now = -1L; long wtime_now = -1L;
@ -462,10 +476,17 @@ mch_inchar(
* We want to be interrupted by the winch signal * We want to be interrupted by the winch signal
* or by an event on the monitored file descriptors. * or by an event on the monitored file descriptors.
*/ */
if (!WaitForChar(wtime_now)) if (!WaitForChar(wtime_now, &interrupted))
{ {
if (do_resize) /* interrupted by SIGWINCH signal */ if (do_resize) /* interrupted by SIGWINCH signal */
handle_resize(); continue;
#ifdef MESSAGE_QUEUE
if (interrupted || wtime_now > 0)
{
parse_queued_messages();
continue;
}
#endif
return 0; return 0;
} }
@ -482,11 +503,9 @@ mch_inchar(
*/ */
len = read_from_input_buf(buf, (long)maxlen); len = read_from_input_buf(buf, (long)maxlen);
if (len > 0) if (len > 0)
{
return len; return len;
} }
} }
}
static void static void
handle_resize(void) handle_resize(void)
@ -501,7 +520,7 @@ handle_resize(void)
int int
mch_char_avail(void) mch_char_avail(void)
{ {
return WaitForChar(0L); return WaitForChar(0L, NULL);
} }
#if defined(HAVE_TOTAL_MEM) || defined(PROTO) #if defined(HAVE_TOTAL_MEM) || defined(PROTO)
@ -691,7 +710,7 @@ mch_delay(long msec, int ignoreinput)
in_mch_delay = FALSE; in_mch_delay = FALSE;
} }
else else
WaitForChar(msec); WaitForChar(msec, NULL);
} }
#if defined(HAVE_STACK_LIMIT) \ #if defined(HAVE_STACK_LIMIT) \
@ -5229,6 +5248,10 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
if (stderr_works) if (stderr_works)
perror("executing job failed"); perror("executing job failed");
#ifdef EXITFREE
/* calling free_all_mem() here causes problems. Ignore valgrind
* reporting possibly leaked memory. */
#endif
_exit(EXEC_FAILED); /* exec failed, return failure code */ _exit(EXEC_FAILED); /* exec failed, return failure code */
} }
@ -5376,16 +5399,17 @@ mch_breakcheck(void)
* from inbuf[]. * from inbuf[].
* "msec" == -1 will block forever. * "msec" == -1 will block forever.
* Invokes timer callbacks when needed. * Invokes timer callbacks when needed.
* When a GUI is being used, this will never get called -- webb * "interrupted" (if not NULL) is set to TRUE when no character is available
* but something else needs to be done.
* Returns TRUE when a character is available. * Returns TRUE when a character is available.
* When a GUI is being used, this will never get called -- webb
*/ */
static int static int
WaitForChar(long msec) WaitForChar(long msec, int *interrupted)
{ {
#ifdef FEAT_TIMERS #ifdef FEAT_TIMERS
long due_time; long due_time;
long remaining = msec; long remaining = msec;
int break_loop = FALSE;
int tb_change_cnt = typebuf.tb_change_cnt; int tb_change_cnt = typebuf.tb_change_cnt;
/* When waiting very briefly don't trigger timers. */ /* When waiting very briefly don't trigger timers. */
@ -5404,9 +5428,9 @@ WaitForChar(long msec)
} }
if (due_time <= 0 || (msec > 0 && due_time > remaining)) if (due_time <= 0 || (msec > 0 && due_time > remaining))
due_time = remaining; due_time = remaining;
if (WaitForCharOrMouse(due_time, &break_loop)) if (WaitForCharOrMouse(due_time, interrupted))
return TRUE; return TRUE;
if (break_loop) if (interrupted != NULL && *interrupted)
/* Nothing available, but need to return so that side effects get /* Nothing available, but need to return so that side effects get
* handled, such as handling a message on a channel. */ * handled, such as handling a message on a channel. */
return FALSE; return FALSE;
@ -5415,7 +5439,7 @@ WaitForChar(long msec)
} }
return FALSE; return FALSE;
#else #else
return WaitForCharOrMouse(msec, NULL); return WaitForCharOrMouse(msec, interrupted);
#endif #endif
} }
@ -5423,10 +5447,12 @@ WaitForChar(long msec)
* Wait "msec" msec until a character is available from the mouse or keyboard * Wait "msec" msec until a character is available from the mouse or keyboard
* or from inbuf[]. * or from inbuf[].
* "msec" == -1 will block forever. * "msec" == -1 will block forever.
* "interrupted" (if not NULL) is set to TRUE when no character is available
* but something else needs to be done.
* When a GUI is being used, this will never get called -- webb * When a GUI is being used, this will never get called -- webb
*/ */
static int static int
WaitForCharOrMouse(long msec, int *break_loop) WaitForCharOrMouse(long msec, int *interrupted)
{ {
#ifdef FEAT_MOUSE_GPM #ifdef FEAT_MOUSE_GPM
int gpm_process_wanted; int gpm_process_wanted;
@ -5473,9 +5499,9 @@ WaitForCharOrMouse(long msec, int *break_loop)
# ifdef FEAT_MOUSE_GPM # ifdef FEAT_MOUSE_GPM
gpm_process_wanted = 0; gpm_process_wanted = 0;
avail = RealWaitForChar(read_cmd_fd, msec, avail = RealWaitForChar(read_cmd_fd, msec,
&gpm_process_wanted, break_loop); &gpm_process_wanted, interrupted);
# else # else
avail = RealWaitForChar(read_cmd_fd, msec, NULL, break_loop); avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
# endif # endif
if (!avail) if (!avail)
{ {
@ -5498,7 +5524,7 @@ WaitForCharOrMouse(long msec, int *break_loop)
; ;
#else #else
avail = RealWaitForChar(read_cmd_fd, msec, NULL, break_loop); avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
#endif #endif
return avail; return avail;
} }
@ -5511,13 +5537,15 @@ WaitForCharOrMouse(long msec, int *break_loop)
* When a GUI is being used, this will not be used for input -- webb * When a GUI is being used, this will not be used for input -- webb
* Or when a Linux GPM mouse event is waiting. * Or when a Linux GPM mouse event is waiting.
* Or when a clientserver message is on the queue. * Or when a clientserver message is on the queue.
* "interrupted" (if not NULL) is set to TRUE when no character is available
* but something else needs to be done.
*/ */
#if defined(__BEOS__) #if defined(__BEOS__)
int int
#else #else
static int static int
#endif #endif
RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *break_loop) RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
{ {
int ret; int ret;
int result; int result;
@ -5627,12 +5655,14 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *break_loop)
#ifdef FEAT_JOB_CHANNEL #ifdef FEAT_JOB_CHANNEL
nfd = channel_poll_setup(nfd, &fds); nfd = channel_poll_setup(nfd, &fds);
#endif #endif
if (interrupted != NULL)
*interrupted = FALSE;
ret = poll(fds, nfd, towait); ret = poll(fds, nfd, towait);
result = ret > 0 && (fds[0].revents & POLLIN); result = ret > 0 && (fds[0].revents & POLLIN);
if (break_loop != NULL && ret > 0) if (result == 0 && interrupted != NULL && ret > 0)
*break_loop = TRUE; *interrupted = TRUE;
# ifdef FEAT_MZSCHEME # ifdef FEAT_MZSCHEME
if (ret == 0 && mzquantum_used) if (ret == 0 && mzquantum_used)
@ -5679,7 +5709,6 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *break_loop)
ret = channel_poll_check(ret, &fds); ret = channel_poll_check(ret, &fds);
#endif #endif
#else /* HAVE_SELECT */ #else /* HAVE_SELECT */
struct timeval tv; struct timeval tv;
@ -5760,13 +5789,15 @@ select_eintr:
# ifdef FEAT_JOB_CHANNEL # ifdef FEAT_JOB_CHANNEL
maxfd = channel_select_setup(maxfd, &rfds, &wfds); maxfd = channel_select_setup(maxfd, &rfds, &wfds);
# endif # endif
if (interrupted != NULL)
*interrupted = FALSE;
ret = select(maxfd + 1, &rfds, &wfds, &efds, tvp); ret = select(maxfd + 1, &rfds, &wfds, &efds, tvp);
result = ret > 0 && FD_ISSET(fd, &rfds); result = ret > 0 && FD_ISSET(fd, &rfds);
if (result) if (result)
--ret; --ret;
if (break_loop != NULL && ret > 0) else if (interrupted != NULL && ret > 0)
*break_loop = TRUE; *interrupted = TRUE;
# ifdef EINTR # ifdef EINTR
if (ret == -1 && errno == EINTR) if (ret == -1 && errno == EINTR)

View File

@ -47,7 +47,6 @@ int vpeekc_nomap(void);
int vpeekc_any(void); int vpeekc_any(void);
int char_avail(void); int char_avail(void);
void vungetc(int c); void vungetc(int c);
int inchar(char_u *buf, int maxlen, long wait_time, int tb_change_cnt);
int fix_input_buffer(char_u *buf, int len, int script); int fix_input_buffer(char_u *buf, int len, int script);
int input_available(void); int input_available(void);
int do_map(int maptype, char_u *arg, int mode, int abbrev); int do_map(int maptype, char_u *arg, int mode, int abbrev);

View File

@ -753,6 +753,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1886,
/**/ /**/
1885, 1885,
/**/ /**/