Cannot cancel exclusion of directory that was excluded from plugin code.
I've written a plugin that finds all 'dist' in my project and exclude them, this is the code (action):
public class ExcludeAction extends AnAction {
public ExcludeAction() {
super("_Auto Exclude");
}
@Override
public void actionPerformed(AnActionEvent event) {
if (event.getProject() != null) {
VirtualFile baseDir = event.getProject().getBaseDir();
Module projectModule = ModuleUtilCore.findModuleForFile(baseDir, event.getProject());
Application application = ApplicationManager.getApplication();
application.runWriteAction(() -> {
if (projectModule != null) {
ModifiableRootModel modifiableModel = ModuleRootManager.getInstance(projectModule).getModifiableModel();
VfsUtilCore.iterateChildrenRecursively(baseDir, VirtualFileFilter.ALL, getIterator(modifiableModel));
}
});
}
}
@NotNull
private ContentIterator getIterator(ModifiableRootModel modifiableModel) {
return virtualFile -> {
if (virtualFile.isDirectory() && virtualFile.getPresentableName().equals("dist")) {
modifiableModel.addContentEntry(virtualFile).addExcludeFolder(virtualFile);
modifiableModel.commit();
}
return true;
};
}
}
I first got an error that I was writing outside a write action so I fixed that by using a runnable inside:
application.runWriteAction(...)
Now when I execute the action the dist folders do get excluded but I am unable to cancel exclusion (by using right click > mark directory as > cancel exclusion). What am I doing wrong?
Thanks in advance!
Jeroen
请先登录再写评论。
Firstly your code doesn't commit the model properly. If there are several 'dist' directories it may commit the model and then try to modify it again. It isn't allowed, see javadoc of 'commit' method. Also if there are no 'dist' directories at all, the model won't be committed, and it is also not allowed, see javadoc of getModifiableModel'. Instead of doing this, you can firstly perform all modifications in ModifiableRootModel (and you don't need WriteAction for that) and than commit the model (under WriteAction) once.
Secondly, it makes no sense to add a content entry to exclude a directory. If a directory is already under a content root you can get the containing ContentEntry and invoke 'addExcludeFolder' on it, this should fix the problem with 'Cancel Exclusion'. Also note that Project.getBaseDir return a directory containing .idea folder (see its javadoc). In general that directory may not be related to the project sources. So it would be better to iterate over ModuleRootModel#getContentEntries instead, process their files recursively and invoke 'addExludeFolder' for found directories.
Thirdly it would be better to use VirtualFile#getName instead of 'getPresentableName' for comparison. 'getPresentableName' is meant to be used for presentation purposes only.
@Nikolay Chashnikov
Thank you for your feedback!
I've updated my code but I am still unable to cancel exclusion. As you can see I now check for matching content entries and act accordingly:
Second question:
"In general that directory may not be related to the project sources. So it would be better to iterate over ModuleRootModel#getContentEntries instead, process their files recursively and invoke 'addExludeFolder' for found directories."
Isn't getContentEntries returning multiple results, for example: a, a>b, a>b2, a>c. So do I only need to recursively process the first result in the array or is there a better way?
Greetings
Jeroen
We don't have ContentEntry for each directory in a project, a ContentEntry describes a content root and directories and their subdirectories and files located under it belong to the corresponding module. So if you want to find a ContentEntry by a file/directory you need to check that ContentEntry's file is ancestor of your file, not equal to it. Looks how it's implemented in MarkRootActionBase for example. However it seems that you don't need this in your case. If you iterate over ContentEntry#getFile's children instead of project.getBaseDir you'll automatically have parent ContentEntry for the files you're processing.
Ok makes sense but how would you get a starting point ContentEntry in actionPerfromed#. Is there another way than getting it from:
Greetings
Jeroen
You can get them from ModuleRootManager.
And retrieving them module using the following code is ok?
I think it would be better to iterate over all modules in the project (ModuleManager.getModules). This way you'll support multi-module projects and behavior won't depend on location of .idea directory.
Thank you so much for taking the time to answer my questions :)