diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorFromCallFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorFromCallFix.java index 0527f0b18f7d..e2e669006723 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorFromCallFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorFromCallFix.java @@ -65,7 +65,7 @@ public class CreateConstructorFromCallFix extends CreateFromUsageBaseFix { editor.getCaretModel().moveToOffset(textRange.getStartOffset()); startTemplate(editor, template, project, new TemplateEditingAdapter() { - public void templateFinished(Template template) { + public void templateFinished(Template template, boolean brokenOff) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { try { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorFromThisOrSuperFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorFromThisOrSuperFix.java index 5b650ba422dd..f954e5cefb7a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorFromThisOrSuperFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorFromThisOrSuperFix.java @@ -108,7 +108,7 @@ public abstract class CreateConstructorFromThisOrSuperFix extends CreateFromUsag editor.getCaretModel().moveToOffset(textRange.getStartOffset()); startTemplate(editor, template, project, new TemplateEditingAdapter() { - public void templateFinished(Template template) { + public void templateFinished(Template template, boolean brokenOff) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { try { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalVarFromInstanceofAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalVarFromInstanceofAction.java index 14f04687e1c4..9e80437e43a9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalVarFromInstanceofAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalVarFromInstanceofAction.java @@ -166,7 +166,7 @@ public class CreateLocalVarFromInstanceofAction extends BaseIntentionAction { newEditor.getDocument().deleteString(range.getStartOffset(), range.getEndOffset()); CreateFromUsageBaseFix.startTemplate(newEditor, template, project, new TemplateEditingAdapter() { - public void templateFinished(Template template) { + public void templateFinished(Template template, boolean brokenOff) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java index bc461090e45c..bc3a15c092e4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java @@ -231,7 +231,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { if (!shouldBeAbstract) { startTemplate(newEditor, template, project, new TemplateEditingAdapter() { - public void templateFinished(Template template) { + public void templateFinished(Template template, boolean brokenOff) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { PsiDocumentManager.getInstance(project).commitDocument(newEditor.getDocument()); diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersHandlerBase.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersHandlerBase.java index a9755aa83b2d..9d9da0b92338 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersHandlerBase.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersHandlerBase.java @@ -145,7 +145,7 @@ public abstract class GenerateMembersHandlerBase implements CodeInsightActionHan editor.getCaretModel().moveToOffset(offset); editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); TemplateManager.getInstance(myProject).startTemplate(editor, template, new TemplateEditingAdapter() { - public void templateFinished(Template template) { + public void templateFinished(Template template, boolean brokenOff) { if (index + 1 < templates.size()){ ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { diff --git a/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java b/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java index ab864f3aeece..130e6f58b4d1 100644 --- a/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java +++ b/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java @@ -141,7 +141,7 @@ public class TestIntegrationUtils { if (!automatic) { adapter = new TemplateEditingAdapter() { @Override - public void templateFinished(Template template) { + public void templateFinished(Template template, boolean brokenOff) { ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java index c5dbfd9d60ac..6bd5b3c562d9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java @@ -153,6 +153,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware { else { new ReformatCodeProcessor(project, dir, dialog.isIncludeSubdirectories()).run(); } + return; } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java index bd7edb0b857c..977adac61580 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/TemplateInsertHandler.java @@ -67,7 +67,7 @@ public abstract class TemplateInsertHandler implements InsertHandler { final RangeMarker offsetRangeMarker = document.createRangeMarker(templateStartOffset, templateStartOffset); TemplateManager.getInstance(editor.getProject()).startTemplate(editor, template, new TemplateEditingAdapter() { - public void templateFinished(Template template) { + public void templateFinished(Template template, boolean brokenOff) { lookupItem.setAttribute(EXPANDED_TEMPLATE_ATTR, Boolean.TRUE); if (!offsetRangeMarker.isValid()) return; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomLiveTemplate.java b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomLiveTemplate.java new file mode 100644 index 000000000000..74912fddebad --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomLiveTemplate.java @@ -0,0 +1,32 @@ +/* + * 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 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); +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java new file mode 100644 index 000000000000..d7b4bdeb5f68 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java @@ -0,0 +1,124 @@ +/* + * 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 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 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, 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); + } + return templateFinished[0]; + } + + private static List 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; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/Iteration.java b/platform/lang-impl/src/com/intellij/codeInsight/template/Iteration.java new file mode 100644 index 000000000000..3c7b7ee1959d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/Iteration.java @@ -0,0 +1,48 @@ +/* + * 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(); +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingAdapter.java b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingAdapter.java index c29d5ed0ecef..743f8eb708f7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingAdapter.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingAdapter.java @@ -26,7 +26,7 @@ public abstract class TemplateEditingAdapter implements TemplateEditingListener public void beforeTemplateFinished(final TemplateState state, final Template template) { } - public void templateFinished(Template template) { + public void templateFinished(Template template, boolean brokenOff) { } public void templateCancelled(Template template) { @@ -34,4 +34,7 @@ public abstract class TemplateEditingAdapter implements TemplateEditingListener public void currentVariableChanged(TemplateState templateState, Template template, int oldIndex, int newIndex) { } + + public void templateExpanded(Template template) { + } } 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 990f3767e1d4..0412c9a0a097 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingListener.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateEditingListener.java @@ -23,7 +23,8 @@ import com.intellij.codeInsight.template.impl.TemplateState; */ public interface TemplateEditingListener { void beforeTemplateFinished(TemplateState state, Template template); - void templateFinished(Template template); + void templateFinished(Template template, boolean brokenOff); void templateCancelled(Template template); void currentVariableChanged(TemplateState templateState, Template template, int oldIndex, int newIndex); + void templateExpanded(Template template); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateInvokationListener.java b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateInvokationListener.java new file mode 100644 index 000000000000..0ad5a09a5a1f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateInvokationListener.java @@ -0,0 +1,23 @@ +/* + * 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); +} 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 9a67f8ab31e9..f0369f22b35e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java @@ -1,19 +1,18 @@ - /* - * 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; @@ -36,8 +35,15 @@ public abstract class TemplateManager { 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 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 callback); public abstract boolean startTemplate(@NotNull Editor editor, char shortcutChar); 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 566327bb87ca..302e249ba15d 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,21 +132,22 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo } 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 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 processor) { + final PairProcessor processor, + boolean inSeparateCommand) { final TemplateState templateState = initTemplateState(editor); templateState.getProperties().put(ExpressionContext.SELECTION, selectionString); @@ -154,7 +155,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo 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() { @@ -168,7 +169,13 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo } 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(); @@ -180,7 +187,14 @@ 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); + 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) { @@ -200,12 +214,47 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo } } + 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 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 processor) { + final Document document = editor.getDocument(); + CharSequence text = document.getCharsSequence(); final int caretOffset = editor.getCaretModel().getOffset(); @@ -258,15 +307,14 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo else { ListTemplatesHandler.showTemplatesLookup(myProject, editor, candidate2Argument); } - return true; } - private static List findMatchingTemplates(CharSequence text, - int caretOffset, - char shortcutChar, - TemplateSettings settings, - boolean hasArgument) { + public static List findMatchingTemplates(CharSequence text, + int caretOffset, + char shortcutChar, + TemplateSettings settings, + boolean hasArgument) { String key; List candidates = Collections.emptyList(); for (int i = settings.getMaxKeyLength(); i >= 1; i--) { @@ -318,7 +366,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo }, CodeInsightBundle.message("insert.code.template.command"), null); } - private static List filterApplicableCandidates(PsiFile file, int caretOffset, List candidates) { + public static List filterApplicableCandidates(PsiFile file, int caretOffset, List candidates) { List result = new ArrayList(); for (TemplateImpl candidate : candidates) { if (isApplicable(file, caretOffset - candidate.getKey().length(), candidate)) { 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 98b09560cae8..36283f15a0e3 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 @@ -318,9 +318,11 @@ public class TemplateState implements Disposable { calcResults(false); //Fixed SCR #[vk500] : all variables should be recalced twice on start. doReformat(); + fireTemplateExpanded(); + int nextVariableNumber = getNextVariableNumber(-1); if (nextVariableNumber == -1) { - finishTemplateEditing(); + finishTemplateEditing(false); } else { setCurrentVariableNumber(nextVariableNumber); @@ -536,7 +538,7 @@ public class TemplateState implements Disposable { final TextResult value = getVariableValue(variableName); if (value != null && value.getText().length() > 0) { if (!myProcessor.process(variableName, value.getText())) { - finishTemplateEditing(); // nextTab(); ? + finishTemplateEditing(false); // nextTab(); ? return; } } @@ -684,7 +686,7 @@ public class TemplateState implements Disposable { reformat(); } }); - finishTemplateEditing(); + finishTemplateEditing(false); return; } focusCurrentHighlighter(false); @@ -733,13 +735,17 @@ public class TemplateState implements Disposable { }; } - public void gotoEnd() { + public void gotoEnd(boolean brokenOff) { calcResults(false); doReformat(); - finishTemplateEditing(); + finishTemplateEditing(brokenOff); } - private void finishTemplateEditing() { + public void gotoEnd() { + gotoEnd(false); + } + + private void finishTemplateEditing(boolean brokenOff) { if (myTemplate == null) return; LookupManager.getInstance(myProject).hideActiveLookup(); @@ -772,7 +778,7 @@ public class TemplateState implements Disposable { setCurrentVariableNumber(-1); currentVariableChanged(oldVar); ((TemplateManagerImpl)TemplateManager.getInstance(myProject)).clearTemplateState(editor); - fireTemplateFinished(); + fireTemplateFinished(brokenOff); myListeners.clear(); myProject = null; } @@ -990,12 +996,12 @@ public class TemplateState implements Disposable { myListeners.add(listener); } - private void fireTemplateFinished() { + private void fireTemplateFinished(boolean brokenOff) { if (myFinished) return; myFinished = true; TemplateEditingListener[] listeners = myListeners.toArray(new TemplateEditingListener[myListeners.size()]); for (TemplateEditingListener listener : listeners) { - listener.templateFinished(myTemplate); + listener.templateFinished(myTemplate, brokenOff); } } @@ -1006,6 +1012,13 @@ public class TemplateState implements Disposable { } } + 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) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EscapeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EscapeHandler.java index 2ef75be62b69..943bb7d7210b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EscapeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/EscapeHandler.java @@ -36,7 +36,7 @@ public class EscapeHandler extends EditorActionHandler { final TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); if (templateState != null && !templateState.isFinished()) { CommandProcessor.getInstance().setCurrentCommandName(CodeInsightBundle.message("finish.template.command")); - templateState.gotoEnd(); + templateState.gotoEnd(true); return; } } diff --git a/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java b/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java index eb955c90b885..3b39633d514e 100644 --- a/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java +++ b/platform/lang-impl/src/com/intellij/execution/RunManagerEx.java @@ -79,4 +79,7 @@ public abstract class RunManagerEx extends RunManager { public abstract Collection getSortedConfigurations(); public abstract void removeConfiguration(RunnerAndConfigurationSettingsImpl settings); + + public abstract void addRunManagerListener(RunManagerListener listener); + public abstract void removeRunManagerListener(RunManagerListener listener); } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/RunManagerListener.java b/platform/lang-impl/src/com/intellij/execution/RunManagerListener.java new file mode 100644 index 000000000000..3f89a3895079 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/RunManagerListener.java @@ -0,0 +1,20 @@ +/* + * 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.execution; + +public interface RunManagerListener { + void beforeRunTasksChanged(); +} diff --git a/platform/lang-impl/src/com/intellij/execution/impl/BaseExecuteBeforeRunDialog.java b/platform/lang-impl/src/com/intellij/execution/impl/BaseExecuteBeforeRunDialog.java index 374b626198cb..8472d0adb3ff 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/BaseExecuteBeforeRunDialog.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/BaseExecuteBeforeRunDialog.java @@ -208,6 +208,7 @@ public abstract class BaseExecuteBeforeRunDialog extend } } + ((RunManagerImpl)RunManagerEx.getInstanceEx(myProject)).fireBeforeRunTasksUpdated(); close(OK_EXIT_CODE); } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java index b7ebeeca4082..b3169c1e936e 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java @@ -68,6 +68,8 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, private List myUnloadedElements = null; private JDOMExternalizableStringList myOrder = new JDOMExternalizableStringList(); + private final List myListeners = ContainerUtil.createEmptyCOWList(); + public RunManagerImpl(final Project project, PropertiesComponent propertiesComponent) { myConfig = new RunManagerConfig(propertiesComponent, this); @@ -468,6 +470,8 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, myOrder.readExternal(parentNode); mySelectedConfig = parentNode.getAttributeValue(SELECTED_ATTR); + + fireBeforeRunTasksUpdated(); } public void readContext(Element parentNode) throws InvalidDataException { @@ -744,10 +748,12 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, //} } myConfigurationToBeforeTasksMap.put(runConfiguration, taskMap); + fireBeforeRunTasksUpdated(); } public final void resetBeforeRunTasks(final RunConfiguration runConfiguration) { myConfigurationToBeforeTasksMap.remove(runConfiguration); + fireBeforeRunTasksUpdated(); } public void addConfiguration(final RunnerAndConfigurationSettingsImpl settings, final boolean isShared) { @@ -768,6 +774,22 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, } } + @Override + public void addRunManagerListener(RunManagerListener listener) { + myListeners.add(listener); + } + + @Override + public void removeRunManagerListener(RunManagerListener listener) { + myListeners.remove(listener); + } + + public void fireBeforeRunTasksUpdated() { + for (RunManagerListener each : myListeners) { + each.beforeRunTasksChanged(); + } + } + private Map, BeforeRunTaskProvider> myBeforeStepsMap; private Map> myProviderKeysMap; diff --git a/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceManagerImpl.java b/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceManagerImpl.java index 984f9ad10ee4..765d3fad8220 100644 --- a/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceManagerImpl.java @@ -252,7 +252,7 @@ public class PathReferenceManagerImpl extends PathReferenceManager { for (Iterator it = set.iterator(); it.hasNext();) { PsiReference reference = it.next(); final TextRange range = reference.getRangeInElement(); - if (endOffset == -1 || range.getStartOffset() < endOffset) { + if (endOffset == -1 || range.getStartOffset() <= endOffset) { startOffset = Math.min(startOffset, range.getStartOffset()); endOffset = Math.max(range.getEndOffset(), endOffset); toAdd.add(reference); diff --git a/platform/lang-impl/src/com/intellij/openapi/paths/PsiDynaReference.java b/platform/lang-impl/src/com/intellij/openapi/paths/PsiDynaReference.java index 24bc4b35f7b9..9d1011363134 100644 --- a/platform/lang-impl/src/com/intellij/openapi/paths/PsiDynaReference.java +++ b/platform/lang-impl/src/com/intellij/openapi/paths/PsiDynaReference.java @@ -42,7 +42,7 @@ public class PsiDynaReference extends PsiReferenceBase implements FileReferenceOwner, PsiPolyVariantReference, QuickFixProvider, LocalQuickFixProvider, EmptyResolveMessageProvider { private final List myReferences = new ArrayList(); - private int myChoosenOne = -1; + private int myChosenOne = -1; private ResolveResult[] myCachedResult; public PsiDynaReference(final T psiElement) { @@ -170,23 +170,23 @@ public class PsiDynaReference extends PsiReferenceBase @Nullable private PsiReference chooseReference(){ - if(myChoosenOne != -1){ - return myReferences.get(myChoosenOne); + if(myChosenOne != -1){ + return myReferences.get(myChosenOne); } boolean flag = false; for(int i = 0; i < myReferences.size(); i++){ final PsiReference reference = myReferences.get(i); if(reference.isSoft() && flag) continue; if(!reference.isSoft() && !flag){ - myChoosenOne = i; + myChosenOne = i; flag = true; continue; } if(reference.resolve() != null){ - myChoosenOne = i; + myChosenOne = i; } } - return myChoosenOne >= 0 ? myReferences.get(myChoosenOne) : null; + return myChosenOne >= 0 ? myReferences.get(myChosenOne) : null; } public void registerQuickfix(final HighlightInfo info, final PsiDynaReference reference) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java index d2ba8d1ad574..50e6dbdd2d47 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java @@ -192,6 +192,7 @@ public class FileReference implements FileReferenceOwner, PsiPolyVariantReferenc return _text; } + @NotNull public Object[] getVariants() { final String s = getText(); if (s != null && s.equals("/")) { diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java index d5fbe7650153..8b5f4db0883f 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java @@ -202,8 +202,8 @@ public class VariableInplaceRenamer { } @Override - public void templateFinished(Template template) { - super.templateFinished(template); + public void templateFinished(Template template, boolean brokenOff) { + super.templateFinished(template, brokenOff); if (myNewName != null) { performAutomaticRename(myNewName, PsiTreeUtil.getParentOfType(containingFile.findElementAt(renameOffset), PsiNameIdentifierOwner.class)); } diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index c3b4b27d47d6..1540d23fe7cc 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -20,7 +20,7 @@ actionSystem.keyGestures.enabled=false actionSystem.suspendFocusTransferIfApplicationInactive=true actionSystem.noContextComponentWhileFocusTransfer=true -ide.debugMode=true +ide.debugMode=false ide.debugMode.description=Record additonal information to make bug reports more informative ide.forcedShowTooltip=alt ide.forcedShowTooltip.description=Shortcut for forced show tooltip diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index d5172d75f071..e44942b97fa2 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -174,6 +174,7 @@ + diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index 1ad2878f27c1..4142e22f93c1 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -285,6 +285,7 @@ implementationClass="com.intellij.codeInsight.hint.XmlImplementationTextSelectioner"/> + diff --git a/platform/testFramework/src/com/intellij/testFramework/FileTreeAccessFilter.java b/platform/testFramework/src/com/intellij/testFramework/FileTreeAccessFilter.java index 4123eab292db..87670a70423a 100755 --- a/platform/testFramework/src/com/intellij/testFramework/FileTreeAccessFilter.java +++ b/platform/testFramework/src/com/intellij/testFramework/FileTreeAccessFilter.java @@ -30,11 +30,12 @@ import java.util.Set; */ public class FileTreeAccessFilter implements VirtualFileFilter { protected final Set myAddedClasses = new THashSet(); + private boolean myTreeAccessAllowed; public boolean accept(VirtualFile file) { if (file instanceof VirtualFileWindow) return false; - if (myAddedClasses.contains(file)) return false; + if (myAddedClasses.contains(file) || myTreeAccessAllowed) return false; FileType fileType = FileTypeManager.getInstance().getFileTypeByFile(file); return (fileType == StdFileTypes.JAVA || fileType == StdFileTypes.CLASS) && !file.getName().equals("package-info.java"); @@ -43,4 +44,8 @@ public class FileTreeAccessFilter implements VirtualFileFilter { public void allowTreeAccessForFile(VirtualFile file) { myAddedClasses.add(file); } + + public void allowTreeAccessForAllFiles() { + myTreeAccessAllowed = true; + } } diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 7fc5616a2444..bb51060993f7 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -438,13 +438,17 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da CompletionProgressIndicator.cleanupForNextTest(); if (checkForEditors) { - final Editor[] allEditors = EditorFactory.getInstance().getAllEditors(); - if (allEditors.length > 0) { - for (Editor allEditor : allEditors) { - EditorFactory.getInstance().releaseEditor(allEditor); - } - fail("Unreleased editors: " + allEditors.length); + checkEditorsReleased(); + } + } + + public static void checkEditorsReleased() { + final Editor[] allEditors = EditorFactory.getInstance().getAllEditors(); + if (allEditors.length > 0) { + for (Editor allEditor : allEditors) { + EditorFactory.getInstance().releaseEditor(allEditor); } + fail("Unreleased editors: " + allEditors.length); } } diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index 1487f0648369..8bbf90165ca0 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -279,7 +279,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro } protected void tearDown() throws Exception { - LightPlatformTestCase.doTearDown(getProject(), ourApplication, true); + LightPlatformTestCase.doTearDown(getProject(), ourApplication, false); try { checkForSettingsDamage(); @@ -317,6 +317,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro //cleanTheWorld(); myEditorListenerTracker.checkListenersLeak(); myThreadTracker.checkLeak(); + LightPlatformTestCase.checkEditorsReleased(); } finally { myProjectManager = null; diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java index 937c8d7cacc8..e61cb2610f56 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java @@ -325,4 +325,6 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { void renameElement(PsiElement element, String newName) throws Exception; void allowTreeAccessForFile(VirtualFile file); + + void allowTreeAccessForAllFiles(); } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 5d285a318292..42174f8acfe4 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1194,6 +1194,10 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig myJavaFilesFilter.allowTreeAccessForFile(file); } + public void allowTreeAccessForAllFiles() { + myJavaFilesFilter.allowTreeAccessForAllFiles(); + } + static class SelectionAndCaretMarkupLoader { final String newFileText; final RangeMarker caretMarker; diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java index 73e9eeaa9398..23460814d10b 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyIdeaTestFixtureImpl.java @@ -118,6 +118,7 @@ class HeavyIdeaTestFixtureImpl extends BaseFixture implements HeavyIdeaTestFixtu myEditorListenerTracker.checkListenersLeak(); myThreadTracker.checkLeak(); + LightPlatformTestCase.checkEditorsReleased(); } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/explorer/AntExplorer.java b/plugins/ant/src/com/intellij/lang/ant/config/explorer/AntExplorer.java index cbce55dcd503..8d850cc65254 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/explorer/AntExplorer.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/explorer/AntExplorer.java @@ -15,6 +15,8 @@ */ package com.intellij.lang.ant.config.explorer; +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.RunManagerListener; import com.intellij.ide.CommonActionsManager; import com.intellij.ide.DataManager; import com.intellij.ide.TreeExpander; @@ -140,6 +142,12 @@ public class AntExplorer extends SimpleToolWindowPanel implements DataProvider { setContent(new JScrollPane(myTree)); ToolTipManager.sharedInstance().registerComponent(myTree); myKeymapListener = new KeymapListener(); + + RunManagerEx.getInstanceEx(myProject).addRunManagerListener(new RunManagerListener() { + public void beforeRunTasksChanged() { + myBuilder.refresh(); + } + }); } public void dispose() { @@ -621,7 +629,6 @@ public class AntExplorer extends SimpleToolWindowPanel implements DataProvider { public void actionPerformed(AnActionEvent e) { final AntExecuteBeforeRunDialog dialog = new AntExecuteBeforeRunDialog(myProject, myTarget); dialog.show(); - myBuilder.refresh(); } public void update(AnActionEvent e) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java index ab2093c92f85..9f5a7dadeb40 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndex.java @@ -368,8 +368,6 @@ public class MavenIndex { } private void updateData(ProgressIndicator progress) throws IOException, UnsupportedExistingLuceneIndexException { - progress.setText2(IndicesBundle.message("maven.indices.updating.saving")); - String newDataDirName; IndexData newData; @@ -391,7 +389,6 @@ public class MavenIndex { synchronized (this) { IndexData oldData = myData; - String oldDataDir = myDataDirName; myData = newData; myDataDirName = newDataDirName; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndicesManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndicesManager.java index 9db61a13546f..5eb65ee61a81 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndicesManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/indices/MavenIndicesManager.java @@ -89,11 +89,6 @@ public class MavenIndicesManager implements ApplicationComponent { } public void initComponent() { - ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { - public void run() { - doShutdown(); - } - }); } @TestOnly @@ -117,6 +112,12 @@ public class MavenIndicesManager implements ApplicationComponent { } }); + ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { + public void run() { + doShutdown(); + } + }); + loadUserArchetypes(); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java index d6737cdf9899..2f9497a9ac23 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java @@ -15,25 +15,33 @@ */ package org.jetbrains.idea.maven.navigator; +import com.intellij.execution.RunManagerEx; +import com.intellij.execution.RunManagerListener; +import com.intellij.ide.util.treeView.TreeState; import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; import com.intellij.ui.treeStructure.SimpleTree; import com.intellij.util.containers.ContainerUtil; +import org.jdom.Element; import org.jetbrains.annotations.TestOnly; import org.jetbrains.idea.maven.project.*; import org.jetbrains.idea.maven.tasks.MavenShortcutsManager; import org.jetbrains.idea.maven.tasks.MavenTasksManager; import org.jetbrains.idea.maven.utils.MavenIcons; +import org.jetbrains.idea.maven.utils.MavenLog; import org.jetbrains.idea.maven.utils.MavenUtil; import org.jetbrains.idea.maven.utils.SimpleProjectComponent; @@ -43,7 +51,6 @@ import java.awt.*; import java.net.URL; import java.util.Collections; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; @State(name = "MavenProjectNavigator", storages = {@Storage(id = "default", file = "$WORKSPACE_FILE$")}) public class MavenProjectsNavigator extends SimpleProjectComponent implements PersistentStateComponent { @@ -52,8 +59,6 @@ public class MavenProjectsNavigator extends SimpleProjectComponent implements Pe private static final URL ADD_ICON_URL = MavenProjectsNavigator.class.getResource("/general/add.png"); private static final URL SYNC_ICON_URL = MavenProjectsNavigator.class.getResource("/actions/sync.png"); - private final AtomicBoolean myInitialized = new AtomicBoolean(false); - private MavenProjectsNavigatorState myState = new MavenProjectsNavigatorState(); private final MavenProjectsManager myProjectsManager; @@ -79,6 +84,17 @@ public class MavenProjectsNavigator extends SimpleProjectComponent implements Pe } public MavenProjectsNavigatorState getState() { + ApplicationManager.getApplication().assertIsDispatchThread(); + if (myStructure != null) { + try { + myState.treeState = new Element("root"); + TreeState.createOn(myTree).writeExternal(myState.treeState); + } + catch (WriteExternalException e) { + MavenLog.LOG.warn(e); + } + + } return myState; } @@ -169,6 +185,16 @@ public class MavenProjectsNavigator extends SimpleProjectComponent implements Pe }); } }); + + RunManagerEx.getInstanceEx(myProject).addRunManagerListener(new RunManagerListener() { + public void beforeRunTasksChanged() { + scheduleStructureRequest(new Runnable() { + public void run() { + myStructure.updateGoals(); + } + }); + } + }); } private void initToolWindow() { @@ -254,10 +280,26 @@ public class MavenProjectsNavigator extends SimpleProjectComponent implements Pe MavenUtil.invokeLater(myProject, new Runnable() { public void run() { if (!myToolWindow.isVisible()) return; - if (myStructure == null) { + + boolean shouldCreate = myStructure == null; + if (shouldCreate) { initStructure(); } + r.run(); + + if (shouldCreate) { + if (myState.treeState != null) { + TreeState treeState = new TreeState(); + try { + treeState.readExternal(myState.treeState); + treeState.applyTo(myTree); + } + catch (InvalidDataException e) { + MavenLog.LOG.info(e); + } + } + } } }); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorState.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorState.java index 68bf4040dab3..172ca21e9682 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorState.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorState.java @@ -15,8 +15,14 @@ */ package org.jetbrains.idea.maven.navigator; +import com.intellij.util.xmlb.annotations.Tag; +import org.jdom.Element; + public class MavenProjectsNavigatorState { public boolean groupStructurally = false; public boolean showIgnored = true; public boolean showBasicPhasesOnly = true; + + @Tag("treeState") + public Element treeState; } \ No newline at end of file diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsStructure.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsStructure.java index 856177159379..4af25939d6b0 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsStructure.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsStructure.java @@ -1004,7 +1004,7 @@ public class MavenProjectsStructure extends SimpleTreeStructure { @Override public boolean isVisible() { // show regardless absence of children - return getDisplayKind() != DisplayKind.NEVER; + return super.isVisible() || getDisplayKind() != DisplayKind.NEVER; } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenBeforeRunTasksProvider.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenBeforeRunTasksProvider.java index 4d3f226b84a6..4dd15823f6e4 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenBeforeRunTasksProvider.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenBeforeRunTasksProvider.java @@ -94,8 +94,6 @@ public class MavenBeforeRunTasksProvider extends BeforeRunTaskProvider desc = getTaskDesc(e); new MavenExecuteBeforeRunDialog(MavenActionUtil.getProject(e), desc.first, desc.second).show(); - MavenTasksManager.getInstance(MavenActionUtil.getProject(e)).fireTasksChanged(); } protected Pair getTaskDesc(AnActionEvent e) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenJDOMUtil.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenJDOMUtil.java index e7b730a394f7..ea0ac1474ee4 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenJDOMUtil.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenJDOMUtil.java @@ -55,7 +55,7 @@ public class MavenJDOMUtil { return doRead(text, handler); } - @NotNull + @Nullable public static Element read(byte[] bytes, @Nullable ErrorHandler handler) { return doRead(CharsetToolkit.bytesToString(bytes), handler); } diff --git a/plugins/maven/src/main/resources/IndicesBundle.properties b/plugins/maven/src/main/resources/IndicesBundle.properties index 824e264849ff..b239f68af9b7 100644 --- a/plugins/maven/src/main/resources/IndicesBundle.properties +++ b/plugins/maven/src/main/resources/IndicesBundle.properties @@ -7,6 +7,5 @@ maven.index.updated.error=Error maven.indices.updating=Updating Maven Repository Indices... maven.indices.updating.index=Updating [{0}] {1} maven.indices.updating.processing=Processing indices... -maven.indices.updating.saving=Saving indices... repository.plugin.corrupt={0} not a Maven 2 plugin file repository.plugin.title=Opening Maven plugin file \ No newline at end of file diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/indices/MavenIndicesTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/indices/MavenIndicesTest.java index 5ff0ba8a3340..bae55479e089 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/indices/MavenIndicesTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/indices/MavenIndicesTest.java @@ -127,6 +127,16 @@ public class MavenIndicesTest extends MavenIndicesTestCase { assertUnorderedElementsAreEqual(i.getGroupIds(), "jmock"); } + public void testClearingUpdateDirAfterUpdate() throws Exception { + ignore(); + //MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL); + // + //myIndices.updateOrRepair(i, myEmbedder, true, new EmptyProgressIndicator()); + //assertUnorderedElementsAreEqual(i.getGroupIds(), "junit"); + // + //assertFalse(i.getUpdateDir().exists()); + } + public void testAddingRemote() throws Exception { MavenIndex i = myIndices.add("id", "file:///" + myRepositoryHelper.getTestDataPath("remote"), MavenIndex.Kind.REMOTE); myIndices.updateOrRepair(i, myEmbedder, true, new EmptyProgressIndicator()); @@ -140,6 +150,7 @@ public class MavenIndicesTest extends MavenIndicesTestCase { //shouldn't throw 'The existing index is for repository [remote] and not for repository [xxx]' myIndices.updateOrRepair(i, myEmbedder, true, new EmptyProgressIndicator()); + assertUnorderedElementsAreEqual(i.getGroupIds(), "junit"); } public void testDoNotAddSameIndexTwice() throws Exception { diff --git a/xml/impl/src/com/intellij/codeInsight/completion/ExtendedTagInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/ExtendedTagInsertHandler.java index d935312f634e..5be551653479 100644 --- a/xml/impl/src/com/intellij/codeInsight/completion/ExtendedTagInsertHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/completion/ExtendedTagInsertHandler.java @@ -98,7 +98,7 @@ public class ExtendedTagInsertHandler extends XmlTagInsertHandler { try { final String prefixByNamespace = getPrefixByNamespace(file, myNamespace); if (myNamespacePrefix != null || StringUtil.isEmpty(prefixByNamespace)) { - final String nsPrefix = myNamespacePrefix == null ? suggestPrefix(file) : myNamespacePrefix; + final String nsPrefix = myNamespacePrefix == null ? suggestPrefix(file, myNamespace) : myNamespacePrefix; extension.insertNamespaceDeclaration(file, editor, Collections.singleton(myNamespace), nsPrefix, runAfter); FeatureUsageTracker.getInstance().triggerFeatureUsed(XmlCompletionContributor.TAG_NAME_COMPLETION_FEATURE); } else { @@ -130,12 +130,12 @@ public class ExtendedTagInsertHandler extends XmlTagInsertHandler { } @Nullable - protected String suggestPrefix(XmlFile file) { - if (myNamespace == null) { + public static String suggestPrefix(XmlFile file, @Nullable String namespace) { + if (namespace == null) { return null; } for (XmlSchemaProvider provider : XmlSchemaProvider.getAvailableProviders(file)) { - String prefix = provider.getDefaultPrefix(myNamespace, file); + String prefix = provider.getDefaultPrefix(namespace, file); if (prefix != null) { return prefix; } diff --git a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java index 59fd8b5197fc..76234e05e4af 100644 --- a/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java +++ b/xml/impl/src/com/intellij/codeInsight/completion/XmlTagInsertHandler.java @@ -220,7 +220,7 @@ public class XmlTagInsertHandler implements InsertHandler { final boolean weInsertedSomeCodeThatCouldBeInvalidated1 = weInsertedSomeCodeThatCouldBeInvalidated; templateManager.startTemplate(editor, template, new TemplateEditingAdapter() { - public void templateFinished(final Template template) { + public void templateFinished(final Template template, boolean brokenOff) { final int offset = editor.getCaretModel().getOffset(); if (weInsertedSomeCodeThatCouldBeInvalidated1 && diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java index 5029f682a745..91e3b8d11f19 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/CreateNSDeclarationIntentionFix.java @@ -131,19 +131,26 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi project, new StringToAttributeProcessor() { public void doSomethingWithGivenStringToProduceXmlAttributeNowPlease(@NotNull final String namespace) throws IncorrectOperationException { - if (StringUtil.isEmpty(myNamespacePrefix)) { + String prefix = myNamespacePrefix; + if (StringUtil.isEmpty(prefix)) { final XmlExtension extension = XmlExtension.getExtension(myFile); final XmlFile xmlFile = extension.getContainingFile(myElement); - final String prefixByNamespace = ExtendedTagInsertHandler.getPrefixByNamespace(xmlFile, namespace); - if (prefixByNamespace != null) { - ExtendedTagInsertHandler.qualifyWithPrefix(prefixByNamespace, myElement); + prefix = ExtendedTagInsertHandler.getPrefixByNamespace(xmlFile, namespace); + if (StringUtil.isNotEmpty(prefix)) { + ExtendedTagInsertHandler.qualifyWithPrefix(prefix, myElement); return; + } else { + prefix = ExtendedTagInsertHandler.suggestPrefix(xmlFile, namespace); + if (StringUtil.isNotEmpty(prefix)) { + ExtendedTagInsertHandler.qualifyWithPrefix(prefix, myElement); + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); + } } } final int offset = editor.getCaretModel().getOffset(); final RangeMarker marker = editor.getDocument().createRangeMarker(offset, offset); final XmlExtension extension = XmlExtension.getExtension(file); - extension.insertNamespaceDeclaration((XmlFile)file, editor, Collections.singleton(namespace), myNamespacePrefix, new XmlExtension.Runner() { + extension.insertNamespaceDeclaration((XmlFile)file, editor, Collections.singleton(namespace), prefix, new XmlExtension.Runner() { public void run(final String param) throws IncorrectOperationException { if (namespace.length() > 0) { editor.getCaretModel().moveToOffset(marker.getStartOffset()); diff --git a/xml/impl/src/com/intellij/codeInsight/template/XmlCustomLiveTemplate.java b/xml/impl/src/com/intellij/codeInsight/template/XmlCustomLiveTemplate.java new file mode 100644 index 000000000000..41f4ccbbda4e --- /dev/null +++ b/xml/impl/src/com/intellij/codeInsight/template/XmlCustomLiveTemplate.java @@ -0,0 +1,459 @@ +/* + * 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.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.psi.xml.XmlFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * @author Eugene.Kudelevsky + */ +public class XmlCustomLiveTemplate implements CustomLiveTemplate { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.template.XmlCustomLiveTemplate"); + + private static final String POSSIBLE_OPERATIONS = ">+*"; + private static final char MARKER = '$'; + + private static enum MyState { + OPERATION, WORD, AFTER_NUMBER, NUMBER + } + + private static class MyToken { + } + + private static class MyMarkerToken extends MyToken { + } + + private static class MyTemplateToken extends MyToken { + final String myKey; + + MyTemplateToken(String key) { + myKey = key; + } + } + + private static class MyNumberToken extends MyToken { + final int myNumber; + + MyNumberToken(int number) { + myNumber = number; + } + } + + private static class MyOperationToken extends MyToken { + final char mySign; + + MyOperationToken(char sign) { + mySign = sign; + } + } + + private static boolean isTemplateKeyPart(char c) { + return !Character.isWhitespace(c) && POSSIBLE_OPERATIONS.indexOf(c) < 0; + } + + private static int parseNonNegativeInt(@NotNull String s) { + try { + return Integer.parseInt(s); + } + catch (Throwable ignored) { + } + return -1; + } + + @Nullable + private static List parse(@NotNull String text, @NotNull CustomTemplateCallback callback) { + text += MARKER; + StringBuilder templateKeyBuilder = new StringBuilder(); + List result = new ArrayList(); + for (int i = 0, n = text.length(); i < n; i++) { + char c = text.charAt(i); + if (i == n - 1 || POSSIBLE_OPERATIONS.indexOf(c) >= 0) { + String key = templateKeyBuilder.toString(); + templateKeyBuilder = new StringBuilder(); + int num = parseNonNegativeInt(key); + if (num > 0) { + result.add(new MyNumberToken(num)); + } + else { + if (key.length() == 0) { + return null; + } + if (!callback.isLiveTemplateApplicable(key) && key.indexOf('<') >= 0) { + return null; + } + result.add(new MyTemplateToken(key)); + } + result.add(i < n - 1 ? new MyOperationToken(c) : new MyMarkerToken()); + } + else if (isTemplateKeyPart(c)) { + templateKeyBuilder.append(c); + } + else { + return null; + } + } + return result; + } + + private static boolean check(@NotNull Collection tokens) { + MyState state = MyState.WORD; + for (MyToken token : tokens) { + if (token instanceof MyMarkerToken) { + break; + } + switch (state) { + case OPERATION: + if (token instanceof MyOperationToken) { + state = ((MyOperationToken)token).mySign == '*' ? MyState.NUMBER : MyState.WORD; + } + else { + return false; + } + break; + case WORD: + if (token instanceof MyTemplateToken) { + state = MyState.OPERATION; + } + else { + return false; + } + break; + case NUMBER: + if (token instanceof MyNumberToken) { + state = MyState.AFTER_NUMBER; + } + else { + return false; + } + break; + case AFTER_NUMBER: + if (token instanceof MyOperationToken && ((MyOperationToken)token).mySign != '*') { + state = MyState.WORD; + } + else { + return false; + } + break; + } + } + return state == MyState.OPERATION || state == MyState.AFTER_NUMBER; + } + + public boolean isApplicable(@NotNull String key, @NotNull CustomTemplateCallback callback) { + if (callback.getFile() instanceof XmlFile) { + List tokens = parse(key, callback); + if (tokens != null) { + return check(tokens); + } + } + return false; + } + + public void execute(@NotNull String key, @NotNull CustomTemplateCallback callback, @Nullable TemplateInvokationListener listener) { + List tokens = parse(key, callback); + assert tokens != null; + MyInterpreter interpreter = new MyInterpreter(tokens, 0, callback, MyState.WORD, listener); + interpreter.iter(); + } + + private static void fail() { + LOG.error("Input string was checked incorrectly during isApplicable() invokation"); + } + + private static boolean invokeTemplate(String key, CustomTemplateCallback callback, TemplateInvokationListener listener) { + if (callback.isLiveTemplateApplicable(key)) { + return callback.startTemplate(key, listener); + } + else { + TemplateImpl template = new TemplateImpl("", ""); + template.addTextSegment('<' + key + '>'); + template.addVariableSegment(TemplateImpl.END); + template.addTextSegment(""); + return callback.startTemplate(template, listener); + } + } + + private class MyInterpreter extends Iteration { + private final List myTokens; + private final CustomTemplateCallback myCallback; + private final TemplateInvokationListener myListener; + private MyState myState; + private int myEndOffset = -1; + + private MyInterpreter(List tokens, + int startIndex, + CustomTemplateCallback callback, + MyState initialState, + TemplateInvokationListener listener) { + super(startIndex, tokens.size(), null); + myTokens = tokens; + myCallback = callback; + myListener = listener; + myState = initialState; + } + + private void fixEndOffset() { + if (myEndOffset < 0) { + myEndOffset = getOffset(); + } + } + + private int getOffset() { + return myCallback.getEditor().getCaretModel().getOffset(); + } + + private int getTextLength() { + return myCallback.getEditor().getDocument().getCharsSequence().length(); + } + + private void moveCaret(int delta) { + myCallback.getEditor().getCaretModel().moveToOffset(delta); + } + + private void finish(boolean inSeparateEvent) { + Editor editor = myCallback.getEditor(); + if (myEndOffset >= 0) { + editor.getCaretModel().moveToOffset(myEndOffset); + } + editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + if (myListener != null) { + myListener.finished(inSeparateEvent, true); + } + } + + @Override + protected void next() { + if (myIndex == myMaxIndex - 1) { + finish(true); + } + super.next(); + } + + @Override + protected void iter() { + String templateKey = null; + int number = -1; + for (; myIndex < myMaxIndex; myIndex++) { + MyToken token = myTokens.get(myIndex); + switch (myState) { + case OPERATION: + if (templateKey != null) { + if (token instanceof MyMarkerToken || token instanceof MyOperationToken) { + final char sign = token instanceof MyOperationToken ? ((MyOperationToken)token).mySign : MARKER; + if (sign == MARKER || sign == '+') { + final int offsetBefore = getOffset(); + final int lengthBefore = getTextLength(); + TemplateInvokationListener listener = new TemplateInvokationListener() { + public void finished(boolean inSeparateEvent, boolean success) { + myState = MyState.WORD; + fixEndOffset(); + if (sign == '+') { + moveCaret(offsetBefore + getTextLength() - lengthBefore); + } + if (inSeparateEvent) { + next(); + } + } + }; + if (!invokeTemplate(templateKey, myCallback, listener)) { + return; + } + templateKey = null; + } + else if (sign == '>') { + if (!startTemplate(templateKey)) { + return; + } + templateKey = null; + } + else if (sign == '*') { + myState = MyState.NUMBER; + } + } + else { + fail(); + } + } + break; + case WORD: + if (token instanceof MyTemplateToken) { + templateKey = ((MyTemplateToken)token).myKey; + myState = MyState.OPERATION; + } + else { + fail(); + } + break; + case NUMBER: + if (token instanceof MyNumberToken) { + number = ((MyNumberToken)token).myNumber; + myState = MyState.AFTER_NUMBER; + } + else { + fail(); + } + break; + case AFTER_NUMBER: + if (token instanceof MyMarkerToken || token instanceof MyOperationToken) { + char sign = token instanceof MyOperationToken ? ((MyOperationToken)token).mySign : MARKER; + if (sign == MARKER || sign == '+') { + ConsecutiveTemplateInvokation iteration = new ConsecutiveTemplateInvokation(templateKey, number); + iteration.iter(); + if (!iteration.isFinished()) { + return; + } + templateKey = null; + } + else if (number > 1) { + ConsecutiveTemplateWithTailInvokation iteration = + new ConsecutiveTemplateWithTailInvokation(templateKey, myTokens, myIndex + 1, number); + iteration.iter(); + if (iteration.isFinished()) { + myIndex = myMaxIndex; + finish(false); + } + return; + } + else { + assert number == 1; + if (!startTemplate(templateKey)) { + return; + } + templateKey = null; + } + myState = MyState.WORD; + } + else { + fail(); + } + break; + } + } + finish(false); + } + + private boolean startTemplate(String templateKey) { + TemplateInvokationListener listener = new TemplateInvokationListener() { + public void finished(boolean inSeparateEvent, boolean success) { + myState = MyState.WORD; + if (inSeparateEvent) { + next(); + } + } + }; + if (!invokeTemplate(templateKey, myCallback, listener)) { + return false; + } + return true; + } + + private class ConsecutiveTemplateInvokation extends Iteration { + private final String myTemplateKey; + + public ConsecutiveTemplateInvokation(String templateKey, int count) { + super(0, count, MyInterpreter.this); + myTemplateKey = templateKey; + } + + @Override + protected void iter() { + final int offsetBefore = getOffset(); + final int lengthBefore = getTextLength(); + for (; myIndex < myMaxIndex; myIndex++) { + TemplateInvokationListener listener = new TemplateInvokationListener() { + public void finished(boolean inSeparateEvent, boolean success) { + myState = MyState.WORD; + fixEndOffset(); + moveCaret(offsetBefore + getTextLength() - lengthBefore); + if (inSeparateEvent) { + next(); + } + } + }; + if (!invokeTemplate(myTemplateKey, myCallback, listener)) { + return; + } + } + } + } + + private class ConsecutiveTemplateWithTailInvokation extends Iteration { + private final String myTemplateKey; + private final List myTokens; + private final int myTailStart; + + public ConsecutiveTemplateWithTailInvokation(String templateKey, List tokens, int tailStart, int count) { + super(0, count, null); + assert count > 1; + assert tailStart < tokens.size(); + myTemplateKey = templateKey; + myTailStart = tailStart; + myTokens = tokens; + } + + @Override + protected void next() { + if (myIndex == myMaxIndex - 1) { + finish(true); + } + super.next(); + } + + @Override + protected void iter() { + final int offsetBefore = getOffset(); + final int lengthBefore = getTextLength(); + for (; myIndex < myMaxIndex; myIndex++) { + final boolean[] flag = new boolean[]{false}; + TemplateInvokationListener listener = new TemplateInvokationListener() { + public void finished(boolean inSeparateEvent, boolean success) { + MyInterpreter interpreter = + new MyInterpreter(myTokens, myTailStart, myCallback, MyState.WORD, new TemplateInvokationListener() { + public void finished(boolean inSeparateEvent, boolean success) { + fixEndOffset(); + moveCaret(offsetBefore + getTextLength() - lengthBefore); + if (inSeparateEvent) { + next(); + } + } + }); + interpreter.iter(); + if (inSeparateEvent && interpreter.isFinished()) { + next(); + } + if (!interpreter.isFinished()) { + flag[0] = true; + } + } + }; + if (!invokeTemplate(myTemplateKey, myCallback, listener) || flag[0]) { + return; + } + } + } + } + } +} diff --git a/xml/impl/src/com/intellij/xml/DefaultXmlExtension.java b/xml/impl/src/com/intellij/xml/DefaultXmlExtension.java index 985295a8ad62..cce77d904eb1 100644 --- a/xml/impl/src/com/intellij/xml/DefaultXmlExtension.java +++ b/xml/impl/src/com/intellij/xml/DefaultXmlExtension.java @@ -185,7 +185,7 @@ public class DefaultXmlExtension extends XmlExtension { prefix = provider.getDefaultPrefix(namespace, file); } if (prefix == null) { - prefix = "x"; + prefix = ""; } final XmlElementFactory elementFactory = XmlElementFactory.getInstance(project); diff --git a/xml/impl/src/com/intellij/xml/refactoring/XmlTagInplaceRenamer.java b/xml/impl/src/com/intellij/xml/refactoring/XmlTagInplaceRenamer.java index c2184d72068f..9585643b775a 100644 --- a/xml/impl/src/com/intellij/xml/refactoring/XmlTagInplaceRenamer.java +++ b/xml/impl/src/com/intellij/xml/refactoring/XmlTagInplaceRenamer.java @@ -99,7 +99,7 @@ public class XmlTagInplaceRenamer { final Template t = buildTemplate(tag, pair); TemplateManager.getInstance(project).startTemplate(myEditor, t, new TemplateEditingAdapter() { - public void templateFinished(final Template template) { + public void templateFinished(final Template template, boolean brokenOff) { finish(); }