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

Code before:
    wp->w_width_request = MAX(width, 0);
    win_set_inner_size(wp, true);
  }
}

static void ui_attach_error(uint32_t ns_id, const char *name, const char *msg)
{
  const char *ns = describe_ns((NS)ns_id, "(UNKNOWN PLUGIN)");
  ELOG("Error in \"%s\" UI event handler (ns=%s):\n%s", name, ns, msg);
  msg_schedule_semsg_multiline("Error in \"%s\" UI event handler (ns=%s):\n%s", name, ns, msg);
}

void ui_call_event(char *name, Array args)
{
  // Internal messages are considered unsafe and are executed in fast context.
  bool fast = strcmp(name, "msg_show") == 0;
  const char *not_fast[] = {
    "empty",
    "echo",
    "echomsg",
    "echoerr",
    "list_cmd",
    "lua_error",
    "lua_print",
    "progress",
    "verbose",
    NULL,
  };

  for (int i = 0; fast && not_fast[i]; i++) {
    fast = !strequal(not_fast[i], args.items[0].data.string.data);
  }

  // Don't impose textlock restrictions upon UI event handlers.
  int save_expr_map_lock = expr_map_lock;
  int save_textlock = textlock;
  expr_map_lock = 0;
  textlock = 0;

  bool handled = false;
  UIEventCallback *event_cb;
  map_foreach(&ui_event_cbs, ui_event_ns_id, event_cb, {
    Error err = ERROR_INIT;
    uint32_t ns_id = ui_event_ns_id;
    Object res = nlua_call_ref_ctx(fast, event_cb->cb, name, args, kRetNilBool, NULL, &err);
    ui_event_ns_id = 0;
    if (LUARET_TRUTHY(res)) {
      handled = true;
    }
    if (ERROR_SET(&err)) {
      ui_attach_error(ns_id, name, err.msg);

Review comment (refactor):
Making `verbose` messages non-fast is unfortunate but with commands like `:verbose au` it currently results in just the non-verbose part being printed, because the verbose events handlers need to be scheduled.

Either we make all `verbose` messages non-fast but there's some that seem more risky as opposed to "last_set" messages, risking regressing #27874.

Otherwise we need to drop the verbose kind for these commands interspersed with "last_set" messages, and just make it a single message. That would lose the verbose information. Although I can't imagine what a UI would want to do with it, so maybe that would be better. Would just make `:au verbose` a single message event, and should simplify the newline logic I added in this PR somewhat.

Code after:
    wp->w_width_request = MAX(width, 0);
    win_set_inner_size(wp, true);
  }
}

static void ui_attach_error(uint32_t ns_id, const char *name, const char *msg)
{
  const char *ns = describe_ns((NS)ns_id, "(UNKNOWN PLUGIN)");
  ELOG("Error in \"%s\" UI event handler (ns=%s):\n%s", name, ns, msg);
  msg_schedule_semsg_multiline("Error in \"%s\" UI event handler (ns=%s):\n%s", name, ns, msg);
}

void ui_call_event(char *name, Array args)
{
  // Internal messages are considered unsafe and are executed in fast context.
  bool fast = strcmp(name, "msg_show") == 0;
  const char *not_fast[] = {
    "empty",
    "echo",
    "echomsg",
    "echoerr",
    "list_cmd",
    "lua_error",
    "lua_print",
    "progress",
    NULL,
  };

  for (int i = 0; fast && not_fast[i]; i++) {
    fast = !strequal(not_fast[i], args.items[0].data.string.data);
  }

  // Don't impose textlock restrictions upon UI event handlers.
  int save_expr_map_lock = expr_map_lock;
  int save_textlock = textlock;
  expr_map_lock = 0;
  textlock = 0;

  bool handled = false;
  UIEventCallback *event_cb;
  map_foreach(&ui_event_cbs, ui_event_ns_id, event_cb, {
    Error err = ERROR_INIT;
    uint32_t ns_id = ui_event_ns_id;
    Object res = nlua_call_ref_ctx(fast, event_cb->cb, name, args, kRetNilBool, NULL, &err);
    ui_event_ns_id = 0;
    if (LUARET_TRUTHY(res)) {
      handled = true;
    }
    if (ERROR_SET(&err)) {
      ui_attach_error(ns_id, name, err.msg);
      ui_remove_cb(ns_id, true);