delete the UI for editing Kotlin signatures in Java files
This commit is contained in:
@@ -27,9 +27,6 @@
|
|||||||
<component>
|
<component>
|
||||||
<implementation-class>org.jetbrains.kotlin.idea.configuration.ui.NonConfiguredKotlinProjectComponent</implementation-class>
|
<implementation-class>org.jetbrains.kotlin.idea.configuration.ui.NonConfiguredKotlinProjectComponent</implementation-class>
|
||||||
</component>
|
</component>
|
||||||
<component>
|
|
||||||
<implementation-class>org.jetbrains.kotlin.idea.ktSignature.KotlinSignatureInJavaMarkerUpdater</implementation-class>
|
|
||||||
</component>
|
|
||||||
<component>
|
<component>
|
||||||
<implementation-class>org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager</implementation-class>
|
<implementation-class>org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager</implementation-class>
|
||||||
</component>
|
</component>
|
||||||
@@ -84,11 +81,6 @@
|
|||||||
<add-to-group group-id="CodeMenu" anchor="last"/>
|
<add-to-group group-id="CodeMenu" anchor="last"/>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
<group id="EditorGutterKotlinPopupMenu">
|
|
||||||
<action id="ShowKotlinSignatures" class="org.jetbrains.kotlin.idea.ktSignature.ShowKotlinSignaturesAction"/>
|
|
||||||
<add-to-group group-id="EditorGutterPopupMenu" anchor="last"/>
|
|
||||||
</group>
|
|
||||||
|
|
||||||
<group id="KotlinToolsGroup" popup="true" text="Kotlin" icon="/org/jetbrains/kotlin/idea/icons/kotlin13.png"
|
<group id="KotlinToolsGroup" popup="true" text="Kotlin" icon="/org/jetbrains/kotlin/idea/icons/kotlin13.png"
|
||||||
class="org.jetbrains.kotlin.idea.actions.KotlinActionGroup">
|
class="org.jetbrains.kotlin.idea.actions.KotlinActionGroup">
|
||||||
<add-to-group group-id="ToolsMenu" anchor="last"/>
|
<add-to-group group-id="ToolsMenu" anchor="last"/>
|
||||||
@@ -407,8 +399,6 @@
|
|||||||
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinRunConfigurationProducer"/>
|
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinRunConfigurationProducer"/>
|
||||||
<codeInsight.lineMarkerProvider language="jet" implementationClass="org.jetbrains.kotlin.idea.highlighter.markers.KotlinLineMarkerProvider"/>
|
<codeInsight.lineMarkerProvider language="jet" implementationClass="org.jetbrains.kotlin.idea.highlighter.markers.KotlinLineMarkerProvider"/>
|
||||||
<codeInsight.lineMarkerProvider language="jet" implementationClass="org.jetbrains.kotlin.idea.highlighter.KotlinRecursiveCallLineMarkerProvider"/>
|
<codeInsight.lineMarkerProvider language="jet" implementationClass="org.jetbrains.kotlin.idea.highlighter.KotlinRecursiveCallLineMarkerProvider"/>
|
||||||
<codeInsight.lineMarkerProvider language="JAVA"
|
|
||||||
implementationClass="org.jetbrains.kotlin.idea.ktSignature.KotlinSignatureInJavaMarkerProvider"/>
|
|
||||||
<iconProvider implementation="org.jetbrains.kotlin.idea.JetIconProvider"/>
|
<iconProvider implementation="org.jetbrains.kotlin.idea.JetIconProvider"/>
|
||||||
<itemPresentationProvider implementationClass="org.jetbrains.kotlin.idea.presentation.JetFunctionPresenter"
|
<itemPresentationProvider implementationClass="org.jetbrains.kotlin.idea.presentation.JetFunctionPresenter"
|
||||||
forClass="org.jetbrains.kotlin.psi.JetFunction"/>
|
forClass="org.jetbrains.kotlin.psi.JetFunction"/>
|
||||||
@@ -576,11 +566,6 @@
|
|||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
</intentionAction>
|
</intentionAction>
|
||||||
|
|
||||||
<intentionAction>
|
|
||||||
<className>org.jetbrains.kotlin.idea.ktSignature.KotlinSignatureAnnotationIntention</className>
|
|
||||||
<category>Kotlin</category>
|
|
||||||
</intentionAction>
|
|
||||||
|
|
||||||
<intentionAction>
|
<intentionAction>
|
||||||
<className>org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToAssignmentIntention</className>
|
<className>org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToAssignmentIntention</className>
|
||||||
<category>Kotlin</category>
|
<category>Kotlin</category>
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-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 org.jetbrains.kotlin.idea.ktSignature;
|
|
||||||
|
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsManager;
|
|
||||||
import com.intellij.openapi.actionSystem.AnAction;
|
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
|
||||||
import com.intellij.openapi.application.Result;
|
|
||||||
import com.intellij.openapi.command.WriteCommandAction;
|
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
import com.intellij.psi.PsiAnnotation;
|
|
||||||
import com.intellij.psi.PsiModifierListOwner;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KOTLIN_SIGNATURE;
|
|
||||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.OLD_KOTLIN_SIGNATURE;
|
|
||||||
|
|
||||||
public class DeleteSignatureAction extends AnAction {
|
|
||||||
private final PsiModifierListOwner annotationOwner;
|
|
||||||
|
|
||||||
public DeleteSignatureAction(@NotNull PsiModifierListOwner elementInEditor) {
|
|
||||||
super("Delete");
|
|
||||||
this.annotationOwner = KotlinSignatureUtil.getAnalyzableAnnotationOwner(elementInEditor);
|
|
||||||
getTemplatePresentation().setVisible(annotationOwner != null && KotlinSignatureUtil.isAnnotationEditable(elementInEditor));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(AnActionEvent e) {
|
|
||||||
final Project project = e.getProject();
|
|
||||||
assert project != null;
|
|
||||||
|
|
||||||
final PsiAnnotation annotation = KotlinSignatureUtil.findKotlinSignatureAnnotation(annotationOwner);
|
|
||||||
assert annotation != null;
|
|
||||||
|
|
||||||
if (annotation.getContainingFile() != annotationOwner.getContainingFile()) {
|
|
||||||
// external annotation
|
|
||||||
new WriteCommandAction(project) {
|
|
||||||
@Override
|
|
||||||
protected void run(@NotNull Result result) throws Throwable {
|
|
||||||
ExternalAnnotationsManager.getInstance(project).deannotate(annotationOwner, KOTLIN_SIGNATURE.asString());
|
|
||||||
ExternalAnnotationsManager.getInstance(project).deannotate(annotationOwner, OLD_KOTLIN_SIGNATURE.asString());
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
new WriteCommandAction(project) {
|
|
||||||
@Override
|
|
||||||
protected void run(@NotNull Result result) throws Throwable {
|
|
||||||
annotation.delete();
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
KotlinSignatureUtil.refreshMarkers(project);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-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 org.jetbrains.kotlin.idea.ktSignature;
|
|
||||||
|
|
||||||
import com.intellij.codeInsight.navigation.NavigationUtil;
|
|
||||||
import com.intellij.openapi.actionSystem.AnAction;
|
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
|
||||||
import com.intellij.openapi.actionSystem.DataContext;
|
|
||||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
|
||||||
import com.intellij.openapi.editor.Editor;
|
|
||||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
|
||||||
import com.intellij.psi.*;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
|
|
||||||
public class EditSignatureAction extends AnAction {
|
|
||||||
private final PsiModifierListOwner elementInEditor;
|
|
||||||
|
|
||||||
public EditSignatureAction(@NotNull PsiModifierListOwner elementInEditor) {
|
|
||||||
super(KotlinSignatureUtil.isAnnotationEditable(elementInEditor) ? "Edit" : "View");
|
|
||||||
this.elementInEditor = elementInEditor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(AnActionEvent e) {
|
|
||||||
actionPerformed(e.getDataContext(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void actionPerformed(@NotNull DataContext dataContext, @Nullable Point point) {
|
|
||||||
Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
|
|
||||||
assert editor != null;
|
|
||||||
invokeEditSignature(elementInEditor, editor, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void invokeEditSignature(@NotNull PsiElement elementInEditor, @NotNull Editor editor, @Nullable Point point) {
|
|
||||||
PsiAnnotation annotation = KotlinSignatureUtil.findKotlinSignatureAnnotation(elementInEditor);
|
|
||||||
assert annotation != null;
|
|
||||||
if (annotation.getContainingFile() == elementInEditor.getContainingFile()) {
|
|
||||||
// not external, go to
|
|
||||||
for (PsiNameValuePair pair : annotation.getParameterList().getAttributes()) {
|
|
||||||
if (pair.getName() == null || "value".equals(pair.getName())) {
|
|
||||||
PsiAnnotationMemberValue value = pair.getValue();
|
|
||||||
if (value != null) {
|
|
||||||
VirtualFile virtualFile = value.getContainingFile().getVirtualFile();
|
|
||||||
assert virtualFile != null;
|
|
||||||
|
|
||||||
PsiElement firstChild = value.getFirstChild();
|
|
||||||
if (firstChild != null && firstChild.getNode().getElementType() == JavaTokenType.STRING_LITERAL) {
|
|
||||||
new OpenFileDescriptor(value.getProject(), virtualFile, value.getTextOffset() + 1).navigate(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NavigationUtil.activateFileWithPsiElement(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PsiModifierListOwner annotationOwner = KotlinSignatureUtil.getAnalyzableAnnotationOwner(elementInEditor);
|
|
||||||
boolean editable = KotlinSignatureUtil.isAnnotationEditable(elementInEditor);
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
EditSignatureBalloon balloon = new EditSignatureBalloon(annotationOwner, KotlinSignatureUtil.getKotlinSignature(annotation),
|
|
||||||
editable, annotation.getQualifiedName());
|
|
||||||
balloon.show(point, editor, elementInEditor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-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 org.jetbrains.kotlin.idea.ktSignature;
|
|
||||||
|
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsManager;
|
|
||||||
import com.intellij.openapi.Disposable;
|
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
|
||||||
import com.intellij.openapi.application.Result;
|
|
||||||
import com.intellij.openapi.command.WriteCommandAction;
|
|
||||||
import com.intellij.openapi.editor.*;
|
|
||||||
import com.intellij.openapi.editor.colors.EditorColors;
|
|
||||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
|
||||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
|
||||||
import com.intellij.openapi.editor.ex.EditorEx;
|
|
||||||
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
|
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
import com.intellij.openapi.ui.popup.Balloon;
|
|
||||||
import com.intellij.openapi.ui.popup.JBPopupAdapter;
|
|
||||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
|
||||||
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
|
|
||||||
import com.intellij.openapi.util.Disposer;
|
|
||||||
import com.intellij.openapi.wm.IdeFocusManager;
|
|
||||||
import com.intellij.psi.PsiDocumentManager;
|
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import com.intellij.psi.PsiFile;
|
|
||||||
import com.intellij.psi.PsiModifierListOwner;
|
|
||||||
import com.intellij.testFramework.LightVirtualFile;
|
|
||||||
import com.intellij.ui.awt.RelativePoint;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.idea.JetFileType;
|
|
||||||
import org.jetbrains.kotlin.psi.JetFile;
|
|
||||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.InputEvent;
|
|
||||||
import java.awt.event.KeyEvent;
|
|
||||||
|
|
||||||
class EditSignatureBalloon implements Disposable {
|
|
||||||
private final Editor editor;
|
|
||||||
private final PsiModifierListOwner annotatedElement;
|
|
||||||
private final Project project;
|
|
||||||
private final String previousSignature;
|
|
||||||
private final MyPanel panel;
|
|
||||||
private final Balloon balloon;
|
|
||||||
private final boolean editable;
|
|
||||||
private final String kotlinSignatureAnnotationFqName;
|
|
||||||
|
|
||||||
public EditSignatureBalloon(
|
|
||||||
@NotNull PsiModifierListOwner annotatedElement,
|
|
||||||
@NotNull String previousSignature,
|
|
||||||
boolean editable,
|
|
||||||
@NotNull String kotlinSignatureAnnotationFqName
|
|
||||||
) {
|
|
||||||
this.annotatedElement = annotatedElement;
|
|
||||||
this.previousSignature = previousSignature;
|
|
||||||
this.editable = editable;
|
|
||||||
this.kotlinSignatureAnnotationFqName = kotlinSignatureAnnotationFqName;
|
|
||||||
|
|
||||||
project = annotatedElement.getProject();
|
|
||||||
editor = createEditor();
|
|
||||||
panel = new MyPanel();
|
|
||||||
balloon = createBalloon();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Balloon createBalloon() {
|
|
||||||
Balloon balloon = JBPopupFactory.getInstance().createDialogBalloonBuilder(panel, "Kotlin signature")
|
|
||||||
.setHideOnClickOutside(true)
|
|
||||||
.setHideOnKeyOutside(true)
|
|
||||||
.setBlockClicksThroughBalloon(true).createBalloon();
|
|
||||||
|
|
||||||
balloon.addListener(new JBPopupAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onClosed(LightweightWindowEvent event) {
|
|
||||||
Disposer.dispose(EditSignatureBalloon.this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return balloon;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Editor createEditor() {
|
|
||||||
EditorFactory editorFactory = EditorFactory.getInstance();
|
|
||||||
assert editorFactory != null;
|
|
||||||
LightVirtualFile virtualFile = new LightVirtualFile("signature.kt", JetFileType.INSTANCE, previousSignature);
|
|
||||||
virtualFile.setWritable(editable);
|
|
||||||
final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
|
|
||||||
assert document != null;
|
|
||||||
|
|
||||||
document.addDocumentListener(new DocumentAdapter() {
|
|
||||||
@Override
|
|
||||||
public void documentChanged(DocumentEvent event) {
|
|
||||||
PsiDocumentManager psiDocManager = PsiDocumentManager.getInstance(project);
|
|
||||||
|
|
||||||
final PsiFile psiFile = psiDocManager.getPsiFile(document);
|
|
||||||
assert psiFile instanceof JetFile;
|
|
||||||
|
|
||||||
psiDocManager.performForCommittedDocument(document, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
panel.setSaveButtonEnabled(hasErrors((JetFile) psiFile));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
psiDocManager.commitDocument(document);
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
Editor editor = editorFactory.createEditor(document, project, JetFileType.INSTANCE, !editable);
|
|
||||||
EditorSettings settings = editor.getSettings();
|
|
||||||
settings.setVirtualSpace(false);
|
|
||||||
settings.setLineMarkerAreaShown(false);
|
|
||||||
settings.setFoldingOutlineShown(false);
|
|
||||||
settings.setRightMarginShown(false);
|
|
||||||
settings.setAdditionalPageAtBottom(false);
|
|
||||||
settings.setAdditionalLinesCount(2);
|
|
||||||
settings.setAdditionalColumnsCount(12);
|
|
||||||
|
|
||||||
assert editor instanceof EditorEx;
|
|
||||||
((EditorEx)editor).setEmbeddedIntoDialogWrapper(true);
|
|
||||||
|
|
||||||
editor.getColorsScheme().setColor(EditorColors.CARET_ROW_COLOR, editor.getColorsScheme().getDefaultBackground());
|
|
||||||
|
|
||||||
return editor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getLineY(@NotNull Editor editor, @NotNull PsiElement psiElementInEditor) {
|
|
||||||
LogicalPosition logicalPosition = editor.offsetToLogicalPosition(psiElementInEditor.getTextOffset());
|
|
||||||
return editor.logicalPositionToXY(logicalPosition).y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void show(@Nullable Point point, @NotNull final Editor mainEditor, @NotNull PsiElement psiElementInEditor) {
|
|
||||||
int lineY = getLineY(mainEditor, psiElementInEditor);
|
|
||||||
EditorGutterComponentEx gutter = (EditorGutterComponentEx) mainEditor.getGutter();
|
|
||||||
Point adjustedPoint;
|
|
||||||
if (point == null) {
|
|
||||||
adjustedPoint = new Point(gutter.getIconsAreaWidth() + gutter.getLineMarkerAreaOffset(), lineY);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
adjustedPoint = new Point(point.x, Math.min(lineY, point.y));
|
|
||||||
}
|
|
||||||
balloon.show(new RelativePoint(gutter, adjustedPoint), Balloon.Position.above);
|
|
||||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
IdeFocusManager.getInstance(mainEditor.getProject()).requestFocus(editor.getContentComponent(), false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
EditorFactory editorFactory = EditorFactory.getInstance();
|
|
||||||
assert editorFactory != null;
|
|
||||||
editorFactory.releaseEditor(editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveAndHide() {
|
|
||||||
balloon.hide();
|
|
||||||
|
|
||||||
final String newSignature = editor.getDocument().getText();
|
|
||||||
if (previousSignature.equals(newSignature)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
new WriteCommandAction(project) {
|
|
||||||
@Override
|
|
||||||
protected void run(@NotNull Result result) throws Throwable {
|
|
||||||
ExternalAnnotationsManager.getInstance(project).editExternalAnnotation(
|
|
||||||
annotatedElement, kotlinSignatureAnnotationFqName,
|
|
||||||
KotlinSignatureUtil.signatureToNameValuePairs(project, newSignature)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasErrors(@NotNull JetFile file) {
|
|
||||||
return AnalyzingUtils.getSyntaxErrorRanges(file).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MyPanel extends JPanel {
|
|
||||||
private final JButton saveButton;
|
|
||||||
|
|
||||||
MyPanel() {
|
|
||||||
super(new BorderLayout());
|
|
||||||
add(editor.getComponent(), BorderLayout.CENTER);
|
|
||||||
|
|
||||||
if (editable) {
|
|
||||||
JPanel toolbar = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
|
||||||
saveButton = new JButton("Save") {
|
|
||||||
@Override
|
|
||||||
public boolean isDefaultButton() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
toolbar.add(saveButton);
|
|
||||||
add(toolbar, BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
ActionListener saveAndHideListener = new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(@NotNull ActionEvent e) {
|
|
||||||
saveAndHide();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
saveButton.addActionListener(saveAndHideListener);
|
|
||||||
registerKeyboardAction(saveAndHideListener, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK),
|
|
||||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
saveButton = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerKeyboardAction(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(@NotNull ActionEvent e) {
|
|
||||||
balloon.hide();
|
|
||||||
}
|
|
||||||
}, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSaveButtonEnabled(boolean enabled) {
|
|
||||||
if (saveButton != null) {
|
|
||||||
saveButton.setEnabled(enabled);
|
|
||||||
saveButton.setToolTipText(enabled ? null : "Please fix errors in signature to save it.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-225
@@ -1,225 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-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 org.jetbrains.kotlin.idea.ktSignature;
|
|
||||||
|
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsListener;
|
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsManager;
|
|
||||||
import com.intellij.codeInsight.intention.AddAnnotationFix;
|
|
||||||
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
|
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
|
||||||
import com.intellij.openapi.application.ModalityState;
|
|
||||||
import com.intellij.openapi.editor.Editor;
|
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
import com.intellij.openapi.util.Iconable;
|
|
||||||
import com.intellij.openapi.util.TextRange;
|
|
||||||
import com.intellij.psi.*;
|
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
|
||||||
import com.intellij.psi.util.PsiUtil;
|
|
||||||
import com.intellij.util.IncorrectOperationException;
|
|
||||||
import com.intellij.util.messages.MessageBusConnection;
|
|
||||||
import kotlin.Unit;
|
|
||||||
import kotlin.jvm.functions.Function1;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor;
|
|
||||||
import org.jetbrains.kotlin.idea.JetBundle;
|
|
||||||
import org.jetbrains.kotlin.idea.JetIcons;
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
|
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaConstructorImpl;
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaFieldImpl;
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaMethodImpl;
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier;
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions;
|
|
||||||
import org.jetbrains.kotlin.renderer.NameShortness;
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KOTLIN_SIGNATURE;
|
|
||||||
|
|
||||||
public class KotlinSignatureAnnotationIntention extends BaseIntentionAction implements Iconable {
|
|
||||||
private static final DescriptorRenderer RENDERER = DescriptorRenderer.Companion.withOptions(
|
|
||||||
new Function1<DescriptorRendererOptions, Unit>() {
|
|
||||||
@Override
|
|
||||||
public Unit invoke(DescriptorRendererOptions options) {
|
|
||||||
options.setTypeNormalizer(IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES);
|
|
||||||
options.setNameShortness(NameShortness.SHORT);
|
|
||||||
options.setModifiers(Collections.<DescriptorRendererModifier>emptySet());
|
|
||||||
options.setWithDefinedIn(false);
|
|
||||||
return Unit.INSTANCE$;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public String getFamilyName() {
|
|
||||||
return JetBundle.message("add.kotlin.signature.action.family.name");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Icon getIcon(@IconFlags int flags) {
|
|
||||||
return JetIcons.SMALL_LOGO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
|
||||||
PsiMember memberUnderCaret = findMemberUnderCaret(file, editor);
|
|
||||||
if (memberUnderCaret == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiModifierListOwner annotationOwner = KotlinSignatureUtil.getAnalyzableAnnotationOwner(memberUnderCaret);
|
|
||||||
if (annotationOwner == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PsiUtil.isLanguageLevel5OrHigher(annotationOwner)) return false;
|
|
||||||
|
|
||||||
if (KotlinSignatureUtil.findKotlinSignatureAnnotation(annotationOwner) != null) {
|
|
||||||
if (KotlinSignatureUtil.isAnnotationEditable(annotationOwner)) {
|
|
||||||
setText(JetBundle.message("edit.kotlin.signature.action.text"));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setText(JetBundle.message("view.kotlin.signature.action.text"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setText(JetBundle.message("add.kotlin.signature.action.text"));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
|
|
||||||
final PsiMember annotatedElement = findMemberUnderCaret(file, editor);
|
|
||||||
|
|
||||||
assert annotatedElement != null;
|
|
||||||
|
|
||||||
if (KotlinSignatureUtil.findKotlinSignatureAnnotation(annotatedElement) != null) {
|
|
||||||
EditSignatureAction.invokeEditSignature(annotatedElement, editor, null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String signature = getDefaultSignature(project, annotatedElement);
|
|
||||||
|
|
||||||
final MessageBusConnection busConnection = project.getMessageBus().connect();
|
|
||||||
busConnection.subscribe(ExternalAnnotationsManager.TOPIC, new ExternalAnnotationsListener.Adapter() {
|
|
||||||
@Override
|
|
||||||
public void afterExternalAnnotationChanging(@NotNull PsiModifierListOwner owner, @NotNull String annotationFQName, boolean successful) {
|
|
||||||
busConnection.disconnect();
|
|
||||||
|
|
||||||
if (successful && owner == annotatedElement && KOTLIN_SIGNATURE.asString().equals(annotationFQName)) {
|
|
||||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
KotlinSignatureUtil.refreshMarkers(project);
|
|
||||||
EditSignatureAction.invokeEditSignature(annotatedElement, editor, null);
|
|
||||||
}
|
|
||||||
}, ModalityState.NON_MODAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
AddAnnotationFix addAnnotationFix = new AddAnnotationFix(
|
|
||||||
KOTLIN_SIGNATURE.asString(), annotatedElement, KotlinSignatureUtil
|
|
||||||
.signatureToNameValuePairs(annotatedElement.getProject(), signature));
|
|
||||||
addAnnotationFix.invoke(project, editor, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String renderMember(PsiMember member) {
|
|
||||||
PsiClass containingClass = member.getContainingClass();
|
|
||||||
assert containingClass != null;
|
|
||||||
String qualifiedName = containingClass.getQualifiedName();
|
|
||||||
assert qualifiedName != null;
|
|
||||||
|
|
||||||
return member.getName() + " in " + qualifiedName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static String getDefaultSignature(@NotNull Project project, @NotNull PsiMember element) {
|
|
||||||
PsiMember analyzableAnnotationOwner = KotlinSignatureUtil.getAnalyzableAnnotationOwner(element);
|
|
||||||
assert analyzableAnnotationOwner != null;
|
|
||||||
JavaDescriptorResolver javaDescriptorResolver = ResolvePackage.getJavaDescriptorResolver(analyzableAnnotationOwner);
|
|
||||||
|
|
||||||
if (analyzableAnnotationOwner instanceof PsiMethod) {
|
|
||||||
PsiMethod psiMethod = (PsiMethod) analyzableAnnotationOwner;
|
|
||||||
if (psiMethod.isConstructor()) {
|
|
||||||
ConstructorDescriptor constructorDescriptor =
|
|
||||||
ResolvePackage.resolveConstructor(javaDescriptorResolver, new JavaConstructorImpl(psiMethod));
|
|
||||||
assert constructorDescriptor != null: "Couldn't find constructor descriptor for " + renderMember(psiMethod);
|
|
||||||
return getDefaultConstructorAnnotation(constructorDescriptor);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
FunctionDescriptor functionDescriptor = ResolvePackage.resolveMethod(javaDescriptorResolver, new JavaMethodImpl(psiMethod));
|
|
||||||
assert functionDescriptor != null: "Couldn't find function descriptor for " + renderMember(psiMethod);
|
|
||||||
return RENDERER.render(functionDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (analyzableAnnotationOwner instanceof PsiField) {
|
|
||||||
VariableDescriptor variableDescriptor =
|
|
||||||
ResolvePackage.resolveField(javaDescriptorResolver, new JavaFieldImpl((PsiField) analyzableAnnotationOwner));
|
|
||||||
assert variableDescriptor != null : "Couldn't find variable descriptor for field " + renderMember(analyzableAnnotationOwner);
|
|
||||||
return RENDERER.render(variableDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalStateException("PsiMethod or PsiField are expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getDefaultConstructorAnnotation(ConstructorDescriptor constructorDescriptor) {
|
|
||||||
return String.format("fun %s%s", constructorDescriptor.getContainingDeclaration().getName(), RENDERER.renderFunctionParameters(constructorDescriptor));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static PsiMember findMemberUnderCaret(@NotNull PsiElement file, Editor editor) {
|
|
||||||
int offset = editor.getCaretModel().getOffset();
|
|
||||||
PsiMember methodMember = findMethod(file, offset);
|
|
||||||
if (methodMember != null) {
|
|
||||||
return methodMember;
|
|
||||||
}
|
|
||||||
|
|
||||||
return findField(file, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static PsiMethod findMethod(@NotNull PsiElement file, int offset) {
|
|
||||||
PsiElement element = file.findElementAt(offset);
|
|
||||||
PsiMethod res = PsiTreeUtil.getParentOfType(element, PsiMethod.class);
|
|
||||||
if (res == null) return null;
|
|
||||||
|
|
||||||
//Not available in method's body
|
|
||||||
PsiCodeBlock body = res.getBody();
|
|
||||||
if (body != null) {
|
|
||||||
TextRange bodyRange = body.getTextRange();
|
|
||||||
if (bodyRange != null && bodyRange.getStartOffset() <= offset) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static PsiField findField(@NotNull PsiElement file, int offset) {
|
|
||||||
return PsiTreeUtil.getParentOfType(file.findElementAt(offset), PsiField.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-197
@@ -1,197 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-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 org.jetbrains.kotlin.idea.ktSignature;
|
|
||||||
|
|
||||||
import com.intellij.codeHighlighting.Pass;
|
|
||||||
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler;
|
|
||||||
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
|
||||||
import com.intellij.codeInsight.daemon.LineMarkerProvider;
|
|
||||||
import com.intellij.icons.AllIcons;
|
|
||||||
import com.intellij.ide.DataManager;
|
|
||||||
import com.intellij.ide.util.PropertiesComponent;
|
|
||||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
|
||||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
|
||||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
|
||||||
import com.intellij.openapi.module.Module;
|
|
||||||
import com.intellij.openapi.module.ModuleUtilCore;
|
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
|
||||||
import com.intellij.psi.*;
|
|
||||||
import com.intellij.util.ExceptionUtil;
|
|
||||||
import com.intellij.util.Function;
|
|
||||||
import com.intellij.util.ui.UIUtil;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
|
||||||
import org.jetbrains.kotlin.idea.JetIcons;
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.KotlinCacheService;
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
|
|
||||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil;
|
|
||||||
import org.jetbrains.kotlin.load.java.JavaBindingContext;
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform;
|
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class KotlinSignatureInJavaMarkerProvider implements LineMarkerProvider {
|
|
||||||
private static final String SHOW_MARKERS_PROPERTY = "kotlin.signature.markers.enabled";
|
|
||||||
private static final Logger LOG = Logger.getInstance(KotlinSignatureInJavaMarkerProvider.class);
|
|
||||||
|
|
||||||
private static final GutterIconNavigationHandler<PsiModifierListOwner> NAVIGATION_HANDLER = new GutterIconNavigationHandler<PsiModifierListOwner>() {
|
|
||||||
@Override
|
|
||||||
public void navigate(MouseEvent e, PsiModifierListOwner element) {
|
|
||||||
if (UIUtil.isActionClick(e, MouseEvent.MOUSE_RELEASED)) {
|
|
||||||
new EditSignatureAction(element).actionPerformed(DataManager.getInstance().getDataContext(e.getComponent()), e.getPoint());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {
|
|
||||||
if (elements.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiElement firstElement = elements.get(0);
|
|
||||||
Project project = firstElement.getProject();
|
|
||||||
if (!isMarkersEnabled(project)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ProjectStructureUtil.hasJvmKotlinModules(project)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Module module = ModuleUtilCore.findModuleForPsiElement(firstElement);
|
|
||||||
if (module != null && !ProjectStructureUtil.isUsedInKotlinJavaModule(module)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
markElements(elements, result, firstElement.getContainingFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void markElements(
|
|
||||||
@NotNull List<PsiElement> elements,
|
|
||||||
@NotNull Collection<LineMarkerInfo> result,
|
|
||||||
@NotNull PsiFile psiFile
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
for (PsiElement element : elements) {
|
|
||||||
markElement(element, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (AssertionError error) {
|
|
||||||
LOG.warn("Exception while collecting KotlinSignature markers:\n" + ExceptionUtil.getThrowableText(error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void markElement(@NotNull PsiElement element, @NotNull Collection<LineMarkerInfo> result) {
|
|
||||||
Project project = element.getProject();
|
|
||||||
PsiModifierListOwner annotationOwner = KotlinSignatureUtil.getAnalyzableAnnotationOwner(element);
|
|
||||||
if (!(annotationOwner instanceof PsiMember)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeclarationDescriptor memberDescriptor = ResolvePackage.getJavaMemberDescriptor((PsiMember) annotationOwner);
|
|
||||||
|
|
||||||
if (memberDescriptor == null) return;
|
|
||||||
|
|
||||||
BindingContext bindingContext = KotlinCacheService.getInstance(project).getGlobalFacade(JvmPlatform.INSTANCE$)
|
|
||||||
.getFrontendService(annotationOwner, BindingTrace.class).getBindingContext();
|
|
||||||
|
|
||||||
List<String> errors = bindingContext.get(JavaBindingContext.LOAD_FROM_JAVA_SIGNATURE_ERRORS, memberDescriptor);
|
|
||||||
boolean hasSignatureAnnotation = KotlinSignatureUtil.findKotlinSignatureAnnotation(annotationOwner) != null;
|
|
||||||
|
|
||||||
if (errors != null || hasSignatureAnnotation) {
|
|
||||||
result.add(new MyLineMarkerInfo((PsiModifierListOwner) element, errors, hasSignatureAnnotation));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isMarkersEnabled(@NotNull Project project) {
|
|
||||||
return PropertiesComponent.getInstance(project).getBoolean(SHOW_MARKERS_PROPERTY, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setMarkersEnabled(@NotNull Project project, boolean value) {
|
|
||||||
PropertiesComponent.getInstance(project).setValue(SHOW_MARKERS_PROPERTY, Boolean.toString(value));
|
|
||||||
KotlinSignatureUtil.refreshMarkers(project);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class MyLineMarkerInfo extends LineMarkerInfo<PsiModifierListOwner> {
|
|
||||||
public MyLineMarkerInfo(PsiModifierListOwner element, @Nullable List<String> errors, boolean hasAnnotation) {
|
|
||||||
super(element, element.getTextOffset(), errors != null ? AllIcons.Ide.Error : JetIcons.SMALL_LOGO, Pass.UPDATE_OVERRIDEN_MARKERS,
|
|
||||||
new TooltipProvider(errors), hasAnnotation ? NAVIGATION_HANDLER : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public GutterIconRenderer createGutterRenderer() {
|
|
||||||
return new LineMarkerGutterIconRenderer<PsiModifierListOwner>(this) {
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public ActionGroup getPopupMenuActions() {
|
|
||||||
if (getNavigationHandler() == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiModifierListOwner element = getElement();
|
|
||||||
assert element != null;
|
|
||||||
|
|
||||||
return new DefaultActionGroup(new EditSignatureAction(element), new DeleteSignatureAction(element));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TooltipProvider implements Function<PsiElement, String> {
|
|
||||||
private final @Nullable List<String> errors;
|
|
||||||
|
|
||||||
private TooltipProvider(@Nullable List<String> errors) {
|
|
||||||
this.errors = errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public String fun(PsiElement element) {
|
|
||||||
PsiAnnotation annotation = KotlinSignatureUtil.findKotlinSignatureAnnotation(element);
|
|
||||||
|
|
||||||
if (annotation == null) return errorsString();
|
|
||||||
|
|
||||||
String signature = KotlinSignatureUtil.getKotlinSignature(annotation);
|
|
||||||
String text = "Alternative Kotlin signature is available for this method:\n" + StringUtil.escapeXml(signature);
|
|
||||||
if (errors == null) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
return text + "\nIt has the following " + StringUtil.pluralize("error", errors.size()) + ":\n" + errorsString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String errorsString() {
|
|
||||||
assert errors != null;
|
|
||||||
return StringUtil.escapeXml(StringUtil.join(errors, "\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-38
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-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 org.jetbrains.kotlin.idea.ktSignature;
|
|
||||||
|
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsListener;
|
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsManager;
|
|
||||||
import com.intellij.openapi.components.AbstractProjectComponent;
|
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
|
|
||||||
public class KotlinSignatureInJavaMarkerUpdater extends AbstractProjectComponent {
|
|
||||||
protected KotlinSignatureInJavaMarkerUpdater(Project project) {
|
|
||||||
super(project);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initComponent() {
|
|
||||||
myProject.getMessageBus().connect().subscribe(ExternalAnnotationsManager.TOPIC, new ExternalAnnotationsListener.Adapter() {
|
|
||||||
@Override
|
|
||||||
public void externalAnnotationsChangedExternally() {
|
|
||||||
KotlinSignatureUtil.refreshMarkers(myProject);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-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 org.jetbrains.kotlin.idea.ktSignature;
|
|
||||||
|
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsManager;
|
|
||||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
|
||||||
import com.intellij.psi.*;
|
|
||||||
import com.intellij.psi.impl.compiled.ClsElementImpl;
|
|
||||||
import com.intellij.psi.util.PsiUtil;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.load.java.components.PsiBasedExternalAnnotationResolver;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KOTLIN_SIGNATURE;
|
|
||||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.OLD_KOTLIN_SIGNATURE;
|
|
||||||
|
|
||||||
class KotlinSignatureUtil {
|
|
||||||
private KotlinSignatureUtil() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For element from library sources or decompiled library sources return corresponding cls element */
|
|
||||||
@Nullable
|
|
||||||
static PsiMember getAnalyzableAnnotationOwner(@NotNull PsiElement element) {
|
|
||||||
if (!(element instanceof PsiField || element instanceof PsiMethod) || element instanceof PsiEnumConstant) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiMember member = (PsiMember) element;
|
|
||||||
if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiClass containingClass = member.getContainingClass();
|
|
||||||
if (containingClass != null && PsiUtil.isLocalOrAnonymousClass(containingClass)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiMember annotationOwner = element.getOriginalElement() instanceof PsiMember
|
|
||||||
? (PsiMember) element.getOriginalElement()
|
|
||||||
: (PsiMember) element;
|
|
||||||
|
|
||||||
if (!annotationOwner.isPhysical()) {
|
|
||||||
// this is fake PsiFile which is mirror for ClsFile without sources
|
|
||||||
PsiCompiledElement compiledElement = element.getUserData(ClsElementImpl.COMPILED_ELEMENT);
|
|
||||||
if (compiledElement instanceof PsiMember) {
|
|
||||||
return (PsiMember) compiledElement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return annotationOwner;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
static String getKotlinSignature(@NotNull PsiAnnotation kotlinSignatureAnnotation) {
|
|
||||||
PsiNameValuePair pair = kotlinSignatureAnnotation.getParameterList().getAttributes()[0];
|
|
||||||
PsiAnnotationMemberValue value = pair.getValue();
|
|
||||||
if (value == null) {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
else if (value instanceof PsiLiteralExpression) {
|
|
||||||
Object valueObject = ((PsiLiteralExpression) value).getValue();
|
|
||||||
return valueObject == null ? "null" : StringUtil.unescapeStringCharacters(valueObject.toString());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return value.getText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
static PsiNameValuePair[] signatureToNameValuePairs(@NotNull Project project, @NotNull String signature) {
|
|
||||||
return JavaPsiFacade.getElementFactory(project).createAnnotationFromText(
|
|
||||||
"@" + KOTLIN_SIGNATURE + "(value=\"" + StringUtil.escapeStringCharacters(signature) + "\")", null)
|
|
||||||
.getParameterList().getAttributes();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
static PsiAnnotation findKotlinSignatureAnnotation(@NotNull PsiElement element) {
|
|
||||||
if (!(element instanceof PsiModifierListOwner)) return null;
|
|
||||||
PsiModifierListOwner annotationOwner = getAnalyzableAnnotationOwner(element);
|
|
||||||
if (annotationOwner == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiModifierList list = annotationOwner.getModifierList();
|
|
||||||
PsiAnnotation annotation = list == null ? null : list.findAnnotation(KOTLIN_SIGNATURE.asString());
|
|
||||||
if (annotation == null) {
|
|
||||||
annotation = PsiBasedExternalAnnotationResolver.findExternalAnnotation(annotationOwner, KOTLIN_SIGNATURE);
|
|
||||||
if (annotation == null) {
|
|
||||||
annotation = list == null ? null : list.findAnnotation(OLD_KOTLIN_SIGNATURE.asString());
|
|
||||||
if (annotation == null) {
|
|
||||||
annotation = PsiBasedExternalAnnotationResolver.findExternalAnnotation(annotationOwner, OLD_KOTLIN_SIGNATURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (annotation == null) return null;
|
|
||||||
if (annotation.getParameterList().getAttributes().length == 0) return null;
|
|
||||||
return annotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void refreshMarkers(@NotNull Project project) {
|
|
||||||
DaemonCodeAnalyzer.getInstance(project).restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean isAnnotationEditable(@NotNull PsiElement element) {
|
|
||||||
PsiModifierListOwner annotationOwner = getAnalyzableAnnotationOwner(element);
|
|
||||||
if (annotationOwner == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PsiAnnotation annotation = findKotlinSignatureAnnotation(element);
|
|
||||||
assert annotation != null : "Annotation not found for " + element.getText();
|
|
||||||
if (annotation.getContainingFile() == annotationOwner.getContainingFile()) {
|
|
||||||
return annotation.isWritable();
|
|
||||||
} else {
|
|
||||||
ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(element.getProject());
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
return annotationsManager.isExternalAnnotationWritable(annotationOwner, annotation.getQualifiedName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-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 org.jetbrains.kotlin.idea.ktSignature;
|
|
||||||
|
|
||||||
import com.intellij.lang.java.JavaLanguage;
|
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
|
||||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
|
||||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
|
||||||
import com.intellij.openapi.project.Project;
|
|
||||||
import com.intellij.psi.PsiFile;
|
|
||||||
|
|
||||||
public class ShowKotlinSignaturesAction extends ToggleAction {
|
|
||||||
public ShowKotlinSignaturesAction() {
|
|
||||||
super("Show Kotlin Signatures");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSelected(AnActionEvent e) {
|
|
||||||
Project project = e.getProject();
|
|
||||||
return project != null && KotlinSignatureInJavaMarkerProvider.isMarkersEnabled(project);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(AnActionEvent e) {
|
|
||||||
super.update(e);
|
|
||||||
e.getPresentation().setVisible(false);
|
|
||||||
PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
|
|
||||||
if (psiFile != null && psiFile.getLanguage() == JavaLanguage.INSTANCE) {
|
|
||||||
e.getPresentation().setVisible(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSelected(AnActionEvent e, boolean state) {
|
|
||||||
Project project = e.getProject();
|
|
||||||
assert project != null;
|
|
||||||
KotlinSignatureInJavaMarkerProvider.setMarkersEnabled(project, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user