From 450702a37012a325779d6216029f56ba16d76680 Mon Sep 17 00:00:00 2001 From: Yi Li Date: Thu, 22 Oct 2026 23:12:18 +0800 Subject: [PATCH] fix: a q that is another key's argument does not end macro recording While recording, every `q` ended the recording, even when a pending key was waiting for it as its argument: `fq`, `tq`, `"qp`, `@q`, a text object's `iq`. Vim ends the recording only on a `q` that is a command of its own. The check now looks at the key buffer: an empty buffer, or a count only, means the `q` is a command. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01W2aBHqJtz3wmW7kAdNmsYS --- packages/codemirror-vim-core/test/vim_test.js | 7 +++++++ packages/codemirror-vim-core/vim.js | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/codemirror-vim-core/test/vim_test.js b/packages/codemirror-vim-core/test/vim_test.js index 789fc06..c208549 100644 --- a/packages/codemirror-vim-core/test/vim_test.js +++ b/packages/codemirror-vim-core/test/vim_test.js @@ -2655,6 +2655,13 @@ testVim('visual_blank', function(cm, vim, helpers) { helpers.doKeys('v', 'k'); eq(vim.visualMode, true); }, { value: '\n' }); +testVim('macro_q_as_argument_does_not_end_recording', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', 'f', 'q', 'x', 'q'); + eq('abqc', cm.getValue()); + helpers.doKeys('@', 'a'); + eq('abc', cm.getValue()); +}, { value: 'aqbqc' }); testVim('reselect_visual', function(cm, vim, helpers) { helpers.doKeys('l', 'v', 'l', 'l', 'l', 'y', 'g', 'v'); helpers.assertCursorAt(0, 5); diff --git a/packages/codemirror-vim-core/vim.js b/packages/codemirror-vim-core/vim.js index 3cafa6b..1be83e8 100644 --- a/packages/codemirror-vim-core/vim.js +++ b/packages/codemirror-vim-core/vim.js @@ -920,7 +920,10 @@ export function initVim(CM) { function handleMacroRecording() { var macroModeState = vimGlobalState.macroModeState; if (macroModeState.isRecording) { - if (key == 'q') { + // A `q` ends the recording only as a command of its own, not as the + // character a pending key is waiting for (`fq`, `"qp`, `@q`, `iq`). + // A count before it changes nothing. + if (key == 'q' && !/\D/.test(vim.inputState.keyBuffer.join(''))) { macroModeState.exitMacroRecordMode(); clearInputState(cm); return true;