Foam Smart Folders 完全指南:用保存的查询在 VS Code 侧边栏打造动态笔记视图

原创2026-09-20 13:21:42146 阅读
文章标签:知识管理知识库开发工具MCP 服务

Foam Smart Folders 完全指南:用保存的查询在 VS Code 侧边栏打造动态笔记视图

导读

Smart Folders(智能文件夹)是 Foam 在 VS Code 资源管理器中呈现"已保存查询"的方式:每个智能文件夹都是一个存放在 .foam/queries/<id>.yaml 下的查询文件,按需实时执行并把匹配到的笔记以树形或列表形式展示在侧边栏。本文将以 docs/user/features/smart-folders.md 为核心,结合 foam-vscode 与 foam-core 的源码实现,系统讲解智能文件夹的创建、编辑、删除、视图选项,以及底层查询语法与存储机制,帮助你在大规模工作区中摆脱僵化的标签层级,用查询代替手动的目录组织。

Smart Folders 是什么

Smart Folders 的核心思想是:文件夹不存储文件,只存储"筛选条件"。它由三部分组成:

  1. 一个 YAML 查询文件(位于工作区 .foam/queries/ 目录,文件名即查询 id);
  2. Foam 查询引擎(@foam/core 中的 executeQuery)——按查询描述符在工作区中筛选笔记;
  3. VS Code 树视图(SmartFoldersProvider)——把匹配结果渲染到侧边栏。

典型场景是:创建一个名为 "Work in Progress" 的智能文件夹,只显示打了 #wip 标签、且没有 #archive 标签的笔记,见 foam-queries 中保存查询的示例。这样笔记物理上可以分散在任何目录,但视图上始终聚合在同一个逻辑分组下,非常适合跨目录检索大型工作区。

从源码结构看,智能文件夹与内联查询(foam-query 代码块)共享同一套查询语法和引擎:saved-store.ts 中的 QueryStore 负责读写 .foam/queries/ 下的 YAML 文件,而树视图直接调用 @foam/core 的 executeQuery 执行查询(见 smart-folders-explorer.ts),因此"保存的查询"和"内联查询"可以互相复制、完全等价。

创建 Smart Folder

通过面板或命令创建

创建智能文件夹有两种入口(见 create-smart-folder.ts):

  1. 打开资源管理器中的 Smart Folders 面板,点击 Create Smart Folder(对应命令 foam-vscode.views.smart-folders.create);
  2. 或在命令面板运行 Foam: Create Smart Folder。

创建流程分两步交互:

  1. 输入名称(例如 Work in Progress);
  2. 多选要包含的标签(可选,按 Esc 跳过,直接进入 YAML 手动编辑)。

完成后 Foam 会在 .foam/queries/<name>.yaml 生成查询文件并自动打开编辑。

名称如何变成文件名

输入的名称会先经过 sanitizeQueryId 处理成文件系统安全 id(实现见 saved.ts):

  • 全部转小写;
  • 空白与非法字符替换为 -;
  • 去掉首尾的 -,合并连续 -。

例如 Work in Progress → work-in-progress.yaml,research/animals → research-animals.yaml。如果生成的 id 已存在,创建逻辑会自动追加序号(-2、-3……)直到不冲突(见 create-smart-folder.ts)。若名称无法产生有效 id(例如只含符号),Foam 会提示改用字母、数字、连字符或下划线。

标签选择背后的过滤逻辑

多选标签后,Foam 会构建一个"或"过滤器(buildOrFilter):

  • 只选 1 个标签 → filter: { tag: "#wip" };
  • 选择多个标签 → filter: { or: [ { tag: "#a" }, { tag: "#b" } ] },即匹配任意一个所选标签的笔记都会出现;
  • 工作区没有任何标签,或按 Esc 跳过选择 → 生成 filter: "*"(匹配全部笔记),留待你在 YAML 中细化。

生成的文件随后通过 QueryStore.save 写入磁盘(见 saved-store.ts),文件名由 id 决定,因此重命名文件即重命名查询。

编辑 Smart Folder

编辑有两种方式:

  1. 点击面板中智能文件夹旁边的铅笔图标(命令 foam-vscode.views.smart-folders.edit),会自动打开对应的 YAML 文件;
  2. 直接打开 .foam/queries/<id>.yaml 手动编辑。

