aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2019-09-08 16:50:45 +0200
committerGitHub <noreply@github.com>2019-09-08 16:50:45 +0200
commit83632022f84e4addf9518bf9913cc58b2ae41820 (patch)
treed09e86ecd2f61d8e93175bceefa1468df0c586e3
parentfa90f6cdaae800d9bfbc4f28ec04fb7456751dbe (diff)
parentc705e3fb0b70887aaebe4973ce02acc6be45eb97 (diff)
downloadrneovim-83632022f84e4addf9518bf9913cc58b2ae41820.tar.gz
rneovim-83632022f84e4addf9518bf9913cc58b2ae41820.tar.bz2
rneovim-83632022f84e4addf9518bf9913cc58b2ae41820.zip
Merge pull request #10959 from bfredl/resizequeue
fix crash on :!tmux split, redraw after resize in pager
-rw-r--r--src/nvim/eval.c4
-rw-r--r--src/nvim/event/multiqueue.c37
-rw-r--r--src/nvim/ex_cmds.c2
-rw-r--r--src/nvim/ex_docmd.c6
-rw-r--r--src/nvim/getchar.c12
-rw-r--r--src/nvim/getchar.h5
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/message.c46
-rw-r--r--src/nvim/misc1.c20
-rw-r--r--src/nvim/msgpack_rpc/channel.c13
-rw-r--r--src/nvim/os/input.c72
-rw-r--r--src/nvim/os/input.h1
-rw-r--r--src/nvim/state.c4
-rw-r--r--src/nvim/ui.c12
-rw-r--r--src/nvim/ui.h3
-rw-r--r--test/functional/helpers.lua1
-rw-r--r--test/functional/terminal/tui_spec.lua18
-rw-r--r--test/functional/ui/messages_spec.lua117
18 files changed, 272 insertions, 103 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 8e848483a7..0aa0e8c165 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -9941,9 +9941,7 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type == VAR_UNKNOWN) {
// getchar(): blocking wait.
if (!(char_avail() || using_script() || input_available())) {
- input_enable_events();
- (void)os_inchar(NULL, 0, -1, 0);
- input_disable_events();
+ (void)os_inchar(NULL, 0, -1, 0, main_loop.events);
if (!multiqueue_empty(main_loop.events)) {
multiqueue_process_events(main_loop.events);
continue;
diff --git a/src/nvim/event/multiqueue.c b/src/nvim/event/multiqueue.c
index ef9f3f1870..a1b75f66a5 100644
--- a/src/nvim/event/multiqueue.c
+++ b/src/nvim/event/multiqueue.c
@@ -78,6 +78,13 @@ struct multiqueue {
size_t size;
};
+typedef struct {
+ Event event;
+ bool fired;
+ int refcount;
+} SplitEvent;
+
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/multiqueue.c.generated.h"
#endif
@@ -245,3 +252,33 @@ static MultiQueueItem *multiqueue_node_data(QUEUE *q)
{
return QUEUE_DATA(q, MultiQueueItem, node);
}
+
+/// Allow an event to be processed by multiple child queues to the main queue
+///
+/// The handler will be fired once by the _first_ queue that processes the
+/// event. Later processing will do nothing (just memory cleanup).
+///
+/// @param ev the event
+/// @param num number of queues that the split event will be put on
+/// @return an Event that is safe to put onto `num` queues
+Event event_split(Event ev, int num)
+{
+ SplitEvent *data = xmalloc(sizeof(*data));
+ data->event = ev;
+ data->fired = false;
+ data->refcount = num;
+ return event_create(split_event, 1, data);
+}
+static void split_event(void ** argv)
+{
+ SplitEvent *data = argv[0];
+ if (!data->fired) {
+ data->fired = true;
+ if (data->event.handler) {
+ data->event.handler(data->event.argv);
+ }
+ }
+ if ((--data->refcount) == 0) {
+ xfree(data);
+ }
+}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index a0fbde008b..c3e1e69a63 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -5673,7 +5673,6 @@ void ex_substitute(exarg_T *eap)
}
block_autocmds(); // Disable events during command preview.
- input_disable_events();
char_u *save_eap = eap->arg;
garray_T save_view;
@@ -5716,7 +5715,6 @@ void ex_substitute(exarg_T *eap)
restore_search_patterns();
win_size_restore(&save_view);
ga_clear(&save_view);
- input_enable_events();
unblock_autocmds();
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index d524c3d035..154bf9f5f6 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5099,10 +5099,10 @@ static void uc_list(char_u *name, size_t name_len)
if (p_verbose > 0) {
last_set_msg(cmd->uc_script_ctx);
}
- ui_flush();
- os_breakcheck();
- if (got_int)
+ line_breakcheck();
+ if (got_int) {
break;
+ }
}
if (gap == &ucmds || i < gap->ga_len)
break;
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 318b36860e..2469bb5baa 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1532,8 +1532,9 @@ int safe_vgetc(void)
int c;
c = vgetc();
- if (c == NUL)
- c = get_keystroke();
+ if (c == NUL) {
+ c = get_keystroke(NULL);
+ }
return c;
}
@@ -2447,9 +2448,10 @@ int inchar(
char_u dum[DUM_LEN + 1];
for (;; ) {
- len = os_inchar(dum, DUM_LEN, 0L, 0);
- if (len == 0 || (len == 1 && dum[0] == 3))
+ len = os_inchar(dum, DUM_LEN, 0L, 0, NULL);
+ if (len == 0 || (len == 1 && dum[0] == 3)) {
break;
+ }
}
return retesc;
}
@@ -2460,7 +2462,7 @@ int inchar(
// Fill up to a third of the buffer, because each character may be
// tripled below.
- len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt);
+ len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt, NULL);
}
// If the typebuf was changed further down, it is like nothing was added by
diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h
index a40ea7730a..01f60ccf49 100644
--- a/src/nvim/getchar.h
+++ b/src/nvim/getchar.h
@@ -57,9 +57,8 @@ struct map_arguments {
};
typedef struct map_arguments MapArguments;
-#define KEYLEN_PART_KEY -1 /* keylen value for incomplete key-code */
-#define KEYLEN_PART_MAP -2 /* keylen value for incomplete mapping */
-#define KEYLEN_REMOVED 9999 /* keylen value for removed sequence */
+#define KEYLEN_PART_KEY -1 // keylen value for incomplete key-code
+#define KEYLEN_PART_MAP -2 // keylen value for incomplete mapping
/// Maximum number of streams to read script from
enum { NSCRIPT = 15 };
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 50e495c1e6..4335dab1f9 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -144,6 +144,8 @@ void event_init(void)
{
log_init();
loop_init(&main_loop, NULL);
+ resize_events = multiqueue_new_child(main_loop.events);
+
// early msgpack-rpc initialization
msgpack_rpc_init_method_table();
msgpack_rpc_helpers_init();
diff --git a/src/nvim/message.c b/src/nvim/message.c
index c499aa5f0c..30e906cd5f 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -2556,6 +2556,7 @@ static int do_more_prompt(int typed_char)
int c;
int retval = FALSE;
int toscroll;
+ bool to_redraw = false;
msgchunk_T *mp_last = NULL;
msgchunk_T *mp;
int i;
@@ -2587,8 +2588,9 @@ static int do_more_prompt(int typed_char)
if (used_typed_char != NUL) {
c = used_typed_char; /* was typed at hit-enter prompt */
used_typed_char = NUL;
- } else
- c = get_keystroke();
+ } else {
+ c = get_keystroke(resize_events);
+ }
toscroll = 0;
@@ -2661,31 +2663,44 @@ static int do_more_prompt(int typed_char)
lines_left = Rows - 1;
break;
+ case K_EVENT:
+ // only resize_events are processed here
+ // Attempt to redraw the screen. sb_text doesn't support reflow
+ // so this only really works for vertical resize.
+ multiqueue_process_events(resize_events);
+ to_redraw = true;
+ break;
+
default: /* no valid response */
msg_moremsg(TRUE);
continue;
}
- if (toscroll != 0) {
- if (toscroll < 0) {
- /* go to start of last line */
- if (mp_last == NULL)
+ // code assumes we only do one at a time
+ assert((toscroll == 0) || !to_redraw);
+
+ if (toscroll != 0 || to_redraw) {
+ if (toscroll < 0 || to_redraw) {
+ // go to start of last line
+ if (mp_last == NULL) {
mp = msg_sb_start(last_msgchunk);
- else if (mp_last->sb_prev != NULL)
+ } else if (mp_last->sb_prev != NULL) {
mp = msg_sb_start(mp_last->sb_prev);
- else
+ } else {
mp = NULL;
+ }
/* go to start of line at top of the screen */
for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL;
++i)
mp = msg_sb_start(mp->sb_prev);
- if (mp != NULL && mp->sb_prev != NULL) {
- /* Find line to be displayed at top. */
- for (i = 0; i > toscroll; --i) {
- if (mp == NULL || mp->sb_prev == NULL)
+ if (mp != NULL && (mp->sb_prev != NULL || to_redraw)) {
+ // Find line to be displayed at top
+ for (i = 0; i > toscroll; i--) {
+ if (mp == NULL || mp->sb_prev == NULL) {
break;
+ }
mp = msg_sb_start(mp->sb_prev);
if (mp_last == NULL)
mp_last = msg_sb_start(last_msgchunk);
@@ -2693,7 +2708,7 @@ static int do_more_prompt(int typed_char)
mp_last = msg_sb_start(mp_last->sb_prev);
}
- if (toscroll == -1) {
+ if (toscroll == -1 && !to_redraw) {
grid_ins_lines(&msg_grid_adj, 0, 1, Rows, 0, Columns);
grid_fill(&msg_grid_adj, 0, 1, 0, Columns, ' ', ' ',
HL_ATTR(HLF_MSG));
@@ -2709,6 +2724,7 @@ static int do_more_prompt(int typed_char)
mp = disp_sb_line(i, mp);
++msg_scrolled;
}
+ to_redraw = false;
}
toscroll = 0;
}
@@ -3307,8 +3323,8 @@ do_dialog (
hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
for (;; ) {
- /* Get a typed character directly from the user. */
- c = get_keystroke();
+ // Get a typed character directly from the user.
+ c = get_keystroke(NULL);
switch (c) {
case CAR: /* User accepts default option */
case NL:
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index bb95cd5737..ab3520dd73 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -560,7 +560,7 @@ int ask_yesno(const char *const str, const bool direct)
// Same highlighting as for wait_return.
smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str);
if (direct) {
- r = get_keystroke();
+ r = get_keystroke(NULL);
} else {
r = plain_vgetc();
}
@@ -614,7 +614,7 @@ int is_mouse_key(int c)
* Disadvantage: typeahead is ignored.
* Translates the interrupt character for unix to ESC.
*/
-int get_keystroke(void)
+int get_keystroke(MultiQueue *events)
{
char_u *buf = NULL;
int buflen = 150;
@@ -644,7 +644,7 @@ int get_keystroke(void)
/* First time: blocking wait. Second time: wait up to 100ms for a
* terminal code to complete. */
- n = os_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0);
+ n = os_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0, events);
if (n > 0) {
// Replace zero and CSI by a special key code.
n = fix_input_buffer(buf + len, n);
@@ -653,18 +653,12 @@ int get_keystroke(void)
} else if (len > 0)
++waited; /* keep track of the waiting time */
- if (n == KEYLEN_REMOVED) { /* key code removed */
- if (must_redraw != 0 && !need_wait_return && (State & CMDLINE) == 0) {
- /* Redrawing was postponed, do it now. */
- update_screen(0);
- setcursor(); /* put cursor back where it belongs */
- }
- continue;
- }
- if (n > 0) /* found a termcode: adjust length */
+ if (n > 0) { // found a termcode: adjust length
len = n;
- if (len == 0) /* nothing typed yet */
+ }
+ if (len == 0) { // nothing typed yet
continue;
+ }
/* Handle modifier and/or special key code. */
n = buf[0];
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 81c9f1e3f4..19f626c63b 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -31,6 +31,7 @@
#include "nvim/misc1.h"
#include "nvim/lib/kvec.h"
#include "nvim/os/input.h"
+#include "nvim/ui.h"
#if MIN_LOG_LEVEL > DEBUG_LOG_LEVEL
#define log_client_msg(...)
@@ -355,11 +356,19 @@ static void handle_request(Channel *channel, msgpack_object *request)
request_event((void **)&evdata);
}
} else {
- multiqueue_put(channel->events, request_event, 1, evdata);
- DLOG("RPC: scheduled %.*s", method->via.bin.size, method->via.bin.ptr);
+ bool is_resize = handler.fn == handle_nvim_ui_try_resize;
+ if (is_resize) {
+ Event ev = event_split(event_create(request_event, 1, evdata), 2);
+ multiqueue_put_event(channel->events, ev);
+ multiqueue_put_event(resize_events, ev);
+ } else {
+ multiqueue_put(channel->events, request_event, 1, evdata);
+ DLOG("RPC: scheduled %.*s", method->via.bin.size, method->via.bin.ptr);
+ }
}
}
+
/// Handles a message, depending on the type:
/// - Request: invokes method and writes the response (or error).
/// - Notification: invokes method (emits `nvim_error_event` on error).
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 83ac3dfa62..c1580c5fc3 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -38,7 +38,6 @@ static Stream read_stream = { .closed = true }; // Input before UI starts.
static RBuffer *input_buffer = NULL;
static bool input_eof = false;
static int global_fd = -1;
-static int events_enabled = 0;
static bool blocking = false;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -89,7 +88,7 @@ static void cursorhold_event(void **argv)
did_cursorhold = true;
}
-static void create_cursorhold_event(void)
+static void create_cursorhold_event(bool events_enabled)
{
// If events are enabled and the queue has any items, this function should not
// have been called(inbuf_poll would return kInputAvail)
@@ -99,8 +98,12 @@ static void create_cursorhold_event(void)
multiqueue_put(main_loop.events, cursorhold_event, 0);
}
-// Low level input function
-int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
+/// Low level input function
+///
+/// wait until either the input buffer is non-empty or , if `events` is not NULL
+/// until `events` is non-empty.
+int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt,
+ MultiQueue *events)
{
if (maxlen && rbuffer_size(input_buffer)) {
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
@@ -108,21 +111,21 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
InbufPollResult result;
if (ms >= 0) {
- if ((result = inbuf_poll(ms)) == kInputNone) {
+ if ((result = inbuf_poll(ms, events)) == kInputNone) {
return 0;
}
} else {
- if ((result = inbuf_poll((int)p_ut)) == kInputNone) {
+ if ((result = inbuf_poll((int)p_ut, events)) == kInputNone) {
if (read_stream.closed && silent_mode) {
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
read_error_exit();
}
if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) {
- create_cursorhold_event();
+ create_cursorhold_event(events == main_loop.events);
} else {
before_blocking();
- result = inbuf_poll(-1);
+ result = inbuf_poll(-1, events);
}
}
}
@@ -139,7 +142,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
}
// If there are events, return the keys directly
- if (maxlen && pending_events()) {
+ if (maxlen && pending_events(events)) {
return push_event_key(buf, maxlen);
}
@@ -153,7 +156,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt)
// Check if a character is available for reading
bool os_char_avail(void)
{
- return inbuf_poll(0) == kInputAvail;
+ return inbuf_poll(0, NULL) == kInputAvail;
}
// Check for CTRL-C typed by reading all available characters.
@@ -170,15 +173,6 @@ void os_breakcheck(void)
updating_screen = save_us;
}
-void input_enable_events(void)
-{
- events_enabled++;
-}
-
-void input_disable_events(void)
-{
- events_enabled--;
-}
/// Test whether a file descriptor refers to a terminal.
///
@@ -383,27 +377,37 @@ bool input_blocking(void)
return blocking;
}
-static bool input_poll(int ms)
+// This is a replacement for the old `WaitForChar` function in os_unix.c
+static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
{
+ if (input_ready(events)) {
+ return kInputAvail;
+ }
+
if (do_profiling == PROF_YES && ms) {
prof_inchar_enter();
}
- if ((ms == - 1 || ms > 0) && !events_enabled && !input_eof) {
+ if ((ms == - 1 || ms > 0) && events == NULL && !input_eof) {
// The pending input provoked a blocking wait. Do special events now. #6247
blocking = true;
multiqueue_process_events(ch_before_blocking_events);
}
- DLOG("blocking... events_enabled=%d events_pending=%d", events_enabled,
- !multiqueue_empty(main_loop.events));
- LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, input_ready() || input_eof);
+ DLOG("blocking... events_enabled=%d events_pending=%d", events != NULL,
+ events && !multiqueue_empty(events));
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms,
+ input_ready(events) || input_eof);
blocking = false;
if (do_profiling == PROF_YES && ms) {
prof_inchar_exit();
}
- return input_ready();
+ if (input_ready(events)) {
+ return kInputAvail;
+ } else {
+ return input_eof ? kInputEof : kInputNone;
+ }
}
void input_done(void)
@@ -416,16 +420,6 @@ bool input_available(void)
return rbuffer_size(input_buffer) != 0;
}
-// This is a replacement for the old `WaitForChar` function in os_unix.c
-static InbufPollResult inbuf_poll(int ms)
-{
- if (input_ready() || input_poll(ms)) {
- return kInputAvail;
- }
-
- return input_eof ? kInputEof : kInputNone;
-}
-
static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
bool at_eof)
{
@@ -478,11 +472,11 @@ static int push_event_key(uint8_t *buf, int maxlen)
}
// Check if there's pending input
-static bool input_ready(void)
+static bool input_ready(MultiQueue *events)
{
return (typebuf_was_filled // API call filled typeahead
|| rbuffer_size(input_buffer) // Input buffer filled
- || pending_events()); // Events must be processed
+ || pending_events(events)); // Events must be processed
}
// Exit because of an input read error.
@@ -495,7 +489,7 @@ static void read_error_exit(void)
preserve_exit();
}
-static bool pending_events(void)
+static bool pending_events(MultiQueue *events)
{
- return events_enabled && !multiqueue_empty(main_loop.events);
+ return events && !multiqueue_empty(events);
}
diff --git a/src/nvim/os/input.h b/src/nvim/os/input.h
index 5902677a35..d571965408 100644
--- a/src/nvim/os/input.h
+++ b/src/nvim/os/input.h
@@ -5,6 +5,7 @@
#include <stdbool.h>
#include "nvim/api/private/defs.h"
+#include "nvim/event/multiqueue.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/input.h.generated.h"
diff --git a/src/nvim/state.c b/src/nvim/state.c
index dbf04eebec..81bc078a88 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -46,14 +46,12 @@ getkey:
// Event was made available after the last multiqueue_process_events call
key = K_EVENT;
} else {
- input_enable_events();
// Flush screen updates before blocking
ui_flush();
// Call `os_inchar` directly to block for events or user input without
// consuming anything from `input_buffer`(os/input.c) or calling the
// mapping engine.
- (void)os_inchar(NULL, 0, -1, 0);
- input_disable_events();
+ (void)os_inchar(NULL, 0, -1, 0, main_loop.events);
// If an event was put into the queue, we send K_EVENT directly.
key = !multiqueue_empty(main_loop.events)
? K_EVENT
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 94fae0a774..d8c9a3e780 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -174,7 +174,7 @@ void ui_refresh(void)
}
if (updating_screen) {
- ui_schedule_refresh();
+ deferred_refresh_event(NULL);
return;
}
@@ -228,11 +228,11 @@ static void ui_refresh_event(void **argv)
void ui_schedule_refresh(void)
{
- // TODO(bfredl): "fast" is not optimal. UI should be refreshed only at
- // deferred processing plus a few more blocked-on-input situtions like
- // wait_return(), but not any os_breakcheck(). Alternatively make this
- // defered and make wait_return() process deferred events already.
- loop_schedule_fast(&main_loop, event_create(ui_refresh_event, 0));
+ loop_schedule_fast(&main_loop, event_create(deferred_refresh_event, 0));
+}
+static void deferred_refresh_event(void **argv)
+{
+ multiqueue_put(resize_events, ui_refresh_event, 0);
}
void ui_default_colors_set(void)
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index e1dd18a289..1f549160db 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -66,4 +66,7 @@ struct ui_t {
# include "ui.h.generated.h"
# include "ui_events_call.h.generated.h"
#endif
+
+
+EXTERN MultiQueue *resize_events;
#endif // NVIM_UI_H
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index d50ecd2e6f..131ce7ed0b 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -689,6 +689,7 @@ end
module.funcs = module.create_callindex(module.call)
module.meths = module.create_callindex(module.nvim)
+module.async_meths = module.create_callindex(module.nvim_async)
module.uimeths = module.create_callindex(ui)
module.bufmeths = module.create_callindex(module.buffer)
module.winmeths = module.create_callindex(module.window)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 3225ce5162..56c1cc0d7b 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -122,10 +122,10 @@ describe('TUI', function()
screen:try_resize(50,5)
screen:expect{grid=[[
- {8:FAIL 1} |
- {8:FAIL 2} |
{8:FAIL 3} |
- {10:-- More -- SPACE/d/j: screen/page/line down, b/u/}{12:k}|
+ {8:FAIL 4} |
+ {8:FAIL 5} |
+ {10:-- More --}{1: } |
{3:-- TERMINAL --} |
]]}
@@ -144,12 +144,12 @@ describe('TUI', function()
) |
{8:Error detected while processing function ManyErr:} |
{11:line 2:} |
- {10:-- More --} |
- {10: }|
- {10: }|
- {10: }|
- {10: }|
- {10:-- More -- SPACE/d/j: screen/page/line down, b/u/}{12:k}|
+ {8:FAIL 0} |
+ {8:FAIL 1} |
+ {8:FAIL 2} |
+ {8:FAIL 3} |
+ {8:FAIL 4} |
+ {10:-- More --}{1: } |
{3:-- TERMINAL --} |
]]}
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 90874a92ef..875e4092a6 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -6,6 +6,7 @@ local eq = helpers.eq
local command = helpers.command
local set_method_error = helpers.set_method_error
local meths = helpers.meths
+local async_meths = helpers.async_meths
local test_build_dir = helpers.test_build_dir
local nvim_prog = helpers.nvim_prog
local iswin = helpers.iswin
@@ -1073,6 +1074,7 @@ describe('pager', function()
[9] = {foreground = tonumber('0x00000c'), background = Screen.colors.Grey100},
[10] = {background = Screen.colors.Grey100, bold = true, foreground = tonumber('0xe5e5ff')},
[11] = {background = Screen.colors.Grey100, bold = true, foreground = tonumber ('0x2b8452')},
+ [12] = {bold = true, reverse = true},
})
command("set more")
@@ -1392,4 +1394,119 @@ aliquip ex ea commodo consequat.]])
{11:--}{8: }{11:More}{8: }{11:--}{8:^ }|
]]}
end)
+
+ it('with :!cmd does not crash on resize', function()
+ feed(':!sleep 1<cr>')
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {12: }|
+ :!sleep 1 |
+ |
+ ]]}
+
+ -- not processed while command is executing
+ async_meths.ui_try_resize(35, 5)
+
+ -- TODO(bfredl): ideally it should be processed just
+ -- before the "press ENTER" prompt though
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {12: }|
+ :!sleep 1 |
+ |
+ {4:Press ENTER or type command to cont}|
+ {4:inue}^ |
+ ]]}
+
+ feed('<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('can be resized', function()
+ feed(':lua error(_G.x)<cr>')
+ screen:expect{grid=[[
+ {2:E5105: Error while calling lua chun}|
+ {2:k: [string "<VimL compiled string>"}|
+ {2:]:1: Lorem ipsum dolor sit amet, co}|
+ {2:nsectetur} |
+ {2:adipisicing elit, sed do eiusmod te}|
+ {2:mpor} |
+ {2:incididunt ut labore et dolore magn}|
+ {4:-- More --}^ |
+ ]]}
+
+ -- responds to resize, but text is not reflown
+ screen:try_resize(45, 5)
+ screen:expect{grid=[[
+ {2:nsectetur} |
+ {2:adipisicing elit, sed do eiusmod te} |
+ {2:mpor} |
+ {2:incididunt ut labore et dolore magn} |
+ {4:-- More --}^ |
+ ]]}
+
+ -- can create empty space, as the command hasn't output the text below yet.
+ -- text is not reflown; existing lines get cut
+ screen:try_resize(30, 12)
+ screen:expect{grid=[[
+ {2:E5105: Error while calling lua}|
+ {2:k: [string "<VimL compiled str}|
+ {2:]:1: Lorem ipsum dolor sit ame}|
+ {2:nsectetur} |
+ {2:adipisicing elit, sed do eiusm}|
+ {2:mpore} |
+ {2:incididunt ut labore et dolore}|
+ {2: magn} |
+ |
+ |
+ |
+ {4:-- More --}^ |
+ ]]}
+
+ -- continues in a mostly consistent state, but only new lines are
+ -- wrapped at the new screen size.
+ feed('<cr>')
+ screen:expect{grid=[[
+ {2:k: [string "<VimL compiled str}|
+ {2:]:1: Lorem ipsum dolor sit ame}|
+ {2:nsectetur} |
+ {2:adipisicing elit, sed do eiusm}|
+ {2:mpore} |
+ {2:incididunt ut labore et dolore}|
+ {2: magna aliqua.} |
+ {2:Ut enim ad minim veniam, quis }|
+ {2:nostrud xercitation} |
+ {2:ullamco laboris nisi ut} |
+ {2:aliquip ex ea commodo consequa}|
+ {4:-- More --}^ |
+ ]]}
+
+ feed('q')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
end)