From 867db21fcbaea5de5111008d1c57331700756742 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Thu, 11 Feb 2010 21:44:55 +0300 Subject: [PATCH] support of predefined variable values --- .../template/CustomTemplateCallback.java | 50 ++++++++++++++++------ .../template/TemplateEditingListener.java | 2 +- .../codeInsight/template/TemplateManager.java | 7 ++- .../template/impl/TemplateManagerImpl.java | 41 +++++++++++++----- .../codeInsight/template/impl/TemplateState.java | 46 ++++++++++++-------- 5 files changed, 101 insertions(+), 45 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java index d7b4bdeb5f..4b46fd9625 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java @@ -22,10 +22,13 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Map; +import java.util.Set; /** * @author Eugene.Kudelevsky @@ -56,18 +59,39 @@ public class CustomTemplateCallback { return templates.size() > 0; } + public boolean isTemplateContainsVars(@NotNull String key, String... varNames) { + List templates = getMatchingTemplates(key); + templates = TemplateManagerImpl.filterApplicableCandidates(myFile, myStartOffset, templates); + if (templates.size() == 0) { + return false; + } + TemplateImpl template = templates.get(0); + Set varSet = new HashSet(); + for (int i = 0; i < template.getVariableCount(); i++) { + varSet.add(template.getVariableNameAt(i)); + } + for (String varName : varNames) { + if (!varSet.contains(varName)) { + return false; + } + } + return true; + } + /** * @param key - * @param listener - * @return returns if template invokation is finished + * @param predefinedVarValues + * @param listener @return returns if template invokation is finished */ - public boolean startTemplate(@NotNull String key, @Nullable TemplateInvokationListener listener) { + public boolean startTemplate(@NotNull String key, + Map predefinedVarValues, + @Nullable TemplateInvokationListener listener) { int caretOffset = myEditor.getCaretModel().getOffset(); List templates = getMatchingTemplates(key); templates = TemplateManagerImpl.filterApplicableCandidates(myFile, caretOffset, templates); - if (templates.size() == 1) { + if (templates.size() > 0) { TemplateImpl template = templates.get(0); - return startTemplate(template, listener); + return startTemplate(template, predefinedVarValues, listener); } else if (listener != null) { listener.finished(false, false); @@ -77,30 +101,28 @@ public class CustomTemplateCallback { /** * @param template + * @param predefinedVarValues * @param listener * @return returns if template invokation is finished */ - public boolean startTemplate(@NotNull Template template, @Nullable final TemplateInvokationListener listener) { + public boolean startTemplate(@NotNull Template template, + Map predefinedVarValues, + @Nullable final TemplateInvokationListener listener) { final boolean[] templateEnded = new boolean[]{false}; final boolean[] templateFinished = new boolean[]{false}; - myTemplateManager.startTemplate(myEditor, template, new TemplateEditingAdapter() { - + myTemplateManager.startTemplate(myEditor, template, false, predefinedVarValues, new TemplateEditingAdapter() { @Override - public void templateExpanded(Template template) { + public void templateFinished(Template template, boolean brokenOff) { int lengthAfter = myEditor.getDocument().getCharsSequence().length(); CodeStyleManager style = CodeStyleManager.getInstance(myProject); style.reformatText(myFile, myStartOffset, myStartOffset + lengthAfter - myStartLength); - } - - @Override - public void templateFinished(Template template, boolean brokenOff) { if (brokenOff) return; 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); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingListener.java b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingListener.java index 0412c9a0a0..73478f59a7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingListener.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingListener.java @@ -26,5 +26,5 @@ public interface TemplateEditingListener { void templateFinished(Template template, boolean brokenOff); void templateCancelled(Template template); void currentVariableChanged(TemplateState templateState, Template template, int oldIndex, int newIndex); - void templateExpanded(Template template); + void templateExpanded(Template template); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java index f0369f22b3..8caeba8c60 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java @@ -24,6 +24,8 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Map; + public abstract class TemplateManager { public static TemplateManager getInstance(Project project) { return project.getComponent(TemplateManager.class); @@ -37,8 +39,9 @@ public abstract class TemplateManager { public abstract void startTemplate(@NotNull final Editor editor, @NotNull final Template template, - TemplateEditingListener listener, - boolean inSeparateCommand); + boolean inSeparateCommand, + Map predefinedVarValues, + TemplateEditingListener listener); public abstract void startTemplate(@NotNull Editor editor, @NotNull Template template, diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java index 9886c9d69e..0f661293de 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java @@ -132,22 +132,23 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo } public void startTemplate(@NotNull Editor editor, String selectionString, @NotNull Template template) { - startTemplate(editor, selectionString, template, null, null, true); + startTemplate(editor, selectionString, template, true, null, null, null); } public void startTemplate(@NotNull Editor editor, @NotNull Template template, TemplateEditingListener listener, final PairProcessor processor) { - startTemplate(editor, null, template, listener, processor, true); + startTemplate(editor, null, template, true, listener, processor, null); } private void startTemplate(final Editor editor, final String selectionString, final Template template, + boolean inSeparateCommand, TemplateEditingListener listener, final PairProcessor processor, - boolean inSeparateCommand) { + final Map predefinedVarValues) { final TemplateState templateState = initTemplateState(editor); templateState.getProperties().put(ExpressionContext.SELECTION, selectionString); @@ -167,7 +168,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo else { editor.getSelectionModel().removeSelection(); } - templateState.start((TemplateImpl)template, processor, null); + templateState.start((TemplateImpl)template, processor, predefinedVarValues); } }; if (inSeparateCommand) { @@ -187,14 +188,15 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo } public void startTemplate(@NotNull final Editor editor, @NotNull final Template template, TemplateEditingListener listener) { - startTemplate(editor, null, template, listener, null, true); + startTemplate(editor, null, template, true, listener, null, null); } public void startTemplate(@NotNull final Editor editor, @NotNull final Template template, - TemplateEditingListener listener, - boolean inSeparateCommand) { - startTemplate(editor, null, template, listener, null, inSeparateCommand); + boolean inSeparateCommand, + Map predefinedVarValues, + TemplateEditingListener listener) { + startTemplate(editor, null, template, inSeparateCommand, listener, null, predefinedVarValues); } private static int passArgumentBack(CharSequence text, int caretOffset) { @@ -231,13 +233,27 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo return index < s.length() ? s.substring(index) : s; } + @NotNull + private static String normalize(@NotNull String key) { + int lastWhitespaceIndex = -1; + for (int i = 0; i < key.length(); i++) { + if (Character.isWhitespace(key.charAt(i))) { + lastWhitespaceIndex = i; + } + } + if (lastWhitespaceIndex >= 0 && lastWhitespaceIndex < key.length() - 1) { + return key.substring(lastWhitespaceIndex + 1); + } + return key; + } + public boolean startTemplate(final Editor editor, char shortcutChar, final PairProcessor processor) { 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 String currentLineBeforeCaret = normalize(getCurrentLineBeforeCaret(editor)); final CustomTemplateCallback callback = new CustomTemplateCallback(editor, file); if (customLiveTemplate.isApplicable(currentLineBeforeCaret, callback)) { int offset = editor.getCaretModel().getOffset(); @@ -370,7 +386,12 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo editor.getCaretModel().moveToOffset(templateStart); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); editor.getSelectionModel().removeSelection(); - templateState.start(template, processor, argument); + Map predefinedVarValues = null; + if (argument != null) { + predefinedVarValues = new HashMap(); + predefinedVarValues.put(TemplateImpl.ARG, argument); + } + templateState.start(template, processor, predefinedVarValues); } }, CodeInsightBundle.message("insert.code.template.command"), null); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index 36283f15a0..ef9ecf28a6 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -71,7 +71,7 @@ public class TemplateState implements Disposable { private TemplateImpl myTemplate; private TemplateSegments mySegments = null; - private String myArgument; + private Map myPredefinedVariableValues; private RangeMarker myTemplateRange = null; private final ArrayList myTabStopHighlighters = new ArrayList(); @@ -172,10 +172,9 @@ public class TemplateState implements Disposable { if (variableName.equals(TemplateImpl.END)) { return new TextResult(""); } - if (variableName.equals(TemplateImpl.ARG) && myArgument != null) { - return new TextResult(myArgument); + if (myPredefinedVariableValues != null && myPredefinedVariableValues.containsKey(variableName)) { + return new TextResult(myPredefinedVariableValues.get(variableName)); } - CharSequence text = myDocument.getCharsSequence(); int segmentNumber = myTemplate.getVariableSegmentNumber(variableName); if (segmentNumber < 0) { @@ -235,7 +234,9 @@ public class TemplateState implements Disposable { } } - public void start(TemplateImpl template, @Nullable final PairProcessor processor, @Nullable String argument) { + public void start(TemplateImpl template, + @Nullable final PairProcessor processor, + @Nullable Map predefinedVarValues) { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); myProcessor = processor; @@ -271,8 +272,8 @@ public class TemplateState implements Disposable { myCurrentVariableNumber = -1; mySegments = new TemplateSegments(myEditor); myTemplate = template; - myArgument = argument; - + //myArgument = argument; + myPredefinedVariableValues = predefinedVarValues; if (template.isInline()) { int caretOffset = myEditor.getCaretModel().getOffset(); @@ -316,7 +317,7 @@ public class TemplateState implements Disposable { calcResults(false); calcResults(false); //Fixed SCR #[vk500] : all variables should be recalced twice on start. - doReformat(); + doReformat(null); fireTemplateExpanded(); @@ -335,12 +336,19 @@ public class TemplateState implements Disposable { }); } - private void doReformat() { + public void doReformat(final TextRange range) { + RangeMarker rangeMarker = null; + if (range != null) { + rangeMarker = myDocument.createRangeMarker(range); + rangeMarker.setGreedyToLeft(true); + rangeMarker.setGreedyToRight(true); + } + final RangeMarker finalRangeMarker = rangeMarker; final Runnable action = new Runnable() { public void run() { IntArrayList indices = initEmptyVariables(); mySegments.setSegmentsGreedy(false); - reformat(); + reformat(finalRangeMarker); mySegments.setSegmentsGreedy(true); restoreEmptyVariables(indices); } @@ -660,7 +668,7 @@ public class TemplateState implements Disposable { if (previousVariableNumber >= 0) { focusCurrentHighlighter(false); calcResults(false); - doReformat(); + doReformat(null); setCurrentVariableNumber(previousVariableNumber); focusCurrentExpression(); currentVariableChanged(oldVar); @@ -683,7 +691,7 @@ public class TemplateState implements Disposable { calcResults(false); ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { - reformat(); + reformat(null); } }); finishTemplateEditing(false); @@ -691,7 +699,7 @@ public class TemplateState implements Disposable { } focusCurrentHighlighter(false); calcResults(false); - doReformat(); + doReformat(null); setCurrentVariableNumber(nextVariableNumber); focusCurrentExpression(); currentVariableChanged(oldVar); @@ -737,7 +745,7 @@ public class TemplateState implements Disposable { public void gotoEnd(boolean brokenOff) { calcResults(false); - doReformat(); + doReformat(null); finishTemplateEditing(brokenOff); } @@ -807,7 +815,7 @@ public class TemplateState implements Disposable { return false; } String variableName = myTemplate.getVariableNameAt(currentVariableNumber); - if (!(TemplateImpl.ARG.equals(variableName) && myArgument != null)) { + if (!(myPredefinedVariableValues != null && myPredefinedVariableValues.containsKey(variableName))) { if (myTemplate.isAlwaysStopAt(currentVariableNumber)) { return true; } @@ -915,7 +923,7 @@ public class TemplateState implements Disposable { } } - private void reformat() { + private void reformat(RangeMarker rangeMarkerToReformat) { final PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(myDocument); if (file != null) { CodeStyleManager style = CodeStyleManager.getInstance(myProject); @@ -932,7 +940,9 @@ public class TemplateState implements Disposable { PsiElement marker = style.insertNewLineIndentMarker(file, endVarOffset); if (marker != null) rangeMarker = myDocument.createRangeMarker(marker.getTextRange()); } - style.reformatText(file, myTemplateRange.getStartOffset(), myTemplateRange.getEndOffset()); + int startOffset = rangeMarkerToReformat != null ? rangeMarkerToReformat.getStartOffset() : myTemplateRange.getStartOffset(); + int endOffset = rangeMarkerToReformat != null ? rangeMarkerToReformat.getEndOffset() : myTemplateRange.getEndOffset(); + style.reformatText(file, startOffset, endOffset); PsiDocumentManager.getInstance(myProject).commitDocument(myDocument); PsiDocumentManager.getInstance(myProject).doPostponedOperationsAndUnblockDocument(myDocument); @@ -1015,7 +1025,7 @@ public class TemplateState implements Disposable { private void fireTemplateExpanded() { TemplateEditingListener[] listeners = myListeners.toArray(new TemplateEditingListener[myListeners.size()]); for (TemplateEditingListener listener : listeners) { - listener.templateExpanded(myTemplate); + listener.templateExpanded(this, myTemplate); } } -- 2.11.4.GIT