diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java index 4b8099ec1c62..4d145a50c43d 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java @@ -394,12 +394,6 @@ public abstract class AbstractInplaceIntroducer rangesToHighlight, - Collection> stringUsages, - EditorColorsManager colorsManager) { - } - @Override protected void addHighlights(@NotNull Map ranges, @NotNull Editor editor, diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java index 17aed8f83dd3..c57894747d03 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/InplaceVariableIntroducer.java @@ -218,4 +218,10 @@ public class InplaceVariableIntroducer extends VariableInp protected TextRange preserveSelectedRange(SelectionModel selectionModel) { return null; } + + @Override + protected void performOnInvalidIdentifier(String newName, LinkedHashSet nameSuggestions) { + //move logic to performRefactoring + } + } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java index bad2b38d93ff..95e58024e488 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java @@ -15,15 +15,11 @@ */ package com.intellij.refactoring.rename.inplace; -import com.intellij.codeInsight.template.impl.TemplateManagerImpl; -import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.lang.LanguageNamesValidation; import com.intellij.lang.refactoring.NamesValidator; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.impl.FinishMarkAction; import com.intellij.openapi.command.impl.StartMarkAction; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.extensions.Extensions; @@ -31,7 +27,6 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.SearchScope; @@ -55,13 +50,14 @@ import java.util.List; * Date: 11/9/11 */ public class MemberInplaceRenamer extends VariableInplaceRenamer { - protected final String myOldName; private final PsiElement mySubstituted; private RangeMarker mySubstitutedRange; - public MemberInplaceRenamer(@NotNull PsiNameIdentifierOwner elementToRename, PsiElement substituted, Editor editor) { - super(elementToRename, editor); - myOldName = elementToRename.getName(); + this(elementToRename, substituted, editor, elementToRename.getName(), elementToRename.getName()); + } + + public MemberInplaceRenamer(@NotNull PsiNameIdentifierOwner elementToRename, PsiElement substituted, Editor editor, String initialName, String oldName) { + super(elementToRename, editor, elementToRename.getProject(), initialName, oldName); mySubstituted = substituted; if (mySubstituted != null && mySubstituted != myElementToRename && mySubstituted.getTextRange() != null) { final PsiFile containingFile = mySubstituted.getContainingFile(); @@ -76,6 +72,11 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { showDialogAdvertisement("RenameElement"); } + @Override + protected VariableInplaceRenamer createInplaceRenamerToRestart(PsiNamedElement variable, Editor editor, String initialName) { + return new MemberInplaceRenamer((PsiNameIdentifierOwner)variable, getSubstituted(), editor, initialName, myOldName); + } + @Override protected PsiElement checkLocalScope() { PsiElement scope = super.checkLocalScope(); @@ -181,7 +182,7 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { if (substituted == null) { return; } - + final String commandName = RefactoringBundle .message("renaming.0.1.to.2", UsageViewUtil.getType(variable), UsageViewUtil.getDescriptiveName(variable), newName); CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { @@ -218,23 +219,7 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { @Override protected void restoreStateBeforeTemplateIsFinished() { - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - final Editor editor = InjectedLanguageUtil.getTopLevelEditor(myEditor); - final TemplateState state = TemplateManagerImpl.getTemplateState(editor); - assert state != null; - final int segmentsCount = state.getSegmentsCount(); - final Document document = editor.getDocument(); - for (int i = 0; i < segmentsCount; i++) { - final TextRange segmentRange = state.getSegmentRange(i); - document.replaceString(segmentRange.getStartOffset(), segmentRange.getEndOffset(), myOldName); - } - } - }); - } - }, RENAME_TITLE, null); + revertState(); } @Override 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 27a46867dd8a..b70eae8df922 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 @@ -18,7 +18,6 @@ package com.intellij.refactoring.rename.inplace; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl; import com.intellij.codeInsight.highlighting.HighlightManager; -import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.codeInsight.lookup.LookupManager; @@ -29,7 +28,6 @@ import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.lang.LanguageExtension; import com.intellij.lang.LanguageNamesValidation; -import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; @@ -88,7 +86,6 @@ import com.intellij.usageView.UsageViewUtil; import com.intellij.util.PairProcessor; import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.Stack; -import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -117,6 +114,8 @@ public class VariableInplaceRenamer { protected final Editor myEditor; protected final Project myProject; private RangeMarker myRenameOffset; + private String myInitialName; + protected final String myOldName; public void setAdvertisementText(String advertisementText) { myAdvertisementText = advertisementText; @@ -133,10 +132,20 @@ public class VariableInplaceRenamer { public VariableInplaceRenamer(PsiNamedElement elementToRename, Editor editor, Project project) { + this(elementToRename, editor, project, elementToRename != null ? elementToRename.getName() : null, elementToRename != null ? elementToRename.getName() : null); + } + + public VariableInplaceRenamer(PsiNamedElement elementToRename, + Editor editor, + Project project, + final String initialName, + final String oldName) { myElementToRename = elementToRename; myEditor = /*(editor instanceof EditorWindow)? ((EditorWindow)editor).getDelegate() : */editor; myProject = project; + myOldName = oldName; if (myElementToRename != null) { + myInitialName = initialName; final PsiFile containingFile = myElementToRename.getContainingFile(); if (!notSameFile(containingFile.getVirtualFile(), containingFile)) { myRenameOffset = myElementToRename != null && myElementToRename.getTextRange() != null ? myEditor.getDocument().createRangeMarker(myElementToRename.getTextRange()) : null; @@ -243,7 +252,7 @@ public class VariableInplaceRenamer { } } - private boolean runRenameTemplate(LinkedHashSet nameSuggestions, + private boolean runRenameTemplate(final LinkedHashSet nameSuggestions, Collection refs, final Collection> stringUsages, PsiElement scope, @@ -253,10 +262,6 @@ public class VariableInplaceRenamer { scope = context.getContainingFile(); } - final Map rangesToHighlight = new THashMap(); - //it is crucial to highlight AFTER the template is started, so we collect ranges first - collectElementsToHighlight(rangesToHighlight, refs, stringUsages); - final HighlightManager highlightManager = HighlightManager.getInstance(myProject); ResolveSnapshotProvider resolveSnapshotProvider = INSTANCE.forLanguage(scope.getLanguage()); final ResolveSnapshotProvider.ResolveSnapshot snapshot = resolveSnapshotProvider != null ? @@ -329,7 +334,10 @@ public class VariableInplaceRenamer { TextResult value = templateState.getVariableValue(PRIMARY_VARIABLE_NAME); myNewName = getNewName(value != null ? value.toString() : null, snapshot); - + if (!LanguageNamesValidation.INSTANCE.forLanguage(scope1.getLanguage()).isIdentifier(myNewName, myProject)) { + performOnInvalidIdentifier(myNewName, nameSuggestions); + return; + } if (snapshot != null && performAutomaticRename()) { if (LanguageNamesValidation.INSTANCE.forLanguage(scope1.getLanguage()).isIdentifier(myNewName, myProject)) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @@ -410,6 +418,23 @@ public class VariableInplaceRenamer { //add highlights if (myHighlighters != null) { // can be null if finish is called during testing + Map rangesToHighlight = new HashMap(); + final TemplateState templateState = TemplateManagerImpl.getTemplateState(topLevelEditor); + if (templateState != null) { + EditorColorsManager colorsManager = EditorColorsManager.getInstance(); + for (int i = 0; i < templateState.getSegmentsCount(); i++) { + final TextRange segmentOffset = templateState.getSegmentRange(i); + final String name = template.getSegmentName(i); + TextAttributes attributes = null; + if (name.equals(PRIMARY_VARIABLE_NAME)) { + attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.WRITE_SEARCH_RESULT_ATTRIBUTES); + } else if (name.equals(OTHER_VARIABLE_NAME)) { + attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); + } + if (attributes == null) continue; + rangesToHighlight.put(segmentOffset, attributes); + } + } addHighlights(rangesToHighlight, topLevelEditor, myHighlighters, highlightManager); } } @@ -446,8 +471,24 @@ public class VariableInplaceRenamer { } } } + + protected VariableInplaceRenamer createInplaceRenamerToRestart(PsiNamedElement variable, Editor editor, String initialName) { + return new VariableInplaceRenamer(variable, editor, myProject, initialName, myOldName); + } + + protected void performOnInvalidIdentifier(final String newName, final LinkedHashSet nameSuggestions) { + revertState(); + JBPopupFactory.getInstance() + .createConfirmation("Inserted identifier is not valid", "Continue editing", "Cancel", new Runnable() { + @Override + public void run() { + createInplaceRenamerToRestart(getVariable(), myEditor, newName).performInplaceRename(true, nameSuggestions); + } + }, 0).showInBestPositionFor(myEditor); + } + + protected void restoreStateBeforeTemplateIsFinished(){} - protected void restoreStateBeforeTemplateIsFinished() {} @Nullable protected PsiElement getNameIdentifier() { @@ -600,6 +641,36 @@ public class VariableInplaceRenamer { } } + public String getInitialName() { + if (myInitialName == null) { + final PsiNamedElement variable = getVariable(); + if (variable != null) { + return variable.getName(); + } + } + return myInitialName; + } + + protected void revertState() { + CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + final Editor topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(myEditor); + final TemplateState state = TemplateManagerImpl.getTemplateState(topLevelEditor); + assert state != null; + final int segmentsCount = state.getSegmentsCount(); + final Document document = topLevelEditor.getDocument(); + for (int i = 0; i < segmentsCount; i++) { + final TextRange segmentRange = state.getSegmentRange(i); + document.replaceString(segmentRange.getStartOffset(), segmentRange.getEndOffset(), myOldName); + } + } + }); + } + }, RENAME_TITLE, null); + } + private static VirtualFile getTopLevelVirtualFile(final FileViewProvider fileViewProvider) { VirtualFile file = fileViewProvider.getVirtualFile(); if (file instanceof VirtualFileWindow) file = ((VirtualFileWindow)file).getDelegate(); @@ -633,46 +704,6 @@ public class VariableInplaceRenamer { } } - private void collectElementsToHighlight(Map rangesToHighlight, - Collection refs, - Collection> stringUsages) { - EditorColorsManager colorsManager = EditorColorsManager.getInstance(); - PsiElement nameIdentifier = getNameIdentifier(); - if (nameIdentifier != null) { - final TextRange textRange = nameIdentifier.getTextRange(); - LOG.assertTrue(textRange != null, nameIdentifier); - TextRange range = InjectedLanguageManager.getInstance(myProject).injectedToHost(nameIdentifier, textRange); - rangesToHighlight.put(range, colorsManager.getGlobalScheme().getAttributes(EditorColors.WRITE_SEARCH_RESULT_ATTRIBUTES)); - } - - for (PsiReference ref : refs) { - final PsiElement element = ref.getElement(); - TextRange range = ref.getRangeInElement().shiftRight( - InjectedLanguageManager.getInstance(element.getProject()).injectedToHost(element, element.getTextRange().getStartOffset())); - - ReadWriteAccessDetector writeAccessDetector = ReadWriteAccessDetector.findDetector(element); - // TODO: read / write usages - boolean isForWrite = writeAccessDetector != null && - ReadWriteAccessDetector.Access.Write == writeAccessDetector.getExpressionAccess(element); - TextAttributes attributes = colorsManager.getGlobalScheme().getAttributes(isForWrite ? - EditorColors.WRITE_SEARCH_RESULT_ATTRIBUTES : - EditorColors.SEARCH_RESULT_ATTRIBUTES); - rangesToHighlight.put(range, attributes); - } - - collectAdditionalRangesToHighlight(rangesToHighlight, stringUsages, colorsManager); - } - - protected void collectAdditionalRangesToHighlight(Map rangesToHighlight, - Collection> stringUsages, - EditorColorsManager colorsManager) { - for (Pair usage : stringUsages) { - final TextRange range = usage.second.shiftRight(usage.first.getTextOffset()); - final TextAttributes attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); - rangesToHighlight.put(range, attributes); - } - } - protected void addHighlights(@NotNull Map ranges, @NotNull Editor editor, @NotNull Collection highlighters, @NotNull HighlightManager highlightManager) { for (Map.Entry entry : ranges.entrySet()) { TextRange range = entry.getKey(); @@ -720,7 +751,7 @@ public class VariableInplaceRenamer { final LinkedHashSet names) { if (reference.getElement() == selectedElement && contains(reference.getRangeInElement().shiftRight(selectedElement.getTextRange().getStartOffset()), offset)) { - Expression expression = new MyExpression(myElementToRename.getName(), names); + Expression expression = new MyExpression(getInitialName(), names); builder.replaceElement(reference, PRIMARY_VARIABLE_NAME, expression, true); } else { @@ -741,7 +772,7 @@ public class VariableInplaceRenamer { final TemplateBuilderImpl builder, final LinkedHashSet names) { if (element == selectedElement) { - Expression expression = new MyExpression(myElementToRename.getName(), names); + Expression expression = new MyExpression(getInitialName(), names); builder.replaceElement(element, PRIMARY_VARIABLE_NAME, expression, true); } else if (textRange != null) { builder.replaceElement(element, textRange, OTHER_VARIABLE_NAME, PRIMARY_VARIABLE_NAME, false);