From 037c6620e3310ae0e1788eeeb456aafdb33e0eef Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 14 Nov 2025 14:39:35 +0100 Subject: [PATCH] IJPL-214795 [mod-completion] (part) isApplicable handling in ModNavigatorTailType (sort of) GitOrigin-RevId: 9acfd1878611b2a10caf057ff0d4ab981f43b5a6 --- .../intellij/codeInsight/JavaTailTypes.java | 19 ++++++------------- .../analysis-api/api-dump-experimental.txt | 6 ++++++ platform/analysis-api/api-dump.txt | 5 ----- .../codeInsight/ModNavigatorTailType.java | 18 ++++++++++++++++++ .../com/intellij/codeInsight/TailTypes.java | 14 ++++++-------- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/JavaTailTypes.java b/java/java-impl/src/com/intellij/codeInsight/JavaTailTypes.java index c5cff9d94fe7..5ec037876fb1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/JavaTailTypes.java +++ b/java/java-impl/src/com/intellij/codeInsight/JavaTailTypes.java @@ -1,7 +1,6 @@ // 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; -import com.intellij.codeInsight.completion.InsertionContext; import com.intellij.codeInsight.completion.simple.BracesTailType; import com.intellij.codeInsight.completion.simple.ParenthesesTailType; import com.intellij.codeInsight.completion.simple.RParenthTailType; @@ -125,29 +124,23 @@ public final class JavaTailTypes { }; private static final String ARROW = " -> "; public static final ModNavigatorTailType CASE_ARROW = new ModNavigatorTailType() { - @Override - public int processTail(@NotNull Editor editor, int tailOffset) { - Document document = editor.getDocument(); - document.insertString(tailOffset, ARROW); - return moveCaret(editor, tailOffset, ARROW.length()); - } - @Override public int processTail(@NotNull Project project, @NotNull ModNavigator navigator, int tailOffset) { Document document = navigator.getDocument(); + if (!isApplicable(project, document, tailOffset)) return tailOffset; document.insertString(tailOffset, ARROW); return moveCaret(navigator, tailOffset, ARROW.length()); } - @Override - public boolean isApplicable(@NotNull InsertionContext context) { - Document document = context.getDocument(); + public boolean isApplicable(@NotNull Project project, @NotNull Document document, int tailOffset) { CharSequence chars = document.getCharsSequence(); - int offset = CharArrayUtil.shiftForward(chars, context.getTailOffset(), " \n\t"); + int offset = CharArrayUtil.shiftForward(chars, tailOffset, " \n\t"); if (CharArrayUtil.regionMatches(chars, offset, "->")) { return false; } - PsiElement element = context.getFile().findElementAt(context.getStartOffset()); + PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(document); + if (file == null) return false; + PsiElement element = file.findElementAt(tailOffset - 1); return PsiUtil.isJavaToken(element, JavaTokenType.DEFAULT_KEYWORD) || PsiUtil.isJavaToken(element, JavaTokenType.CASE_KEYWORD) || PsiTreeUtil.getParentOfType(element, PsiCaseLabelElementList.class) != null; diff --git a/platform/analysis-api/api-dump-experimental.txt b/platform/analysis-api/api-dump-experimental.txt index 51b1be040da4..0c48e0e0d90c 100644 --- a/platform/analysis-api/api-dump-experimental.txt +++ b/platform/analysis-api/api-dump-experimental.txt @@ -1,3 +1,9 @@ +*a:com.intellij.codeInsight.ModNavigatorTailType +- com.intellij.codeInsight.TailType +- ():V +- isApplicable(com.intellij.codeInsight.completion.InsertionContext):Z +- processTail(com.intellij.openapi.editor.Editor,I):I +- a:processTail(com.intellij.openapi.project.Project,com.intellij.openapi.editor.ModNavigator,I):I a:com.intellij.codeInsight.completion.CompletionService - *p:getVariantsFromGroupContributors(com.intellij.codeInsight.completion.CompletionParameters,com.intellij.codeInsight.completion.PrefixMatcher,com.intellij.util.Consumer):V *:com.intellij.codeInsight.completion.command.CommandCompletionFactory diff --git a/platform/analysis-api/api-dump.txt b/platform/analysis-api/api-dump.txt index 2df935ba084a..f075582d2251 100644 --- a/platform/analysis-api/api-dump.txt +++ b/platform/analysis-api/api-dump.txt @@ -1,11 +1,6 @@ c:com.intellij.codeInsight.CharTailType - com.intellij.codeInsight.ModNavigatorTailType - processTail(com.intellij.openapi.project.Project,com.intellij.openapi.editor.ModNavigator,I):I -a:com.intellij.codeInsight.ModNavigatorTailType -- com.intellij.codeInsight.TailType -- ():V -- processTail(com.intellij.openapi.editor.Editor,I):I -- a:processTail(com.intellij.openapi.project.Project,com.intellij.openapi.editor.ModNavigator,I):I a:com.intellij.codeInsight.TailType - s:insertChar(com.intellij.openapi.editor.ModNavigator,I,C):I - s:insertChar(com.intellij.openapi.editor.ModNavigator,I,C,Z):I diff --git a/platform/analysis-api/src/com/intellij/codeInsight/ModNavigatorTailType.java b/platform/analysis-api/src/com/intellij/codeInsight/ModNavigatorTailType.java index 507c755454e3..6257c464af13 100644 --- a/platform/analysis-api/src/com/intellij/codeInsight/ModNavigatorTailType.java +++ b/platform/analysis-api/src/com/intellij/codeInsight/ModNavigatorTailType.java @@ -1,9 +1,11 @@ // 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; +import com.intellij.codeInsight.completion.InsertionContext; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ModNavigator; import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -11,7 +13,23 @@ import java.util.Objects; /** * A base class for tail types that use {@link ModNavigator} instead of {@link Editor} to insert the tail. */ +@ApiStatus.Experimental public abstract class ModNavigatorTailType extends TailType { + /** + * @return true. {@link ModNavigatorTailType} should be always applicable. + * @deprecated If you want to make it non-applicable, simply do nothing inside {@link #processTail(Project, ModNavigator, int)}. + * May become final in future. + */ + @Deprecated + @Override + public boolean isApplicable(@NotNull InsertionContext context) { + return true; + } + + /** + * @implSpec this implementation delegates to {@link #processTail(Project, ModNavigator, int)} adapting the arguments. + * Normally, it should not be overridden in clients. + */ @Override public int processTail(final @NotNull Editor editor, int tailOffset) { return processTail(Objects.requireNonNull(editor.getProject()), editor.asModNavigator(), tailOffset); diff --git a/platform/analysis-api/src/com/intellij/codeInsight/TailTypes.java b/platform/analysis-api/src/com/intellij/codeInsight/TailTypes.java index 1dc5ce3a23fc..5fbba9384608 100644 --- a/platform/analysis-api/src/com/intellij/codeInsight/TailTypes.java +++ b/platform/analysis-api/src/com/intellij/codeInsight/TailTypes.java @@ -1,7 +1,6 @@ // 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; -import com.intellij.codeInsight.completion.InsertionContext; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ModNavigator; @@ -54,16 +53,15 @@ public final class TailTypes { private static final ModNavigatorTailType HUMBLE_SPACE_BEFORE_WORD = new CharTailType(' ', false) { @Override - public boolean isApplicable(@NotNull InsertionContext context) { - CharSequence text = context.getDocument().getCharsSequence(); - int tail = context.getTailOffset(); - if (text.length() > tail + 1 && text.charAt(tail) == ' ') { - char ch = text.charAt(tail + 1); + public int processTail(@NotNull Project project, @NotNull ModNavigator navigator, int tailOffset) { + CharSequence text = navigator.getDocument().getCharsSequence(); + if (text.length() > tailOffset + 1 && text.charAt(tailOffset) == ' ') { + char ch = text.charAt(tailOffset + 1); if (ch == '@' || Character.isLetter(ch)) { - return false; + return tailOffset; } } - return super.isApplicable(context); + return super.processTail(project, navigator, tailOffset); } @Override