@Override public void doubleClick() { Project project = getProject(); final SRepository r = ProjectHelper.getProjectRepository(project); SModule m = (r == null ? null : new ModelAccessHelper(r) .runReadAction( new Computable<SModule>() { public SModule compute() { return myModule.resolve(r); } })); if (m == null) { return; } ProjectPane.getInstance(project).selectModule(m, false); }
private SNode getNode(AbstractTreeNode treeNode) { if (!(treeNode instanceof MPSPsiElementTreeNode)) { return null; } MPSPsiNodeBase psiNode = ((MPSPsiElementTreeNode) treeNode).getValue(); if (!(psiNode instanceof MPSPsiRealNode)) { return null; } final SNodeReference nodeRef = ((MPSPsiRealNode) psiNode).getSNodeReference(); final SRepository repository = ProjectHelper.getProjectRepository(treeNode.getProject()); // TODO remove read action from here once SModelFileTracker stops doing the same (creating read // action if not already in one) return new ModelComputeRunnable<SNode>( new Computable<SNode>() { @Override public SNode compute() { return nodeRef.resolve(repository); } }) .runRead(repository.getModelAccess()); }
@Override public Collection<AbstractTreeNode> modify( final AbstractTreeNode treeNode, final Collection<AbstractTreeNode> children, final ViewSettings settings) { final Ref<Collection<AbstractTreeNode>> result = new Ref<Collection<AbstractTreeNode>>(children); // we're actually in EDT here, but we work with SModels, and various routines assert that we can // read, thus read action ProjectHelper.getProjectRepository(treeNode.getProject()) .getModelAccess() .runReadAction( new Runnable() { @Override public void run() { List<AbstractTreeNode> updatedChildren = null; final MPSPsiProvider mpsPsiProvider = MPSPsiProvider.getInstance(treeNode.getProject()); // if current dir is data source from some model FolderDataSource currentDirectoryDataSource = null; if (treeNode instanceof PsiDirectoryNode) { // let's see if we have a model built from this dir, e.g. in per-root persistence SModel sModel = SModelFileTracker.getInstance() .findModel( VirtualFileUtils.toIFile( ((PsiDirectoryNode) treeNode).getVirtualFile())); if (sModel != null) { // adding root nodes (removing their corresponding files' nodes from the tree is // further below) List<MPSPsiElementTreeNode> rootsTreeNodes = new ArrayList<MPSPsiElementTreeNode>(); for (SNode root : sModel.getRootNodes()) { rootsTreeNodes.add( new MPSPsiElementTreeNode( treeNode.getProject(), (MPSPsiRootNode) mpsPsiProvider.getPsi(root).getContainingFile(), settings)); } if (!rootsTreeNodes.isEmpty() && updatedChildren == null) { updatedChildren = new ArrayList<AbstractTreeNode>(children); updatedChildren.addAll(rootsTreeNodes); } DataSource dataSource = sModel.getSource(); if (dataSource instanceof FolderDataSource) { // could be assert as currently SModelFileTracker only tracks FileDataSource // and FolderDataSource currentDirectoryDataSource = (FolderDataSource) dataSource; } } } else if (treeNode instanceof MPSPsiModelTreeNode) { MPSPsiModel psiModel = ((MPSPsiModelTreeNode) treeNode).extractPsiFromValue(); updatedChildren = new ArrayList<AbstractTreeNode>(); for (PsiElement psiElement : psiModel.getChildren()) { updatedChildren.add( new MPSPsiElementTreeNode( treeNode.getProject(), (MPSPsiRootNode) psiElement, settings)); } } for (final AbstractTreeNode child : children) { if (child instanceof PsiFileNode) { VirtualFile vFile = ((PsiFileNode) child).getVirtualFile(); if (vFile == null) { continue; } // check if it's a single file model final SModel sModel = SModelFileTracker.getInstance().findModel(VirtualFileUtils.toIFile(vFile)); if (sModel != null) { if (updatedChildren == null) updatedChildren = new ArrayList<AbstractTreeNode>(children); int idx = updatedChildren.indexOf(child); updatedChildren.remove(idx); updatedChildren.add( idx, new MPSPsiModelTreeNode( treeNode.getProject(), mpsPsiProvider.getPsi(sModel), settings)); continue; } if (currentDirectoryDataSource != null && currentDirectoryDataSource.isIncluded(VirtualFileUtils.toIFile(vFile))) { // it's a file that constitutes a FolderDataSource-backed model, remove it // from the tree (root nodes are shown instead) if (updatedChildren == null) updatedChildren = new ArrayList<AbstractTreeNode>(children); int idx = updatedChildren.indexOf(child); updatedChildren.remove(idx); } } else if (child instanceof PsiDirectoryNode) { // below code only attaches our action to the directory and makes it show added // children - our root nodes final SModel perRootModel = SModelFileTracker.getInstance() .findModel( VirtualFileUtils.toIFile( ((PsiDirectoryNode) child).getVirtualFile())); if (perRootModel != null) { if (updatedChildren == null) updatedChildren = new ArrayList<AbstractTreeNode>(children); int idx = updatedChildren.indexOf(child); updatedChildren.remove(idx); updatedChildren.add( idx, new PsiDirectoryNode( treeNode.getProject(), ((PsiDirectoryNode) child).getValue(), settings) { @Override public boolean canNavigate() { return true; } @Override public String getNavigateActionText(boolean focusEditor) { return MPSBundle.message("open.model.properties.action"); } @Override public void navigate(boolean requestFocus) { MPSPropertiesConfigurable configurable = new ModelPropertiesConfigurable( perRootModel, ProjectHelper.toMPSProject(myProject), true); final SingleConfigurableEditor dialog = new SingleConfigurableEditor(myProject, configurable); configurable.setParentForCallBack(dialog); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { dialog.show(); } }); } }); } } } if (updatedChildren != null) { result.set(updatedChildren); } } }); return result.get(); }
@Override public void processQuery( @NotNull SearchParameters queryParameters, @NotNull final Processor<PsiReference> consumer) { if (!(queryParameters.getEffectiveSearchScope() instanceof GlobalSearchScope)) { return; } final GlobalSearchScope scope = (GlobalSearchScope) queryParameters.getEffectiveSearchScope(); final PsiElement target = queryParameters.getElementToSearch(); // Only class names can be prefixes in foreign ids of other nodes if (!(target instanceof PsiClass)) return; final SRepository repository = ProjectHelper.getProjectRepository(scope.getProject()); if (repository == null) { return; } repository .getModelAccess() .runReadAction( new Runnable() { @Override public void run() { final NodePtr nodePtr = JavaForeignIdBuilder.computeNodePtr(target); if (nodePtr == null) return; final SNodeReference mpsTarget = new SNodePointer(nodePtr.getSModelReference(), nodePtr.getNodeId()); // do we have this node? if (mpsTarget.resolve(MPSModuleRepository.getInstance()) == null) return; String prefix = nodePtr.getNodeId().toString(); final String prefixToSearch = (prefix.startsWith(Foreign.ID_PREFIX) ? prefix.substring(1) : prefix); final String prefixToSearchWithDot = prefixToSearch + "."; final Project project = target.getProject(); // first look into changed models SearchScope mpsSearchScope = new IdeaSearchScope(scope, true); CollectConsumer<VirtualFile> processedFilesConsumer = new CollectConsumer<VirtualFile>(); for (SModel model : mpsSearchScope.getModels()) { boolean changed = model instanceof EditableSModel && ((EditableSModel) model).isChanged(); if (!changed) continue; findInModel( model, prefixToSearch, processedFilesConsumer, new Consumer<SReference>() { @Override public void consume(SReference ref) { String role = ref.getRole(); SNode source = ref.getSourceNode(); PsiElement psiNode = MPSPsiProvider.getInstance(project).getPsi(source.getReference()); assert psiNode instanceof MPSPsiNode; consumer.process(new IdPrefixReference(mpsTarget, role, psiNode)); } }); } // now index final Collection<VirtualFile> filesOfChangedModels = processedFilesConsumer.getResult(); GlobalSearchScope truncatedScope = new DelegatingGlobalSearchScope(scope) { @Override public boolean contains(VirtualFile file) { if (filesOfChangedModels.contains(file)) return false; return super.contains(file); } }; ValueProcessor<Collection<Pair<SNodeDescriptor, String>>> sReferenceProcessor = new ValueProcessor<Collection<Pair<SNodeDescriptor, String>>>() { @Override public boolean process( VirtualFile file, Collection<Pair<SNodeDescriptor, String>> refs) { for (Pair<SNodeDescriptor, String> ref : refs) { SNodeReference nodeRef = ref.o1.getNodeReference(); String role = ref.o2; // index got out-of-date on this // unfortunately our indices are not always up-to-date, as we don't index // yet-unsaved changes if (nodeRef.resolve(repository) == null) continue; PsiElement psiNode = MPSPsiProvider.getInstance(project).getPsi(nodeRef); // original node came from MPS index, it must be converted to our PSI // element assert psiNode instanceof MPSPsiNode; consumer.process(new IdPrefixReference(mpsTarget, role, psiNode)); } return true; } }; FileBasedIndex.getInstance() .processValues( ForeignIdReferenceIndex.ID, prefixToSearchWithDot, null, sReferenceProcessor, truncatedScope); } }); }
@Override public void processQuery( @NotNull SearchParameters queryParameters, final @NotNull Processor<PsiReference> consumer) { if (!(queryParameters.getEffectiveSearchScope() instanceof GlobalSearchScope)) { return; } final GlobalSearchScope scope = (GlobalSearchScope) queryParameters.getEffectiveSearchScope(); final PsiElement psiTarget = queryParameters.getElementToSearch(); if (psiTarget instanceof MPSPsiNodeBase) return; final Project project = psiTarget.getProject(); final MPSPsiProvider psiProvider = MPSPsiProvider.getInstance(project); SRepository repository = ProjectHelper.getProjectRepository(project); repository .getModelAccess() .runReadAction( new Runnable() { @Override public void run() { if (DumbService.getInstance(project).isDumb()) { return; } if (psiTarget instanceof LightElement) { // we don't handle light psi elements we don't know about // we may not be able to compute their node id and their Java meaning can be // represented in baseLanguage // in a special way return; } // if MPSReferenceSearch is moved to mps-core, it will be // MPS2PsiMapperUtil.getNodeId final SNode targetNode = getNodeForElement(psiTarget); if (targetNode == null) { // it can't be referenced from MPS return; } Set<SNode> targetNodes = new HashSet<SNode>(1); targetNodes.add(targetNode); Set<SReference> references; try { references = FindUsagesFacade.getInstance() .findUsages(new IdeaSearchScope(scope), targetNodes, null); } catch (IndexNotReadyException e) { // DumbService doesn't seem to work return; } for (SReference sReference : references) { SNode source = sReference.getSourceNode(); MPSPsiNode psiNode = (MPSPsiNode) psiProvider.getPsi(source); // the source could have come from the psi stub itself if (psiNode == null) return; String refRole = sReference.getRole(); MPSPsiRef[] refs = psiNode.getReferences(refRole); if (refs.length == 0) continue; for (MPSPsiRef r : refs) { if (targetNode.getNodeId().equals(r.getNodeId())) { // it's our reference: giving it out to find usages consumer.process(r.getReference()); } } } } }); }
// Maybe will go to MPS2PsiMapper @Nullable public static SNode getNodeForElement(PsiElement element) { // baseLanguage specific check if (!(element instanceof PsiClass || element instanceof PsiMethod || element instanceof PsiField)) { return null; } PsiFile psiFile = element.getContainingFile(); if (!(psiFile instanceof PsiJavaFile)) { return null; } if (PsiManager.getInstance(element.getProject()).isInProject(element)) { // It must be sources, try psi stubs // There might be psi stubs for this element, but there also might not (e.g. if it's inside a // module // with no MPS facet) NodePtr nodePtr = JavaForeignIdBuilder.computeNodePtr(element); if (nodePtr == null) { return null; } SNode node = nodePtr .toSNodeReference() .resolve(ProjectHelper.getProjectRepository(element.getProject())); return node; } else { // It must be from a library or SDK or something like that // Trying to find a suitable node in a class stub model SNodeId nodeId = null; if (element instanceof PsiClass) { nodeId = ASMNodeId.createId(((PsiClass) element).getQualifiedName()); } else if (element instanceof PsiField) { PsiClass clas = ((PsiField) element).getContainingClass(); String clasFqName = clas.getQualifiedName(); nodeId = ASMNodeId.createFieldId(clasFqName, ((PsiField) element).getName()); } else if (element instanceof PsiMethod) { // TODO argument types must be handled like they are in ASMNodeId (via asm classes) } if (nodeId == null) { // can't do anything about it return null; } String packageName = ((PsiJavaFile) psiFile).getPackageName(); for (SModel model : new ModuleRepositoryFacade(ProjectHelper.getProjectRepository(element.getProject())) .getAllModels()) { if (!(model instanceof JavaClassStubModelDescriptor)) continue; if (!packageName.equals(model.getName().getLongName())) { continue; } SNode node = model.getNode(nodeId); if (node == null) continue; return node; } } return null; }