方寸:基于 Rust 与 egui 的桌面文件管理器项目

Windows 优先的桌面文件管理器:双窗格、标签、Everything 搜索与安全移动|作者个人站:https://softwarescience.top/projects/tessera

分支1Tags1
文件最后提交记录最后更新时间
15 天前
22 天前
22 天前
22 天前
22 天前
22 天前
22 天前
15 天前
22 天前

Tessera 方寸

作者个人站:https://softwarescience.top/ · 本项目主页:https://softwarescience.top/projects/tessera(版本、截图与下载都在那儿)

1. 定位

一个 Rust + egui / GPUIKit 的桌面文件管理器,Windows 优先,跨平台降级。核心能力:

  • 多收藏夹、嵌套收藏夹、重命名
  • 给真实文件夹、收藏夹、虚拟集合打标签
  • Everything 外接搜索 + 内置搜索兜底
  • 主题系统
  • 文件夹对比
  • 文件夹安全移动
  • Directory Opus 风格高级能力:双窗格、标签页、批量重命名、操作队列、命令面板、脚本等

UI 层建议抽象一层 UiFacade,如果 GPUIKit 是 egui 封装则直接复用;如果不是,则做适配层,避免业务代码绑死具体 UI 库。


2. 总体架构

tessera/
  main.rs
  app.rs
  ui/
    panes.rs         双窗格
    sidebar.rs       收藏夹/标签/驱动器
    search.rs        搜索面板
    compare.rs       文件夹对比
    settings.rs      设置
    theme.rs         主题
    widgets.rs       通用组件
  core/
    model.rs
    favorite.rs      收藏夹模型
    tag.rs           标签模型
    query.rs         搜索查询
    operation.rs     文件操作模型
  services/
    fs.rs            文件系统抽象
    search/
      mod.rs         SearchProvider trait
      everything.rs  Everything 集成
      internal.rs    内置搜索
    index/
      mod.rs
      usn.rs         Windows USN Journal
      walker.rs      跨平台扫描
      store.rs       SQLite FTS5 / Tantivy
    compare.rs       文件夹对比
    mover.rs         文件夹移动
    theme.rs         主题加载
    opus.rs          Opus 风格能力
    plugin.rs        插件/脚本
  infra/
    config.rs        TOML 配置
    db.rs            SQLite
    logging.rs       tracing
    ipc.rs          进程间通信

核心原则:

  • UI 不直接做重 IO
  • 所有扫描、对比、移动、哈希走后台任务
  • 搜索、索引、标签、主题都可替换
  • 文件操作有队列、进度、取消、撤销日志

3. 数据模型

用 SQLite 存收藏夹、标签、索引和操作历史。配置用 TOML。

收藏夹

收藏夹是虚拟文件夹,可以嵌套、重命名、排序。

favorites(
  id INTEGER PRIMARY KEY,
  parent_id INTEGER,
  name TEXT NOT NULL,
  kind TEXT,          -- folder / query / tag_filter / smart
  path TEXT,          -- 真实路径,可为空
  query_json TEXT,    -- 虚拟收藏夹查询
  icon TEXT,
  color TEXT,
  sort_order INTEGER,
  created_at INTEGER,
  updated_at INTEGER
)

标签

tags(
  id INTEGER PRIMARY KEY,
  name TEXT UNIQUE,
  color TEXT,
  parent_id INTEGER,
  icon TEXT
)

tag_assignments(
  id INTEGER PRIMARY KEY,
  tag_id INTEGER,
  target_type TEXT,   -- file / folder / favorite
  target_path TEXT,
  target_id TEXT,     -- volume_serial + file_id,用于跟踪移动
  created_at INTEGER
)

关键点:给真实文件/文件夹打标签时,不要只存路径。Windows 下存 volume_serial + file_id,路径变化后还能尽量追踪。

索引表

entries(
  id INTEGER PRIMARY KEY,
  path TEXT,
  name TEXT,
  ext TEXT,
  size INTEGER,
  mtime INTEGER,
  is_dir INTEGER,
  volume TEXT,
  file_id TEXT,
  usn INTEGER
)

entries_fts USING fts5(name, path, ext, content='entries')

4. 搜索设计

核心接口:

pub trait SearchProvider: Send + Sync {
    fn id(&self) -> &'static str;
    fn detect(&self) -> Availability;
    fn search(
        &self,
        query: SearchQuery,
        cancel: CancellationToken,
    ) -> Result<SearchResultStream, SearchError>;
}

