From a07577abce74d4e6e9fee9bfe2f6b1e296922279 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Tue, 9 Jun 2015 22:44:28 +0300 Subject: [PATCH] ShowExpressionTypeAction: extension point & providers --- .../codeInsight/hint/JavaTypeProvider.java | 51 ++++++++ .../intellij/lang/ExpressionTypeProvider.java | 35 +++++ .../lang/LanguageExpressionTypes.java | 28 ++++ .../hint/ShowExpressionTypeHandler.java | 123 ++++++++++++++++++ .../actions/ShowExpressionTypeAction.java | 47 +++++++ .../src/messages/ActionsBundle.properties | 2 + .../src/META-INF/LangExtensionPoints.xml | 3 + .../src/idea/Keymap_Default.xml | 3 + .../src/idea/LangActions.xml | 1 + resources/src/META-INF/IdeaPlugin.xml | 1 + 10 files changed, 294 insertions(+) create mode 100644 java/java-impl/src/com/intellij/codeInsight/hint/JavaTypeProvider.java create mode 100644 platform/lang-api/src/com/intellij/lang/ExpressionTypeProvider.java create mode 100644 platform/lang-api/src/com/intellij/lang/LanguageExpressionTypes.java create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/hint/ShowExpressionTypeHandler.java create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowExpressionTypeAction.java diff --git a/java/java-impl/src/com/intellij/codeInsight/hint/JavaTypeProvider.java b/java/java-impl/src/com/intellij/codeInsight/hint/JavaTypeProvider.java new file mode 100644 index 000000000000..17306f0c9159 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/hint/JavaTypeProvider.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2015 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.hint; + +import com.intellij.lang.ExpressionTypeProvider; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiType; +import com.intellij.psi.SyntaxTraverser; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author gregsh + */ +public class JavaTypeProvider extends ExpressionTypeProvider { + @NotNull + @Override + public String getInformationHint(@NotNull PsiExpression element) { + PsiType type = element.getType(); + String text = type == null ? "" : type.getCanonicalText(); + return StringUtil.escapeXml(text); + } + + @NotNull + @Override + public String getErrorHint() { + return "No expression found"; + } + + @NotNull + @Override + public List getExpressionsAt(@NotNull PsiElement elementAt) { + return SyntaxTraverser.psiTraverser().parents(elementAt).filter(PsiExpression.class).toList(); + } +} diff --git a/platform/lang-api/src/com/intellij/lang/ExpressionTypeProvider.java b/platform/lang-api/src/com/intellij/lang/ExpressionTypeProvider.java new file mode 100644 index 000000000000..163dc3f4d0c0 --- /dev/null +++ b/platform/lang-api/src/com/intellij/lang/ExpressionTypeProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2015 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.lang; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author gregsh + */ +public abstract class ExpressionTypeProvider { + @NotNull + public abstract String getInformationHint(@NotNull T element); + + @NotNull + public abstract String getErrorHint(); + + @NotNull + public abstract List getExpressionsAt(@NotNull PsiElement elementAt); +} diff --git a/platform/lang-api/src/com/intellij/lang/LanguageExpressionTypes.java b/platform/lang-api/src/com/intellij/lang/LanguageExpressionTypes.java new file mode 100644 index 000000000000..1e4b4a3299d1 --- /dev/null +++ b/platform/lang-api/src/com/intellij/lang/LanguageExpressionTypes.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2015 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. + */ + +/* + * @author max + */ +package com.intellij.lang; + +public class LanguageExpressionTypes extends LanguageExtension { + public static final LanguageExpressionTypes INSTANCE = new LanguageExpressionTypes(); + + private LanguageExpressionTypes() { + super("com.intellij.codeInsight.typeInfo"); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ShowExpressionTypeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ShowExpressionTypeHandler.java new file mode 100644 index 000000000000..2eaeb0509595 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ShowExpressionTypeHandler.java @@ -0,0 +1,123 @@ +/* + * Copyright 2000-2015 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.hint; + +import com.intellij.codeInsight.CodeInsightActionHandler; +import com.intellij.codeInsight.TargetElementUtil; +import com.intellij.lang.ExpressionTypeProvider; +import com.intellij.lang.Language; +import com.intellij.lang.LanguageExpressionTypes; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.util.EditorUtil; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pass; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.refactoring.IntroduceTargetChooser; +import com.intellij.util.Function; +import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.JBIterable; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.Set; + +public class ShowExpressionTypeHandler implements CodeInsightActionHandler { + + @Override + public boolean startInWriteAction() { + return false; + } + + public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file) { + ApplicationManager.getApplication().assertIsDispatchThread(); + PsiDocumentManager.getInstance(project).commitAllDocuments(); + + PsiElement elementAt = file.findElementAt( + TargetElementUtil.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset())); + if (elementAt == null) return; + + Language language = elementAt.getLanguage(); + final Set handlers = getHandlers(project, language, file.getViewProvider().getBaseLanguage()); + if (handlers.isEmpty()) return; + + TextRange range = EditorUtil.getSelectionInAnyMode(editor); + final Map map = ContainerUtil.newLinkedHashMap(); + for (ExpressionTypeProvider handler : handlers) { + for (PsiElement element : ((ExpressionTypeProvider)handler).getExpressionsAt(elementAt)) { + if (!element.getTextRange().contains(range)) continue; + map.put(element, handler); + } + } + Pass callback = new Pass() { + @Override + public void pass(@NotNull PsiElement expression) { + //noinspection unchecked + ExpressionTypeProvider provider = ObjectUtils.assertNotNull(map.get(expression)); + final String informationHint = provider.getInformationHint(expression); + TextRange range = expression.getTextRange(); + editor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset()); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + HintManager.getInstance().showInformationHint(editor, informationHint); + } + }); + } + }; + if (map.isEmpty()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + String errorHint = ObjectUtils.assertNotNull(ContainerUtil.getFirstItem(handlers)).getErrorHint(); + HintManager.getInstance().showErrorHint(editor, errorHint); + } + }); + } + else if (map.size() == 1) { + callback.pass(ObjectUtils.assertNotNull(ContainerUtil.getFirstItem(map.keySet()))); + } + else { + IntroduceTargetChooser.showChooser( + editor, ContainerUtil.newArrayList(map.keySet()), callback, + new Function() { + @Override + public String fun(@NotNull PsiElement expression) { + return expression.getText(); + } + } + ); + } + } + + @NotNull + public static Set getHandlers(final Project project, Language... languages) { + return JBIterable.of(languages).flatten(new Function>() { + @Override + public Iterable fun(Language language) { + return DumbService.getInstance(project).filterByDumbAwareness(LanguageExpressionTypes.INSTANCE.allForLanguage(language)); + } + }).addAllTo(ContainerUtil.newLinkedHashSet()); + } + +} + diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowExpressionTypeAction.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowExpressionTypeAction.java new file mode 100644 index 000000000000..dff9046a4f4f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowExpressionTypeAction.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2015 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.hint.actions; + +import com.intellij.codeInsight.CodeInsightActionHandler; +import com.intellij.codeInsight.actions.BaseCodeInsightAction; +import com.intellij.codeInsight.hint.ShowExpressionTypeHandler; +import com.intellij.lang.Language; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiUtilCore; +import org.jetbrains.annotations.NotNull; + +public class ShowExpressionTypeAction extends BaseCodeInsightAction implements DumbAware { + public ShowExpressionTypeAction() { + setEnabledInModalContext(true); + } + + @NotNull + @Override + protected CodeInsightActionHandler getHandler() { + return new ShowExpressionTypeHandler(); + } + + @Override + protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull final PsiFile file) { + Language language = PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().getOffset()); + return !ShowExpressionTypeHandler.getHandlers(project, language, file.getViewProvider().getBaseLanguage()).isEmpty(); + } + +} \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 51b020b50bfa..249689fe7bcb 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -392,6 +392,8 @@ action.ShowSiblings.text=Show Siblings action.ShowSiblings.description=Show a popup window with the symbol siblings content action.ParameterInfo.text=_Parameter Info action.ParameterInfo.description=Show parameters of the method call at caret +action.TypeInfo.text=_Type Info +action.TypeInfo.description=Show type of the selected expression action.EditorContextInfo.text=_Context Info action.EditorContextInfo.description=Show the current method or class declaration when it is not visible action.ShowErrorDescription.text=E_rror Description diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 01cb8aced2b7..9ccd239588a7 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -556,6 +556,9 @@ + + + diff --git a/platform/platform-resources/src/idea/Keymap_Default.xml b/platform/platform-resources/src/idea/Keymap_Default.xml index 0ef4d0fba164..df5b99edcf95 100644 --- a/platform/platform-resources/src/idea/Keymap_Default.xml +++ b/platform/platform-resources/src/idea/Keymap_Default.xml @@ -422,6 +422,9 @@ + + + diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 36671e305f56..229a96b53fe6 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -165,6 +165,7 @@ + diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index d9ed97e9257a..0a8c97f22364 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1028,6 +1028,7 @@ +