Skip to content

Commit

Permalink
#1260 | Use closest macro declaration value for folded macro usage
Browse files Browse the repository at this point in the history
  • Loading branch information
mlytvyn authored Nov 1, 2024
1 parent bf96d44 commit ff1fda6
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 106 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Improved **Groovy** language injection for **Script** type [#1255](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/1255)
- Properly resolve references to macro declaration [#1258](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/1258)
- Cache macro declaration references [#1259](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/1259)
- Use closest macro declaration value for folded macro usage [#1260](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/1260)

### Fixes
- Correctly define Scope to filter for Properties File [#1247](https://github.com/epam/sap-commerce-intellij-idea-plugin/pull/1247)
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 All @@ -17,6 +17,7 @@
*/
package com.intellij.idea.plugin.hybris.impex.lang.folding

import com.intellij.idea.plugin.hybris.impex.psi.ImpexFile
import com.intellij.idea.plugin.hybris.impex.utils.ImpexPsiUtils
import com.intellij.lang.ASTNode
import com.intellij.lang.folding.FoldingDescriptor
Expand Down Expand Up @@ -58,11 +59,9 @@ class ImpexFoldingBuilder : AbstractImpExFoldingBuilder() {
val text = ImpexFoldingPlaceholderBuilderFactory.getPlaceholderBuilder(psi.project).getPlaceholder(psi)
var resolvedMacro = text
if (text.startsWith("$")) {
val cache = ImpexMacroUtils.getFileCache(psi.containingFile).value
val descriptor = cache[text]
if (descriptor != null) {
resolvedMacro = descriptor.resolvedValue
}
(psi.containingFile as ImpexFile)
.getSuitableMacroDescriptor(text, psi)
?.let { resolvedMacro = it.resolvedValue }
}
return if (resolvedMacro.length <= text.length) {
resolvedMacro
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 @@ -29,18 +29,17 @@
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.util.SmartList;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.intellij.psi.util.PsiTreeUtil.findChildrenOfAnyType;

Expand All @@ -67,7 +66,7 @@ public FoldingDescriptor[] buildFoldRegions(
@Override
public void visitMacroDeclaration(@NotNull final ImpexMacroDeclaration macroDeclaration) {
super.visitMacroDeclaration(macroDeclaration);
resolveMacroDeclaration(macroDeclaration, results);
resolveMacroDeclaration(macroDeclaration);
}

@Override
Expand All @@ -86,61 +85,51 @@ public void visitString(@NotNull final ImpexString o) {
private void resolveIncludeExternalData(final ImpexString impexString) {
final String text = impexString.getText();
int index = text.indexOf("impex.includeExternalData");
if (index == -1) {
return;
}
if (index == -1) return;
index = text.indexOf("getResourceAsStream");
if (index == -1) {
return;
}
if (index == -1) return;
final int startIndex = text.indexOf('(', index);
if (startIndex == -1) {
return;
}
if (startIndex == -1) return;
final int endIndex = text.indexOf(')', startIndex);
if (endIndex == -1) {
return;
}
if (endIndex == -1) return;

final var resource = StringUtils.strip(text.substring(startIndex + 1, endIndex), "\"' ");
final var directory = impexString.getContainingFile().getContainingDirectory().getVirtualFile();
final var dirPath = directory.getCanonicalPath();
final var impexFile = (ImpexFile) impexString.getContainingFile();
final var containingDirectory = impexFile.getContainingDirectory();

if (containingDirectory == null) return;

final var dirPath = containingDirectory.getVirtualFile().getCanonicalPath();
final var referencedFile = LocalFileSystem.getInstance().findFileByIoFile(new File(dirPath, resource));
if (referencedFile == null || !referencedFile.exists()) {
return;
}
final PsiFile referencedPsi = PsiManager.getInstance(impexString.getProject()).findFile(referencedFile);
if (!(referencedPsi instanceof ImpexFile)) {
return;
}
Map<String, ImpexMacroDescriptor> referencedCache = ImpexMacroUtils.getFileCache(referencedPsi).getValue();
if (referencedFile == null || !referencedFile.exists()) return;

final var referencedPsi = PsiManager.getInstance(impexString.getProject()).findFile(referencedFile);
if (!(referencedPsi instanceof final ImpexFile referencedImpExFile)) return;

var referencedCache = referencedImpExFile.getMacroDescriptors();
if (referencedCache.isEmpty()) {
final Document document = FileDocumentManager.getInstance().getDocument(referencedFile);
if (document == null) {
return;
}
preventRecursion(impexString);
final var document = FileDocumentManager.getInstance().getDocument(referencedFile);
if (document == null) return;

preventRecursion(impexString, referencedCache);
buildFoldRegions(referencedPsi.getNode(), document);
referencedCache = ImpexMacroUtils.getFileCache(referencedPsi).getValue();
referencedCache = referencedImpExFile.getMacroDescriptors();
}
final Map<String, ImpexMacroDescriptor> cache = ImpexMacroUtils.getFileCache(impexString.getContainingFile()).getValue();
cache.putAll(referencedCache);
impexFile.getMacroDescriptors().putAll(referencedCache);
}

private void preventRecursion(final ImpexString impexString) {
final Map<String, ImpexMacroDescriptor> cache = ImpexMacroUtils.getFileCache(impexString.getContainingFile()).getValue();
private void preventRecursion(final ImpexString impexString, final MultiValuedMap<String, ImpexMacroDescriptor> cache) {
if (cache.isEmpty()) {
cache.put("!", new ImpexMacroDescriptor("!", "!", impexString));
}
}

private void resolveMacroDeclaration(
final ImpexMacroDeclaration macroLine,
final SmartList<FoldingDescriptor> results
) {
private void resolveMacroDeclaration(final ImpexMacroDeclaration macroLine) {
final List<PsiElement> lineElements = getAllChildren(macroLine);
String macroName = null;
final StringBuilder sb = new StringBuilder();
final Map<String, ImpexMacroDescriptor> cache = ImpexMacroUtils.getFileCache(macroLine.getContainingFile()).getValue();
final var impexFile = (ImpexFile) macroLine.getContainingFile();
final var cache = impexFile.getMacroDescriptors();
PsiElement anchor = macroLine;
for (PsiElement child : lineElements) {
if (child instanceof final LeafPsiElement leafPsiElement) {
Expand All @@ -152,8 +141,8 @@ private void resolveMacroDeclaration(
macroName = child.getText();
anchor = child;
} else {
if (child instanceof ImpexMacroUsageDec) {
final ImpexMacroDescriptor descriptor = findInCache(cache, child.getText());
if (child instanceof final ImpexMacroUsageDec macroUsage) {
final ImpexMacroDescriptor descriptor = findInCache(impexFile, cache, macroUsage);
if (descriptor != null) {
sb.append(descriptor.resolvedValue());
final int delta = child.getText().length() - descriptor.macroName().length();
Expand Down Expand Up @@ -209,8 +198,8 @@ private void resolveProperty(final ImpexMacroUsageDec macroUsage, final SmartLis
if (text.length() <= HybrisConstants.IMPEX_CONFIG_COMPLETE_PREFIX.length()) {
return;
}
final Map<String, ImpexMacroDescriptor> cache = ImpexMacroUtils.getFileCache(macroUsage.getContainingFile()).getValue();
ImpexMacroDescriptor descriptor = cache.get(text);
final var impexFile = (ImpexFile) macroUsage.getContainingFile();
ImpexMacroDescriptor descriptor = impexFile.getSuitableMacroDescriptor(text, macroUsage);
if (descriptor == null) {
final var propertyName = text.replace(HybrisConstants.IMPEX_CONFIG_COMPLETE_PREFIX, "");
final var propertyService = PropertyService.getInstance(macroUsage.getProject());
Expand All @@ -224,45 +213,51 @@ private void resolveProperty(final ImpexMacroUsageDec macroUsage, final SmartLis
final var propertyKey = HybrisConstants.IMPEX_CONFIG_COMPLETE_PREFIX + iProperty.getKey();

descriptor = new ImpexMacroDescriptor(propertyKey, iProperty.getValue(), iProperty.getPsiElement());
cache.put(text, descriptor);
impexFile.getMacroDescriptors().put(text, descriptor);
}
final int start = macroUsage.getTextRange().getStartOffset();
final TextRange range = new TextRange(start, start + descriptor.macroName().length());
results.add(new FoldingDescriptor(macroUsage.getNode(), range, null));
}

private void resolveLocalMacro(final ImpexMacroUsageDec macroUsage, final SmartList<FoldingDescriptor> results) {
final Map<String, ImpexMacroDescriptor> cache = ImpexMacroUtils.getFileCache(macroUsage.getContainingFile()).getValue();
final var impexFile = (ImpexFile) macroUsage.getContainingFile();
final var cache = impexFile.getMacroDescriptors();
String currentKey = "";
for (String key : cache.keySet()) {
if (macroUsage.getText().startsWith(key)) {
final var macroUsageText = macroUsage.getText();
for (final var key : cache.keySet()) {
if (macroUsageText.startsWith(key)) {
if (key.length() > currentKey.length()) {
currentKey = key;
}
}
}
if (currentKey.isEmpty()) {
return;
}
final ImpexMacroDescriptor descriptor = cache.get(currentKey);
final int start = macroUsage.getTextRange().getStartOffset();
final TextRange range = new TextRange(start, start + descriptor.macroName().length());
if (currentKey.isEmpty()) return;

final var descriptor = impexFile.getSuitableMacroDescriptor(currentKey, macroUsage);
if (descriptor == null) return;

final var start = macroUsage.getTextRange().getStartOffset();
final var range = new TextRange(start, start + descriptor.macroName().length());

results.add(new FoldingDescriptor(macroUsage.getNode(), range, null));

cache.put(macroUsage.getText(), descriptor);
cache.put(macroUsageText, descriptor);
}

@Nullable
private ImpexMacroDescriptor findInCache(
final Map<String, ImpexMacroDescriptor> cache,
final String text
final ImpexFile impexFile,
final MultiValuedMap<String, ImpexMacroDescriptor> cache,
final ImpexMacroUsageDec macroUsageDec
) {
final ImpexMacroDescriptor impexMacroDescriptor = cache.get(text);
if (impexMacroDescriptor != null) {
return impexMacroDescriptor;
}
for (ImpexMacroDescriptor md : cache.values()) {
if (text.startsWith(md.macroName())) {
cache.put(text, md);
final var macroName = macroUsageDec.getName();
final var impexMacroDescriptor = impexFile.getSuitableMacroDescriptor(macroName, macroUsageDec);
if (impexMacroDescriptor != null) return impexMacroDescriptor;

for (final var md : cache.values()) {
if (macroName.startsWith(md.macroName())) {
cache.put(macroName, md);
return md;
}
}
Expand All @@ -272,37 +267,37 @@ private ImpexMacroDescriptor findInCache(
@Nullable
@Override
public String getPlaceholderText(@NotNull final ASTNode node) {
final Map<String, ImpexMacroDescriptor> cache = ImpexMacroUtils.getFileCache(node.getPsi().getContainingFile()).getValue();
final ImpexMacroDescriptor descriptor = cache.get(node.getText());
if (descriptor != null) {
final var resolvedValue = descriptor.resolvedValue();

if (resolvedValue.startsWith("jar:")) {
final var blocks = resolvedValue.substring("jar:".length()).split("&");
if (blocks.length == 2) {
final var loaderClass = blocks[0];
return "jar:"
+ loaderClass.substring(loaderClass.lastIndexOf('.') + 1)
+ '&'
+ getFileName(blocks[1]);
}
} else if (resolvedValue.startsWith("zip:")) {
final var blocks = resolvedValue.substring("zip:".length()).split("&");
if (blocks.length == 2) {
final var zipName = getFileName(blocks[0]);
return "zip:" + zipName + '&' + blocks[1];
}
} else if (resolvedValue.startsWith("file:")) {
final var blocks = resolvedValue.split(":");
if (blocks.length == 2) {
final var fileName = getFileName(blocks[1]);
return "file:" + fileName;
}
}
final var psi = node.getPsi();
final var descriptor = ((ImpexFile) psi.getContainingFile()).getSuitableMacroDescriptor(node.getText(), psi);

if (descriptor == null) return node.getText();

return resolvedValue;
final var resolvedValue = descriptor.resolvedValue();

if (resolvedValue.startsWith("jar:")) {
final var blocks = resolvedValue.substring("jar:".length()).split("&");
if (blocks.length == 2) {
final var loaderClass = blocks[0];
return "jar:"
+ loaderClass.substring(loaderClass.lastIndexOf('.') + 1)
+ '&'
+ getFileName(blocks[1]);
}
} else if (resolvedValue.startsWith("zip:")) {
final var blocks = resolvedValue.substring("zip:".length()).split("&");
if (blocks.length == 2) {
final var zipName = getFileName(blocks[0]);
return "zip:" + zipName + '&' + blocks[1];
}
} else if (resolvedValue.startsWith("file:")) {
final var blocks = resolvedValue.split(":");
if (blocks.length == 2) {
final var fileName = getFileName(blocks[1]);
return "file:" + fileName;
}
}
return node.getText();

return resolvedValue;
}

@NotNull
Expand Down
22 changes: 21 additions & 1 deletion src/com/intellij/idea/plugin/hybris/impex/psi/ImpexFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,14 @@ package com.intellij.idea.plugin.hybris.impex.psi
import com.intellij.extapi.psi.PsiFileBase
import com.intellij.idea.plugin.hybris.impex.ImpexLanguage
import com.intellij.idea.plugin.hybris.impex.file.ImpexFileType
import com.intellij.idea.plugin.hybris.impex.lang.folding.ImpexMacroDescriptor
import com.intellij.idea.plugin.hybris.psi.util.getLineNumber
import com.intellij.openapi.util.Key
import com.intellij.psi.FileViewProvider
import com.intellij.psi.PsiElement
import com.intellij.psi.util.*
import org.apache.commons.collections4.MultiValuedMap
import org.apache.commons.collections4.multimap.HashSetValuedHashMap
import java.io.Serial

class ImpexFile(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, ImpexLanguage) {
Expand All @@ -42,9 +47,24 @@ class ImpexFile(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, Impe
)
}, false)

fun getMacroDescriptors(): MultiValuedMap<String, ImpexMacroDescriptor> = CachedValuesManager.getManager(project).getCachedValue(this, CACHE_KEY_MACRO_DESCRIPTORS, {
CachedValueProvider.Result.createSingleDependency(
HashSetValuedHashMap(),
PsiModificationTracker.MODIFICATION_COUNT,
)
}, false)

fun getSuitableMacroDescriptor(macroName: String, macroUsage: PsiElement) = getMacroDescriptors()[macroName]
?.asSequence()
?.map { it.psiElement.getLineNumber() to it }
?.filter { macroUsage.getLineNumber() >= it.first }
?.sortedByDescending { it.first }
?.map { it.second }
?.firstOrNull()

companion object {
val CACHE_KEY_HEADER_LINES = Key.create<CachedValue<Map<ImpexHeaderLine, Collection<ImpexValueLine>>>>("SAP_CX_IMPEX_HEADER_LINES")
val CACHE_KEY_MACRO_DESCRIPTORS = Key.create<CachedValue<Map<ImpexHeaderLine, Collection<ImpexValueLine>>>>("SAP_CX_IMPEX_MACRO_DESCRIPTORS")
val CACHE_KEY_MACRO_DESCRIPTORS = Key.create<CachedValue<MultiValuedMap<String, ImpexMacroDescriptor>>>("SAP_CX_IMPEX_MACRO_DESCRIPTORS")

@Serial
private val serialVersionUID: Long = 5112646813557523662L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,8 @@ class ImpexMacroReference(owner: PsiElement) : PsiReferenceBase.Poly<PsiElement?

private val provider = ParameterizedCachedValueProvider<Array<ResolveResult>, ImpexMacroReference> { ref ->
val element = ref.element
val text = element.text
val macroUsageLineNumber = element.getLineNumber()
val result = ref.findMacroDeclaration()
?.let { PsiElementResolveResult.createResults(it.originalElement) }
?.let { PsiElementResolveResult.createResults(it.macroNameDec) }
?: ResolveResult.EMPTY_ARRAY

CachedValueProvider.Result.create(
Expand Down

0 comments on commit ff1fda6

Please sign in to comment.