Initial commit: FluidExplorer:从零实现的 WinUI 3 文件资源管理器替代品(Mica、命令栏、面包屑)

This commit is contained in:
WpyQwq
2026-09-19 11:54:03 +08:00
commit 5780fde61a
60 changed files with 15035 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
namespace FluidExplorer.Services.Search;
public enum IndexState
{
NotStarted,
RequiresElevation,
Building,
Ready,
Watching,
Failed,
Stopped
}
/// <summary>索引里的一条记录(NTFS USN 数据的最小集合)。</summary>
public readonly record struct IndexedEntry(
ulong Frn,
ulong ParentFrn,
string Name,
bool IsDirectory,
long Size,
DateTime ModifiedUtc,
uint Attributes)
{
/// <summary>非 NTFS / 非索引来源(例如回退扫描器)可直接携带完整路径。</summary>
public string? FullPath { get; init; }
public string Extension
{
get
{
if (IsDirectory) return string.Empty;
var i = Name.LastIndexOf('.');
return i > 0 && i < Name.Length - 1 ? Name[(i + 1)..] : string.Empty;
}
}
}
public sealed class IndexStateChangedEventArgs(IndexState state, string? message = null) : EventArgs
{
public IndexState State { get; } = state;
public string? Message { get; } = message;
}
/// <summary>
/// 单卷文件索引:Everything 式体验的核心。
/// 实现必须做到:构建阶段不阻塞调用线程(内部自行使用线程池)、
/// 支持增量更新(USN 日志)、查询使用并行扫描并在毫秒级返回。
/// </summary>
public interface IFileIndex
{
/// <summary>卷根,例如 "C:\"。</summary>
string VolumeRoot { get; }
IndexState State { get; }
long EntryCount { get; }
event EventHandler<IndexStateChangedEventArgs>? StateChanged;
/// <summary>建立初始索引(枚举 MFT / 扫描)。可重复调用,完成后自动转入 Watching。</summary>
Task BuildAsync(IProgress<double>? progress, CancellationToken cancellationToken);
/// <summary>启动增量监听(USN journal),保持索引实时。</summary>
void StartWatching();
void Stop();
/// <summary>
/// 查询。实现约定:
/// 1) 先按 IncludeTerms/Extensions/大小/时间/属性过滤(纯内存操作,必须并行化);
/// 2) 仅当 <see cref="SearchQuery.PathFilter"/> 不为空时,才对已命中的候选调用路径解析;
/// 3) 命中数达到 maxResults 即可提前返回,但不要漏掉更"好"的匹配(短名优先)。
/// </summary>
IEnumerable<IndexedEntry> Query(SearchQuery query, int maxResults, CancellationToken cancellationToken);
/// <summary>把 FRN 解析为完整路径(内部要缓存父链解析结果)。失败返回 false。</summary>
bool TryResolvePath(ulong frn, out string fullPath);
}