Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] api: nvim_get_mode() #6247

Merged
merged 4 commits into from
Apr 28, 2017
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
5 changes: 0 additions & 5 deletions runtime/doc/help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -154,22 +154,17 @@ Interfaces ~
|if_cscop.txt| using Cscope with Vim
|if_pyth.txt| Python interface
|if_ruby.txt| Ruby interface
|debugger.txt| Interface with a debugger
|sign.txt| debugging signs

Versions ~
|vim_diff.txt| Main differences between Nvim and Vim
|vi_diff.txt| Main differences between Vim and Vi
*sys-file-list*
Remarks about specific systems ~
|os_win32.txt| MS-Windows
*standard-plugin-list*
Standard plugins ~
|pi_gzip.txt| Reading and writing compressed files
|pi_netrw.txt| Reading and writing files over a network
|pi_paren.txt| Highlight matching parens
|pi_tar.txt| Tar file explorer
|pi_vimball.txt| Create a self-installing Vim script
|pi_zip.txt| Zip archive explorer

LOCAL ADDITIONS: *local-additions*
Expand Down
5 changes: 0 additions & 5 deletions runtime/doc/intro.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ It can be accessed from within Vim with the <Help> or <F1> key and with the
is not located in the default place. You can jump to subjects like with tags:
Use CTRL-] to jump to a subject under the cursor, use CTRL-T to jump back.

This manual refers to Vim on various machines. There may be small differences
between different computers and terminals. Besides the remarks given in this
document, there is a separate document for each supported system, see
|sys-file-list|.

*pronounce*
Vim is pronounced as one word, like Jim, not vi-ai-em. It's written with a
capital, since it's a name, again like Jim.
Expand Down
4 changes: 0 additions & 4 deletions runtime/doc/message.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ Note: If the output has been stopped with "q" at the more prompt, it will only
be displayed up to this point.
The previous command output is cleared when another command produces output.

If you are using translated messages, the first printed line tells who
maintains the messages or the translations. You can use this to contact the
maintainer when you spot a mistake.

If you want to find help on a specific (error) message, use the ID at the
start of the message. For example, to get help on the message: >

Expand Down
19 changes: 19 additions & 0 deletions src/nvim/api/vim.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/option.h"
#include "nvim/state.h"
#include "nvim/syntax.h"
#include "nvim/getchar.h"
#include "nvim/os/input.h"
Expand Down Expand Up @@ -701,6 +702,24 @@ Dictionary nvim_get_color_map(void)
}


/// Gets the current mode.
/// mode: Mode string. |mode()|
/// blocking: true if Nvim is waiting for input.
///
/// @returns Dictionary { "mode": String, "blocking": Boolean }
Dictionary nvim_get_mode(void)
FUNC_API_SINCE(2) FUNC_API_ASYNC
{
Dictionary rv = ARRAY_DICT_INIT;
char *modestr = get_mode();
bool blocked = input_blocking();

PUT(rv, "mode", STRING_OBJ(cstr_as_string(modestr)));
PUT(rv, "blocking", BOOLEAN_OBJ(blocked));

return rv;
}

Array nvim_get_api_info(uint64_t channel_id)
FUNC_API_SINCE(1) FUNC_API_ASYNC FUNC_API_NOEVAL
{
Expand Down
55 changes: 7 additions & 48 deletions src/nvim/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -12575,59 +12575,18 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}

/*
* "mode()" function
*/
/// "mode()" function
static void f_mode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char_u buf[3];
char *mode = get_mode();

buf[1] = NUL;
buf[2] = NUL;

if (VIsual_active) {
if (VIsual_select)
buf[0] = VIsual_mode + 's' - 'v';
else
buf[0] = VIsual_mode;
} else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
|| State == CONFIRM) {
buf[0] = 'r';
if (State == ASKMORE)
buf[1] = 'm';
else if (State == CONFIRM)
buf[1] = '?';
} else if (State == EXTERNCMD)
buf[0] = '!';
else if (State & INSERT) {
if (State & VREPLACE_FLAG) {
buf[0] = 'R';
buf[1] = 'v';
} else if (State & REPLACE_FLAG)
buf[0] = 'R';
else
buf[0] = 'i';
} else if (State & CMDLINE) {
buf[0] = 'c';
if (exmode_active)
buf[1] = 'v';
} else if (exmode_active) {
buf[0] = 'c';
buf[1] = 'e';
} else if (State & TERM_FOCUS) {
buf[0] = 't';
} else {
buf[0] = 'n';
if (finish_op)
buf[1] = 'o';
// Clear out the minor mode when the argument is not a non-zero number or
// non-empty string.
if (!non_zero_arg(&argvars[0])) {
mode[1] = NUL;
}

/* Clear out the minor mode when the argument is not a non-zero number or
* non-empty string. */
if (!non_zero_arg(&argvars[0]))
buf[1] = NUL;

rettv->vval.v_string = vim_strsave(buf);
rettv->vval.v_string = (char_u *)mode;
rettv->v_type = VAR_STRING;
}