Everything 外接

启动时自动检测:

  • 注册表:HKCU/HKLM\Software\voidtools\Everything
  • 安装目录:C:\Program Files\Everything
  • 进程:Everything.exe
  • 服务:Everything
  • es.exe
  • Everything64.dll

检测结果存到配置:

[search.everything]
last_detected = false
prefer_everything = true
dll_path = "C:\\Program Files\\Everything\\Everything64.dll"

如果上次未安装、这次检测到已安装,就弹通知:

检测到 Everything 已安装,是否切换为 Everything 搜索?

集成方式优先级:

  1. 动态加载 Everything64.dll
  2. Everything IPC
  3. es.exe 命令行 fallback

SDK 调用大致:

  • Everything_SetSearchW
  • Everything_QueryW
  • Everything_GetNumResults
  • Everything_GetResultFullPathNameW
  • Everything_GetResultSize
  • Everything_GetResultDateModified

结果流式返回,UI 用虚拟列表,避免一次性渲染大量结果。

内置搜索

没有 Everything 时使用内置能力:

  • Windows:可选 USN Journal / MFT 快速索引,需要权限时降级
  • 跨平台:jwalk / walkdir 扫描 + notify 增量更新
  • 查询:SQLite FTS5,后续可换 Tantivy
  • 索引根目录可配置,避免全盘扫描
  • 支持语法:ext:rs size:>10mb tag:重要 path:project 正则
  • 搜索面板可把结果保存为“虚拟收藏夹”

5. 文件夹对比

输入两个目录 A / B,后台扫描生成相对路径映射。

差异类型:

  • OnlyLeft
  • OnlyRight
  • NewerLeft
  • NewerRight
  • SizeDiff
  • ContentDiff
  • Same

策略:

  1. 先比路径、大小、mtime
  2. 需要时再算 BLAKE3 哈希
  3. 大目录用 rayon 并行
  4. UI 三栏:左目录、右目录、差异列表
  5. 支持操作:复制到右、复制到左、移动、删除、跳过

对比结果可导出 CSV / JSON。


6. 文件夹移动

所有移动进入操作队列。

pub enum MoveStrategy {
    SameVolumeRename,
    CrossVolumeCopyDelete,
}

pub struct MoveJob {
    pub sources: Vec<PathBuf>,
    pub target_dir: PathBuf,
    pub conflict: ConflictPolicy,
    pub verify: VerifyMode,
}

规则:

  • 同卷:rename
  • 跨卷:copy + fsync + verify + delete
  • 冲突:跳过 / 覆盖 / 自动重命名 / 询问
  • 校验:大小 + mtime,可选 BLAKE3
  • 支持暂停、取消、重试
  • 保留撤销日志,尽量支持撤销

7. 主题系统

主题用 TOML/JSON 定义,支持热加载。

name = "Dark+"
accent = "#4c8bf5"
bg = "#1e1e1e"
panel = "#252526"
text = "#d4d4d4"
radius = 6.0
density = "compact"
font = "Microsoft YaHei UI"
icon_theme = "fluent"

内置:

  • Light
  • Dark
  • High Contrast
  • Solarized
  • 用户自定义主题

主题只影响 UI 样式,不影响业务逻辑。


8. Opus 风格能力

如果指 Directory Opus 风格,建议做:

  • 双窗格
  • 多标签页
  • 收藏栏
  • 批量重命名:正则、模板、编号、扩展名替换
  • 文件操作队列
  • 过滤器:通配符、正则、标签、大小、日期
  • 颜色规则:按扩展名、标签、大小着色
  • 命令面板:Ctrl+Shift+P
  • 自定义快捷键
  • 同步浏览
  • 扁平视图
  • 元数据列
  • 脚本:Rhai 或 Lua
  • 自定义按钮 / 工具栏

如果指 Opus 音频,则加插件:

  • lofty 读元数据
  • symphonia 解码
  • opus 编码/转码
  • 音频预览、批量转码、标签编辑

9. UI 布局

┌──────────────────────────────────────────────┐
│ 标签页 | 地址栏 | 搜索框 | 命令面板          │
├──────────┬──────────────────┬────────────────┤
│ 收藏夹树 │ 左窗格           │ 右窗格         │
│ 标签过滤 │ 文件列表         │ 文件列表       │
│ 驱动器   │                  │                │
├──────────┴──────────────────┴────────────────┤
│ 状态栏 | 操作队列 | 进度 | 索引状态          │
└──────────────────────────────────────────────┘

