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

Code before:
  }

  msg_ext_emit_chunk();
  if (msg_ext_chunks->size > 0) {
    Array *tofree = msg_ext_init_chunks();

    ui_call_msg_show(cstr_as_string(msg_ext_kind), *tofree, msg_ext_overwrite, msg_ext_history,
                     msg_ext_append, msg_ext_id);
    // clear info after emitting message.
    if (msg_ext_history) {
      api_free_array(*tofree);
    } else {
      // Add to history as temporary message for "g<".
      HlMessage msg = KV_INITIAL_VALUE;
      for (size_t i = 0; i < kv_size(*tofree); i++) {
        Object *chunk = kv_A(*tofree, i).data.array.items;
        kv_push(msg, ((HlMessageChunk){ chunk[1].data.string, (int)chunk[2].data.integer }));
        xfree(chunk);
      }
      xfree(tofree->items);
      msg_hist_add_multihl(INTEGER_OBJ(0), msg, true, NULL);
    }
    xfree(tofree);
    msg_ext_overwrite = false;
    msg_ext_history = false;
    msg_ext_append = false;
    msg_ext_kind = NULL;
    msg_ext_id = INTEGER_OBJ(0);
  }
}

void msg_ext_flush_showmode(void)
{
  // Showmode messages doesn't interrupt normal message flow, so we use
  // separate event. Still reuse the same chunking logic, for simplicity.
  // This is called unconditionally; check if we are emitting, or have
  // emitted non-empty "content".
  static bool clear = false;
  if (ui_has(kUIMessages) && (msg_ext_last_attr != -1 || clear)) {
    clear = msg_ext_last_attr != -1;
    msg_ext_emit_chunk();
    Array *tofree = msg_ext_init_chunks();
    ui_call_msg_showmode(*tofree);
    api_free_array(*tofree);
    xfree(tofree);
  }
}

/// If the written message runs into the shown command or ruler, we have to
/// wait for hit-return and redraw the window later.
void msg_check(void)

Review comment (suggestion):
This function basically gets skipped if there's no ext-ui connected with ext-message capability (line: 3295). As a result the message-id doesn't get incremented unless user has ui2 enabled. I guess the tests didn't catch it cause the test screen itself connects as an ext-ui.

Code after:
  msg_ext_emit_chunk();
  if (msg_ext_chunks->size > 0) {
    Array *tofree = msg_ext_init_chunks();

    ui_call_msg_show(cstr_as_string(msg_ext_kind), *tofree, msg_ext_overwrite, msg_ext_history,
                     msg_ext_append, msg_ext_id);
    // clear info after emitting message.
    if (msg_ext_history) {
      api_free_array(*tofree);
    } else {
      // Add to history as temporary message for "g<".
      HlMessage msg = KV_INITIAL_VALUE;
      for (size_t i = 0; i < kv_size(*tofree); i++) {
        Object *chunk = kv_A(*tofree, i).data.array.items;
        kv_push(msg, ((HlMessageChunk){ chunk[1].data.string, (int)chunk[2].data.integer }));
        xfree(chunk);
      }
      xfree(tofree->items);
      msg_hist_add_multihl(msg, true, NULL);
    }
    xfree(tofree);
    msg_ext_overwrite = false;
    msg_ext_history = false;
    msg_ext_append = false;
    msg_ext_kind = NULL;
    msg_id_next += (msg_ext_id.data.integer == msg_id_next);
    msg_ext_id = INTEGER_OBJ(msg_id_next);
  }
}

void msg_ext_flush_showmode(void)
{
  // Showmode messages doesn't interrupt normal message flow, so we use
  // separate event. Still reuse the same chunking logic, for simplicity.
  // This is called unconditionally; check if we are emitting, or have
  // emitted non-empty "content".
  static bool clear = false;
  if (ui_has(kUIMessages) && (msg_ext_last_attr != -1 || clear)) {
    clear = msg_ext_last_attr != -1;
    msg_ext_emit_chunk();
    Array *tofree = msg_ext_init_chunks();
    ui_call_msg_showmode(*tofree);
    api_free_array(*tofree);
    xfree(tofree);
  }
}

/// If the written message runs into the shown command or ruler, we have to
/// wait for hit-return and redraw the window later.
void msg_check(void)
{