2 * Copyright 2000-2010 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.codeInsight.template;
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.lang.injection.InjectedLanguageManager;
22 import com.intellij.openapi.editor.Editor;
23 import com.intellij.openapi.fileTypes.FileType;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.psi.PsiElement;
26 import com.intellij.psi.PsiFile;
27 import com.intellij.psi.PsiFileFactory;
28 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
29 import com.intellij.util.LocalTimeCounter;
30 import com.intellij.util.containers.HashMap;
31 import org.jetbrains.annotations.NotNull;
32 import org.jetbrains.annotations.Nullable;
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.List;
40 * @author Eugene.Kudelevsky
42 public class CustomTemplateCallback {
43 private final TemplateManager myTemplateManager;
44 private final Editor myEditor;
45 private final PsiFile myFile;
46 private int myStartOffset;
47 private final Project myProject;
48 private LiveTemplateBuilder.Marker myEndOffsetMarker;
49 private final Map<Object, LiveTemplateBuilder.Marker> myCheckpoints = new HashMap<Object, LiveTemplateBuilder.Marker>();
51 private FileType myFileType;
53 private LiveTemplateBuilder myBuilder = new LiveTemplateBuilder();
54 private int myOffset = 0;
56 public CustomTemplateCallback(Editor editor, PsiFile file) {
59 myProject = file.getProject();
60 myTemplateManager = TemplateManagerImpl.getInstance(myProject);
65 public PsiElement getContext() {
66 return getContext(myFile, myStartOffset > 0 ? myStartOffset - 1 : myStartOffset);
69 public void fixInitialState() {
70 myStartOffset = myEditor.getCaretModel().getOffset();
73 public void fixEndOffset() {
74 if (myEndOffsetMarker == null) {
75 myEndOffsetMarker = myBuilder.createMarker(myOffset);
79 public boolean isLiveTemplateApplicable(@NotNull String key) {
80 return findApplicableTemplate(key) != null;
84 public TemplateImpl findApplicableTemplate(@NotNull String key) {
85 List<TemplateImpl> templates = findApplicableTemplates(key);
86 return templates.size() > 0 ? templates.get(0) : null;
90 public List<TemplateImpl> findApplicableTemplates(String key) {
91 List<TemplateImpl> templates = getMatchingTemplates(key);
92 templates = filterApplicableCandidates(templates);
96 private List<TemplateImpl> filterApplicableCandidates(Collection<TemplateImpl> candidates) {
97 List<TemplateImpl> result = new ArrayList<TemplateImpl>();
98 for (TemplateImpl candidate : candidates) {
99 if (TemplateManagerImpl.isApplicable(myFile, myStartOffset, candidate)) {
100 result.add(candidate);
108 * @param predefinedVarValues
109 * @param listener @return returns if template invokation is finished
111 public void expandTemplate(@NotNull String key,
112 Map<String, String> predefinedVarValues) {
113 List<TemplateImpl> templates = findApplicableTemplates(key);
114 if (templates.size() > 0) {
115 TemplateImpl template = templates.get(0);
116 expandTemplate(template, predefinedVarValues);
120 public void expandTemplate(@NotNull TemplateImpl template,
121 Map<String, String> predefinedVarValues) {
122 int offset = myBuilder.insertTemplate(myOffset, template, predefinedVarValues);
123 moveToOffset(offset);
126 public void fixStartOfTemplate(@NotNull Object key) {
127 LiveTemplateBuilder.Marker marker = myBuilder.createMarker(myOffset);
128 myCheckpoints.put(key, marker);
131 public void gotoEndOfTemplate(@NotNull Object key) {
132 moveToOffset(getEndOfTemplate(key));
135 public int getEndOfTemplate(@NotNull Object key) {
136 LiveTemplateBuilder.Marker marker = myCheckpoints.get(key);
137 if (marker == null) {
138 throw new IllegalArgumentException();
140 return marker.getEndOffset();
143 public int getStartOfTemplate(@NotNull Object key) {
144 LiveTemplateBuilder.Marker marker = myCheckpoints.get(key);
145 if (marker == null) {
146 throw new IllegalArgumentException();
148 return marker.getStartOffset();
151 public void gotoEndOffset() {
152 if (myEndOffsetMarker != null) {
153 moveToOffset(myEndOffsetMarker.getStartOffset());
157 public void startAllExpandedTemplates() {
158 /*myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
159 final CodeStyleManager style = CodeStyleManager.getInstance(myProject);
160 if (myGlobalMarker != null) {
161 style.reformatText(myFile, myGlobalMarker.getStartOffset(), myGlobalMarker.getEndOffset());
163 if (myBuilder.getText().length() == 0) {
167 if (myOffset < myBuilder.getText().length()) {
168 myBuilder.insertVariableSegment(myOffset, TemplateImpl.END);
170 TemplateImpl template = myBuilder.buildTemplate();
171 myTemplateManager.startTemplate(myEditor, template, false, myBuilder.getPredefinedValues(), null);
172 myBuilder = new LiveTemplateBuilder();
173 myEndOffsetMarker = null;
174 myCheckpoints.clear();
177 public boolean startTemplate() {
178 Map<TemplateImpl, String> template2Argument =
179 ((TemplateManagerImpl)myTemplateManager).findMatchingTemplates(myFile, myEditor, null, TemplateSettings.getInstance());
180 return ((TemplateManagerImpl)myTemplateManager).startNonCustomTemplates(template2Argument, myEditor, null);
183 private static List<TemplateImpl> getMatchingTemplates(@NotNull String templateKey) {
184 TemplateSettings settings = TemplateSettings.getInstance();
185 List<TemplateImpl> candidates = new ArrayList<TemplateImpl>();
186 for (TemplateImpl template : settings.getTemplates(templateKey)) {
187 if (!template.isDeactivated() && !template.isSelectionTemplate()) {
188 candidates.add(template);
195 public Editor getEditor() {
200 public FileType getFileType() {
201 if (myFileType == null) {
202 myFileType = myFile.getFileType();
207 public int getOffset() {
212 public PsiFile parseCurrentText(FileType fileType) {
213 return PsiFileFactory.getInstance(myProject)
214 .createFileFromText("dummy.xml", fileType, myBuilder.getText(), LocalTimeCounter.currentTime(), false);
217 public Project getProject() {
221 public void moveToOffset(int offset) {
225 public void insertString(int offset, String text) {
226 myBuilder.insertText(offset, text);
229 public void deleteTemplateKey(String key) {
230 int caretAt = myEditor.getCaretModel().getOffset();
231 myEditor.getDocument().deleteString(caretAt - key.length(), caretAt);
234 public static PsiElement getContext(PsiFile file, int offset) {
235 PsiElement element = null;
236 if (!InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) {
237 element = InjectedLanguageUtil.findInjectedElementNoCommit(file, offset);
239 if (element == null) {
240 element = file.findElementAt(offset > 0 ? offset - 1 : offset);
241 if (element == null) {