改动会自动生效:SmartFolderStorage 为 .foam/queries/*.{yaml,yml} 注册了 FileSystemWatcher,文件创建、修改、删除都会触发树视图刷新(见 smart-folder-storage.ts 与 index.ts)。此外,工作区图谱(foam.graph)的更新同样会触发刷新,因此笔记标签、链接变化后智能文件夹的结果也会随之更新。

YAML 文件结构

一个保存的查询文件把查询字段直接放在 YAML 根级,可选两个包装字段:

name: Work in Progress           # 可选;缺省时由文件名转成人类可读形式
description: Notes I am editing  # 可选
filter:
  and:
    - tag: "#wip"
    - not:
        tag: "#archive"
sort: title ASC
limit: 50

最简有效文件只需一行:filter: "#wip"。

字段说明(完整语法见 foam-queries):

  • filter:选择包含哪些笔记;
  • select:选择展示哪些字段(默认 title 和 path);
  • sort:排序,例如 title ASC 或 backlink-count DESC;被排序的字段需同时出现在 select 中,否则投影后不可用;
  • limit / offset:限制返回条数 / 跳过前 n 条;
  • format:list、table 或 count。

从解析器源码(saved.ts)看,根级只允许 name、description 以及 filter、select、sort、limit、offset、format 这些字段,出现未知字段会被记为解析警告(warning 而非硬错误),并在树视图中以"errors"条目呈现。

filter 支持的筛选键

  • tag:拥有该标签的笔记(如 tag: "#research");
  • type:指定类型的笔记(如 type: "daily-note");
  • path:路径匹配正则的笔记(如 path: "^/projects/");
  • title:标题匹配正则的笔记;
  • links_to / links_from:链接到 / 被链接自某笔记 id 的笔记,可用 "$current" 指代当前笔记;
  • jexl:针对每条笔记求值的 Jexl 表达式(如 "resource.tags|length > 2"),可访问 resource 对象及 length、lower、upper 等内建变换;
  • and / or / not:逻辑组合;
  • 简单快捷形式:"#tag"、"[[note-id]]"、"/regex/"、"*"(全部笔记)。

删除 Smart Folder

点击智能文件夹旁的垃圾桶图标并确认即可删除,对应的 YAML 文件会被移除。源码实现(create-smart-folder.ts)会先弹出模态确认框,只有选择 Delete 才调用 storage.delete(id);QueryStore.delete 会检查文件存在再删除(见 saved-store.ts)。删除后 FileSystemWatcher 的 onDidDelete 事件会清掉内存缓存并刷新视图。

视图选项

面板标题栏提供两个开关:

  • Group By Folder / Flat list:把匹配的笔记按工作区路径分组为目录树,或以扁平列表展示。该偏好通过 ContextMemento 持久化在 foam-vscode.views.smart-folders.group-by 状态中(默认 folder,见 smart-folders-explorer.ts),由命令 foam-vscode.views.smart-folders.group-by:folder 和 group-by:off 控制;
  • Refresh:按需重新执行所有查询。refresh() 会清空结果缓存(uriCache)并重建树(见 smart-folders-explorer.ts)。

树视图本身由 SmartFoldersProvider 驱动(smart-folders-explorer.ts),其行为要点:

  • 顶层条目:每个已保存查询一个条目,图标为 folder-library,描述显示匹配笔记数;若文件存在解析错误,则显示为带警告图标、描述为 errors 的 SmartFolderErrorTreeItem,点击可直接打开查询文件(见 smart-folders-explorer.ts);
  • 分组模式:buildFolderTree 把匹配 URI 按工作区相对路径拆分为嵌套目录节点,每个目录节点显示叶子数,子项按名称排序(smart-folders-explorer.ts);
  • 错误隔离:单个查询执行失败不会拖垮整个面板——异常被捕获并记录日志,该文件夹显示为空结果(对应测试见 smart-folders-explorer.spec.ts);
  • 信任工作区:查询可包含 Jexl 表达式,仅在受信任(trusted)工作区执行,与 foam-query 块的信任门槛一致,未信任时默认 () => false 保证安全(见 smart-folders-explorer.ts)。

底层存储与文件约定

理解以下几点可以更安全地手工管理智能文件夹:

  • 目录与扩展名:查询文件固定存放在 .foam/queries/,glob 为 *.{yaml,yml}(常量 QUERIES_GLOB,见 saved-store.ts);注意这是查询专用目录,Foam 普通笔记数据存储通常只覆盖 **/*.md,不会误扫到这些 YAML;
  • id 来自文件名:查询 id 由文件名(去掉 .yaml/.yml 扩展名)推导(idFromQueryFilename),不写在 YAML 内容里;重命名文件即重命名查询(见 saved.ts);
  • 显示名缺省规则:YAML 中省略 name 时,显示名由 id 经 humanizeQueryId 自动生成,例如 work-in-progress → Work In Progress;序列化时若 name 与缺省值相同会被省略(saved.ts);
  • 缓存与观察:SmartFolderStorage 在内存中缓存解析结果,配合 FileSystemWatcher 增量更新,避免每次刷新重读所有 YAML(smart-folder-storage.ts);查询执行结果也有 uriCache,在每次 refresh() 时清空(smart-folders-explorer.ts)。

与 Foam Queries 的关系

智能文件夹与 Foam Queries 是同一能力的两种形态:

  • 内联形态:在笔记中写 foam-query 代码块,结果渲染在 Markdown 预览中;
  • 持久形态:把同样的字段写入 .foam/queries/ 下的 YAML,侧边栏的 Smart Folders 面板即为其展示层。

两者的语法完全一致,保存的查询文件与内联块可以互相复制。区别在于渲染位置与用途:智能文件夹适合常驻侧边栏的"工作视图"(如进行中的项目、待办聚合),内联查询适合放在某篇笔记里按需展示。若需要把查询结果嵌入到其他笔记,可参考 embeds。

小结

Smart Folders 把"组织笔记"从手工建目录、维护层级,转变为编写并保存查询:创建、编辑、删除、视图切换四个核心操作均可在面板内完成,所有改动即时生效;底层由 foam-core 的 QueryStore + executeQuery 与 foam-vscode 的树视图、文件监听器协作实现。掌握 查询语法(filter 组合、排序、limit、Jexl 表达式等),即可组合出如"#wip 且非 #archive""指向某主题的所有笔记""按回链数排序的 TOP 10"等动态视图,让侧边栏真正反映笔记内容而非目录结构。

登录后查看全文
foam