diff --git a/platform/platform-impl/codeinsight-inline/src/com/intellij/codeInsight/inline/completion/render/InlineCompletionTextRenderManager.kt b/platform/platform-impl/codeinsight-inline/src/com/intellij/codeInsight/inline/completion/render/InlineCompletionTextRenderManager.kt index 0be3e2d759e0..57b9cdb8890a 100644 --- a/platform/platform-impl/codeinsight-inline/src/com/intellij/codeInsight/inline/completion/render/InlineCompletionTextRenderManager.kt +++ b/platform/platform-impl/codeinsight-inline/src/com/intellij/codeInsight/inline/completion/render/InlineCompletionTextRenderManager.kt @@ -306,6 +306,10 @@ internal class InlineCompletionTextRenderManager private constructor( } private fun Editor.forceLeanLeft() { + if (caretModel.currentCaret.isAtRtlLocation) { + // IDEA-373460: otherwise, we may move the caret which invalidates the current inline completion session + return + } val visualPosition = caretModel.visualPosition if (visualPosition.leansRight) { val leftLeaningPosition = VisualPosition(visualPosition.line, visualPosition.column, false) diff --git a/platform/platform-tests/testSrc/com/intellij/codeInsight/inline/completion/RTLInlineCompletionTest.kt b/platform/platform-tests/testSrc/com/intellij/codeInsight/inline/completion/RTLInlineCompletionTest.kt new file mode 100644 index 000000000000..c32851b20eb9 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/codeInsight/inline/completion/RTLInlineCompletionTest.kt @@ -0,0 +1,57 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.codeInsight.inline.completion + +import com.intellij.codeInsight.inline.completion.elements.InlineCompletionElement +import com.intellij.codeInsight.inline.completion.elements.InlineCompletionGrayTextElement +import com.intellij.codeInsight.inline.completion.impl.SimpleInlineCompletionProvider +import com.intellij.openapi.fileTypes.PlainTextFileType +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +internal class RTLInlineCompletionTest : InlineCompletionTestCase() { + + private fun registerSuggestion(vararg suggestion: InlineCompletionElement) { + InlineCompletionHandler.registerTestHandler(Provider(suggestion.toList()), testRootDisposable) + } + + @Test + fun `test accept RTL inline suggestion at the start position`() = myFixture.testInlineCompletion { + init(PlainTextFileType.INSTANCE, " مرحبا، كيف حالك") + caret { + // Forcing RTL + moveRight(); moveRight() + } + registerSuggestion(InlineCompletionGrayTextElement("اليوم؟")) + callInlineCompletion() + delay() + assertInlineRender("اليوم؟") + typeChar('ا') + assertInlineRender("ليوم؟") + insertWithTab() + assertInlineHidden() + assertFileContent(" مرحبا، كيف حالكاليوم؟") // it's actually " arabic". It's just rendered this way in IJ. + } + + @Test + fun `test accept RTL inline suggestion inside RTL part`() = myFixture.testInlineCompletion { + init(PlainTextFileType.INSTANCE, " مرحبا، كيف حالك") + caret { + // RTL position after the first (last) letter + moveRight(); moveRight(); moveRight() + } + registerSuggestion(InlineCompletionGrayTextElement("اليوم؟")) + callInlineCompletion() + delay() + assertInlineRender("اليوم؟") + insertWithTab() + assertFileContent(" مرحبا، كيف حالاليوم؟ك") + } + + private class Provider(suggestion: List) : SimpleInlineCompletionProvider(suggestion) { + override fun isEnabled(event: InlineCompletionEvent): Boolean { + return super.isEnabled(event) || event is InlineCompletionEvent.DirectCall + } + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/codeInsight/inline/completion/impl/InlineCompletionProviders.kt b/platform/platform-tests/testSrc/com/intellij/codeInsight/inline/completion/impl/InlineCompletionProviders.kt index 15b2562452bc..66e2189d23b8 100644 --- a/platform/platform-tests/testSrc/com/intellij/codeInsight/inline/completion/impl/InlineCompletionProviders.kt +++ b/platform/platform-tests/testSrc/com/intellij/codeInsight/inline/completion/impl/InlineCompletionProviders.kt @@ -81,7 +81,7 @@ internal class GradualMultiSuggestInlineCompletionProvider( } } -internal class SimpleInlineCompletionProvider(val suggestion: List) : InlineCompletionProvider { +internal open class SimpleInlineCompletionProvider(val suggestion: List) : InlineCompletionProvider { override val id: InlineCompletionProviderID = InlineCompletionProviderID("SimpleInlineCompletionProvider") override suspend fun getSuggestion(request: InlineCompletionRequest): InlineCompletionSingleSuggestion {