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

Code before:
}

void ui_client_event_grid_line(Array args)
  FUNC_ATTR_NORETURN
{
  abort();  // unreachable
}

void ui_client_event_raw_line(GridLineEvent *g)
{
  int grid = g->args[0];
  int row = g->args[1];
  int startcol = g->args[2];
  Integer endcol = startcol + g->coloff;
  Integer clearcol = endcol + g->clear_width;
  LineFlags lineflags = g->wrap ? kLineFlagWrap : 0;

  tui_raw_line(tui, grid, row, startcol, endcol, clearcol, g->cur_attr, lineflags,
               (const schar_T *)grid_line_buf_char, grid_line_buf_attr);
}

/// When a "connect" UI event is received, its arguments are saved here when
/// waiting for the server to exit.
static Array connect_args;
static bool connect_pending = false;
static bool connect_successful = false;

void ui_client_event_connect(Array args)
{
  api_free_array(connect_args);
  connect_args = copy_array(args, NULL);
  connect_pending = true;
}

/// Called when the current server has exited.
bool ui_client_may_connect(void)
{
  if (!connect_pending) {
    return false;
  }
  if (connect_successful) {
    return true;
  }
  connect_pending = false;
  if (connect_args.size < 1 || connect_args.items[0].type != kObjectTypeString) {
    ELOG("Error handling UI event 'connect'");
    api_free_array(connect_args);
    connect_args = (Array)ARRAY_DICT_INIT;
    return false;
  }


Review comment (bug):
Now we have both `restart_pending` and `connect_pending`. That's not good. There should be only 1 flag, and if it is set and we handle another event that would set it, that should be an error of some kind. For example, if a `restart` event is handled while handling a `connect` event, either we should log-and-ignore or we should raise an error somehow.

I also don't think we need separate `connect_args` and `restart_args`.

`connect_successful` also looks suspicious. 

Please think about how we can avoid state where possible, and reduce the number of edge cases and conflicting states.

Code after:
void ui_client_event_grid_line(Array args)
  FUNC_ATTR_NORETURN
{
  abort();  // unreachable
}

void ui_client_event_raw_line(GridLineEvent *g)
{
  int grid = g->args[0];
  int row = g->args[1];
  int startcol = g->args[2];
  Integer endcol = startcol + g->coloff;
  Integer clearcol = endcol + g->clear_width;
  LineFlags lineflags = g->wrap ? kLineFlagWrap : 0;

  tui_raw_line(tui, grid, row, startcol, endcol, clearcol, g->cur_attr, lineflags,
               (const schar_T *)grid_line_buf_char, grid_line_buf_attr);
}

void ui_client_event_connect(Array args)
{
  if (args.size < 1 || args.items[0].type != kObjectTypeString) {
    ELOG("Error handling UI event 'connect'");
    return;
  }

  char *server_addr = args.items[0].data.string.data;
  multiqueue_put(main_loop.fast_events, channel_connect_event, server_addr);
}

static void channel_connect_event(void **argv)
{
  char *server_addr = argv[0];

  const char *err = "";
  bool is_tcp = !!strrchr(server_addr, ':');
  CallbackReader on_data = CALLBACK_READER_INIT;
  uint64_t chan = channel_connect(is_tcp, server_addr, true, on_data, 50, &err);

  if (!strequal(err, "")) {
    ELOG("Error handling UI event 'connect': %s", err);
    return;
  }

  ui_client_channel_id = chan;
  ui_client_is_remote = true;
  ui_client_attach(tui_width, tui_height, tui_term, tui_rgb);

  ELOG("Connected to channel: %" PRId64, chan);
}