Repository: neovim/neovim
File: src/nvim/msgpack_rpc/channel.c (C)

Code before:
    return;
  }

  channel->rpc.closed = true;

  // Scheduled to avoid running UILeave autocommands in a libuv handler.
  multiqueue_put(main_loop.fast_events, rpc_close_event, channel);
}

static void rpc_close_event(void **argv)
{
  Channel *channel = (Channel *)argv[0];
  assert(channel);

  channel_decref(channel);

  bool is_ui_client = ui_client_channel_id && channel->id == ui_client_channel_id;
  if (is_ui_client || channel->streamtype == kChannelStreamStdio) {
    if (!is_ui_client) {
      // Avoid hanging when there are no other UIs and a prompt is triggered on exit.
      remote_ui_disconnect(channel->id);
    }
    if (is_ui_client && ui_client_pending_restart) {
      ui_client_do_restart();
      if (ui_client_channel_id != channel->id) {  // restart success
        return;
      }
    }
    if (!channel->detach) {
      exit_on_closed_chan(channel->exit_status == -1 ? 0 : channel->exit_status);
    }
  }
}

void rpc_free(Channel *channel)
{
  remote_ui_disconnect(channel->id);
  unpacker_teardown(channel->rpc.unpacker);
  xfree(channel->rpc.unpacker);

  kv_destroy(channel->rpc.call_stack);
  api_free_dict(channel->rpc.info);
}

/// Closes a channel after receiving fatal error, and logs a message.
static void chan_close_on_err(Channel *channel, char *msg, int loglevel)
{
  for (size_t i = 0; i < kv_size(channel->rpc.call_stack); i++) {
    ChannelCallFrame *frame = kv_A(channel->rpc.call_stack, i);
    frame->returned = true;
    frame->errored = true;

Review comment (bug):
should we ELOG a message on failure ? I don't remember if the UI client can log things though, but maybe it can emit something to the server (though that might not even exist), or maybe to stderr?

not a blocker

Code after:
    return;
  }

  channel->rpc.closed = true;

  // Scheduled to avoid running UILeave autocommands in a libuv handler.
  multiqueue_put(main_loop.fast_events, rpc_close_event, channel);
}

static void rpc_close_event(void **argv)
{
  Channel *channel = (Channel *)argv[0];
  assert(channel);

  channel_decref(channel);

  bool is_ui_client = ui_client_channel_id && channel->id == ui_client_channel_id;
  if (is_ui_client || channel->streamtype == kChannelStreamStdio) {
    if (!is_ui_client) {
      // Avoid hanging when there are no other UIs and a prompt is triggered on exit.
      remote_ui_disconnect(channel->id);
    } else {
      ui_client_may_restart_server();
      if (ui_client_channel_id != channel->id) {
        // A new server has been started. Don't exit.
        return;
      }
    }
    if (!channel->detach) {
      exit_on_closed_chan(channel->exit_status == -1 ? 0 : channel->exit_status);
    }
  }
}

void rpc_free(Channel *channel)
{
  remote_ui_disconnect(channel->id);
  unpacker_teardown(channel->rpc.unpacker);
  xfree(channel->rpc.unpacker);

  kv_destroy(channel->rpc.call_stack);
  api_free_dict(channel->rpc.info);
}

/// Closes a channel after receiving fatal error, and logs a message.
static void chan_close_on_err(Channel *channel, char *msg, int loglevel)
{
  for (size_t i = 0; i < kv_size(channel->rpc.call_stack); i++) {
    ChannelCallFrame *frame = kv_A(channel->rpc.call_stack, i);
    frame->returned = true;
    frame->errored = true;