ListTemplateAction should provide custom live templates

This commit is contained in:
Alexander Zolotov
2013-12-23 17:45:27 +04:00
parent 60a5c6086f
commit 544d21fd9a
25 changed files with 409 additions and 156 deletions

View File

@@ -15,27 +15,23 @@
*/
package com.intellij.codeInsight.template.postfix.completion;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.impl.LiveTemplateLookupElement;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import com.intellij.codeInsight.template.impl.CustomLiveTemplateLookupElement;
import com.intellij.codeInsight.template.postfix.templates.PostfixLiveTemplate;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import static com.intellij.codeInsight.template.postfix.completion.PostfixTemplateCompletionContributor.getPostfixLiveTemplate;
class PostfixTemplateLookupElement extends LiveTemplateLookupElement {
@NotNull
public class PostfixTemplateLookupElement extends CustomLiveTemplateLookupElement {
@NotNull
private final PostfixTemplate myTemplate;
public PostfixTemplateLookupElement(@NotNull PostfixTemplate template, char shortcut) {
super(createStubTemplate(template, shortcut), template.getPresentableName(), true, true);
myTemplate = template;
public PostfixTemplateLookupElement(@NotNull PostfixLiveTemplate liveTemplate,
@NotNull PostfixTemplate postfixTemplate,
@NotNull String templateKey,
boolean sudden) {
super(liveTemplate, templateKey, postfixTemplate.getPresentableName(), postfixTemplate.getDescription(), sudden, true);
myTemplate = postfixTemplate;
}
@NotNull
@@ -46,35 +42,15 @@ class PostfixTemplateLookupElement extends LiveTemplateLookupElement {
@Override
public void renderElement(LookupElementPresentation presentation) {
super.renderElement(presentation);
presentation.setTailText(" " + arrow() + " " + myTemplate.getExample());
}
@Override
public void handleInsert(InsertionContext context) {
context.setAddCompletionChar(false);
int lengthOfTypedKey = context.getTailOffset() - context.getStartOffset();
String templateKey = myTemplate.getKey();
Editor editor = context.getEditor();
if (lengthOfTypedKey < templateKey.length()) {
context.getDocument().insertString(context.getTailOffset(), templateKey.substring(lengthOfTypedKey));
editor.getCaretModel().moveToOffset(context.getTailOffset() + templateKey.length() - lengthOfTypedKey);
if (sudden) {
presentation.setTailText(" " + arrow() + " " + myTemplate.getExample());
}
PsiFile file = context.getFile();
PostfixLiveTemplate postfixLiveTemplate = getPostfixLiveTemplate(context.getFile(), context.getEditor());
if (postfixLiveTemplate != null) {
postfixLiveTemplate.expand(templateKey, new CustomTemplateCallback(editor, file, false));
else {
presentation.setTypeText(myTemplate.getExample());
}
}
private static TemplateImpl createStubTemplate(@NotNull PostfixTemplate postfixTemplate, char shortcut) {
TemplateImpl template = new TemplateImpl(postfixTemplate.getKey(), "postfixTemplate");
template.setShortcutChar(shortcut);
return template;
}
private static String arrow() {
return SystemInfo.isMac ? "" :"->";
return SystemInfo.isMac ? "" : "->";
}
}

View File

@@ -46,7 +46,7 @@ class PostfixTemplatesCompletionProvider extends CompletionProvider<CompletionPa
PostfixTemplate template = postfixLiveTemplate.getTemplateByKey(computedKey);
if (template != null) {
result = result.withPrefixMatcher(computedKey);
result.addElement(new PostfixTemplateLookupElement(template, postfixLiveTemplate.getShortcut()));
result.addElement(new PostfixTemplateLookupElement(postfixLiveTemplate, template, computedKey, true));
}
}

View File

@@ -20,7 +20,9 @@ import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.JavaCompletionContributor;
import com.intellij.codeInsight.template.CustomLiveTemplateBase;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.impl.CustomLiveTemplateLookupElement;
import com.intellij.codeInsight.template.impl.TemplateSettings;
import com.intellij.codeInsight.template.postfix.completion.PostfixTemplateLookupElement;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings;
import com.intellij.codeInsight.template.postfix.util.Aliases;
import com.intellij.lang.java.JavaLanguage;
@@ -30,6 +32,7 @@ import com.intellij.openapi.command.undo.UndoConstants;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -43,7 +46,9 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class PostfixLiveTemplate extends CustomLiveTemplateBase {
public static final String POSTFIX_TEMPLATE_ID = "POSTFIX_TEMPLATE_ID";
@@ -79,6 +84,13 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
return isApplicableTemplate(getTemplateByKey(key), key, callback.getContext().getContainingFile(), editor) ? key : null;
}
@Nullable
@Override
public String computeTemplateKeyWithoutContextChecking(@NotNull CustomTemplateCallback callback) {
Editor editor = callback.getEditor();
return computeTemplateKeyWithoutContextChecking(editor.getDocument().getCharsSequence(), editor.getCaretModel().getOffset());
}
@Nullable
public String computeTemplateKeyWithoutContextChecking(@NotNull CharSequence documentContent, int currentOffset) {
int startOffset = currentOffset;
@@ -151,6 +163,24 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
return true;
}
@NotNull
@Override
public Collection<? extends CustomLiveTemplateLookupElement> getLookupElements(@NotNull PsiFile file, @NotNull Editor editor, int offset) {
String key = computeTemplateKeyWithoutContextChecking(editor.getDocument().getCharsSequence(), offset);
if (key != null) {
Map<String, CustomLiveTemplateLookupElement> result = ContainerUtil.newHashMap();
Condition<PostfixTemplate> isApplicationTemplateFunction = createIsApplicationTemplateFunction(key, file, editor);
for (Map.Entry<String, PostfixTemplate> entry : myTemplates.entrySet()) {
PostfixTemplate postfixTemplate = entry.getValue();
if (entry.getKey().startsWith(key) && isApplicationTemplateFunction.value(postfixTemplate)) {
result.put(postfixTemplate.getKey(), new PostfixTemplateLookupElement(this, postfixTemplate, postfixTemplate.getKey(), false));
}
}
return result.values();
}
return super.getLookupElements(file, editor, offset);
}
@Nullable
public PostfixTemplate getTemplateByKey(@NotNull String key) {
return myTemplates.get(key);
@@ -173,12 +203,12 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
@Contract("null, _, _, _ -> false")
private static boolean isApplicableTemplate(@Nullable PostfixTemplate template, @NotNull String key, @NotNull PsiFile file, @NotNull Editor editor) {
if (template == null || !template.isEnabled()) {
return false;
}
return createIsApplicationTemplateFunction(key, file, editor).value(template);
}
private static Condition<PostfixTemplate> createIsApplicationTemplateFunction(@NotNull String key, @NotNull PsiFile file, @NotNull Editor editor) {
int currentOffset = editor.getCaretModel().getOffset();
int newOffset = currentOffset - key.length();
final int newOffset = currentOffset - key.length();
CharSequence fileContent = editor.getDocument().getCharsSequence();
StringBuilder fileContentWithoutKey = new StringBuilder();
@@ -187,7 +217,8 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
PsiFile copyFile = copyFile(file, fileContentWithoutKey);
Document copyDocument = copyFile.getViewProvider().getDocument();
if (copyDocument == null) {
return false;
//noinspection unchecked
return Condition.FALSE;
}
if (isSemicolonNeeded(copyFile, editor)) {
@@ -195,12 +226,19 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
copyFile = copyFile(file, fileContentWithoutKey);
copyDocument = copyFile.getViewProvider().getDocument();
if (copyDocument == null) {
return false;
//noinspection unchecked
return Condition.FALSE;
}
}
PsiElement context = CustomTemplateCallback.getContext(copyFile, newOffset > 0 ? newOffset - 1 : newOffset);
return template.isApplicable(context, copyDocument, newOffset);
final PsiElement context = CustomTemplateCallback.getContext(copyFile, newOffset > 0 ? newOffset - 1 : newOffset);
final Document finalCopyDocument = copyDocument;
return new Condition<PostfixTemplate>() {
@Override
public boolean value(PostfixTemplate template) {
return template != null && template.isEnabled() && template.isApplicable(context, finalCopyDocument, newOffset);
}
};
}
@NotNull

View File

@@ -0,0 +1,7 @@
import java.lang.Object;
public class Foo {
void m() {
new Object().<caret>
}
}

View File

@@ -0,0 +1,5 @@
class A {
void test() {
true.<caret>
}
}

View File

@@ -0,0 +1,5 @@
class A {
void test() {
true.no<caret>
}
}

View File

@@ -0,0 +1,5 @@
class A {
void test() {
false<caret>
}
}

View File

@@ -0,0 +1,5 @@
class A {
void test() {
false<caret>
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.template.postfix.completion;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.template.impl.ListTemplatesHandler;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
public class ListTemplatesActionTest extends LightCodeInsightFixtureTestCase {
public void testListTemplates() {
doTest();
}
public void testListTemplatesWithPrefix() {
doTest();
}
private void doTest() {
myFixture.configureByFile(getTestName(true) + ".java");
new ListTemplatesHandler().invoke(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile());
LookupElement[] elements = myFixture.getLookupElements();
assertNotNull(elements);
LookupElement targetElement = null;
for (LookupElement element : elements) {
if (element.getLookupString().equals(".not")) {
targetElement = element;
}
}
assertNotNull(targetElement);
myFixture.getLookup().setCurrentItem(targetElement);
myFixture.finishLookup(Lookup.NORMAL_SELECT_CHAR);
myFixture.checkResultByFile(getTestName(true) + "_after.java");
}
@Override
protected String getBasePath() {
return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/template/postfix/listTemplates";
}
}

View File

@@ -21,6 +21,7 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings;
import com.intellij.codeInsight.template.postfix.templates.InstanceofExpressionPostfixTemplate;
import com.intellij.codeInsight.template.postfix.templates.NotNullCheckPostfixTemplate;
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
import com.intellij.codeInsight.template.postfix.templates.SwitchStatementPostfixTemplate;
import com.intellij.util.containers.ContainerUtil;
@@ -36,6 +37,10 @@ public class TemplatesCompletionTest extends CompletionAutoPopupTestCase {
doAutoPopupTest("instanceof", InstanceofExpressionPostfixTemplate.class);
}
public void testShowAutoPopupForAliases() {
doAutoPopupTest("nn", NotNullCheckPostfixTemplate.class);
}
public void testDoNotShowTemplateIfPluginIsDisabled() {
PostfixTemplatesSettings settings = PostfixTemplatesSettings.getInstance();
assertNotNull(settings);

View File

@@ -150,7 +150,7 @@ public abstract class ChooseItemAction extends EditorAction {
return false;
}
return TemplateSettings.getInstance().getShortcutChar(liveTemplateLookup.getTemplate()) == shortcutChar;
return liveTemplateLookup.getTemplateShortcut() == shortcutChar;
}
public static class Always extends ChooseItemAction {

View File

@@ -15,8 +15,14 @@
*/
package com.intellij.codeInsight.template;
import com.intellij.codeInsight.template.impl.CustomLiveTemplateLookupElement;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
abstract public class CustomLiveTemplateBase implements CustomLiveTemplate {
/**
@@ -26,4 +32,17 @@ abstract public class CustomLiveTemplateBase implements CustomLiveTemplate {
public boolean hasCompletionItem(@NotNull PsiFile file, int offset) {
return false;
}
/**
* Return lookup elements for popup that appears on ListTemplateAction (Ctrl + J)
*/
@NotNull
public Collection<? extends CustomLiveTemplateLookupElement> getLookupElements(@NotNull PsiFile file, @NotNull Editor editor, int offset) {
return Collections.emptyList();
}
@Nullable
public String computeTemplateKeyWithoutContextChecking(@NotNull CustomTemplateCallback callback) {
return computeTemplateKey(callback);
}
}

View File

@@ -47,7 +47,7 @@ public class CustomTemplateCallback {
private FileType myFileType;
public CustomTemplateCallback(Editor editor, PsiFile file, boolean wrapping) {
public CustomTemplateCallback(@NotNull Editor editor, @NotNull PsiFile file, boolean wrapping) {
myProject = file.getProject();
myTemplateManager = TemplateManager.getInstance(myProject);

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.template.impl;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.template.CustomLiveTemplateBase;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CustomLiveTemplateLookupElement extends LiveTemplateLookupElement {
@NotNull private final CustomLiveTemplateBase myCustomLiveTemplate;
@NotNull private final String myTemplateKey;
@NotNull private final String myItemText;
public CustomLiveTemplateLookupElement(@NotNull CustomLiveTemplateBase customLiveTemplate,
@NotNull String templateKey,
@NotNull String itemText,
@Nullable String description,
boolean sudden,
boolean worthShowingInAutoPopup) {
super(templateKey, description, sudden, worthShowingInAutoPopup);
myCustomLiveTemplate = customLiveTemplate;
myTemplateKey = templateKey;
myItemText = itemText;
}
@NotNull
@Override
protected String getItemText() {
return myItemText;
}
@NotNull
public CustomLiveTemplateBase getCustomLiveTemplate() {
return myCustomLiveTemplate;
}
@Override
public char getTemplateShortcut() {
return myCustomLiveTemplate.getShortcut();
}
@Override
public void handleInsert(InsertionContext context) {
context.setAddCompletionChar(false);
expandTemplate(context.getEditor(), context.getFile());
}
public void expandTemplate(@NotNull Editor editor, @NotNull PsiFile file) {
myCustomLiveTemplate.expand(myTemplateKey, new CustomTemplateCallback(editor, file, false));
}
}

View File

@@ -23,6 +23,9 @@ import com.intellij.codeInsight.completion.PlainPrefixMatcher;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.lookup.*;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.codeInsight.template.CustomLiveTemplate;
import com.intellij.codeInsight.template.CustomLiveTemplateBase;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.openapi.application.Result;
@@ -61,18 +64,25 @@ public class ListTemplatesHandler implements CodeInsightActionHandler {
final Pattern prefixSearchPattern = Pattern.compile(".*\\b" + prefixWithoutDots + ".*");
for (TemplateImpl template : applicableTemplates) {
final String templateDescription = template.getDescription();
if (template.getKey().startsWith(prefix) ||
if (template.getKey().startsWith(prefix) ||
!prefixWithoutDots.isEmpty() && templateDescription != null && prefixSearchPattern.matcher(templateDescription).matches()) {
matchingTemplates.add(template);
}
}
List<CustomLiveTemplateLookupElement> customTemplatesLookupElements = ContainerUtil.newArrayList();
for (CustomLiveTemplate customLiveTemplate : CustomLiveTemplate.EP_NAME.getExtensions()) {
if (customLiveTemplate instanceof CustomLiveTemplateBase && TemplateManagerImpl.isApplicable(customLiveTemplate, editor, file)) {
customTemplatesLookupElements.addAll(((CustomLiveTemplateBase)customLiveTemplate).getLookupElements(file, editor, offset));
}
}
if (matchingTemplates.isEmpty()) {
matchingTemplates.addAll(applicableTemplates);
prefixWithoutDots = "";
}
if (matchingTemplates.size() == 0) {
if (matchingTemplates.isEmpty() && customTemplatesLookupElements.isEmpty()) {
String text = prefixWithoutDots.length() == 0
? CodeInsightBundle.message("templates.no.defined")
: CodeInsightBundle.message("templates.no.defined.with.prefix", prefix);
@@ -81,23 +91,33 @@ public class ListTemplatesHandler implements CodeInsightActionHandler {
}
Collections.sort(matchingTemplates, TemplateListPanel.TEMPLATE_COMPARATOR);
showTemplatesLookup(project, editor, prefixWithoutDots, matchingTemplates);
showTemplatesLookup(project, editor, file, prefixWithoutDots, matchingTemplates, customTemplatesLookupElements);
}
public static void showTemplatesLookup(final Project project, final Editor editor,
@NotNull String prefix, List<TemplateImpl> matchingTemplates) {
private static void showTemplatesLookup(final Project project,
final Editor editor,
final PsiFile file,
@NotNull String prefix,
@NotNull List<TemplateImpl> matchingTemplates,
@NotNull List<CustomLiveTemplateLookupElement> customTemplatesLookupElements) {
final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(project).createLookup(editor, LookupElement.EMPTY_ARRAY, prefix,
new TemplatesArranger());
for (TemplateImpl template : matchingTemplates) {
lookup.addItem(createTemplateElement(template), new PlainPrefixMatcher(prefix));
}
showLookup(lookup, null);
CustomTemplateCallback customTemplateCallback = new CustomTemplateCallback(editor, file, false);
for (CustomLiveTemplateLookupElement element : customTemplatesLookupElements) {
String customTemplatePrefix = element.getCustomLiveTemplate().computeTemplateKeyWithoutContextChecking(customTemplateCallback);
lookup.addItem(element, new PlainPrefixMatcher(customTemplatePrefix));
}
showLookup(lookup, file);
}
private static LiveTemplateLookupElement createTemplateElement(final TemplateImpl template) {
return new LiveTemplateLookupElement(template, false) {
return new LiveTemplateLookupElementImpl(template, false) {
@Override
public Set<String> getAllLookupStrings() {
String description = template.getDescription();
@@ -139,6 +159,14 @@ public class ListTemplatesHandler implements CodeInsightActionHandler {
lookup.showLookup();
}
private static void showLookup(LookupImpl lookup, @NotNull PsiFile file) {
Editor editor = lookup.getEditor();
Project project = editor.getProject();
lookup.addLookupListener(new MyLookupAdapter(project, editor, file));
lookup.refreshUi(false, true);
lookup.showLookup();
}
@Override
public boolean startInWriteAction() {
return true;
@@ -160,26 +188,48 @@ public class ListTemplatesHandler implements CodeInsightActionHandler {
private final Project myProject;
private final Editor myEditor;
private final Map<TemplateImpl, String> myTemplate2Argument;
private final PsiFile myFile;
public MyLookupAdapter(Project project, Editor editor, Map<TemplateImpl, String> template2Argument) {
public MyLookupAdapter(Project project, Editor editor, @Nullable Map<TemplateImpl, String> template2Argument) {
myProject = project;
myEditor = editor;
myTemplate2Argument = template2Argument;
myFile = null;
}
public MyLookupAdapter(Project project, Editor editor, @Nullable PsiFile file) {
myProject = project;
myEditor = editor;
myTemplate2Argument = null;
myFile = file;
}
@Override
public void itemSelected(LookupEvent event) {
public void itemSelected(final LookupEvent event) {
FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.liveTemplates");
LookupElement item = event.getItem();
if (item instanceof LiveTemplateLookupElement) {
final TemplateImpl template = ((LiveTemplateLookupElement)item).getTemplate();
final String argument = myTemplate2Argument != null ? myTemplate2Argument.get(template) : null;
new WriteCommandAction(myProject) {
@Override
protected void run(Result result) throws Throwable {
((TemplateManagerImpl)TemplateManager.getInstance(myProject)).startTemplateWithPrefix(myEditor, template, null, argument);
}
}.execute();
final LookupElement item = event.getItem();
if (item instanceof LiveTemplateLookupElementImpl) {
final TemplateImpl template = ((LiveTemplateLookupElementImpl)item).getTemplate();
final String argument;
if (myTemplate2Argument != null) {
argument = myTemplate2Argument.get(template);
new WriteCommandAction(myProject) {
@Override
protected void run(@NotNull Result result) throws Throwable {
((TemplateManagerImpl)TemplateManager.getInstance(myProject)).startTemplateWithPrefix(myEditor, template, null, argument);
}
}.execute();
}
}
else if (item instanceof CustomLiveTemplateLookupElement) {
if (myFile != null) {
new WriteCommandAction(myProject) {
@Override
protected void run(@NotNull Result result) throws Throwable {
((CustomLiveTemplateLookupElement)item).expandTemplate(myEditor, myFile);
}
}.execute();
}
}
}
}
@@ -205,6 +255,5 @@ public class ListTemplatesHandler implements CodeInsightActionHandler {
public LookupArranger createEmptyCopy() {
return new TemplatesArranger();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ public class LiveTemplateCharFilter extends CharFilter {
if (item instanceof LiveTemplateLookupElement && lookup.isCompletion()) {
if (Character.isJavaIdentifierPart(c)) return Result.ADD_TO_PREFIX;
if (c == ((LiveTemplateLookupElement)item).getTemplate().getShortcutChar()) {
if (c == ((LiveTemplateLookupElement)item).getTemplateShortcut()) {
return Result.SELECT_ITEM_AND_FINISH_LOOKUP;
}
return Result.HIDE_LOOKUP;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,7 +71,7 @@ public class LiveTemplateCompletionContributor extends CompletionContributor {
final TemplateImpl template = findApplicableTemplate(file, offset, templatePrefix);
if (template != null) {
result = result.withPrefixMatcher(template.getKey());
result.addElement(new LiveTemplateLookupElement(template, true));
result.addElement(new LiveTemplateLookupElementImpl(template, true));
}
for (final TemplateImpl possible : templates) {
result.restartCompletionOnPrefixChange(possible.getKey());
@@ -90,7 +90,7 @@ public class LiveTemplateCompletionContributor extends CompletionContributor {
if (!templatesShown.get()) {
templatesShown.set(true);
for (final TemplateImpl possible : templates) {
result.addElement(new LiveTemplateLookupElement(possible, false));
result.addElement(new LiveTemplateLookupElementImpl(possible, false));
}
}
}

View File

@@ -31,8 +31,8 @@ import javax.swing.*;
public class LiveTemplateDocumentationProvider extends AbstractDocumentationProvider {
@Override
public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) {
if (object instanceof LiveTemplateLookupElement) {
TemplateImpl template = ((LiveTemplateLookupElement)object).getTemplate();
if (object instanceof LiveTemplateLookupElementImpl) {
TemplateImpl template = ((LiveTemplateLookupElementImpl)object).getTemplate();
final TemplateImpl templateFromSettings = TemplateSettings.getInstance().getTemplate(template.getKey(), template.getGroupName());
if (templateFromSettings != null) {
return new LiveTemplateElement(templateFromSettings, psiManager);

View File

@@ -32,8 +32,8 @@ import com.intellij.util.PlatformIcons;
public class LiveTemplateLookupActionProvider implements LookupActionProvider {
@Override
public void fillActions(LookupElement element, final Lookup lookup, Consumer<LookupElementAction> consumer) {
if (element instanceof LiveTemplateLookupElement) {
final TemplateImpl template = ((LiveTemplateLookupElement)element).getTemplate();
if (element instanceof LiveTemplateLookupElementImpl) {
final TemplateImpl template = ((LiveTemplateLookupElementImpl)element).getTemplate();
final TemplateImpl templateFromSettings = TemplateSettings.getInstance().getTemplate(template.getKey(), template.getGroupName());
if (templateFromSettings != null) {

View File

@@ -15,12 +15,9 @@
*/
package com.intellij.codeInsight.template.impl;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.codeInsight.lookup.RealLookupElementPresentation;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,66 +26,54 @@ import java.awt.event.KeyEvent;
/**
* @author peter
*/
public class LiveTemplateLookupElement extends LookupElement {
private final String myPrefix;
@NotNull private final TemplateImpl myTemplate;
abstract public class LiveTemplateLookupElement extends LookupElement {
private final String myLookupString;
public final boolean sudden;
private final boolean myWorthShowingInAutoPopup;
private final String myDescription;
public LiveTemplateLookupElement(@NotNull TemplateImpl template, boolean sudden) {
this(template, null, sudden, false);
}
public LiveTemplateLookupElement(@NotNull TemplateImpl template, @Nullable String lookupString, boolean sudden, boolean worthShowingInAutoPopup) {
public LiveTemplateLookupElement(@NotNull String lookupString, @Nullable String description, boolean sudden, boolean worthShowingInAutoPopup) {
myDescription = description;
this.sudden = sudden;
myLookupString = lookupString;
myPrefix = template.getKey();
myTemplate = template;
myWorthShowingInAutoPopup = worthShowingInAutoPopup;
}
@NotNull
@Override
public String getLookupString() {
return myPrefix;
return myLookupString;
}
@NotNull
public TemplateImpl getTemplate() {
return myTemplate;
protected String getItemText() {
return myLookupString;
}
@Override
public void renderElement(LookupElementPresentation presentation) {
super.renderElement(presentation);
presentation.setItemText(StringUtil.notNullize(myLookupString, myPrefix));
char shortcut = getTemplateShortcut();
presentation.setItemText(getItemText());
if (sudden) {
presentation.setItemTextBold(true);
if (!presentation.isReal() || !((RealLookupElementPresentation)presentation).isLookupSelectionTouched()) {
char shortcutChar = myTemplate.getShortcutChar();
if (shortcutChar == TemplateSettings.DEFAULT_CHAR) {
shortcutChar = TemplateSettings.getInstance().getDefaultShortcutChar();
if (shortcut == TemplateSettings.DEFAULT_CHAR) {
shortcut = TemplateSettings.getInstance().getDefaultShortcutChar();
}
presentation.setTypeText(" [" + KeyEvent.getKeyText(shortcutChar) + "] ");
presentation.setTypeText(" [" + KeyEvent.getKeyText(shortcut) + "] ");
}
String description = myTemplate.getDescription();
if (description != null) {
presentation.setTailText(" (" + description + ")", true);
}
} else {
presentation.setTypeText(myTemplate.getDescription());
presentation.setTailText(" (" + myDescription + ")", true);
}
else {
presentation.setTypeText(myDescription);
}
}
@Override
public void handleInsert(InsertionContext context) {
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
context.setAddCompletionChar(false);
TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), myTemplate);
}
@Override
public boolean isWorthShowingInAutoPopup() {
return myWorthShowingInAutoPopup;
}
public abstract char getTemplateShortcut();
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.template.impl;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
public class LiveTemplateLookupElementImpl extends LiveTemplateLookupElement {
private final TemplateImpl myTemplate;
public LiveTemplateLookupElementImpl(@NotNull TemplateImpl template, boolean sudden) {
super(template.getKey(), StringUtil.notNullize(template.getDescription()), sudden, false);
myTemplate = template;
}
@NotNull
@Override
public String getLookupString() {
return myTemplate.getKey();
}
@NotNull
public TemplateImpl getTemplate() {
return myTemplate;
}
@Override
public char getTemplateShortcut() {
return TemplateSettings.getInstance().getShortcutChar(myTemplate);
}
@Override
public void handleInsert(InsertionContext context) {
context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset());
context.setAddCompletionChar(false);
TemplateManager.getInstance(context.getProject()).startTemplate(context.getEditor(), myTemplate);
}
}

View File

@@ -18,12 +18,11 @@ package com.intellij.codeInsight.template.emmet.completion;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionProvider;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.template.CustomTemplateCallback;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateEditingListener;
import com.intellij.codeInsight.template.*;
import com.intellij.codeInsight.template.emmet.ZenCodingTemplate;
import com.intellij.codeInsight.template.emmet.filters.SingleLineEmmetFilter;
import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
import com.intellij.codeInsight.template.impl.CustomLiveTemplateLookupElement;
import com.intellij.codeInsight.template.impl.LiveTemplateCompletionContributor;
import com.intellij.codeInsight.template.impl.LiveTemplateLookupElement;
import com.intellij.codeInsight.template.impl.TemplateImpl;
@@ -56,6 +55,11 @@ abstract public class EmmetAbbreviationCompletionProvider extends CompletionProv
return;
}
ZenCodingTemplate zenCodingTemplate = CustomLiveTemplate.EP_NAME.findExtension(ZenCodingTemplate.class);
if (zenCodingTemplate == null) {
return;
}
final PsiFile file = parameters.getPosition().getContainingFile();
final Editor editor = parameters.getEditor();
@@ -89,13 +93,13 @@ abstract public class EmmetAbbreviationCompletionProvider extends CompletionProv
final TemplateImpl template = generatedTemplate.get();
template.setKey(templatePrefix);
template.setDescription(template.getTemplateText());
result.addElement(createLookupElement(template));
result.addElement(createLookupElement(zenCodingTemplate, template));
result.restartCompletionOnPrefixChange(StandardPatterns.string().startsWith(templatePrefix));
}
}
protected LiveTemplateLookupElement createLookupElement(TemplateImpl template) {
return new EmmetAbbreviationLookupElement(template, null, true);
protected LiveTemplateLookupElement createLookupElement(@NotNull CustomLiveTemplateBase customLiveTemplate, @NotNull TemplateImpl template) {
return new CustomLiveTemplateLookupElement(customLiveTemplate, template.getKey(), template.getKey(), template.getDescription(), true, true);
}
protected abstract ZenCodingGenerator getGenerator();

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.template.emmet.completion;
import com.intellij.codeInsight.template.impl.LiveTemplateLookupElement;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class EmmetAbbreviationLookupElement extends LiveTemplateLookupElement {
public EmmetAbbreviationLookupElement(@NotNull TemplateImpl template, @Nullable String lookupString, boolean sudden) {
super(template, lookupString, sudden, true);
}
}

View File

@@ -21,6 +21,8 @@ import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupActionProvider;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementAction;
import com.intellij.codeInsight.template.emmet.ZenCodingTemplate;
import com.intellij.codeInsight.template.impl.CustomLiveTemplateLookupElement;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.options.ShowSettingsUtil;
@@ -31,7 +33,8 @@ import com.intellij.util.PlatformIcons;
public class EmmetLookupActionProvider implements LookupActionProvider {
@Override
public void fillActions(LookupElement element, final Lookup lookup, Consumer<LookupElementAction> consumer) {
if (element instanceof EmmetAbbreviationLookupElement) {
if (element instanceof CustomLiveTemplateLookupElement &&
((CustomLiveTemplateLookupElement)element).getCustomLiveTemplate() instanceof ZenCodingTemplate) {
consumer.consume(new LookupElementAction(PlatformIcons.EDIT, "Edit Emmet settings") {
@Override
public Result performLookupAction() {

View File

@@ -17,15 +17,14 @@ package com.intellij.codeInsight.template.emmet.completion;
import com.intellij.application.options.emmet.EmmetOptions;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.template.CustomLiveTemplateBase;
import com.intellij.codeInsight.template.emmet.generators.XmlZenCodingGeneratorImpl;
import com.intellij.codeInsight.template.emmet.generators.ZenCodingGenerator;
import com.intellij.codeInsight.template.impl.CustomLiveTemplateLookupElement;
import com.intellij.codeInsight.template.impl.LiveTemplateLookupElement;
import com.intellij.codeInsight.template.impl.TemplateImpl;
import org.jetbrains.annotations.NotNull;
/**
* User: zolotov
* Date: 8/9/13
*/
public class XmlEmmetAbbreviationCompletionProvider extends EmmetAbbreviationCompletionProvider {
@Override
protected boolean isAvailable(CompletionParameters parameters) {
@@ -34,10 +33,8 @@ public class XmlEmmetAbbreviationCompletionProvider extends EmmetAbbreviationCom
}
@Override
protected LiveTemplateLookupElement createLookupElement(final TemplateImpl template) {
final String description = template.getDescription();
template.setDescription(null);
return new EmmetAbbreviationLookupElement(template, description, false);
protected LiveTemplateLookupElement createLookupElement(@NotNull CustomLiveTemplateBase customLiveTemplate, @NotNull final TemplateImpl template) {
return new CustomLiveTemplateLookupElement(customLiveTemplate, template.getKey(), template.getDescription(), "", false, true);
}
@Override