Skip to content

Commit ed59dc9

Browse files
Merge pull request #1032 from alexstpp/613-diff-overridden-template
613: Added possibility to compare overridden template with the original one
2 parents 3c6721b + 4cee5c5 commit ed59dc9

File tree

5 files changed

+276
-8
lines changed

5 files changed

+276
-8
lines changed

resources/META-INF/plugin.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@
130130
<action id="MagentoInjectConstructorArgumentAction.Menu" class="com.magento.idea.magento2plugin.actions.generation.InjectConstructorArgumentAction">
131131
<add-to-group group-id="EditorPopupMenu"/>
132132
</action>
133+
<action id="MagentoCompareTemplate.Menu" class="com.magento.idea.magento2plugin.actions.comparator.CompareTemplateAction">
134+
<add-to-group group-id="EditorPopupMenu"/>
135+
</action>
133136

134137
<action id="CopyMagentoPath"
135138
class="com.magento.idea.magento2plugin.actions.CopyMagentoPath"
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.actions.comparator;
7+
8+
import com.intellij.diff.DiffDialogHints;
9+
import com.intellij.diff.DiffManager;
10+
import com.intellij.diff.chains.DiffRequestChain;
11+
import com.intellij.openapi.actionSystem.AnAction;
12+
import com.intellij.openapi.actionSystem.AnActionEvent;
13+
import com.intellij.openapi.actionSystem.PlatformDataKeys;
14+
import com.intellij.openapi.project.Project;
15+
import com.intellij.openapi.vfs.VfsUtil;
16+
import com.intellij.openapi.vfs.VirtualFile;
17+
import com.intellij.psi.PsiDirectory;
18+
import com.intellij.psi.PsiFile;
19+
import com.magento.idea.magento2plugin.MagentoIcons;
20+
import com.magento.idea.magento2plugin.actions.comparator.util.DiffRequestChainUtil;
21+
import com.magento.idea.magento2plugin.indexes.ModuleIndex;
22+
import com.magento.idea.magento2plugin.magento.packages.Areas;
23+
import com.magento.idea.magento2plugin.project.Settings;
24+
import com.magento.idea.magento2plugin.util.magento.GetModuleNameByDirectoryUtil;
25+
import com.magento.idea.magento2plugin.util.magento.area.AreaResolverUtil;
26+
import java.nio.file.Path;
27+
import org.apache.commons.lang3.StringUtils;
28+
import org.jetbrains.annotations.NotNull;
29+
import org.jetbrains.annotations.Nullable;
30+
31+
public class CompareTemplateAction extends AnAction {
32+
33+
public static final String ACTION_NAME = "Compare overridden template with the original one";
34+
public static final String ACTION_DESCRIPTION = "The Magento 2 overridden template comparing";
35+
36+
private static final String PHTML_EXTENSION = "phtml";
37+
protected VirtualFile selectedFile;
38+
protected VirtualFile originalFile;
39+
40+
/**
41+
* Compare template action constructor.
42+
*/
43+
public CompareTemplateAction() {
44+
super(ACTION_NAME, ACTION_DESCRIPTION, MagentoIcons.MODULE);
45+
}
46+
47+
/**
48+
* Updates the state of action.
49+
*
50+
* @param event AnActionEvent
51+
*/
52+
@SuppressWarnings("PMD.NPathComplexity")
53+
@Override
54+
public void update(final @NotNull AnActionEvent event) {
55+
setStatus(event, false);
56+
final Project project = event.getData(PlatformDataKeys.PROJECT);
57+
58+
if (project == null) {
59+
return;
60+
}
61+
62+
if (!Settings.isEnabled(project)) {
63+
return;
64+
}
65+
final PsiFile psiFile = event.getData(PlatformDataKeys.PSI_FILE);
66+
67+
if (psiFile == null) {
68+
return;
69+
}
70+
final VirtualFile targetFileCandidate = psiFile.getVirtualFile();
71+
72+
if (targetFileCandidate == null) {
73+
return;
74+
}
75+
76+
if (!PHTML_EXTENSION.equals(targetFileCandidate.getExtension())) {
77+
return;
78+
}
79+
final Areas area = AreaResolverUtil.getForFileInCustomTheme(targetFileCandidate);
80+
81+
if (area == null) {
82+
return;
83+
}
84+
final String originalModuleName = getOriginalModuleName(project, psiFile);
85+
86+
final PsiDirectory originalModuleDirectory =
87+
new ModuleIndex(project).getModuleDirectoryByModuleName(originalModuleName);
88+
89+
if (originalModuleDirectory == null) {
90+
return;
91+
}
92+
final String originalFilePath = originalModuleDirectory.getVirtualFile().getPath()
93+
+ "/view/"
94+
+ area
95+
+ StringUtils.substringAfter(targetFileCandidate.getPath(), originalModuleName);
96+
97+
final VirtualFile origFileCandidate = VfsUtil.findFile(Path.of(originalFilePath), false);
98+
99+
if (origFileCandidate == null) {
100+
return;
101+
}
102+
selectedFile = targetFileCandidate;
103+
originalFile = origFileCandidate;
104+
this.setStatus(event, true);
105+
}
106+
107+
@Override
108+
public void actionPerformed(final @NotNull AnActionEvent event) {
109+
final Project project = event.getProject();
110+
111+
if (project == null || selectedFile == null || originalFile == null) {
112+
return;
113+
}
114+
final DiffRequestChain chain = DiffRequestChainUtil.createMutableChain(
115+
project,
116+
selectedFile,
117+
originalFile
118+
);
119+
120+
if (chain == null) {
121+
return;
122+
}
123+
DiffManager.getInstance().showDiff(
124+
project,
125+
chain,
126+
DiffDialogHints.DEFAULT
127+
);
128+
}
129+
130+
private @Nullable String getOriginalModuleName(
131+
final @NotNull Project project,
132+
final @NotNull PsiFile psiFile
133+
) {
134+
final PsiDirectory directory = psiFile.getContainingDirectory();
135+
136+
return GetModuleNameByDirectoryUtil.execute(directory, project);
137+
}
138+
139+
private void setStatus(final AnActionEvent event, final boolean status) {
140+
event.getPresentation().setVisible(status);
141+
event.getPresentation().setEnabled(status);
142+
}
143+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.actions.comparator.util;
7+
8+
import com.intellij.diff.DiffContentFactory;
9+
import com.intellij.diff.DiffRequestFactory;
10+
import com.intellij.diff.actions.BlankDiffWindowUtil;
11+
import com.intellij.diff.actions.impl.MutableDiffRequestChain;
12+
import com.intellij.diff.contents.DiffContent;
13+
import com.intellij.diff.contents.DocumentContent;
14+
import com.intellij.openapi.project.Project;
15+
import com.intellij.openapi.vfs.VirtualFile;
16+
import org.jetbrains.annotations.NotNull;
17+
import org.jetbrains.annotations.Nullable;
18+
19+
public final class DiffRequestChainUtil {
20+
21+
private DiffRequestChainUtil() {}
22+
23+
/**
24+
* Create mutable chain for files comparing.
25+
*
26+
* @param project Project
27+
* @param targetFile VirtualFile
28+
* @param baseFile VirtualFile
29+
*
30+
* @return MutableDiffRequestChain
31+
*/
32+
public static @Nullable MutableDiffRequestChain createMutableChain(
33+
final @NotNull Project project,
34+
final @NotNull VirtualFile targetFile,
35+
final @NotNull VirtualFile baseFile
36+
) {
37+
final DiffContentFactory contentFactory = DiffContentFactory.getInstance();
38+
final DiffContent targetContent = contentFactory.create(project, targetFile);
39+
final DiffContent baseContent = contentFactory.create(project, baseFile);
40+
41+
if (!(targetContent instanceof DocumentContent)
42+
|| !(baseContent instanceof DocumentContent)) {
43+
return null;
44+
}
45+
46+
final MutableDiffRequestChain chain = BlankDiffWindowUtil.createBlankDiffRequestChain(
47+
(DocumentContent) targetContent,
48+
(DocumentContent) baseContent,
49+
null
50+
);
51+
chain.setWindowTitle(DiffRequestFactory.getInstance().getTitle(targetFile, baseFile));
52+
53+
return chain;
54+
}
55+
}

src/com/magento/idea/magento2plugin/indexes/ModuleIndex.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.intellij.psi.PsiDirectory;
1313
import com.intellij.psi.PsiManager;
1414
import com.intellij.psi.search.GlobalSearchScope;
15+
import com.intellij.util.SlowOperations;
1516
import com.intellij.util.indexing.FileBasedIndex;
1617
import com.jetbrains.php.lang.PhpFileType;
1718
import com.magento.idea.magento2plugin.magento.packages.Package;
@@ -116,6 +117,7 @@ private List<String> getNames(
116117
* Returns PSI directory of the certain module.
117118
*
118119
* @param moduleName String
120+
*
119121
* @return PsiDirectory
120122
*/
121123
public @Nullable PsiDirectory getModuleDirectoryByModuleName(final String moduleName) {
@@ -124,14 +126,20 @@ private List<String> getNames(
124126
}
125127
final FileBasedIndex index = FileBasedIndex
126128
.getInstance();
127-
128-
final Collection<VirtualFile> files = index.getContainingFiles(
129-
ModuleNameIndex.KEY,
130-
moduleName,
131-
GlobalSearchScope.getScopeRestrictedByFileTypes(
132-
GlobalSearchScope.allScope(project),
133-
PhpFileType.INSTANCE
134-
));
129+
final Collection<VirtualFile> files = new ArrayList<>();
130+
131+
SlowOperations.allowSlowOperations(() -> {
132+
files.addAll(
133+
index.getContainingFiles(
134+
ModuleNameIndex.KEY,
135+
moduleName,
136+
GlobalSearchScope.getScopeRestrictedByFileTypes(
137+
GlobalSearchScope.allScope(project),
138+
PhpFileType.INSTANCE
139+
)
140+
)
141+
);
142+
});
135143

136144
if (files.isEmpty()) {
137145
return null;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.util.magento.area;
7+
8+
import com.intellij.openapi.vfs.VirtualFile;
9+
import com.magento.idea.magento2plugin.magento.packages.Areas;
10+
import java.util.regex.Matcher;
11+
import java.util.regex.Pattern;
12+
import org.jetbrains.annotations.NotNull;
13+
import org.jetbrains.annotations.Nullable;
14+
15+
public final class AreaResolverUtil {
16+
17+
private static final String CUSTOM_THEME_AREA = "\\/design\\/(adminhtml|frontend)\\/";
18+
private static final String MODULE_AREA =
19+
"\\/view\\/(adminhtml|frontend|base|crontab|webapi_rest|webapi_soap|graphql)\\/";
20+
21+
private AreaResolverUtil() {}
22+
23+
/**
24+
* Get Magento 2 area for the specified file (file should be in the custom theme).
25+
*
26+
* @param virtualFile VirtualFile
27+
*
28+
* @return Areas or null if file does not belong to the custom (editable) theme.
29+
*/
30+
public static @Nullable Areas getForFileInCustomTheme(final @NotNull VirtualFile virtualFile) {
31+
return getArea(virtualFile.getPath(), CUSTOM_THEME_AREA);
32+
}
33+
34+
/**
35+
* Get Magento 2 area for the specified file (file should be in the Magento 2 module).
36+
*
37+
* @param virtualFile VirtualFile
38+
*
39+
* @return Areas or null if file does not belong to the Magento 2 module.
40+
*/
41+
public static @Nullable Areas getForFileInModule(final @NotNull VirtualFile virtualFile) {
42+
return getArea(virtualFile.getPath(), MODULE_AREA);
43+
}
44+
45+
private static @Nullable Areas getArea(
46+
final @NotNull String filePath,
47+
final @NotNull String searchingRegex
48+
) {
49+
final Pattern pattern = Pattern.compile(searchingRegex);
50+
final Matcher matcher = pattern.matcher(filePath);
51+
String areaName = null;
52+
53+
if (matcher.find()) {
54+
areaName = matcher.group(1);
55+
}
56+
57+
return areaName == null ? null : Areas.getAreaByString(areaName);
58+
}
59+
}

0 commit comments

Comments
 (0)