mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
IJPL-233853 [mod-completion] LiveTemplateCompletionContributor (2st step)
GitOrigin-RevId: eb7a5d5e65a307bb01f9883451196fac0c0e53ea
This commit is contained in:
committed by
intellij-monorepo-bot
parent
e6c2be9ab0
commit
3eee71e033
+1
@@ -26,6 +26,7 @@ import com.intellij.codeInsight.template.macro.MethodNameMacro;
|
||||
import com.intellij.codeInsight.template.macro.MethodReturnTypeMacro;
|
||||
import com.intellij.codeInsight.template.macro.VariableOfTypeMacro;
|
||||
import com.intellij.modcommand.ActionContext;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.ModCommandExecutor;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl;
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.LanguageExtension;
|
||||
import com.intellij.lang.LanguageExtensionWithAny;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -23,7 +24,7 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
@NotNullByDefault
|
||||
public interface ModCompletionItemProvider {
|
||||
LanguageExtension<ModCompletionItemProvider> EP_NAME = new LanguageExtension<>("com.intellij.modcompletion.completionItemProvider");
|
||||
LanguageExtension<ModCompletionItemProvider> EP_NAME = new LanguageExtensionWithAny<>("com.intellij.modcompletion.completionItemProvider");
|
||||
|
||||
/**
|
||||
* Provide completion items for given context
|
||||
|
||||
@@ -4,8 +4,8 @@ package com.intellij.codeInsight.template.impl;
|
||||
|
||||
import com.intellij.codeInsight.template.Expression;
|
||||
import com.intellij.codeInsight.template.Template;
|
||||
import com.intellij.modcommand.ActionContext;
|
||||
import com.intellij.modcommand.ModCommand;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcommand.ModTemplateBuilder;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
@@ -397,8 +397,10 @@ public class TemplateImpl extends TemplateBase implements SchemeElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context context where the template should be executed
|
||||
* @return the {@link ModCommand}, which when executed will show the template like the current one.
|
||||
* Performs a template execution within ModCommand context. The template is not actually executed, but
|
||||
* contributes to {@link ModPsiUpdater} to form the final {@link ModCommand}.
|
||||
*
|
||||
* @param updater {@link ModPsiUpdater} to use.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public void update(@NotNull ModPsiUpdater updater, @NotNull TemplateStateProcessor processor) {
|
||||
|
||||
@@ -4798,7 +4798,6 @@ f:com.intellij.codeInsight.template.impl.InvokeTemplateAction
|
||||
f:com.intellij.codeInsight.template.impl.ListTemplatesHandler
|
||||
- com.intellij.codeInsight.CodeInsightActionHandler
|
||||
- <init>():V
|
||||
- s:filterTemplatesByPrefix(java.util.Collection,com.intellij.openapi.editor.Editor,I,Z,Z):java.util.Map
|
||||
- s:getCustomTemplatesLookupItems(com.intellij.openapi.editor.Editor,com.intellij.psi.PsiFile,I):com.intellij.util.containers.MultiMap
|
||||
- invoke(com.intellij.openapi.project.Project,com.intellij.openapi.editor.Editor,com.intellij.psi.PsiFile):V
|
||||
- s:showTemplatesLookup(com.intellij.openapi.project.Project,com.intellij.openapi.editor.Editor,java.util.Map):V
|
||||
|
||||
@@ -408,6 +408,8 @@ com.intellij.codeInsight.template.impl.DefaultLiveTemplatesProvider
|
||||
- sf:EP_NAME:com.intellij.openapi.extensions.ExtensionPointName
|
||||
- a:getDefaultLiveTemplateFiles():java.lang.String[]
|
||||
- a:getHiddenLiveTemplateFiles():java.lang.String[]
|
||||
f:com.intellij.codeInsight.template.impl.ListTemplatesHandler
|
||||
- s:filterTemplatesByPrefix(java.util.Collection,com.intellij.openapi.editor.Document,I,Z,Z):java.util.Map
|
||||
f:com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
||||
- s:updateTemplate(com.intellij.codeInsight.template.impl.TemplateImpl,com.intellij.modcommand.ModPsiUpdater):V
|
||||
com.intellij.codeInsight.template.postfix.templates.PostfixTemplateExpressionSelector
|
||||
|
||||
+8
-8
@@ -56,12 +56,13 @@ public final class ListTemplatesHandler implements CodeInsightActionHandler {
|
||||
public void invoke(final @NotNull Project project, final @NotNull Editor editor, @NotNull PsiFile psiFile) {
|
||||
EditorUtil.fillVirtualSpaceUntilCaret(editor);
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
|
||||
Document document = editor.getDocument();
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document);
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
List<TemplateImpl> applicableTemplates = TemplateManagerImpl.listApplicableTemplateWithInsertingDummyIdentifier(
|
||||
TemplateActionContext.expanding(psiFile, editor));
|
||||
|
||||
Map<TemplateImpl, String> matchingTemplates = filterTemplatesByPrefix(applicableTemplates, editor, offset, false, true);
|
||||
Map<TemplateImpl, String> matchingTemplates = filterTemplatesByPrefix(applicableTemplates, document, offset, false, true);
|
||||
MultiMap<String, CustomLiveTemplateLookupElement> customTemplatesLookupElements = getCustomTemplatesLookupItems(editor, psiFile, offset);
|
||||
|
||||
if (matchingTemplates.isEmpty()) {
|
||||
@@ -81,17 +82,16 @@ public final class ListTemplatesHandler implements CodeInsightActionHandler {
|
||||
}
|
||||
|
||||
public static @NotNull Map<TemplateImpl, String> filterTemplatesByPrefix(@NotNull Collection<? extends TemplateImpl> templates,
|
||||
@NotNull Editor editor,
|
||||
int offset,
|
||||
@NotNull Document document, int offset,
|
||||
boolean fullMatch,
|
||||
boolean searchInDescription) {
|
||||
if (offset > editor.getDocument().getTextLength()) {
|
||||
if (offset > document.getTextLength()) {
|
||||
LOG.error("Cannot filter templates, index out of bounds. Offset: " + offset,
|
||||
CoreAttachmentFactory.createAttachment(editor.getDocument()));
|
||||
CoreAttachmentFactory.createAttachment(document));
|
||||
}
|
||||
CharSequence documentText = editor.getDocument().getCharsSequence().subSequence(0, offset);
|
||||
CharSequence documentText = document.getCharsSequence().subSequence(0, offset);
|
||||
|
||||
String prefixWithoutDots = computeDescriptionMatchingPrefix(editor.getDocument(), offset);
|
||||
String prefixWithoutDots = computeDescriptionMatchingPrefix(document, offset);
|
||||
Pattern prefixSearchPattern = Pattern.compile(".*\\b" + prefixWithoutDots + ".*");
|
||||
|
||||
Map<TemplateImpl, String> matchingTemplates = new TreeMap<>(TemplateListPanel.TEMPLATE_COMPARATOR);
|
||||
|
||||
+4
-4
@@ -39,8 +39,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.intellij.codeInsight.template.impl.ListTemplatesHandler.filterTemplatesByPrefix;
|
||||
|
||||
public final class LiveTemplateCompletionContributor extends CompletionContributor implements DumbAware {
|
||||
private static final Key<Boolean> ourShowTemplatesInTests = Key.create("ShowTemplatesInTests");
|
||||
|
||||
@@ -79,7 +77,8 @@ public final class LiveTemplateCompletionContributor extends CompletionContribut
|
||||
Editor editor = parameters.getEditor();
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
List<TemplateImpl> availableTemplates = TemplateManagerImpl.listApplicableTemplates(TemplateActionContext.expanding(file, editor));
|
||||
Map<TemplateImpl, String> templates = filterTemplatesByPrefix(availableTemplates, editor, offset, false, false);
|
||||
Map<TemplateImpl, String> templates =
|
||||
ListTemplatesHandler.filterTemplatesByPrefix(availableTemplates, editor.getDocument(), offset, false, false);
|
||||
boolean isAutopopup = parameters.getInvocationCount() == 0;
|
||||
|
||||
AtomicBoolean templatesShown = new AtomicBoolean(false);
|
||||
@@ -155,7 +154,8 @@ public final class LiveTemplateCompletionContributor extends CompletionContribut
|
||||
public static @Nullable TemplateImpl findFullMatchedApplicableTemplate(@NotNull Editor editor,
|
||||
int offset,
|
||||
@NotNull Collection<? extends TemplateImpl> availableTemplates) {
|
||||
Map<TemplateImpl, String> templates = filterTemplatesByPrefix(availableTemplates, editor, offset, true, false);
|
||||
Map<TemplateImpl, String> templates =
|
||||
ListTemplatesHandler.filterTemplatesByPrefix(availableTemplates, editor.getDocument(), offset, true, false);
|
||||
if (templates.size() == 1) {
|
||||
TemplateImpl template = ContainerUtil.getFirstItem(templates.keySet());
|
||||
if (template != null) {
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.template.impl;
|
||||
|
||||
import com.intellij.codeInsight.template.TemplateActionContext;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.modcommand.ActionContext;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.modcompletion.ModCompletionItem;
|
||||
import com.intellij.modcompletion.ModCompletionItemPresentation;
|
||||
import com.intellij.modcompletion.ModCompletionItemProvider;
|
||||
import com.intellij.modcompletion.PsiUpdateCompletionItem;
|
||||
import com.intellij.openapi.util.text.MarkupText;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@NotNullByDefault
|
||||
final class LiveTemplateModCompletionItemProvider implements ModCompletionItemProvider {
|
||||
@Override
|
||||
public void provideItems(CompletionContext context, Consumer<ModCompletionItem> sink) {
|
||||
if (!LiveTemplateCompletionContributor.shouldShowAllTemplates()) return;
|
||||
PsiFile file = context.getPosition().getContainingFile();
|
||||
int offset = context.offset();
|
||||
List<TemplateImpl> availableTemplates = TemplateManagerImpl.listApplicableTemplates(
|
||||
TemplateActionContext.expanding(file, offset));
|
||||
Map<TemplateImpl, String> templates =
|
||||
ListTemplatesHandler.filterTemplatesByPrefix(availableTemplates, file.getFileDocument(), offset, false, false);
|
||||
for (Map.Entry<TemplateImpl, String> entry : templates.entrySet()) {
|
||||
sink.accept(new LiveTemplateModCompletionItem(entry.getKey()));
|
||||
}
|
||||
}
|
||||
|
||||
private static class LiveTemplateModCompletionItem extends PsiUpdateCompletionItem<TemplateImpl> {
|
||||
private LiveTemplateModCompletionItem(TemplateImpl template) {
|
||||
super(template.getKey(), template);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(ActionContext actionContext, InsertionContext insertionContext, ModPsiUpdater updater) {
|
||||
updater.getDocument().deleteString(actionContext.selection().getStartOffset(), actionContext.selection().getEndOffset());
|
||||
TemplateManagerImpl.updateTemplate(contextObject(), updater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModCompletionItemPresentation presentation() {
|
||||
String description = contextObject().getDescription();
|
||||
return new ModCompletionItemPresentation(MarkupText.plainText(contextObject().getKey()))
|
||||
.withMainIcon(() -> AllIcons.Nodes.Template)
|
||||
.withDetailText(description == null ? MarkupText.empty() : MarkupText.plainText(description));
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -64,8 +64,6 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static com.intellij.codeInsight.template.impl.ListTemplatesHandler.filterTemplatesByPrefix;
|
||||
|
||||
public final class TemplateManagerImpl extends TemplateManager implements Disposable {
|
||||
private final @NotNull Project myProject;
|
||||
private static final Key<Boolean> ourTemplateTesting = Key.create("TemplateTesting");
|
||||
@@ -599,7 +597,9 @@ public final class TemplateManagerImpl extends TemplateManager implements Dispos
|
||||
public static boolean isApplicableTemplatePresent(@NotNull PsiFile file, @NotNull Editor editor) {
|
||||
TemplateActionContext context = TemplateActionContext.expanding(file, editor);
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
Map<TemplateImpl, String> templates = filterTemplatesByPrefix(listApplicableTemplates(context), editor, offset, true, false);
|
||||
@NotNull Collection<? extends TemplateImpl> applicableTemplates = listApplicableTemplates(context);
|
||||
Map<TemplateImpl, String> templates =
|
||||
ListTemplatesHandler.filterTemplatesByPrefix(applicableTemplates, editor.getDocument(), offset, true, false);
|
||||
if (!templates.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -676,6 +676,10 @@
|
||||
implementationClass="com.intellij.codeInsight.completion.ReferenceBasedCompletionContributor"/>
|
||||
<completion.contributor language="any" id="commands" order="first, after liveTemplates"
|
||||
implementationClass="com.intellij.codeInsight.completion.command.CommandCompletionContributor"/>
|
||||
|
||||
<modcompletion.completionItemProvider language="any" implementationClass="com.intellij.codeInsight.template.impl.LiveTemplateModCompletionItemProvider"
|
||||
id="liveTemplates" order="first"/>
|
||||
|
||||
<codeCompletionConfigurable provider="com.intellij.codeInsight.completion.command.configuration.CommandCompletionConfigurableProvider"/>
|
||||
|
||||
<applicationService serviceImplementation="com.intellij.execution.console.ConsoleFoldingSettings"/>
|
||||
|
||||
Reference in New Issue
Block a user