VFS、索引与 Dumb Mode¶
VFS 和索引是插件性能与正确性的关键。插件一旦需要处理项目文件、查找符号或跨文件分析,就必须理解这三件事:VFS 快照、索引访问和 Dumb Mode。
Virtual File System¶
VFS 是 IntelliJ Platform 对文件的统一抽象。它用 VirtualFile 表示文件,不关心文件实际来自磁盘、压缩包、远程位置还是其他来源。
VFS 的核心特性:
- 提供统一文件访问 API。
- 跟踪文件变化。
- 维护一个应用级快照。
- 通过刷新操作把磁盘变化同步到 IDE。
注意:IDE UI 中看到的文件状态来自 VFS 快照,短时间内可能与磁盘实际状态不完全一致。
刷新¶
优先使用异步刷新:
virtualFile.refresh(false, true) {
// run after refresh
}
同步刷新会阻塞调用线程;如果调用线程持有 Read Lock,可能导致死锁。除非你非常明确当前锁和线程状态,否则不要在后台读动作中发起同步刷新。
VFS 事件¶
监听 VFS 变化常用 BulkFileListener:
project.messageBus.connect(disposable).subscribe(
VirtualFileManager.VFS_CHANGES,
object : BulkFileListener {
override fun after(events: List<VFileEvent>) {
// filter relevant files
}
}
)
VFS 监听器是应用级的,会收到所有打开项目的变化。插件应使用 ProjectFileIndex 或其他条件过滤无关文件。
索引¶
索引用于在大项目中快速查找文件或 PSI 元素。
两类常见索引:
| 类型 | 数据来源 | 查询结果 | 适合场景 |
|---|---|---|---|
| File-Based Index | 文件内容 | 匹配的文件 | 按文本、元数据或轻量结构查文件 |
| Stub Index | Stub Tree | 匹配的 PSI 元素 | 自定义语言查声明、类、函数、符号 |
自定义语言插件通常依赖 Stub Index 查找可见声明,避免全项目遍历 PSI。
Dumb Mode¶
索引构建期间,IDE 进入 Dumb Mode。此时依赖索引的功能不能运行,否则可能抛出 IndexNotReadyException。
处理方式:
- 不访问索引的扩展实现
DumbAware。 - Action 使用
DumbAwareAction,不要只覆写isDumbAware()。 - 需要索引的逻辑通过
DumbService延迟到 Smart Mode。
DumbService.getInstance(project).runWhenSmart {
// index-dependent code
}
性能建议¶
- 不要用全项目 PSI 遍历替代索引。
- 索引构建尽量基于 Lexer 信息,能不构建完整 AST 就不要构建。
- Completion、Annotator、Inspection 中避免昂贵索引查询。
- 对可缓存但不需要全项目预计算的数据,考虑 Gist。
- 在内部模式中测试 Dumb Mode,确认插件在索引构建期间不会破坏编辑体验。