diff --git a/java/java-impl/src/META-INF/JavaPlugin.xml b/java/java-impl/src/META-INF/JavaPlugin.xml
index 6e3a4228adcb..808b60de41ac 100644
--- a/java/java-impl/src/META-INF/JavaPlugin.xml
+++ b/java/java-impl/src/META-INF/JavaPlugin.xml
@@ -60,6 +60,9 @@
com.intellij.codeInsight.hints.AnnotationHintsPassFactory
+
+ com.intellij.lang.java.JavaModuleRenameListener
+
com.intellij.openapi.vcs.impl.ModuleVcsDetector
@@ -299,7 +302,6 @@
-
@@ -1109,7 +1111,6 @@
-
@@ -1155,6 +1156,7 @@
+
diff --git a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationHintsConfigurable.kt b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationHintsConfigurable.kt
deleted file mode 100644
index daa9cc67c4bd..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationHintsConfigurable.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
-package com.intellij.codeInsight.hints
-
-import com.intellij.application.options.editor.CodeFoldingOptionsProvider
-import com.intellij.codeInsight.CodeInsightSettings
-import com.intellij.openapi.application.ApplicationBundle
-import com.intellij.openapi.options.BeanConfigurable
-
-/**
- * @author egor
- */
-class AnnotationHintsConfigurable : BeanConfigurable(), CodeFoldingOptionsProvider {
- init {
- val settings = CodeInsightSettings.getInstance()
-
- checkBox(ApplicationBundle.message("editor.appearance.show.external.annotations"), settings::SHOW_EXTERNAL_ANNOTATIONS_INLINE)
- checkBox(ApplicationBundle.message("editor.appearance.show.inferred.annotations"), settings::SHOW_INFERRED_ANNOTATIONS_INLINE)
- }
-
- override fun apply() {
- super.apply()
- AnnotationHintsPassFactory.modificationStampHolder.forceHintsUpdateOnNextPass()
- }
-}
diff --git a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationHintsPass.kt b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationHintsPass.kt
deleted file mode 100644
index 5ab09d137a23..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationHintsPass.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
-package com.intellij.codeInsight.hints
-
-import com.intellij.codeInsight.CodeInsightSettings
-import com.intellij.codeInsight.ExternalAnnotationsManager
-import com.intellij.codeInsight.InferredAnnotationsManager
-import com.intellij.codeInsight.daemon.impl.HintRenderer
-import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.ToggleAction
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.editor.Inlay
-import com.intellij.openapi.util.Key
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.psi.PsiAnnotation
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiModifierListOwner
-
-class AnnotationHintsPass(
- rootElement: PsiElement, editor: Editor,
- modificationStampHolder: ModificationStampHolder
-) : ElementProcessingHintPass(rootElement, editor, modificationStampHolder) {
-
- override fun isAvailable(virtualFile: VirtualFile): Boolean =
- (CodeInsightSettings.getInstance().SHOW_EXTERNAL_ANNOTATIONS_INLINE
- && ExternalAnnotationsManager.getInstance(myProject).hasAnnotationRootsForFile(virtualFile))
- || CodeInsightSettings.getInstance().SHOW_INFERRED_ANNOTATIONS_INLINE
-
- override fun collectElementHints(element: PsiElement, collector: (offset: Int, hint: String) -> Unit) {
- if (element is PsiModifierListOwner) {
- var annotations = emptySequence()
- if (CodeInsightSettings.getInstance().SHOW_EXTERNAL_ANNOTATIONS_INLINE) {
- annotations += ExternalAnnotationsManager.getInstance(myProject).findExternalAnnotations(element).orEmpty()
- }
- if (CodeInsightSettings.getInstance().SHOW_INFERRED_ANNOTATIONS_INLINE) {
- annotations += InferredAnnotationsManager.getInstance(myProject).findInferredAnnotations(element)
- }
-
- val shownAnnotations = mutableSetOf()
- annotations.forEach {
- val nameReferenceElement = it.nameReferenceElement
- if (nameReferenceElement != null && element.modifierList != null &&
- (shownAnnotations.add(nameReferenceElement.qualifiedName) || JavaDocInfoGenerator.isRepeatableAnnotationType(it))) {
- val offset = element.modifierList!!.textRange.startOffset
- collector.invoke(offset, "@" + nameReferenceElement.referenceName + it.parameterList.text)
- }
- }
- }
- }
-
- override fun getHintKey(): Key = ANNOTATION_INLAY_KEY
- override fun createRenderer(text: String): HintRenderer = AnnotationHintRenderer(text)
-
- companion object {
- private val ANNOTATION_INLAY_KEY = Key.create("ANNOTATION_INLAY_KEY")
- }
-
- private class AnnotationHintRenderer(text: String) : HintRenderer(text) {
- override fun getContextMenuGroupId(inlay: Inlay<*>) = "AnnotationHintsContextMenu"
- }
-
- class ToggleExternalAnnotationsHintsAction : ToggleAction() {
- override fun isSelected(e: AnActionEvent): Boolean = CodeInsightSettings.getInstance().SHOW_EXTERNAL_ANNOTATIONS_INLINE
-
- override fun setSelected(e: AnActionEvent, state: Boolean) {
- CodeInsightSettings.getInstance().SHOW_EXTERNAL_ANNOTATIONS_INLINE = state
- AnnotationHintsPassFactory.modificationStampHolder.forceHintsUpdateOnNextPass()
- }
- }
-
- class ToggleInferredAnnotationsHintsAction : ToggleAction() {
- override fun isSelected(e: AnActionEvent): Boolean = CodeInsightSettings.getInstance().SHOW_INFERRED_ANNOTATIONS_INLINE
-
- override fun setSelected(e: AnActionEvent, state: Boolean) {
- CodeInsightSettings.getInstance().SHOW_INFERRED_ANNOTATIONS_INLINE = state
- AnnotationHintsPassFactory.modificationStampHolder.forceHintsUpdateOnNextPass()
- }
- }
-}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationHintsPassFactory.kt b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationHintsPassFactory.kt
deleted file mode 100644
index 78fb3ac66909..000000000000
--- a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationHintsPassFactory.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
-package com.intellij.codeInsight.hints
-
-import com.intellij.codeHighlighting.TextEditorHighlightingPass
-import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory
-import com.intellij.codeHighlighting.TextEditorHighlightingPassFactoryRegistrar
-import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.Key
-import com.intellij.psi.PsiFile
-import com.intellij.psi.PsiJavaFile
-
-internal class AnnotationHintsPassFactory : TextEditorHighlightingPassFactory, TextEditorHighlightingPassFactoryRegistrar {
- override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) {
- registrar.registerTextEditorHighlightingPass(this, null, null, false, -1)
- }
-
- override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? {
- if (editor.isOneLineMode ||
- file !is PsiJavaFile ||
- modificationStampHolder.isNotChanged(editor, file)) return null
- return AnnotationHintsPass(file, editor, modificationStampHolder)
- }
-
- companion object {
- val modificationStampHolder: ModificationStampHolder = ModificationStampHolder(Key.create("LAST_PASS_MODIFICATION_TIMESTAMP"))
- }
-}
\ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlayProvider.kt b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlayProvider.kt
new file mode 100644
index 000000000000..708f0e96f103
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/hints/AnnotationInlayProvider.kt
@@ -0,0 +1,167 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.codeInsight.hints
+
+import com.intellij.codeInsight.ExternalAnnotationsManager
+import com.intellij.codeInsight.InferredAnnotationsManager
+import com.intellij.codeInsight.MakeInferredAnnotationExplicit
+import com.intellij.codeInsight.hints.presentation.InsetPresentation
+import com.intellij.codeInsight.hints.presentation.MenuOnClickPresentation
+import com.intellij.codeInsight.javadoc.JavaDocInfoGenerator
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.application.ApplicationBundle
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.project.Project
+import com.intellij.psi.*
+import com.intellij.ui.layout.*
+import javax.swing.JComponent
+import kotlin.reflect.KMutableProperty0
+
+class AnnotationInlayProvider : InlayHintsProvider {
+ override fun getCollectorFor(file: PsiFile,
+ editor: Editor,
+ settings: Settings,
+ sink: InlayHintsSink): InlayHintsCollector? {
+ val project = file.project
+ return object : FactoryInlayHintsCollector(editor) {
+ override fun collect(element: PsiElement, editor: Editor, sink: InlayHintsSink): Boolean {
+ if (element is PsiModifierListOwner) {
+ var annotations = emptySequence()
+ if (settings.showExternal) {
+ annotations += ExternalAnnotationsManager.getInstance(project).findExternalAnnotations(element).orEmpty()
+ }
+ if (settings.showInferred) {
+ annotations += InferredAnnotationsManager.getInstance(project).findInferredAnnotations(element)
+ }
+
+ val shownAnnotations = mutableSetOf()
+ annotations.forEach {
+ val nameReferenceElement = it.nameReferenceElement
+ if (nameReferenceElement != null && element.modifierList != null &&
+ (shownAnnotations.add(nameReferenceElement.qualifiedName) || JavaDocInfoGenerator.isRepeatableAnnotationType(it))) {
+ val offset = element.modifierList!!.textRange.startOffset
+ val presentation = annotationPresentation(it)
+ val menuOnClick = MenuOnClickPresentation(presentation, project) {
+ val makeExplicit = InsertAnnotationAction(project, file, element)
+ listOf(
+ makeExplicit,
+ ToggleSettingsAction("Turn off external annotations", settings::showExternal),
+ ToggleSettingsAction("Turn off inferred annotations", settings::showInferred)
+ )
+ }
+ sink.addInlineElement(offset, true, menuOnClick)
+ }
+ }
+ }
+ return true
+ }
+
+ private fun annotationPresentation(annotation: PsiAnnotation): InsetPresentation = with(factory) {
+ val nameReferenceElement = annotation.nameReferenceElement
+ val parameterList = annotation.parameterList
+ inset(
+ roundWithBackground(seq(
+ smallText("@"),
+ psiSingleReference(smallText(nameReferenceElement?.referenceName ?: "")) { nameReferenceElement?.resolve() },
+ parametersPresentation(parameterList)
+ )),
+ left = 1,
+ right = 1
+ )
+
+ }
+
+ private fun parametersPresentation(parameterList: PsiAnnotationParameterList) = with(factory) {
+ val attributes = parameterList.attributes
+ when {
+ attributes.isEmpty() -> smallText("()")
+ else -> insideParametersPresentation(attributes, collapsed = parameterList.textLength > 30)
+ }
+ }
+
+ private fun insideParametersPresentation(attributes: Array, collapsed: Boolean) = with(factory) {
+ collapsible(
+ smallText("("),
+ smallText("..."),
+ {
+ join(
+ presentations = attributes.map { pairPresentation(it) },
+ separator = { smallText(", ") }
+ )
+ },
+ smallText(")"),
+ collapsed
+ )
+ }
+
+ private fun pairPresentation(attribute: PsiNameValuePair) = with(factory) {
+ seq(
+ psiSingleReference(smallText(attribute.name ?: ""), resolve = { attribute.reference?.resolve() }),
+ smallText(" = "),
+ smallText(attribute.value?.text ?: "") // TODO values references, at least annotations and enum names
+ )
+ }
+ }
+ }
+
+ override fun createSettings(): Settings = Settings(showInferred = true, showExternal = true)
+
+ override val name: String
+ get() = "Annotations"
+ override val key: SettingsKey
+ get() = ourKey
+ override val previewText: String?
+ get() = "" // TODO
+
+ override fun createConfigurable(settings: Settings): ImmediateConfigurable {
+ return object : ImmediateConfigurable {
+ override fun createComponent(listener: ChangeListener): JComponent {
+ return panel {
+ row {
+ checkBox(ApplicationBundle.message("editor.appearance.show.external.annotations"), settings::showExternal)
+ }
+ row {
+ checkBox(ApplicationBundle.message("editor.appearance.show.external.annotations"), settings::showExternal)
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ val ourKey: SettingsKey = SettingsKey("annotation.hints")
+ }
+
+ data class Settings(var showInferred: Boolean = true, var showExternal: Boolean = true)
+
+
+ class ToggleSettingsAction(val text: String, val prop: KMutableProperty0) : AnAction() {
+
+ override fun update(e: AnActionEvent) {
+ val presentation = e.presentation
+ presentation.text = text
+ }
+
+ override fun actionPerformed(e: AnActionEvent) {
+ prop.set(!prop.get())
+ }
+
+ }
+}
+
+class InsertAnnotationAction(
+ private val project: Project,
+ private val file: PsiFile,
+ private val element: PsiModifierListOwner
+) : AnAction() {
+ override fun update(e: AnActionEvent) {
+ e.presentation.text = "Insert annotation"
+ }
+
+ override fun actionPerformed(e: AnActionEvent) {
+ val intention = MakeInferredAnnotationExplicit()
+ if (intention.isAvailable(project, file, element)) {
+ intention.makeAnnotationsExplicit(project, file, element)
+ }
+ }
+}
\ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hints/presentation/PresentationFactory.kt b/platform/lang-impl/src/com/intellij/codeInsight/hints/presentation/PresentationFactory.kt
index 87db8182268e..40a37fcc81c0 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/hints/presentation/PresentationFactory.kt
+++ b/platform/lang-impl/src/com/intellij/codeInsight/hints/presentation/PresentationFactory.kt
@@ -117,6 +117,11 @@ class PresentationFactory(private val editor: EditorImpl) {
}), onClick = unwrapAction)
}
+ @Contract(pure = true)
+ fun inset(base: InlayPresentation, left: Int = 0, right: Int = 0, top: Int = 0, down: Int = 0): InsetPresentation {
+ return InsetPresentation(base, left, right, top, down)
+ }
+
/**
* Creates node, that can be collapsed/expanded by clicking on prefix/suffix.
* If presentation is collapsed, clicking to content will expand it.
@@ -270,6 +275,19 @@ class PresentationFactory(private val editor: EditorImpl) {
}
}
+ fun join(presentations: List, separator: () -> InlayPresentation) : InlayPresentation {
+ val seq = mutableListOf()
+ var first = true
+ for (presentation in presentations) {
+ if (!first) {
+ seq.add(separator())
+ }
+ seq.add(presentation)
+ first = false
+ }
+ return SequencePresentation(seq)
+ }
+
@Contract(pure = true)
fun rounding(arcWidth: Int, arcHeight: Int, presentation: InlayPresentation): InlayPresentation =
RoundPresentation(presentation, arcWidth, arcHeight)
diff --git a/resources/src/idea/JavaActions.xml b/resources/src/idea/JavaActions.xml
index 129d1fc79f26..65bc03557736 100644
--- a/resources/src/idea/JavaActions.xml
+++ b/resources/src/idea/JavaActions.xml
@@ -775,17 +775,6 @@
-
-