diff --git a/plugins/grazie/src/main/kotlin/com/intellij/grazie/ide/inspection/grammar/quickfix/GrazieReplaceTypoQuickFix.kt b/plugins/grazie/src/main/kotlin/com/intellij/grazie/ide/inspection/grammar/quickfix/GrazieReplaceTypoQuickFix.kt index b1c7b7ab87b6..ddc7645e13ba 100644 --- a/plugins/grazie/src/main/kotlin/com/intellij/grazie/ide/inspection/grammar/quickfix/GrazieReplaceTypoQuickFix.kt +++ b/plugins/grazie/src/main/kotlin/com/intellij/grazie/ide/inspection/grammar/quickfix/GrazieReplaceTypoQuickFix.kt @@ -124,17 +124,27 @@ object GrazieReplaceTypoQuickFix { val commonSuffix = min(commonSuffixLength(suggestion, replacedText), min(suggestion.length, replacementRange.length) - commonPrefix) val localRange = TextRange(replacementRange.startOffset + commonPrefix, replacementRange.endOffset - commonSuffix) - val replacement = suggestion.substring(commonPrefix, suggestion.length - commonSuffix) + var replacement = suggestion.substring(commonPrefix, suggestion.length - commonSuffix) val file = text.containingFile val spm = SmartPointerManager.getInstance(file.project) val shreds = text.intersection(text.textRangeToFile(localRange)) if (shreds.isEmpty()) return emptyList() + if (replacement.isEmpty() && removalWouldGlueUnrelatedTokens(localRange, text)) { + replacement = " "; + } + val best = if (isWordMiddle(text, localRange.endOffset)) shreds.last() else shreds.first() return shreds.map { spm.createSmartPsiFileRangePointer(file, it) to (if (it === best) replacement else "") } } + private fun removalWouldGlueUnrelatedTokens(removedRange: TextRange, text: TextContent): Boolean { + val prevFileIndex = text.textOffsetToFile(0) - 1 + return removedRange.endOffset < text.length && text[removedRange.endOffset].isLetterOrDigit() && + prevFileIndex > 0 && text.containingFile.viewProvider.contents[prevFileIndex].isLetterOrDigit() + } + private fun isWordMiddle(text: CharSequence, index: Int) = index > 0 && index < text.length && Character.isLetter(text[index]) && Character.isLetter(text[index - 1]) diff --git a/plugins/grazie/src/test/kotlin/com/intellij/grazie/ide/language/JavaSupportTest.kt b/plugins/grazie/src/test/kotlin/com/intellij/grazie/ide/language/JavaSupportTest.kt index dd958b446e29..7069865f96f4 100644 --- a/plugins/grazie/src/test/kotlin/com/intellij/grazie/ide/language/JavaSupportTest.kt +++ b/plugins/grazie/src/test/kotlin/com/intellij/grazie/ide/language/JavaSupportTest.kt @@ -36,6 +36,12 @@ class JavaSupportTest : GrazieTestBase() { myFixture.checkResultByFile("ide/language/java/SplitLine_after.java") } + fun `test do not merge text with non-text`() { + runHighlightTestForFile("ide/language/java/AccidentalMerge.java") + myFixture.launchAction(myFixture.findSingleIntention("Remove")) + myFixture.checkResultByFile("ide/language/java/AccidentalMerge_after.java") + } + fun `test long comment performance`() { PlatformTestUtil.startPerformanceTest("highlighting", 1000) { runHighlightTestForFile("ide/language/java/LongCommentPerformance.java") diff --git a/plugins/grazie/src/test/testData/ide/language/java/AccidentalMerge.java b/plugins/grazie/src/test/testData/ide/language/java/AccidentalMerge.java new file mode 100644 index 000000000000..4077da911c9a --- /dev/null +++ b/plugins/grazie/src/test/testData/ide/language/java/AccidentalMerge.java @@ -0,0 +1,6 @@ +class C { + /** + * @param a:here is some English text producing an error. And here's another sentence. + */ + void foo(int a){} +} \ No newline at end of file diff --git a/plugins/grazie/src/test/testData/ide/language/java/AccidentalMerge_after.java b/plugins/grazie/src/test/testData/ide/language/java/AccidentalMerge_after.java new file mode 100644 index 000000000000..7efc421d82e6 --- /dev/null +++ b/plugins/grazie/src/test/testData/ide/language/java/AccidentalMerge_after.java @@ -0,0 +1,6 @@ +class C { + /** + * @param a here is some English text producing an error. And here's another sentence. + */ + void foo(int a){} +} \ No newline at end of file