Commit Graph

117 Commits

Author SHA1 Message Date
Björn Linse
19993bca4a rpc: allow handling of nvim_ui_try_resize at the pager
This makes external UI behave consistenly with TUI w.r.t resizes.
Which will be needed anyway as TUI will use the external UI protocol
soon.
2019-09-08 15:24:14 +02:00
Björn Linse
7030d7daf1 rename: FUNC_API_ASYNC => FUNC_API_FAST 2019-06-30 11:33:01 +02:00
Justin M. Keyes
f046f3a239 build: fix some warnings
../src/nvim/event/rstream.c:119:44: warning: format specifies type 'void *' but the argument has type 'Stream *' (aka 'struct stream *') [-Wformat-pedantic]
          DLOG("Closing Stream (%p): %s (%s)", stream,
                                ~~             ^~~~~~
    ../src/nvim/event/stream.c:95:30: warning: format specifies type 'void *' but the argument has type 'Stream *' (aka 'struct stream *') [-Wformat-pedantic]
      DLOG("closing Stream: %p", stream);
                            ~~   ^~~~~~
    ../src/nvim/msgpack_rpc/channel.c:71:72: warning: format specifies type 'void *' but the argument has type 'Stream *' (aka 'struct stream *') [-Wformat-pedantic]
        DLOG("rpc ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id, in, out);
                                           ~~                              ^~
    ../src/nvim/msgpack_rpc/channel.c:71:76: warning: format specifies type 'void *' but the argument has type 'Stream *' (aka 'struct stream *') [-Wformat-pedantic]
        DLOG("rpc ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id, in, out);
                                                         ~~                    ^~~
    ../src/nvim/msgpack_rpc/channel.c:226:28: warning: format specifies type 'void *' but the argument has type 'Stream *' (aka 'struct stream *') [-Wformat-pedantic]
           channel->id, count, stream);
                               ^~~~~~
2019-06-03 00:21:20 +02:00
Björn Linse
8ed54bbec3 messages: use proper multiline error message for rpcrequest and API wrappers 2019-05-26 15:42:16 +02:00
Justin M. Keyes
7e1591e06a API: emit nvim_error_event on failed async request
We already do this for _invalid_ async requests #9300.
Now we also do it for failed invocation of valid requests.
2019-04-13 17:07:58 +02:00
Daniel Bershatsky
8dbf23181a RPC: conform message-id type to msgpack-RPC spec
According to [MessagePack RPC specification](https://github.com/msgpack-rpc/msgpack-rpc),
message ID must be 32-bit unsigned integer. But Neovim implementation
uses uint64_t instead of uint32_t. This can have wrong results in the
case of large ids or a malformed request, for example:

    Actual response:   [1,18446744073709551615,[1,"Message is not an array"],null]
    Expected response: [1,4294967295,[1,"Message is not an array"],null]

The issue does not affect RPC clients written in dynamically-typed
languages like Python. Wrong type of sequence id number breaks RPC
clients written statically typed languages like C/C++/Golang: all of
them expect uint32_t as message id.
Examples:
  11268ba2be/src/msgpack/rpc/protocol.h (L27)
  https://github.com/ugorji/go/blob/master/codec/msgpack.go#L993

closes #8850
2019-04-12 02:31:46 +02:00
Justin M. Keyes
fd00806f01 RPC: eliminate NO_RESPONSE
Using a sentinel value in the response-id is ambiguous because the
msgpack-rpc spec allows all values (including zero/max). And clients
control the id, so we can't be sure they won't use the sentinel value.

Instead of a sentinel value, check the message type explicitly.

ref #8850
2019-04-12 02:30:31 +02:00
Justin M. Keyes
a70fde1b45 build: enable -Wshadow
Note about shada.c:
- shada_read_next_item_start was intentionally shadowing `unpacked` and
  `i` because many of the macros (e.g. ADDITIONAL_KEY) implicitly
  depended on those variable names.
- Macros were changed to parameterize `unpacked` (but not `i`). Macros
  like CLEAR_GA_AND_ERROR_OUT do control-flow (goto), so any other
  approach is messy.
2019-01-02 21:06:37 +01:00
Björn Linse
8b42249cdd RPC: turn errors from async calls into notifications
Previously, nvim sent a response with invalid request id (UINT64_MAX).
In functionaltests, catch unexpected error notifications in after_each().
2018-12-03 10:42:00 +01:00
Björn Linse
4da5cb38d3 startup: always wait for UI with --embed, unless --headless also is supplied 2018-09-22 10:18:28 +02:00
Justin M. Keyes
7c00b9efca log: RPC, input, other events 2018-09-19 01:11:09 +02:00
Björn Linse
bd8d43c6fe startup: wait for embedder before executing startup commands and files
Give embeders a chance to set up nvim, by processing a request before
startup. This allows an external UI to show messages and prompts from
--cmd and buffer loading (e.g. swap files)
2018-09-18 19:22:16 +02:00
Daniel Hahler
643ef257b3 API: nvim_unsubscribe(): Handle unknown events #8745
close #8745
2018-08-28 10:20:19 +02:00
micha
ed02278e42 channel.c: refactor spaghetti code
channel.c: WIP remove redundant method check and added FUNC_ATTR_NONNULL_ALL macro

channel.c channel_defs.h helpers.c: added Error field to RequestEvent, added no_op handler func

channel.c: use const char* instead of string and cleanup

channel.c; channel_defs.h; helpers.c: removed error from event again; send errors directly to the channel without using handlers and events

channel.c: fixed memory leak and lint errors

api/private/dispatch.c; api/vim.c; msgpack_rpc/channel.c msgpack_rpc/helpers.c added Error* field to msgpack_get_handler_for; further refactored channel.c

channel.c:323 changed order of evaluation in if statement

channel.c: removed superflous whitespace

dispatch.c: review comment
2018-07-14 11:47:18 +02:00
Justin M. Keyes
3abf17ae88 API: validation: mention invalid method name (#8489) 2018-06-07 10:56:44 +02:00
Björn Linse
6da4548f0e api: list information about all channels/jobs.
Fire autocmd when channel opens or its info changes.
Add a way for API clients can describe themselves.
2018-05-23 18:18:16 +02:00
Björn Linse
90e5cc5484 channels: generalize jobclose() 2017-11-25 09:37:00 +01:00
Björn Linse
1ebc96fe10 channels: allow bytes sockets and stdio, and buffered bytes output 2017-11-24 14:54:15 +01:00
Björn Linse
5215e3205a channels: refactor 2017-11-24 14:50:00 +01:00
Björn Linse
3717e2157f Revert channel logging, rebased on new code below 2017-11-24 14:04:56 +01:00
Björn Linse
2a3bcd1ff8 rpc: Don't delay notifications when request is pending (#6544)
With the old behavior, if a GUI makes a blocking request that requires user
interaction (like nvim_input()), it would not get any screen updates.

The client, not nvim, should decide how to handle notifications during a
pending request. If an rplugin wants to avoid async calls while a sync call is
busy, it likely wants to avoid processing async calls while another async call
also is handled as well.

This may break the expectation of some existing rplugins. For compatibility,
remote/define.vim reimplements the old behavior. Clients can opt-out by
specifying `sync=urgent`.

- Legacy hosts should be updated to use `sync=urgent`. They could add a flag
  indicating which async methods are always safe to call and which must wait
  until the main loop returns.
- New hosts can expose the full asyncness, they don't need to offer both
  behaviors.

ref #6532
ref #1398 d83868fe90
2017-10-29 03:06:53 +01:00
Justin M. Keyes
cdd9e868ef doc: channel, eventloop 2017-09-05 15:01:07 +02:00
Justin M. Keyes
0f442c328e channel.c:call_set_error(): fix memory leak 2017-08-21 01:04:28 +02:00
Justin M. Keyes
af993da435 rpc: close channel if stream was closed
f_jobstop()/f_rpcstop() .. process_stop() .. process_close_in(proc)
closes the write-stream of a RPC channel. But there might be
a pending RPC notification on the queue, which may get processed just
before the channel is closed.

To handle that case, check the Stream.closed in
channel.c:receive_msgpack().

Before this change, the above scenario could trigger
this assert(!stream->closed) in wstream_write():

    0x00007f96e1cd3428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
    0x00007f96e1cd502a in __GI_abort () at abort.c:89
    0x00007f96e1ccbbd7 in __assert_fail_base (fmt=<optimized out>, assertion=assertion@entry=0x768f9b "!stream->closed",
    file=file@entry=0x768f70 "../src/nvim/event/wstream.c", line=line@entry=77,
    function=function@entry=0x768fb0 <__PRETTY_FUNCTION__.13735> "wstream_write") at assert.c:92
    0x00007f96e1ccbc82 in __GI___assert_fail (assertion=0x768f9b "!stream->closed", file=0x768f70 "../src/nvim/event/wstream.c", line=77,
    function=0x768fb0 <__PRETTY_FUNCTION__.13735> "wstream_write") at assert.c:101
    0x00000000004d2c1f in wstream_write (stream=0x7f96e0a35078, buffer=0x7f96e09f9b40) at ../src/nvim/event/wstream.c:77
    0x00000000005857b2 in channel_write (channel=0x7f96e0ae5800, buffer=0x7f96e09f9b40) at ../src/nvim/msgpack_rpc/channel.c:551
    0x000000000058567d in on_request_event (argv=0x7ffed792efa0) at ../src/nvim/msgpack_rpc/channel.c:523
    0x00000000005854c8 in handle_request (channel=0x7f96e0ae5800, request=0x7ffed792f1b8) at ../src/nvim/msgpack_rpc/channel.c:503
    0x00000000005850cb in parse_msgpack (channel=0x7f96e0ae5800) at ../src/nvim/msgpack_rpc/channel.c:423
    0x0000000000584f90 in receive_msgpack (stream=0x7f96e0a35218, rbuf=0x7f96e0d1d4c0, c=22, data=0x7f96e0ae5800, eof=false)
    at ../src/nvim/msgpack_rpc/channel.c:389
    0x00000000004d0b20 in read_event (argv=0x7ffed792f4a8) at ../src/nvim/event/rstream.c:190
    0x00000000004ce462 in multiqueue_process_events (this=0x7f96e18172d0) at ../src/nvim/event/multiqueue.c:150
    0x000000000059b630 in nv_event (cap=0x7ffed792f620) at ../src/nvim/normal.c:7908
    0x000000000058be69 in normal_execute (state=0x7ffed792f580, key=-25341) at ../src/nvim/normal.c:1137
    0x0000000000652463 in state_enter (s=0x7ffed792f580) at ../src/nvim/state.c:61
    0x000000000058a1fe in normal_enter (cmdwin=false, noexmode=false) at ../src/nvim/normal.c:467
    0x00000000005500c2 in main (argc=2, argv=0x7ffed792f8d8) at ../src/nvim/main.c:554

Alternative approach suggested by bfredl is to use close_cb of the
process. My unsuccessful attempt is below. (It seems close_cb is queued
too late, which is the similar problem addressed by this commit):

    commit 75fc12c6ab15711bdb7b18c6d42ec9d157f5145e
    Author: Justin M. Keyes <justinkz@gmail.com>
    Date:   Fri Aug 18 01:30:41 2017 +0200

        rpc: use Stream's close_cb instead of explicit check in receive_msgpack()

    diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
    index 8371d3cd482e..e52da23cdc40 100644
    --- a/src/nvim/event/process.c
    +++ b/src/nvim/event/process.c
    @@ -416,6 +416,10 @@ static void on_process_exit(Process *proc)
     static void on_process_stream_close(Stream *stream, void *data)
     {
       Process *proc = data;
    +  ILOG("on_process_stream_close");
    +  if (proc->stream_close_cb != NULL) {
    +    proc->stream_close_cb(stream, proc->stream_close_data);
    +  }
       decref(proc);
     }

    diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
    index 5c00e8e7ecd5..34a8d54f6f8c 100644
    --- a/src/nvim/event/process.h
    +++ b/src/nvim/event/process.h
    @@ -26,6 +26,11 @@ struct process {
       Stream *in, *out, *err;
       process_exit_cb cb;
       internal_process_cb internal_exit_cb, internal_close_cb;
    +
    +  // Called when any of the process streams (in/out/err) closes.
    +  stream_close_cb stream_close_cb;
    +  void *stream_close_data;
    +
       bool closed, detach;
       MultiQueue *events;
     };
    @@ -50,6 +55,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
         .closed = false,
         .internal_close_cb = NULL,
         .internal_exit_cb = NULL,
    +    .stream_close_cb = NULL,
    +    .stream_close_data = NULL,
         .detach = false
       };
     }
    diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
    index 7c865bfe1e8c..c8720d1e45d9 100644
    --- a/src/nvim/event/stream.c
    +++ b/src/nvim/event/stream.c
    @@ -95,7 +95,11 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data)
     void stream_close_handle(Stream *stream)
       FUNC_ATTR_NONNULL_ALL
     {
    +  ILOG("stream=%d", stream);
    +  // LOG_CALLSTACK();
       if (stream->uvstream) {
    +    // problem:  this schedules on the queue, but channel.c:receive_msgpack may
    +    // be processed before close_cb is called by libuv.
         uv_close((uv_handle_t *)stream->uvstream, close_cb);
       } else {
         uv_close((uv_handle_t *)&stream->uv.idle, close_cb);
    @@ -105,6 +109,7 @@ void stream_close_handle(Stream *stream)
     static void close_cb(uv_handle_t *handle)
     {
       Stream *stream = handle->data;
    +  ILOG(">>>>>>>>>>>>>>>>>>>>>>> stream=%p stream->internal_close_cb=%p", stream, stream->internal_close_cb);
       if (stream->buffer) {
         rbuffer_free(stream->buffer);
       }
    diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
    index 782eabe04e4a..dc2b794e366a 100644
    --- a/src/nvim/msgpack_rpc/channel.c
    +++ b/src/nvim/msgpack_rpc/channel.c
    @@ -128,6 +128,8 @@ uint64_t channel_from_process(Process *proc, uint64_t id, char *source)
                                           source);
       incref(channel);  // process channels are only closed by the exit_cb
       channel->data.proc = proc;
    +  channel->data.proc->stream_close_cb = close_cb2;
    +  channel->data.proc->stream_close_data = channel;

       wstream_init(proc->in, 0);
       rstream_init(proc->out, 0);
    @@ -387,17 +389,6 @@ static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c,
         goto end;
       }

    -  if ((chan_wstream(channel) != NULL && chan_wstream(channel)->closed)
    -      || (chan_rstream(channel) != NULL && chan_rstream(channel)->closed)) {
    -    char buf[256];
    -    snprintf(buf, sizeof(buf),
    -             "ch %" PRIu64 ": stream closed unexpectedly. "
    -             "closing channel",
    -             channel->id);
    -    call_set_error(channel, buf, WARN_LOG_LEVEL);
    -    goto end;
    -  }
    -
       size_t count = rbuffer_size(rbuf);
       DLOG("ch %" PRIu64 ": parsing %u bytes from msgpack Stream: %p",
            channel->id, count, stream);
    @@ -571,23 +562,6 @@ static Stream *chan_wstream(Channel *chan)
       abort();
     }

    -/// Returns the Stream that a Channel reads from.
    -static Stream *chan_rstream(Channel *chan)
    -{
    -  switch (chan->type) {
    -    case kChannelTypeSocket:
    -      return &chan->data.stream;
    -    case kChannelTypeProc:
    -      return chan->data.proc->out;
    -    case kChannelTypeStdio:
    -      return &chan->data.std.in;
    -    case kChannelTypeInternal:
    -      return NULL;
    -  }
    -  abort();
    -}
    -
    -
     static bool channel_write(Channel *channel, WBuffer *buffer)
     {
       bool success = false;
    @@ -799,6 +773,12 @@ static void close_cb(Stream *stream, void *data)
       decref(data);
     }

    +static void close_cb2(Stream *stream, void *data)
    +{
    +  ILOG("close_cb2");
    +  close_channel(data);
    +}
    +
     /// @param source description of source function, rplugin name, TCP addr, etc
     static Channel *register_channel(ChannelType type, uint64_t id,
                                      MultiQueue *events, char *source)
2017-08-21 01:04:28 +02:00
Justin M. Keyes
e006b1d98d log: some DEBUG-level stream logging 2017-08-21 01:04:28 +02:00
Justin M. Keyes
bc6a3fe784 log: caller provides the source details 2017-07-23 15:01:31 +02:00
Justin M. Keyes
502af39f62 log: channel registration 2017-07-22 21:26:03 +02:00
Justin M. Keyes
fe1af9c2bc log: Always enable; remove DISABLE_LOG
- Establish ERROR log level as "critical". Such errors are rare and will
  be valuable when users encounter unusual circumstances.
- Set -DMIN_LOG_LEVEL=3 for release-type builds
2017-06-07 00:26:21 +02:00
Justin M. Keyes
fcc9d99967 channel_write: fix compiler warning 2017-05-31 14:10:04 +02:00
Björn Linse
5a151555c8 sockets: don't deadlock when connecting to own pipe address 2017-05-29 19:02:49 +02:00
Björn Linse
6a75938758 channels: implement sockopen() to connect to socket
Helped-By: oni-link <knil.ino@gmail.com>
2017-05-29 19:02:49 +02:00
Justin M. Keyes
1483800cdf coverity/161682: FP: Dereference after null check (#6630) 2017-05-01 17:04:56 +02:00
Justin M. Keyes
f17a818519 api/nvim_get_mode: Use child-queue instead of "priority". 2017-04-28 19:20:09 +02:00
Justin M. Keyes
acfd2a2a29 input.c: Process only safe events before blocking.
Introduce multiqueue_process_priority() to process only events at or
above a certain priority.
2017-04-28 19:19:51 +02:00
Justin M. Keyes
3ea1007753 api: nvim_get_mode()
Asynchronous API functions are served immediately, which means pending
input could change the state of Nvim shortly after an async API function
result is returned.

nvim_get_mode() is different:
  - If RPCs are known to be blocked, it responds immediately (without
    flushing the input/event queue)
  - else it is handled just-in-time before waiting for input, after
    pending input was processed. This makes the result more reliable
    (but not perfect).

Internally this is handled as a special case, but _semantically_ nothing
has changed: API users never know when input flushes, so this internal
special-case doesn't violate that. As far as API users are concerned,
nvim_get_mode() is just another asynchronous API function.

In all cases nvim_get_mode() never blocks for more than the time it
takes to flush the input/event queue (~µs).

Note: This doesn't address #6166; nvim_get_mode() will provoke #6166 if
e.g. `d` is operator-pending.

Closes #6159
2017-04-28 19:14:34 +02:00
Justin M. Keyes
086c354a0a api: Do not translate error messages.
Also re-word some error messages:
- "Key does not exist: %s"
- "Invalid channel: %<PRIu64>"
- "Request array size must be 4 (request) or 3 (notification)"
- "String cannot contain newlines"

References #6150
2017-04-24 00:11:27 +02:00
Justin M. Keyes
3fbc660d57 api_set_error(): rename 2017-04-23 23:44:57 +02:00
Justin M. Keyes
2ed91f222f api/internal: Remove set field from Error type. 2017-04-23 23:44:32 +02:00
Justin M. Keyes
2a49163103 api_clear_error() 2017-04-23 23:44:32 +02:00
Sander Bosma
5c9860a0a2 api: Do not truncate errors <1 MB. #6237
Closes #5984
2017-04-23 23:44:29 +02:00
ZyX
c2f3e361c5 *: Add comment to all C files 2017-04-19 19:11:50 +03:00
ZyX
28dafe3ff0 eval,*: Move get_tv_string to typval.c
Function was renamed and changed to return `const char *`.
2017-03-29 10:08:05 +03:00
Justin M. Keyes
857113ca8c terminal: Disable some options in terminal-mode.
In terminal-mode these options are nonsense because cursor is placed at
end of buffer to "follow" output.

Closes #2259
2017-03-01 14:47:49 +01:00
Justin M. Keyes
f7908b6f49 channel.c: logging 2017-02-26 13:00:02 +01:00
Björn Linse
f6968dc0f7 api: call multiple methods atomically (useful in async contexts)
remove unused response_id parameter of handle_nvim_... helpers
2016-10-22 10:51:32 +02:00
Justin M. Keyes
6186df3562 event/multiqueue.c: Rename "queue" to "multiqueue".
`lib/queue.h` implements a basic queue. `event/queue.c` implements
a specialized data structure on top of lib/queue.h; it is not a "normal"
queue.

Rename the specialized multi-level queue implemented in event/queue.c to
"multiqueue", to avoid confusion when reading the code.

Before this change one can eventually notice that "macros (uppercase
symbols) are for the normal queue, lowercase operations are for the
multi-level queue", but that is unnecessary friction for new developers
(or existing developers just visiting this part of the codebase).
2016-10-02 00:24:49 +02:00
Björn Linse
acb7c826b3 api: fix leak when a api function is incorrectly called with a list.
This applies both to msgpack-rpc and eval.
2016-08-31 21:57:06 +02:00
Björn Linse
2d60a15e25 job control: reuse common job code for rpc jobs
This makes stderr and exit callbacks work for rpc jobs
2016-08-20 12:55:35 +02:00
Björn Linse
215922120c stream: set data together with callback 2016-08-20 10:25:33 +02:00
ZyX
458a4d0444 *: Fix linter errors
Also adds one exception to linter rules:

    typedef struct {
      kvec_t(Object) stack;
    } EncodedData;

is completely valid (from the style guide point of view) code.
2016-06-24 17:16:11 +03:00