From da4355ab8f68c4e0290134e691ab7b9dedc2a5df Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 3 Sep 2026 13:22:50 -0400 Subject: [PATCH] fix(multicursor): 'guicursor' uses Normal shape in Visual mode #41669 Problem: 'guicursor' is not respected when extra cursors exist. Per-cursor selection toggles Visual off, and the sandbox restores it only after restore_current_state(), whose ui_cursor_shape() caches the Normal shape. Solution: Restore Visual before restore_current_state(). --- src/nvim/mcursor.c | 6 +++--- test/functional/editor/mcursor_spec.lua | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/nvim/mcursor.c b/src/nvim/mcursor.c index 2c58f14045..6a8260f473 100644 --- a/src/nvim/mcursor.c +++ b/src/nvim/mcursor.c @@ -307,10 +307,10 @@ static void mc_sandbox_leave(McSandbox *sb) ctx_free(&sb->regs); restore_redobuff(&sb->redo); restore_search_patterns(); - restore_current_state(&sb->sst); - // Visual before the cursor restore: check_cursor() below must see the restored mode (a - // blockwise 'virtualedit' selection would otherwise lose the cursor's coladd). + // Visual first: restore_current_state() updates the cursor shape, and check_cursor() below keeps + // a blockwise 'virtualedit' selection's coladd. Visual = sb->visual; + restore_current_state(&sb->sst); buf_T *buf = handle_get_buffer(sb->bufnr); bool topline_valid = false; if (buf != NULL) { diff --git a/test/functional/editor/mcursor_spec.lua b/test/functional/editor/mcursor_spec.lua index 7e5b4a1fc8..a6fbe4d700 100644 --- a/test/functional/editor/mcursor_spec.lua +++ b/test/functional/editor/mcursor_spec.lua @@ -1512,7 +1512,7 @@ describe('multicursor', function() eq('n', api.nvim_get_mode().mode) end) - it('shows per-cursor visual selection', function() + it('shows per-cursor selection', function() local screen = Screen.new(30, 6) cursors({ 'longword x', 'ab y', 'medium z' }) -- Each cursor shows its own selection ("iw" = that cursor's word), previewed live. @@ -1524,6 +1524,7 @@ describe('multicursor', function() {1:~ }|*2 {5:-- VISUAL --} | ]]) + eq('visual', screen.mode) -- The UI mode ('guicursor'). #41631 feed('e') screen:expect([[ {17:longword x} | @@ -1540,6 +1541,7 @@ describe('multicursor', function() {1:~ }|*2 | ]]) + eq('normal', screen.mode) end) it('shows linewise/blockwise selections', function()