diff options
Diffstat (limited to 'src/nvim/channel.c')
-rw-r--r-- | src/nvim/channel.c | 148 |
1 files changed, 109 insertions, 39 deletions
diff --git a/src/nvim/channel.c b/src/nvim/channel.c index b37fa10b12..64d743891b 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -1,11 +1,13 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "nvim/api/private/helpers.h" #include "nvim/api/ui.h" #include "nvim/channel.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/event/socket.h" +#include "nvim/fileio.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/os/shell.h" @@ -145,6 +147,9 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error) return false; } break; + + default: + abort(); } return true; @@ -180,47 +185,11 @@ static Channel *channel_alloc(ChannelStreamType type) return chan; } -/// Not implemented, only logging for now void channel_create_event(Channel *chan, const char *ext_source) { #if MIN_LOG_LEVEL <= INFO_LOG_LEVEL - const char *stream_desc; - const char *mode_desc; const char *source; - switch (chan->streamtype) { - case kChannelStreamProc: - if (chan->stream.proc.type == kProcessTypePty) { - stream_desc = "pty job"; - } else { - stream_desc = "job"; - } - break; - - case kChannelStreamStdio: - stream_desc = "stdio"; - break; - - case kChannelStreamSocket: - stream_desc = "socket"; - break; - - case kChannelStreamInternal: - stream_desc = "socket (internal)"; - break; - - default: - stream_desc = "?"; - } - - if (chan->is_rpc) { - mode_desc = ", rpc"; - } else if (chan->term) { - mode_desc = ", terminal"; - } else { - mode_desc = ""; - } - if (ext_source) { // TODO(bfredl): in a future improved traceback solution, // external events should be included. @@ -230,12 +199,21 @@ void channel_create_event(Channel *chan, const char *ext_source) source = (const char *)IObuff; } - ILOG("new channel %" PRIu64 " (%s%s): %s", chan->id, stream_desc, - mode_desc, source); + Dictionary info = channel_info(chan->id); + typval_T tv = TV_INITIAL_VALUE; + // TODO(bfredl): do the conversion in one step. Also would be nice + // to pretty print top level dict in defined order + (void)object_to_vim(DICTIONARY_OBJ(info), &tv, NULL); + char *str = encode_tv2json(&tv, NULL); + ILOG("new channel %" PRIu64 " (%s) : %s", chan->id, source, str); + xfree(str); + api_free_dictionary(info); + #else - (void)chan; (void)ext_source; #endif + + channel_info_changed(chan, true); } void channel_incref(Channel *chan) @@ -755,3 +733,95 @@ static void term_close(void *data) multiqueue_put(chan->events, term_delayed_free, 1, data); } +void channel_info_changed(Channel *chan, bool new) +{ + event_T event = new ? EVENT_CHANOPEN : EVENT_CHANINFO; + if (has_event(event)) { + channel_incref(chan); + multiqueue_put(main_loop.events, set_info_event, + 2, chan, event); + } +} + +static void set_info_event(void **argv) +{ + Channel *chan = argv[0]; + event_T event = (event_T)(ptrdiff_t)argv[1]; + + dict_T *dict = get_vim_var_dict(VV_EVENT); + Dictionary info = channel_info(chan->id); + typval_T retval; + (void)object_to_vim(DICTIONARY_OBJ(info), &retval, NULL); + tv_dict_add_dict(dict, S_LEN("info"), retval.vval.v_dict); + + apply_autocmds(event, NULL, NULL, false, curbuf); + + tv_dict_clear(dict); + api_free_dictionary(info); + channel_decref(chan); +} + +Dictionary channel_info(uint64_t id) +{ + Channel *chan = find_channel(id); + if (!chan) { + return (Dictionary)ARRAY_DICT_INIT; + } + + Dictionary info = ARRAY_DICT_INIT; + PUT(info, "id", INTEGER_OBJ((Integer)chan->id)); + + const char *stream_desc, *mode_desc; + switch (chan->streamtype) { + case kChannelStreamProc: + stream_desc = "job"; + if (chan->stream.proc.type == kProcessTypePty) { + const char *name = pty_process_tty_name(&chan->stream.pty); + PUT(info, "pty", STRING_OBJ(cstr_to_string(name))); + } + break; + + case kChannelStreamStdio: + stream_desc = "stdio"; + break; + + case kChannelStreamStderr: + stream_desc = "stderr"; + break; + + case kChannelStreamInternal: + PUT(info, "internal", BOOLEAN_OBJ(true)); + // FALLTHROUGH + + case kChannelStreamSocket: + stream_desc = "socket"; + break; + + default: + abort(); + } + PUT(info, "stream", STRING_OBJ(cstr_to_string(stream_desc))); + + if (chan->is_rpc) { + mode_desc = "rpc"; + PUT(info, "client", DICTIONARY_OBJ(rpc_client_info(chan))); + } else if (chan->term) { + mode_desc = "terminal"; + PUT(info, "buffer", BUFFER_OBJ(terminal_buf(chan->term))); + } else { + mode_desc = "bytes"; + } + PUT(info, "mode", STRING_OBJ(cstr_to_string(mode_desc))); + + return info; +} + +Array channel_all_info(void) +{ + Channel *channel; + Array ret = ARRAY_DICT_INIT; + map_foreach_value(channels, channel, { + ADD(ret, DICTIONARY_OBJ(channel_info(channel->id))); + }); + return ret; +} |