Skip to content

613: Added possibility to compare overridden template with the original one #1032

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
Show file tree
Hide file tree
Changes from 11 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
3 changes: 3 additions & 0 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@
<action id="MagentoInjectConstructorArgumentAction.Menu" class="com.magento.idea.magento2plugin.actions.generation.InjectConstructorArgumentAction">
<add-to-group group-id="EditorPopupMenu"/>
</action>
<action id="MagentoCompareTemplate.Menu" class="com.magento.idea.magento2plugin.actions.comparator.CompareTemplateAction">
<add-to-group group-id="EditorPopupMenu"/>
</action>

<action id="CopyMagentoPath"
class="com.magento.idea.magento2plugin.actions.CopyMagentoPath"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

package com.magento.idea.magento2plugin.actions.comparator;

import com.intellij.diff.DiffDialogHints;
import com.intellij.diff.DiffManager;
import com.intellij.diff.chains.DiffRequestChain;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.magento.idea.magento2plugin.MagentoIcons;
import com.magento.idea.magento2plugin.actions.comparator.util.DiffRequestChainUtil;
import com.magento.idea.magento2plugin.indexes.ModuleIndex;
import com.magento.idea.magento2plugin.magento.packages.Areas;
import com.magento.idea.magento2plugin.project.Settings;
import com.magento.idea.magento2plugin.util.magento.GetModuleNameByDirectoryUtil;
import com.magento.idea.magento2plugin.util.magento.area.AreaResolverUtil;
import java.nio.file.Path;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class CompareTemplateAction extends AnAction {

public static final String ACTION_NAME = "Compare overridden template with the original one";
public static final String ACTION_DESCRIPTION = "The Magento 2 overridden template comparing";

private static final String PHTML_EXTENSION = "phtml";
protected VirtualFile selectedFile;
protected VirtualFile originalFile;

/**
* Compare template action constructor.
*/
public CompareTemplateAction() {
super(ACTION_NAME, ACTION_DESCRIPTION, MagentoIcons.MODULE);
}

/**
* Updates the state of action.
*
* @param event AnActionEvent
*/
@SuppressWarnings("PMD.NPathComplexity")
@Override
public void update(final @NotNull AnActionEvent event) {
setStatus(event, false);
final Project project = event.getData(PlatformDataKeys.PROJECT);

if (project == null) {
return;
}

if (!Settings.isEnabled(project)) {
return;
}
final PsiFile psiFile = event.getData(PlatformDataKeys.PSI_FILE);

if (psiFile == null) {
return;
}
final VirtualFile targetFileCandidate = psiFile.getVirtualFile();

if (targetFileCandidate == null) {
return;
}

if (!PHTML_EXTENSION.equals(targetFileCandidate.getExtension())) {
return;
}
final Areas area = AreaResolverUtil.getForFileInCustomTheme(targetFileCandidate);

if (area == null) {
return;
}
final String originalModuleName = getOriginalModuleName(project, psiFile);
final PsiDirectory originalModuleDirectory =
new ModuleIndex(project).getModuleDirectoryByModuleName(originalModuleName);

if (originalModuleDirectory == null) {
return;
}
final String originalFilePath = originalModuleDirectory.getVirtualFile().getPath()
+ "/view/"
+ area
+ StringUtils.substringAfter(targetFileCandidate.getPath(), originalModuleName);

final VirtualFile origFileCandidate = VfsUtil.findFile(Path.of(originalFilePath), false);

if (origFileCandidate == null) {
return;
}
selectedFile = targetFileCandidate;
originalFile = origFileCandidate;
this.setStatus(event, true);
}

@Override
public void actionPerformed(final @NotNull AnActionEvent event) {
final Project project = event.getProject();

if (project == null || selectedFile == null || originalFile == null) {
return;
}
final DiffRequestChain chain = DiffRequestChainUtil.createMutableChain(
project,
selectedFile,
originalFile
);

if (chain == null) {
return;
}
DiffManager.getInstance().showDiff(
project,
chain,
DiffDialogHints.DEFAULT
);
}

private @Nullable String getOriginalModuleName(
final @NotNull Project project,
final @NotNull PsiFile psiFile
) {
final PsiDirectory directory = psiFile.getContainingDirectory();

return GetModuleNameByDirectoryUtil.execute(directory, project);
}

private void setStatus(final AnActionEvent event, final boolean status) {
event.getPresentation().setVisible(status);
event.getPresentation().setEnabled(status);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

package com.magento.idea.magento2plugin.actions.comparator.util;

import com.intellij.diff.DiffContentFactory;
import com.intellij.diff.DiffRequestFactory;
import com.intellij.diff.actions.BlankDiffWindowUtil;
import com.intellij.diff.actions.impl.MutableDiffRequestChain;
import com.intellij.diff.contents.DiffContent;
import com.intellij.diff.contents.DocumentContent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class DiffRequestChainUtil {

private DiffRequestChainUtil() {}

/**
* Create mutable chain for files comparing.
*
* @param project Project
* @param targetFile VirtualFile
* @param baseFile VirtualFile
*
* @return MutableDiffRequestChain
*/
public static @Nullable MutableDiffRequestChain createMutableChain(
final @NotNull Project project,
final @NotNull VirtualFile targetFile,
final @NotNull VirtualFile baseFile
) {
final DiffContentFactory contentFactory = DiffContentFactory.getInstance();
final DiffContent targetContent = contentFactory.create(project, targetFile);
final DiffContent baseContent = contentFactory.create(project, baseFile);

if (!(targetContent instanceof DocumentContent)
|| !(baseContent instanceof DocumentContent)) {
return null;
}

final MutableDiffRequestChain chain = BlankDiffWindowUtil.createBlankDiffRequestChain(
(DocumentContent) targetContent,
(DocumentContent) baseContent,
null
);
chain.setWindowTitle(DiffRequestFactory.getInstance().getTitle(targetFile, baseFile));

return chain;
}
}
24 changes: 16 additions & 8 deletions src/com/magento/idea/magento2plugin/indexes/ModuleIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.SlowOperations;
import com.intellij.util.indexing.FileBasedIndex;
import com.jetbrains.php.lang.PhpFileType;
import com.magento.idea.magento2plugin.magento.packages.Package;
Expand Down Expand Up @@ -116,6 +117,7 @@ private List<String> getNames(
* Returns PSI directory of the certain module.
*
* @param moduleName String
*
* @return PsiDirectory
*/
public @Nullable PsiDirectory getModuleDirectoryByModuleName(final String moduleName) {
Expand All @@ -124,14 +126,20 @@ private List<String> getNames(
}
final FileBasedIndex index = FileBasedIndex
.getInstance();

final Collection<VirtualFile> files = index.getContainingFiles(
ModuleNameIndex.KEY,
moduleName,
GlobalSearchScope.getScopeRestrictedByFileTypes(
GlobalSearchScope.allScope(project),
PhpFileType.INSTANCE
));
final Collection<VirtualFile> files = new ArrayList<>();

SlowOperations.allowSlowOperations(() -> {
files.addAll(
index.getContainingFiles(
ModuleNameIndex.KEY,
moduleName,
GlobalSearchScope.getScopeRestrictedByFileTypes(
GlobalSearchScope.allScope(project),
PhpFileType.INSTANCE
)
)
);
});

if (files.isEmpty()) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

package com.magento.idea.magento2plugin.util.magento.area;

import com.intellij.openapi.vfs.VirtualFile;
import com.magento.idea.magento2plugin.magento.packages.Areas;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class AreaResolverUtil {

private static final String CUSTOM_THEME_AREA = "\\/design\\/(adminhtml|frontend)\\/";
private static final String MODULE_AREA =
"\\/view\\/(adminhtml|frontend|base|crontab|webapi_rest|webapi_soap|graphql)\\/";

private AreaResolverUtil() {}

/**
* Get Magento 2 area for the specified file (file should be in the custom theme).
*
* @param virtualFile VirtualFile
*
* @return Areas or null if file does not belong to the custom (editable) theme.
*/
public static @Nullable Areas getForFileInCustomTheme(final @NotNull VirtualFile virtualFile) {
return getArea(virtualFile.getPath(), CUSTOM_THEME_AREA);
}

/**
* Get Magento 2 area for the specified file (file should be in the Magento 2 module).
*
* @param virtualFile VirtualFile
*
* @return Areas or null if file does not belong to the Magento 2 module.
*/
public static @Nullable Areas getForFileInModule(final @NotNull VirtualFile virtualFile) {
return getArea(virtualFile.getPath(), MODULE_AREA);
}

private static @Nullable Areas getArea(
final @NotNull String filePath,
final @NotNull String searchingRegex
) {
final Pattern pattern = Pattern.compile(searchingRegex);
final Matcher matcher = pattern.matcher(filePath);
String areaName = null;

if (matcher.find()) {
areaName = matcher.group(1);
}

return areaName == null ? null : Areas.getAreaByString(areaName);
}
}