搜索、对比、设置用独立窗口或侧边面板。


10. 技术栈

  • Rust 2021/2024
  • egui / eframe 或 GPUIKit
  • tokio:后台 IO / IPC
  • rayon:并行扫描、哈希
  • rusqlite + FTS5:本地数据
  • serde + toml:配置
  • notify:文件监控
  • blake3:哈希
  • tracing:日志
  • windows crate:Windows API
  • libloading:动态加载 Everything DLL
  • thiserror / anyhow:错误

11. 路线图

  1. MVP:双窗格、文件列表、收藏夹、标签、主题、内置搜索
  2. Everything 检测与集成、操作队列、文件夹移动
  3. 文件夹对比、批量重命名、命令面板
  4. 脚本插件、USN 索引、跨平台搜索优化

12. 主要风险

  • Everything SDK 许可和 32/64 位问题
  • Windows 权限:USN/MFT 可能需要管理员
  • 标签跟踪:文件移动后路径失效,需要 file_id
  • egui 大列表性能:必须虚拟化
  • 跨平台搜索能力差异大
  • 文件操作安全:移动、覆盖、删除必须有校验和撤销日志

13. 工程与使用(实现说明)

本仓库已是可编译运行的 Rust 工程:cargo build 通过、cargo clippy --all-targets 零警告、cargo test 181 项全绿, 设计按上述各节落地,模块划分与 §2 一一对应。

13.1 实际目录结构

src/
  main.rs        入口:GUI / 无头索引 / 无头搜索 / 自检
  app.rs         Services 装配、AppState、UiCommand 派发与 UiEvent 回灌
  lib.rs         库入口(集成测试引用)
  core/          model / query / operation / favorite / tag
  infra/         config(TOML) / db(SQLite+FTS5 迁移) / logging / ipc(单实例+回环总线)
  services/      fs / search{everything,internal} / index{walker,usn,store}
                 compare / mover / theme / opus / plugin(Rhai)
  ui/            widgets / panes / sidebar / search / compare / settings / theme / opus
tests/end_to_end.rs   跨模块集成测试(索引→搜索→对比→队列→撤销)

13.2 命令

cargo build                                  # 构建
cargo test                                   # 全部测试
cargo clippy --all-targets                   # 静态检查
cargo run -- .                               # 启动界面(可带起始路径)
cargo run -- --index D:\some\tree            # 无头:把目录加入索引根并建索引
cargo run -- --search "ext:rs size:>10mb tag:重要"   # 无头:用内置索引搜索
cargo run -- --selftest                      # 端到端自检(配置/DB/收藏夹/标签/索引/对比/移动/重命名/主题)

13.3 数据落盘位置

内容 路径
配置(TOML) %APPDATA%\CoderLife\Tessera\config\config.toml
主库(收藏夹/标签/操作历史/撤销日志) %APPDATA%\CoderLife\Tessera\data\tessera.db
索引库(entries + entries_fts) %APPDATA%\CoderLife\Tessera\data\index.db
日志 %APPDATA%\CoderLife\Tessera\data\logs\tessera.log
用户主题 / 脚本 …\config\themes\*.toml、…\config\scripts\*.rhai

13.4 实现取舍与当前边界

项 现状
Everything 六级探测(注册表 HKCU/HKLM、安装目录、进程、服务、es.exe、Everything64.dll)与三档集成(DLL → IPC → es.exe)已实现;开发机未安装 Everything,只在真机验证了"探测如实返回不可用 + 自动降级到内置搜索"
内置索引 jwalk 遍历 + SQLite FTS5;USN Journal 后端(FSCTL_ENUM_USN_DATA)已实现,无管理员权限时按 §4 降级为目录遍历
MFT 直读 未实现(§4 标为可选),IndexBackend 只保留已实现的后端
删除 默认送 Windows 回收站(SHFileOperationW + FOF_ALLOWUNDO,可用「Shift+Delete」显式永久删除);回收站不可用时降级为永久删除并在状态栏说明
剪贴板 程序内部剪贴板:复制 / 剪切 / 粘贴,可跨窗格(不碰系统剪贴板,避免误伤用户内容)
新建 F7 / 右键「新建文件夹」「新建文本文件」,重名自动加序号,建完直接进入行内重命名
拖拽 跨窗格拖拽传输:直接拖=移动,按住 Ctrl 拖=复制(源/目标重叠时会拒绝并提示)
属性 Alt+Enter 打开属性窗口:名称/路径/类型/时间/卷/标签/文件身份 + 目录占用统计(后台线程,可重算)
对比同步 七种动作齐全;嵌套差异按"最浅差异祖先"折叠后整目录传输,避免平铺进目标根目录丢结构
撤销 移动/重命名写 undo_log 可撤销;复制不进撤销日志(复制没有"还原"语义)
标签追踪 绑定 volume_serial + file_id;文件在卷内移动/改名后按身份找回并自动修正缓存路径
UI egui/eframe 0.36;文件表、搜索结果、对比结果、重命名预览、命令面板全部走 ScrollArea::show_rows 虚拟化
列宽 表头分隔线可拖拽调整并持久化到 [ui.column_widths];窄窗格按 标签 → 时间 → 大小 的顺序让位,窗格底栏有「重置列宽」