Expand Down
8 changes: 3 additions & 5 deletions src/nvim/event/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@

typedef void (*argv_callback)(void **argv);
typedef struct message {
int priority;
argv_callback handler;
void *argv[EVENT_HANDLER_MAX_ARGC];
} Event;
typedef void(*event_scheduler)(Event event, void *data);

#define VA_EVENT_INIT(event, p, h, a) \
#define VA_EVENT_INIT(event, h, a) \
do { \
assert(a <= EVENT_HANDLER_MAX_ARGC); \
(event)->priority = p; \
(event)->handler = h; \
if (a) { \
va_list args; \
Expand All @@ -29,11 +27,11 @@ typedef void(*event_scheduler)(Event event, void *data);
} \
} while (0)

static inline Event event_create(int priority, argv_callback cb, int argc, ...)
static inline Event event_create(argv_callback cb, int argc, ...)
{
assert(argc <= EVENT_HANDLER_MAX_ARGC);
Event event;
VA_EVENT_INIT(&event, priority, cb, argc);
VA_EVENT_INIT(&event, cb, argc);
return event;
}

Expand Down
3 changes: 1 addition & 2 deletions src/nvim/event/loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ void loop_poll_events(Loop *loop, int ms)
// we do not block indefinitely for I/O.
uv_timer_start(&loop->poll_timer, timer_cb, (uint64_t)ms, (uint64_t)ms);
} else if (ms == 0) {
// For ms == 0, we need to do a non-blocking event poll by
// setting the run mode to UV_RUN_NOWAIT.
// For ms == 0, do a non-blocking event poll.
mode = UV_RUN_NOWAIT;
}

Expand Down
48 changes: 31 additions & 17 deletions src/nvim/event/multiqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ void multiqueue_free(MultiQueue *this)
xfree(this);
}

