renaming; show popup, if it is simple live template invokation by zen-coding shortcut...
[idea/community.git] / platform / lang-impl / src / com / intellij / codeInsight / template / CustomTemplateCallback.java
1 /*
2  * Copyright 2000-2010 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.codeInsight.template;
17
18 import com.intellij.codeInsight.template.impl.TemplateImpl;
19 import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
20 import com.intellij.codeInsight.template.impl.TemplateSettings;
21 import com.intellij.openapi.editor.Editor;
22 import com.intellij.openapi.fileTypes.FileType;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.psi.PsiElement;
25 import com.intellij.psi.PsiFile;
26 import com.intellij.psi.PsiFileFactory;
27 import com.intellij.util.LocalTimeCounter;
28 import com.intellij.util.containers.HashMap;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
31
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.List;
35 import java.util.Map;
36
37 /**
38  * @author Eugene.Kudelevsky
39  */
40 public class CustomTemplateCallback {
41   private final TemplateManager myTemplateManager;
42   private final Editor myEditor;
43   private final PsiFile myFile;
44   private int myStartOffset;
45   private final Project myProject;
46   private LiveTemplateBuilder.Marker myEndOffsetMarker;
47   private final Map<Object, LiveTemplateBuilder.Marker> myCheckpoints = new HashMap<Object, LiveTemplateBuilder.Marker>();
48
49   private FileType myFileType;
50
51   private LiveTemplateBuilder myBuilder = new LiveTemplateBuilder();
52   private int myOffset = 0;
53
54   public CustomTemplateCallback(Editor editor, PsiFile file) {
55     myEditor = editor;
56     myFile = file;
57     myProject = file.getProject();
58     myTemplateManager = TemplateManagerImpl.getInstance(myProject);
59     fixInitialState();
60   }
61
62   @Nullable
63   public PsiElement getContext() {
64     int offset = myStartOffset;
65     return myFile.findElementAt(offset > 0 ? offset - 1 : offset);
66   }
67
68   public void fixInitialState() {
69     myStartOffset = myEditor.getCaretModel().getOffset();
70   }
71
72   public void fixEndOffset() {
73     if (myEndOffsetMarker == null) {
74       myEndOffsetMarker = myBuilder.createMarker(myOffset);
75     }
76   }
77
78   public boolean isLiveTemplateApplicable(@NotNull String key) {
79     return findApplicableTemplate(key) != null;
80   }
81
82   @Nullable
83   public TemplateImpl findApplicableTemplate(@NotNull String key) {
84     List<TemplateImpl> templates = findApplicableTemplates(key);
85     return templates.size() > 0 ? templates.get(0) : null;
86   }
87
88   @NotNull
89   public List<TemplateImpl> findApplicableTemplates(String key) {
90     List<TemplateImpl> templates = getMatchingTemplates(key);
91     templates = filterApplicableCandidates(templates);
92     return templates;
93   }
94
95   private List<TemplateImpl> filterApplicableCandidates(Collection<TemplateImpl> candidates) {
96     List<TemplateImpl> result = new ArrayList<TemplateImpl>();
97     for (TemplateImpl candidate : candidates) {
98       if (TemplateManagerImpl.isApplicable(myFile, myStartOffset, candidate)) {
99         result.add(candidate);
100       }
101     }
102     return result;
103   }
104
105   /**
106    * @param key
107    * @param predefinedVarValues
108    * @param listener            @return returns if template invokation is finished
109    */
110   public void expandTemplate(@NotNull String key,
111                              Map<String, String> predefinedVarValues) {
112     List<TemplateImpl> templates = findApplicableTemplates(key);
113     if (templates.size() > 0) {
114       TemplateImpl template = templates.get(0);
115       expandTemplate(template, predefinedVarValues);
116     }
117   }
118
119   public void expandTemplate(@NotNull TemplateImpl template,
120                              Map<String, String> predefinedVarValues) {
121     int offset = myBuilder.insertTemplate(myOffset, template, predefinedVarValues);
122     moveToOffset(offset);
123   }
124
125   public void fixStartOfTemplate(@NotNull Object key) {
126     LiveTemplateBuilder.Marker marker = myBuilder.createMarker(myOffset);
127     myCheckpoints.put(key, marker);
128   }
129
130   public void gotoEndOfTemplate(@NotNull Object key) {
131     moveToOffset(getEndOfTemplate(key));
132   }
133
134   public int getEndOfTemplate(@NotNull Object key) {
135     LiveTemplateBuilder.Marker marker = myCheckpoints.get(key);
136     if (marker == null) {
137       throw new IllegalArgumentException();
138     }
139     return marker.getEndOffset();
140   }
141
142   public int getStartOfTemplate(@NotNull Object key) {
143     LiveTemplateBuilder.Marker marker = myCheckpoints.get(key);
144     if (marker == null) {
145       throw new IllegalArgumentException();
146     }
147     return marker.getStartOffset();
148   }
149
150   public void gotoEndOffset() {
151     if (myEndOffsetMarker != null) {
152       moveToOffset(myEndOffsetMarker.getStartOffset());
153     }
154   }
155
156   public void startAllExpandedTemplates() {
157     /*myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
158     final CodeStyleManager style = CodeStyleManager.getInstance(myProject);
159     if (myGlobalMarker != null) {
160       style.reformatText(myFile, myGlobalMarker.getStartOffset(), myGlobalMarker.getEndOffset());
161     }*/
162     if (myBuilder.getText().length() == 0) {
163       return;
164     }
165     gotoEndOffset();
166     if (myOffset < myBuilder.getText().length()) {
167       myBuilder.insertVariableSegment(myOffset, TemplateImpl.END);
168     }
169     TemplateImpl template = myBuilder.buildTemplate();
170     myTemplateManager.startTemplate(myEditor, template, false, myBuilder.getPredefinedValues(), null);
171     myBuilder = new LiveTemplateBuilder();
172     myEndOffsetMarker = null;
173     myCheckpoints.clear();
174   }
175
176   public boolean startTemplate(@NotNull String key) {
177     List<TemplateImpl> templates = findApplicableTemplates(key);
178     Map<TemplateImpl, String> template2Argument = new HashMap<TemplateImpl, String>();
179     for (TemplateImpl template : templates) {
180       template2Argument.put(template, null);
181     }
182     return ((TemplateManagerImpl)myTemplateManager).startNonCustomTemplates(template2Argument, myEditor, null);
183   }
184
185   private static List<TemplateImpl> getMatchingTemplates(@NotNull String templateKey) {
186     TemplateSettings settings = TemplateSettings.getInstance();
187     List<TemplateImpl> candidates = new ArrayList<TemplateImpl>();
188     for (TemplateImpl template : settings.getTemplates(templateKey)) {
189       if (!template.isDeactivated() && !template.isSelectionTemplate()) {
190         candidates.add(template);
191       }
192     }
193     return candidates;
194   }
195
196   @NotNull
197   public Editor getEditor() {
198     return myEditor;
199   }
200
201   @NotNull
202   public FileType getFileType() {
203     if (myFileType == null) {
204       myFileType = myFile.getFileType();
205     }
206     return myFileType;
207   }
208
209   public int getOffset() {
210     return myOffset;
211   }
212
213   @NotNull
214   public PsiFile parseCurrentText(FileType fileType) {
215     return PsiFileFactory.getInstance(myProject)
216       .createFileFromText("dummy.xml", fileType, myBuilder.getText(), LocalTimeCounter.currentTime(), false);
217   }
218
219   public Project getProject() {
220     return myProject;
221   }
222
223   public void moveToOffset(int offset) {
224     myOffset = offset;
225   }
226
227   public void insertString(int offset, String text) {
228     myBuilder.insertText(offset, text);
229   }
230
231   public void deleteTemplateKey(String key) {
232     int caretAt = myEditor.getCaretModel().getOffset();
233     myEditor.getDocument().deleteString(caretAt - key.length(), caretAt);
234   }
235 }