protected void doOKAction() {
String key = myKeyField.getText().trim();
+ final String newGroup = (String)myGroupCombo.getSelectedItem();
+
for (TemplateGroup templateGroup : myTemplateGroups) {
- for (TemplateImpl template : templateGroup.getElements()) {
- if (template.getKey().equals(key) && myTemplate != template) {
- Messages.showMessageDialog(
- getContentPane(),
- CodeInsightBundle.message("dialog.edit.template.error.already.exists", key, template.getGroupName()),
- CodeInsightBundle.message("dialog.edit.template.error.title"),
- Messages.getErrorIcon()
- );
- return;
+ if (templateGroup.getName().equals(newGroup)) {
+ for (TemplateImpl template : templateGroup.getElements()) {
+ if (template.getKey().equals(key) && myTemplate != template) {
+ Messages.showMessageDialog(getContentPane(),
+ CodeInsightBundle.message("dialog.edit.template.error.already.exists", key, template.getGroupName()),
+ CodeInsightBundle.message("dialog.edit.template.error.title"), Messages.getErrorIcon());
+ return;
+ }
}
}
-
}
if (!TemplateImplUtil.validateTemplateText(myTemplateEditor.getDocument().getText())) {
}
SchemesManager<TemplateGroup, TemplateGroup> schemesManager = TemplateSettings.getInstance().getSchemesManager();
- TemplateGroup group = schemesManager.findSchemeByName((String)myGroupCombo.getSelectedItem());
+ TemplateGroup group = schemesManager.findSchemeByName(newGroup);
if (group != null && schemesManager.isShared(group)) {
Messages.showMessageDialog (
getContentPane(),
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
+import java.util.List;
public class ListTemplatesHandler implements CodeInsightActionHandler{
public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file) {
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
int offset = editor.getCaretModel().getOffset();
String prefix = getPrefix(editor.getDocument(), offset);
-
- ArrayList<LookupItem> array = new ArrayList<LookupItem>();
+
+ List<TemplateImpl> matchingTemplates = new ArrayList<TemplateImpl>();
for (TemplateImpl template : SurroundWithTemplateHandler.getApplicableTemplates(editor, file, false)) {
- String key = template.getKey();
- if (key.startsWith(prefix)) {
- array.add(new LookupItem(template, key));
+ if (template.getKey().startsWith(prefix)) {
+ matchingTemplates.add(template);
}
}
- LookupElement[] items = array.toArray(new LookupElement[array.size()]);
-
- if (items.length == 0){
+
+ if (matchingTemplates.size() == 0) {
String text = prefix.length() == 0
? CodeInsightBundle.message("templates.no.defined")
: CodeInsightBundle.message("templates.no.defined.with.prefix", prefix);
return;
}
+ showTemplatesLookup(project, editor, prefix, matchingTemplates);
+ }
+
+ public static void showTemplatesLookup(final Project project, final Editor editor, String prefix, List<TemplateImpl> matchingTemplates) {
+ ArrayList<LookupItem> array = new ArrayList<LookupItem>();
+ for (TemplateImpl template: matchingTemplates) {
+ array.add(new LookupItem(template, template.getKey()));
+ }
+ LookupElement[] items = array.toArray(new LookupElement[array.size()]);
+
final LookupImpl lookup = (LookupImpl) LookupManager.getInstance(project).createLookup(editor, items, prefix, LookupArranger.DEFAULT);
lookup.addLookupListener(
new LookupAdapter() {
public void itemSelected(LookupEvent event) {
+ final TemplateImpl template = (TemplateImpl)event.getItem().getObject();
new WriteCommandAction(project) {
protected void run(Result result) throws Throwable {
- TemplateManager.getInstance(project).startTemplate(editor, '\0');
+ ((TemplateManagerImpl) TemplateManager.getInstance(project)).startTemplateWithPrefix(editor, template, null);
}
}.execute();
}
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
public class TemplateManagerImpl extends TemplateManager implements ProjectComponent {
protected Project myProject;
}
public boolean startTemplate(@NotNull Editor editor, char shortcutChar) {
- return startTemplate(this, editor, shortcutChar, null);
+ return startTemplate(editor, shortcutChar, null);
}
public void startTemplate(@NotNull final Editor editor, @NotNull Template template) {
startTemplate(editor, null, template, listener, null);
}
- public boolean startTemplate(TemplateManagerImpl templateManager, final Editor editor, char shortcutChar) {
- return startTemplate(templateManager, editor, shortcutChar, null);
- }
-
- public boolean startTemplate(TemplateManagerImpl templateManager, final Editor editor, char shortcutChar, final PairProcessor<String, String> processor) {
+ public boolean startTemplate(final Editor editor, char shortcutChar, final PairProcessor<String, String> processor) {
final Document document = editor.getDocument();
PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject);
if (file == null) return false;
TemplateSettings templateSettings = TemplateSettings.getInstance();
CharSequence text = document.getCharsSequence();
final int caretOffset = editor.getCaretModel().getOffset();
- TemplateImpl template = null;
- int wordStart = 0;
+ String key = null;
+ List<TemplateImpl> candidates = Collections.emptyList();
for (int i = templateSettings.getMaxKeyLength(); i >= 1 ; i--) {
- wordStart = caretOffset - i;
+ int wordStart = caretOffset - i;
if (wordStart < 0) {
continue;
}
- String key = text.subSequence(wordStart, caretOffset).toString();
- template = templateSettings.getTemplate(key);
- if (template != null && template.isDeactivated()) {
- template = null;
- }
- if (template != null) {
- if (Character.isJavaIdentifierStart(key.charAt(0))) {
- if (wordStart > 0 && Character.isJavaIdentifierPart(text.charAt(wordStart - 1))) {
- template = null;
- continue;
- }
+ key = text.subSequence(wordStart, caretOffset).toString();
+ if (Character.isJavaIdentifierStart(key.charAt(0))) {
+ if (wordStart > 0 && Character.isJavaIdentifierPart(text.charAt(wordStart - 1))) {
+ continue;
}
- break;
}
- }
-
- if (template == null) return false;
- if (shortcutChar != 0 && getShortcutChar(template) != shortcutChar) {
- return false;
+ candidates = templateSettings.collectMatchingCandidates(key, shortcutChar);
+ if (!candidates.isEmpty()) break;
}
- if (template.isSelectionTemplate()) return false;
+ if (candidates.isEmpty()) return false;
CommandProcessor.getInstance().executeCommand(
myProject, new Runnable() {
},
"", null
);
- if (!isApplicable(file, caretOffset - template.getKey().length(), template)) {
+
+ candidates = filterApplicableCandidates(file, caretOffset - key.length(), candidates);
+ if (candidates.isEmpty()) {
return false;
}
if (!FileDocumentManager.getInstance().requestWriting(editor.getDocument(), myProject)) {
- return false;
+ return false;
+ }
+
+ if (candidates.size() == 1) {
+ TemplateImpl template = candidates.get(0);
+ startTemplateWithPrefix(editor, template, processor);
}
- final int wordStart0 = wordStart;
- final TemplateImpl template0 = template;
- final TemplateState templateState0 = templateManager.initTemplateState(editor);
+ else {
+ ListTemplatesHandler.showTemplatesLookup(myProject, editor, key, candidates);
+ }
+
+ return true;
+ }
+
+ public void startTemplateWithPrefix(final Editor editor, final TemplateImpl template, @Nullable final PairProcessor<String, String> processor) {
+ final int caretOffset = editor.getCaretModel().getOffset();
+ final int wordStart = caretOffset - template.getKey().length();
+ final TemplateState templateState = initTemplateState(editor);
CommandProcessor commandProcessor = CommandProcessor.getInstance();
commandProcessor.executeCommand(
myProject, new Runnable() {
public void run() {
- editor.getDocument().deleteString(wordStart0, caretOffset);
- editor.getCaretModel().moveToOffset(wordStart0);
+ editor.getDocument().deleteString(wordStart, caretOffset);
+ editor.getCaretModel().moveToOffset(wordStart);
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
editor.getSelectionModel().removeSelection();
- templateState0.start(template0, processor);
+ templateState.start(template, processor);
}
},
CodeInsightBundle.message("insert.code.template.command"), null
);
- return true;
}
- private static char getShortcutChar(TemplateImpl template) {
- char c = template.getShortcutChar();
- if (c == TemplateSettings.DEFAULT_CHAR) {
- return TemplateSettings.getInstance().getDefaultShortcutChar();
- }
- else {
- return c;
+ private static List<TemplateImpl> filterApplicableCandidates(PsiFile file, int offset, List<TemplateImpl> candidates) {
+ List<TemplateImpl> result = new ArrayList<TemplateImpl>();
+ for (TemplateImpl candidate : candidates) {
+ if (isApplicable(file, offset, candidate)) {
+ result.add(candidate);
+ }
}
+ return result;
}
public TemplateContextType getContextType(@NotNull PsiFile file, int offset) {
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.util.containers.MultiMap;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
private @NonNls static final String TEMPLATE = "template";
private @NonNls static final String DELETED_TEMPLATES = "deleted_templates";
- private final List<String> myDeletedTemplates = new ArrayList<String>();
+ private final List<TemplateKey> myDeletedTemplates = new ArrayList<TemplateKey>();
public static final char SPACE_CHAR = ' ';
public static final char TAB_CHAR = '\t';
private static final @NonNls String TEMPLATES_CONFIG_FOLDER = "templates";
- private final Map<String,Template> myTemplates = new LinkedHashMap<String,Template>();
+ private final List<TemplateImpl> myAllTemplates = new ArrayList<TemplateImpl>();
+ private final MultiMap<String,TemplateImpl> myTemplates = new MultiMap<String,TemplateImpl>();
private final Map<String,Template> myTemplatesById = new LinkedHashMap<String,Template>();
private final Map<String,TemplateImpl> myDefaultTemplates = new LinkedHashMap<String, TemplateImpl>();
private final SchemeProcessor<TemplateGroup> myProcessor;
private static final String FILE_SPEC = "$ROOT_CONFIG$/templates";
+ private static class TemplateKey {
+ final String groupName;
+ final String key;
+
+ private TemplateKey(String groupName, String key) {
+ this.groupName = groupName;
+ this.key = key;
+ }
+
+ public static TemplateKey keyOf(TemplateImpl template) {
+ return new TemplateKey(template.getGroupName(), template.getKey());
+ }
+ }
+
public TemplateSettings(SchemesManagerFactory schemesManagerFactory) {
List children = deleted.getChildren();
for (final Object aChildren : children) {
Element child = (Element)aChildren;
- myDeletedTemplates.add(child.getAttributeValue(NAME));
+ myDeletedTemplates.add(new TemplateKey(child.getAttributeValue(NAME), child.getAttributeValue(GROUP)));
}
}
- for (String name : myDeletedTemplates) {
- Template toDelete = myTemplates.get(name);
- if (toDelete != null) {
- removeTemplate(toDelete);
+ for (TemplateKey templateKey : myDeletedTemplates) {
+ if (templateKey.groupName == null) {
+ final Collection<TemplateImpl> templates = myTemplates.get(templateKey.key);
+ for (TemplateImpl template : templates) {
+ removeTemplate(template);
+ }
+ }
+ else {
+ final TemplateImpl toDelete = getTemplate(templateKey.key, templateKey.groupName);
+ if (toDelete != null) {
+ removeTemplate(toDelete);
+ }
}
}
if (myDeletedTemplates.size() > 0) {
Element deleted = new Element(DELETED_TEMPLATES);
- for (final String myDeletedTemplate : myDeletedTemplates) {
+ for (final TemplateKey deletedTemplate : myDeletedTemplates) {
Element template = new Element(TEMPLATE);
- template.setAttribute(NAME, myDeletedTemplate);
+ template.setAttribute(NAME, deletedTemplate.key);
+ template.setAttribute(GROUP, deletedTemplate.groupName);
deleted.addContent(template);
}
}
public TemplateImpl[] getTemplates() {
- return myTemplates.values().toArray(new TemplateImpl[myTemplates.size()]);
+ return myAllTemplates.toArray(new TemplateImpl[myAllTemplates.size()]);
}
public char getDefaultShortcutChar() {
myDefaultShortcutChar = defaultShortcutChar;
}
- public TemplateImpl getTemplate(@NonNls String key) {
- return (TemplateImpl) myTemplates.get(key);
+ public Collection<TemplateImpl> getTemplates(@NonNls String key) {
+ return myTemplates.get(key);
+ }
+
+ public TemplateImpl getTemplate(@NonNls String key, String group) {
+ final Collection<TemplateImpl> templates = myTemplates.get(key);
+ for (TemplateImpl template : templates) {
+ if (template.getGroupName().equals(group)) {
+ return template;
+ }
+ }
+ return null;
}
public Template getTemplateById(@NonNls String id) {
}
private void clearPreviouslyRegistered(final Template template) {
- TemplateImpl existing = getTemplate(template.getKey());
+ TemplateImpl existing = getTemplate(template.getKey(), ((TemplateImpl) template).getGroupName());
if (existing != null) {
LOG.info("Template with key " + template.getKey() + " and id " + template.getId() + " already registered");
TemplateGroup group = mySchemesManager.findSchemeByName(existing.getGroupName());
mySchemesManager.removeScheme(group);
}
}
- myTemplates.remove(template.getKey());
+ myTemplates.removeValue(template.getKey(), existing);
}
}
private void addTemplateImpl(Template template) {
- if (!myTemplates.containsKey(template.getKey())) {
- myTemplates.put(template.getKey(), template);
-
- myMaxKeyLength = Math.max(myMaxKeyLength, template.getKey().length());
+ final TemplateImpl templateImpl = (TemplateImpl)template;
+ if (getTemplate(templateImpl.getKey(), templateImpl.getGroupName()) == null) {
+ myTemplates.putValue(template.getKey(), templateImpl);
+ myAllTemplates.add(templateImpl);
}
- myDeletedTemplates.remove(template.getKey());
+
+ myMaxKeyLength = Math.max(myMaxKeyLength, template.getKey().length());
+ myDeletedTemplates.remove(TemplateKey.keyOf((TemplateImpl)template));
}
}
public void removeTemplate(Template template) {
- myTemplates.remove(template.getKey());
+ myTemplates.removeValue(template.getKey(), (TemplateImpl )template);
- TemplateImpl templImpl = (TemplateImpl)template;
- String groupName = templImpl.getGroupName();
+ TemplateImpl templateImpl = (TemplateImpl)template;
+ myAllTemplates.remove(templateImpl);
+ String groupName = templateImpl.getGroupName();
TemplateGroup group = mySchemesManager.findSchemeByName(groupName);
if (group != null) {
Element element = (Element)o1;
TemplateImpl template = readTemplateFromElement(isDefault, groupName, element);
- boolean doNotRegister = isDefault && (myDeletedTemplates.contains(template.getKey()) || myTemplates.containsKey(template.getKey()));
+ boolean doNotRegister = isDefault && (myDeletedTemplates.contains(TemplateKey.keyOf(template)) || myTemplates.containsKey(template.getKey()));
if(!doNotRegister) {
created.put(template.getKey(), template);
}
-
-
-
}
if (registerTemplate) {
myTemplates.clear();
myDeletedTemplates.clear();
for (TemplateImpl template : myDefaultTemplates.values()) {
- myDeletedTemplates.add(template.getKey());
+ myDeletedTemplates.add(TemplateKey.keyOf(template));
}
mySchemesManager.clearAllSchemes();
myMaxKeyLength = 0;
public List<TemplateGroup> getTemplateGroups() {
return mySchemesManager.getAllSchemes();
}
+
+ public List<TemplateImpl> collectMatchingCandidates(String key, char shortcutChar) {
+ final Collection<TemplateImpl> templates = getTemplates(key);
+ List<TemplateImpl> candidates = new ArrayList<TemplateImpl>();
+ for (TemplateImpl template : templates) {
+ if (template.isDeactivated()) {
+ continue;
+ }
+ if (getShortcutChar(template) != shortcutChar) {
+ continue;
+ }
+ if (template.isSelectionTemplate()) {
+ continue;
+ }
+ candidates.add(template);
+ }
+ return candidates;
+ }
+
+ private char getShortcutChar(TemplateImpl template) {
+ char c = template.getShortcutChar();
+ if (c == DEFAULT_CHAR) {
+ return getDefaultShortcutChar();
+ }
+ else {
+ return c;
+ }
+ }
}
private boolean myTemplateIndented = false;
private Document myDocument;
private boolean myFinished;
- private PairProcessor<String, String> myProcessor;
+ @Nullable private PairProcessor<String, String> myProcessor;
public TemplateState(@NotNull Project project, final Editor editor) {
myProject = project;
}
}
- public void start(TemplateImpl template, final PairProcessor<String, String> processor) {
+ public void start(TemplateImpl template, @Nullable final PairProcessor<String, String> processor) {
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
myProcessor = processor;
TemplateManagerImpl templateManager = (TemplateManagerImpl)TemplateManager.getInstance(project);
- if (!templateManager.startTemplate(templateManager, editor, TemplateSettings.ENTER_CHAR)) {
+ if (!templateManager.startTemplate(editor, TemplateSettings.ENTER_CHAR)) {
myOriginalHandler.execute(editor, dataContext);
}
}
}
TemplateManagerImpl templateManager = (TemplateManagerImpl) TemplateManagerImpl.getInstance(project);
- if (!templateManager.startTemplate(templateManager, editor, TemplateSettings.SPACE_CHAR)) {
+ if (!templateManager.startTemplate(editor, TemplateSettings.SPACE_CHAR)) {
myOriginalHandler.execute(editor, charTyped, dataContext);
}
}
TemplateManagerImpl templateManager = (TemplateManagerImpl) TemplateManagerImpl.getInstance(project);
- if (!templateManager.startTemplate(templateManager, editor, TemplateSettings.TAB_CHAR)) {
+ if (!templateManager.startTemplate(editor, TemplateSettings.TAB_CHAR)) {
myOriginalHandler.execute(editor, dataContext);
}
}
dialog.edit.template.checkbox.other=O&ther
dialog.edit.template.error.title=Cannot Save
dialog.edit.template.error.malformed.abbreviation=Cannot save the template.\nTemplate abbreviation should contain only letters, digits, dots and hyphens.
-dialog.edit.template.error.already.exists=Cannot save the template.\nTemplate with the abbreviation \"{0}\"\nalready exists in group \"{1}\".\nTry another abbreviation.
+dialog.edit.template.error.already.exists=Cannot save the template.\nTemplate with the abbreviation \"{0}\"\nalready exists in group \"{1}\".\nPlease choose a different abbreviation or group.
dialog.edit.template.error.malformed.template=Error parsing the template
finish.template.command=Finish Template
insert.code.template.command=Insert Code Template