From 414a185e2e5f83a1a985381846830589f7941d29 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 21 Nov 2013 16:28:47 +0400 Subject: [PATCH] fixed clicking on stacktrace links in console when several classes are found: prefer modules over libraries, show popup if necessary (IDEA-52913) --- .../filters/ExceptionExFilterFactory.java | 11 +- .../execution/filters/ExceptionWorker.java | 135 +++++++----------- .../filters/HyperlinkInfoFactory.java | 37 +++++ .../impl/HyperlinkInfoFactoryImpl.java | 36 +++++ .../impl/MultipleFilesHyperlinkInfo.java | 119 +++++++++++++++ .../execution/impl/ConsoleViewImpl.java | 13 +- .../execution/filters/HyperlinkInfoBase.java | 33 +++++ .../impl/EditorHyperlinkSupport.java | 9 +- .../src/META-INF/LangExtensions.xml | 2 + 9 files changed, 307 insertions(+), 88 deletions(-) create mode 100644 platform/lang-api/src/com/intellij/execution/filters/HyperlinkInfoFactory.java create mode 100644 platform/lang-impl/src/com/intellij/execution/filters/impl/HyperlinkInfoFactoryImpl.java create mode 100644 platform/lang-impl/src/com/intellij/execution/filters/impl/MultipleFilesHyperlinkInfo.java create mode 100644 platform/platform-api/src/com/intellij/execution/filters/HyperlinkInfoBase.java diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionExFilterFactory.java b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionExFilterFactory.java index 88fa616d7025..433da78acb21 100644 --- a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionExFilterFactory.java +++ b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionExFilterFactory.java @@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.markup.EffectType; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.Trinity; import com.intellij.psi.*; @@ -84,10 +85,16 @@ public class ExceptionExFilterFactory implements ExceptionFilterFactory { worker.execute(text, lineEndOffset); Result result = worker.getResult(); if (result == null) continue; - OpenFileHyperlinkInfo hyperlinkInfo = ExceptionWorker.getOpenFileHyperlinkInfo(result); - int offset = hyperlinkInfo == null? -1 : hyperlinkInfo.getDescriptor().getOffset(); + HyperlinkInfo hyperlinkInfo = result.hyperlinkInfo; + if (!(hyperlinkInfo instanceof FileHyperlinkInfo)) continue; + + OpenFileDescriptor descriptor = ((FileHyperlinkInfo)hyperlinkInfo).getDescriptor(); + if (descriptor == null) continue; + + int offset = descriptor.getOffset(); PsiFile psiFile = worker.getFile(); if (offset <= 0 || psiFile == null) continue; + PsiElement element = psiFile.findElementAt(offset); PsiTryStatement parent = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class, true, PsiClass.class); PsiCodeBlock tryBlock = parent != null? parent.getTryBlock() : null; diff --git a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java index 3fcd9c959a50..ff02aadc3856 100644 --- a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java +++ b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java @@ -15,26 +15,29 @@ */ package com.intellij.execution.filters; -import com.intellij.openapi.application.AccessToken; -import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.editor.colors.CodeInsightColors; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.Trinity; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; +import com.intellij.util.ArrayUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.*; +import java.util.ArrayList; +import java.util.List; /** * User: Irina.Chernushina @@ -61,8 +64,8 @@ public class ExceptionWorker { private final Project myProject; private final GlobalSearchScope mySearchScope; private Filter.Result myResult; - private PsiClass myClass; - private PsiFile myFile; + private PsiClass[] myClasses = PsiClass.EMPTY_ARRAY; + private PsiFile[] myFiles = PsiFile.EMPTY_ARRAY; private String myMethod; private Trinity myInfo; @@ -90,16 +93,17 @@ public class ExceptionWorker { final String lineString = fileAndLine.substring(colonIndex + 1); try { final int lineNumber = Integer.parseInt(lineString); - myClass = findPositionClass(line); - myFile = myClass == null ? null : (PsiFile)myClass.getContainingFile().getNavigationElement(); - if (myFile == null) { - // try find the file with the required name - PsiFile[] files = PsiShortNamesCache.getInstance(myProject).getFilesByName(fileAndLine.substring(0, colonIndex).trim()); - if (files.length > 0) { - myFile = files[0]; - } + myClasses = findPositionClasses(line); + myFiles = new PsiFile[myClasses.length]; + for (int i = 0; i < myClasses.length; i++) { + myFiles[i] = (PsiFile)myClasses[i].getContainingFile().getNavigationElement(); } - if (myFile == null) return; + if (myFiles.length == 0) { + // try find the file with the required name + //todo[nik] it would be better to use FilenameIndex here to honor the scope by it isn't accessible in Open API + myFiles = PsiShortNamesCache.getInstance(myProject).getFilesByName(fileAndLine.substring(0, colonIndex).trim()); + } + if (myFiles.length == 0) return; /* IDEADEV-4976: Some scramblers put something like SourceFile mock instead of real class name. @@ -113,12 +117,31 @@ public class ExceptionWorker { final int highlightStartOffset = textStartOffset + lparenthIndex + 1; final int highlightEndOffset = textStartOffset + rparenthIndex; - final VirtualFile virtualFile = myFile.getVirtualFile(); - HyperlinkInfo linkInfo = new MyHyperlinkInfo(myProject, virtualFile, lineNumber); + ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex(); + List virtualFilesInLibraries = new ArrayList(); + List virtualFilesInContent = new ArrayList(); + for (PsiFile file : myFiles) { + VirtualFile virtualFile = file.getVirtualFile(); + if (index.isInContent(virtualFile)) { + virtualFilesInContent.add(virtualFile); + } + else { + virtualFilesInLibraries.add(virtualFile); + } + } - boolean inContent = ProjectRootManager.getInstance(myProject).getFileIndex().isInContent(virtualFile); - TextAttributes attributes = inContent ? HYPERLINK_ATTRIBUTES : LIBRARY_HYPERLINK_ATTRIBUTES; + List virtualFiles; + TextAttributes attributes; + if (virtualFilesInContent.isEmpty()) { + attributes = LIBRARY_HYPERLINK_ATTRIBUTES; + virtualFiles = virtualFilesInLibraries; + } + else { + attributes = HYPERLINK_ATTRIBUTES; + virtualFiles = virtualFilesInContent; + } + HyperlinkInfo linkInfo = HyperlinkInfoFactory.getInstance().createMultipleFilesHyperlinkInfo(virtualFiles, lineNumber - 1, myProject); myResult = new Filter.Result(highlightStartOffset, highlightEndOffset, linkInfo, attributes); } catch (NumberFormatException e) { @@ -126,22 +149,23 @@ public class ExceptionWorker { } } - private PsiClass findPositionClass(String line) { + private PsiClass[] findPositionClasses(String line) { String className = myInfo.first.substring(line).trim(); - PsiClass result = findClassPreferringMyScope(className); - if (result == null) { + PsiClass[] result = findClassesPreferringMyScope(className); + if (result.length == 0) { final int dollarIndex = className.indexOf('$'); if (dollarIndex >= 0) { - result = findClassPreferringMyScope(className.substring(0, dollarIndex)); + result = findClassesPreferringMyScope(className.substring(0, dollarIndex)); } } return result; } - private PsiClass findClassPreferringMyScope(String className) { + @NotNull + private PsiClass[] findClassesPreferringMyScope(String className) { JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); - PsiClass result = psiFacade.findClass(className, mySearchScope); - return result != null ? result : psiFacade.findClass(className, GlobalSearchScope.allScope(myProject)); + PsiClass[] result = psiFacade.findClasses(className, mySearchScope); + return result.length != 0 ? result : psiFacade.findClasses(className, GlobalSearchScope.allScope(myProject)); } public Filter.Result getResult() { @@ -149,7 +173,7 @@ public class ExceptionWorker { } public PsiClass getPsiClass() { - return myClass; + return ArrayUtil.getFirstElement(myClasses); } public String getMethod() { @@ -157,7 +181,7 @@ public class ExceptionWorker { } public PsiFile getFile() { - return myFile; + return ArrayUtil.getFirstElement(myFiles); } public Trinity getInfo() { @@ -205,59 +229,4 @@ public class ExceptionWorker { } return pos; } - - @Nullable - static OpenFileHyperlinkInfo getOpenFileHyperlinkInfo(Filter.Result result) { - if (result.hyperlinkInfo instanceof MyHyperlinkInfo) { - MyHyperlinkInfo info = (MyHyperlinkInfo)result.hyperlinkInfo; - return new OpenFileHyperlinkInfo(info.myProject, info.myVirtualFile, info.myLineNumber); - } - return null; - } - - private static class MyHyperlinkInfo implements FileHyperlinkInfo { - private final VirtualFile myVirtualFile; - private final int myLineNumber; - private final Project myProject; - - public MyHyperlinkInfo(@NotNull Project project, @NotNull VirtualFile virtualFile, int lineNumber) { - myProject = project; - myVirtualFile = virtualFile; - myLineNumber = lineNumber; - } - - @Override - public void navigate(Project project) { - VirtualFile currentVirtualFile = null; - - AccessToken accessToken = ReadAction.start(); - - try { - if (!myVirtualFile.isValid()) return; - - PsiFile psiFile = PsiManager.getInstance(project).findFile(myVirtualFile); - if (psiFile != null) { - PsiElement navigationElement = psiFile.getNavigationElement(); // Sources may be downloaded. - if (navigationElement instanceof PsiFile) { - currentVirtualFile = ((PsiFile)navigationElement).getVirtualFile(); - } - } - - if (currentVirtualFile == null) { - currentVirtualFile = myVirtualFile; - } - } - finally { - accessToken.finish(); - } - - new OpenFileHyperlinkInfo(myProject, currentVirtualFile, myLineNumber - 1).navigate(project); - } - - @Nullable - @Override - public OpenFileDescriptor getDescriptor() { - return new OpenFileDescriptor(myProject, myVirtualFile, myLineNumber - 1, 0); - } - } } diff --git a/platform/lang-api/src/com/intellij/execution/filters/HyperlinkInfoFactory.java b/platform/lang-api/src/com/intellij/execution/filters/HyperlinkInfoFactory.java new file mode 100644 index 000000000000..42beb03faeff --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/filters/HyperlinkInfoFactory.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author nik + */ +public abstract class HyperlinkInfoFactory { + @NotNull + public static HyperlinkInfoFactory getInstance() { + return ServiceManager.getService(HyperlinkInfoFactory.class); + } + + @NotNull + public abstract HyperlinkInfo createMultipleFilesHyperlinkInfo(@NotNull List files, + int line, @NotNull Project project); +} diff --git a/platform/lang-impl/src/com/intellij/execution/filters/impl/HyperlinkInfoFactoryImpl.java b/platform/lang-impl/src/com/intellij/execution/filters/impl/HyperlinkInfoFactoryImpl.java new file mode 100644 index 000000000000..f8a800094410 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/filters/impl/HyperlinkInfoFactoryImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters.impl; + +import com.intellij.execution.filters.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author nik + */ +public class HyperlinkInfoFactoryImpl extends HyperlinkInfoFactory { + + @NotNull + @Override + public HyperlinkInfo createMultipleFilesHyperlinkInfo(@NotNull List files, + int line, @NotNull Project project) { + return new MultipleFilesHyperlinkInfo(files, line, project); + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/filters/impl/MultipleFilesHyperlinkInfo.java b/platform/lang-impl/src/com/intellij/execution/filters/impl/MultipleFilesHyperlinkInfo.java new file mode 100644 index 000000000000..36dc51e15be9 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/filters/impl/MultipleFilesHyperlinkInfo.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters.impl; + +import com.intellij.execution.filters.FileHyperlinkInfo; +import com.intellij.execution.filters.HyperlinkInfoBase; +import com.intellij.execution.filters.OpenFileHyperlinkInfo; +import com.intellij.ide.util.gotoByName.GotoFileCellRenderer; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.components.JBList; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** +* @author nik +*/ +class MultipleFilesHyperlinkInfo extends HyperlinkInfoBase implements FileHyperlinkInfo { + private final List myVirtualFiles; + private final int myLineNumber; + private final Project myProject; + + public MultipleFilesHyperlinkInfo(@NotNull List virtualFiles, int lineNumber, @NotNull Project project) { + myVirtualFiles = virtualFiles; + myLineNumber = lineNumber; + myProject = project; + } + + @Override + public void navigate(@NotNull final Project project, @Nullable RelativePoint hyperlinkLocationPoint) { + List currentFiles = new ArrayList(); + + AccessToken accessToken = ReadAction.start(); + try { + for (VirtualFile file : myVirtualFiles) { + if (!file.isValid()) continue; + + PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + if (psiFile != null) { + PsiElement navigationElement = psiFile.getNavigationElement(); // Sources may be downloaded. + if (navigationElement instanceof PsiFile) { + currentFiles.add((PsiFile)navigationElement); + continue; + } + currentFiles.add(psiFile); + } + } + } + finally { + accessToken.finish(); + } + + if (currentFiles.isEmpty()) return; + + if (currentFiles.size() == 1) { + new OpenFileHyperlinkInfo(myProject, currentFiles.get(0).getVirtualFile(), myLineNumber).navigate(project); + } + else { + final JBList list = new JBList(currentFiles); + int width = WindowManager.getInstance().getFrame(project).getSize().width; + list.setCellRenderer(new GotoFileCellRenderer(width)); + JBPopup popup = JBPopupFactory.getInstance().createListPopupBuilder(list) + .setTitle("Choose Target File") + .setItemChoosenCallback(new Runnable() { + @Override + public void run() { + VirtualFile file = ((PsiFile)list.getSelectedValue()).getVirtualFile(); + new OpenFileHyperlinkInfo(myProject, file, myLineNumber).navigate(project); + } + }) + .createPopup(); + if (hyperlinkLocationPoint != null) { + popup.show(hyperlinkLocationPoint); + } + else { + popup.showInFocusCenter(); + } + } + } + + @Nullable + @Override + public OpenFileDescriptor getDescriptor() { + VirtualFile file = getPreferredFile(); + return file != null ? new OpenFileDescriptor(myProject, file, myLineNumber, 0) : null; + } + + @Nullable + private VirtualFile getPreferredFile() { + return ContainerUtil.getFirstItem(myVirtualFiles); + } +} diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index 154d1e8a36f3..2d4a9c356af1 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -65,6 +65,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.ui.EditorNotificationPanel; +import com.intellij.ui.awt.RelativePoint; import com.intellij.util.Alarm; import com.intellij.util.Consumer; import com.intellij.util.EditorPopupHandler; @@ -1384,10 +1385,18 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo return EditorHyperlinkSupport.getNextOccurrence(myEditor, hyperlinks.getHyperlinks().keySet(), delta, new Consumer() { @Override public void consume(RangeHighlighter next) { - scrollTo(next.getStartOffset()); + int offset = next.getStartOffset(); + scrollTo(offset); final HyperlinkInfo hyperlinkInfo = hyperlinks.getHyperlinks().get(next); if (hyperlinkInfo != null) { - hyperlinkInfo.navigate(myProject); + if (hyperlinkInfo instanceof HyperlinkInfoBase) { + VisualPosition position = myEditor.offsetToVisualPosition(offset); + Point point = myEditor.visualPositionToXY(new VisualPosition(position.getLine() + 1, position.getColumn())); + ((HyperlinkInfoBase)hyperlinkInfo).navigate(myProject, new RelativePoint(myEditor.getContentComponent(), point)); + } + else { + hyperlinkInfo.navigate(myProject); + } } } }); diff --git a/platform/platform-api/src/com/intellij/execution/filters/HyperlinkInfoBase.java b/platform/platform-api/src/com/intellij/execution/filters/HyperlinkInfoBase.java new file mode 100644 index 000000000000..2529ca84d329 --- /dev/null +++ b/platform/platform-api/src/com/intellij/execution/filters/HyperlinkInfoBase.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.filters; + +import com.intellij.openapi.project.Project; +import com.intellij.ui.awt.RelativePoint; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author nik + */ +public abstract class HyperlinkInfoBase implements HyperlinkInfo { + public abstract void navigate(@NotNull Project project, @Nullable RelativePoint hyperlinkLocationPoint); + + @Override + public void navigate(Project project) { + navigate(project, null); + } +} diff --git a/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java b/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java index c0e0362f8642..25ca738635b3 100644 --- a/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java +++ b/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java @@ -18,6 +18,7 @@ package com.intellij.execution.impl; import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.FilterMixin; import com.intellij.execution.filters.HyperlinkInfo; +import com.intellij.execution.filters.HyperlinkInfoBase; import com.intellij.ide.OccurenceNavigator; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -36,6 +37,7 @@ import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.pom.NavigatableAdapter; +import com.intellij.ui.awt.RelativePoint; import com.intellij.util.BeforeAfter; import com.intellij.util.Consumer; import com.intellij.util.SmartList; @@ -87,7 +89,12 @@ public class EditorHyperlinkSupport { if (range != null) { final HyperlinkInfo info = myHighlighterToMessageInfoMap.get(range); if (info != null) { - info.navigate(project); + if (info instanceof HyperlinkInfoBase) { + ((HyperlinkInfoBase)info).navigate(project, new RelativePoint(mouseEvent)); + } + else { + info.navigate(project); + } linkFollowed(editor, getHyperlinks().keySet(), range); } } diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index e0082450dc10..65fd47d6baf1 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -44,6 +44,8 @@ +