Skip to content

Commit

Permalink
#1188 | Added code completion and reference resolution for primitive …
Browse files Browse the repository at this point in the history
…types
  • Loading branch information
mlytvyn authored Aug 4, 2024
1 parent 7dc0737 commit 54c048f
Show file tree
Hide file tree
Showing 29 changed files with 240 additions and 159 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### `Type System` enhancements
- Added dom model for `core-advanced-deployment.xml` [#1187](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/1187)
- Added code completion and reference resolution for primitive types [#1188](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/1188)

### Other
- Omit internal IntelliJ API usage in `ProjectBeforeCompilerTask` [#1186](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/1186)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<dom.fileMetaData rootTagName="items" stubVersion="22"
implementation="com.intellij.idea.plugin.hybris.system.type.file.TSDomFileDescription"/>

<dom.fileMetaData rootTagName="model" stubVersion="1"
<dom.fileMetaData rootTagName="model" stubVersion="2"
implementation="com.intellij.idea.plugin.hybris.system.type.file.TSDeploymentModelDomFileDescription"/>

<lang.foldingBuilder language="XML" implementationClass="com.intellij.idea.plugin.hybris.system.type.lang.folding.ItemsXmlFoldingBuilder"/>
Expand Down
14 changes: 9 additions & 5 deletions src/com/intellij/idea/plugin/hybris/common/utils/HybrisIcons.kt
Original file line number Diff line number Diff line change
Expand Up @@ -198,18 +198,13 @@ object HybrisIcons {
val GROUP_MAP = getIcon("/icons/typeSystem/groupByMap.svg")
val GROUP_RELATION = getIcon("/icons/typeSystem/groupByRelation.svg")
val DESCRIPTION = AllIcons.Windows.Help
val ENUM = getIcon("/icons/typeSystem/enum.svg")
val ENUM_VALUE = getIcon("/icons/typeSystem/enumValue.svg")
val ATOMIC = getIcon("/icons/typeSystem/atomic.svg")
val ITEM = getIcon("/icons/typeSystem/item.svg")
val MAP = getIcon("/icons/typeSystem/map.svg")
val RELATION = getIcon("/icons/typeSystem/relation.svg")
val CUSTOM_PROPERTY = getIcon("/icons/typeSystem/customProperty.svg")
val ATTRIBUTE = getIcon("/icons/typeSystem/attribute.svg")
val ORDERING_ATTRIBUTE = getIcon("/icons/typeSystem/orderingAttribute.svg")
val RELATION_SOURCE = getIcon("/icons/typeSystem/relationSource.svg")
val RELATION_TARGET = getIcon("/icons/typeSystem/relationTarget.svg")
val COLLECTION = getIcon("/icons/typeSystem/collection.svg")
val INDEX = getIcon("/icons/typeSystem/index.svg")
val INDEX_UNIQUE = getIcon("/icons/typeSystem/indexUnique.svg")
val INDEX_REPLACE = getIcon("/icons/typeSystem/indexReplace.svg")
Expand All @@ -218,6 +213,15 @@ object HybrisIcons {
val ALTERNATIVE_DECLARATION = AllIcons.Actions.Forward
val SIBLING = AllIcons.Gutter.OverridenMethod

object Types {
val ATOMIC = getIcon("/icons/typeSystem/atomic.svg")
val MAP = getIcon("/icons/typeSystem/map.svg")
val RELATION = getIcon("/icons/typeSystem/relation.svg")
val ENUM = getIcon("/icons/typeSystem/enum.svg")
val COLLECTION = getIcon("/icons/typeSystem/collection.svg")
val PRIMITIVE = HybrisIcons.Types.PRIMITIVE
}

object Preview {
object Actions {
val SHOW = AllIcons.Actions.Show
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class TSDiagramNodeContentManager : AbstractDiagramNodeContentManager() {
val PROPERTIES = DiagramCategory({ message("hybris.diagram.ts.provider.category.properties") }, HybrisIcons.TypeSystem.Diagram.PROPERTY, true, false)
val DEPLOYMENT = DiagramCategory({ message("hybris.diagram.ts.provider.category.deployment") }, HybrisIcons.TypeSystem.Diagram.DEPLOYMENT, true, false)
val ATTRIBUTES = DiagramCategory({ message("hybris.diagram.ts.provider.category.attributes") }, HybrisIcons.TypeSystem.ATTRIBUTE, true, false)
val RELATION_ENDS = DiagramCategory({ message("hybris.diagram.ts.provider.category.relation_ends") }, HybrisIcons.TypeSystem.RELATION, true, false)
val RELATION_ENDS = DiagramCategory({ message("hybris.diagram.ts.provider.category.relation_ends") }, HybrisIcons.TypeSystem.Types.RELATION, true, false)
val CUSTOM_PROPERTIES = DiagramCategory({ message("hybris.diagram.ts.provider.category.custom_properties") }, HybrisIcons.TypeSystem.CUSTOM_PROPERTY, true, false)
val INDEXES = DiagramCategory({ message("hybris.diagram.ts.provider.category.indexes") }, HybrisIcons.TypeSystem.INDEX, true, false)
val ENUM_VALUES = DiagramCategory({ message("hybris.diagram.ts.provider.category.enum_values") }, HybrisIcons.TypeSystem.ENUM_VALUE, true, false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ class TSDiagramNode(val graphNode: TSGraphNode, provider: DiagramProvider<TSGrap
.asSafely<TSGraphNodeClassifier>()
?.let {
when (it.meta) {
is TSGlobalMetaEnum -> HybrisIcons.TypeSystem.ENUM
is TSGlobalMetaEnum -> HybrisIcons.TypeSystem.Types.ENUM
is TSGlobalMetaItem -> HybrisIcons.TypeSystem.ITEM
is TSGlobalMetaCollection -> HybrisIcons.TypeSystem.COLLECTION
is TSGlobalMetaMap -> HybrisIcons.TypeSystem.MAP
is TSGlobalMetaRelation -> HybrisIcons.TypeSystem.RELATION
is TSGlobalMetaCollection -> HybrisIcons.TypeSystem.Types.COLLECTION
is TSGlobalMetaMap -> HybrisIcons.TypeSystem.Types.MAP
is TSGlobalMetaRelation -> HybrisIcons.TypeSystem.Types.RELATION
else -> HybrisIcons.TypeSystem.FILE
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA.
* This file is part of "SAP Commerce Developers Toolset" plugin for IntelliJ IDEA.
* Copyright (C) 2014-2016 Alexander Bartash <[email protected]>
* Copyright (C) 2019-2023 EPAM Systems <[email protected]> and contributors
* Copyright (C) 2019-2024 EPAM Systems <[email protected]> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
Expand Down Expand Up @@ -58,7 +58,7 @@ class ImpexFunctionTSAttributeReference(owner: ImpexParameter) : TSReferenceBase
// if an inline type already present, we should not suggest any other types
if (element.inlineTypeName != null) return emptyArray()
return TSCompletionService.getInstance(element.project)
.getImpexInlineTypeCompletions(element.project, element)
.getImpExInlineTypeCompletions(element.project, element)
.toTypedArray()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA.
* Copyright (C) 2019-2023 EPAM Systems <[email protected]> and contributors
* This file is part of "SAP Commerce Developers Toolset" plugin for IntelliJ IDEA.
* Copyright (C) 2019-2024 EPAM Systems <[email protected]> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
Expand Down Expand Up @@ -42,7 +42,7 @@ class ImpexFunctionTSItemReference(owner: ImpexParameter) : TSReferenceBase<Impe
?: super.calculateDefaultRangeInElement()

override fun getVariants(): Array<LookupElement> = TSCompletionService.getInstance(element.project)
.getImpexInlineTypeCompletions(element.project, element)
.getImpExInlineTypeCompletions(element.project, element)
.toTypedArray()

override fun multiResolve(incompleteCode: Boolean): Array<ResolveResult> {
Expand Down
5 changes: 3 additions & 2 deletions src/com/intellij/idea/plugin/hybris/psi/util/PsiUtils.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* This file is part of "SAP Commerce Developers Toolset" plugin for Intellij IDEA.
* Copyright (C) 2019-2023 EPAM Systems <[email protected]> and contributors
* This file is part of "SAP Commerce Developers Toolset" plugin for IntelliJ IDEA.
* Copyright (C) 2019-2024 EPAM Systems <[email protected]> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
Expand Down Expand Up @@ -43,6 +43,7 @@ public final class PsiUtils {
private PsiUtils() {
}

@Nullable
public static Module getModule(final @NotNull PsiFile file) {
final VirtualFile vFile = file.getVirtualFile();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ class CngItemTypeCodeCompletionProvider : ItemTypeCodeCompletionProvider() {
?.withTypeText(typeText, true)
?.withBoldness(true)
}
.map { PrioritizedLookupElement.withPriority(it, 1.0) }
.map { PrioritizedLookupElement.withGrouping(it, 1) }
.map { PrioritizedLookupElement.withPriority(it, TSLookupElementFactory.PRIORITY_1_0) }
.map { PrioritizedLookupElement.withGrouping(it, TSLookupElementFactory.GROUP_1) }
.forEach { resultCaseInsensitive.addElement(it) }

allItems
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class TSCompletionService(private val project: Project) {
.flatten()
}

fun getImpexInlineTypeCompletions(project: Project, element: ImpexParameter): List<LookupElement> {
fun getImpExInlineTypeCompletions(project: Project, element: ImpexParameter): List<LookupElement> {
val completion = DeveloperSettingsComponent.getInstance(project).state.impexSettings.completion
if (!completion.showInlineTypes) return emptyList()

Expand All @@ -108,8 +108,8 @@ class TSCompletionService(private val project: Project) {
TSLookupElementFactory.build(it, suffix)
?.withTypeText(" child of $referenceItemTypeName", true)
}
.map { PrioritizedLookupElement.withPriority(it, 2.0) }
.map { PrioritizedLookupElement.withGrouping(it, 2) }
.map { PrioritizedLookupElement.withPriority(it, TSLookupElementFactory.PRIORITY_2_0) }
.map { PrioritizedLookupElement.withGrouping(it, TSLookupElementFactory.GROUP_2) }
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import javax.swing.Icon
class ModelEnumLineMarkerProvider : AbstractHybrisClassLineMarkerProvider<PsiClass>() {

override fun getName() = message("hybris.editor.gutter.ts.model.enum.name")
override fun getIcon(): Icon = HybrisIcons.TypeSystem.ENUM
override fun getIcon(): Icon = HybrisIcons.TypeSystem.Types.ENUM
override fun canProcess(psi: PsiClass) = TSUtils.isEnumFile(psi)
override fun tryCast(psi: PsiElement) = (psi as? PsiClass)
?.takeIf { it.nameIdentifier != null }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class ModelItemAttributeFieldLineMarkerProvider : AbstractModelAttributeLineMark
?.xmlAttributeValue
?.let {
NavigationGutterIconBuilder
.create(HybrisIcons.TypeSystem.RELATION)
.create(HybrisIcons.TypeSystem.Types.RELATION)
.setTargets(it)
.setTooltipText(message("hybris.editor.gutter.ts.model.item.attribute.field.relation.tooltip.text"))
.setAlignment(GutterIconRenderer.Alignment.LEFT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class ItemsXmlInlayHintsCollector(editor: Editor) : AbstractSystemAwareInlayHint
return when {
parent.name == EnumTypes.ENUMTYPE && attribute == EnumType.CODE -> finEnumClass(project, name)
.takeIf { it.isNotEmpty() }
?.let { inlayPresentation(HybrisIcons.TypeSystem.ENUM, it) }
?.let { inlayPresentation(HybrisIcons.TypeSystem.Types.ENUM, it) }
?: unknown

// It is possible to declare many-to-many Relation as Item to add new index
Expand All @@ -88,7 +88,7 @@ class ItemsXmlInlayHintsCollector(editor: Editor) : AbstractSystemAwareInlayHint
?.code
?.xmlAttributeValue
?.asSafely<Navigatable>()
?.let { inlayPresentation(HybrisIcons.TypeSystem.RELATION, arrayOf(it), "Navigate to Relation declaration") }
?.let { inlayPresentation(HybrisIcons.TypeSystem.Types.RELATION, arrayOf(it), "Navigate to Relation declaration") }
?: findItemClass(project, name)
.takeIf { it.isNotEmpty() }
?.let { inlayPresentation(HybrisIcons.TypeSystem.ITEM, it) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,16 @@ import com.intellij.idea.plugin.hybris.system.type.meta.model.*
import com.intellij.idea.plugin.hybris.system.type.model.AtomicType
import com.intellij.idea.plugin.hybris.system.type.model.EnumType
import com.intellij.idea.plugin.hybris.system.type.model.ItemType
import com.intellij.idea.plugin.hybris.system.type.model.deployment.TypeMapping

object TSLookupElementFactory {

const val PRIORITY_2_0 = 2.0
const val PRIORITY_1_0 = 1.0
const val GROUP_1 = 1
const val GROUP_2 = 2
const val GROUP_3 = 3

fun build(
meta: TSGlobalMetaItem,
suffix: String = ""
Expand All @@ -47,30 +54,34 @@ object TSLookupElementFactory {
.withCaseSensitivity(false)
}

fun build(meta: TSGlobalMetaRelation) = meta.name?.let {
LookupElementBuilder.create(it)
.withTypeText(meta.flattenType)
.withIcon(HybrisIcons.TypeSystem.RELATION)
.withCaseSensitivity(false)
}

fun build(meta: TSGlobalMetaCollection) = meta.name?.let {
LookupElementBuilder.create(it)
.withTypeText(meta.flattenType)
.withIcon(HybrisIcons.TypeSystem.COLLECTION)
.withCaseSensitivity(false)
}

fun build(meta: TSGlobalMetaMap) = meta.name?.let {
LookupElementBuilder.create(it)
.withTypeText(meta.flattenType)
.withIcon(HybrisIcons.TypeSystem.MAP)
.withCaseSensitivity(false)
}
fun build(meta: TSGlobalMetaRelation) = meta.name
?.let {
LookupElementBuilder.create(it)
.withTypeText(meta.flattenType)
.withIcon(HybrisIcons.TypeSystem.Types.RELATION)
.withCaseSensitivity(false)
}

fun build(meta: TSGlobalMetaCollection) = meta.name
?.let {
LookupElementBuilder.create(it)
.withTypeText(meta.flattenType)
.withIcon(HybrisIcons.TypeSystem.Types.COLLECTION)
.withCaseSensitivity(false)
}

fun build(meta: TSGlobalMetaMap) = meta.name
?.let {
LookupElementBuilder.create(it)
.withTypeText(meta.flattenType)
.withIcon(HybrisIcons.TypeSystem.Types.MAP)
.withCaseSensitivity(false)
}

fun build(meta: TSGlobalMetaItem.TSGlobalMetaItemAttribute) = LookupElementBuilder.create(meta.name)
.withStrikeoutness(meta.isDeprecated)
.withTypeText(meta.flattenType,
.withTypeText(
meta.flattenType,
if (meta.isLocalized) HybrisIcons.TypeSystem.LOCALIZED
else null,
true
Expand Down Expand Up @@ -114,7 +125,7 @@ object TSLookupElementFactory {
?.let {
LookupElementBuilder.create(it)
.withTailText(if (meta.isDynamic) " (" + message("hybris.ts.type.dynamic") + ")" else "", true)
.withIcon(HybrisIcons.TypeSystem.ENUM)
.withIcon(HybrisIcons.TypeSystem.Types.ENUM)
.withTypeText(":: ${HybrisConstants.TS_TYPE_ENUMERATION_VALUE}", HybrisIcons.TypeSystem.ITEM, true)
.withTypeIconRightAligned(true)
.withCaseSensitivity(false)
Expand All @@ -124,7 +135,8 @@ object TSLookupElementFactory {
.withIcon(HybrisIcons.TypeSystem.ATTRIBUTE)
.withTailText(if (attribute.isDynamic) " (" + message("hybris.ts.type.dynamic") + ')' else "", true)
.withStrikeoutness(attribute.isDeprecated)
.withTypeText(attribute.flattenType,
.withTypeText(
attribute.flattenType,
if (attribute.isLocalized) HybrisIcons.TypeSystem.LOCALIZED
else null,
true
Expand All @@ -134,20 +146,20 @@ object TSLookupElementFactory {

fun build(type: String?, lookupString: String) = LookupElementBuilder.create(lookupString)
.withTypeText(type, true)
.withIcon(HybrisIcons.TypeSystem.MAP)
.withIcon(HybrisIcons.TypeSystem.Types.MAP)
.withCaseSensitivity(false)

fun build(dom: EnumType) = dom.code.stringValue
?.let {
LookupElementBuilder.create(it)
.withTailText(if (dom.dynamic.value) " (" + message("hybris.ts.type.dynamic") + ")" else "", true)
.withIcon(HybrisIcons.TypeSystem.ENUM)
.withIcon(HybrisIcons.TypeSystem.Types.ENUM)
}

fun build(dom: AtomicType) = dom.clazz.stringValue
?.let {
LookupElementBuilder.create(it)
.withIcon(HybrisIcons.TypeSystem.ATOMIC)
.withIcon(HybrisIcons.TypeSystem.Types.ATOMIC)
}

fun build(dom: ItemType) = dom.code.stringValue
Expand All @@ -156,31 +168,41 @@ object TSLookupElementFactory {
.withIcon(HybrisIcons.TypeSystem.ITEM)
}

fun buildPrimitive(dom: TypeMapping?) = dom
?.let {
val type = it.type.stringValue ?: return@let null
val persistenceType = it.persistenceType.stringValue ?: return@let null

LookupElementBuilder.create(type)
.withTypeText(persistenceType, true)
.withIcon(HybrisIcons.TypeSystem.Types.PRIMITIVE)
}
?.let { PrioritizedLookupElement.withGrouping(it, GROUP_3) }

fun buildCustomProperty(lookupString: String) = LookupElementBuilder.create(lookupString)
.withIcon(HybrisIcons.TypeSystem.CUSTOM_PROPERTY)
.withCaseSensitivity(false)

fun buildHeaderAbbreviation(lookupString: String) = PrioritizedLookupElement.withPriority(
LookupElementBuilder.create(lookupString)
.withTypeText("Header Abbreviation", true)
.withIcon(HybrisIcons.TypeSystem.HEADER_ABBREVIATION)
.withInsertHandler(lookupString.contains('@')
.takeIf { it }
?.let {
object : AutoPopupInsertHandler() {
override fun handle(context: InsertionContext, item: LookupElement) {
lookupString.indexOf('@')
.takeIf { it >= 0 }
?.let { index ->
val cursorOffset = context.editor.caretModel.offset
val moveBackTo = lookupString.length - index - 1
val offset = cursorOffset - moveBackTo
context.editor.caretModel.moveToOffset(offset)
context.editor.selectionModel.setSelection(offset, offset + moveBackTo)
}
}
fun buildHeaderAbbreviation(lookupString: String) = LookupElementBuilder.create(lookupString)
.withTypeText("Header Abbreviation", true)
.withIcon(HybrisIcons.TypeSystem.HEADER_ABBREVIATION)
.withInsertHandler(lookupString.contains('@')
.takeIf { it }
?.let {
object : AutoPopupInsertHandler() {
override fun handle(context: InsertionContext, item: LookupElement) {
lookupString.indexOf('@')
.takeIf { it >= 0 }
?.let { index ->
val cursorOffset = context.editor.caretModel.offset
val moveBackTo = lookupString.length - index - 1
val offset = cursorOffset - moveBackTo
context.editor.caretModel.moveToOffset(offset)
context.editor.selectionModel.setSelection(offset, offset + moveBackTo)
}
}
}
), 2.0
)
}
)
.let { PrioritizedLookupElement.withPriority(it, 2.0) }
}
Loading

0 comments on commit 54c048f

Please sign in to comment.