mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
VFS visitor extended
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.vfs;
|
||||
|
||||
import com.intellij.openapi.roots.ContentIterator;
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayInputStream;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.Function;
|
||||
@@ -26,9 +27,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class VfsUtilCore {
|
||||
/**
|
||||
@@ -170,38 +169,63 @@ public class VfsUtilCore {
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static void visitChildrenRecursively(@NotNull VirtualFile file, @NotNull VirtualFileVisitor visitor) {
|
||||
visitChildrenRecursively(file, visitor, null);
|
||||
public static boolean iterateChildrenRecursively(@NotNull final VirtualFile root,
|
||||
@Nullable final VirtualFileFilter filter,
|
||||
@NotNull final ContentIterator iterator) {
|
||||
final VirtualFileVisitor.Result result = visitChildrenRecursively(root, new VirtualFileVisitor() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Result visitFileEx(@NotNull VirtualFile file) {
|
||||
if (filter != null && !filter.accept(file)) return SKIP_CHILDREN;
|
||||
if (!iterator.processFile(file)) return skipTo(root);
|
||||
return CONTINUE;
|
||||
}
|
||||
});
|
||||
return result.skipToParent != root;
|
||||
}
|
||||
|
||||
private static void visitChildrenRecursively(@NotNull VirtualFile file,
|
||||
@NotNull VirtualFileVisitor visitor,
|
||||
@Nullable Set<VirtualFile> visitedSymLinks) {
|
||||
if (!file.isValid()) return;
|
||||
if (!visitor.visitFile(file)) return;
|
||||
public static VirtualFileVisitor.Result visitChildrenRecursively(@NotNull VirtualFile file, @NotNull VirtualFileVisitor visitor) {
|
||||
if (!file.isValid()) return VirtualFileVisitor.CONTINUE;
|
||||
|
||||
boolean visitChildren = true;
|
||||
if (file.isSymLink()) {
|
||||
if (!visitor.followSymLinks()) return;
|
||||
if (visitedSymLinks == null) {
|
||||
visitedSymLinks = new HashSet<VirtualFile>();
|
||||
visitor.pushFrame();
|
||||
try {
|
||||
final boolean visited = visitor.allowVisitFile(file);
|
||||
if (visited) {
|
||||
VirtualFileVisitor.Result result = visitor.visitFileEx(file);
|
||||
if (result.skipChildren) return result;
|
||||
}
|
||||
if (!visitedSymLinks.add(file) || isInvalidLink(file)) {
|
||||
visitChildren = false;
|
||||
|
||||
if (!visitor.allowVisitChildren(file)) return VirtualFileVisitor.CONTINUE;
|
||||
|
||||
if (!visitor.depthLimitReached()) {
|
||||
final Iterable<VirtualFile> iterable = visitor.getChildrenIterable(file);
|
||||
if (iterable != null) {
|
||||
for (VirtualFile child : iterable) {
|
||||
VirtualFileVisitor.Result result = visitChildrenRecursively(child, visitor);
|
||||
if (result.skipToParent != null && result.skipToParent != child) return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@SuppressWarnings("UnsafeVfsRecursion") VirtualFile[] children = file.getChildren();
|
||||
for (VirtualFile child : children) {
|
||||
VirtualFileVisitor.Result result = visitChildrenRecursively(child, visitor);
|
||||
if (result.skipToParent != null && result.skipToParent != child) return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (visited) {
|
||||
visitor.afterChildrenVisited(file);
|
||||
}
|
||||
|
||||
return VirtualFileVisitor.CONTINUE;
|
||||
}
|
||||
|
||||
if (visitChildren) {
|
||||
@SuppressWarnings("UnsafeVfsRecursion") VirtualFile[] children = file.getChildren();
|
||||
for (VirtualFile child : children) {
|
||||
visitChildrenRecursively(child, visitor, visitedSymLinks);
|
||||
}
|
||||
finally {
|
||||
visitor.popFrame();
|
||||
}
|
||||
|
||||
visitor.afterChildrenVisited(file);
|
||||
}
|
||||
|
||||
private static boolean isInvalidLink(@NotNull VirtualFile link) {
|
||||
public static boolean isInvalidLink(@NotNull VirtualFile link) {
|
||||
final VirtualFile target = link.getCanonicalFile();
|
||||
return target == null || target == link || isAncestor(target, link, true);
|
||||
}
|
||||
|
||||
@@ -15,28 +15,182 @@
|
||||
*/
|
||||
package com.intellij.openapi.vfs;
|
||||
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
* @since 31.10.2011
|
||||
*/
|
||||
public abstract class VirtualFileVisitor {
|
||||
private final boolean myFollowSymLinks;
|
||||
public static class Option {
|
||||
private Option() { }
|
||||
|
||||
protected VirtualFileVisitor() {
|
||||
this(true);
|
||||
private static class LimitOption extends Option {
|
||||
private final int limit;
|
||||
|
||||
private LimitOption(int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected VirtualFileVisitor(boolean followSymLinks) {
|
||||
myFollowSymLinks = followSymLinks;
|
||||
public static final Option NO_FOLLOW_SYMLINKS = new Option();
|
||||
public static final Option SKIP_ROOT = new Option();
|
||||
public static final Option ONE_LEVEL_DEEP = new Option.LimitOption(1);
|
||||
|
||||
public static Option limit(int maxDepth) {
|
||||
return new Option.LimitOption(maxDepth);
|
||||
}
|
||||
|
||||
public boolean followSymLinks() {
|
||||
return myFollowSymLinks;
|
||||
|
||||
public static class Result {
|
||||
public final boolean skipChildren;
|
||||
public final VirtualFile skipToParent;
|
||||
|
||||
private Result(boolean skipChildren, @Nullable VirtualFile skipToParent) {
|
||||
this.skipChildren = skipChildren;
|
||||
this.skipToParent = skipToParent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + (skipChildren ? "skip," + skipToParent : "continue") + ")";
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean visitFile(@NotNull VirtualFile file);
|
||||
public static final Result CONTINUE = new Result(false, null);
|
||||
public static final Result SKIP_CHILDREN = new Result(true, null);
|
||||
|
||||
public static Result skipTo(@NotNull VirtualFile parentToSkipTo) {
|
||||
return new Result(true, parentToSkipTo);
|
||||
}
|
||||
|
||||
|
||||
private boolean myFollowSymLinks = true;
|
||||
private boolean mySkipRoot = false;
|
||||
private int myDepthLimit = -1;
|
||||
|
||||
private int myLevel = -1;
|
||||
private Stack<Map<Key, Object>> myParameters = null;
|
||||
|
||||
protected VirtualFileVisitor(Option... options) {
|
||||
for (Option option : options) {
|
||||
if (option == NO_FOLLOW_SYMLINKS) myFollowSymLinks = false;
|
||||
else if (option == SKIP_ROOT) mySkipRoot = true;
|
||||
else if (option instanceof Option.LimitOption) myDepthLimit = ((Option.LimitOption)option).limit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple visiting method.
|
||||
* On returning {@code true} a visitor will proceed to file's children, on {@code false} - to file's next sibling.
|
||||
*
|
||||
* @param file a file to visit.
|
||||
* @return {@code true} to proceed to file's children, {@code false} to skip to file's next sibling.
|
||||
*/
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended visiting method.
|
||||
*
|
||||
* @param file a file to visit.
|
||||
* @return {@linkplain #CONTINUE} to proceed to file's children,<br/>
|
||||
* {@linkplain #SKIP_CHILDREN} to skip to file's next sibling,<br/>
|
||||
* result of {@linkplain #skipTo(VirtualFile)} to skip to given file's next sibling.
|
||||
*/
|
||||
@NotNull
|
||||
public Result visitFileEx(@NotNull VirtualFile file) {
|
||||
return visitFile(file) ? CONTINUE : SKIP_CHILDREN;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only called if visiting wasn't interrupted (by returning skip-requesting result
|
||||
* from {@linkplain #visitFile(VirtualFile)} or {@linkplain #visitFileEx(VirtualFile)} methods).
|
||||
*
|
||||
* @param file a file whose children were successfully visited.
|
||||
*/
|
||||
public void afterChildrenVisited(@NotNull VirtualFile file) { }
|
||||
|
||||
/**
|
||||
* By default, visitor uses ({@linkplain com.intellij.openapi.vfs.VirtualFile#getChildren()}) to iterate over file's children.
|
||||
* You can override this method to implement another mechanism.
|
||||
*
|
||||
* @param file a virtual file to get children from.
|
||||
* @return children iterable, or null to use {@linkplain com.intellij.openapi.vfs.VirtualFile#getChildren()}.
|
||||
*/
|
||||
@Nullable
|
||||
public Iterable<VirtualFile> getChildrenIterable(@NotNull VirtualFile file) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public final <T> void set(@NotNull Key<T> parameter, @Nullable T value) {
|
||||
if (myParameters == null) {
|
||||
myParameters = ContainerUtil.newStack();
|
||||
}
|
||||
|
||||
final Map<Key, Object> frame;
|
||||
if (myParameters.isEmpty()) {
|
||||
myParameters.push(frame = ContainerUtil.newHashMap());
|
||||
}
|
||||
else {
|
||||
frame = myParameters.peek();
|
||||
}
|
||||
|
||||
frame.put(parameter, value);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public final <T> T get(@NotNull Key<T> parameter) {
|
||||
if (myParameters == null || myParameters.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) final T value = (T)myParameters.peek().get(parameter);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
final boolean allowVisitFile(@SuppressWarnings("UnusedParameters") @NotNull VirtualFile file) {
|
||||
return myLevel > 0 || !mySkipRoot;
|
||||
}
|
||||
|
||||
final boolean allowVisitChildren(@NotNull VirtualFile file) {
|
||||
return !file.isSymLink() || (myFollowSymLinks && !VfsUtilCore.isInvalidLink(file));
|
||||
}
|
||||
|
||||
final boolean depthLimitReached() {
|
||||
return myDepthLimit >= 0 && myLevel >= myDepthLimit;
|
||||
}
|
||||
|
||||
final void pushFrame() {
|
||||
++myLevel;
|
||||
|
||||
if (myParameters != null && !myParameters.isEmpty()) {
|
||||
final Map<Key, Object> lastFrame = myParameters.peek();
|
||||
myParameters.push(new HashMap<Key, Object>() {
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return containsKey(key) ? super.get(key) : lastFrame.get(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
final void popFrame() {
|
||||
--myLevel;
|
||||
|
||||
if (myParameters != null && !myParameters.isEmpty()) {
|
||||
myParameters.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-2
@@ -443,7 +443,6 @@ public class FileDocumentManagerImplTest extends PlatformLiteFixture {
|
||||
|
||||
myDocumentManager.myReloadFromDisk = Boolean.TRUE;
|
||||
try {
|
||||
file.setActualTimeStamp(file.getTimeStamp() + 1);
|
||||
myDocumentManager.saveAllDocuments();
|
||||
long fileStamp = file.getModificationStamp();
|
||||
|
||||
@@ -476,7 +475,6 @@ public class FileDocumentManagerImplTest extends PlatformLiteFixture {
|
||||
|
||||
file.setContent(null, "xxx", false);
|
||||
|
||||
file.setActualTimeStamp(file.getTimeStamp() + 1);
|
||||
myDocumentManager.saveAllDocuments();
|
||||
|
||||
assertEquals("zzztest", document.getText());
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.vfs;
|
||||
|
||||
import com.intellij.mock.MockVirtualFile;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class VirtualFileVisitorTest {
|
||||
private static VirtualFile myRoot;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() throws Exception {
|
||||
myRoot =
|
||||
dir("/",
|
||||
dir("d1",
|
||||
dir("d11",
|
||||
file("f11.1"),
|
||||
file("f11.2")),
|
||||
file("f1.1"),
|
||||
dir("d12",
|
||||
file("f12.1"),
|
||||
file("f12.2"))),
|
||||
dir("d2",
|
||||
file("f2.1"),
|
||||
file("f2.2")));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() throws Exception {
|
||||
myRoot = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void visitAll() {
|
||||
doTest(
|
||||
null, null,
|
||||
"-> /\n" +
|
||||
" -> d1\n" +
|
||||
" -> d11\n" +
|
||||
" -> f11.1\n" +
|
||||
" <- f11.1\n" +
|
||||
" -> f11.2\n" +
|
||||
" <- f11.2\n" +
|
||||
" <- d11\n" +
|
||||
" -> f1.1\n" +
|
||||
" <- f1.1\n" +
|
||||
" -> d12\n" +
|
||||
" -> f12.1\n" +
|
||||
" <- f12.1\n" +
|
||||
" -> f12.2\n" +
|
||||
" <- f12.2\n" +
|
||||
" <- d12\n" +
|
||||
" <- d1\n" +
|
||||
" -> d2\n" +
|
||||
" -> f2.1\n" +
|
||||
" <- f2.1\n" +
|
||||
" -> f2.2\n" +
|
||||
" <- f2.2\n" +
|
||||
" <- d2\n" +
|
||||
"<- /\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipChildrenForDirectory() {
|
||||
doTest(
|
||||
new Function<VirtualFile, Object>() {
|
||||
@Override
|
||||
public Object fun(VirtualFile file) {
|
||||
return "d11".equals(file.getName()) ? VirtualFileVisitor.SKIP_CHILDREN : VirtualFileVisitor.CONTINUE;
|
||||
}
|
||||
},
|
||||
null,
|
||||
"-> /\n" +
|
||||
" -> d1\n" +
|
||||
" -> d11\n" +
|
||||
" -> f1.1\n" +
|
||||
" <- f1.1\n" +
|
||||
" -> d12\n" +
|
||||
" -> f12.1\n" +
|
||||
" <- f12.1\n" +
|
||||
" -> f12.2\n" +
|
||||
" <- f12.2\n" +
|
||||
" <- d12\n" +
|
||||
" <- d1\n" +
|
||||
" -> d2\n" +
|
||||
" -> f2.1\n" +
|
||||
" <- f2.1\n" +
|
||||
" -> f2.2\n" +
|
||||
" <- f2.2\n" +
|
||||
" <- d2\n" +
|
||||
" <- /\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipChildrenForFiles() {
|
||||
doTest(
|
||||
new Function<VirtualFile, Object>() {
|
||||
@Override
|
||||
public Object fun(VirtualFile file) {
|
||||
return file.isDirectory() ? VirtualFileVisitor.CONTINUE : VirtualFileVisitor.SKIP_CHILDREN;
|
||||
}
|
||||
},
|
||||
null,
|
||||
"-> /\n" +
|
||||
" -> d1\n" +
|
||||
" -> d11\n" +
|
||||
" -> f11.1\n" +
|
||||
" -> f11.2\n" +
|
||||
" <- d11\n" +
|
||||
" -> f1.1\n" +
|
||||
" -> d12\n" +
|
||||
" -> f12.1\n" +
|
||||
" -> f12.2\n" +
|
||||
" <- d12\n" +
|
||||
" <- d1\n" +
|
||||
" -> d2\n" +
|
||||
" -> f2.1\n" +
|
||||
" -> f2.2\n" +
|
||||
" <- d2\n" +
|
||||
" <- /\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipToParent() {
|
||||
final Ref<VirtualFile> skip = Ref.create();
|
||||
doTest(
|
||||
new Function<VirtualFile, Object>() {
|
||||
@Override
|
||||
public Object fun(VirtualFile file) {
|
||||
if ("d1".equals(file.getName())) skip.set(file);
|
||||
return "f11.1".equals(file.getName()) ? skip.get() : VirtualFileVisitor.CONTINUE;
|
||||
}
|
||||
},
|
||||
null,
|
||||
"-> /\n" +
|
||||
" -> d1\n" +
|
||||
" -> d11\n" +
|
||||
" -> f11.1\n" +
|
||||
" -> d2\n" +
|
||||
" -> f2.1\n" +
|
||||
" <- f2.1\n" +
|
||||
" -> f2.2\n" +
|
||||
" <- f2.2\n" +
|
||||
" <- d2\n" +
|
||||
" <- /\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipToRoot() {
|
||||
doTest(
|
||||
new Function<VirtualFile, Object>() {
|
||||
@Override
|
||||
public Object fun(VirtualFile file) {
|
||||
return "f11.1".equals(file.getName()) ? myRoot : VirtualFileVisitor.CONTINUE;
|
||||
}
|
||||
},
|
||||
null,
|
||||
"-> /\n" +
|
||||
" -> d1\n" +
|
||||
" -> d11\n" +
|
||||
" -> f11.1\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void abort() {
|
||||
doTest(
|
||||
new Function<VirtualFile, Object>() {
|
||||
@Override
|
||||
public Object fun(VirtualFile file) {
|
||||
if ("f11.1".equals(file.getName())) {
|
||||
throw new AbortException();
|
||||
}
|
||||
return VirtualFileVisitor.CONTINUE;
|
||||
}
|
||||
},
|
||||
null,
|
||||
"-> /\n" +
|
||||
" -> d1\n" +
|
||||
" -> d11\n" +
|
||||
" -> f11.1\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parameters() {
|
||||
final Key<String> KEY = Key.create("vfs.visitor.test.parameter");
|
||||
|
||||
VfsUtilCore.visitChildrenRecursively(myRoot, new VirtualFileVisitor() {
|
||||
{
|
||||
set(KEY, myRoot.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
String expected = file == myRoot ? myRoot.getPath() : file.getParent().getPath();
|
||||
assertEquals(expected, get(KEY));
|
||||
|
||||
if (file.isDirectory()) {
|
||||
set(KEY, file.getPath());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void depthLimit() {
|
||||
doTest(
|
||||
null, null,
|
||||
"-> /\n" +
|
||||
"<- /\n",
|
||||
VirtualFileVisitor.limit(0)
|
||||
);
|
||||
|
||||
doTest(
|
||||
null, null,
|
||||
"-> /\n" +
|
||||
" -> d1\n" +
|
||||
" <- d1\n" +
|
||||
" -> d2\n" +
|
||||
" <- d2\n" +
|
||||
"<- /\n",
|
||||
VirtualFileVisitor.ONE_LEVEL_DEEP
|
||||
);
|
||||
|
||||
doTest(
|
||||
null, null,
|
||||
"-> d1\n" +
|
||||
"<- d1\n" +
|
||||
"-> d2\n" +
|
||||
"<- d2\n",
|
||||
VirtualFileVisitor.SKIP_ROOT, VirtualFileVisitor.ONE_LEVEL_DEEP);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customIterable() {
|
||||
doTest(
|
||||
null,
|
||||
new NullableFunction<VirtualFile, Iterable<VirtualFile>>() {
|
||||
@Override
|
||||
public Iterable<VirtualFile> fun(VirtualFile file) {
|
||||
return "d12".equals(file.getName()) ? Collections.singletonList(file.getChildren()[1]) : null;
|
||||
}
|
||||
},
|
||||
"-> /\n" +
|
||||
" -> d1\n" +
|
||||
" -> d11\n" +
|
||||
" -> f11.1\n" +
|
||||
" <- f11.1\n" +
|
||||
" -> f11.2\n" +
|
||||
" <- f11.2\n" +
|
||||
" <- d11\n" +
|
||||
" -> f1.1\n" +
|
||||
" <- f1.1\n" +
|
||||
" -> d12\n" +
|
||||
" -> f12.2\n" +
|
||||
" <- f12.2\n" +
|
||||
" <- d12\n" +
|
||||
" <- d1\n" +
|
||||
" -> d2\n" +
|
||||
" -> f2.1\n" +
|
||||
" <- f2.1\n" +
|
||||
" -> f2.2\n" +
|
||||
" <- f2.2\n" +
|
||||
" <- d2\n" +
|
||||
"<- /\n");
|
||||
}
|
||||
|
||||
private static class AbortException extends RuntimeException { }
|
||||
|
||||
private static void doTest(@Nullable final Function<VirtualFile, Object> condition,
|
||||
@Nullable final Function<VirtualFile, Iterable<VirtualFile>> iterable,
|
||||
@NotNull String expected,
|
||||
VirtualFileVisitor.Option... options) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
try {
|
||||
VfsUtilCore.visitChildrenRecursively(myRoot, new VirtualFileVisitor(options) {
|
||||
private int level = 0;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Result visitFileEx(@NotNull VirtualFile file) {
|
||||
sb.append(StringUtil.repeat(" ", level++)).append("-> ").append(file.getName()).append('\n');
|
||||
|
||||
if (condition != null) {
|
||||
Object result = condition.fun(file);
|
||||
if (result instanceof Result) return (Result)result;
|
||||
if (result instanceof VirtualFile) return skipTo((VirtualFile)result);
|
||||
}
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterChildrenVisited(@NotNull VirtualFile file) {
|
||||
sb.append(StringUtil.repeat(" ", --level)).append("<- ").append(file.getName()).append('\n');
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Iterable<VirtualFile> getChildrenIterable(@NotNull VirtualFile file) {
|
||||
return iterable != null ? iterable.fun(file) : super.getChildrenIterable(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (AbortException ignore) { }
|
||||
|
||||
assertEquals(expected, sb.toString());
|
||||
}
|
||||
|
||||
private static MockVirtualFile dir(@NotNull String name, MockVirtualFile... children) {
|
||||
final MockVirtualFile root = new MockVirtualFile(true, name);
|
||||
for (MockVirtualFile child : children) {
|
||||
root.addChild(child);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
private static MockVirtualFile file(@NotNull String name) {
|
||||
return new MockVirtualFile(name);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -389,7 +389,7 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
|
||||
}));
|
||||
|
||||
final Set<String> actualSet = new HashSet<String>();
|
||||
VfsUtilCore.visitChildrenRecursively(vDir, new VirtualFileVisitor(true) {
|
||||
VfsUtilCore.visitChildrenRecursively(vDir, new VirtualFileVisitor() {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
actualSet.add(file.getPath());
|
||||
|
||||
+6
-24
@@ -13,38 +13,20 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.intellij.openapi.roots.impl;
|
||||
|
||||
import com.intellij.openapi.roots.ContentIterator;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileFilter;
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FileIndexImplUtil {
|
||||
private FileIndexImplUtil() {
|
||||
private FileIndexImplUtil() { }
|
||||
|
||||
public static boolean iterateRecursively(@NotNull final VirtualFile root,
|
||||
@NotNull final VirtualFileFilter filter,
|
||||
@NotNull final ContentIterator iterator) {
|
||||
return VfsUtilCore.iterateChildrenRecursively(root, filter, iterator);
|
||||
}
|
||||
|
||||
public static boolean iterateRecursively(@NotNull final VirtualFile root, @NotNull final VirtualFileFilter filter, @NotNull final ContentIterator iterator){
|
||||
|
||||
try {
|
||||
VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
if (!file.isValid() || !filter.accept(file)) return false;
|
||||
|
||||
if (!iterator.processFile(file)) throw new StopItException();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
catch (StopItException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class StopItException extends RuntimeException {}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public class MockVirtualFile extends VirtualFile {
|
||||
private final List<VirtualFile> myChildren = new SmartList<VirtualFile>();
|
||||
private String myText;
|
||||
private final MockVirtualFileSystem myFileSystem = new MockVirtualFileSystem();
|
||||
private boolean myIsWritable = true;
|
||||
private long myModStamp = LocalTimeCounter.currentTime();
|
||||
|
||||
public MockVirtualFile(final String name) {
|
||||
@@ -73,11 +74,15 @@ public class MockVirtualFile extends VirtualFile {
|
||||
@Override
|
||||
public VirtualFile createChildData(final Object requestor, @NotNull @NonNls final String name) {
|
||||
final MockVirtualFile file = new MockVirtualFile(name);
|
||||
file.setParent(this);
|
||||
myChildren.add(file);
|
||||
addChild(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
public void addChild(@NotNull final MockVirtualFile child) {
|
||||
child.setParent(this);
|
||||
myChildren.add(child);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public VirtualFileSystem getFileSystem() {
|
||||
@@ -90,11 +95,11 @@ public class MockVirtualFile extends VirtualFile {
|
||||
return prefix + "/" + myName;
|
||||
}
|
||||
|
||||
private boolean myIsWritable = true;
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return myIsWritable;
|
||||
}
|
||||
|
||||
public void setWritable(boolean b) {
|
||||
myIsWritable = b;
|
||||
}
|
||||
@@ -117,7 +122,7 @@ public class MockVirtualFile extends VirtualFile {
|
||||
|
||||
@Override
|
||||
public VirtualFile[] getChildren() {
|
||||
return VfsUtil.toVirtualFileArray(myChildren);
|
||||
return VfsUtilCore.toVirtualFileArray(myChildren);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,16 +166,6 @@ public class MockVirtualFile extends VirtualFile {
|
||||
|
||||
@Override
|
||||
public void refresh(boolean asynchronous, boolean recursive, Runnable postRunnable) {
|
||||
|
||||
}
|
||||
|
||||
private long myActualTimeStamp = myTimeStamp;
|
||||
public void setActualTimeStamp(long actualTimeStamp) {
|
||||
myActualTimeStamp = actualTimeStamp;
|
||||
}
|
||||
|
||||
public long getActualTimeStamp() {
|
||||
return myActualTimeStamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -191,6 +186,4 @@ public class MockVirtualFile extends VirtualFile {
|
||||
myListener.contentsChanged(new VirtualFileEvent(requestor, this, null, oldStamp, myModStamp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -127,6 +127,21 @@ public class ContainerUtilRt {
|
||||
return 5 + size + size / 5;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> Stack<T> newStack() {
|
||||
return new Stack<T>();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> Stack<T> newStack(Collection<T> initial) {
|
||||
return new Stack<T>(initial);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> Stack<T> newStack(T... initial) {
|
||||
return new Stack<T>(Arrays.asList(initial));
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized toArray() as opposed to the {@link java.util.Collections#emptyList()}.
|
||||
*/
|
||||
|
||||
+7
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,14 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package com.intellij.util.containers;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A drop-in replacement for {@link java.util.Stack} based on {@link java.util.ArrayList} (instead of {@link java.util.Vector})
|
||||
* and therefore is (1) not synchronized and (2) faster.
|
||||
*
|
||||
* @author max
|
||||
*/
|
||||
public class Stack<T> extends ArrayList<T> {
|
||||
public Stack(int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
@@ -1490,6 +1490,21 @@ public class ContainerUtil extends ContainerUtilRt {
|
||||
return list;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> Stack<T> newStack() {
|
||||
return ContainerUtilRt.newStack();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> Stack<T> newStack(Collection<T> initial) {
|
||||
return ContainerUtilRt.newStack(initial);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> Stack<T> newStack(T... initial) {
|
||||
return ContainerUtilRt.newStack(initial);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> List<T> emptyList() {
|
||||
return ContainerUtilRt.emptyList();
|
||||
|
||||
@@ -165,29 +165,24 @@ public class VcsRootIterator {
|
||||
}
|
||||
|
||||
public void iterate() {
|
||||
class StopIterationException extends RuntimeException { }
|
||||
|
||||
try {
|
||||
VfsUtilCore.visitChildrenRecursively(myRoot, new VirtualFileVisitor(false) {
|
||||
@Override
|
||||
public void afterChildrenVisited(@NotNull VirtualFile file) {
|
||||
if (myDirectoryFilter != null) {
|
||||
myDirectoryFilter.afterChildrenVisited(file);
|
||||
}
|
||||
VfsUtilCore.visitChildrenRecursively(myRoot, new VirtualFileVisitor(VirtualFileVisitor.NO_FOLLOW_SYMLINKS) {
|
||||
@Override
|
||||
public void afterChildrenVisited(@NotNull VirtualFile file) {
|
||||
if (myDirectoryFilter != null) {
|
||||
myDirectoryFilter.afterChildrenVisited(file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
if (isExcluded(myExcludedFileIndex, file)) return false;
|
||||
if (myRootPresentFilter != null && ! myRootPresentFilter.accept(file)) return false;
|
||||
if (myProject.isDisposed() || ! process(file)) throw new StopIterationException();
|
||||
if (myDirectoryFilter != null && file.isDirectory() && ! myDirectoryFilter.shouldGoIntoDirectory(file)) return false;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} catch (StopIterationException e) {
|
||||
//
|
||||
}
|
||||
@NotNull
|
||||
@Override
|
||||
public Result visitFileEx(@NotNull VirtualFile file) {
|
||||
if (isExcluded(myExcludedFileIndex, file)) return SKIP_CHILDREN;
|
||||
if (myRootPresentFilter != null && ! myRootPresentFilter.accept(file)) return SKIP_CHILDREN;
|
||||
if (myProject.isDisposed() || ! process(file)) return skipTo(myRoot);
|
||||
if (myDirectoryFilter != null && file.isDirectory() && ! myDirectoryFilter.shouldGoIntoDirectory(file)) return SKIP_CHILDREN;
|
||||
return CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean process(VirtualFile current) {
|
||||
|
||||
Reference in New Issue
Block a user