mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Directory recursive pointers support (for libraries jar directories)
This commit is contained in:
@@ -35,4 +35,12 @@ public interface VirtualFilePointer {
|
||||
String getPresentableUrl();
|
||||
|
||||
boolean isValid();
|
||||
|
||||
/**
|
||||
* @return true if {@link VirtualFilePointerListener#validityChanged(VirtualFilePointer[])}
|
||||
* should fired for every change beneath this directory (Used for jar directories in libraries)
|
||||
*/
|
||||
default boolean isRecursive() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+41
-6
@@ -17,6 +17,7 @@ package com.intellij.openapi.vfs.pointers;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -36,15 +37,19 @@ public interface VirtualFilePointerContainer {
|
||||
|
||||
void remove(@NotNull VirtualFilePointer pointer);
|
||||
|
||||
@NotNull List<VirtualFilePointer> getList();
|
||||
@NotNull
|
||||
List<VirtualFilePointer> getList();
|
||||
|
||||
void addAll(@NotNull VirtualFilePointerContainer that);
|
||||
|
||||
@NotNull String[] getUrls();
|
||||
@NotNull
|
||||
String[] getUrls();
|
||||
|
||||
@NotNull VirtualFile[] getFiles();
|
||||
@NotNull
|
||||
VirtualFile[] getFiles();
|
||||
|
||||
@NotNull VirtualFile[] getDirectories();
|
||||
@NotNull
|
||||
VirtualFile[] getDirectories();
|
||||
|
||||
@Nullable
|
||||
VirtualFilePointer findByUrl(@NotNull String url);
|
||||
@@ -53,6 +58,15 @@ public interface VirtualFilePointerContainer {
|
||||
|
||||
int size();
|
||||
|
||||
/**
|
||||
* For example, to read from the xml below, call {@code readExternal(myRootTag, "childElementName"); }
|
||||
* <pre>{@code
|
||||
* <myroot>
|
||||
* <childElementName url="xxx1"/>
|
||||
* <childElementName url="xxx2"/>
|
||||
* </myroot>
|
||||
* }</pre>
|
||||
*/
|
||||
void readExternal(@NotNull Element rootChild, @NotNull String childElementName) throws InvalidDataException;
|
||||
|
||||
void writeExternal(@NotNull Element element, @NotNull String childElementName);
|
||||
@@ -61,7 +75,28 @@ public interface VirtualFilePointerContainer {
|
||||
|
||||
void moveDown(@NotNull String url);
|
||||
|
||||
@NotNull VirtualFilePointerContainer clone(@NotNull Disposable parent);
|
||||
@NotNull
|
||||
VirtualFilePointerContainer clone(@NotNull Disposable parent);
|
||||
|
||||
@NotNull VirtualFilePointerContainer clone(@NotNull Disposable parent, @Nullable VirtualFilePointerListener listener);
|
||||
@NotNull
|
||||
VirtualFilePointerContainer clone(@NotNull Disposable parent, @Nullable VirtualFilePointerListener listener);
|
||||
|
||||
/**
|
||||
* Adds {@code directory} as a root of jar files.
|
||||
* After that the {@link #getFiles()} and {@link #getUrls()} etc will return jar files in this directory
|
||||
* (and, if {@code recursively} was set, the jar files in all-subdirectories).
|
||||
*/
|
||||
void addJarDirectory(@NotNull String directoryUrl, boolean recursively);
|
||||
/**
|
||||
* Removes {@code directory} from the roots of jar files.
|
||||
* After that the {@link #getFiles()} and {@link #getUrls()} etc will not return jar files in this directory anymore.
|
||||
* @return true if removed
|
||||
*/
|
||||
boolean removeJarDirectory(@NotNull String directoryUrl);
|
||||
|
||||
/**
|
||||
* Returns list of (directory url, isRecursive) which were added via {@link #addJarDirectory(String, boolean)} }
|
||||
*/
|
||||
@NotNull
|
||||
List<Pair<String, Boolean>> getJarDirectories();
|
||||
}
|
||||
|
||||
@@ -42,4 +42,10 @@ public abstract class VirtualFilePointerManager extends SimpleModificationTracke
|
||||
|
||||
@NotNull
|
||||
public abstract VirtualFilePointerContainer createContainer(@NotNull Disposable parent, @Nullable VirtualFilePointerListener listener);
|
||||
|
||||
@NotNull
|
||||
public abstract VirtualFilePointer createDirectoryPointer(@NotNull String url,
|
||||
boolean recursively,
|
||||
@NotNull Disposable parent,
|
||||
@NotNull VirtualFilePointerListener listener);
|
||||
}
|
||||
|
||||
+8
@@ -59,4 +59,12 @@ public class CoreVirtualFilePointerManager extends VirtualFilePointerManager {
|
||||
public VirtualFilePointerContainer createContainer(@NotNull Disposable parent, @Nullable VirtualFilePointerListener listener) {
|
||||
return new VirtualFilePointerContainerImpl(this, parent, listener);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public VirtualFilePointer createDirectoryPointer(@NotNull String url,
|
||||
boolean recursively,
|
||||
@NotNull Disposable parent, @NotNull VirtualFilePointerListener listener) {
|
||||
return create(url, parent, listener);
|
||||
}
|
||||
}
|
||||
|
||||
+93
-14
@@ -15,21 +15,28 @@
|
||||
*/
|
||||
package com.intellij.openapi.vfs.impl;
|
||||
|
||||
import com.intellij.ide.highlighter.ArchiveFileType;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TraceableDisposable;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.StandardFileSystems;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -45,6 +52,8 @@ import java.util.List;
|
||||
class VirtualFilePointerContainerImpl extends TraceableDisposable implements VirtualFilePointerContainer, Disposable {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer");
|
||||
@NotNull private final List<VirtualFilePointer> myList = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
@NotNull private final List<VirtualFilePointer> myJarDirectories = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
@NotNull private final List<VirtualFilePointer> myJarRecursiveDirectories = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
@NotNull private final VirtualFilePointerManager myVirtualFilePointerManager;
|
||||
@NotNull private final Disposable myParent;
|
||||
private final VirtualFilePointerListener myListener;
|
||||
@@ -56,7 +65,6 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
VirtualFilePointerContainerImpl(@NotNull VirtualFilePointerManager manager,
|
||||
@NotNull Disposable parentDisposable,
|
||||
@Nullable VirtualFilePointerListener listener) {
|
||||
//noinspection HardCodedStringLiteral
|
||||
super(TRACE_CREATION && !ApplicationInfoImpl.isInStressTest());
|
||||
myVirtualFilePointerManager = manager;
|
||||
myParent = parentDisposable;
|
||||
@@ -64,8 +72,8 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(@NotNull final Element rootChild, @NotNull final String childElements) throws InvalidDataException {
|
||||
final List<Element> urls = rootChild.getChildren(childElements);
|
||||
public void readExternal(@NotNull final Element rootChild, @NotNull final String childName) throws InvalidDataException {
|
||||
final List<Element> urls = rootChild.getChildren(childName);
|
||||
for (Element url : urls) {
|
||||
final String urlAttribute = url.getAttributeValue(URL_ATTR);
|
||||
if (urlAttribute == null) throw new InvalidDataException("path element without url");
|
||||
@@ -119,16 +127,14 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
public void add(@NotNull VirtualFile file) {
|
||||
assert !myDisposed;
|
||||
dropCaches();
|
||||
final VirtualFilePointer pointer = create(file);
|
||||
myList.add(pointer);
|
||||
myList.add(create(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(@NotNull String url) {
|
||||
assert !myDisposed;
|
||||
dropCaches();
|
||||
final VirtualFilePointer pointer = create(url);
|
||||
myList.add(pointer);
|
||||
myList.add(create(url));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,6 +160,12 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
for (final VirtualFilePointer pointer : that.getList()) {
|
||||
myList.add(duplicate(pointer));
|
||||
}
|
||||
for (VirtualFilePointer jarDirectory : ((VirtualFilePointerContainerImpl)that).myJarDirectories) {
|
||||
myJarDirectories.add(duplicate(jarDirectory));
|
||||
}
|
||||
for (VirtualFilePointer jarRecursiveDirectory : ((VirtualFilePointerContainerImpl)that).myJarRecursiveDirectories) {
|
||||
myJarRecursiveDirectories.add(duplicate(jarRecursiveDirectory));
|
||||
}
|
||||
}
|
||||
|
||||
private void dropCaches() {
|
||||
@@ -181,7 +193,7 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
@NotNull
|
||||
private Trinity<String[], VirtualFile[], VirtualFile[]> cacheThings() {
|
||||
Trinity<String[], VirtualFile[], VirtualFile[]> result;
|
||||
if (myList.isEmpty()) {
|
||||
if (myList.isEmpty() && myJarDirectories.isEmpty() && myJarRecursiveDirectories.isEmpty()) {
|
||||
result = EMPTY;
|
||||
}
|
||||
else {
|
||||
@@ -203,6 +215,40 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
}
|
||||
}
|
||||
}
|
||||
for (VirtualFilePointer jarDirectoryPtr : myJarDirectories) {
|
||||
VirtualFile jarDirectory = jarDirectoryPtr.getFile();
|
||||
if (jarDirectory != null) {
|
||||
VirtualFile[] children = jarDirectory.getChildren();
|
||||
for (VirtualFile file : children) {
|
||||
if (!file.isDirectory() && FileTypeRegistry.getInstance().getFileTypeByFileName(file.getName()) == ArchiveFileType.INSTANCE) {
|
||||
VirtualFile jarRoot = StandardFileSystems.jar().findFileByPath(file.getPath() + URLUtil.JAR_SEPARATOR);
|
||||
if (jarRoot != null) {
|
||||
cachedFiles.add(jarRoot);
|
||||
cachedDirectories.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (VirtualFilePointer jarDirectoryPtr : myJarRecursiveDirectories) {
|
||||
VirtualFile jarDirectory = jarDirectoryPtr.getFile();
|
||||
if (jarDirectory != null) {
|
||||
VfsUtilCore.visitChildrenRecursively(jarDirectory, new VirtualFileVisitor() {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
if (!file.isDirectory() && FileTypeRegistry.getInstance().getFileTypeByFileName(file.getName()) == ArchiveFileType.INSTANCE) {
|
||||
VirtualFile jarRoot = StandardFileSystems.jar().findFileByPath(file.getPath() + URLUtil.JAR_SEPARATOR);
|
||||
if (jarRoot != null) {
|
||||
cachedFiles.add(jarRoot);
|
||||
cachedDirectories.add(file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
VirtualFile[] directories = VfsUtilCore.toVirtualFileArray(cachedDirectories);
|
||||
VirtualFile[] files = allFilesAreDirs ? directories : VfsUtilCore.toVirtualFileArray(cachedFiles);
|
||||
String[] urlsArray = ArrayUtil.toStringArray(cachedUrls);
|
||||
@@ -229,7 +275,7 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
@Nullable
|
||||
public VirtualFilePointer findByUrl(@NotNull String url) {
|
||||
assert !myDisposed;
|
||||
for (VirtualFilePointer pointer : myList) {
|
||||
for (VirtualFilePointer pointer : ContainerUtil.concat(myList, myJarDirectories, myJarRecursiveDirectories)) {
|
||||
if (url.equals(pointer.getUrl())) return pointer;
|
||||
}
|
||||
return null;
|
||||
@@ -243,16 +289,18 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return myList.size();
|
||||
return myList.size()+myJarDirectories.size()+myJarRecursiveDirectories.size();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof VirtualFilePointerContainerImpl)) return false;
|
||||
|
||||
final VirtualFilePointerContainerImpl virtualFilePointerContainer = (VirtualFilePointerContainerImpl)o;
|
||||
VirtualFilePointerContainerImpl impl = (VirtualFilePointerContainerImpl)o;
|
||||
|
||||
return myList.equals(virtualFilePointerContainer.myList);
|
||||
return myList.equals(impl.myList) &&
|
||||
myJarDirectories.equals(impl.myJarDirectories) &&
|
||||
myJarRecursiveDirectories.equals(impl.myJarRecursiveDirectories);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
@@ -278,7 +326,9 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
@NonNls
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VFPContainer: " + myList/*+"; parent:"+myParent*/;
|
||||
return "VFPContainer: " + myList
|
||||
+ (myJarDirectories.isEmpty() ? "" : ", jars: "+myJarDirectories)
|
||||
+ (myJarRecursiveDirectories.isEmpty() ? "" : ", jars(recursively): "+myJarRecursiveDirectories);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -291,10 +341,16 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
@NotNull
|
||||
public VirtualFilePointerContainer clone(@NotNull Disposable parent, @Nullable VirtualFilePointerListener listener) {
|
||||
assert !myDisposed;
|
||||
VirtualFilePointerContainer clone = myVirtualFilePointerManager.createContainer(parent, listener);
|
||||
VirtualFilePointerContainerImpl clone = (VirtualFilePointerContainerImpl)myVirtualFilePointerManager.createContainer(parent, listener);
|
||||
for (VirtualFilePointer pointer : myList) {
|
||||
clone.add(pointer.getUrl());
|
||||
}
|
||||
for (VirtualFilePointer jarDirectoryPtr : myJarDirectories) {
|
||||
clone.addJarDirectory(jarDirectoryPtr.getUrl(), false);
|
||||
}
|
||||
for (VirtualFilePointer jarDirectoryPtr : myJarRecursiveDirectories) {
|
||||
clone.addJarDirectory(jarDirectoryPtr.getUrl(), true);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -305,4 +361,27 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir
|
||||
kill(null);
|
||||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addJarDirectory(@NotNull String directoryUrl, boolean recursively) {
|
||||
VirtualFilePointer pointer = myVirtualFilePointerManager.createDirectoryPointer(directoryUrl, recursively, myParent, myListener);
|
||||
(recursively ? myJarRecursiveDirectories : myJarDirectories).add(pointer);
|
||||
dropCaches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeJarDirectory(@NotNull String directoryUrl) {
|
||||
dropCaches();
|
||||
//noinspection NonShortCircuitBooleanExpression
|
||||
return myJarDirectories.removeIf(ptr-> FileUtil.pathsEqual(ptr.getUrl(), directoryUrl))
|
||||
| myJarRecursiveDirectories.removeIf(ptr-> FileUtil.pathsEqual(ptr.getUrl(), directoryUrl));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Pair<String, Boolean>> getJarDirectories() {
|
||||
List<Pair<String, Boolean>> jars = ContainerUtil.map(myJarDirectories, ptr -> Pair.create(ptr.getUrl(), false));
|
||||
List<Pair<String, Boolean>> recJars = ContainerUtil.map(myJarRecursiveDirectories, ptr -> Pair.create(ptr.getUrl(), true));
|
||||
return ContainerUtil.concat(jars, recJars);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.vfs.newvfs.ManagingFS;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -51,11 +52,12 @@ class FilePointerPartNode {
|
||||
int pointersUnder; // number of alive pointers in this node plus all nodes beneath
|
||||
private static final VirtualFileManager ourFileManager = VirtualFileManager.getInstance();
|
||||
|
||||
FilePointerPartNode(@NotNull String part, FilePointerPartNode parent, Pair<VirtualFile,String> fileAndUrl) {
|
||||
FilePointerPartNode(@NotNull String part, FilePointerPartNode parent, Pair<VirtualFile,String> fileAndUrl, int pointersToStore) {
|
||||
this.part = part;
|
||||
this.parent = parent;
|
||||
children = EMPTY_ARRAY;
|
||||
myFileAndUrl = fileAndUrl;
|
||||
pointersUnder = pointersToStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,8 +69,9 @@ class FilePointerPartNode {
|
||||
private int position(@Nullable VirtualFile parent,
|
||||
@Nullable CharSequence parentName,
|
||||
boolean separator,
|
||||
@NotNull CharSequence childName,
|
||||
@NotNull FilePointerPartNode[] outNode) {
|
||||
@NotNull CharSequence childName, int childStart, int childEnd,
|
||||
@NotNull FilePointerPartNode[] outNode,
|
||||
@NotNull List<FilePointerPartNode> dirs) {
|
||||
int partStart;
|
||||
if (parent == null) {
|
||||
partStart = 0;
|
||||
@@ -77,52 +80,77 @@ class FilePointerPartNode {
|
||||
else {
|
||||
VirtualFile gParent = parent.getParent();
|
||||
CharSequence gParentName = gParent == null ? null : gParent.getNameSequence();
|
||||
partStart = position(gParent, gParentName, gParentName != null && !StringUtil.equals(gParentName, "/"), parentName, outNode);
|
||||
partStart = position(gParent, gParentName, gParentName != null && !StringUtil.equals(gParentName, "/"), parentName, 0, parentName.length(), outNode, dirs);
|
||||
if (partStart == -1) return -1;
|
||||
}
|
||||
|
||||
FilePointerPartNode found = outNode[0];
|
||||
boolean childSeparator = false;
|
||||
if (separator) {
|
||||
if (partStart == outNode[0].part.length()) {
|
||||
if (partStart == found.part.length()) {
|
||||
childSeparator = true;
|
||||
}
|
||||
else {
|
||||
int sepIndex = indexOfFirstDifferentChar("/", 0, outNode[0].part, partStart);
|
||||
int sepIndex = indexOfFirstDifferentChar("/", 0, found.part, partStart);
|
||||
if (sepIndex != 1) return -1;
|
||||
partStart++;
|
||||
}
|
||||
}
|
||||
int index = indexOfFirstDifferentChar(childName, 0, outNode[0].part, partStart);
|
||||
int index = indexOfFirstDifferentChar(childName, childStart, found.part, partStart);
|
||||
|
||||
if (index == childEnd) {
|
||||
addRecursiveDirectoryPtr(dirs);
|
||||
|
||||
if (index == childName.length()) {
|
||||
return partStart+index;
|
||||
}
|
||||
|
||||
if (partStart + index == outNode[0].part.length()) {
|
||||
if (partStart + index-childStart == found.part.length()) {
|
||||
// go to children
|
||||
for (FilePointerPartNode child : outNode[0].children) {
|
||||
int childPos = child.position(null, null, childSeparator, childName.subSequence(index, childName.length()), outNode);
|
||||
if (childPos != -1) return childPos;
|
||||
for (FilePointerPartNode child : found.children) {
|
||||
int childPos = child.position(null, null, childSeparator, childName, index, childEnd, outNode, dirs);
|
||||
if (childPos != -1) {
|
||||
addRecursiveDirectoryPtr(dirs);
|
||||
|
||||
return childPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
// else there is no match
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void addRecursiveDirectoryPtr(@NotNull List<FilePointerPartNode> dirs) {
|
||||
if(hasRecursiveDirectoryPointer() && (dirs.isEmpty() || dirs.get(dirs.size()-1) != this)) {
|
||||
dirs.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
// appends to "out" all nodes under this node whose path (beginning from this node) starts in prefix.subSequence(start), then parent.getPath(), then childName
|
||||
void addPointersUnder(@Nullable VirtualFile parent,
|
||||
boolean separator,
|
||||
@NotNull CharSequence childName,
|
||||
@NotNull List<FilePointerPartNode> out) {
|
||||
FilePointerPartNode[] outNode = new FilePointerPartNode[1];
|
||||
void addRelevantPointersFrom(@Nullable VirtualFile parent,
|
||||
boolean separator,
|
||||
@NotNull CharSequence childName,
|
||||
@NotNull List<FilePointerPartNode> out) {
|
||||
CharSequence parentName = parent == null ? null : parent.getNameSequence();
|
||||
int position = position(parent, parentName, separator, childName, outNode);
|
||||
FilePointerPartNode[] outNode = new FilePointerPartNode[1];
|
||||
int position = position(parent, parentName, separator, childName, 0, childName.length(), outNode, out);
|
||||
if (position != -1) {
|
||||
FilePointerPartNode node = outNode[0];
|
||||
addAllPointersUnder(node, out);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasRecursiveDirectoryPointer() {
|
||||
if (leaves == null) return false;
|
||||
if (leaves instanceof VirtualFilePointer) {
|
||||
return ((VirtualFilePointer)leaves).isRecursive();
|
||||
}
|
||||
VirtualFilePointerImpl[] leaves = (VirtualFilePointerImpl[])this.leaves;
|
||||
for (VirtualFilePointerImpl leaf : leaves) {
|
||||
if (leaf.isRecursive()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void addAllPointersUnder(@NotNull FilePointerPartNode node, @NotNull List<FilePointerPartNode> out) {
|
||||
if (node.leaves != null) {
|
||||
out.add(node);
|
||||
@@ -190,8 +218,7 @@ class FilePointerPartNode {
|
||||
}
|
||||
// cannot insert to children, create child node manually
|
||||
String pathRest = path.substring(index);
|
||||
FilePointerPartNode newNode = new FilePointerPartNode(pathRest, this, fileAndUrl);
|
||||
newNode.pointersUnder += pointersToStore;
|
||||
FilePointerPartNode newNode = new FilePointerPartNode(pathRest, this, fileAndUrl, pointersToStore);
|
||||
children = ArrayUtil.append(children, newNode);
|
||||
pointersUnder += pointersToStore;
|
||||
return newNode;
|
||||
@@ -200,17 +227,13 @@ class FilePointerPartNode {
|
||||
// try to make "/" start the splitted part
|
||||
if (index > start + 1 && index != path.length() && path.charAt(index - 1) == '/') index--;
|
||||
String pathRest = path.substring(index);
|
||||
FilePointerPartNode newNode = pathRest.isEmpty() ? this : new FilePointerPartNode(pathRest, this, fileAndUrl);
|
||||
if (newNode != this) {
|
||||
newNode.pointersUnder = pointersToStore;
|
||||
}
|
||||
FilePointerPartNode newNode = pathRest.isEmpty() ? this : new FilePointerPartNode(pathRest, this, fileAndUrl, pointersToStore);
|
||||
String commonPredecessor = StringUtil.first(part, index - start, false);
|
||||
FilePointerPartNode splittedAway = new FilePointerPartNode(part.substring(index - start), this, myFileAndUrl);
|
||||
FilePointerPartNode splittedAway = new FilePointerPartNode(part.substring(index - start), this, myFileAndUrl, pointersUnder);
|
||||
splittedAway.children = children;
|
||||
for (FilePointerPartNode child : children) {
|
||||
child.parent = splittedAway;
|
||||
}
|
||||
splittedAway.pointersUnder = pointersUnder;
|
||||
splittedAway.useCount = useCount;
|
||||
splittedAway.associate(leaves, myFileAndUrl);
|
||||
useCount = 0;
|
||||
|
||||
@@ -35,6 +35,7 @@ class VirtualFilePointerImpl extends TraceableDisposable implements VirtualFileP
|
||||
private static final boolean TRACE_CREATION = LOG.isDebugEnabled() || ApplicationManager.getApplication().isUnitTestMode();
|
||||
|
||||
volatile FilePointerPartNode myNode; // null means disposed
|
||||
boolean recursive; // true if the validityChanged() event should be fired for any change under this directory. Used for library jar directories.
|
||||
|
||||
VirtualFilePointerImpl(@Nullable VirtualFilePointerListener listener) {
|
||||
super(TRACE_CREATION);
|
||||
@@ -132,4 +133,9 @@ class VirtualFilePointerImpl extends TraceableDisposable implements VirtualFileP
|
||||
int incrementUsageCount(int delta) {
|
||||
return myNode.incrementUsageCount(delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecursive() {
|
||||
return recursive;
|
||||
}
|
||||
}
|
||||
|
||||
+34
-23
@@ -117,16 +117,16 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
@TestOnly
|
||||
synchronized VirtualFilePointer[] getPointersUnder(VirtualFile parent, String childName) {
|
||||
List<FilePointerPartNode> nodes = new ArrayList<>();
|
||||
addPointersUnder(parent, true, childName, nodes);
|
||||
addRelevantPointers(parent, true, childName, nodes);
|
||||
return toPointers(nodes);
|
||||
}
|
||||
|
||||
private void addPointersUnder(VirtualFile parent,
|
||||
boolean separator,
|
||||
@NotNull CharSequence childName,
|
||||
@NotNull List<FilePointerPartNode> out) {
|
||||
private void addRelevantPointers(VirtualFile parent,
|
||||
boolean separator,
|
||||
@NotNull CharSequence childName,
|
||||
@NotNull List<FilePointerPartNode> out) {
|
||||
for (FilePointerPartNode root : myPointers.values()) {
|
||||
root.addPointersUnder(parent, separator, childName, out);
|
||||
root.addRelevantPointersFrom(parent, separator, childName, out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
}
|
||||
}
|
||||
// else url has come from VirtualFile.getPath() and is good enough
|
||||
VirtualFilePointerImpl pointer = getOrCreate(listener, path, Pair.create(file, url));
|
||||
VirtualFilePointerImpl pointer = getOrCreate(path, Pair.create(file, url), listener);
|
||||
DelegatingDisposable.registerDisposable(parentDisposable, pointer);
|
||||
return pointer;
|
||||
}
|
||||
@@ -215,7 +215,7 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
VirtualFilePointerListener listener) {
|
||||
IdentityVirtualFilePointer pointer = myUrlToIdentity.get(url);
|
||||
if (pointer == null) {
|
||||
pointer = new IdentityVirtualFilePointer(found, url,listener){
|
||||
pointer = new IdentityVirtualFilePointer(found, url,listener) {
|
||||
@Override
|
||||
public void dispose() {
|
||||
synchronized (VirtualFilePointerManagerImpl.this) {
|
||||
@@ -247,14 +247,13 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private VirtualFilePointerImpl getOrCreate(@Nullable VirtualFilePointerListener listener,
|
||||
@NotNull String path,
|
||||
@NotNull Pair<VirtualFile, String> fileAndUrl) {
|
||||
private VirtualFilePointerImpl getOrCreate(@NotNull String path,
|
||||
@NotNull Pair<VirtualFile, String> fileAndUrl,
|
||||
@Nullable VirtualFilePointerListener listener) {
|
||||
FilePointerPartNode root = myPointers.get(listener);
|
||||
FilePointerPartNode node;
|
||||
if (root == null) {
|
||||
root = new FilePointerPartNode(path, null, fileAndUrl);
|
||||
root.pointersUnder++;
|
||||
root = new FilePointerPartNode(path, null, fileAndUrl, 1);
|
||||
myPointers.put(listener, root);
|
||||
node = root;
|
||||
}
|
||||
@@ -286,7 +285,7 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
for (Map.Entry<VirtualFilePointerListener, FilePointerPartNode> entry : myPointers.entrySet()) {
|
||||
FilePointerPartNode root = entry.getValue();
|
||||
List<FilePointerPartNode> left = new ArrayList<>();
|
||||
root.addPointersUnder(null, false, "", left);
|
||||
root.addRelevantPointersFrom(null, false, "", left);
|
||||
List<VirtualFilePointerImpl> pointers = new ArrayList<>();
|
||||
for (FilePointerPartNode node : left) {
|
||||
node.addAllPointersTo(pointers);
|
||||
@@ -316,7 +315,7 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
synchronized void addAllPointersTo(@NotNull Collection<VirtualFilePointerImpl> pointers) {
|
||||
List<FilePointerPartNode> out = new ArrayList<>();
|
||||
for (FilePointerPartNode root : myPointers.values()) {
|
||||
root.addPointersUnder(null, false, "", out);
|
||||
root.addRelevantPointersFrom(null, false, "", out);
|
||||
}
|
||||
for (FilePointerPartNode node : out) {
|
||||
node.addAllPointersTo(pointers);
|
||||
@@ -378,24 +377,23 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
for (VFileEvent event : events) {
|
||||
if (event instanceof VFileDeleteEvent) {
|
||||
final VFileDeleteEvent deleteEvent = (VFileDeleteEvent)event;
|
||||
addPointersUnder(deleteEvent.getFile(), false, "", toFireEvents);
|
||||
|
||||
addRelevantPointers(deleteEvent.getFile(), false, "", toFireEvents);
|
||||
}
|
||||
else if (event instanceof VFileCreateEvent) {
|
||||
final VFileCreateEvent createEvent = (VFileCreateEvent)event;
|
||||
addPointersUnder(createEvent.getParent(), true, createEvent.getChildName(), toFireEvents);
|
||||
addRelevantPointers(createEvent.getParent(), true, createEvent.getChildName(), toFireEvents);
|
||||
}
|
||||
else if (event instanceof VFileCopyEvent) {
|
||||
final VFileCopyEvent copyEvent = (VFileCopyEvent)event;
|
||||
addPointersUnder(copyEvent.getNewParent(), true, copyEvent.getFile().getName(), toFireEvents);
|
||||
addRelevantPointers(copyEvent.getNewParent(), true, copyEvent.getFile().getName(), toFireEvents);
|
||||
}
|
||||
else if (event instanceof VFileMoveEvent) {
|
||||
final VFileMoveEvent moveEvent = (VFileMoveEvent)event;
|
||||
VirtualFile eventFile = moveEvent.getFile();
|
||||
addPointersUnder(moveEvent.getNewParent(), true, eventFile.getName(), toFireEvents);
|
||||
addRelevantPointers(moveEvent.getNewParent(), true, eventFile.getName(), toFireEvents);
|
||||
|
||||
List<FilePointerPartNode> nodes = new ArrayList<>();
|
||||
addPointersUnder(eventFile, false, "", nodes);
|
||||
addRelevantPointers(eventFile, false, "", nodes);
|
||||
toFireEvents.addAll(nodes); // files deleted from eventFile and created in moveEvent.getNewParent()
|
||||
for (FilePointerPartNode node : nodes) {
|
||||
VirtualFilePointerImpl pointer = node.getAnyPointer();
|
||||
@@ -411,10 +409,10 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
&& !Comparing.equal(change.getOldValue(), change.getNewValue())) {
|
||||
VirtualFile eventFile = change.getFile();
|
||||
VirtualFile parent = eventFile.getParent(); // e.g. for LightVirtualFiles
|
||||
addPointersUnder(parent, true, change.getNewValue().toString(), toFireEvents);
|
||||
addRelevantPointers(parent, true, change.getNewValue().toString(), toFireEvents);
|
||||
|
||||
List<FilePointerPartNode> nodes = new ArrayList<>();
|
||||
addPointersUnder(eventFile, false, "", nodes);
|
||||
addRelevantPointers(eventFile, false, "", nodes);
|
||||
for (FilePointerPartNode node : nodes) {
|
||||
VirtualFilePointerImpl pointer = node.getAnyPointer();
|
||||
VirtualFile file = pointer == null ? null : pointer.getFile();
|
||||
@@ -567,6 +565,18 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public synchronized VirtualFilePointer createDirectoryPointer(@NotNull String url,
|
||||
boolean recursively,
|
||||
@NotNull Disposable parent, @NotNull VirtualFilePointerListener listener) {
|
||||
VirtualFilePointer pointer = create(null, url, parent, listener);
|
||||
if (pointer instanceof VirtualFilePointerImpl) {
|
||||
((VirtualFilePointerImpl)pointer).recursive = true;
|
||||
}
|
||||
return pointer;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
synchronized int numberOfPointers() {
|
||||
int number = 0;
|
||||
@@ -585,4 +595,5 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
int numberOfCachedUrlToIdentity() {
|
||||
return myUrlToIdentity.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
@@ -1004,4 +1004,24 @@ public class VirtualFilePointerTest extends PlatformTestCase {
|
||||
}
|
||||
LOG.debug("final i = " + i);
|
||||
}
|
||||
|
||||
public void testDirectoryPointersWork() throws Exception {
|
||||
final File dir = createTempDirectory();
|
||||
VirtualFile vDir = LocalFileSystem.getInstance().findFileByIoFile(dir);
|
||||
assertNotNull(vDir);
|
||||
VirtualFile deep = createChildDirectory(vDir, "deep");
|
||||
|
||||
LoggingListener listener = new LoggingListener();
|
||||
Disposable disposable = Disposer.newDisposable();
|
||||
VirtualFilePointer ptr = myVirtualFilePointerManager.createDirectoryPointer(vDir.getUrl(), false, disposable, listener);
|
||||
|
||||
createChildData(vDir, "1");
|
||||
assertEquals("[before:true, after:true]", listener.getLog().toString());
|
||||
Disposer.dispose(disposable);
|
||||
listener = new LoggingListener();
|
||||
myVirtualFilePointerManager.createDirectoryPointer(vDir.getUrl(), true, this.disposable, listener);
|
||||
|
||||
createChildData(deep, "1");
|
||||
assertEquals("[before:true, after:true]", listener.getLog().toString());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user