diff --git a/doc/IdeaVim Plugins.md b/doc/IdeaVim Plugins.md
index de38d59d6..91b1c7a43 100644
--- a/doc/IdeaVim Plugins.md	
+++ b/doc/IdeaVim Plugins.md	
@@ -423,6 +423,24 @@ https://plugins.jetbrains.com/plugin/19417-ideavim-quickscope
 
 </details>
 
+<details>
+<summary><h2>Mini.ai: Extend and create a/i textobjects (IMPORTANT: The plugin is not related with artificial intelligence)</h2></summary>
+
+### Features: 
+Provides additional text object motions for handling quotes and brackets. The following motions are included:
+
+- aq: Around any quotes.
+- iq: Inside any quotes.
+- ab: Around any parentheses, curly braces, and square brackets.
+- ib: Inside any parentheses, curly braces, and square brackets.
+
+Original plugin: [mini.ai](https://github.com/echasnovski/mini.ai).
+
+### Setup:
+- Add the following command to `~/.ideavimrc`: `set mini-ai`
+
+</details>
+
 
 <details>
 <summary><h2>Which-Key</h2></summary>
@@ -484,4 +502,3 @@ or restart the IDE.
 
 https://plugins.jetbrains.com/plugin/25899-vim-switch
 
-</details>
diff --git a/src/main/java/com/maddyhome/idea/vim/extension/miniai/MiniAI.kt b/src/main/java/com/maddyhome/idea/vim/extension/miniai/MiniAI.kt
new file mode 100644
index 000000000..2bda28f6c
--- /dev/null
+++ b/src/main/java/com/maddyhome/idea/vim/extension/miniai/MiniAI.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2003-2023 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 com.maddyhome.idea.vim.extension.miniai
+
+import com.maddyhome.idea.vim.KeyHandler
+import com.maddyhome.idea.vim.api.ExecutionContext
+import com.maddyhome.idea.vim.api.ImmutableVimCaret
+import com.maddyhome.idea.vim.api.VimEditor
+import com.maddyhome.idea.vim.api.injector
+import com.maddyhome.idea.vim.command.CommandFlags
+import com.maddyhome.idea.vim.command.MappingMode
+import com.maddyhome.idea.vim.command.OperatorArguments
+import com.maddyhome.idea.vim.command.TextObjectVisualType
+import com.maddyhome.idea.vim.common.TextRange
+import com.maddyhome.idea.vim.extension.ExtensionHandler
+import com.maddyhome.idea.vim.extension.VimExtension
+import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
+import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
+import com.maddyhome.idea.vim.group.findBlockRange
+import com.maddyhome.idea.vim.handler.TextObjectActionHandler
+import com.maddyhome.idea.vim.helper.enumSetOf
+import com.maddyhome.idea.vim.state.KeyHandlerState
+import java.util.*
+
+/**
+ * Extend and create a/i textobjects
+ *
+ * <p>
+ * mini ai provides the next motions:
+ * <ul>
+ *   <li>aq around any quotes.</li>
+ *   <li>iq inside any quotes.</li>
+ *   <li>ab around any parentheses, curly braces and square brackets.</li>
+ *   <li>ib inside any parentheses, curly braces and square brackets.</li>
+ * </ul>
+ *
+ * @author Osvaldo Cordova Aburto (@oca159)
+ */
+internal class MiniAI : VimExtension {
+
+  companion object {
+    // Constants for key mappings
+    private const val PLUG_AQ = "<Plug>mini-ai-aq"
+    private const val PLUG_IQ = "<Plug>mini-ai-iq"
+    private const val PLUG_AB = "<Plug>mini-ai-ab"
+    private const val PLUG_IB = "<Plug>mini-ai-ib"
+
+    // Constants for key sequences
+    private const val KEY_AQ = "aq"
+    private const val KEY_IQ = "iq"
+    private const val KEY_AB = "ab"
+    private const val KEY_IB = "ib"
+  }
+
+  override fun getName() = "mini-ai"
+
+  override fun init() {
+    registerMappings()
+  }
+
+  private fun registerMappings() {
+    val mappings = listOf(
+      PLUG_AQ to AroundAnyQuotesHandler(),
+      PLUG_IQ to InsideAnyQuotesHandler(),
+      PLUG_AB to AroundAnyBracketsHandler(),
+      PLUG_IB to InsideAnyBracketsHandler()
+    )
+
+    mappings.forEach { (key, handler) ->
+      putExtensionHandlerMapping(MappingMode.XO, injector.parser.parseKeys(key), owner, handler, false)
+    }
+
+    val keyMappings = listOf(
+      KEY_AQ to PLUG_AQ,
+      KEY_IQ to PLUG_IQ,
+      KEY_AB to PLUG_AB,
+      KEY_IB to PLUG_IB
+    )
+
+    keyMappings.forEach { (key, plug) ->
+      putKeyMapping(MappingMode.XO, injector.parser.parseKeys(key), owner, injector.parser.parseKeys(plug), true)
+    }
+  }
+
+
+  private class InsideAnyQuotesHandler : ExtensionHandler {
+    override val isRepeatable = true
+
+    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
+      addAction(MotionInnerAnyQuoteProximityAction())
+    }
+  }
+
+  private class AroundAnyQuotesHandler : ExtensionHandler {
+    override val isRepeatable = true
+
+    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
+      addAction(MotionOuterAnyQuoteProximityAction())
+    }
+  }
+
+  private class InsideAnyBracketsHandler : ExtensionHandler {
+    override val isRepeatable = true
+
+    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
+      addAction(MotionInnerAnyBracketProximityAction())
+    }
+  }
+
+  private class AroundAnyBracketsHandler : ExtensionHandler {
+    override val isRepeatable = true
+
+    override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
+      addAction(MotionOuterAnyBracketProximityAction())
+    }
+  }
+
+  class MotionInnerAnyQuoteProximityAction : TextObjectActionHandler() {
+
+    override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_TEXT_BLOCK)
+
+    override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE
+
+    override fun getRange(
+      editor: VimEditor,
+      caret: ImmutableVimCaret,
+      context: ExecutionContext,
+      count: Int,
+      rawCount: Int,
+    ): TextRange? {
+      return findClosestQuoteRange(editor, caret, false)
+    }
+  }
+
+  class MotionOuterAnyQuoteProximityAction : TextObjectActionHandler() {
+
+    override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_TEXT_BLOCK)
+
+    override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE
+
+    override fun getRange(
+      editor: VimEditor,
+      caret: ImmutableVimCaret,
+      context: ExecutionContext,
+      count: Int,
+      rawCount: Int,
+    ): TextRange? {
+      return findClosestQuoteRange(editor, caret, true)
+    }
+  }
+
+  class MotionInnerAnyBracketProximityAction : TextObjectActionHandler() {
+
+    override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_TEXT_BLOCK)
+
+    override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE
+
+    override fun getRange(
+      editor: VimEditor,
+      caret: ImmutableVimCaret,
+      context: ExecutionContext,
+      count: Int,
+      rawCount: Int,
+    ): TextRange? {
+      return findClosestBracketRange(editor, caret, count, false)
+    }
+  }
+}
+
+class MotionOuterAnyBracketProximityAction : TextObjectActionHandler() {
+
+  override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_TEXT_BLOCK)
+
+  override val visualType: TextObjectVisualType = TextObjectVisualType.CHARACTER_WISE
+
+  override fun getRange(
+    editor: VimEditor,
+    caret: ImmutableVimCaret,
+    context: ExecutionContext,
+    count: Int,
+    rawCount: Int,
+  ): TextRange? {
+    return findClosestBracketRange(editor, caret, count, true)
+  }
+}
+
+private fun addAction(action: TextObjectActionHandler) {
+  val keyHandlerState: KeyHandlerState = KeyHandler.getInstance().keyHandlerState
+  keyHandlerState.commandBuilder.addAction(action)
+}
+
+private fun findClosestBracketRange(
+  editor: VimEditor,
+  caret: ImmutableVimCaret,
+  count: Int,
+  isOuter: Boolean,
+): TextRange? {
+  return listOf('(', '[', '{')
+    .mapNotNull { char ->
+      findBlockRange(editor, caret, char, count, isOuter)?.let { range -> range to char }
+    }
+    .minByOrNull { it.first.distanceTo(caret.offset) }?.first
+}
+
+private fun findClosestQuoteRange(
+  editor: VimEditor,
+  caret: ImmutableVimCaret,
+  isOuter: Boolean,
+): TextRange? {
+  return listOf('`', '"', '\'')
+    .mapNotNull { char ->
+      injector.searchHelper.findBlockQuoteInLineRange(editor, caret, char, isOuter)?.let { range -> range to char }
+    }
+    .minByOrNull { it.first.distanceTo(caret.offset) }?.first
+}
+
+private fun TextRange.distanceTo(caretOffset: Int): Int {
+  return if (caretOffset < startOffset) {
+    startOffset - caretOffset
+  } else if (caretOffset > endOffset) {
+    caretOffset - endOffset
+  } else {
+    0 // Caret is inside the range
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/maddyhome/idea/vim/statistic/PluginState.kt b/src/main/java/com/maddyhome/idea/vim/statistic/PluginState.kt
index 355516a12..035036fec 100644
--- a/src/main/java/com/maddyhome/idea/vim/statistic/PluginState.kt
+++ b/src/main/java/com/maddyhome/idea/vim/statistic/PluginState.kt
@@ -45,7 +45,8 @@ internal class PluginState : ApplicationUsagesCollector() {
       "surround",
       "commentary",
       "matchit",
-      "textobj-indent"
+      "textobj-indent",
+      "mini-ai"
     )
     internal val enabledExtensions = HashSet<String>()
   }
diff --git a/src/main/resources/META-INF/includes/VimExtensions.xml b/src/main/resources/META-INF/includes/VimExtensions.xml
index f7d15720a..7a14af971 100644
--- a/src/main/resources/META-INF/includes/VimExtensions.xml
+++ b/src/main/resources/META-INF/includes/VimExtensions.xml
@@ -49,6 +49,15 @@
       </aliases>
     </vimExtension>
 
+
+    <vimExtension implementation="com.maddyhome.idea.vim.extension.miniai.MiniAI"
+                  name="mini-ai">
+      <aliases>
+        <alias name="https://github.com/echasnovski/mini.ai"/>
+        <alias name="echasnovski/mini.ai"/>
+      </aliases>
+    </vimExtension>
+
     <vimExtension implementation="com.maddyhome.idea.vim.extension.argtextobj.VimArgTextObjExtension"
                   name="argtextobj">
       <aliases>
diff --git a/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetCommandTest.kt b/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetCommandTest.kt
index ba0f965f9..c9d0f6253 100644
--- a/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetCommandTest.kt
+++ b/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetCommandTest.kt
@@ -183,20 +183,21 @@ class SetCommandTest : VimTestCase() {
       "set all",
       """
         |--- Options ---
-        |noargtextobj          ideamarks           scroll=0          nosurround
-        |nobomb                ideawrite=all       scrolljump=1      notextobj-entire
-        |nobreakindent       noignorecase          scrolloff=0       notextobj-indent
-        |  colorcolumn=      noincsearch           selectmode=         textwidth=0
-        |nocommentary        nolist                shellcmdflag=-x     timeout
-        |nocursorline        nomatchit             shellxescape=@      timeoutlen=1000
-        |nodigraph             maxmapdepth=20      shellxquote={     notrackactionids
-        |noexchange            more                showcmd             undolevels=1000
-        |  fileformat=unix   nomultiple-cursors    showmode            virtualedit=
-        |nogdefault          noNERDTree            sidescroll=0      novisualbell
-        |nohighlightedyank     nrformats=hex       sidescrolloff=0     visualdelay=100
-        |  history=50        nonumber            nosmartcase           whichwrap=b,s
-        |nohlsearch            operatorfunc=     nosneak               wrap
-        |noideajoin          norelativenumber      startofline         wrapscan
+        |noargtextobj          ideawrite=all       scrolljump=1      notextobj-indent
+        |nobomb              noignorecase          scrolloff=0         textwidth=0
+        |nobreakindent       noincsearch           selectmode=         timeout
+        |  colorcolumn=      nolist                shellcmdflag=-x     timeoutlen=1000
+        |nocommentary        nomatchit             shellxescape=@    notrackactionids
+        |nocursorline          maxmapdepth=20      shellxquote={       undolevels=1000
+        |nodigraph           nomini-ai             showcmd             virtualedit=
+        |noexchange            more                showmode          novisualbell
+        |  fileformat=unix   nomultiple-cursors    sidescroll=0        visualdelay=100
+        |nogdefault          noNERDTree            sidescrolloff=0     whichwrap=b,s
+        |nohighlightedyank     nrformats=hex     nosmartcase           wrap
+        |  history=50        nonumber            nosneak               wrapscan
+        |nohlsearch            operatorfunc=       startofline
+        |noideajoin          norelativenumber    nosurround
+        |  ideamarks           scroll=0          notextobj-entire
         |  clipboard=ideaput,autoselect
         |  fileencoding=utf-8
         |  guicursor=n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175
@@ -288,6 +289,7 @@ class SetCommandTest : VimTestCase() {
       |nomatchit
       |  matchpairs=(:),{:},[:]
       |  maxmapdepth=20
+      |nomini-ai
       |  more
       |nomultiple-cursors
       |noNERDTree
diff --git a/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetglobalCommandTest.kt b/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetglobalCommandTest.kt
index 48afdcb8a..54132197b 100644
--- a/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetglobalCommandTest.kt
+++ b/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetglobalCommandTest.kt
@@ -432,21 +432,21 @@ class SetglobalCommandTest : VimTestCase() {
     assertCommandOutput(
       "setglobal all", """
       |--- Global option values ---
-      |noargtextobj          ideamarks           scrolljump=1      notextobj-indent
-      |nobomb                ideawrite=all       scrolloff=0         textwidth=0
-      |nobreakindent       noignorecase          selectmode=         timeout
-      |  colorcolumn=      noincsearch           shellcmdflag=-x     timeoutlen=1000
-      |nocommentary        nolist                shellxescape=@    notrackactionids
-      |nocursorline        nomatchit             shellxquote={       undolevels=1000
-      |nodigraph             maxmapdepth=20      showcmd             virtualedit=
-      |noexchange            more                showmode          novisualbell
-      |  fileencoding=     nomultiple-cursors    sidescroll=0        visualdelay=100
-      |  fileformat=unix   noNERDTree            sidescrolloff=0     whichwrap=b,s
-      |nogdefault            nrformats=hex     nosmartcase           wrap
-      |nohighlightedyank   nonumber            nosneak               wrapscan
-      |  history=50          operatorfunc=       startofline
-      |nohlsearch          norelativenumber    nosurround
-      |noideajoin            scroll=0          notextobj-entire
+      |noargtextobj          ideamarks           scroll=0          notextobj-entire
+      |nobomb                ideawrite=all       scrolljump=1      notextobj-indent
+      |nobreakindent       noignorecase          scrolloff=0         textwidth=0
+      |  colorcolumn=      noincsearch           selectmode=         timeout
+      |nocommentary        nolist                shellcmdflag=-x     timeoutlen=1000
+      |nocursorline        nomatchit             shellxescape=@    notrackactionids
+      |nodigraph             maxmapdepth=20      shellxquote={       undolevels=1000
+      |noexchange          nomini-ai             showcmd             virtualedit=
+      |  fileencoding=       more                showmode          novisualbell
+      |  fileformat=unix   nomultiple-cursors    sidescroll=0        visualdelay=100
+      |nogdefault          noNERDTree            sidescrolloff=0     whichwrap=b,s
+      |nohighlightedyank     nrformats=hex     nosmartcase           wrap
+      |  history=50        nonumber            nosneak               wrapscan
+      |nohlsearch            operatorfunc=       startofline
+      |noideajoin          norelativenumber    nosurround
       |  clipboard=ideaput,autoselect
       |  guicursor=n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175
       |  ide=IntelliJ IDEA Community Edition
@@ -539,6 +539,7 @@ class SetglobalCommandTest : VimTestCase() {
       |nomatchit
       |  matchpairs=(:),{:},[:]
       |  maxmapdepth=20
+      |nomini-ai
       |  more
       |nomultiple-cursors
       |noNERDTree
diff --git a/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetlocalCommandTest.kt b/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetlocalCommandTest.kt
index 7f51d520e..b1d785c66 100644
--- a/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetlocalCommandTest.kt
+++ b/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/SetlocalCommandTest.kt
@@ -483,20 +483,21 @@ class SetlocalCommandTest : VimTestCase() {
     assertCommandOutput(
       "setlocal all", """
       |--- Local option values ---
-      |noargtextobj          ideamarks         norelativenumber      startofline
-      |nobomb                idearefactormode=   scroll=0          nosurround
-      |nobreakindent         ideawrite=all       scrolljump=1      notextobj-entire
-      |  colorcolumn=      noignorecase          scrolloff=-1      notextobj-indent
-      |nocommentary        noincsearch           selectmode=         textwidth=0
-      |nocursorline        nolist                shellcmdflag=-x     timeout
-      |nodigraph           nomatchit             shellxescape=@      timeoutlen=1000
-      |noexchange            maxmapdepth=20      shellxquote={     notrackactionids
-      |  fileformat=unix     more                showcmd             virtualedit=
-      |nogdefault          nomultiple-cursors    showmode          novisualbell
-      |nohighlightedyank   noNERDTree            sidescroll=0        visualdelay=100
-      |  history=50          nrformats=hex       sidescrolloff=-1    whichwrap=b,s
-      |nohlsearch          nonumber            nosmartcase           wrap
-      |--ideajoin            operatorfunc=     nosneak               wrapscan
+      |noargtextobj          idearefactormode=   scroll=0          notextobj-entire
+      |nobomb                ideawrite=all       scrolljump=1      notextobj-indent
+      |nobreakindent       noignorecase          scrolloff=-1        textwidth=0
+      |  colorcolumn=      noincsearch           selectmode=         timeout
+      |nocommentary        nolist                shellcmdflag=-x     timeoutlen=1000
+      |nocursorline        nomatchit             shellxescape=@    notrackactionids
+      |nodigraph             maxmapdepth=20      shellxquote={       virtualedit=
+      |noexchange          nomini-ai             showcmd           novisualbell
+      |  fileformat=unix     more                showmode            visualdelay=100
+      |nogdefault          nomultiple-cursors    sidescroll=0        whichwrap=b,s
+      |nohighlightedyank   noNERDTree            sidescrolloff=-1    wrap
+      |  history=50          nrformats=hex     nosmartcase           wrapscan
+      |nohlsearch          nonumber            nosneak
+      |--ideajoin            operatorfunc=       startofline
+      |  ideamarks         norelativenumber    nosurround
       |  clipboard=ideaput,autoselect
       |  fileencoding=utf-8
       |  guicursor=n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175
@@ -588,6 +589,7 @@ class SetlocalCommandTest : VimTestCase() {
       |nomatchit
       |  matchpairs=(:),{:},[:]
       |  maxmapdepth=20
+      |nomini-ai
       |  more
       |nomultiple-cursors
       |noNERDTree
diff --git a/tests/java-tests/src/test/kotlin/org/jetbrains/plugins/ideavim/extension/miniai/MiniAIExtensionTest.kt b/tests/java-tests/src/test/kotlin/org/jetbrains/plugins/ideavim/extension/miniai/MiniAIExtensionTest.kt
new file mode 100644
index 000000000..03c00adbf
--- /dev/null
+++ b/tests/java-tests/src/test/kotlin/org/jetbrains/plugins/ideavim/extension/miniai/MiniAIExtensionTest.kt
@@ -0,0 +1,644 @@
+/*
+ * Copyright 2003-2024 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.extension.miniai
+
+import com.intellij.ide.highlighter.JavaFileType
+import com.maddyhome.idea.vim.state.mode.Mode
+import org.jetbrains.plugins.ideavim.VimJavaTestCase
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.TestInfo
+
+@Suppress("SpellCheckingInspection")
+class MiniAIExtensionTest : VimJavaTestCase() {
+  @BeforeEach
+  override fun setUp(testInfo: TestInfo) {
+    super.setUp(testInfo)
+    enableExtensions("mini-ai")
+  }
+
+  @Test
+  fun testChangeInsideSingleQuote() {
+    doTest(
+      "ciq",
+      "<caret>This is a 'simple' test",
+      "This is a '<caret>' test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideSingleQuoteNotBalanced() {
+    doTest(
+      "ciq",
+      "<caret>This is a 'simple test",
+      "<caret>This is a 'simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideDoubleQuote() {
+    doTest(
+      "ciq",
+      "<caret>This is a \"simple\" test",
+      "This is a \"<caret>\" test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideDoubleQuoteNotBalanced() {
+    doTest(
+      "ciq",
+      "<caret>This is a \"simple test",
+      "<caret>This is a \"simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideBackQuote() {
+    doTest(
+      "ciq",
+      "<caret>This is a `simple` test",
+      "This is a `<caret>` test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideBackQuoteNotBalanced() {
+    doTest(
+      "ciq",
+      "<caret>This is a `simple test",
+      "<caret>This is a `simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundSingleQuote() {
+    doTest(
+      "caq",
+      "<caret>This is a 'simple' test",
+      "This is a <caret> test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundSingleQuoteNotBalanced() {
+    doTest(
+      "caq",
+      "<caret>This is a 'simple test",
+      "<caret>This is a 'simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundDoubleQuote() {
+    doTest(
+      "caq",
+      "<caret>This is a \"simple\" test",
+      "This is a <caret> test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundDoubleQuoteNotBalanced() {
+    doTest(
+      "caq",
+      "<caret>This is a \"simple test",
+      "<caret>This is a \"simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+  @Test
+  fun testChangeAroundBackQuote() {
+    doTest(
+      "caq",
+      "<caret>This is a `simple` test",
+      "This is a <caret> test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundBackQuoteNotBalanced() {
+    doTest(
+      "caq",
+      "<caret>This is a `simple test",
+      "<caret>This is a `simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+  @Test
+  fun testChangeInsideRoundBrackets() {
+    doTest(
+      "cib",
+      "<caret>This is a (simple) test",
+      "This is a (<caret>) test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideRoundBracketsNotBalanced() {
+    doTest(
+      "cib",
+      "<caret>This is a (simple test",
+      "<caret>This is a (simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideSquareBrackets() {
+    doTest(
+      "cib",
+      "<caret>This is a [simple] test",
+      "This is a [<caret>] test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideSquareBracketsNotBalanced() {
+    doTest(
+      "cib",
+      "<caret>This is a [simple test",
+      "<caret>This is a [simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideCurlyBrackets() {
+    doTest(
+      "cib",
+      "<caret>This is a {simple} test",
+      "This is a {<caret>} test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeInsideCurlyBracketsNotBalanced() {
+    doTest(
+      "cib",
+      "<caret>This is a {simple test",
+      "<caret>This is a {simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundRoundBrackets() {
+    doTest(
+      "cab",
+      "<caret>This is a (simple) test",
+      "This is a <caret> test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundRoundBracketsNotBalanced() {
+    doTest(
+      "cab",
+      "<caret>This is a (simple test",
+      "<caret>This is a (simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundSquareBrackets() {
+    doTest(
+      "cab",
+      "<caret>This is a [simple] test",
+      "This is a <caret> test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+  @Test
+  fun testChangeAroundSquareBracketsNotBalanced() {
+    doTest(
+      "cab",
+      "<caret>This is a [simple test",
+      "<caret>This is a [simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundCurlyBrackets() {
+    doTest(
+      "cab",
+      "<caret>This is a {simple} test",
+      "This is a <caret> test",
+      Mode.INSERT,
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testChangeAroundCurlyBracketsNotBalanced() {
+    doTest(
+      "cab",
+      "<caret>This is a {simple test",
+      "<caret>This is a {simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+  // DELETE tests
+  @Test
+  fun testDeleteInsideSingleQuote() {
+    doTest(
+      "diq",
+      "<caret>This is a 'simple' test",
+      "This is a '<caret>' test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideSingleQuoteNotBalanced() {
+    doTest(
+      "diq",
+      "<caret>This is a 'simple test",
+      "<caret>This is a 'simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideDoubleQuote() {
+    doTest(
+      "diq",
+      "<caret>This is a \"simple\" test",
+      "This is a \"<caret>\" test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideDoubleQuoteNotBalanced() {
+    doTest(
+      "diq",
+      "<caret>This is a \"simple test",
+      "<caret>This is a \"simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideBackQuote() {
+    doTest(
+      "diq",
+      "<caret>This is a `simple` test",
+      "This is a `<caret>` test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideBackQuoteNotBalanced() {
+    doTest(
+      "diq",
+      "<caret>This is a `simple test",
+      "<caret>This is a `simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundSingleQuote() {
+    doTest(
+      "daq",
+      "<caret>This is a 'simple' test",
+      "This is a <caret> test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+  @Test
+  fun testDeleteAroundSingleQuoteNotBalanced() {
+    doTest(
+      "daq",
+      "<caret>This is a 'simple test",
+      "<caret>This is a 'simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundDoubleQuote() {
+    doTest(
+      "daq",
+      "<caret>This is a \"simple\" test",
+      "This is a <caret> test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundDoubleQuoteNotBalanced() {
+    doTest(
+      "daq",
+      "<caret>This is a \"simple test",
+      "<caret>This is a \"simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundBackQuote() {
+    doTest(
+      "daq",
+      "<caret>This is a `simple` test",
+      "This is a <caret> test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundBackQuoteNotBalanced() {
+    doTest(
+      "daq",
+      "<caret>This is a `simple test",
+      "<caret>This is a `simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideRoundBrackets() {
+    doTest(
+      "dib",
+      "<caret>This is a (simple) test",
+      "This is a (<caret>) test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideRoundBracketsNotBalanced() {
+    doTest(
+      "dib",
+      "<caret>This is a (simple test",
+      "<caret>This is a (simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideSquareBrackets() {
+    doTest(
+      "dib",
+      "<caret>This is a [simple] test",
+      "This is a [<caret>] test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideSquareBracketsNotBalanced() {
+    doTest(
+      "dib",
+      "<caret>This is a [simple test",
+      "<caret>This is a [simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideCurlyBrackets() {
+    doTest(
+      "dib",
+      "<caret>This is a {simple} test",
+      "This is a {<caret>} test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteInsideCurlyBracketsNotBalanced() {
+    doTest(
+      "dib",
+      "<caret>This is a {simple test",
+      "<caret>This is a {simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundRoundBrackets() {
+    doTest(
+      "dab",
+      "<caret>This is a (simple) test",
+      "This is a <caret> test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundRoundBracketsNotBalanced() {
+    doTest(
+      "dab",
+      "<caret>This is a (simple test",
+      "<caret>This is a (simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundSquareBrackets() {
+    doTest(
+      "dab",
+      "<caret>This is a [simple] test",
+      "This is a <caret> test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundSquareBracketsNotBalanced() {
+    doTest(
+      "dab",
+      "<caret>This is a [simple test",
+      "<caret>This is a [simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundCurlyBrackets() {
+    doTest(
+      "dab",
+      "<caret>This is a {simple} test",
+      "This is a <caret> test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+
+
+  @Test
+  fun testDeleteAroundCurlyBracketsNotBalanced() {
+    doTest(
+      "dab",
+      "<caret>This is a {simple test",
+      "<caret>This is a {simple test",
+      Mode.NORMAL(),
+      JavaFileType.INSTANCE,
+    )
+    assertSelection(null)
+  }
+}