summaryrefslogtreecommitdiff
path: root/platform/lang-impl/src/com/intellij/codeInsight
diff options
context:
space:
mode:
Diffstat (limited to 'platform/lang-impl/src/com/intellij/codeInsight')
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java11
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java3
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java47
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/WolfHighlightingPass.java2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java22
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java4
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java90
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java9
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java45
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java256
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/problems/MockWolfTheProblemSolver.java5
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/problems/WolfTheProblemSolverImpl.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java7
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ChooserExpressionSelector.java (renamed from platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ExpressionPostfixTemplateWithChooser.java)66
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/NotPostfixTemplate.java22
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ParenthesizedPostfixTemplate.java19
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplateExpressionSelector.java54
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatePsiInfo.java35
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatePsiInfoBase.java39
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplateWithExpressionSelector.java83
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatesUtils.java18
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StringBasedPostfixTemplate.java8
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java12
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/TopmostExpressionSelector.java58
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/TypedPostfixTemplate.java42
27 files changed, 756 insertions, 215 deletions
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java
index bf77a3022a0e..af6bbdc931ca 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java
@@ -289,7 +289,16 @@ public class FormatChangedTextUtil {
}
try {
- List<Range> changedRanges = new RangesBuilder(document, documentFromVcs).getRanges();
+ List<Range> changedRanges;
+
+ LineStatusTracker tracker = LineStatusTrackerManager.getInstance(project).getLineStatusTracker(document);
+ if (tracker != null) {
+ changedRanges = tracker.getRanges();
+ }
+ else {
+ changedRanges = new RangesBuilder(document, documentFromVcs).getRanges();
+ }
+
return getChangedTextRanges(document, changedRanges);
}
catch (FilesTooBigForDiffException e) {
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 4966a9466a26..8ec833e8258b 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java
@@ -79,9 +79,6 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
PsiDocumentManager.getInstance(project).commitAllDocuments();
final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
- if (files == null) {
- return;
- }
PsiFile file = null;
final PsiDirectory dir;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
index e0a3be5f423d..fcb080dcd277 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
@@ -71,6 +71,8 @@ import java.util.concurrent.atomic.AtomicReference;
public class CodeCompletionHandlerBase {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.CodeCompletionHandlerBase");
+ private static final Key<Boolean> CARET_PROCESSED = Key.create("CodeCompletionHandlerBase.caretProcessed");
+
@NotNull private final CompletionType myCompletionType;
final boolean invokedExplicitly;
final boolean synchronous;
@@ -108,6 +110,13 @@ public class CodeCompletionHandlerBase {
}
public final void invokeCompletion(@NotNull final Project project, @NotNull final Editor editor, int time, boolean hasModifiers, boolean restarted) {
+ clearCaretMarkers(editor);
+ invokeCompletion(project, editor, time, hasModifiers, restarted, editor.getCaretModel().getPrimaryCaret());
+ }
+
+ public final void invokeCompletion(@NotNull final Project project, @NotNull final Editor editor, int time, boolean hasModifiers, boolean restarted, @NotNull final Caret caret) {
+ markCaretAsProcessed(caret);
+
if (invokedExplicitly) {
CompletionLookupArranger.applyLastCompletionStatisticsUpdate();
}
@@ -162,12 +171,12 @@ public class CodeCompletionHandlerBase {
PsiDocumentManager.getInstance(project).commitAllDocuments();
CompletionAssertions.checkEditorValid(editor);
- final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project);
+ final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(caret, project);
assert psiFile != null : "no PSI file: " + FileDocumentManager.getInstance().getFile(editor.getDocument());
psiFile.putUserData(PsiFileEx.BATCH_REFERENCE_PROCESSING, Boolean.TRUE);
CompletionAssertions.assertCommitSuccessful(editor, psiFile);
- initializationContext[0] = runContributorsBeforeCompletion(editor, psiFile, invocationCount);
+ initializationContext[0] = runContributorsBeforeCompletion(editor, psiFile, invocationCount, caret);
}
};
ApplicationManager.getApplication().runWriteAction(runnable);
@@ -186,9 +195,9 @@ public class CodeCompletionHandlerBase {
insertDummyIdentifier(initializationContext[0], hasModifiers, invocationCount);
}
- private CompletionInitializationContext runContributorsBeforeCompletion(Editor editor, PsiFile psiFile, int invocationCount) {
+ private CompletionInitializationContext runContributorsBeforeCompletion(Editor editor, PsiFile psiFile, int invocationCount, Caret caret) {
final Ref<CompletionContributor> current = Ref.create(null);
- CompletionInitializationContext context = new CompletionInitializationContext(editor, psiFile, myCompletionType, invocationCount) {
+ CompletionInitializationContext context = new CompletionInitializationContext(editor, caret, psiFile, myCompletionType, invocationCount) {
CompletionContributor dummyIdentifierChanger;
@Override
@@ -400,8 +409,15 @@ public class CodeCompletionHandlerBase {
final LookupElement[] items, boolean hasModifiers) {
if (items.length == 0) {
LookupManager.getInstance(indicator.getProject()).hideActiveLookup();
- indicator.handleEmptyLookup(true);
- checkNotSync(indicator, items);
+
+ Caret nextCaret = getNextCaretToProcess(indicator.getEditor());
+ if (nextCaret != null) {
+ invokeCompletion(indicator.getProject(), indicator.getEditor(), indicator.getParameters().getInvocationCount(), hasModifiers, false, nextCaret);
+ }
+ else {
+ indicator.handleEmptyLookup(true);
+ checkNotSync(indicator, items);
+ }
return;
}
@@ -866,4 +882,23 @@ public class CodeCompletionHandlerBase {
}
};
}
+
+ private static void clearCaretMarkers(@NotNull Editor editor) {
+ for (Caret caret : editor.getCaretModel().getAllCarets()) {
+ caret.putUserData(CARET_PROCESSED, null);
+ }
+ }
+
+ private static void markCaretAsProcessed(@NotNull Caret caret) {
+ caret.putUserData(CARET_PROCESSED, Boolean.TRUE);
+ }
+
+ private static Caret getNextCaretToProcess(@NotNull Editor editor) {
+ for (Caret caret : editor.getCaretModel().getAllCarets()) {
+ if (caret.getUserData(CARET_PROCESSED) == null) {
+ return caret;
+ }
+ }
+ return null;
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java
index 8560129194f1..0321191294c5 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/InjectedGeneralHighlightingPass.java
@@ -73,7 +73,7 @@ public class InjectedGeneralHighlightingPass extends GeneralHighlightingPass imp
@Override
protected void collectInformationWithProgress(@NotNull final ProgressIndicator progress) {
- if (!Registry.is("editor.injected.highlighting.enabled", true)) return;
+ if (!Registry.is("editor.injected.highlighting.enabled")) return;
final Set<HighlightInfo> gotHighlights = new THashSet<HighlightInfo>(100);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/WolfHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/WolfHighlightingPass.java
index 9211bead784b..6ff242108eed 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/WolfHighlightingPass.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/WolfHighlightingPass.java
@@ -38,7 +38,7 @@ class WolfHighlightingPass extends ProgressableTextEditorHighlightingPass implem
@Override
protected void collectInformationWithProgress(@NotNull final ProgressIndicator progress) {
- if (!Registry.is("wolf.the.problem.solver", true)) return;
+ if (!Registry.is("wolf.the.problem.solver")) return;
final WolfTheProblemSolver solver = WolfTheProblemSolver.getInstance(myProject);
if (solver instanceof WolfTheProblemSolverImpl) {
((WolfTheProblemSolverImpl)solver).startCheckingIfVincentSolvedProblemsYet(progress, this);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
index c27ce400049e..05a1e01c6aa1 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
@@ -261,10 +261,20 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
}
public void showJavaDocInfo(final Editor editor, @Nullable final PsiFile file, boolean requestFocus) {
- showJavaDocInfo(editor, file, requestFocus, true);
+ showJavaDocInfo(editor, file, requestFocus, null);
}
- private void showJavaDocInfo(final Editor editor, @Nullable final PsiFile file, boolean requestFocus, final boolean autoupdate) {
+ public void showJavaDocInfo(final Editor editor,
+ @Nullable final PsiFile file,
+ boolean requestFocus,
+ final Runnable closeCallback) {
+ showJavaDocInfo(editor, file, requestFocus, true, closeCallback);
+ }
+
+ private void showJavaDocInfo(final Editor editor,
+ @Nullable final PsiFile file,
+ boolean requestFocus,
+ final boolean autoupdate, @Nullable final Runnable closeCallback) {
myEditor = editor;
final Project project = getProject(file);
PsiDocumentManager.getInstance(project).commitAllDocuments();
@@ -314,7 +324,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
return;
}
if (lookupIteObject instanceof PsiElement) {
- doShowJavaDocInfo((PsiElement)lookupIteObject, false, this, originalElement, autoupdate);
+ doShowJavaDocInfo((PsiElement)lookupIteObject, false, this, originalElement, autoupdate, closeCallback);
return;
}
@@ -337,12 +347,12 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
}
}
else {
- doShowJavaDocInfo(element, false, this, originalElement, autoupdate);
+ doShowJavaDocInfo(element, false, this, originalElement, autoupdate, closeCallback);
}
}
};
- doShowJavaDocInfo(element, requestFocus, updateProcessor, originalElement, autoupdate);
+ doShowJavaDocInfo(element, requestFocus, updateProcessor, originalElement, autoupdate, closeCallback);
}
public PsiElement findTargetElement(Editor editor, PsiFile file) {
@@ -969,7 +979,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
@Override
protected void doUpdateComponent(Editor editor, PsiFile psiFile) {
- showJavaDocInfo(editor, psiFile, false, true);
+ showJavaDocInfo(editor, psiFile, false, true, null);
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java
index 2a46c08fc2dd..b738bafb038a 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java
@@ -19,12 +19,12 @@ package com.intellij.codeInsight.editorActions;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.openapi.editor.actions.CopyAction;
import com.intellij.openapi.editor.actions.EditorActionUtil;
import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.impl.EditorCopyPasteHelperImpl;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.openapi.project.Project;
@@ -92,7 +92,7 @@ public class CopyHandler extends EditorActionHandler {
}
String text = editor.getCaretModel().supportsMultipleCarets()
- ? CopyPasteSupport.getSelectedTextForClipboard(editor, transferableDatas)
+ ? EditorCopyPasteHelperImpl.getSelectedTextForClipboard(editor, transferableDatas)
: selectionModel.getSelectedText();
String rawText = TextBlockTransferable.convertLineSeparators(text, "\n", transferableDatas);
String escapedText = null;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java
index 345cb80bae69..17916e008501 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java
@@ -17,15 +17,22 @@ package com.intellij.codeInsight.editorActions;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeStyle.CodeStyleFacade;
+import com.intellij.formatting.*;
+import com.intellij.lang.LanguageFormatting;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
@@ -36,40 +43,75 @@ import org.jetbrains.annotations.NotNull;
public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
private static final Logger LOG = Logger.getInstance(IndentingBackspaceHandler.class);
+ private boolean isApplicable;
private boolean caretWasAtLineStart;
+ private String precalculatedSpacing;
@Override
public void beforeCharDeleted(char c, PsiFile file, Editor editor) {
- caretWasAtLineStart = editor.getCaretModel().getLogicalPosition().column == 0;
- }
-
- @Override
- public boolean charDeleted(char c, PsiFile file, Editor editor) {
if (CodeInsightSettings.getInstance().SMART_BACKSPACE != CodeInsightSettings.AUTOINDENT || !StringUtil.isWhiteSpace(c)) {
- return false;
+ isApplicable = false;
+ return;
}
LanguageCodeStyleSettingsProvider codeStyleSettingsProvider = LanguageCodeStyleSettingsProvider.forLanguage(file.getLanguage());
if (codeStyleSettingsProvider != null && codeStyleSettingsProvider.isIndentBasedLanguageSemantics()) {
+ isApplicable = false;
+ return;
+ }
+ Document document = editor.getDocument();
+ CharSequence charSequence = document.getCharsSequence();
+ CaretModel caretModel = editor.getCaretModel();
+ int caretOffset = caretModel.getOffset();
+ LogicalPosition pos = caretModel.getLogicalPosition();
+ isApplicable = true;
+ caretWasAtLineStart = pos.column == 0;
+ precalculatedSpacing = null;
+ if (caretWasAtLineStart && pos.line > 0 && caretOffset < charSequence.length() && !StringUtil.isWhiteSpace(charSequence.charAt(caretOffset))) {
+ int prevLineEnd = document.getLineEndOffset(pos.line - 1);
+ if (prevLineEnd > 0 && !StringUtil.isWhiteSpace(charSequence.charAt(prevLineEnd - 1))) {
+ PsiDocumentManager.getInstance(file.getProject()).commitDocument(document);
+ precalculatedSpacing = getSpacing(file, caretOffset);
+ }
+ }
+ }
+
+ @Override
+ public boolean charDeleted(char c, PsiFile file, Editor editor) {
+ if (!isApplicable) {
return false;
}
+ Project project = file.getProject();
Document document = editor.getDocument();
+ CaretModel caretModel = editor.getCaretModel();
- int caretOffset = editor.getCaretModel().getOffset();
+ int caretOffset = caretModel.getOffset();
int offset = CharArrayUtil.shiftForward(document.getCharsSequence(), caretOffset, " \t");
int beforeWhitespaceOffset = CharArrayUtil.shiftBackward(document.getCharsSequence(), offset - 1, " \t") + 1;
- LogicalPosition logicalPosition = caretOffset < offset ? editor.offsetToLogicalPosition(offset) : editor.getCaretModel().getLogicalPosition();
+ LogicalPosition logicalPosition = caretOffset < offset ? editor.offsetToLogicalPosition(offset) : caretModel.getLogicalPosition();
int lineStartOffset = document.getLineStartOffset(logicalPosition.line);
if (lineStartOffset < beforeWhitespaceOffset) {
- if (caretWasAtLineStart && beforeWhitespaceOffset < offset) {
- document.deleteString(beforeWhitespaceOffset, offset);
- return true;
+ if (caretWasAtLineStart && beforeWhitespaceOffset <= offset) {
+ String spacing;
+ if (precalculatedSpacing == null) {
+ PsiDocumentManager.getInstance(project).commitDocument(document);
+ spacing = getSpacing(file, offset);
+ }
+ else {
+ spacing = precalculatedSpacing;
+ }
+ if (beforeWhitespaceOffset < offset || !spacing.isEmpty()) {
+ document.replaceString(beforeWhitespaceOffset, offset, spacing);
+ caretModel.moveToOffset(beforeWhitespaceOffset + spacing.length());
+ return true;
+ }
}
return false;
}
- CodeStyleFacade codeStyleFacade = CodeStyleFacade.getInstance(editor.getProject());
- String indent = codeStyleFacade.getLineIndent(document, lineStartOffset);
+ PsiDocumentManager.getInstance(project).commitDocument(document);
+ CodeStyleFacade codeStyleFacade = CodeStyleFacade.getInstance(project);
+ String indent = codeStyleFacade.getLineIndent(document, offset);
if (indent == null) {
return false;
}
@@ -79,7 +121,7 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
if (logicalPosition.column == targetColumn) {
if (caretOffset < offset) {
- editor.getCaretModel().moveToLogicalPosition(logicalPosition);
+ caretModel.moveToLogicalPosition(logicalPosition);
return true;
}
return false;
@@ -87,7 +129,7 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
if (caretWasAtLineStart || logicalPosition.column > targetColumn) {
document.replaceString(lineStartOffset, offset, indent);
- editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(logicalPosition.line, targetColumn));
+ caretModel.moveToLogicalPosition(new LogicalPosition(logicalPosition.line, targetColumn));
return true;
}
@@ -100,12 +142,13 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
int targetOffset = CharArrayUtil.shiftBackward(document.getCharsSequence(), prevLineEndOffset - 1, " \t") + 1;
if (prevLineStartOffset < targetOffset) {
- document.deleteString(targetOffset, offset);
- editor.getCaretModel().moveToOffset(targetOffset);
+ String spacing = getSpacing(file, offset);
+ document.replaceString(targetOffset, offset, spacing);
+ caretModel.moveToOffset(targetOffset + spacing.length());
}
else {
document.replaceString(prevLineStartOffset, offset, indent);
- editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(logicalPosition.line - 1, targetColumn));
+ caretModel.moveToLogicalPosition(new LogicalPosition(logicalPosition.line - 1, targetColumn));
}
return true;
}
@@ -132,4 +175,15 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
}
return width;
}
+
+ private static String getSpacing(PsiFile file, int offset) {
+ FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(file);
+ if (builder == null) {
+ return "";
+ }
+ CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(file.getProject());
+ FormattingModel model = builder.createModel(file, settings);
+ int spacing = FormatterEx.getInstance().getSpacingForBlockAtOffset(model, offset);
+ return StringUtil.repeatSymbol(' ', spacing);
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java
index bb21eac69ecd..ba4768f73099 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java
@@ -148,14 +148,17 @@ public class TypedHandler extends TypedActionHandlerBase {
return;
}
+ final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
+ final Document originalDocument = originalEditor.getDocument();
originalEditor.getCaretModel().runForEachCaret(new CaretAction() {
@Override
public void perform(Caret caret) {
- PsiDocumentManager.getInstance(project)
- .doPostponedOperationsAndUnblockDocument(originalEditor.getDocument()); // to clean up after previous caret processing
+ if (psiDocumentManager.isDocumentBlockedByPsi(originalDocument)) {
+ psiDocumentManager.doPostponedOperationsAndUnblockDocument(originalDocument); // to clean up after previous caret processing
+ }
Editor editor = injectedEditorIfCharTypedIsSignificant(charTyped, originalEditor, originalFile);
- PsiFile file = editor == originalEditor ? originalFile : PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+ PsiFile file = editor == originalEditor ? originalFile : psiDocumentManager.getPsiFile(editor.getDocument());
final TypedHandlerDelegate[] delegates = Extensions.getExtensions(TypedHandlerDelegate.EP_NAME);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java
index 3a1f04b80414..9a71909fcca8 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java
@@ -372,31 +372,34 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable,
checkValid();
CollectionListModel<LookupElement> listModel = getListModel();
- synchronized (myList) {
- Pair<List<LookupElement>, Integer> pair = myPresentableArranger.arrangeItems(this, onExplicitAction || reused);
- List<LookupElement> items = pair.first;
- Integer toSelect = pair.second;
- if (toSelect == null || toSelect < 0 || items.size() > 0 && toSelect >= items.size()) {
- LOG.error("Arranger " + myPresentableArranger + " returned invalid selection index=" + toSelect + "; items=" + items);
- }
-
- myOffsets.checkMinPrefixLengthChanges(items, this);
- List<LookupElement> oldModel = listModel.toList();
- listModel.removeAll();
- if (!items.isEmpty()) {
- listModel.add(items);
- }
- else {
- addEmptyItem(listModel);
- }
+ Pair<List<LookupElement>, Integer> pair;
+ synchronized (myList) {
+ pair = myPresentableArranger.arrangeItems(this, onExplicitAction || reused);
+ }
+
+ List<LookupElement> items = pair.first;
+ Integer toSelect = pair.second;
+ if (toSelect == null || toSelect < 0 || items.size() > 0 && toSelect >= items.size()) {
+ LOG.error("Arranger " + myPresentableArranger + " returned invalid selection index=" + toSelect + "; items=" + items);
+ toSelect = 0;
+ }
- updateListHeight(listModel);
+ myOffsets.checkMinPrefixLengthChanges(items, this);
+ List<LookupElement> oldModel = listModel.toList();
- myList.setSelectedIndex(toSelect);
- return !ContainerUtil.equalsIdentity(oldModel, items);
+ listModel.removeAll();
+ if (!items.isEmpty()) {
+ listModel.add(items);
}
+ else {
+ addEmptyItem(listModel);
+ }
+
+ updateListHeight(listModel);
+ myList.setSelectedIndex(toSelect);
+ return !ContainerUtil.equalsIdentity(oldModel, items);
}
private boolean isSelectionVisible() {
@@ -566,7 +569,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable,
public void perform(Caret caret) {
EditorModificationUtil.deleteSelectedText(hostEditor);
final int caretOffset = hostEditor.getCaretModel().getOffset();
- int lookupStart = caretOffset - prefix;
+ int lookupStart = Math.max(caretOffset - prefix, 0);
int len = hostEditor.getDocument().getTextLength();
LOG.assertTrue(lookupStart >= 0 && lookupStart <= len,
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java
index 3c0e84a11656..3617c944e888 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java
@@ -19,30 +19,46 @@ package com.intellij.codeInsight.navigation;
import com.intellij.ide.util.DefaultPsiElementCellRenderer;
import com.intellij.ide.util.EditSourceUtil;
import com.intellij.ide.util.PsiElementListCellRenderer;
+import com.intellij.navigation.GotoRelatedItem;
+import com.intellij.navigation.GotoRelatedProvider;
import com.intellij.navigation.NavigationItem;
+import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.fileEditor.impl.EditorHistoryManager;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
+import com.intellij.openapi.ui.popup.PopupStep;
+import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
+import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.ElementBase;
import com.intellij.psi.search.PsiElementProcessor;
-import com.intellij.ui.JBListWithHintProvider;
+import com.intellij.ui.*;
+import com.intellij.ui.popup.list.ListPopupImpl;
+import com.intellij.ui.popup.list.PopupListElementRenderer;
+import com.intellij.util.Processor;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.util.*;
+import java.util.List;
/**
* @author ven
@@ -220,4 +236,242 @@ public final class NavigationUtil {
}
return attributes;
}
+
+ @NotNull
+ public static JBPopup getRelatedItemsPopup(final List<? extends GotoRelatedItem> items, String title) {
+ Object[] elements = new Object[items.size()];
+ //todo[nik] move presentation logic to GotoRelatedItem class
+ final Map<PsiElement, GotoRelatedItem> itemsMap = new HashMap<PsiElement, GotoRelatedItem>();
+ for (int i = 0; i < items.size(); i++) {
+ GotoRelatedItem item = items.get(i);
+ elements[i] = item.getElement() != null ? item.getElement() : item;
+ itemsMap.put(item.getElement(), item);
+ }
+
+ return getPsiElementPopup(elements, itemsMap, title, new Processor<Object>() {
+ @Override
+ public boolean process(Object element) {
+ if (element instanceof PsiElement) {
+ //noinspection SuspiciousMethodCalls
+ itemsMap.get(element).navigate();
+ }
+ else {
+ ((GotoRelatedItem)element).navigate();
+ }
+ return true;
+ }
+ }
+ );
+ }
+
+ private static JBPopup getPsiElementPopup(final Object[] elements, final Map<PsiElement, GotoRelatedItem> itemsMap,
+ final String title, final Processor<Object> processor) {
+
+ final Ref<Boolean> hasMnemonic = Ref.create(false);
+ final DefaultPsiElementCellRenderer renderer = new DefaultPsiElementCellRenderer() {
+ {
+ setFocusBorderEnabled(false);
+ }
+
+ @Override
+ public String getElementText(PsiElement element) {
+ String customName = itemsMap.get(element).getCustomName();
+ return (customName != null ? customName : super.getElementText(element));
+ }
+
+ @Override
+ protected Icon getIcon(PsiElement element) {
+ Icon customIcon = itemsMap.get(element).getCustomIcon();
+ return customIcon != null ? customIcon : super.getIcon(element);
+ }
+
+ @Override
+ public String getContainerText(PsiElement element, String name) {
+ String customContainerName = itemsMap.get(element).getCustomContainerName();
+
+ if (customContainerName != null) {
+ return customContainerName;
+ }
+ PsiFile file = element.getContainingFile();
+ return file != null && !getElementText(element).equals(file.getName())
+ ? "(" + file.getName() + ")"
+ : null;
+ }
+
+ @Override
+ protected DefaultListCellRenderer getRightCellRenderer(Object value) {
+ return null;
+ }
+
+ @Override
+ protected boolean customizeNonPsiElementLeftRenderer(ColoredListCellRenderer renderer,
+ JList list,
+ Object value,
+ int index,
+ boolean selected,
+ boolean hasFocus) {
+ final GotoRelatedItem item = (GotoRelatedItem)value;
+ Color color = list.getForeground();
+ final SimpleTextAttributes nameAttributes = new SimpleTextAttributes(Font.PLAIN, color);
+ final String name = item.getCustomName();
+ if (name == null) return false;
+ renderer.append(name, nameAttributes);
+ renderer.setIcon(item.getCustomIcon());
+ return true;
+ }
+
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ final JPanel component = (JPanel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+ if (!hasMnemonic.get()) return component;
+
+ final JPanel panelWithMnemonic = new JPanel(new BorderLayout());
+ final int mnemonic = getMnemonic(value, itemsMap);
+ final JLabel label = new JLabel("");
+ if (mnemonic != -1) {
+ label.setText(mnemonic + ".");
+ label.setDisplayedMnemonicIndex(0);
+ }
+ label.setPreferredSize(new JLabel("8.").getPreferredSize());
+
+ final JComponent leftRenderer = (JComponent)component.getComponents()[0];
+ component.remove(leftRenderer);
+ panelWithMnemonic.setBorder(BorderFactory.createEmptyBorder(0, 7, 0, 0));
+ panelWithMnemonic.setBackground(leftRenderer.getBackground());
+ label.setBackground(leftRenderer.getBackground());
+ panelWithMnemonic.add(label, BorderLayout.WEST);
+ panelWithMnemonic.add(leftRenderer, BorderLayout.CENTER);
+ component.add(panelWithMnemonic);
+ return component;
+ }
+ };
+ final ListPopupImpl popup = new ListPopupImpl(new BaseListPopupStep<Object>(title, Arrays.asList(elements)) {
+ @Override
+ public boolean isSpeedSearchEnabled() {
+ return true;
+ }
+
+ @Override
+ public String getIndexedString(Object value) {
+ if (value instanceof GotoRelatedItem) {
+ //noinspection ConstantConditions
+ return ((GotoRelatedItem)value).getCustomName();
+ }
+ final PsiElement element = (PsiElement)value;
+ return renderer.getElementText(element) + " " + renderer.getContainerText(element, null);
+ }
+
+ @Override
+ public PopupStep onChosen(Object selectedValue, boolean finalChoice) {
+ processor.process(selectedValue);
+ return super.onChosen(selectedValue, finalChoice);
+ }
+ }) {
+ };
+ popup.getList().setCellRenderer(new PopupListElementRenderer(popup) {
+ Map<Object, String> separators = new HashMap<Object, String>();
+ {
+ final ListModel model = popup.getList().getModel();
+ String current = null;
+ boolean hasTitle = false;
+ for (int i = 0; i < model.getSize(); i++) {
+ final Object element = model.getElementAt(i);
+ final GotoRelatedItem item = itemsMap.get(element);
+ if (item != null && !StringUtil.equals(current, item.getGroup())) {
+ current = item.getGroup();
+ separators.put(element, current);
+ if (!hasTitle && !StringUtil.isEmpty(current)) {
+ hasTitle = true;
+ }
+ }
+ }
+
+ if (!hasTitle) {
+ separators.remove(model.getElementAt(0));
+ }
+ }
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ final Component component = renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+ final String separator = separators.get(value);
+
+ if (separator != null) {
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.add(component, BorderLayout.CENTER);
+ final SeparatorWithText sep = new SeparatorWithText() {
+ @Override
+ protected void paintComponent(Graphics g) {
+ g.setColor(new JBColor(Color.WHITE, UIUtil.getSeparatorColor()));
+ g.fillRect(0,0,getWidth(), getHeight());
+ super.paintComponent(g);
+ }
+ };
+ sep.setCaption(separator);
+ panel.add(sep, BorderLayout.NORTH);
+ return panel;
+ }
+ return component;
+ }
+ });
+
+ popup.setMinimumSize(new Dimension(200, -1));
+
+ for (Object item : elements) {
+ final int mnemonic = getMnemonic(item, itemsMap);
+ if (mnemonic != -1) {
+ final Action action = createNumberAction(mnemonic, popup, itemsMap, processor);
+ popup.registerAction(mnemonic + "Action", KeyStroke.getKeyStroke(String.valueOf(mnemonic)), action);
+ popup.registerAction(mnemonic + "Action", KeyStroke.getKeyStroke("NUMPAD" + String.valueOf(mnemonic)), action);
+ hasMnemonic.set(true);
+ }
+ }
+ return popup;
+ }
+
+ private static Action createNumberAction(final int mnemonic,
+ final ListPopupImpl listPopup,
+ final Map<PsiElement, GotoRelatedItem> itemsMap,
+ final Processor<Object> processor) {
+ return new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ for (final Object item : listPopup.getListStep().getValues()) {
+ if (getMnemonic(item, itemsMap) == mnemonic) {
+ listPopup.setFinalRunnable(new Runnable() {
+ @Override
+ public void run() {
+ processor.process(item);
+ }
+ });
+ listPopup.closeOk(null);
+ }
+ }
+ }
+ };
+ }
+
+ private static int getMnemonic(Object item, Map<PsiElement, GotoRelatedItem> itemsMap) {
+ return (item instanceof GotoRelatedItem ? (GotoRelatedItem)item : itemsMap.get((PsiElement)item)).getMnemonic();
+ }
+
+ @NotNull
+ public static List<GotoRelatedItem> collectRelatedItems(@NotNull PsiElement contextElement, @Nullable DataContext dataContext) {
+ Set<GotoRelatedItem> items = ContainerUtil.newLinkedHashSet();
+ for (GotoRelatedProvider provider : Extensions.getExtensions(GotoRelatedProvider.EP_NAME)) {
+ items.addAll(provider.getItems(contextElement));
+ if (dataContext != null) {
+ items.addAll(provider.getItems(dataContext));
+ }
+ }
+ GotoRelatedItem[] result = items.toArray(new GotoRelatedItem[items.size()]);
+ Arrays.sort(result, new Comparator<GotoRelatedItem>() {
+ @Override
+ public int compare(GotoRelatedItem i1, GotoRelatedItem i2) {
+ String o1 = i1.getGroup();
+ String o2 = i2.getGroup();
+ return StringUtil.isEmpty(o1) ? 1 : StringUtil.isEmpty(o2) ? -1 : o1.compareTo(o2);
+ }
+ });
+ return Arrays.asList(result);
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/problems/MockWolfTheProblemSolver.java b/platform/lang-impl/src/com/intellij/codeInsight/problems/MockWolfTheProblemSolver.java
index eeb5e04b8aab..4ea365f34b0c 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/problems/MockWolfTheProblemSolver.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/problems/MockWolfTheProblemSolver.java
@@ -44,6 +44,11 @@ public class MockWolfTheProblemSolver extends WolfTheProblemSolver {
}
@Override
+ public void weHaveGotNonIgnorableProblems(@NotNull VirtualFile virtualFile, @NotNull List<Problem> problems) {
+ if (myDelegate != null) myDelegate.weHaveGotNonIgnorableProblems(virtualFile, problems);
+ }
+
+ @Override
public boolean hasProblemFilesBeneath(@NotNull final Condition<VirtualFile> condition) {
return false;
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/problems/WolfTheProblemSolverImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/problems/WolfTheProblemSolverImpl.java
index 45b4532713c4..fab185e6ddc0 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/problems/WolfTheProblemSolverImpl.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/problems/WolfTheProblemSolverImpl.java
@@ -413,6 +413,12 @@ public class WolfTheProblemSolverImpl extends WolfTheProblemSolver {
public void weHaveGotProblems(@NotNull final VirtualFile virtualFile, @NotNull List<Problem> problems) {
if (problems.isEmpty()) return;
if (!isToBeHighlighted(virtualFile)) return;
+ weHaveGotNonIgnorableProblems(virtualFile, problems);
+ }
+
+ @Override
+ public void weHaveGotNonIgnorableProblems(@NotNull VirtualFile virtualFile, @NotNull List<Problem> problems) {
+ if (problems.isEmpty()) return;
boolean fireListener = false;
synchronized (myProblems) {
ProblemFileInfo storedProblems = myProblems.get(virtualFile);
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 516ed9118c8c..0c838cd05ec5 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
@@ -212,8 +212,11 @@ public class TemplateState implements Disposable {
if (variableName.equals(TemplateImpl.END)) {
return new TextResult("");
}
- if (myPredefinedVariableValues != null && myPredefinedVariableValues.containsKey(variableName)) {
- return new TextResult(myPredefinedVariableValues.get(variableName));
+ if (myPredefinedVariableValues != null) {
+ String text = myPredefinedVariableValues.get(variableName);
+ if (text != null) {
+ return new TextResult(text);
+ }
}
CharSequence text = myDocument.getCharsSequence();
int segmentNumber = myTemplate.getVariableSegmentNumber(variableName);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ExpressionPostfixTemplateWithChooser.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ChooserExpressionSelector.java
index f6b0cedae31e..2989f0d0c97c 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ExpressionPostfixTemplateWithChooser.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ChooserExpressionSelector.java
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.template.postfix.templates;
+
import com.intellij.codeInsight.unwrap.ScopeHighlighter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
@@ -30,45 +31,43 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
- * @author ignatov
+ * See {@link PostfixTemplateExpressionSelector} for description
*/
-public abstract class ExpressionPostfixTemplateWithChooser extends PostfixTemplate {
+public class ChooserExpressionSelector implements PostfixTemplateExpressionSelector {
@NotNull
- protected final PostfixTemplatePsiInfoBase myInfo;
+ private final Condition<PsiElement> myCondition;
- protected ExpressionPostfixTemplateWithChooser(@NotNull String name, @NotNull String example, @NotNull PostfixTemplatePsiInfoBase info) {
- super(name, example);
- myInfo = info;
+ public ChooserExpressionSelector(@NotNull Condition<PsiElement> condition) {
+ myCondition = condition;
}
- protected ExpressionPostfixTemplateWithChooser(@NotNull String name,
- @NotNull String key,
- @NotNull String example,
- @NotNull PostfixTemplatePsiInfoBase info) {
- super(name, key, example);
- myInfo = info;
- }
- @Override
- public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
- return !getExpressions(context, copyDocument, newOffset).isEmpty();
+ public boolean hasExpression(@NotNull final PostfixTemplateWithExpressionSelector postfixTemplate,
+ @NotNull PsiElement context,
+ @NotNull Document copyDocument,
+ int newOffset) {
+ return !getExpressions(postfixTemplate, context, copyDocument, newOffset).isEmpty();
}
- @Override
- public void expand(@NotNull PsiElement context, @NotNull final Editor editor) {
- List<PsiElement> expressions = getExpressions(context, editor.getDocument(), editor.getCaretModel().getOffset());
+ public void expandTemplate(@NotNull final PostfixTemplateWithExpressionSelector postfixTemplate,
+ @NotNull PsiElement context,
+ @NotNull final Editor editor) {
+ List<PsiElement> expressions =
+ getExpressions(postfixTemplate, context, editor.getDocument(), editor.getCaretModel().getOffset());
if (expressions.isEmpty()) {
PostfixTemplatesUtils.showErrorHint(context.getProject(), editor);
}
else if (expressions.size() == 1) {
- doIt(editor, expressions.get(0));
+ postfixTemplate.expandForChooseExpression(expressions.get(0), editor);
}
else {
if (ApplicationManager.getApplication().isUnitTestMode()) {
- doIt(editor, expressions.get(expressions.size() - 1));
+ PsiElement item = ContainerUtil.getLastItem(expressions);
+ assert item != null;
+ postfixTemplate.expandForChooseExpression(item, editor);
return;
}
@@ -81,22 +80,25 @@ public abstract class ExpressionPostfixTemplateWithChooser extends PostfixTempla
public void run() {
CommandProcessor.getInstance().executeCommand(e.getProject(), new Runnable() {
public void run() {
- doIt(editor, e);
+ postfixTemplate.expandForChooseExpression(e, editor);
}
}, "Expand postfix template", PostfixLiveTemplate.POSTFIX_TEMPLATE_ID);
}
});
}
},
- myInfo.getRenderer(),
+ postfixTemplate.getPsiInfo().getRenderer(),
"Expressions", 0, ScopeHighlighter.NATURAL_RANGER
);
}
}
@NotNull
- protected List<PsiElement> getExpressions(@NotNull PsiElement context, @NotNull Document document, final int offset) {
- List<PsiElement> possibleExpressions = myInfo.getExpressions(context, document, offset);
+ private List<PsiElement> getExpressions(@NotNull PostfixTemplateWithExpressionSelector postfixTemplate,
+ @NotNull PsiElement context,
+ @NotNull Document document,
+ final int offset) {
+ List<PsiElement> possibleExpressions = postfixTemplate.getPsiInfo().getExpressions(context, document, offset);
List<PsiElement> expressions = ContainerUtil.filter(possibleExpressions,
new Condition<PsiElement>() {
@Override
@@ -105,19 +107,13 @@ public abstract class ExpressionPostfixTemplateWithChooser extends PostfixTempla
}
}
);
- return ContainerUtil.filter(expressions.isEmpty() ? maybeTopmostExpression(context) : expressions, getTypeCondition());
+ return ContainerUtil
+ .filter(expressions.isEmpty() ? maybeTopmostExpression(postfixTemplate, context) : expressions, myCondition);
}
- @NotNull
- @SuppressWarnings("unchecked")
- protected Condition<PsiElement> getTypeCondition() {
- return Condition.TRUE;
- }
@NotNull
- private List<PsiElement> maybeTopmostExpression(@NotNull PsiElement context) {
- return ContainerUtil.createMaybeSingletonList(myInfo.getTopmostExpression(context));
+ private static List<PsiElement> maybeTopmostExpression(@NotNull PostfixTemplateWithExpressionSelector postfixTemplate, @NotNull PsiElement context) {
+ return ContainerUtil.createMaybeSingletonList(postfixTemplate.getPsiInfo().getTopmostExpression(context));
}
-
- protected abstract void doIt(@NotNull Editor editor, @NotNull PsiElement expression);
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/NotPostfixTemplate.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/NotPostfixTemplate.java
index 9c1d9c66b94d..3944cd930af0 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/NotPostfixTemplate.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/NotPostfixTemplate.java
@@ -16,26 +16,34 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
-public class NotPostfixTemplate extends ExpressionPostfixTemplateWithChooser {
+import static com.intellij.codeInsight.template.postfix.templates.PostfixTemplatesUtils.selectorWithChooser;
- public NotPostfixTemplate(@NotNull PostfixTemplatePsiInfoBase info) {
- super("not", "!expr", info);
+public class NotPostfixTemplate extends PostfixTemplateWithExpressionSelector {
+
+ public NotPostfixTemplate(@NotNull PostfixTemplatePsiInfo info, @NotNull Condition<PsiElement> typeChecker) {
+ super("not", "!expr", info, selectorWithChooser(typeChecker));
}
+ public NotPostfixTemplate(@NotNull PostfixTemplatePsiInfo info) {
+ super("not", "!expr", info, selectorWithChooser());
+ }
public NotPostfixTemplate(@NotNull String name,
@NotNull String key,
@NotNull String example,
- @NotNull PostfixTemplatePsiInfoBase info) {
- super(name, key, example, info);
+ @NotNull PostfixTemplatePsiInfo info,
+ @NotNull Condition<PsiElement> typeChecker
+ ) {
+ super(name, key, example, info, selectorWithChooser(typeChecker));
}
@Override
- protected void doIt(@NotNull Editor editor, @NotNull PsiElement expression) {
- PsiElement element = myInfo.getNegatedExpression(expression);
+ protected void expandForChooseExpression(@NotNull PsiElement expression, @NotNull Editor editor) {
+ PsiElement element = myPsiInfo.getNegatedExpression(expression);
expression.replace(element);
}
} \ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ParenthesizedPostfixTemplate.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ParenthesizedPostfixTemplate.java
index 9a5d03a9359c..3f1dd1143348 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ParenthesizedPostfixTemplate.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ParenthesizedPostfixTemplate.java
@@ -16,16 +16,25 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
-public class ParenthesizedPostfixTemplate extends ExpressionPostfixTemplateWithChooser {
- public ParenthesizedPostfixTemplate(PostfixTemplatePsiInfoBase psiInfo) {
- super("par", "(expr)", psiInfo);
+import static com.intellij.codeInsight.template.postfix.templates.PostfixTemplatesUtils.selectorWithChooser;
+
+public class ParenthesizedPostfixTemplate extends PostfixTemplateWithExpressionSelector {
+
+ public ParenthesizedPostfixTemplate(PostfixTemplatePsiInfo psiInfo, Condition<PsiElement> condition) {
+ super("par", "(expr)", psiInfo, selectorWithChooser(condition));
+ }
+
+
+ public ParenthesizedPostfixTemplate(PostfixTemplatePsiInfo psiInfo) {
+ super("par", "(expr)", psiInfo, selectorWithChooser());
}
@Override
- protected void doIt(@NotNull Editor editor, @NotNull PsiElement expression) {
- expression.replace(myInfo.createExpression(expression, "(", ")"));
+ protected void expandForChooseExpression(@NotNull PsiElement expression, @NotNull Editor editor) {
+ expression.replace(myPsiInfo.createExpression(expression, "(", ")"));
}
} \ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplateExpressionSelector.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplateExpressionSelector.java
new file mode 100644
index 000000000000..6b5d559da1de
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplateExpressionSelector.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2014 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.postfix.templates;
+
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Interface provides method used in {@link com.intellij.codeInsight.template.postfix.templates.PostfixTemplateWithExpressionSelector}
+ *
+ * You should implement the interface if you have non-trivial logic how to determine expression for next processing in postfix template
+ * Otherwise, you can use one of existing simple implementations:
+ *
+ * 1) {@link com.intellij.codeInsight.template.postfix.templates.ChooserExpressionSelector} - The selector get all expression
+ * in the current position and show to user chooser for these expressions.
+ *
+ * 2) {@link com.intellij.codeInsight.template.postfix.templates.TopmostExpressionSelector} - The selector pass to postfix template
+ * top most expression in the current position
+ *
+ *
+ */
+public interface PostfixTemplateExpressionSelector {
+
+ /**
+ * Check that we can select not-null expression(PsiElement) in current context
+ */
+ boolean hasExpression(@NotNull final PostfixTemplateWithExpressionSelector postfixTemplate,
+ @NotNull PsiElement context,
+ @NotNull Document copyDocument,
+ int newOffset);
+
+ /**
+ * Select expression(PsiElement) and call postfixTemplate.expandForChooseExpression for selected expression
+ */
+ void expandTemplate(@NotNull final PostfixTemplateWithExpressionSelector postfixTemplate,
+ @NotNull PsiElement context,
+ @NotNull final Editor editor);
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatePsiInfo.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatePsiInfo.java
index 8f4716787453..6664d6404d64 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatePsiInfo.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatePsiInfo.java
@@ -16,25 +16,42 @@
package com.intellij.codeInsight.template.postfix.templates;
+import com.intellij.openapi.editor.Document;
import com.intellij.psi.PsiElement;
+import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-public interface PostfixTemplatePsiInfo {
+import java.util.List;
+
+public abstract class PostfixTemplatePsiInfo {
@NotNull
- PsiElement createStatement(@NotNull PsiElement context,
- @NotNull String prefix,
- @NotNull String suffix);
+ public abstract PsiElement createStatement(@NotNull PsiElement context,
+ @NotNull String prefix,
+ @NotNull String suffix);
@NotNull
- PsiElement createExpression(@NotNull PsiElement context,
- @NotNull String prefix,
- @NotNull String suffix);
+ public abstract PsiElement createExpression(@NotNull PsiElement context,
+ @NotNull String prefix,
+ @NotNull String suffix);
@Nullable
- PsiElement getTopmostExpression(@NotNull PsiElement element);
+ public abstract PsiElement getTopmostExpression(@NotNull PsiElement element);
+
+ @NotNull
+ public abstract PsiElement getNegatedExpression(@NotNull PsiElement element);
+
+ @NotNull
+ public abstract List<PsiElement> getExpressions(@NotNull PsiElement context, @NotNull Document document, int offset);
@NotNull
- PsiElement getNegatedExpression(@NotNull PsiElement element);
+ public Function<PsiElement, String> getRenderer() {
+ return new Function<PsiElement, String>() {
+ @Override
+ public String fun(@NotNull PsiElement element) {
+ return element.getText();
+ }
+ };
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatePsiInfoBase.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatePsiInfoBase.java
deleted file mode 100644
index 7254e651ce41..000000000000
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatePsiInfoBase.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2000-2014 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.postfix.templates;
-
-import com.intellij.openapi.editor.Document;
-import com.intellij.psi.PsiElement;
-import com.intellij.util.Function;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-public abstract class PostfixTemplatePsiInfoBase implements PostfixTemplatePsiInfo {
-
- @NotNull
- public abstract List<PsiElement> getExpressions(@NotNull PsiElement context, @NotNull Document document, int newOffset);
-
- @NotNull
- public Function<PsiElement, String> getRenderer() {
- return new Function<PsiElement, String>() {
- @Override
- public String fun(@NotNull PsiElement element) {
- return element.getText();
- }
- };
- }
-}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplateWithExpressionSelector.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplateWithExpressionSelector.java
new file mode 100644
index 000000000000..d7cfbafdf7a8
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplateWithExpressionSelector.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2000-2014 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.postfix.templates;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.util.Condition;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+
+import static com.intellij.codeInsight.template.postfix.templates.PostfixTemplatesUtils.selectorTopmost;
+
+public abstract class PostfixTemplateWithExpressionSelector extends PostfixTemplate {
+
+ @NotNull
+ protected final PostfixTemplatePsiInfo myPsiInfo;
+ @NotNull
+ private final PostfixTemplateExpressionSelector mySelector;
+
+ protected PostfixTemplateWithExpressionSelector(@NotNull String name,
+ @NotNull String key,
+ @NotNull String example,
+ @NotNull PostfixTemplatePsiInfo psiInfo,
+ @NotNull PostfixTemplateExpressionSelector selector) {
+ super(name, key, example);
+ myPsiInfo = psiInfo;
+ mySelector = selector;
+ }
+
+
+ protected PostfixTemplateWithExpressionSelector(@NotNull String name,
+ @NotNull String example,
+ @NotNull PostfixTemplatePsiInfo psiInfo,
+ @NotNull PostfixTemplateExpressionSelector selector) {
+ super(name, example);
+ myPsiInfo = psiInfo;
+ mySelector = selector;
+ }
+
+ protected PostfixTemplateWithExpressionSelector(@NotNull String name,
+ @NotNull String example,
+ @NotNull PostfixTemplatePsiInfo psiInfo,
+ @NotNull Condition<PsiElement> typeChecker) {
+ this(name, example, psiInfo, selectorTopmost(typeChecker));
+ }
+
+ protected PostfixTemplateWithExpressionSelector(@NotNull String name,
+ @NotNull String example,
+ @NotNull PostfixTemplatePsiInfo psiInfo) {
+ this(name, example, psiInfo, selectorTopmost());
+ }
+
+
+ @Override
+ public final boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
+ return mySelector.hasExpression(this, context, copyDocument, newOffset);
+ }
+
+ @Override
+ public final void expand(@NotNull PsiElement context, @NotNull Editor editor) {
+ mySelector.expandTemplate(this, context, editor);
+ }
+
+ protected abstract void expandForChooseExpression(@NotNull PsiElement expression, @NotNull Editor editor);
+
+ @NotNull
+ PostfixTemplatePsiInfo getPsiInfo() {
+ return myPsiInfo;
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatesUtils.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatesUtils.java
index 877e10b53490..5ff744e3d72a 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatesUtils.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixTemplatesUtils.java
@@ -21,6 +21,8 @@ import com.intellij.lang.surroundWith.Surrounder;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.refactoring.util.CommonRefactoringUtil;
@@ -31,6 +33,22 @@ public abstract class PostfixTemplatesUtils {
private PostfixTemplatesUtils() {
}
+ public static PostfixTemplateExpressionSelector selectorWithChooser() {
+ return selectorWithChooser(Conditions.<PsiElement>alwaysTrue());
+ }
+
+ public static PostfixTemplateExpressionSelector selectorTopmost() {
+ return selectorTopmost(Conditions.<PsiElement>alwaysTrue());
+ }
+
+ public static PostfixTemplateExpressionSelector selectorWithChooser(Condition<PsiElement> condition) {
+ return new ChooserExpressionSelector(condition);
+ }
+
+ public static PostfixTemplateExpressionSelector selectorTopmost(Condition<PsiElement> condition) {
+ return new TopmostExpressionSelector(condition);
+ }
+
@Nullable
public static TextRange surround(@NotNull Surrounder surrounder,
@NotNull Editor editor,
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java
index ed1605d3a9fb..5b5c3624f33b 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java
@@ -22,7 +22,7 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
-public abstract class StatementWrapPostfixTemplate extends TypedPostfixTemplate {
+public abstract class StatementWrapPostfixTemplate extends PostfixTemplateWithExpressionSelector {
@SuppressWarnings("unchecked")
protected StatementWrapPostfixTemplate(@NotNull String name,
@@ -39,9 +39,7 @@ public abstract class StatementWrapPostfixTemplate extends TypedPostfixTemplate
}
@Override
- public void expand(@NotNull PsiElement context, @NotNull Editor editor) {
- PsiElement topmostExpression = myPsiInfo.getTopmostExpression(context);
- assert topmostExpression != null;
+ public void expandForChooseExpression(@NotNull PsiElement topmostExpression, @NotNull Editor editor) {
PsiElement parent = topmostExpression.getParent();
PsiElement expression = getWrappedExpression(topmostExpression);
PsiElement replace = parent.replace(expression);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StringBasedPostfixTemplate.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StringBasedPostfixTemplate.java
index 4d6582f071de..9f19b2011a49 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StringBasedPostfixTemplate.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StringBasedPostfixTemplate.java
@@ -26,7 +26,7 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-public abstract class StringBasedPostfixTemplate extends TypedPostfixTemplate {
+public abstract class StringBasedPostfixTemplate extends PostfixTemplateWithExpressionSelector {
public StringBasedPostfixTemplate(@NotNull String name,
@NotNull String example,
@@ -36,10 +36,8 @@ public abstract class StringBasedPostfixTemplate extends TypedPostfixTemplate {
}
@Override
- public final void expand(@NotNull PsiElement context, @NotNull Editor editor) {
- PsiElement expr = myPsiInfo.getTopmostExpression(context);
- assert expr != null;
- Project project = context.getProject();
+ public final void expandForChooseExpression(@NotNull PsiElement expr, @NotNull Editor editor) {
+ Project project = expr.getProject();
Document document = editor.getDocument();
PsiElement elementForRemoving = shouldRemoveParent() ? expr.getParent() : expr;
document.deleteString(elementForRemoving.getTextRange().getStartOffset(), elementForRemoving.getTextRange().getEndOffset());
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java
index 52ad0c4cdde8..29ea4d39ac64 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java
@@ -40,11 +40,9 @@ public abstract class SurroundPostfixTemplateBase extends StatementWrapPostfixTe
@Override
- public void expand(@NotNull PsiElement context, @NotNull final Editor editor) {
+ public final void expandForChooseExpression(@NotNull PsiElement context, @NotNull final Editor editor) {
PsiElement topmostExpression = myPsiInfo.getTopmostExpression(context);
- PsiElement expression = getWrappedExpression(topmostExpression);
- assert topmostExpression != null;
- PsiElement replace = topmostExpression.replace(expression);
+ PsiElement replace = getReplacedExpression(topmostExpression);
TextRange range = PostfixTemplatesUtils.surround(getSurrounder(), editor, replace);
if (range != null) {
@@ -52,6 +50,12 @@ public abstract class SurroundPostfixTemplateBase extends StatementWrapPostfixTe
}
}
+ protected PsiElement getReplacedExpression(PsiElement topmostExpression) {
+ PsiElement expression = getWrappedExpression(topmostExpression);
+ assert topmostExpression != null;
+ return topmostExpression.replace(expression);
+ }
+
public boolean isStatement() {
return false;
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/TopmostExpressionSelector.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/TopmostExpressionSelector.java
new file mode 100644
index 000000000000..bd6028d2d8d2
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/TopmostExpressionSelector.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2014 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.postfix.templates;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.util.Condition;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+
+
+/**
+ * See {@link PostfixTemplateExpressionSelector} for description
+ */
+public class TopmostExpressionSelector implements PostfixTemplateExpressionSelector {
+
+ @NotNull
+ private final Condition<PsiElement> myCondition;
+
+ public TopmostExpressionSelector(@NotNull Condition<PsiElement> condition) {
+
+ myCondition = condition;
+ }
+
+ @Override
+ public boolean hasExpression(@NotNull PostfixTemplateWithExpressionSelector template,
+ @NotNull PsiElement context,
+ @NotNull Document copyDocument,
+ int newOffset) {
+ PsiElement topmostExpression = template.getPsiInfo().getTopmostExpression(context);
+ return topmostExpression != null && myCondition.value(topmostExpression);
+ }
+
+ @Override
+ public void expandTemplate(@NotNull PostfixTemplateWithExpressionSelector template,
+ @NotNull PsiElement context,
+ @NotNull Editor editor) {
+ PostfixTemplatePsiInfo info = template.getPsiInfo();
+ PsiElement expression = info.getTopmostExpression(context);
+ if (expression == null) {
+ return;
+ }
+ template.expandForChooseExpression(expression, editor);
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/TypedPostfixTemplate.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/TypedPostfixTemplate.java
deleted file mode 100644
index 0d7d424d99a8..000000000000
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/TypedPostfixTemplate.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2000-2014 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.postfix.templates;
-
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.util.Condition;
-import com.intellij.psi.PsiElement;
-import org.jetbrains.annotations.NotNull;
-
-public abstract class TypedPostfixTemplate extends PostfixTemplate {
-
- protected final PostfixTemplatePsiInfo myPsiInfo;
- protected final Condition<PsiElement> myTypeChecker;
-
- protected TypedPostfixTemplate(@NotNull String name,
- @NotNull String example,
- @NotNull PostfixTemplatePsiInfo psiInfo,
- @NotNull Condition<PsiElement> typeChecker) {
- super(name, example);
- this.myPsiInfo = psiInfo;
- this.myTypeChecker = typeChecker;
- }
-
- @Override
- public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) {
- PsiElement topmostExpression = myPsiInfo.getTopmostExpression(context);
- return topmostExpression != null && myTypeChecker.value(topmostExpression);
- }
-}