Skip to content

feat: editor: hint matches for matchLabels/-Expressions & list them in dialog (#642) #858

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ java {

repositories {
mavenLocal()
maven { url = uri("https://repository.jboss.org") }
/*
* github repo with intellij-common needs to be listed before jboss repository. Both have 1.9.9-SNAPSHOT
* First hit wins regardless of timestamp
*/
maven { url = uri("https://raw.githubusercontent.com/redhat-developer/intellij-common/repository/snapshots") }
maven { url = uri("https://raw.githubusercontent.com/redhat-developer/intellij-common/repository/releases") }
maven { url = uri("https://repository.jboss.org") }
mavenCentral()
intellijPlatform {
defaultRepositories()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ open class ResourceEditor(

override fun dispose() {
resourceModel.removeListener(onNamespaceContextChanged)
editorResources.dispose()
connection.dispose()
editorResources.dispose()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,6 @@ open class ResourceEditorFactory protected constructor(

/* for testing purposes */
protected open fun getTelemetryMessageBuilder(): TelemetryMessageBuilder {
return TelemetryService.instance;
return TelemetryService.instance
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ import com.intellij.codeInsight.hints.InlayHintsProvider
import com.intellij.codeInsight.hints.InlayHintsSink
import com.intellij.codeInsight.hints.NoSettings
import com.intellij.codeInsight.hints.SettingsKey
import com.intellij.codeInsight.hints.presentation.PresentationFactory
import com.intellij.json.psi.JsonFile
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.ui.dsl.builder.panel
import com.redhat.devtools.intellij.common.validation.KubernetesTypeInfo
import com.redhat.devtools.intellij.kubernetes.editor.inlay.base64.Base64Presentations
import com.redhat.devtools.intellij.kubernetes.editor.inlay.selector.SelectorPresentations
import com.redhat.devtools.intellij.kubernetes.editor.util.PsiElements
import org.jetbrains.yaml.psi.YAMLFile
import javax.swing.JComponent

Expand Down Expand Up @@ -65,34 +67,44 @@ internal class ResourceEditorInlayHintsProvider : InlayHintsProvider<NoSettings>
}
return when(element) {
is YAMLFile -> {
create(element, sink, editor)
create(element, sink, editor, factory)
false
}
is JsonFile -> {
create(element, sink, editor)
create(element, sink, editor, factory)
false
}
else -> true
}
}

private fun create(file: YAMLFile, sink: InlayHintsSink, editor: Editor) {
private fun create(file: YAMLFile, sink: InlayHintsSink, editor: Editor, factory: PresentationFactory) {
return ReadAction.run<Exception> {
file.documents.forEach { document ->
val info = KubernetesTypeInfo.create(document) ?: return@forEach
val element = document.topLevelValue ?: return@forEach
Base64Presentations.create(element, info, sink, editor)?.create()
}
file.documents
.mapNotNull { document -> document.topLevelValue }
.forEach { element ->
createPresentations(element, sink, editor, factory)
}
}
}

private fun create(file: JsonFile, sink: InlayHintsSink, editor: Editor) {
private fun create(file: JsonFile, sink: InlayHintsSink, editor: Editor, factory: PresentationFactory) {
return ReadAction.run<Exception> {
val info = KubernetesTypeInfo.create(file) ?: return@run
val element = file.topLevelValue ?: return@run
Base64Presentations.create(element, info, sink, editor)?.create()
file.allTopLevelValues.forEach { element ->
createPresentations(element, sink, editor, factory)
}
}
}

private fun createPresentations(element: PsiElement, sink: InlayHintsSink, editor: Editor, factory: PresentationFactory) {
val info = KubernetesTypeInfo.create(element) ?: return
Base64Presentations.create(element, info, sink, editor, factory)

val fileType = editor.virtualFile?.fileType ?: return
val project = editor.project ?: return
val allElements = PsiElements.getAllNoExclusions(fileType, project)
SelectorPresentations.createForSelector(element, allElements, sink, editor, factory)
SelectorPresentations.createForAllLabels(element, allElements, sink, editor, factory)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,41 @@ object Base64Presentations {
private const val SECRET_RESOURCE_KIND = "Secret"
private const val CONFIGMAP_RESOURCE_KIND = "ConfigMap"

fun create(element: PsiElement, info: KubernetesTypeInfo, sink: InlayHintsSink, editor: Editor): InlayPresentationsFactory? {
return when {
fun create(
element: PsiElement,
info: KubernetesTypeInfo,
sink: InlayHintsSink,
editor: Editor,
factory: PresentationFactory,
/* for testing purposes */
stringPresentationFactory: (element: PsiElement, sink: InlayHintsSink, editor: Editor, factory: PresentationFactory) -> Unit
= { element, sink, editor, factory ->
StringPresentationsFactory(element, sink, editor, factory).create()
},
/* for testing purposes */
binaryPresentationFactory: (element: PsiElement, sink: InlayHintsSink, editor: Editor, factory: PresentationFactory) -> Unit
= { element, sink, editor, factory ->
BinaryPresentationsFactory(element, sink, editor, factory).create()
},
) {
when {
isKubernetesResource(SECRET_RESOURCE_KIND, info) -> {
val data = getDataValue(element) ?: return null
StringPresentationsFactory(data, sink, editor)
val data = element.getDataValue() ?: return
stringPresentationFactory.invoke(data, sink, editor, factory)
}

isKubernetesResource(CONFIGMAP_RESOURCE_KIND, info) -> {
val binaryData = getBinaryData(element) ?: return null
BinaryPresentationsFactory(binaryData, sink, editor)
val binaryData = element.getBinaryData() ?: return
binaryPresentationFactory.invoke(binaryData, sink, editor, factory)
}

else -> null
}
}

abstract class InlayPresentationsFactory(
private val element: PsiElement,
protected val sink: InlayHintsSink,
protected val editor: Editor
protected val editor: Editor,
protected val factory: PresentationFactory
) {

protected companion object {
Expand All @@ -69,17 +84,15 @@ object Base64Presentations {

fun create(): Collection<InlayPresentation> {
return element.children.mapNotNull { child ->
val adapter = Base64ValueAdapter(child)
create(adapter)
create(Base64ValueAdapter(child))
}
}

protected abstract fun create(adapter: Base64ValueAdapter): InlayPresentation?

}

class StringPresentationsFactory(element: PsiElement, sink: InlayHintsSink, editor: Editor)
: InlayPresentationsFactory(element, sink, editor) {
class StringPresentationsFactory(element: PsiElement, sink: InlayHintsSink, editor: Editor, factory: PresentationFactory)
: InlayPresentationsFactory(element, sink, editor, factory) {

override fun create(adapter: Base64ValueAdapter): InlayPresentation? {
val decoded = adapter.getDecoded() ?: return null
Expand All @@ -89,20 +102,22 @@ object Base64Presentations {
onValidValue(adapter::set, editor.project),
editor
)::show
val presentation = create(decoded, onClick, editor) ?: return null
val presentation = create(decoded, onClick, factory) ?: return null
sink.addInlineElement(offset, false, presentation, false)
return presentation
}

private fun create(text: String, onClick: (event: MouseEvent) -> Unit, editor: Editor): InlayPresentation? {
val factory = PresentationFactory(editor)
private fun create(text: String, onClick: (event: MouseEvent) -> Unit, factory: PresentationFactory): InlayPresentation? {
val trimmed = trimWithEllipsis(text, INLAY_HINT_MAX_WIDTH) ?: return null
val textPresentation = factory.smallText(trimmed)
val hoverPresentation = factory.referenceOnHover(textPresentation) { event, _ ->
onClick.invoke(event)
}
val tooltipPresentation = factory.withTooltip("Click to change value", hoverPresentation)
return factory.roundWithBackground(tooltipPresentation)
return factory.roundWithBackground(
factory.withTooltip(
"Click to change value",
factory.referenceOnHover(
factory.smallText(trimmed)) { event, _ ->
onClick.invoke(event)
}
)
)
}

private fun onValidValue(setter: (value: String, wrapAt: Int) -> Unit, project: Project?)
Expand All @@ -118,8 +133,8 @@ object Base64Presentations {

}

class BinaryPresentationsFactory(element: PsiElement, sink: InlayHintsSink, editor: Editor)
: InlayPresentationsFactory(element, sink, editor) {
class BinaryPresentationsFactory(element: PsiElement, sink: InlayHintsSink, editor: Editor, factory: PresentationFactory)
: InlayPresentationsFactory(element, sink, editor, factory) {

override fun create(adapter: Base64ValueAdapter): InlayPresentation? {
val decoded = adapter.getDecodedBytes() ?: return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
******************************************************************************/
package com.redhat.devtools.intellij.kubernetes.editor.inlay.base64

import com.intellij.json.psi.JsonProperty
import com.intellij.psi.PsiElement
import com.redhat.devtools.intellij.kubernetes.editor.util.decodeBase64
import com.redhat.devtools.intellij.kubernetes.editor.util.decodeBase64ToBytes
import com.redhat.devtools.intellij.kubernetes.editor.util.encodeBase64
import com.redhat.devtools.intellij.kubernetes.editor.util.getValue
import com.redhat.devtools.intellij.kubernetes.editor.util.setValue
import org.jetbrains.yaml.psi.YAMLKeyValue

class Base64ValueAdapter(private val element: PsiElement) {

Expand Down Expand Up @@ -80,6 +82,10 @@ class Base64ValueAdapter(private val element: PsiElement) {
}

fun getStartOffset(): Int? {
return com.redhat.devtools.intellij.kubernetes.editor.util.getStartOffset(element)
return when(element) {
is YAMLKeyValue -> element.value?.textRange?.startOffset
is JsonProperty -> element.value?.textRange?.startOffset
else -> null
}
}
}
Loading
Loading