Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/nvim/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
37 changes: 37 additions & 0 deletions src/nvim/event/multiqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bfredl is it really limited to "child queues of the main queue" ? Seems like any queue could be used (safely), no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, it is just easier to reason about. Events will always be processed by the main queue "eventually", child queues processes subsets of the main queue events. This allows events to be in two (or more) such named subsets.

///
/// 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);
}
}
2 changes: 0 additions & 2 deletions src/nvim/ex_cmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}

Expand Down
6 changes: 3 additions & 3 deletions src/nvim/ex_docmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 7 additions & 5 deletions src/nvim/getchar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand All @@ -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
Expand Down
5 changes: 2 additions & 3 deletions src/nvim/getchar.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
2 changes: 2 additions & 0 deletions src/nvim/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
46 changes: 31 additions & 15 deletions src/nvim/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2661,39 +2663,52 @@ 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);
else
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));
Expand All @@ -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;
}
Expand Down Expand Up @@ -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:
Expand Down
20 changes: 7 additions & 13 deletions src/nvim/misc1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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];
Expand Down
13 changes: 11 additions & 2 deletions src/nvim/msgpack_rpc/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(...)
Expand Down Expand Up @@ -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).
Expand Down
Loading