-
Notifications
You must be signed in to change notification settings - Fork 807
Fix VIM-945: Implement i_CTRL-R_CTRL-O to insert register literally #1417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| /* | ||
| * Copyright 2003-2025 The IdeaVim authors | ||
| * | ||
| * Use of this source code is governed by an MIT-style | ||
| * license that can be found in the LICENSE.txt file or at | ||
| * https://opensource.org/licenses/MIT. | ||
| */ | ||
|
|
||
| package org.jetbrains.plugins.ideavim.action.change.insert | ||
|
|
||
| import com.maddyhome.idea.vim.state.mode.Mode | ||
| import org.jetbrains.plugins.ideavim.VimTestCase | ||
| import org.junit.jupiter.api.Test | ||
|
|
||
| class InsertRegisterLiterallyActionTest : VimTestCase() { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing test coverage: Consider adding tests that verify the auto-indent behavior difference between For example:
The command-line mode tests in |
||
| @Test | ||
| fun `test insert named register literally with CTRL-R CTRL-R`() { | ||
| configureByText("\n") | ||
| enterCommand("let @a=\"hello world\"") | ||
| typeText("i<C-R><C-R>a") | ||
| assertState("hello world${c}\n") | ||
| } | ||
|
|
||
| @Test | ||
| fun `test insert named register literally with CTRL-R CTRL-O`() { | ||
| configureByText("\n") | ||
| enterCommand("let @a=\"hello world\"") | ||
| typeText("i<C-R><C-O>a") | ||
| assertState("hello world${c}\n") | ||
| } | ||
|
|
||
| @Test | ||
| fun `test insert named register literally with CTRL-R CTRL-R after existing text`() { | ||
| configureByText("${c}\n") | ||
| enterCommand("let @a=\"world\"") | ||
| typeText("ihello <C-R><C-R>a") | ||
| assertState("hello world${c}\n") | ||
| } | ||
|
|
||
| @Test | ||
| fun `test insert named register literally with CTRL-R CTRL-O after existing text`() { | ||
| configureByText("${c}\n") | ||
| enterCommand("let @a=\"world\"") | ||
| typeText("ihello <C-R><C-O>a") | ||
| assertState("hello world${c}\n") | ||
| } | ||
|
|
||
| @Test | ||
| fun `test insert default register literally with CTRL-R CTRL-R`() { | ||
| configureByText("${c}hello\n") | ||
| typeText("ywo<C-R><C-R>\"") | ||
| assertState("hello\nhello${c}\n") | ||
| } | ||
|
|
||
| @Test | ||
| fun `test insert default register literally with CTRL-R CTRL-O`() { | ||
| configureByText("${c}hello\n") | ||
| typeText("ywo<C-R><C-O>\"") | ||
| assertState("hello\nhello${c}\n") | ||
| } | ||
|
|
||
| @Test | ||
| fun `test insert numbered register literally with CTRL-R CTRL-R`() { | ||
| configureByText("${c}line1\nline2\n") | ||
| typeText("yyjo<C-R><C-R>0") | ||
| assertState("line1\nline2\nline1\n${c}\n") | ||
| } | ||
|
|
||
| @Test | ||
| fun `test insert numbered register literally with CTRL-R CTRL-O`() { | ||
| configureByText("${c}line1\nline2\n") | ||
| typeText("yyjo<C-R><C-O>0") | ||
| assertState("line1\nline2\nline1\n${c}\n") | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -60,6 +60,42 @@ class InsertRegisterAction : VimActionHandler.SingleExecution() { | |
| } | ||
| } | ||
|
|
||
| @CommandOrMotion(keys = ["<C-R><C-R>", "<C-R><C-O>"], modes = [Mode.INSERT]) | ||
| class InsertRegisterLiterallyAction : VimActionHandler.SingleExecution() { | ||
| override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED | ||
|
|
||
| override val argumentType: Argument.Type = Argument.Type.CHARACTER | ||
|
|
||
| override fun execute( | ||
| editor: VimEditor, | ||
| context: ExecutionContext, | ||
| cmd: Command, | ||
| operatorArguments: OperatorArguments, | ||
| ): Boolean { | ||
| val argument = cmd.argument as? Argument.Character ?: return false | ||
| if (argument.character == '=') { | ||
| injector.commandLine.readInputAndProcess(editor, context, "=", finishOn = null) { input -> | ||
| try { | ||
| if (input.isNotEmpty()) { | ||
| val expression = | ||
| injector.vimscriptParser.parseExpression(input)?.evaluate(editor, context, Script(listOf())) | ||
| ?: throw exExceptionMessage("E15", input) | ||
| val textToStore = expression.toInsertableString() | ||
| injector.registerGroup.storeTextSpecial('=', textToStore) | ||
| } | ||
| insertRegisterLiterally(editor, context, '=') | ||
| } catch (e: ExException) { | ||
| injector.messages.indicateError() | ||
| injector.messages.showStatusBarMessage(editor, e.message) | ||
| } | ||
| } | ||
| return true | ||
| } else { | ||
| return insertRegisterLiterally(editor, context, argument.character) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Inserts the contents of the specified register | ||
| * | ||
|
|
@@ -84,3 +120,28 @@ private fun insertRegister(editor: VimEditor, context: ExecutionContext, key: Ch | |
| } | ||
| return false | ||
| } | ||
|
|
||
| /** | ||
| * Inserts the contents of the specified register literally without auto-indent | ||
| * | ||
| * @param editor The editor to insert the text into | ||
| * @param context The data context | ||
| * @param key The register name | ||
| * @return true if able to insert the register contents, false if not | ||
| */ | ||
| @VimLockLabel.SelfSynchronized | ||
| private fun insertRegisterLiterally(editor: VimEditor, context: ExecutionContext, key: Char): Boolean { | ||
| val register: Register? = injector.registerGroup.getRegister(editor, context, key) | ||
| if (register != null) { | ||
| val textData = PutData.TextData( | ||
| register.name, | ||
| injector.clipboardManager.dumbCopiedText(register.text), | ||
| SelectionType.CHARACTER_WISE | ||
| ) | ||
| val putData = | ||
| PutData(textData, null, 1, insertTextBeforeCaret = true, rawIndent = true, caretAfterInsertedText = true) | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
| injector.put.putText(editor, context, putData) | ||
| return true | ||
| } | ||
| return false | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good - this test verifies basic
<C-R>functionality. However, consider adding a test that demonstrates the auto-indent behavior of<C-R>vs the literal behavior of<C-R><C-R>with multi-line or indented content.