diff --git a/platform/core-nio-fs/src/com/intellij/platform/core/nio/fs/BasicFileAttributesHolder2.java b/platform/core-nio-fs/src/com/intellij/platform/core/nio/fs/BasicFileAttributesHolder2.java
index 13273c63c8d7..e97ed8628668 100644
--- a/platform/core-nio-fs/src/com/intellij/platform/core/nio/fs/BasicFileAttributesHolder2.java
+++ b/platform/core-nio-fs/src/com/intellij/platform/core/nio/fs/BasicFileAttributesHolder2.java
@@ -6,10 +6,14 @@ import org.jetbrains.annotations.Nullable;
import sun.nio.fs.BasicFileAttributesHolder;
import java.lang.ref.WeakReference;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
/**
* This interface allows not adding `--add-exports` to modules where some class implements {@link BasicFileAttributesHolder}.
+ *
+ * Also, this interface defines some hacks and helper methods related to {@link BasicFileAttributesHolder}.
*/
public interface BasicFileAttributesHolder2 extends BasicFileAttributesHolder {
/**
@@ -47,4 +51,30 @@ public interface BasicFileAttributesHolder2 extends BasicFileAttributesHolder {
myCachedAttributes.clear();
}
}
+
+ static @Nullable BasicFileAttributes getAttributesFromHolder(@NotNull Path path) {
+ if (path instanceof BasicFileAttributesHolder bafh) {
+ return bafh.get();
+ }
+ return null;
+ }
+
+ /**
+ * A marker interface for {@link java.nio.file.spi.FileSystemProvider#newDirectoryStream}
+ * that advises the file system to fetch file attributes and fill {@link BasicFileAttributesHolder}, if it's supported.
+ *
+ * Unlike many other methods in {@code FileSystemProvider}, {@code newDirectoryStream} doesn't accept a set of options.
+ * The easiest way to provide additional information to the method is through the filter argument.
+ *
+ * A file system provider should support this feature explicitly.
+ * This interface has no effect on default filesystems from JDK:
+ *
+ * - In the default file system on Windows, file attributes are always fetched, regardless of the filter argument.
+ * - In the default file system on Posix, file attributes are never fetched.
+ *
+ */
+ @FunctionalInterface
+ interface FetchAttributesFilter extends DirectoryStream.Filter {
+ FetchAttributesFilter ACCEPT_ALL = path -> true;
+ }
}
diff --git a/platform/ijent/impl/src/com/intellij/platform/ijent/community/impl/nio/IjentNioFileSystemProvider.kt b/platform/ijent/impl/src/com/intellij/platform/ijent/community/impl/nio/IjentNioFileSystemProvider.kt
index cfe95c5e8db8..b13e49c839cc 100644
--- a/platform/ijent/impl/src/com/intellij/platform/ijent/community/impl/nio/IjentNioFileSystemProvider.kt
+++ b/platform/ijent/impl/src/com/intellij/platform/ijent/community/impl/nio/IjentNioFileSystemProvider.kt
@@ -2,6 +2,7 @@
package com.intellij.platform.ijent.community.impl.nio
import com.intellij.openapi.diagnostic.thisLogger
+import com.intellij.platform.core.nio.fs.BasicFileAttributesHolder2.FetchAttributesFilter
import com.intellij.platform.ijent.community.impl.IjentFsResultImpl
import com.intellij.platform.ijent.community.impl.nio.IjentNioFileSystemProvider.Companion.newFileSystemMap
import com.intellij.platform.ijent.community.impl.nio.IjentNioFileSystemProvider.UnixFilePermissionBranch.*
@@ -180,23 +181,34 @@ class IjentNioFileSystemProvider : FileSystemProvider() {
val nioFs = dir.nioFs
return fsBlocking {
- val children = nioFs.ijentFs
- .listDirectoryWithAttrs(ensurePathIsAbsolute(dir.ijentPath), IjentFileSystemApi.SymlinkPolicy.DO_NOT_RESOLVE)
- .getOrThrowFileSystemException()
-
- val nioPathList = children.asSequence()
- .map { (childName, childStat) ->
- val childIjentPath = dir.ijentPath.getChild(childName).getOrThrow()
- val childAttrs = when (childStat) {
- is IjentPosixFileInfo -> IjentNioPosixFileAttributes(childStat)
- is IjentWindowsFileInfo -> TODO()
- }
- IjentNioPath(childIjentPath, nioFs, childAttrs)
+ val notFilteredPaths =
+ if (pathFilter is FetchAttributesFilter) {
+ nioFs.ijentFs
+ .listDirectoryWithAttrs(ensurePathIsAbsolute(dir.ijentPath), IjentFileSystemApi.SymlinkPolicy.DO_NOT_RESOLVE)
+ .getOrThrowFileSystemException()
+ .asSequence()
+ .map { (childName, childStat) ->
+ val childIjentPath = dir.ijentPath.getChild(childName).getOrThrow()
+ val childAttrs = when (childStat) {
+ is IjentPosixFileInfo -> IjentNioPosixFileAttributes(childStat)
+ is IjentWindowsFileInfo -> TODO()
+ }
+ IjentNioPath(childIjentPath, nioFs, childAttrs)
+ }
}
- .filter { nioPath ->
- pathFilter?.accept(nioPath) != false
+ else {
+ nioFs.ijentFs
+ .listDirectory(ensurePathIsAbsolute(dir.ijentPath))
+ .getOrThrowFileSystemException()
+ .asSequence()
+ .map { childName ->
+ val childIjentPath = dir.ijentPath.getChild(childName).getOrThrow()
+ IjentNioPath(childIjentPath, nioFs, null)
+ }
}
- .toMutableList()
+ val nioPathList = notFilteredPaths.filterTo(mutableListOf()) { nioPath ->
+ pathFilter?.accept(nioPath) != false
+ }
object : DirectoryStream {
// The compiler doesn't (didn't?) allow to relax types here.
diff --git a/platform/platform-impl/src/com/intellij/execution/wsl/ijent/nio/IjentWslNioFileSystemProvider.kt b/platform/platform-impl/src/com/intellij/execution/wsl/ijent/nio/IjentWslNioFileSystemProvider.kt
index 8ab53ec95546..00bb9e263624 100644
--- a/platform/platform-impl/src/com/intellij/execution/wsl/ijent/nio/IjentWslNioFileSystemProvider.kt
+++ b/platform/platform-impl/src/com/intellij/execution/wsl/ijent/nio/IjentWslNioFileSystemProvider.kt
@@ -6,6 +6,8 @@ import com.intellij.execution.wsl.WslPath
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.util.io.CaseSensitivityAttribute
import com.intellij.openapi.util.io.FileAttributes
+import com.intellij.platform.core.nio.fs.BasicFileAttributesHolder2
+import com.intellij.platform.core.nio.fs.BasicFileAttributesHolder2.FetchAttributesFilter
import com.intellij.platform.core.nio.fs.RoutingAwareFileSystemProvider
import com.intellij.platform.ijent.IjentPosixInfo
import com.intellij.platform.ijent.community.impl.nio.IjentNioPath
@@ -315,11 +317,9 @@ class IjentWslNioFileSystemProvider(
lastDirectory = lastDirectory.parent
}
- // TODO Add BasicFileAttributesHolder, it gives a huge speed up.
- //val stat =
- // source.asSafely()?.get()
- // ?: source.readAttributes(LinkOption.NOFOLLOW_LINKS)
- val stat = source.readAttributes(LinkOption.NOFOLLOW_LINKS)
+ val stat =
+ BasicFileAttributesHolder2.getAttributesFromHolder(source)
+ ?: source.readAttributes(LinkOption.NOFOLLOW_LINKS)
// WindowsPath doesn't support resolve() from paths of different class.
val target = source.relativeTo(sourceRoot).fold(targetRoot) { parent, file ->
@@ -337,7 +337,7 @@ class IjentWslNioFileSystemProvider(
throw err
}
}
- Files.newDirectoryStream(source).use { children ->
+ source.fileSystem.provider().newDirectoryStream(source, FetchAttributesFilter.ACCEPT_ALL).use { children ->
sourceStack.addAll(children.toList().asReversed())
}
}
diff --git a/platform/platform-impl/src/com/intellij/util/io/PlatformNioHelper.java b/platform/platform-impl/src/com/intellij/util/io/PlatformNioHelper.java
index 152cba2c0769..3ad07b8f24dd 100644
--- a/platform/platform-impl/src/com/intellij/util/io/PlatformNioHelper.java
+++ b/platform/platform-impl/src/com/intellij/util/io/PlatformNioHelper.java
@@ -2,6 +2,7 @@
package com.intellij.util.io;
import com.intellij.openapi.util.io.NioFiles;
+import com.intellij.platform.core.nio.fs.BasicFileAttributesHolder2.FetchAttributesFilter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,7 +41,7 @@ public final class PlatformNioHelper {
@SuppressWarnings({"UnnecessaryFullyQualifiedName", "InstanceofIncompatibleInterface"})
public static void visitDirectory(@NotNull Path directory, @Nullable Set filter, @NotNull BiPredicate> consumer)
throws IOException, SecurityException {
- try (var dirStream = Files.newDirectoryStream(directory)) {
+ try (var dirStream = directory.getFileSystem().provider().newDirectoryStream(directory, FetchAttributesFilter.ACCEPT_ALL)) {
for (var path : dirStream) {
if (filter != null && !filter.contains(path.getFileName().toString())) {
continue;