--- /dev/null
+/*
+ * Copyright 2000-2010 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;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public interface CustomLiveTemplate {
+ ExtensionPointName<CustomLiveTemplate> EP_NAME = ExtensionPointName.create("com.intellij.customLiveTemplate");
+
+ boolean isApplicable(@NotNull String key, @NotNull CustomTemplateCallback callback);
+
+ void execute(@NotNull String key, @NotNull CustomTemplateCallback callback, @Nullable TemplateInvokationListener listener);
+}
--- /dev/null
+/*
+ * Copyright 2000-2010 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;
+
+import com.intellij.codeInsight.template.impl.TemplateImpl;
+import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
+import com.intellij.codeInsight.template.impl.TemplateSettings;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class CustomTemplateCallback {
+ private final TemplateManager myTemplateManager;
+ private final Editor myEditor;
+ private final PsiFile myFile;
+ private int myStartOffset;
+ private int myStartLength;
+ private Project myProject;
+
+ public CustomTemplateCallback(Editor editor, PsiFile file) {
+ myEditor = editor;
+ myFile = file;
+ myProject = file.getProject();
+ myTemplateManager = TemplateManagerImpl.getInstance(myProject);
+ }
+
+ public void fixInitialEditorState() {
+ myStartOffset = myEditor.getCaretModel().getOffset();
+ myStartLength = myEditor.getDocument().getCharsSequence().length();
+ }
+
+ public boolean isLiveTemplateApplicable(@NotNull String key) {
+ List<TemplateImpl> templates = getMatchingTemplates(key);
+ templates = TemplateManagerImpl.filterApplicableCandidates(myFile, myStartOffset, templates);
+ return templates.size() > 0;
+ }
+
+ /**
+ * @param key
+ * @param listener
+ * @return returns if template invokation is finished
+ */
+ public boolean startTemplate(@NotNull String key, @Nullable TemplateInvokationListener listener) {
+ int caretOffset = myEditor.getCaretModel().getOffset();
+ List<TemplateImpl> templates = getMatchingTemplates(key);
+ templates = TemplateManagerImpl.filterApplicableCandidates(myFile, caretOffset, templates);
+ if (templates.size() == 1) {
+ TemplateImpl template = templates.get(0);
+ return startTemplate(template, listener);
+ }
+ else if (listener != null) {
+ listener.finished(false, false);
+ }
+ return true;
+ }
+
+ /**
+ * @param template
+ * @param listener
+ * @return returns if template invokation is finished
+ */
+ public boolean startTemplate(@NotNull Template template, @Nullable final TemplateInvokationListener listener) {
+ final boolean[] templateEnded = new boolean[]{false};
+ final boolean[] templateFinished = new boolean[]{false};
+ myTemplateManager.startTemplate(myEditor, template, new TemplateEditingAdapter() {
+
+ @Override
+ public void templateExpanded(Template template) {
+ int lengthAfter = myEditor.getDocument().getCharsSequence().length();
+ CodeStyleManager style = CodeStyleManager.getInstance(myProject);
+ style.reformatText(myFile, myStartOffset, myStartOffset + lengthAfter - myStartLength);
+ }
+
+ @Override
+ public void templateFinished(Template template) {
+ templateFinished[0] = true;
+ if (templateEnded[0] && listener != null) {
+ listener.finished(true, true);
+ }
+ }
+ }, false);
+ templateEnded[0] = true;
+ if (templateFinished[0] && listener != null) {
+ listener.finished(false, true);
+ }
+ return templateFinished[0];
+ }
+
+ private static List<TemplateImpl> getMatchingTemplates(@NotNull String templateKey) {
+ TemplateSettings settings = TemplateSettings.getInstance();
+ return settings.collectMatchingCandidates(templateKey, settings.getDefaultShortcutChar(), false);
+ }
+
+ @NotNull
+ public Editor getEditor() {
+ return myEditor;
+ }
+
+ public PsiFile getFile() {
+ return myFile;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2010 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;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public abstract class Iteration {
+ protected final int myMaxIndex;
+ protected int myIndex;
+ private final Iteration myParentIteration;
+
+ public Iteration(int index, int maxIndex, Iteration parentIteration) {
+ myIndex = index;
+ myMaxIndex = maxIndex;
+ myParentIteration = parentIteration;
+ }
+
+ protected void next() {
+ myIndex++;
+ if (myIndex < myMaxIndex) {
+ iter();
+ }
+ else if (myIndex == myMaxIndex && myParentIteration != null) {
+ myParentIteration.next();
+ }
+ }
+
+ public boolean isFinished() {
+ return myIndex >= myMaxIndex;
+ }
+
+ // returns if next() is going to be invoked
+ protected abstract void iter();
+}
public void currentVariableChanged(TemplateState templateState, Template template, int oldIndex, int newIndex) {
}
+
+ public void templateExpanded(Template template) {
+ }
}
void templateFinished(Template template);
void templateCancelled(Template template);
void currentVariableChanged(TemplateState templateState, Template template, int oldIndex, int newIndex);
+ void templateExpanded(Template template);
}
--- /dev/null
+/*
+ * Copyright 2000-2010 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;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public interface TemplateInvokationListener {
+ void finished(boolean inSeparateEvent, boolean success);
+}
-
/*
- * Copyright 2000-2009 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.
- */
+* Copyright 2000-2009 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;
public abstract void startTemplate(@NotNull Editor editor, @NotNull Template template, TemplateEditingListener listener);
- public abstract void startTemplate(@NotNull Editor editor, @NotNull Template template, TemplateEditingListener listener,
- final PairProcessor<String, String> callback);
+ public abstract void startTemplate(@NotNull final Editor editor,
+ @NotNull final Template template,
+ TemplateEditingListener listener,
+ boolean inSeparateCommand);
+
+ public abstract void startTemplate(@NotNull Editor editor,
+ @NotNull Template template,
+ TemplateEditingListener listener,
+ final PairProcessor<String, String> callback);
public abstract boolean startTemplate(@NotNull Editor editor, char shortcutChar);
}
public void startTemplate(@NotNull Editor editor, String selectionString, @NotNull Template template) {
- startTemplate(editor, selectionString, template, null, null);
+ startTemplate(editor, selectionString, template, null, null, true);
}
public void startTemplate(@NotNull Editor editor,
@NotNull Template template,
TemplateEditingListener listener,
final PairProcessor<String, String> processor) {
- startTemplate(editor, null, template, listener, processor);
+ startTemplate(editor, null, template, listener, processor, true);
}
private void startTemplate(final Editor editor,
final String selectionString,
final Template template,
TemplateEditingListener listener,
- final PairProcessor<String, String> processor) {
+ final PairProcessor<String, String> processor,
+ boolean inSeparateCommand) {
final TemplateState templateState = initTemplateState(editor);
templateState.getProperties().put(ExpressionContext.SELECTION, selectionString);
if (listener != null) {
templateState.addTemplateStateListener(listener);
}
- CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
+ Runnable r = new Runnable() {
public void run() {
if (selectionString != null) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
}
templateState.start((TemplateImpl)template, processor, null);
}
- }, CodeInsightBundle.message("insert.code.template.command"), null);
+ };
+ if (inSeparateCommand) {
+ CommandProcessor.getInstance().executeCommand(myProject, r, CodeInsightBundle.message("insert.code.template.command"), null);
+ }
+ else {
+ r.run();
+ }
if (shouldSkipInTests()) {
if (!templateState.isFinished()) templateState.gotoEnd();
}
public void startTemplate(@NotNull final Editor editor, @NotNull final Template template, TemplateEditingListener listener) {
- startTemplate(editor, null, template, listener, null);
+ startTemplate(editor, null, template, listener, null, false);
+ }
+
+ public void startTemplate(@NotNull final Editor editor,
+ @NotNull final Template template,
+ TemplateEditingListener listener,
+ boolean inSeparateCommand) {
+ startTemplate(editor, null, template, listener, null, inSeparateCommand);
}
private static int passArgumentBack(CharSequence text, int caretOffset) {
}
}
+ private static String getCurrentLineBeforeCaret(@NotNull Editor editor) {
+ CaretModel caretModel = editor.getCaretModel();
+ int line = caretModel.getLogicalPosition().line;
+ int lineStart = editor.getDocument().getLineStartOffset(line);
+ int offset = caretModel.getOffset();
+ String s = editor.getDocument().getCharsSequence().subSequence(lineStart, offset).toString();
+ int index = 0;
+ while (index < s.length() && Character.isWhitespace(s.charAt(index))) {
+ index++;
+ }
+ return index < s.length() ? s.substring(index) : s;
+ }
+
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();
+ if (shortcutChar == templateSettings.getDefaultShortcutChar()) {
+ for (final CustomLiveTemplate customLiveTemplate : CustomLiveTemplate.EP_NAME.getExtensions()) {
+ final String currentLineBeforeCaret = getCurrentLineBeforeCaret(editor);
+ final CustomTemplateCallback callback = new CustomTemplateCallback(editor, file);
+ if (customLiveTemplate.isApplicable(currentLineBeforeCaret, callback)) {
+ int offset = editor.getCaretModel().getOffset();
+ final int startOffset = offset - currentLineBeforeCaret.length();
+ editor.getDocument().deleteString(startOffset, offset);
+ callback.fixInitialEditorState();
+ customLiveTemplate.execute(currentLineBeforeCaret, callback, null);
+ return true;
+ }
+ }
+ }
+ return startNonCustomTemplate(templateSettings, file, editor, shortcutChar, processor);
+ }
+
+ private boolean startNonCustomTemplate(TemplateSettings templateSettings,
+ PsiFile file,
+ Editor editor,
+ char shortcutChar,
+ PairProcessor<String, String> processor) {
+ final Document document = editor.getDocument();
+
CharSequence text = document.getCharsSequence();
final int caretOffset = editor.getCaretModel().getOffset();
else {
ListTemplatesHandler.showTemplatesLookup(myProject, editor, candidate2Argument);
}
-
return true;
}
- private static List<TemplateImpl> findMatchingTemplates(CharSequence text,
- int caretOffset,
- char shortcutChar,
- TemplateSettings settings,
- boolean hasArgument) {
+ public static List<TemplateImpl> findMatchingTemplates(CharSequence text,
+ int caretOffset,
+ char shortcutChar,
+ TemplateSettings settings,
+ boolean hasArgument) {
String key;
List<TemplateImpl> candidates = Collections.emptyList();
for (int i = settings.getMaxKeyLength(); i >= 1; i--) {
}, CodeInsightBundle.message("insert.code.template.command"), null);
}
- private static List<TemplateImpl> filterApplicableCandidates(PsiFile file, int caretOffset, List<TemplateImpl> candidates) {
+ public static List<TemplateImpl> filterApplicableCandidates(PsiFile file, int caretOffset, List<TemplateImpl> candidates) {
List<TemplateImpl> result = new ArrayList<TemplateImpl>();
for (TemplateImpl candidate : candidates) {
if (isApplicable(file, caretOffset - candidate.getKey().length(), candidate)) {
calcResults(false); //Fixed SCR #[vk500] : all variables should be recalced twice on start.
doReformat();
+ fireTemplateExpanded();
+
int nextVariableNumber = getNextVariableNumber(-1);
if (nextVariableNumber == -1) {
finishTemplateEditing();
}
}
+ private void fireTemplateExpanded() {
+ TemplateEditingListener[] listeners = myListeners.toArray(new TemplateEditingListener[myListeners.size()]);
+ for (TemplateEditingListener listener : listeners) {
+ listener.templateExpanded(myTemplate);
+ }
+ }
+
private void currentVariableChanged(int oldIndex) {
TemplateEditingListener[] listeners = myListeners.toArray(new TemplateEditingListener[myListeners.size()]);
for (TemplateEditingListener listener : listeners) {
<extensionPoint name="lang.unwrapDescriptor" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint name="lang.parserDefinition" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint name="lang.treePatcher" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
- <extensionPoint name="lang.tokenSeparatorGenerator" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint name="lang.fileViewProviderFactory" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint name="fileType.fileViewProviderFactory" beanClass="com.intellij.openapi.fileTypes.FileTypeExtensionPoint"/>
<extensionPoint name="liveTemplateMacro" interface="com.intellij.codeInsight.template.Macro"/>
<extensionPoint name="liveTemplateOptionalProcessor" interface="com.intellij.codeInsight.template.impl.TemplateOptionalProcessor"/>
<extensionPoint name="liveTemplatePreprocessor" interface="com.intellij.codeInsight.template.impl.TemplatePreprocessor"/>
+ <extensionPoint name="customLiveTemplate" interface="com.intellij.codeInsight.template.CustomLiveTemplate"/>
<extensionPoint name="fileTemplateGroup"
interface="com.intellij.ide.fileTemplates.FileTemplateGroupDescriptorFactory"/>