diff --git a/src/shell/activity.rs b/src/shell/activity.rs index f5b180a..8f2938c 100644 --- a/src/shell/activity.rs +++ b/src/shell/activity.rs @@ -1,5 +1,5 @@ //! 有界 HTTP 活动记录。保存请求/响应的可显示预览供 Network 工具读取,不负责执行请求。 -//! 正文预览和允许显示的头部受限制,避免活动面板成为无限日志或暴露不必要数据的通道。 +//! 本模块限制预览字节数与记录条数;请求头白名单由 runtime/api::ObservedRequest 提前筛选。 //! //! Bounded observation of this process's local HTTP API, never external traffic. use std::{ @@ -20,10 +20,11 @@ const MAX_RECORDS: usize = 80; pub struct Exchange { // 由 begin 分配的日志身份,HTTP worker 后续只携带此 ID 更新,不持有队列元素引用。 pub id: u64, - // 请求方法和来源标签由本地 API 观察器传入;origin 只供显示,不授予执行权限。 + // 请求方法由本地 API 观察器传入,按原文本保存;这里不校验或执行 HTTP 方法。 pub method: String, // 请求 URL 的受限预览,不在此解析路由或读取所指文件。 pub path: String, + // ObservedRequest 传入 HTTP/Console 显示标签;本字段不参与认证或路由,也不在此截断。 pub origin: String, // 开始时刻的 UTC 时分秒文本,不含日期;耗时另用 started 单调时钟计算。 pub timestamp: String, @@ -35,7 +36,9 @@ pub struct Exchange { pub status: Option, // 初始为零,finish 时从 begin 起累计毫秒;不在界面每次绘制时持续刷新。 pub elapsed_ms: u128, + // 请求头已经过观察器白名单筛选,这里再截断文本;ActivityLog 自身不检查头名称。 pub request_headers: String, + // respond 提供已构造响应的全部头部文本,本模块仅限长,不沿用请求头的白名单。 pub response_headers: String, // 使用单调时钟计算耗时,不受系统时间调整影响;timestamp 则用于显示 UTC 时刻。 started: Instant, @@ -46,6 +49,7 @@ pub struct Exchange { pub struct ActivityLog { // 开始顺序队列,Network/Console 工具通过共享锁读取或复制;完成顺序不会重排记录。 pub records: VecDeque, + // 默认从零开始,begin 先递增再使用;计数仅属此日志实例,不是跨进程请求身份。 next_id: u64, } impl ActivityLog { @@ -100,6 +104,7 @@ impl ActivityLog { // 仅更新仍保留的请求,响应正文和头部都重新截断;耗时从 begin 起计算。 // ObservedRequest::respond 在真实响应发送前调用,状态和耗时表示已构造响应,不证明客户端接收成功。 pub fn finish(&mut self, id: u64, status: u16, body: &str, headers: String) { + // finish 可能晚于容量淘汰,找不到 ID 时整个更新跳过;不为旧响应另建记录。 if let Some(record) = self.records.iter_mut().find(|r| r.id == id) { record.status = Some(status); record.response = preview(body); diff --git a/src/shell/clipboard.rs b/src/shell/clipboard.rs index 10dc876..f4a697f 100644 --- a/src/shell/clipboard.rs +++ b/src/shell/clipboard.rs @@ -15,7 +15,7 @@ fn command(program: &str) -> std::process::Command { cmd } /// 取得系统剪贴板的 UTF-8 文本,失败作为可显示错误返回。 -// shell/app 处理开发工具粘贴快捷键时调用;失败由工具 input_error 展示,不用空字符串冒充成功。 +// shell/app 处理开发工具粘贴快捷键时同步调用;等待 pbpaste 结束后才插入文本,失败由 input_error 展示。 pub fn read() -> Result { #[cfg(target_os = "macos")] { @@ -39,7 +39,7 @@ pub fn read() -> Result { } } /// 将提供的文本交给系统剪贴板命令,不执行文本内容。 -// shell/app 的复制与剪切路径调用;只有成功返回后剪切才会删除编辑器中的选中文本。 +// shell/app 的复制与剪切快捷键同步调用;仅非空选区才进入这里,成功返回后剪切才删除编辑器选中文本。 pub fn write(value: &str) -> Result<()> { #[cfg(target_os = "macos")] { diff --git a/src/shell/sidebar.rs b/src/shell/sidebar.rs index 65b4e3d..c4ee8ce 100644 --- a/src/shell/sidebar.rs +++ b/src/shell/sidebar.rs @@ -24,15 +24,21 @@ pub const CONTROLS: f32 = if cfg!(target_os = "macos") { 86.0 } else { 0.0 }; /// 侧栏释放激活后要执行的管理动作,绘制本身只登记它。 // app::sidebar_action 执行这些已确认动作;页面 ID 来自本窗口的 Tab 投影,不是 VM 对象引用。 pub enum Action { + // app 就地切换侧栏占用宽度并发布视口,不向 VM 发送标签事件。 Toggle, + // app 通过 open_developer_tool("New tab") 提交新页请求,不在 draw 内创建页面。 NewPage, + // 固定工具名称交给同一打开入口,是否复用已有工具页由运行时处理。 Tool(&'static str), + // app 将当前窗口标签 ID 放进 Input.mount,并以 tab-activate 交给 worker 校验与切页。 Activate(u64), + // 与激活使用相同身份通道,但事件种类为 tab-close,不能按列表行号关闭页面。 Close(u64), } /// 侧栏开合、控件交互和本帧目标集合,决定实际占用页面宽度。 pub struct State { + // 仅属宿主 UI 的开合状态;决定 left/covers/draw,不是托管页面中的可响应属性。 pub open: bool, // 跨帧保存悬停、键盘焦点和按下捕获;目标矩形则由每次 draw 重建。 pub interaction: Interaction, @@ -154,7 +160,6 @@ impl State { let y = area.y + index as f32 * 36.0 - self.scroll; // Register only fully visible rows: paint clipping must match input. // 当前实现完全跳过部分可见行,绘制与注册都不发生;Clip 仍保护其他原语不溢出列表区域。 - // 部分可见行整行跳过,既不产生切页按钮也不产生关闭按钮,防止不可见片段仍可激活。 if y < area.y || y + 32.0 > area.y + area.height { continue; } diff --git a/src/shell/tabs.rs b/src/shell/tabs.rs index 54b6ffc..de8e5fa 100644 --- a/src/shell/tabs.rs +++ b/src/shell/tabs.rs @@ -1,14 +1,15 @@ //! 发布页面标签的数据结构。保留稳定页面身份、标题、选中状态和开发工具类别;页面的托管所有权由模型层管理。 //! //! Immutable page registry projections. Host navigation is rendered in sidebar. -//! IDs are session-local data and never own managed VM objects. +//! IDs are local to each window presentation and never own managed VM objects. use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] /// 托管页面注册表的不可变投影,原生工具只使用稳定 ID 与显示元数据。 // ui_bridge::project_tabs 从当前窗口页面注册表生成;sidebar 画标签,scene 用 developer_tool 标记选择宿主管理页。 pub struct Tab { - // 会话内稳定 ID,供原生侧发起切页/关闭操作;不能直接当作 VM 对象地址。 + // 当前窗口展示内稳定的 ID,不保证跨窗口唯一;输入还需携带窗口、session 和 layout_version。 + // project_tabs 按 Page 弱身份复用 ID;移出窗口后映射删除,再加入时可获得新 ID,不能当作 VM 地址。 pub id: u64, // 本次发布的标题文本副本,原生界面显示时无需读取 VM。 pub title: String,