Merge branch 'master' of git@git.labs.intellij.net:idea/community

This commit is contained in:
Dmitry Jemerov
2010-02-10 18:05:41 +03:00
52 changed files with 991 additions and 100 deletions
@@ -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 {
@@ -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 {
@@ -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());
@@ -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());
@@ -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() {
@@ -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());
@@ -153,6 +153,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
else {
new ReformatCodeProcessor(project, dir, dialog.isIncludeSubdirectories()).run();
}
return;
}
}
@@ -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;
@@ -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<CustomLiveTemplate> EP_NAME = ExtensionPointName.create("com.intellij.customLiveTemplate");
boolean isApplicable(@NotNull String key, @NotNull CustomTemplateCallback callback);
void execute(@NotNull String key, @NotNull CustomTemplateCallback callback, @Nullable TemplateInvokationListener listener);
}
@@ -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<TemplateImpl> templates = getMatchingTemplates(key);
templates = TemplateManagerImpl.filterApplicableCandidates(myFile, myStartOffset, templates);
return templates.size() > 0;
}
/**
* @param key
* @param listener
* @return returns if template invokation is finished
*/
public boolean startTemplate(@NotNull String key, @Nullable TemplateInvokationListener listener) {
int caretOffset = myEditor.getCaretModel().getOffset();
List<TemplateImpl> templates = getMatchingTemplates(key);
templates = TemplateManagerImpl.filterApplicableCandidates(myFile, caretOffset, templates);
if (templates.size() == 1) {
TemplateImpl template = templates.get(0);
return startTemplate(template, listener);
}
else if (listener != null) {
listener.finished(false, false);
}
return true;
}
/**
* @param template
* @param listener
* @return returns if template invokation is finished
*/
public boolean startTemplate(@NotNull Template template, @Nullable final TemplateInvokationListener listener) {
final boolean[] templateEnded = new boolean[]{false};
final boolean[] templateFinished = new boolean[]{false};
myTemplateManager.startTemplate(myEditor, template, new TemplateEditingAdapter() {
@Override
public void templateExpanded(Template template) {
int lengthAfter = myEditor.getDocument().getCharsSequence().length();
CodeStyleManager style = CodeStyleManager.getInstance(myProject);
style.reformatText(myFile, myStartOffset, myStartOffset + lengthAfter - myStartLength);
}
@Override
public void templateFinished(Template template, 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<TemplateImpl> getMatchingTemplates(@NotNull String templateKey) {
TemplateSettings settings = TemplateSettings.getInstance();
return settings.collectMatchingCandidates(templateKey, settings.getDefaultShortcutChar(), false);
}
@NotNull
public Editor getEditor() {
return myEditor;
}
public PsiFile getFile() {
return myFile;
}
}
@@ -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();
}
@@ -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) {
}
}
@@ -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);
}
@@ -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);
}
@@ -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<String, String> callback);
public abstract void startTemplate(@NotNull final Editor editor,
@NotNull final Template template,
TemplateEditingListener listener,
boolean inSeparateCommand);
public abstract void startTemplate(@NotNull Editor editor,
@NotNull Template template,
TemplateEditingListener listener,
final PairProcessor<String, String> callback);
public abstract boolean startTemplate(@NotNull Editor editor, char shortcutChar);
@@ -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<String, String> processor) {
startTemplate(editor, null, template, listener, processor);
startTemplate(editor, null, template, listener, processor, true);
}
private void startTemplate(final Editor editor,
final String selectionString,
final Template template,
TemplateEditingListener listener,
final PairProcessor<String, String> processor) {
final PairProcessor<String, String> processor,
boolean inSeparateCommand) {
final TemplateState templateState = initTemplateState(editor);
templateState.getProperties().put(ExpressionContext.SELECTION, selectionString);
@@ -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<String, String> processor) {
final Document document = editor.getDocument();
PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject);
if (file == null) return false;
TemplateSettings templateSettings = TemplateSettings.getInstance();
if (shortcutChar == templateSettings.getDefaultShortcutChar()) {
for (final CustomLiveTemplate customLiveTemplate : CustomLiveTemplate.EP_NAME.getExtensions()) {
final String currentLineBeforeCaret = getCurrentLineBeforeCaret(editor);
final CustomTemplateCallback callback = new CustomTemplateCallback(editor, file);
if (customLiveTemplate.isApplicable(currentLineBeforeCaret, callback)) {
int offset = editor.getCaretModel().getOffset();
final int startOffset = offset - currentLineBeforeCaret.length();
editor.getDocument().deleteString(startOffset, offset);
callback.fixInitialEditorState();
customLiveTemplate.execute(currentLineBeforeCaret, callback, null);
return true;
}
}
}
return startNonCustomTemplate(templateSettings, file, editor, shortcutChar, processor);
}
private boolean startNonCustomTemplate(TemplateSettings templateSettings,
PsiFile file,
Editor editor,
char shortcutChar,
PairProcessor<String, String> processor) {
final Document document = editor.getDocument();
CharSequence text = document.getCharsSequence();
final int caretOffset = editor.getCaretModel().getOffset();
@@ -258,15 +307,14 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo
else {
ListTemplatesHandler.showTemplatesLookup(myProject, editor, candidate2Argument);
}
return true;
}
private static List<TemplateImpl> findMatchingTemplates(CharSequence text,
int caretOffset,
char shortcutChar,
TemplateSettings settings,
boolean hasArgument) {
public static List<TemplateImpl> findMatchingTemplates(CharSequence text,
int caretOffset,
char shortcutChar,
TemplateSettings settings,
boolean hasArgument) {
String key;
List<TemplateImpl> candidates = Collections.emptyList();
for (int i = settings.getMaxKeyLength(); i >= 1; i--) {
@@ -318,7 +366,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo
}, CodeInsightBundle.message("insert.code.template.command"), null);
}
private static List<TemplateImpl> filterApplicableCandidates(PsiFile file, int caretOffset, List<TemplateImpl> candidates) {
public static List<TemplateImpl> filterApplicableCandidates(PsiFile file, int caretOffset, List<TemplateImpl> candidates) {
List<TemplateImpl> result = new ArrayList<TemplateImpl>();
for (TemplateImpl candidate : candidates) {
if (isApplicable(file, caretOffset - candidate.getKey().length(), candidate)) {
@@ -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) {
@@ -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;
}
}
@@ -79,4 +79,7 @@ public abstract class RunManagerEx extends RunManager {
public abstract Collection<RunnerAndConfigurationSettingsImpl> getSortedConfigurations();
public abstract void removeConfiguration(RunnerAndConfigurationSettingsImpl settings);
public abstract void addRunManagerListener(RunManagerListener listener);
public abstract void removeRunManagerListener(RunManagerListener listener);
}
@@ -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();
}
@@ -208,6 +208,7 @@ public abstract class BaseExecuteBeforeRunDialog<T extends BeforeRunTask> extend
}
}
((RunManagerImpl)RunManagerEx.getInstanceEx(myProject)).fireBeforeRunTasksUpdated();
close(OK_EXIT_CODE);
}
@@ -68,6 +68,8 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable,
private List<Element> myUnloadedElements = null;
private JDOMExternalizableStringList myOrder = new JDOMExternalizableStringList();
private final List<RunManagerListener> 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<Key<? extends BeforeRunTask>, BeforeRunTaskProvider> myBeforeStepsMap;
private Map<String, Key<? extends BeforeRunTask>> myProviderKeysMap;
@@ -252,7 +252,7 @@ public class PathReferenceManagerImpl extends PathReferenceManager {
for (Iterator<PsiReference> 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);
@@ -42,7 +42,7 @@ public class PsiDynaReference<T extends PsiElement> extends PsiReferenceBase<T>
implements FileReferenceOwner, PsiPolyVariantReference, QuickFixProvider<PsiDynaReference>, LocalQuickFixProvider, EmptyResolveMessageProvider {
private final List<PsiReference> myReferences = new ArrayList<PsiReference>();
private int myChoosenOne = -1;
private int myChosenOne = -1;
private ResolveResult[] myCachedResult;
public PsiDynaReference(final T psiElement) {
@@ -170,23 +170,23 @@ public class PsiDynaReference<T extends PsiElement> extends PsiReferenceBase<T>
@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) {
@@ -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("/")) {
@@ -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));
}
@@ -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
@@ -174,6 +174,7 @@
<extensionPoint name="liveTemplateMacro" interface="com.intellij.codeInsight.template.Macro"/>
<extensionPoint name="liveTemplateOptionalProcessor" interface="com.intellij.codeInsight.template.impl.TemplateOptionalProcessor"/>
<extensionPoint name="liveTemplatePreprocessor" interface="com.intellij.codeInsight.template.impl.TemplatePreprocessor"/>
<extensionPoint name="customLiveTemplate" interface="com.intellij.codeInsight.template.CustomLiveTemplate"/>
<extensionPoint name="fileTemplateGroup"
interface="com.intellij.ide.fileTemplates.FileTemplateGroupDescriptorFactory"/>
@@ -285,6 +285,7 @@
implementationClass="com.intellij.codeInsight.hint.XmlImplementationTextSelectioner"/>
<basicWordSelectionFilter implementation="com.intellij.codeInsight.editorActions.XmlBasicWordSelectionFilter"/>
<defaultLiveTemplatesProvider implementation="com.intellij.codeInsight.template.XmlDefaultLiveTemplatesProvider"/>
<customLiveTemplate implementation="com.intellij.codeInsight.template.XmlCustomLiveTemplate"/>
<productivityFeaturesProvider implementation="com.intellij.featureStatistics.XmlProductivityFeatureProvider"/>
<idIndexer filetype="XML" implementationClass="com.intellij.psi.impl.cache.impl.idCache.XmlIdIndexer"/>
@@ -30,11 +30,12 @@ import java.util.Set;
*/
public class FileTreeAccessFilter implements VirtualFileFilter {
protected final Set<VirtualFile> myAddedClasses = new THashSet<VirtualFile>();
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;
}
}
@@ -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);
}
}
@@ -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;
@@ -325,4 +325,6 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
void renameElement(PsiElement element, String newName) throws Exception;
void allowTreeAccessForFile(VirtualFile file);
void allowTreeAccessForAllFiles();
}
@@ -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;
@@ -118,6 +118,7 @@ class HeavyIdeaTestFixtureImpl extends BaseFixture implements HeavyIdeaTestFixtu
myEditorListenerTracker.checkListenersLeak();
myThreadTracker.checkLeak();
LightPlatformTestCase.checkEditorsReleased();
}
@@ -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) {
@@ -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;
@@ -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();
}
@@ -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<MavenProjectsNavigatorState> {
@@ -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);
}
}
}
}
});
}
@@ -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;
}
@@ -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;
}
}
@@ -94,8 +94,6 @@ public class MavenBeforeRunTasksProvider extends BeforeRunTaskProvider<MavenBefo
task.setProjectPath(dialog.getSelectedProjectPath());
task.setGoal(dialog.getSelectedGoal());
MavenTasksManager.getInstance(myProject).fireTasksChanged();
return true;
}
@@ -47,7 +47,6 @@ public class ToggleBeforeRunTaskAction extends MavenToggleAction {
public void setSelected(final AnActionEvent e, boolean state) {
Pair<MavenProject, String> desc = getTaskDesc(e);
new MavenExecuteBeforeRunDialog(MavenActionUtil.getProject(e), desc.first, desc.second).show();
MavenTasksManager.getInstance(MavenActionUtil.getProject(e)).fireTasksChanged();
}
protected Pair<MavenProject, String> getTaskDesc(AnActionEvent e) {
@@ -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);
}
@@ -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
@@ -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 {
@@ -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;
}
@@ -220,7 +220,7 @@ public class XmlTagInsertHandler implements InsertHandler<LookupElement> {
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 &&
@@ -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<String, IncorrectOperationException>() {
extension.insertNamespaceDeclaration((XmlFile)file, editor, Collections.singleton(namespace), prefix, new XmlExtension.Runner<String, IncorrectOperationException>() {
public void run(final String param) throws IncorrectOperationException {
if (namespace.length() > 0) {
editor.getCaretModel().moveToOffset(marker.getStartOffset());
@@ -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<MyToken> parse(@NotNull String text, @NotNull CustomTemplateCallback callback) {
text += MARKER;
StringBuilder templateKeyBuilder = new StringBuilder();
List<MyToken> result = new ArrayList<MyToken>();
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<MyToken> 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<MyToken> 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<MyToken> 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("</" + key + ">");
return callback.startTemplate(template, listener);
}
}
private class MyInterpreter extends Iteration {
private final List<MyToken> myTokens;
private final CustomTemplateCallback myCallback;
private final TemplateInvokationListener myListener;
private MyState myState;
private int myEndOffset = -1;
private MyInterpreter(List<MyToken> 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<MyToken> myTokens;
private final int myTailStart;
public ConsecutiveTemplateWithTailInvokation(String templateKey, List<MyToken> 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;
}
}
}
}
}
}
@@ -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);
@@ -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();
}