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

Code before:
  return cursor_col;
}

void ui_flush(void)
{
  assert(!ui_client_channel_id);
  if (!ui_active()) {
    return;
  }

  static bool was_busy = false;

  if (!(State & MODE_CMDLINE)) {
    if (curwin->w_floating && curwin->w_config.hide) {
      if (!was_busy) {
        ui_call_busy_start();
        was_busy = true;
      }
    } else {
      if (was_busy) {
        ui_call_busy_stop();
        was_busy = false;
      }

      int crow = curwin->w_winrow + curwin->w_wrow;
      int ccol = curwin->w_wincol + curwin->w_wcol;
      ScreenGrid *top_grid = ui_comp_get_grid_at_coord(crow, ccol);
      win_T *wp = (top_grid && top_grid != &curwin->w_grid_alloc && top_grid != &default_grid)
                  ? get_win_by_grid_handle(top_grid->handle) : NULL;

      int cur_z = curwin->w_floating ? curwin->w_config.zindex : 0;
      bool cursor_obscured = wp && wp->w_floating && !wp->w_config.hide
                             && wp->w_config.zindex > cur_z;
      int new_idx = cursor_obscured ? SHAPE_IDX_R : cursor_get_mode_idx();
      if (ui_mode_idx != new_idx) {
        ui_mode_idx = new_idx;
        pending_mode_update = true;
      }
    }
  } else if (was_busy) {
    ui_call_busy_stop();
    was_busy = false;
  }

  win_ui_flush(false);
  // Avoid flushing callbacks expected to change text during textlock.
  if (textlock == 0 && expr_map_lock == 0) {
    cmdline_ui_flush();
    msg_ext_ui_flush();
  }
  msg_scroll_flush();

Review comment (suggestion):
```suggestion
      int crow = curwin->w_winrow + curwin->w_winrow_off + curwin->w_wrow;
      int ccol = curwin->w_wincol + curwin->w_wincol_off
                 + (curwin->w_p_rl ? curwin->w_view_width - curwin->w_wcol - 1
                                   : curwin->w_wcol);
```

Maybe there's a better way, but this needs to at least consider `w_win{row,col}_off`, otherwise borders aren't accounted for. Plus `'rightleft'`. Add these tests:

```lua
vim.api.nvim_open_win(0, true, {relative = "editor", width = 5, height = 5, row = 8, col = 9, border = "single", zindex = 1})
vim.api.nvim_open_win(0, false, {relative = "editor", width = 10, height = 10, row = 0, col = 0, zindex = 2})
-- Cursor should be unobscured here.

vim.api.nvim_win_set_config(0, {relative = "editor", row = 9, col = 8})
-- Cursor should also be unobscured here.

vim.api.nvim_win_set_config(0, {relative = "editor", row = 8, col = 8})
vim.o.rightleft = true
-- Cursor should also be unobscured here.

vim.o.virtualedit = "all"
vim.fn.setpos(".", {0, 1, 1, 4})
-- Cursor should be *obscured* here.
```

Code after:
  return cursor_col;
}

void ui_flush(void)
{
  assert(!ui_client_channel_id);
  if (!ui_active()) {
    return;
  }

  static bool was_busy = false;

  if (!(State & MODE_CMDLINE) && curwin->w_floating && curwin->w_config.hide) {
    if (!was_busy) {
      ui_call_busy_start();
      was_busy = true;
    }
  } else if (was_busy) {
    ui_call_busy_stop();
    was_busy = false;
  }

  win_ui_flush(false);
  // Avoid flushing callbacks expected to change text during textlock.
  if (textlock == 0 && expr_map_lock == 0) {
    cmdline_ui_flush();
    msg_ext_ui_flush();
  }
  msg_scroll_flush();

  if (pending_cursor_update) {
    ui_call_grid_cursor_goto(cursor_grid_handle, cursor_row, cursor_col);
    pending_cursor_update = false;
    // The cursor move might change the composition order,
    // so flush again to update the windows that changed
    // TODO(bfredl): refactor the flow of information so that win_ui_flush()
    // only is called once. (as order state is exposed, it should be owned
    // by nvim core, not the compositor)
    win_ui_flush(false);
  }

  // Show "empty box" (underline style) cursor if behind a floatwin.
  if (!(State & MODE_CMDLINE)) {
    bool cursor_obscured = ui_cursor_is_behind_floatwin();
    int new_idx = cursor_obscured ? SHAPE_IDX_R : cursor_get_mode_idx();
    if (ui_mode_idx != new_idx) {
      ui_mode_idx = new_idx;
      pending_mode_update = true;
    }
  }