Files

73 lines
3.3 KiB
Rust

//! 云文件浏览的 provider 抽象与工作区状态。默认 provider 未连接,不假装已有外部文件。
//! 列出和打开文件的结果作为工具数据展示,错误保持在当前工具状态中供界面说明。
//!
//! Cloud source integration seam. The host installs a provider when one exists;
//! the default workspace stays disconnected and never fabricates or stores files.
use anyhow::Result;
#[derive(Clone, Debug)]
/// provider 提供的一条文件元数据,供云文件列表显示。
pub struct SourceFile {
// provider 定义的不透明文件身份,后续 open_file 使用;显示路径不必等于该身份。
pub id: String,
// 面向用户显示的路径文本,不能据此推断为本机可直接读取的文件路径。
pub path: String,
}
#[derive(Clone, Debug)]
/// 已经取得的源文件内容与标识,不代表它已经被执行。
pub struct OpenedSource {
pub path: String,
pub code: String,
}
/// 外部文件能力接口;只负责列出和读取,不与 VM 全局环境耦合。
// 由宿主注入具体实现;Send 允许转移线程,但方法使用 &mut self,不声明可并行共享调用。
pub trait CloudSourceProvider: std::fmt::Debug + Send {
/// 返回 provider 当前可列出的文件;未连接状态由 SourceWorkspace 的 Option 表达。
fn list_files(&mut self) -> Result<Vec<SourceFile>>;
/// 通过 provider 取得指定文件内容,不在工具查看动作中执行该内容。
fn open_file(&mut self, id: &str) -> Result<OpenedSource>;
}
#[derive(Debug, Default)]
/// Sources 云文件页面保留的 provider、列表、选择、内容与错误状态。
pub struct SourceWorkspace {
// None 表示未接入外部文件服务;默认工作区不提供虚构文件或隐式认证。
pub provider: Option<Box<dyn CloudSourceProvider>>,
pub files: Vec<SourceFile>,
pub opened: Option<OpenedSource>,
pub error: String,
}
impl SourceWorkspace {
/// 更新云文件列表并保存结果或错误,供 Sources 页面显示。
pub fn refresh(&mut self) {
// 未连接时明确写错误并返回;已有文件列表/打开内容不会在失败路径中被清除。
let Some(provider) = &mut self.provider else {
self.error = "No cloud file provider configured".into();
return;
};
// 调用是同步的,调用方负责安排执行位置;成功才整体替换列表,失败保留旧列表供查看。
match provider.list_files() {
Ok(files) => {
self.files = files;
self.error.clear();
}
Err(error) => self.error = error.to_string(),
}
}
/// 更新选中文件的内容与打开状态,失败保持可读错误信息。
// 只读取内容而不执行代码;未连接时直接返回,不像 refresh 那样写入新的错误。
pub fn open(&mut self, id: &str) {
let Some(provider) = &mut self.provider else {
return;
};
// 成功替换 opened 并清错;失败只更新 error,用户仍可查看之前成功打开的内容。
match provider.open_file(id) {
Ok(source) => {
self.opened = Some(source);
self.error.clear();
}
Err(error) => self.error = error.to_string(),
}
}
}