/// Removes the next item and returns its Event.
Event multiqueue_get(MultiQueue *this)
{
return multiqueue_empty(this) ? NILEVENT : multiqueue_remove(this);
Expand All @@ -144,7 +145,7 @@ void multiqueue_process_events(MultiQueue *this)
{
assert(this);
while (!multiqueue_empty(this)) {
Event event = multiqueue_get(this);
Event event = multiqueue_remove(this);
if (event.handler) {
event.handler(event.argv);
}
Expand Down Expand Up @@ -178,43 +179,56 @@ size_t multiqueue_size(MultiQueue *this)
return this->size;
}

static Event multiqueue_remove(MultiQueue *this)
/// Gets an Event from an item.
///
/// @param remove Remove the node from its queue, and free it.
static Event multiqueueitem_get_event(MultiQueueItem *item, bool remove)
{
assert(!multiqueue_empty(this));
QUEUE *h = QUEUE_HEAD(&this->headtail);
QUEUE_REMOVE(h);
MultiQueueItem *item = multiqueue_node_data(h);
Event rv;

assert(item != NULL);
Event ev;
if (item->link) {
assert(!this->parent);
// remove the next node in the linked queue
// get the next node in the linked queue
MultiQueue *linked = item->data.queue;
assert(!multiqueue_empty(linked));
MultiQueueItem *child =
multiqueue_node_data(QUEUE_HEAD(&linked->headtail));
QUEUE_REMOVE(&child->node);
rv = child->data.item.event;
xfree(child);
ev = child->data.item.event;
// remove the child node
if (remove) {
QUEUE_REMOVE(&child->node);
xfree(child);
}
} else {
if (this->parent) {
// remove the corresponding link node in the parent queue
// remove the corresponding link node in the parent queue
if (remove && item->data.item.parent_item) {
QUEUE_REMOVE(&item->data.item.parent_item->node);
xfree(item->data.item.parent_item);
item->data.item.parent_item = NULL;
}
rv = item->data.item.event;
ev = item->data.item.event;
}
return ev;
}

static Event multiqueue_remove(MultiQueue *this)
{
assert(!multiqueue_empty(this));
QUEUE *h = QUEUE_HEAD(&this->headtail);
QUEUE_REMOVE(h);
MultiQueueItem *item = multiqueue_node_data(h);
assert(!item->link || !this->parent); // Only a parent queue has link-nodes
Event ev = multiqueueitem_get_event(item, true);
this->size--;
xfree(item);
return rv;
return ev;
}

static void multiqueue_push(MultiQueue *this, Event event)
{
MultiQueueItem *item = xmalloc(sizeof(MultiQueueItem));
item->link = false;
item->data.item.event = event;
item->data.item.parent_item = NULL;
QUEUE_INSERT_TAIL(&this->headtail, &item->node);
if (this->parent) {
// push link node to the parent queue
Expand Down
2 changes: 1 addition & 1 deletion src/nvim/event/multiqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ typedef struct multiqueue MultiQueue;
typedef void (*put_callback)(MultiQueue *multiq, void *data);

#define multiqueue_put(q, h, ...) \
multiqueue_put_event(q, event_create(1, h, __VA_ARGS__));
multiqueue_put_event(q, event_create(h, __VA_ARGS__));


#ifdef INCLUDE_GENERATED_DECLARATIONS
Expand Down
4 changes: 0 additions & 4 deletions src/nvim/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,6 @@ char *xstpcpy(char *restrict dst, const char *restrict src)
/// WARNING: xstpncpy will ALWAYS write maxlen bytes. If src is shorter than
/// maxlen, zeroes will be written to the remaining bytes.
///
/// TODO(aktau): I don't see a good reason to have this last behaviour, and
/// it is potentially wasteful. Could we perhaps deviate from the standard
/// and not zero the rest of the buffer?
///
/// @param dst
/// @param src
/// @param maxlen
Expand Down
2 changes: 1 addition & 1 deletion src/nvim/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ void msg_schedule_emsgf(const char *const fmt, ...)
va_end(ap);

char *s = xstrdup((char *)IObuff);
loop_schedule(&main_loop, event_create(1, msg_emsgf_event, 1, s));
loop_schedule(&main_loop, event_create(msg_emsgf_event, 1, s));
}

/*
Expand Down
25 changes: 18 additions & 7 deletions src/nvim/msgpack_rpc/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "nvim/log.h"
#include "nvim/misc1.h"
#include "nvim/lib/kvec.h"
#include "nvim/os/input.h"

#define CHANNEL_BUFFER_SIZE 0xffff

Expand Down Expand Up @@ -89,6 +90,7 @@ static msgpack_sbuffer out_buffer;
/// Initializes the module
void channel_init(void)
{
ch_before_blocking_events = multiqueue_new_child(main_loop.events);
channels = pmap_new(uint64_t)();
event_strings = pmap_new(cstr_t)();
msgpack_sbuffer_init(&out_buffer);
Expand Down Expand Up @@ -433,16 +435,25 @@ static void handle_request(Channel *channel, msgpack_object *request)
handler.async = true;
}

RequestEvent *event_data = xmalloc(sizeof(RequestEvent));
event_data->channel = channel;
event_data->handler = handler;
event_data->args = args;
event_data->request_id = request_id;
RequestEvent *evdata = xmalloc(sizeof(RequestEvent));
evdata->channel = channel;
evdata->handler = handler;
evdata->args = args;
evdata->request_id = request_id;
incref(channel);
if (handler.async) {
on_request_event((void **)&event_data);
bool is_get_mode = sizeof("nvim_get_mode") - 1 == method->via.bin.size
&& !strncmp("nvim_get_mode", method->via.bin.ptr, method->via.bin.size);

if (is_get_mode && !input_blocking()) {
// Defer the event to a special queue used by os/input.c. #6247
multiqueue_put(ch_before_blocking_events, on_request_event, 1, evdata);
} else {
// Invoke immediately.
on_request_event((void **)&evdata);
}
} else {
multiqueue_put(channel->events, on_request_event, 1, event_data);
multiqueue_put(channel->events, on_request_event, 1, evdata);
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/nvim/msgpack_rpc/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@

#define METHOD_MAXLEN 512

/// HACK: os/input.c drains this queue immediately before blocking for input.
/// Events on this queue are async-safe, but they need the resolved state
/// of os_inchar(), so they are processed "just-in-time".
MultiQueue *ch_before_blocking_events;

#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "msgpack_rpc/channel.h.generated.h"
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/nvim/msgpack_rpc/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ typedef struct {
size_t idx;
} MPToAPIObjectStackItem;

/// Convert type used by msgpack parser to Neovim own API type
/// Convert type used by msgpack parser to Nvim API type.
///
/// @param[in] obj Msgpack value to convert.
/// @param[out] arg Location where result of conversion will be saved.
Expand Down
4 changes: 2 additions & 2 deletions src/nvim/normal.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ static bool normal_handle_special_visual_command(NormalState *s)
return false;
}

static bool normal_need_aditional_char(NormalState *s)
static bool normal_need_additional_char(NormalState *s)
{
int flags = nv_cmds[s->idx].cmd_flags;
bool pending_op = s->oa.op_type != OP_NOP;
Expand Down Expand Up @@ -1083,7 +1083,7 @@ static int normal_execute(VimState *state, int key)
}

// Get an additional character if we need one.
if (normal_need_aditional_char(s)) {
if (normal_need_additional_char(s)) {
normal_get_additional_char(s);
}

Expand Down
Loading