13.5 界面与交互

  • 视觉方向:Fluent / Windows 11 资源管理器风格——分层背景(窗口底 / 面板 / 卡片三档)、30px 行高、斑马纹 + 悬停反馈、胶囊选中态、扁平图标按钮;保留 Directory Opus 式的双窗格与"活动窗格"强调。
  • 设计系统只有一处来源:src/ui/design.rs(颜色/圆角/间距/字号令牌 + 全部基础组件,含右键菜单组件)与 src/ui/icons.rs(31 个 Painter 矢量图标,不依赖字体,避免缺字形出现豆腐块);services/theme.rs 把主题映射成 egui 的 Visuals/Spacing/TextStyles。界面代码里不再出现 ui.button / selectable_label / ui.separator() 这类默认控件。
  • 视觉验证流程:启动程序 → 强制置顶后截取窗口 → 送本地 Qwen3-VL(D:\Develop\workspace\videotest 的 llama-server @127.0.0.1:8098)做设计评审 → 按评审与自查看图逐条修;交互类改动用合成鼠标(悬停扫掠 / 右键 / 拖拽)做冒烟,再复查截图与配置文件。

13.6 键盘

键 作用 键 作用
↑ / ↓ 移动选中行 Enter 打开(目录进入 / 文件用默认程序)
Backspace 上一级 F2 重命名(行内)
F5 复制到对侧窗格 F6 移动到对侧窗格
F7 新建文件夹 Alt+Enter 属性
Delete 送回收站 Shift+Delete 永久删除
Ctrl+A 全选(当前窗格可见行) Ctrl+C / Ctrl+X / Ctrl+V 复制 / 剪切 / 粘贴
Ctrl+R 刷新活动窗格 Ctrl+←/→ 切换活动窗格
Ctrl+H 显示/隐藏隐藏文件 Ctrl+F 或 F3 搜索面板
Ctrl+T / Ctrl+W 新建 / 关闭标签页 Ctrl+Z 撤销上一次移动/重命名
Ctrl+Shift+P 命令面板 Ctrl+Shift+N 新建文件夹(同 F7)
Esc 清空选择 / 关闭浮层 Ctrl+Q 退出

文本框获得焦点时不会抢按键(否则在过滤框里按 Delete 会删文件)。

13.7 元信息

项 值
开发者 CodeLife leon、omp
项目标识 top.softwarescience.Tessera(包元数据、任务栏分组;配置与数据目录也归在这个命名空间下)
图标 assets/icon.svg(含背景浅色字母 G 的阴影形态)+ assets/icon-small.svg(16/24/32px 简化版);assets/tessera.ico 为多尺寸成品,assets/icon-128.rgba 供运行时窗口图标,assets/tessera.rc 把它们与版本信息编进 exe
许可 木兰宽松许可证,第 2 版(MulanPSL-2.0,见 LICENSE)
仓库 git@gitcode.com:CoderLife/Tessera.git
版本 见 Cargo.toml 的 version(同时用于窗口标题)

最终建议:项目名用 Tessera / 方寸,先做 Windows 优先的 MVP,把“收藏夹 + 标签 + 搜索提供者 + 操作队列”打牢,再叠加 Everything、对比和 Opus 风格高级能力。

关于

这个项目由 CodeLife Leon 独立开发与维护。更多项目、各项目发版信息、赞赏与联系方式都在个人站:

问题反馈与需求建议:优先在仓库提 Issue,也可以邮件 virgil_lgp@163.com。

项目介绍

Windows 优先的桌面文件管理器:双窗格、标签、Everything 搜索与安全移动|作者个人站:https://softwarescience.top/projects/tessera

https://softwarescience.top/projects/tessera定制我的领域