public static void showNow() { if (ourInstance == null) { IdeFrame frame = EP.getExtensions().length == 0 ? new WelcomeFrame() : EP.getExtensions()[0].createFrame(); if (SystemInfo.isLinux) { ApplicationMenu.tryInstall(((JFrame) frame)); } ((JFrame) frame).setVisible(true); ourInstance = frame; } }
public static void showDialogAndAddLibraryToDependencies( final Library library, final Project project, boolean allowEmptySelection) { for (ProjectStructureValidator validator : EP_NAME.getExtensions()) { if (validator.addLibraryToDependencies(library, project, allowEmptySelection)) { return; } } final ModuleStructureConfigurable moduleStructureConfigurable = ModuleStructureConfigurable.getInstance(project); final List<Module> modules = LibraryEditingUtil.getSuitableModules( moduleStructureConfigurable, ((LibraryEx) library).getKind(), library); if (modules.isEmpty()) return; final ChooseModulesDialog dlg = new ChooseModulesDialog( moduleStructureConfigurable.getProject(), modules, ProjectBundle.message("choose.modules.dialog.title"), ProjectBundle.message("choose.modules.dialog.description", library.getName())); if (dlg.showAndGet()) { final List<Module> chosenModules = dlg.getChosenElements(); for (Module module : chosenModules) { moduleStructureConfigurable.addLibraryOrderEntry(module, library); } } }
/** * Base class and extension point for custom folding providers. * * @author Rustam Vishnyakov */ public abstract class CustomFoldingProvider { public static final ExtensionPointName<CustomFoldingProvider> EP_NAME = ExtensionPointName.create("com.intellij.customFoldingProvider"); public static CustomFoldingProvider[] getAllProviders() { return Extensions.getExtensions(EP_NAME); } public abstract boolean isCustomRegionStart(String elementText); public abstract boolean isCustomRegionEnd(String elementText); public abstract String getPlaceholderText(String elementText); /** @return A description string shown in "Surround With" action. */ public abstract String getDescription(); public abstract String getStartString(); public abstract String getEndString(); public boolean isCollapsedByDefault(String text) { return false; } }
/** @author Max Medvedev */ public abstract class CustomAnnotationChecker { public static final ExtensionPointName<CustomAnnotationChecker> EP_NAME = ExtensionPointName.create("org.intellij.groovy.customAnnotationChecker"); public boolean checkArgumentList( @NotNull AnnotationHolder holder, @NotNull GrAnnotation annotation) { return false; } public boolean checkApplicability( @NotNull AnnotationHolder holder, @NotNull GrAnnotation annotation) { return false; } @Nullable public static String isAnnotationApplicable( @NotNull GrAnnotation annotation, final PsiElement parent) { PsiElement owner = parent.getParent(); final PsiElement ownerToUse = parent instanceof PsiModifierList ? owner : parent; String[] elementTypeFields = GrAnnotationImpl.getApplicableElementTypeFields(ownerToUse); if (elementTypeFields != null && !GrAnnotationImpl.isAnnotationApplicableTo(annotation, false, elementTypeFields)) { final String annotationTargetText = JavaErrorMessages.message("annotation.target." + elementTypeFields[0]); GrCodeReferenceElement ref = annotation.getClassReference(); return JavaErrorMessages.message( "annotation.not.applicable", ref.getText(), annotationTargetText); } return null; } }
/** @author egor */ public abstract class JvmSteppingCommandProvider { public static final ExtensionPointName<JvmSteppingCommandProvider> EP_NAME = ExtensionPointName.create("com.intellij.debugger.jvmSteppingCommandProvider"); /** @return null if can not handle */ public DebugProcessImpl.ResumeCommand getStepIntoCommand( SuspendContextImpl suspendContext, boolean ignoreFilters, final MethodFilter smartStepFilter, int stepSize) { return null; } /** @return null if can not handle */ public DebugProcessImpl.ResumeCommand getStepOutCommand( SuspendContextImpl suspendContext, int stepSize) { return null; } /** @return null if can not handle */ public DebugProcessImpl.ResumeCommand getStepOverCommand( SuspendContextImpl suspendContext, boolean ignoreBreakpoints, int stepSize) { return null; } }
/** * Factory to instantiate {@link jetbrains.mps.openapi.editor.Editor editor} for a node. It's {@link * EditorOpenHandler} done right - no IOperationContext, and it doesn't open editors, it * instantiates (hence factory) component, and actual code to open an editor is platform's * responsibility. * * <p>Instances of the factory are registered with {@link #EXT_POINT} extension point, within * Project area (thus can access {@link com.intellij.openapi.project.Project} or {@link * jetbrains.mps.project.MPSProject} as constructor argument. * * <p>To avoid code breakage in the future MPS versions, do not implement this interface directly * (outside of MPS), rather subclass {@link NodeEditorFactoryBase}. * * @author Artem Tikhomirov * @since 3.4 */ public interface NodeEditorFactory { ExtensionPointName<NodeEditorFactory> EXT_POINT = ExtensionPointName.create("jetbrains.mps.NodeEditorFactory"); boolean canCreate(@NotNull Context context); @Nullable Editor create(@NotNull Context context); /** * This is dubious method with unclear contract. Used to carry "todo split into base node getter & * TabbedEditorHandler" comment Meanwhile is just a copy of {@link * EditorOpenHandler#getBaseNode(IOperationContext, SNode)}, without IOperationContext. */ SNode getBaseNode(@NotNull SNode aspect); /** * Set of parameters for the factory. At the moment, we don't need/pass anything but node, * interface introduced for ease of future extension. */ interface Context { @NotNull SNode getNode(); } }
/** * Allows to provide a custom list of keyword arguments for a function that uses **kwargs. * * @author yole */ public interface PyKeywordArgumentProvider { ExtensionPointName<PyKeywordArgumentProvider> EP_NAME = ExtensionPointName.create("Pythonid.keywordArgumentProvider"); @NotNull List<String> getKeywordArguments(PyFunction function, PyCallExpression callExpr); }
public interface TreeGenerator { ExtensionPointName<TreeGenerator> EP_NAME = ExtensionPointName.create("com.intellij.treeGenerator"); @Nullable TreeElement generateTreeFor(PsiElement original, CharTable table, final PsiManager manager); }
/** @author Eugene.Kudelevsky */ public interface AndroidRefactoringContextProvider { ExtensionPointName<AndroidRefactoringContextProvider> EP_NAME = ExtensionPointName.create("org.jetbrains.android.refactoringContextProvider"); @Nullable XmlTag getComponentTag(@NotNull DataContext dataContext); }
/** * Provides {@link com.intellij.execution.ExecutionTarget ExecutionTargets} for run configurations. */ public abstract class ExecutionTargetProvider { public static final ExtensionPointName<ExecutionTargetProvider> EXTENSION_NAME = ExtensionPointName.create("com.intellij.executionTargetProvider"); @NotNull public abstract List<ExecutionTarget> getTargets( @NotNull Project project, @NotNull RunnerAndConfigurationSettings configuration); }
/** * Named component which provides a configuration user interface. * * <p> * * <p>Use {@code com.intellij.projectConfigurable} and {@code com.intellij.applicationConfigurable} * extensions to provide items for "Project Settings" and "IDE Settings" groups correspondingly in * the "Settings" dialog. There are two ways to declare such extension: * * <ul> * <li>an extension element with 'instance' attribute <br> * <extensions defaultExtensionNs="com.intellij"><br> * <projectConfigurable instance="class-name"/><br> * </extensions><br> * where 'class-name' implements {@link Configurable} means that a new instance of the * specified class will be created each time when the dialog is opened. * <p> * <li>an extension with 'provider' attribute<br> * <extensions defaultExtensionNs="com.intellij"><br> * <projectConfigurable provider="class-name"/><br> * </extensions><br> * where 'class-name' implements {@link ConfigurableProvider} means that method {@link * ConfigurableProvider#createConfigurable()} will be used to create instance each time when * the dialog is opened. * </ul> * * @see SearchableConfigurable */ public interface Configurable extends UnnamedConfigurable { ExtensionPointName<ConfigurableEP<Configurable>> APPLICATION_CONFIGURABLE = ExtensionPointName.create("com.intellij.applicationConfigurable"); ExtensionPointName<ConfigurableEP<Configurable>> PROJECT_CONFIGURABLE = ExtensionPointName.create("com.intellij.projectConfigurable"); /** * Returns the user-visible name of the settings component. * * @return the visible name of the component. */ @Nls String getDisplayName(); /** * Returns the topic in the help file which is shown when help for the configurable is requested. * * @return the help topic, or null if no help is available. */ @Nullable @NonNls String getHelpTopic(); /** * @deprecated this marker interface was used to hide a Configurable declared as * applicationConfigurable or projectConfigurable extension from the Settings dialog. However * it makes no sense to register a Configurable as extension if you don't want to see it in * the Settings dialog */ interface Assistant extends Configurable {} interface Composite { Configurable[] getConfigurables(); } /** * Forbids wrapping the content of the configurable in a scroll pane. Required when the * configurable contains its own scrollable components. */ interface NoScroll {} /** Forbids setting an empty border to the content of the configurable. */ interface NoMargin {} }
/** @author Vladislav.Kaznacheev */ public abstract class ProjectImportBuilder<T> extends ProjectBuilder { public static final ExtensionPointName<ProjectImportBuilder> EXTENSIONS_POINT_NAME = ExtensionPointName.create("com.intellij.projectImportBuilder"); private boolean myUpdate; private String myFileToImport; @NotNull public abstract String getName(); public abstract Icon getIcon(); public abstract List<T> getList(); public abstract boolean isMarked(final T element); public abstract void setList(List<T> list) throws ConfigurationException; public abstract void setOpenProjectSettingsAfter(boolean on); @Override public List<Module> commit( @NotNull Project project, ModifiableModuleModel model, ModulesProvider modulesProvider) { return commit(project, model, modulesProvider, null); } @Nullable public abstract List<Module> commit( Project project, ModifiableModuleModel model, ModulesProvider modulesProvider, ModifiableArtifactModel artifactModel); public void setFileToImport(String path) { myFileToImport = path; } public String getFileToImport() { return myFileToImport; } @Nullable public static Project getCurrentProject() { return CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext()); } protected String getTitle() { return IdeBundle.message("project.import.wizard.title", getName()); } public boolean isUpdate() { return myUpdate; } public void setUpdate(final boolean update) { myUpdate = update; } }
@Nullable public static MvcFramework findCommonPluginModuleFramework(Module module) { for (MvcFramework framework : EP_NAME.getExtensions()) { if (framework.isCommonPluginsModule(module)) { return framework; } } return null; }
@Nullable public static MvcFramework getInstanceBySdk(@NotNull Module module) { for (final MvcFramework framework : EP_NAME.getExtensions()) { if (framework.getSdkRoot(module) != null) { return framework; } } return null; }
/** * IntelliJ external systems integration is built using GoF Bridge pattern, i.e. 'external-system' * module defines external system-specific extension (current interface) and an api which is used by * all extensions. Most of the codebase is built on top of that api and provides generic actions * like 'sync ide project with external project'; 'import library dependencies which are configured * at external system but not at the ide' etc. * * <p>That makes it relatively easy to add a new external system integration. * * @author Denis Zhdanov * @since 4/4/13 4:05 PM */ public interface ExternalSystemManager< ProjectSettings extends ExternalProjectSettings, SettingsListener extends ExternalSystemSettingsListener<ProjectSettings>, Settings extends AbstractExternalSystemSettings<ProjectSettings, SettingsListener>, LocalSettings extends AbstractExternalSystemLocalSettings, ExecutionSettings extends ExternalSystemExecutionSettings> extends ParametersEnhancer { ExtensionPointName<ExternalSystemManager> EP_NAME = ExtensionPointName.create("com.intellij.externalSystemManager"); /** @return id of the external system represented by the current manager */ @NotNull ProjectSystemId getSystemId(); /** * @return a strategy which can be queried for external system settings to use with the given * project */ @NotNull Function<Project, Settings> getSettingsProvider(); /** * @return a strategy which can be queried for external system local settings to use with the * given project */ @NotNull Function<Project, LocalSettings> getLocalSettingsProvider(); /** * @return a strategy which can be queried for external system execution settings to use with the * given project */ @NotNull Function<Pair<Project, String /*linked project path*/>, ExecutionSettings> getExecutionSettingsProvider(); /** * Allows to retrieve information about {@link ExternalSystemProjectResolver project resolver} to * use for the target external system. * * <p><b>Note:</b> we return a class instance instead of resolver object here because there is a * possible case that the resolver is used at external (non-ide) process, so, it needs information * which is enough for instantiating it there. That implies the requirement that target resolver * class is expected to have a no-args constructor * * @return class of the project resolver to use for the target external system */ @NotNull Class<? extends ExternalSystemProjectResolver<ExecutionSettings>> getProjectResolverClass(); /** * @return class of the build manager to use for the target external system * @see #getProjectResolverClass() */ Class<? extends ExternalSystemBuildManager<ExecutionSettings>> getBuildManagerClass(); }
public static List<RenamePsiElementProcessor> allForElement(@NotNull PsiElement element) { final List<RenamePsiElementProcessor> result = new ArrayList<>(); for (RenamePsiElementProcessor processor : EP_NAME.getExtensions()) { if (processor.canProcessElement(element)) { result.add(processor); } } return result; }
public static void check( ProjectStructureElement element, ProjectStructureProblemsHolder problemsHolder) { for (ProjectStructureValidator validator : EP_NAME.getExtensions()) { if (validator.checkElement(element, problemsHolder)) { return; } } element.check(problemsHolder); }
/** @author yole */ public abstract class FindUsagesHandlerFactory { public static final ExtensionPointName<FindUsagesHandlerFactory> EP_NAME = ExtensionPointName.create("com.intellij.findUsagesHandlerFactory"); public abstract boolean canFindUsages(PsiElement element); @Nullable public abstract FindUsagesHandler createFindUsagesHandler( PsiElement element, final boolean forHighlightUsages); }
/** User: anna Date: Jan 30, 2005 */ public abstract class ProductivityFeaturesProvider { public static ExtensionPointName<ProductivityFeaturesProvider> EP_NAME = ExtensionPointName.create("com.intellij.productivityFeaturesProvider"); public abstract FeatureDescriptor[] getFeatureDescriptors(); public abstract GroupDescriptor[] getGroupDescriptors(); public abstract ApplicabilityFilter[] getApplicabilityFilters(); }
public static List<ProjectStructureElementUsage> getUsagesInElement( final ProjectStructureElement element) { for (ProjectStructureValidator validator : EP_NAME.getExtensions()) { List<ProjectStructureElementUsage> usages = validator.getUsagesIn(element); if (usages != null) { return usages; } } return element.getUsagesInElement(); }
/** * Finds extensions supporting the given <code>schemeClass</code> * * @param schemeClass The class of the scheme to search extensions for. * @return A collection of importers capable of importing schemes of the given class. An empty * collection is returned if there are no matching importers. */ @NotNull public static <S extends Scheme> Collection<SchemeImporterEP<S>> getExtensions( Class<S> schemeClass) { List<SchemeImporterEP<S>> importers = new ArrayList<SchemeImporterEP<S>>(); for (SchemeImporterEP<?> importerEP : EP_NAME.getExtensions()) { if (schemeClass.getName().equals(importerEP.schemeClass)) { //noinspection unchecked importers.add((SchemeImporterEP<S>) importerEP); } } return importers; }
public static List<MavenImporter> getSuitableImporters(MavenProject p) { List<MavenImporter> result = null; Set<ModuleType> moduleTypes = null; for (MavenImporter importer : EXTENSION_POINT_NAME.getExtensions()) { if (importer.isApplicable(p)) { if (result == null) { result = new ArrayList<MavenImporter>(); moduleTypes = new THashSet<ModuleType>(); } result.add(importer); moduleTypes.add(importer.getModuleType()); } } if (result == null) { return Collections.emptyList(); } if (moduleTypes.size() <= 1) { return result; } // This code is reached when several importers say that they are applicable but they want to // have different module types. // Now we select one module type and return only those importers that are ok with it. // If possible - return at least one importer that explicitly supports packaging of the given // maven project. ModuleType moduleType = result.get(0).getModuleType(); List<String> supportedPackagings = new ArrayList<String>(); for (MavenImporter importer : result) { supportedPackagings.clear(); importer.getSupportedPackagings(supportedPackagings); if (supportedPackagings.contains(p.getPackaging())) { moduleType = importer.getModuleType(); break; } } final ModuleType finalModuleType = moduleType; return ContainerUtil.filter( result, new Condition<MavenImporter>() { public boolean value(final MavenImporter importer) { return importer.getModuleType() == finalModuleType; } }); }
private static void ensureInit() { if (ourClassSpecifiedContributors != null) return; MultiMap<String, NonCodeMembersContributor> contributorMap = new MultiMap<String, NonCodeMembersContributor>(); for (final NonCodeMembersContributor contributor : EP_NAME.getExtensions()) { contributorMap.putValue(contributor.getParentClassName(), contributor); } Collection<NonCodeMembersContributor> allTypeContributors = contributorMap.remove(null); ourAllTypeContributors = allTypeContributors.toArray(new NonCodeMembersContributor[allTypeContributors.size()]); ourClassSpecifiedContributors = contributorMap; }
public static <T> void registerExtension( final ExtensionsArea area, final ExtensionPointName<T> name, final T t, final Disposable parentDisposable) { final ExtensionPoint<T> extensionPoint = area.getExtensionPoint(name.getName()); extensionPoint.registerExtension(t); Disposer.register( parentDisposable, new Disposable() { @Override public void dispose() { extensionPoint.unregisterExtension(t); } }); }
/** * Implement this class to provide settings page for debugger. Settings page will be placed under * 'Debugger' node in the 'Settings' dialog. An implementation should be registered in plugin.xml: * * <p><extensions defaultExtensionNs="com.intellij"><br> * <xdebugger.settings implementation="qualified-class-name"/><br> * </extensions> * * @author nik */ public abstract class XDebuggerSettings<T> implements PersistentStateComponent<T> { public static final ExtensionPointName<XDebuggerSettings> EXTENSION_POINT = ExtensionPointName.create("com.intellij.xdebugger.settings"); private final String myId; protected XDebuggerSettings(final @NotNull @NonNls String id) { myId = id; } protected static <S extends XDebuggerSettings<?>> S getInstance(Class<S> aClass) { return XDebuggerUtil.getInstance().getDebuggerSettings(aClass); } public final String getId() { return myId; } @NotNull public abstract Configurable createConfigurable(); }
/** @author peter */ public class DomExtenderEP extends AbstractExtensionPointBean { private static final Logger LOG = Logger.getInstance("#com.intellij.util.xml.reflect.DomExtenderEP"); public static final ExtensionPointName<DomExtenderEP> EP_NAME = ExtensionPointName.create("com.intellij.dom.extender"); @Attribute("domClass") public String domClassName; @Attribute("extenderClass") public String extenderClassName; private Class<?> myDomClass; private DomExtender myExtender; @Nullable public DomExtensionsRegistrarImpl extend( @NotNull final Project project, @NotNull final DomInvocationHandler handler, @Nullable DomExtensionsRegistrarImpl registrar) { if (myExtender == null) { try { myDomClass = findClass(domClassName); myExtender = instantiate(extenderClassName, project.getPicoContainer()); } catch (Exception e) { LOG.error(e); return null; } } if (myDomClass.isAssignableFrom(handler.getRawType())) { if (!myExtender.supportsStubs() && XmlUtil.isStubBuilding()) return registrar; if (registrar == null) { registrar = new DomExtensionsRegistrarImpl(); } //noinspection unchecked myExtender.registerExtensions(handler.getProxy(), registrar); } return registrar; } }
private void notifyCheckoutListeners( final File directory, final ExtensionPointName<CheckoutListener> epName) { final CheckoutListener[] listeners = Extensions.getExtensions(epName); for (CheckoutListener listener : listeners) { myFoundProject = listener.processCheckedOutDirectory(myProject, directory); if (myFoundProject) break; } if (!myFoundProject && !epName.equals(CheckoutListener.COMPLETED_EP_NAME)) { final VcsAwareCheckoutListener[] vcsAwareExtensions = Extensions.getExtensions(VcsAwareCheckoutListener.EP_NAME); for (VcsAwareCheckoutListener extension : vcsAwareExtensions) { myFoundProject = extension.processCheckedOutDirectory(myProject, directory, myVcsKey); if (myFoundProject) break; } } final Project[] openProjects = ProjectManager.getInstance().getOpenProjects(); if (openProjects.length > 0) { final Project lastOpenedProject = openProjects[openProjects.length - 1]; for (CheckoutListener listener : listeners) { listener.processOpenedProject(lastOpenedProject); } } }
/** @author Rustam Vishnyakov */ public class SchemeImporterEP<S extends Scheme> extends AbstractExtensionPointBean { public static ExtensionPointName<SchemeImporterEP> EP_NAME = ExtensionPointName.create("com.intellij.schemeImporter"); @Attribute("name") public String name; @Attribute("schemeClass") public String schemeClass; @Attribute("implementationClass") public String implementationClass; private final LazyInstance<SchemeImporter<S>> myImporterInstance = new LazyInstance<SchemeImporter<S>>() { @Override protected Class<SchemeImporter<S>> getInstanceClass() throws ClassNotFoundException { return findClass(implementationClass); } }; public SchemeImporter<S> getInstance() { return myImporterInstance.getValue(); } /** * Finds extensions supporting the given <code>schemeClass</code> * * @param schemeClass The class of the scheme to search extensions for. * @return A collection of importers capable of importing schemes of the given class. An empty * collection is returned if there are no matching importers. */ @NotNull public static <S extends Scheme> Collection<SchemeImporterEP<S>> getExtensions( Class<S> schemeClass) { List<SchemeImporterEP<S>> importers = new ArrayList<SchemeImporterEP<S>>(); for (SchemeImporterEP<?> importerEP : EP_NAME.getExtensions()) { if (schemeClass.getName().equals(importerEP.schemeClass)) { //noinspection unchecked importers.add((SchemeImporterEP<S>) importerEP); } } return importers; } /** * Find an importer for the given name and scheme class. It is allowed for importers to have the * same name but different scheme classes. * * @param name The importer name as defined in plug-in configuration. * @param schemeClass The scheme class the importer has to support. * @return The found importer or null if there are no importers for the given name and scheme * class. */ @Nullable public static <S extends Scheme> SchemeImporter<S> getImporter( @NotNull String name, Class<S> schemeClass) { for (SchemeImporterEP<S> importerEP : getExtensions(schemeClass)) { if (name.equals(importerEP.name)) { return importerEP.getInstance(); } } return null; } }
class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable { private static final ExtensionPointName<ChangeLocalityDetector> EP_NAME = ExtensionPointName.create("com.intellij.daemon.changeLocalityDetector"); private /*NOT STATIC!!!*/ final Key<Boolean> UPDATE_ON_COMMIT_ENGAGED = Key.create("UPDATE_ON_COMMIT_ENGAGED"); private final Project myProject; private final Map<Document, List<Pair<PsiElement, Boolean>>> changedElements = new WeakHashMap<>(); private final FileStatusMap myFileStatusMap; PsiChangeHandler( @NotNull Project project, @NotNull final PsiDocumentManagerImpl documentManager, @NotNull EditorFactory editorFactory, @NotNull MessageBusConnection connection, @NotNull FileStatusMap fileStatusMap) { myProject = project; myFileStatusMap = fileStatusMap; editorFactory .getEventMulticaster() .addDocumentListener( new DocumentAdapter() { @Override public void beforeDocumentChange(DocumentEvent e) { final Document document = e.getDocument(); if (documentManager.getSynchronizer().isInSynchronization(document)) return; if (documentManager.getCachedPsiFile(document) == null) return; if (document.getUserData(UPDATE_ON_COMMIT_ENGAGED) == null) { document.putUserData(UPDATE_ON_COMMIT_ENGAGED, Boolean.TRUE); PsiDocumentManagerBase.addRunOnCommit( document, () -> { if (document.getUserData(UPDATE_ON_COMMIT_ENGAGED) != null) { updateChangesForDocument(document); document.putUserData(UPDATE_ON_COMMIT_ENGAGED, null); } }); } } }, this); connection.subscribe( PsiDocumentTransactionListener.TOPIC, new PsiDocumentTransactionListener() { @Override public void transactionStarted( @NotNull final Document doc, @NotNull final PsiFile file) {} @Override public void transactionCompleted( @NotNull final Document document, @NotNull final PsiFile file) { updateChangesForDocument(document); document.putUserData( UPDATE_ON_COMMIT_ENGAGED, null); // ensure we don't call updateChangesForDocument() twice which can lead to // whole file re-highlight } }); } @Override public void dispose() {} private void updateChangesForDocument(@NotNull final Document document) { ApplicationManager.getApplication().assertIsDispatchThread(); if (DaemonListeners.isUnderIgnoredAction(null) || myProject.isDisposed()) return; List<Pair<PsiElement, Boolean>> toUpdate = changedElements.get(document); if (toUpdate == null) { // The document has been changed, but psi hasn't // We may still need to rehighlight the file if there were changes inside highlighted ranges. if (UpdateHighlightersUtil.isWhitespaceOptimizationAllowed(document)) return; // don't create PSI for files in other projects PsiElement file = PsiDocumentManager.getInstance(myProject).getCachedPsiFile(document); if (file == null) return; toUpdate = Collections.singletonList(Pair.create(file, true)); } Application application = ApplicationManager.getApplication(); final Editor editor = FileEditorManager.getInstance(myProject).getSelectedTextEditor(); if (editor != null && !application.isUnitTestMode()) { application.invokeLater( () -> { if (!editor.isDisposed()) { EditorMarkupModel markupModel = (EditorMarkupModel) editor.getMarkupModel(); PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument()); TrafficLightRenderer.setOrRefreshErrorStripeRenderer( markupModel, myProject, editor.getDocument(), file); } }, ModalityState.stateForComponent(editor.getComponent()), myProject.getDisposed()); } for (Pair<PsiElement, Boolean> changedElement : toUpdate) { PsiElement element = changedElement.getFirst(); Boolean whiteSpaceOptimizationAllowed = changedElement.getSecond(); updateByChange(element, document, whiteSpaceOptimizationAllowed); } changedElements.remove(document); } @Override public void childAdded(@NotNull PsiTreeChangeEvent event) { queueElement(event.getParent(), true, event); } @Override public void childRemoved(@NotNull PsiTreeChangeEvent event) { queueElement(event.getParent(), true, event); } @Override public void childReplaced(@NotNull PsiTreeChangeEvent event) { queueElement(event.getNewChild(), typesEqual(event.getNewChild(), event.getOldChild()), event); } private static boolean typesEqual(final PsiElement newChild, final PsiElement oldChild) { return newChild != null && oldChild != null && newChild.getClass() == oldChild.getClass(); } @Override public void childrenChanged(@NotNull PsiTreeChangeEvent event) { if (((PsiTreeChangeEventImpl) event).isGenericChange()) { return; } queueElement(event.getParent(), true, event); } @Override public void beforeChildMovement(@NotNull PsiTreeChangeEvent event) { queueElement(event.getOldParent(), true, event); queueElement(event.getNewParent(), true, event); } @Override public void beforeChildrenChange(@NotNull PsiTreeChangeEvent event) { // this event sent always before every PSI change, even not significant one (like after quick // typing/backspacing char) // mark file dirty just in case PsiFile psiFile = event.getFile(); if (psiFile != null) { myFileStatusMap.markFileScopeDirtyDefensively(psiFile, event); } } @Override public void propertyChanged(@NotNull PsiTreeChangeEvent event) { String propertyName = event.getPropertyName(); if (!propertyName.equals(PsiTreeChangeEvent.PROP_WRITABLE)) { Object oldValue = event.getOldValue(); if (oldValue instanceof VirtualFile && shouldBeIgnored((VirtualFile) oldValue)) { // ignore workspace.xml return; } myFileStatusMap.markAllFilesDirty(event); } } private void queueElement( @NotNull PsiElement child, final boolean whitespaceOptimizationAllowed, @NotNull PsiTreeChangeEvent event) { ApplicationManager.getApplication().assertIsDispatchThread(); PsiFile file = event.getFile(); if (file == null) file = child.getContainingFile(); if (file == null) { myFileStatusMap.markAllFilesDirty(child); return; } if (!child.isValid()) return; PsiDocumentManagerImpl pdm = (PsiDocumentManagerImpl) PsiDocumentManager.getInstance(myProject); Document document = pdm.getCachedDocument(file); if (document != null) { if (pdm.getSynchronizer().getTransaction(document) == null) { // content reload, language level change or some other big change myFileStatusMap.markAllFilesDirty(child); return; } List<Pair<PsiElement, Boolean>> toUpdate = changedElements.get(document); if (toUpdate == null) { toUpdate = new SmartList<>(); changedElements.put(document, toUpdate); } toUpdate.add(Pair.create(child, whitespaceOptimizationAllowed)); } } private void updateByChange( @NotNull PsiElement child, @NotNull final Document document, final boolean whitespaceOptimizationAllowed) { ApplicationManager.getApplication().assertIsDispatchThread(); final PsiFile file; try { file = child.getContainingFile(); } catch (PsiInvalidElementAccessException e) { myFileStatusMap.markAllFilesDirty(e); return; } if (file == null || file instanceof PsiCompiledElement) { myFileStatusMap.markAllFilesDirty(child); return; } VirtualFile virtualFile = file.getVirtualFile(); if (virtualFile != null && shouldBeIgnored(virtualFile)) { // ignore workspace.xml return; } int fileLength = file.getTextLength(); if (!file.getViewProvider().isPhysical()) { myFileStatusMap.markFileScopeDirty( document, new TextRange(0, fileLength), fileLength, "Non-physical file update: " + file); return; } PsiElement element = whitespaceOptimizationAllowed && UpdateHighlightersUtil.isWhitespaceOptimizationAllowed(document) ? child : child.getParent(); while (true) { if (element == null || element instanceof PsiFile || element instanceof PsiDirectory) { myFileStatusMap.markAllFilesDirty("Top element: " + element); return; } final PsiElement scope = getChangeHighlightingScope(element); if (scope != null) { myFileStatusMap.markFileScopeDirty( document, scope.getTextRange(), fileLength, "Scope: " + scope); return; } element = element.getParent(); } } private boolean shouldBeIgnored(@NotNull VirtualFile virtualFile) { return ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile) || ProjectRootManager.getInstance(myProject).getFileIndex().isExcluded(virtualFile); } @Nullable private static PsiElement getChangeHighlightingScope(@NotNull PsiElement element) { DefaultChangeLocalityDetector defaultDetector = null; for (ChangeLocalityDetector detector : Extensions.getExtensions(EP_NAME)) { if (detector instanceof DefaultChangeLocalityDetector) { // run default detector last assert defaultDetector == null : defaultDetector; defaultDetector = (DefaultChangeLocalityDetector) detector; continue; } final PsiElement scope = detector.getChangeHighlightingDirtyScopeFor(element); if (scope != null) return scope; } assert defaultDetector != null : "com.intellij.codeInsight.daemon.impl.DefaultChangeLocalityDetector is unregistered"; return defaultDetector.getChangeHighlightingDirtyScopeFor(element); } }
/** @author peter */ @Deprecated // TODO [VISTALL] rewrit it using ModuleExtensions public abstract class MvcFramework { protected static final ExtensionPointName<MvcFramework> EP_NAME = ExtensionPointName.create("org.intellij.groovy.mvc.framework"); private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.mvc.MvcFramework"); public static final Key<Boolean> CREATE_APP_STRUCTURE = Key.create("CREATE_MVC_APP_STRUCTURE"); public static final Key<Boolean> UPGRADE = Key.create("UPGRADE"); @NonNls public static final String GROOVY_STARTER_CONF = "/conf/groovy-starter.conf"; @NonNls public static final String XMX_JVM_PARAMETER = "-Xmx"; public abstract boolean hasSupport(@NotNull Module module); public boolean isAuxModule(@NotNull Module module) { return isCommonPluginsModule(module) || isGlobalPluginModule(module); } public boolean hasFrameworkJar(@NotNull Module module) { GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false); return JavaPsiFacade.getInstance(module.getProject()).findClass(getSomeFrameworkClass(), scope) != null; } public boolean isCommonPluginsModule(@NotNull Module module) { return module.getName().endsWith(getCommonPluginSuffix()); } public List<Module> reorderModulesForMvcView(List<Module> modules) { return modules; } public abstract String getApplicationDirectoryName(); public void syncSdkAndLibrariesInPluginsModule(@NotNull Module module) { final Module pluginsModule = findCommonPluginsModule(module); if (pluginsModule != null) { MvcModuleStructureUtil.syncAuxModuleSdk(module, pluginsModule, this); } } public boolean isInteractiveConsoleSupported(@NotNull Module module) { return false; } public void runInteractiveConsole(@NotNull Module module) { throw new UnsupportedOperationException(); } public abstract void upgradeFramework(@NotNull Module module); public void createApplicationIfNeeded(@NotNull final Module module) { if (findAppRoot(module) == null && module.getUserData(CREATE_APP_STRUCTURE) == Boolean.TRUE) { while (ModuleUtilCore.getSdk(module, JavaModuleExtensionImpl.class) == null) { if (Messages.showYesNoDialog( module.getProject(), "Cannot generate " + getDisplayName() + " project structure because JDK is not specified for module \"" + module.getName() + "\".\n" + getDisplayName() + " project will not be created if you don't specify JDK.\nDo you want to specify JDK?", "Error", Messages.getErrorIcon()) == 1) { return; } ProjectSettingsService.getInstance(module.getProject()) .showModuleConfigurationDialog(module.getName(), ClasspathEditor.NAME); } module.putUserData(CREATE_APP_STRUCTURE, null); final GeneralCommandLine commandLine = getCreationCommandLine(module); if (commandLine == null) return; MvcConsole.executeProcess( module, commandLine, new Runnable() { public void run() { VirtualFile root = findAppRoot(module); if (root == null) return; PsiDirectory psiDir = PsiManager.getInstance(module.getProject()).findDirectory(root); IdeView ide = LangDataKeys.IDE_VIEW.getData(DataManager.getInstance().getDataContext()); if (ide != null) ide.selectElement(psiDir); // also here comes fileCreated(application.properties) which manages roots and run // configuration } }, true); } } @Nullable protected GeneralCommandLine getCreationCommandLine(Module module) { String message = "Create default " + getDisplayName() + " directory structure in module '" + module.getName() + "'?"; final int result = Messages.showDialog( module.getProject(), message, "Create " + getDisplayName() + " application", new String[] {"Run 'create-&app'", "Run 'create-&plugin'", "&Cancel"}, 0, getIcon()); if (result < 0 || result > 1) { return null; } return createCommandAndShowErrors( null, module, true, new MvcCommand(result == 0 ? "create-app" : "create-plugin")); } public abstract void updateProjectStructure(@NotNull final Module module); public abstract void ensureRunConfigurationExists(@NotNull Module module); @Nullable public VirtualFile findAppRoot(@Nullable Module module) { if (module == null) return null; String appDirName = getApplicationDirectoryName(); for (VirtualFile root : ModuleRootManager.getInstance(module).getContentRoots()) { if (root.findChild(appDirName) != null) return root; } return null; } @Nullable public VirtualFile findAppRoot(@Nullable PsiElement element) { VirtualFile appDirectory = findAppDirectory(element); return appDirectory == null ? null : appDirectory.getParent(); } @Nullable public VirtualFile findAppDirectory(@Nullable Module module) { if (module == null) return null; String appDirName = getApplicationDirectoryName(); for (VirtualFile root : ModuleRootManager.getInstance(module).getContentRoots()) { VirtualFile res = root.findChild(appDirName); if (res != null) return res; } return null; } @Nullable public VirtualFile findAppDirectory(@Nullable PsiElement element) { if (element == null) return null; PsiFile containingFile = element.getContainingFile().getOriginalFile(); VirtualFile file = containingFile.getVirtualFile(); if (file == null) return null; ProjectFileIndex index = ProjectRootManager.getInstance(containingFile.getProject()).getFileIndex(); VirtualFile root = index.getContentRootForFile(file); if (root == null) return null; return root.findChild(getApplicationDirectoryName()); } @Nullable public abstract VirtualFile getSdkRoot(@Nullable Module module); public abstract String getUserLibraryName(); protected List<File> getImplicitClasspathRoots(@NotNull Module module) { final List<File> toExclude = new ArrayList<File>(); VirtualFile sdkRoot = getSdkRoot(module); if (sdkRoot != null) toExclude.add(VfsUtil.virtualToIoFile(sdkRoot)); ContainerUtil.addIfNotNull(getCommonPluginsDir(module), toExclude); final VirtualFile appRoot = findAppRoot(module); if (appRoot != null) { VirtualFile pluginDir = appRoot.findChild(MvcModuleStructureUtil.PLUGINS_DIRECTORY); if (pluginDir != null) toExclude.add(VfsUtil.virtualToIoFile(pluginDir)); VirtualFile libDir = appRoot.findChild("lib"); if (libDir != null) toExclude.add(VfsUtil.virtualToIoFile(libDir)); } final Library library = MvcModuleStructureUtil.findUserLibrary(module, getUserLibraryName()); if (library != null) { for (VirtualFile file : library.getFiles(OrderRootType.CLASSES)) { toExclude.add(VfsUtil.virtualToIoFile(PathUtil.getLocalFile(file))); } } return toExclude; } private PathsList removeFrameworkStuff(Module module, List<VirtualFile> rootFiles) { final List<File> toExclude = getImplicitClasspathRoots(module); if (LOG.isDebugEnabled()) { LOG.debug("Before removing framework stuff: " + rootFiles); LOG.debug("Implicit roots:" + toExclude); } PathsList scriptClassPath = new PathsList(); eachRoot: for (VirtualFile file : rootFiles) { for (final File excluded : toExclude) { if (VfsUtil.isAncestor(excluded, VfsUtil.virtualToIoFile(file), false)) { continue eachRoot; } } scriptClassPath.add(file); } return scriptClassPath; } public PathsList getApplicationClassPath(Module module) { final List<VirtualFile> classPath = OrderEnumerator.orderEntries(module) .recursively() .withoutSdk() .getPathsList() .getVirtualFiles(); retainOnlyJarsAndDirectories(classPath); removeModuleOutput(module, classPath); final Module pluginsModule = findCommonPluginsModule(module); if (pluginsModule != null) { removeModuleOutput(pluginsModule, classPath); } return removeFrameworkStuff(module, classPath); } public abstract boolean updatesWholeProject(); private static void retainOnlyJarsAndDirectories(List<VirtualFile> woSdk) { for (Iterator<VirtualFile> iterator = woSdk.iterator(); iterator.hasNext(); ) { VirtualFile file = iterator.next(); final VirtualFile local = ArchiveVfsUtil.getVirtualFileForJar(file); final boolean dir = file.isDirectory(); final String name = file.getName(); if (LOG.isDebugEnabled()) { LOG.debug( "Considering: " + file.getPath() + "; local=" + local + "; dir=" + dir + "; name=" + name); } if (dir || local != null) { continue; } if (name.endsWith(".jar")) { continue; } LOG.debug("Removing"); iterator.remove(); } } private static void removeModuleOutput(Module module, List<VirtualFile> from) { CompilerPathsManager compilerPathsManager = CompilerPathsManager.getInstance(module.getProject()); for (ContentFolderType contentFolderType : ContentFolderType.ALL_SOURCE_ROOTS) { from.remove(compilerPathsManager.getCompilerOutput(module, contentFolderType)); } } public abstract JavaParameters createJavaParameters( @NotNull Module module, boolean forCreation, boolean forTests, boolean classpathFromDependencies, @Nullable String jvmParams, @NotNull MvcCommand command) throws ExecutionException; protected static void ensureRunConfigurationExists( Module module, ConfigurationType configurationType, String name) { final RunManagerEx runManager = RunManagerEx.getInstanceEx(module.getProject()); for (final RunConfiguration runConfiguration : runManager.getConfigurations(configurationType)) { if (runConfiguration instanceof MvcRunConfiguration && ((MvcRunConfiguration) runConfiguration).getModule() == module) { return; } } final ConfigurationFactory factory = configurationType.getConfigurationFactories()[0]; final RunnerAndConfigurationSettings runSettings = runManager.createRunConfiguration(name, factory); final MvcRunConfiguration configuration = (MvcRunConfiguration) runSettings.getConfiguration(); configuration.setModule(module); runManager.addConfiguration(runSettings, false); runManager.setActiveConfiguration(runSettings); RunManagerEx.disableTasks( module.getProject(), configuration, CompileStepBeforeRun.ID, CompileStepBeforeRunNoErrorCheck.ID); } public abstract String getFrameworkName(); public String getDisplayName() { return getFrameworkName(); } public abstract Icon getIcon(); // 16*16 public abstract Icon getToolWindowIcon(); // 13*13 public abstract String getSdkHomePropertyName(); @Nullable public GeneralCommandLine createCommandAndShowErrors( @NotNull Module module, @NotNull String command, String... args) { return createCommandAndShowErrors(null, module, new MvcCommand(command, args)); } @Nullable public GeneralCommandLine createCommandAndShowErrors( @NotNull Module module, @NotNull MvcCommand command) { return createCommandAndShowErrors(null, module, command); } @Nullable public GeneralCommandLine createCommandAndShowErrors( @Nullable String vmOptions, @NotNull Module module, @NotNull MvcCommand command) { return createCommandAndShowErrors(vmOptions, module, false, command); } @Nullable public GeneralCommandLine createCommandAndShowErrors( @Nullable String vmOptions, @NotNull Module module, final boolean forCreation, @NotNull MvcCommand command) { try { return createCommand(module, vmOptions, forCreation, command); } catch (ExecutionException e) { Messages.showErrorDialog(e.getMessage(), "Failed to run grails command: " + command); return null; } } @NotNull public GeneralCommandLine createCommand( @NotNull Module module, @Nullable String jvmParams, boolean forCreation, @NotNull MvcCommand command) throws ExecutionException { final JavaParameters params = createJavaParameters(module, forCreation, false, true, jvmParams, command); addJavaHome(params, module); final GeneralCommandLine commandLine = createCommandLine(params); final VirtualFile griffonHome = getSdkRoot(module); if (griffonHome != null) { commandLine .getEnvironment() .put(getSdkHomePropertyName(), FileUtil.toSystemDependentName(griffonHome.getPath())); } final VirtualFile root = findAppRoot(module); final File ioRoot = root != null ? VfsUtilCore.virtualToIoFile(root) : new File(module.getModuleDirPath()); commandLine.setWorkDirectory(forCreation ? ioRoot.getParentFile() : ioRoot); return commandLine; } public static void addJavaHome(@NotNull JavaParameters params, @NotNull Module module) { final Sdk sdk = ModuleUtilCore.getSdk(module, JavaModuleExtensionImpl.class); if (sdk != null && sdk.getSdkType() instanceof JavaSdkType) { String path = StringUtil.trimEnd(sdk.getHomePath(), File.separator); if (StringUtil.isNotEmpty(path)) { Map<String, String> env = params.getEnv(); if (env == null) { env = new HashMap<String, String>(); params.setEnv(env); } env.put("JAVA_HOME", FileUtil.toSystemDependentName(path)); } } } public static GeneralCommandLine createCommandLine(@NotNull JavaParameters params) throws CantRunException { return CommandLineBuilder.createFromJavaParameters(params); } private void extractPlugins( Project project, @Nullable VirtualFile pluginRoot, Map<String, VirtualFile> res) { if (pluginRoot != null) { VirtualFile[] children = pluginRoot.getChildren(); if (children != null) { for (VirtualFile child : children) { String pluginName = getInstalledPluginNameByPath(project, child); if (pluginName != null) { res.put(pluginName, child); } } } } } public Collection<VirtualFile> getAllPluginRoots(@NotNull Module module, boolean refresh) { return getCommonPluginRoots(module, refresh); } public void collectCommonPluginRoots( Map<String, VirtualFile> result, @NotNull Module module, boolean refresh) { if (isCommonPluginsModule(module)) { for (VirtualFile root : ModuleRootManager.getInstance(module).getContentRoots()) { String pluginName = getInstalledPluginNameByPath(module.getProject(), root); if (pluginName != null) { result.put(pluginName, root); } } } else { VirtualFile root = findAppRoot(module); if (root == null) return; extractPlugins( module.getProject(), root.findChild(MvcModuleStructureUtil.PLUGINS_DIRECTORY), result); extractPlugins( module.getProject(), MvcModuleStructureUtil.findFile(getCommonPluginsDir(module), refresh), result); extractPlugins( module.getProject(), MvcModuleStructureUtil.findFile(getGlobalPluginsDir(module), refresh), result); } } public Collection<VirtualFile> getCommonPluginRoots(@NotNull Module module, boolean refresh) { Map<String, VirtualFile> result = new HashMap<String, VirtualFile>(); collectCommonPluginRoots(result, module, refresh); return result.values(); } @Nullable public Module findCommonPluginsModule(@NotNull Module module) { return ModuleManager.getInstance(module.getProject()) .findModuleByName(getCommonPluginsModuleName(module)); } public boolean isGlobalPluginModule(@NotNull Module module) { return module.getName().startsWith(getGlobalPluginsModuleName()); } @Nullable public File getSdkWorkDir(@NotNull Module module) { return getDefaultSdkWorkDir(module); } @Nullable public abstract File getDefaultSdkWorkDir(@NotNull Module module); @Nullable public File getGlobalPluginsDir(@NotNull Module module) { final File sdkWorkDir = getSdkWorkDir(module); return sdkWorkDir == null ? null : new File(sdkWorkDir, "global-plugins"); } @Nullable public File getCommonPluginsDir(@NotNull Module module) { final File grailsWorkDir = getSdkWorkDir(module); if (grailsWorkDir == null) return null; final String applicationName = getApplicationName(module); if (applicationName == null) return null; return new File(grailsWorkDir, "projects/" + applicationName + "/plugins"); } public String getApplicationName(Module module) { final VirtualFile root = findAppRoot(module); if (root == null) return null; return root.getName(); } protected abstract String getCommonPluginSuffix(); public abstract String getGlobalPluginsModuleName(); public String getCommonPluginsModuleName(Module module) { return module.getName() + getCommonPluginSuffix(); } public abstract boolean isSDKLibrary(Library library); public abstract MvcProjectStructure createProjectStructure( @NotNull Module module, boolean auxModule); public abstract LibraryKind getLibraryKind(); public abstract String getSomeFrameworkClass(); public static void addAvailableSystemScripts( final Collection<String> result, @NotNull Module module) { VirtualFile scriptRoot = null; GlobalSearchScope searchScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false); for (PsiClass aClass : JavaPsiFacade.getInstance(module.getProject()).findClasses("CreateApp_", searchScope)) { PsiClass superClass = aClass.getSuperClass(); if (superClass != null && GroovyCommonClassNames.GROOVY_LANG_SCRIPT.equals(superClass.getQualifiedName())) { PsiFile psiFile = aClass.getContainingFile(); if (psiFile != null) { VirtualFile file = psiFile.getVirtualFile(); if (file != null && file.getFileSystem() instanceof ArchiveFileSystem) { VirtualFile parent = file.getParent(); if (parent != null && parent.findChild("Console.class") != null) { scriptRoot = parent; break; } } } } } if (scriptRoot == null) return; Pattern scriptPattern = Pattern.compile("([A-Za-z0-9]+)_?\\.class"); for (VirtualFile file : scriptRoot.getChildren()) { Matcher matcher = scriptPattern.matcher(file.getName()); if (matcher.matches()) { result.add(GroovyNamesUtil.camelToSnake(matcher.group(1))); } } } public abstract boolean isToReformatOnCreation(VirtualFile file); public static void addAvailableScripts( final Collection<String> result, @Nullable final VirtualFile root) { if (root == null || !root.isDirectory()) { return; } final VirtualFile scripts = root.findChild("scripts"); if (scripts == null || !scripts.isDirectory()) { return; } for (VirtualFile child : scripts.getChildren()) { if (isScriptFile(child)) { result.add(GroovyNamesUtil.camelToSnake(child.getNameWithoutExtension())); } } } @Nullable public static MvcFramework findCommonPluginModuleFramework(Module module) { for (MvcFramework framework : EP_NAME.getExtensions()) { if (framework.isCommonPluginsModule(module)) { return framework; } } return null; } public static boolean isScriptFileName(String fileName) { return fileName.endsWith(GroovyFileType.DEFAULT_EXTENSION) && fileName.charAt(0) != '_'; } private static boolean isScriptFile(VirtualFile virtualFile) { return !virtualFile.isDirectory() && isScriptFileName(virtualFile.getName()); } @Nullable public String getInstalledPluginNameByPath(Project project, @NotNull VirtualFile pluginPath) { VirtualFile pluginXml = pluginPath.findChild("plugin.xml"); if (pluginXml == null) return null; PsiFile pluginXmlPsi = PsiManager.getInstance(project).findFile(pluginXml); if (!(pluginXmlPsi instanceof XmlFile)) return null; XmlTag rootTag = ((XmlFile) pluginXmlPsi).getRootTag(); if (rootTag == null || !"plugin".equals(rootTag.getName())) return null; XmlAttribute attrName = rootTag.getAttribute("name"); if (attrName == null) return null; String res = attrName.getValue(); if (res == null) return null; res = res.trim(); if (res.length() == 0) return null; return res; } @Nullable public static MvcFramework getInstance(@Nullable final Module module) { if (module == null) { return null; } final Project project = module.getProject(); return CachedValuesManager.getManager(project) .getCachedValue( module, new CachedValueProvider<MvcFramework>() { @Override public Result<MvcFramework> compute() { final ModificationTracker tracker = MvcModuleStructureSynchronizer.getInstance(project) .getFileAndRootsModificationTracker(); for (final MvcFramework framework : EP_NAME.getExtensions()) { if (framework.hasSupport(module)) { return Result.create(framework, tracker); } } return Result.create(null, tracker); } }); } @Nullable public static MvcFramework getInstanceBySdk(@NotNull Module module) { for (final MvcFramework framework : EP_NAME.getExtensions()) { if (framework.getSdkRoot(module) != null) { return framework; } } return null; } }