Skip to content

Commit

Permalink
fix: calculation to find the closest delimited range
Browse files Browse the repository at this point in the history
  • Loading branch information
oca159 committed Jan 29, 2025
1 parent f1fd08c commit ad37956
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 26 deletions.
73 changes: 47 additions & 26 deletions src/main/java/com/maddyhome/idea/vim/extension/miniai/MiniAI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -194,42 +194,63 @@ private fun addAction(action: TextObjectActionHandler) {
keyHandlerState.commandBuilder.addAction(action)
}

private fun findClosestBracketRange(
private fun findClosestDelimitedRange(
editor: VimEditor,
caret: ImmutableVimCaret,
count: Int,
isOuter: Boolean,
delimiters: List<Char>,
findRange: (Char) -> TextRange?
): TextRange? {
return listOf('(', '[', '{')
.mapNotNull { char ->
findBlockRange(editor, caret, char, count, isOuter)?.let { range -> range to char }
val allRanges = delimiters.mapNotNull { char ->
findRange(char)?.let { range ->
DelimitedRange(range, char)
}
.minByOrNull { it.first.distanceTo(caret.offset) }?.first
}

// First, find all ranges that contain the caret
val containingRanges = allRanges.filter {
caret.offset in it.range.startOffset..it.range.endOffset
}

// If we have containing ranges, return the smallest one
if (containingRanges.isNotEmpty()) {
return containingRanges.minBy {
it.range.endOffset - it.range.startOffset
}.range
}

// If no containing ranges, find the closest one
return allRanges
.minByOrNull { range ->
val startDistance = kotlin.math.abs(caret.offset - range.range.startOffset)
val endDistance = kotlin.math.abs(caret.offset - range.range.endOffset)
startDistance + endDistance
}?.range
}

private fun findClosestQuoteRange(
private fun findClosestBracketRange(
editor: VimEditor,
caret: ImmutableVimCaret,
isOuter: Boolean,
count: Int,
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
val brackets = listOf('(', '[', '{')
return findClosestDelimitedRange(editor, caret, brackets) { char ->
findBlockRange(editor, caret, char, count, isOuter)
}
}

private fun TextRange.distanceTo(caretOffset: Int): Int {
val rangeLength = endOffset - startOffset

// If caret is inside the range
if (caretOffset in startOffset..endOffset) {
// Return the length of the range - smaller ranges get priority
return rangeLength
private fun findClosestQuoteRange(
editor: VimEditor,
caret: ImmutableVimCaret,
isOuter: Boolean
): TextRange? {
val quotes = listOf('`', '"', '\'')
return findClosestDelimitedRange(editor, caret, quotes) { char ->
injector.searchHelper.findBlockQuoteInLineRange(editor, caret, char, isOuter)
}

// If caret is outside, make the distance much larger
val startDistance = kotlin.math.abs(caretOffset - startOffset)
val endDistance = kotlin.math.abs(caretOffset - endOffset)
return (startDistance + endDistance) * 1000 + rangeLength
}

private data class DelimitedRange(
val range: TextRange,
val char: Char
)
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ class MiniAIExtensionTest : VimJavaTestCase() {
enableExtensions("mini-ai")
}


@Test
fun testFromAlex() {
doTest(
"ciq",
"<caret>This is a \"'simple'\" test",
"This is a \"<caret>\" test",
Mode.INSERT,
JavaFileType.INSTANCE,
)
assertSelection(null)
}

@Test
fun testChangeInsideNestedQuotes() {
doTest(
Expand Down

0 comments on commit ad37956

Please sign in to comment.