# 基于 DBX 的 Navop SQL 编辑器完整实现规格 > 文档状态:Implementation Specification > > 目标读者:负责 Navop SQL 编辑器、SQL 分析、元数据、执行链路和 GPUI Input 基础设施的开发 Agent > > 基准源码:本工作区 `dbx` 与 `navop` 当前源码 > > 编写日期:2026-08-27 > > 目标:以 DBX 的真实源码行为为基线,在 Navop 中实现一套统一、可扩展、异步安全的 SQL 编辑器能力 --- ## 1. 文档目的 本文不是 UI 效果猜测,也不是只描述“行号左侧放一个运行按钮”的局部需求。本文依据 DBX 当前源码,对 SQL 编辑器的完整能力、内部数据流、边界行为、异步约束和测试基线进行拆解,并给出 Navop(Rust + GPUI)的迁移设计。 其他 Agent 应能依据本文按阶段完成以下能力: 1. 在每条完整、可执行 SQL statement 的起始行左侧显示运行图标; 2. 点击图标精确执行该 statement,不改变当前光标或选区; 3. hover 表、视图、函数等 SQL 对象时展示详细元数据和 DDL; 4. 提供表、字段、别名、CTE、函数、关键字、snippet 等上下文补全; 5. 提供当前 statement 边框、执行状态 marker、错误映射和结果联动; 6. 提供语义诊断、格式化、参数替换、变量展开、`IN (...)` 粘贴、INSERT 值提示等编辑辅助; 7. 正确处理不同数据库方言、quoted identifier、大 schema 和 stale async response; 8. 建立统一的 statement、document revision、metadata scope 和 offset contract,避免各模块独立解析 SQL。 ### 1.1 非目标 本文不要求: - 将 DBX 的 Vue/CodeMirror 代码逐行翻译为 Rust; - 在一个 PR 中一次性完成所有能力; - 将展示型 fallback DDL 当作可直接执行的权威 DDL; - 用 `StreamingSqlParser` 直接承担编辑器增量分析; - 为实现 SQL 专用功能而破坏 GPUI Input 的通用性。 ### 1.2 事实与建议的标记 本文使用以下措辞区分来源: - **DBX 事实**:DBX 当前源码已经存在的行为; - **Navop 现状**:Navop 当前源码已经具备的能力; - **Navop 方案**:建议新增或改造的实现; - **建议扩展**:不一定与 DBX 完全等价,但为了 Navop 架构完整性建议实现。 --- ## 2. 总体结论 DBX SQL 编辑器不是一个单独的“编辑框组件”,而是下列子系统的组合: ```text 长期存活的编辑器状态 │ ├── SQL statement range / executable range ├── dialect-aware lexical + semantic analysis ├── local metadata cache + remote metadata assistant ├── completion / signature / snippets ├── hover / navigation / context actions ├── diagnostics / execution error mapping ├── gutter / current-statement frame / decorations ├── execution target resolution / parameter preprocessing ├── result run / source range / execution state └── formatter / editing assists / persistence ``` Navop 实现时必须坚持三个核心原则。 ### 2.1 唯一 statement range 来源 以下所有能力必须共用同一份 `SqlStatementRangeService` 或 `SqlAnalysisSnapshot.statements`: - gutter 图标位置; - gutter 点击执行范围; - Run Current; - current statement frame; - execution picker; - diagnostics statement window; - execution marker; - database error line/column 回映; - result statement source range。 禁止 gutter、编辑器命令、driver execution parser、diagnostics 各自采用不同的 SQL 分割算法。 ### 2.2 所有异步结果必须绑定 revision 和 scope 每一个异步请求至少绑定: - document revision; - connection id; - catalog/database/schema; - database type/dialect; - metadata generation; - request id 或 cancellation token。 请求返回后,如果其中任何一项已变化,结果必须丢弃,且不得写入当前 cache。 ### 2.3 SQL 能力与 GPUI Input 基础能力分层 建议分为三层: ```text crates/ui 通用 gutter marker、range decoration、hover/completion host、hitbox、绘制 crates/db SQL tokenizer、statement ranges、identifier、semantic model、diagnostics contracts crates/db_view connection scope、metadata provider、execution、result integration、SQL editor facade ``` GPUI Input 不应知道“table”或“SQL statement”,但应知道: - 某逻辑行有一个可点击 marker; - 某 byte/rope range 有 decoration; - 某 marker 有图标、状态、tooltip 和 action; - 某异步结果属于哪个 document revision。 --- ## 3. DBX 能力总览 | 能力 | DBX 当前行为 | Navop 目标 | |---|---|---| | Statement 分割 | 方言感知,支持 `;`、`GO`、`DELIMITER`、Oracle `/`、routine block 等 | 建立编辑器专用 range engine | | 左侧运行图标 | 每条 executable statement 起始行显示 | 增加通用 gutter marker lane | | 精确执行 | gutter 永远执行对应 statement | 统一 `ExactRange` execution target | | 当前 statement | 光标与前后空白、分号、注释有明确归属规则 | 与 gutter 使用相同 snapshot | | 当前 statement frame | 无非空选区时绘制 statement 边框 | 增加 range decoration/layer | | 表/字段补全 | semantic + metadata + keyword + snippet 合并 | 扩展当前 provider 为多 source | | CTE/子查询补全 | 可使用局部推导出的输出列 | 扩展 symbol/semantic model | | 函数补全与签名 | routine、signature、parameter help | 元数据增加 overload/signature | | Hover | 表结构、注释、列、PK、索引、DDL | SQL hover resolver + detail popover | | Navigation | table/view/materialized view/routine 等 | Cmd/Ctrl-click 与 context action | | Diagnostics | unknown table/column、parser error、execution error | 视口级异步诊断 | | INSERT 值提示 | `VALUES` 中显示对应列名 | inline widget/decorations | | `SELECT *` 展开 | 结合 source 与 metadata 安全展开 | completion/intention action | | 参数 | 多种 placeholder、类型输入、preview | execution preprocessing pipeline | | SQL 变量 | `@set` 声明和引用展开 | 参数处理前执行 | | Format/Compress | 方言格式化与压缩 | selection/full document action | | Snippet | 内置、自定义、方言改写 | completion source | | `IN` 粘贴 | 列表转 SQL literals | editor action | | 状态持久化 | selection、viewport、tab 生命周期 | tab state snapshot | | 结果联动 | statement 状态、summary、source focus | execution fingerprint + source map | --- ## 4. 统一数据契约 本节是 Phase 0 必须先确定的 contract。后续实现不得绕过这些结构自行传裸字符串和裸 offset。 ### 4.1 Offset 约定 内部 SQL 分析统一使用 **UTF-8 byte offset**: ```rust #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct SqlTextRange { /// Inclusive UTF-8 byte offset. pub start_byte: usize, /// Exclusive UTF-8 byte offset. pub end_byte: usize, } ``` 约束: - `start_byte <= end_byte <= text.len()`; - 两端都必须位于 UTF-8 char boundary; - `end_byte` exclusive; - UI Rope offset、GPUI text offset、LSP UTF-16 position 只在边界层转换; - 禁止在同一结构中混用 byte、char 和 UTF-16 offset; - debug build 中应对 range 做 boundary assertion。 建议新增显式转换 API: ```rust fn sql_byte_to_rope_offset(text: &Rope, byte: usize) -> Result; fn rope_offset_to_sql_byte(text: &Rope, offset: usize) -> Result; fn sql_byte_to_line_column(text: &str, byte: usize) -> SqlLineColumn; fn lsp_position_to_sql_byte(text: &str, position: LspPosition) -> Result; ``` ### 4.2 Document snapshot ```rust #[derive(Clone)] pub struct SqlDocumentSnapshot { pub revision: u64, pub text: Arc, pub database_type: DatabaseType, pub scope: SqlMetadataScope, } ``` Revision 规则: - 每次文档内容变化递增; - 不因 selection、viewport 或主题变化递增; - connection/database/schema/dialect 变化即使文本未变,也必须使 analysis/completion 请求失效; - revision 不要求跨应用启动持久化,只需当前 editor instance 内单调递增。 ### 4.3 Connection/metadata scope ```rust #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct SqlMetadataScope { pub connection_id: ConnectionId, pub catalog: Option>, pub database: Option>, pub schema: Option>, pub database_type: DatabaseType, pub generation: u64, } ``` `generation` 在以下情况递增: - connection 切换; - database/catalog/schema 切换; - session context 变化; - DDL 执行后 metadata invalidation; - 用户主动刷新 metadata; - driver completion context version 变化。 ### 4.4 Qualified identifier ```rust #[derive(Clone, Debug)] pub struct QualifiedIdentifier { pub parts: Vec, pub range: SqlTextRange, } #[derive(Clone, Debug)] pub struct IdentifierPart { /// SQL 中的原始文本,不含或包含 quote 的策略必须全局一致。 pub raw: Arc, /// 按当前 dialect 规则归一化后的查找值。 pub normalized: Arc, pub quoted: bool, pub quote_style: Option, pub range: SqlTextRange, } ``` 必须保留: - `"Foo"`; - `` `Foo` ``; - `[Foo]`; - 未加引号的 `foo`。 不能在 tokenizer 后无条件 lowercase,因为 quoted identifier 的大小写语义可能不同。 ### 4.5 Analysis snapshot ```rust #[derive(Clone)] pub struct SqlAnalysisSnapshot { pub document_revision: u64, pub scope_generation: u64, pub statements: Arc<[SqlStatementRange]>, pub tokens: Arc<[SqlToken]>, pub semantic_model: Arc, pub diagnostics: Arc<[SqlDiagnostic]>, } ``` Snapshot 是只读、可共享、带版本的。UI 和后台任务不可原地修改旧 snapshot。 --- ## 5. Statement Range Engine ### 5.1 DBX 事实 DBX 的 `SqlTextRange` 结构包含: ```ts type SqlTextRange = { from: number to: number sql: string } ``` 其中: - `to` 是 exclusive; - 正常 range 不包含 statement 末尾分号; - 正常 range 不包含语句间空白; - 内部 `RawStatement` 额外包含 `hitFrom`; - `hitFrom` 表示光标位于前置缩进/空白时,仍可归属该 statement 的起点; - `from` 仍是实际 SQL 内容的第一个字符。 证据: - `dbx/apps/desktop/src/lib/sql/sqlStatementRanges.ts:7-15` - `dbx/apps/desktop/src/lib/sql/sqlStatementRanges.ts:42-51` - `dbx/apps/desktop/src/lib/sql/sqlStatementRanges.ts:282-358` ### 5.2 Navop 目标模型 ```rust #[derive(Clone, Debug)] pub struct SqlStatementRange { /// 光标归属范围的起点,可包含前置空白。 pub hit_start_byte: usize, /// 实际 executable SQL,不含分隔符和 statement 间空白。 pub sql_range: SqlTextRange, /// 可选分隔符范围,例如 `;`、GO 行、Oracle `/`。 pub delimiter_range: Option, /// gutter marker 所在 logical source row。 pub executable_line: usize, pub kind: SqlStatementKind, pub batch_index: usize, } pub enum SqlStatementKind { Sql, Procedure, Function, Trigger, AnonymousBlock, MongoCommand, RedisCommand, ElasticsearchRequest, Directive, } ``` ### 5.3 必须支持的 lexical state Scanner 至少需要维护: ```rust enum SqlLexicalState { Normal, SingleQuotedString, DoubleQuotedIdentifierOrString, BacktickIdentifier, BracketIdentifier, LineCommentDash, LineCommentHash, BlockComment { depth: usize }, DollarQuotedString { tag: Arc }, } ``` 注意: - PostgreSQL 支持 dollar quote; - 某些数据库支持嵌套块注释,能力应由 dialect profile 控制; - MySQL `#` 可能是 comment,但 MyBatis `#{name}` 不是; - MySQL 中 `--` 是否为注释需要遵守其空白规则; - SQL Server 方括号 identifier 内的 `;`、`GO` 不得切分; - string/comment 内的 delimiter 永远不能切 statement。 ### 5.4 必须支持的 delimiter/batch DBX 已处理: - 顶层 `;`; - MySQL `DELIMITER`; - SQL Server `GO` / `GO n`; - Oracle 行首单独 `/`; - Oracle PL/SQL block; - MySQL procedure/function/trigger routine block; - Mongo、Redis、Elasticsearch 的特殊 command range。 主要证据: - `sqlStatementRanges.ts:292-558` - `sqlStatementRanges.ts:689-710` - `sqlStatementRanges.ts:1510-1564` - `sqlStatementRanges.ts:1778-1845` - `sqlStatementRanges.ts:1969-2001` - `sqlStatementRanges.ts:2075-2085` ### 5.5 Current statement 归属规则 `statement_at_cursor(offset)` 必须满足: 1. offset 先 clamp 到 `[0, text.len()]`; 2. cursor 位于 statement SQL 内容内部时返回该 statement; 3. cursor 位于 statement 前的缩进空白,可归属后一个 statement; 4. cursor 位于 statement 后的同一行空白或 delimiter gap,可归属前一 statement; 5. cursor 位于纯空白行或纯注释行时返回 `None`; 6. 前导普通注释不能被误认为 executable statement; 7. executable directive 可将运行图标定位到 directive 后真正 SQL 起始行; 8. 返回的 executable range 仍从实际 SQL 内容开始,不包含命中用空白。 DBX 证据: - `sqlStatementRanges.ts:605-640` - `executableStatementRangeCache.ts:89-130` - `statementDelimiter.ts:8-70` ### 5.6 Cache 建议: ```rust pub struct SqlStatementRangeCache { revision: u64, database_type: DatabaseType, parameter_syntax_key: u64, ranges: Arc<[SqlStatementRange]>, by_sql_start: HashMap, by_executable_line: HashMap, } ``` 仅在以下变化时重建: - document revision; - database type/dialect; - parameter syntax/profile; - parser behavior version。 查询必须是 O(log n) 或 O(1): - `statement_at_cursor(offset)`; - `statement_starting_on_line(row)`; - `statements_intersecting(range)`; - `statement_by_sql_start(byte)`。 ### 5.7 不应直接复用 `StreamingSqlParser` Navop 当前 `crates/db/src/streaming_parser.rs` 面向大文件/大脚本流式执行,公开模型是 source、bytes read 和 progress,不是长期存活编辑器的 revision snapshot。 实现原则: - 编辑器 range engine 放在新模块; - 如两者要复用分隔逻辑,抽出无 UI、无 I/O 的纯 scanner; - `StreamingSqlParser` 和 editor service 分别做 adapter; - 不让 UI 依赖流式 parser 的读取状态; - 当前 `streaming_parser.rs` 有既存未提交修改,本设计实现不得覆盖或回滚。 --- ## 6. 左侧运行图标与通用 Gutter ### 6.1 DBX 用户行为 - 只有每条 executable statement 的起始行显示 play icon; - 多行 statement 不在每一行重复显示; - 前导空行和普通注释行不显示; - MySQL routine 整体只显示一个运行入口; - 只响应左键 `mousedown`; - 查不到 statement range 时不处理; - gutter 点击始终执行对应 statement,即使全局执行模式设置为 All; - 点击 gutter 不主动 focus editor,不把 viewport 滚回旧 cursor; - marker 可显示 running、succeeded、failed; - 文档变化时旧 marker 清空; - execution state effect 到达时重新生成 marker。 证据: - `dbx/apps/desktop/src/components/editor/QueryEditor.vue:1675-1687` - `dbx/apps/desktop/src/components/editor/QueryEditor.vue:4704-4749` ### 6.2 GPUI 通用 API 在 `crates/ui/src/input/state.rs` 新增通用模型: ```rust #[derive(Clone)] pub struct InputGutterMarker { pub id: SharedString, pub logical_row: usize, pub lane: InputGutterLane, pub icon: IconName, pub state: InputGutterMarkerState, pub tooltip: Option, pub enabled: bool, pub action: Option, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum InputGutterLane { PrimaryAction, Diagnostic, Breakpoint, Custom(u8), } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum InputGutterMarkerState { Idle, Running, Success, Error, Disabled, } ``` 建议 `InputGutterAction` 不直接持有 SQL closure,而使用稳定 id 发通用 event: ```rust pub enum InputEvent { // existing events... GutterMarkerMouseDown { marker_id: SharedString, logical_row: usize, button: MouseButton, }, } ``` ### 6.3 Layout 与 hit-testing 修改 `crates/ui/src/input/element.rs`: 1. gutter 由固定 lane 组成: - marker lane; - fold lane; - line number lane; 2. gutter 总宽度取决于启用 lane,不应因某一行有无 marker 而抖动; 3. marker 使用 logical source row,而不是 soft-wrap visual row; 4. 一条 source line 被 soft wrap 后,只在第一个 visual fragment 显示; 5. 横向滚动只影响文本,不移动 gutter; 6. marker 每个实例有独立 hitbox; 7. marker hitbox 优先于 line-number/fold/text hitbox; 8. `mousedown` 命中后 stop propagation,避免改变 cursor/selection; 9. tooltip 使用通用 hover/popover 生命周期; 10. fold 后不可见行的 marker 不绘制。 ### 6.4 SQL facade `crates/db_view/src/sql_editor.rs` 增加: ```rust impl SqlEditor { pub fn set_statement_gutter_markers( &mut self, markers: Vec, cx: &mut Context, ); } pub struct SqlStatementGutterMarker { pub statement_start_byte: usize, pub logical_row: usize, pub state: SqlExecutionMarkerState, } ``` Marker id 推荐编码为: ```text sql-statement:{document_revision}:{start_byte}:{end_byte} ``` 事件处理时不能只相信 marker 中的旧 SQL。必须: 1. 解析 marker id; 2. 确认当前 document revision 相同; 3. 从当前 snapshot 重新按 start/end 查 range; 4. 创建 `ExactRange` execution request。 --- ## 7. 执行目标解析 ### 7.1 DBX 优先级 DBX 的执行选择逻辑: 1. 有非空 selection:执行 selection; 2. 否则构造 current/all candidates; 3. shortcut 路径 bypass picker; 4. toolbar 点击在设置开启且存在多个候选时可显示 picker; 5. gutter 永远执行精确 statement range。 DBX 的 `ExecutionSnapshot` 包含: - `fullSql` - `selectedSql` - `cursorPos` - `selectionFrom` - `selectionTo` - 可选 `editorViewportRequestId` 证据: - `QueryEditor.vue:822-885` - `sqlExecutionTarget.ts:7-14` - `sqlExecutionTarget.ts:45-78` ### 7.2 Navop 目标模型 ```rust pub enum SqlExecutionTarget { Selection(SqlTextRange), CurrentStatement, AllStatements, ExactRange(SqlTextRange), } pub struct SqlExecutionRequest { pub request_id: u64, pub document_revision: u64, pub full_sql: Arc, pub target: SqlExecutionTarget, pub resolved_sql: Arc, pub source_range: Option, pub statement_identity: Option, pub scope: SqlMetadataScope, pub transaction_mode: TransactionMode, pub open_in_new_result_tab: bool, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct SqlStatementIdentity { pub document_revision: u64, pub start_byte: usize, pub end_byte: usize, pub sql_fingerprint: u64, } ``` ### 7.3 入口行为 | 入口 | Target | 是否使用 picker | 是否改 selection/focus | |---|---|---:|---:| | Gutter play | `ExactRange` | 否 | 否 | | Run shortcut | Selection 或 Current | 否 | 否 | | Run All shortcut | `AllStatements` | 否 | 否 | | Toolbar Run | Selection/Current/All | 可配置 | 否 | | Context menu Run Selection | `Selection` | 否 | 右键前同步 selection | | Context menu Run Current | `CurrentStatement` | 否 | 右键前同步 pointer target | ### 7.4 执行前处理顺序 推荐统一 pipeline: ```text resolve target from snapshot → extract source SQL → expand declared SQL variables → extract unresolved parameters → optional parameter dialog → substitute parameters → construct dialect-specific batch script → execute → bind result to statement identity ``` 变量展开必须先于 placeholder 参数替换。未声明变量应保留给参数系统。 ### 7.5 执行状态 ```rust pub enum SqlExecutionState { Pending, Running, Succeeded, Failed, Cancelled, Skipped, } ``` 文档一旦编辑: - 旧 marker 不能继续附着到新文本; - 可以保留历史 result tab; - 但 result tab 的 source highlight 必须标明它属于旧 revision; - 若 fingerprint 无法匹配当前 statement,不得自动跳转到错误 range。 --- ## 8. SQL 分析层 ### 8.1 推荐模块 ```text crates/db/src/sql_editor/ ├── document.rs ├── dialect.rs ├── identifier.rs ├── statement_ranges.rs ├── analysis.rs ├── semantic_model.rs ├── diagnostics.rs ├── completion.rs └── metadata.rs ``` 如需降低首期改动,至少先新增: ```text statement_ranges.rs identifier.rs analysis.rs metadata.rs ``` ### 8.2 Tokenizer Navop 当前 tokenizer 已支持: - keyword; - ident/quoted ident; - string; - number; - line/block comment; - dot/comma/semicolon/parenthesis/operator; - byte spans; - token at offset。 现有文件: - `navop/crates/db/src/sql_editor/sql_tokenizer.rs` 需要扩展: - database dialect profile; - backtick 和 bracket identifier; - PostgreSQL dollar quote; - incomplete string/comment 的稳定 token; - parameter token; - executable directive; - token 中保留 raw text 与 normalized identifier; - error/recovery token; - statement scanner 可复用的 lexical state。 ### 8.3 Semantic model 最低目标: ```rust pub struct SqlSemanticModel { pub statements: Vec, pub references: Vec, pub scopes: Vec, } pub struct SqlScope { pub parent: Option, pub row_sources: Vec, pub projection_columns: Vec, pub ctes: Vec, } pub enum SqlRowSource { Table(SqlTableReference), Cte(SqlCteReference), DerivedTable(SqlDerivedTable), TableFunction(SqlRoutineReference), } ``` 必须解析或保守推导: - `FROM table [AS] alias`; - `JOIN table alias`; - qualified table; - CTE 名称和输出列; - subquery/derived table alias 和 projection; - `SELECT expr AS alias`; - INSERT target; - UPDATE target; - function call; - visible scope 与 correlated parent scope。 语义模型面对不完整 SQL 时应“尽可能返回已知信息”,而不是因为 parse error 整体失败。 ### 8.4 Statement window DBX 在有 live CodeMirror state 时优先使用增量 syntax tree;tree 尚未 parse 到 cursor、出现 recovery error 或 dollar quote 可能截断时,回退 bounded scanner。 Navop 不一定复制 CodeMirror tree,但应保留相同策略: 1. 优先使用当前 revision 的 analysis snapshot; 2. snapshot 未完成或 cursor 不在已分析范围时,使用轻量 bounded scanner; 3. bounded scanner 默认向两侧最多扩展 32 KiB; 4. 超长 statement 可按需要扩大窗口; 5. 不在 UI thread 强制等待完整解析。 --- ## 9. 自动完成 ### 9.1 DBX 分层 DBX completion 的概念流程: ```text cursor lexer/parser → CompletionContext → local semantic candidates → metadata tree/cache candidates → remote completion assistant → merge/filter/rank/dedupe → editor CompletionResult ``` 这意味着“字段完成提示”不是简单地把所有列名放进一个数组。 ### 9.2 Completion context 目标 context: ```rust pub enum SqlCompletionContextKind { Start, Keyword, Catalog, Schema, Table, Routine, Column, AliasColumn, InsertTarget, InsertColumn, UpdateTarget, SetClause, Condition, JoinSource, JoinCondition, OrderBy, GroupBy, FunctionArgument, ExecArgument, } ``` Request: ```rust pub struct SqlCompletionRequest { pub request_id: u64, pub document_revision: u64, pub cursor_byte: usize, pub trigger: SqlCompletionTrigger, pub scope: SqlMetadataScope, pub replacement_range: SqlTextRange, pub context: SqlCompletionContext, pub analysis: Arc, } ``` ### 9.3 Candidate 数据 ```rust pub struct SqlCompletionCandidate { pub label: Arc, pub insert_text: Arc, pub replacement_range: SqlTextRange, pub kind: SqlCompletionItemKind, pub detail: Option>, pub documentation: Option>, pub filter_text: Option>, pub sort_text: Option>, pub source: SqlCompletionSourceKind, pub score: i32, pub deprecated: bool, pub snippet: bool, pub commit_characters: Arc<[char]>, } pub enum SqlCompletionItemKind { Catalog, Database, Schema, Table, View, MaterializedView, Column, Alias, Function, Procedure, Package, Trigger, Sequence, Keyword, Snippet, Value, } ``` 字段 candidate 至少保存: - column name; - physical table; - source alias; - source qualifier SQL; - schema; - data type; - nullable; - comment。 表 candidate 至少保存: - catalog/database/schema; - object type; - detail/comment; - apply name; - boost。 Routine candidate 至少保存: - parent schema/name; - signature; - comment; - overload identity。 ### 9.4 Completion source ```rust pub trait SqlCompletionSource: Send + Sync { fn complete( &self, request: SqlCompletionRequest, cx: &mut AsyncApp, ) -> Task>; } pub struct SqlCompletionSourceResult { pub request_id: u64, pub document_revision: u64, pub scope_generation: u64, pub candidates: Vec, pub incomplete: bool, } ``` 建议 source: - `DialectKeywordCompletionSource` - `SemanticCompletionSource` - `MetadataCompletionSource` - `RoutineCompletionSource` - `SnippetCompletionSource` - `HistoryCompletionBoostSource` 由 `MergedSqlCompletionProvider` 合并。不要让 schema refresh 直接替换整个 provider。 ### 9.5 表和 schema 补全 必须支持: - `table`; - `schema.table`; - MySQL 风格 `database.table`; - `database.schema.table`; - quoted schema 后的 dot completion; - catalog/database/schema 切换; - table/view/materialized view 类型区分; - INSERT/UPDATE target; - JOIN source; - 自动 alias,可配置; - Oracle 等不支持 table alias `AS` 的方言差异。 生成 alias 时: - 多词表名可使用首字母; - alias 冲突时加编号; - 不覆盖显式 alias; - 设置关闭时不生成; - quoted table 需要按方言生成合法 alias。 ### 9.6 字段完成提示 字段 completion 的解析顺序: 1. 从当前 statement semantic scope 收集 row source; 2. 分辨 physical table、CTE、derived table 和 table function; 3. 对 `alias.` 只返回该 source 的 columns; 4. 对未限定字段,根据所有 visible row source 合并; 5. 同名列需要显示来源并降低歧义; 6. CTE/subquery 的投影列不需要远端 metadata; 7. physical table cache miss 时异步请求 columns; 8. remote 返回前可显示已有 local candidates; 9. remote 返回后仅在 request/revision/scope 仍有效时刷新 popup。 必须覆盖: - `SELECT | FROM users u` → users fields; - `SELECT u.| FROM users u` → only `u` fields; - `JOIN orders o ON u.id = o.|` → orders fields; - correlated subquery 可看到合法 parent scope; - `UPDATE users SET |` → target table fields; - `INSERT INTO users (|)` → target table fields; - `ORDER BY |` 可包含 projection alias; - projection alias 在 WHERE/GROUP BY/HAVING/ORDER BY 的可见性按 dialect 控制; - 不完整 metadata 时不应错误展开 `*` 或报 unknown column。 ### 9.7 `SELECT *` 展开 DBX 支持结合 semantic source 和 metadata 展开 wildcard。 Navop 行为: - 单表: ```sql SELECT * FROM users; ``` 展开为列列表。 - alias: ```sql SELECT u.* FROM users u; ``` 展开时保留 `u.` qualifier。 - 多表: - 保持 FROM/JOIN source 顺序; - 同名列根据设置使用 qualifier; - metadata 不完整或 stale 时拒绝操作,不生成猜测结果; - 异步返回后确认旧 SQL 与当前 document revision/range 内容一致。 ### 9.8 Function/routine 与 signature help Completion: - function name; - signature; - return type; - schema/package; - overload; - snippet-style parameters; - 已有 `(` 时不重复插入。 Signature help: - cursor 位于 argument list 时显示; - 标出 active parameter; - overloaded routine 可切换; - 文档编辑或 cursor 离开 call 时关闭; - metadata scope 变化使旧 signature 失效。 ### 9.9 Snippet DBX 内置 prefix 包括: - `sel` - `ins` - `upd` - `cte` - `join` - `case` - `ct` - `ex` - `nex` - `at` - `ci` 并有 Manticore 专用模板。 Navop 应支持: - 内置 snippet; - 用户自定义 snippet; - tab stop; - next/previous field; - dialect-specific body; - 只有用户仍使用内置默认 body 时才自动做 dialect 改写; - 用户自定义 body 永不被 silently rewrite。 典型方言改写: - `LIMIT` - `TOP` - `FIRST` - `FETCH FIRST` - `ROWS` - `ROWNUM` - ClickHouse `ALTER TABLE ... UPDATE` - 不同 `ALTER TABLE ADD COLUMN` 形式。 ### 9.10 排序、过滤和去重 DBX 排序综合: 1. context/variable/exact; 2. fuzzy score; 3. history boost; 4. type boost。 DBX type boost 示例: - column: 180 - table: 160 - schema: 120 - function: 90 - keyword: 0 Navop 推荐评分: ```text final_score = exact_prefix_score + context_score + semantic_visibility_score + item_kind_score + history_score + fuzzy_score - qualification_penalty - ambiguity_penalty ``` 匹配至少支持: - exact; - case-insensitive prefix; - identifier initials; - substring; - ordered fuzzy subsequence; - 可选汉字拼音首字母。 去重 key 不能只用 label,应包含: ```text kind + qualified identity + insert_text + signature ``` ### 9.11 Completion stale 防护 必须有单调递增 `completion_epoch` 或 request id。 以下事件使旧请求失效: - document changed; - cursor/selection 变化导致 context 改变; - popup abort; - connection/catalog/database/schema 变化; - dialect/profile 变化; - metadata generation 变化; - IME composition start; - editor deactivation; - completion setting/snippet setting 变化。 每个关键 `await` 后都要检查: ```rust if !completion_guard.is_current( request_id, document_revision, scope_generation, ) { return Ok(None); } ``` --- ## 10. Metadata Model 与 Cache ### 10.1 Navop 当前问题 当前 `SqlSchema` 主要包含: - tables; - global columns; - functions; - columns_by_table。 缺少: - catalog/database/schema; - object kind; - table/view distinction; - PK/FK/index; - nullable/default/comment; - routine overload; - qualification/quoted state; - revision/version。 当前 schema 加载还存在逐表串行请求 columns 的 N+1 风险。 ### 10.2 Metadata contract ```rust pub trait SqlMetadataProvider: Send + Sync { fn search_objects( &self, request: SearchSqlObjectsRequest, cx: &mut AsyncApp, ) -> Task>; fn list_columns( &self, request: ListSqlColumnsRequest, cx: &mut AsyncApp, ) -> Task>; fn get_object_detail( &self, request: GetSqlObjectDetailRequest, cx: &mut AsyncApp, ) -> Task>; fn get_ddl( &self, request: GetSqlObjectDdlRequest, cx: &mut AsyncApp, ) -> Task>; } ``` ### 10.3 Object model ```rust pub enum SqlObjectKind { Catalog, Database, Schema, Table, View, MaterializedView, Function, Procedure, Package, Trigger, Sequence, } pub struct SqlObjectRef { pub kind: SqlObjectKind, pub catalog: Option>, pub database: Option>, pub schema: Option>, pub name: Arc, pub quoted_parts: Arc<[bool]>, } pub struct SqlColumnMetadata { pub name: Arc, pub data_type: Arc, pub nullable: Option, pub default_value: Option>, pub comment: Option>, pub ordinal: Option, pub primary_key: bool, pub generated: bool, } pub struct SqlObjectDetail { pub object: SqlObjectRef, pub comment: Option>, pub columns: Arc<[SqlColumnMetadata]>, pub primary_key: Arc<[Arc]>, pub indexes: Arc<[SqlIndexMetadata]>, pub foreign_keys: Arc<[SqlForeignKeyMetadata]>, pub signature: Option>, } ``` ### 10.4 Search assistant contract DBX remote assistant 请求包括: - connection id; - database; - schema; - object kinds; - mask; - case sensitivity; - global search; - max results; - search comments/definitions; - parent schema/name; - match mode。 Response 包括: - candidates; - incomplete; - fallback used。 Navop 应保留等价字段,以便: - completion; - object search; - navigation; - hover cache miss; - large schema lazy lookup。 ### 10.5 Cache key 至少包含: ```rust pub struct SqlMetadataCacheKey { pub connection_id: ConnectionId, pub catalog: Option>, pub database: Option>, pub schema: Option>, pub object: Option>, pub object_kind: Option, pub quoted_parts: Arc<[bool]>, pub database_type: DatabaseType, pub session_context: Option>, } ``` 禁止仅按裸 `table_name` 缓存 columns。 ### 10.6 Cache 写入规则 请求发起时捕获: - connection generation; - database generation; - scope generation。 返回后: ```rust if current_scope.generation != requested_generation { // Discard. Do not write into cache. return; } ``` 建议分层 cache: - object search:短 TTL; - columns:中 TTL; - object detail:中 TTL; - DDL:中/长 TTL,但 DDL 后立即 invalidation; - negative result:很短 TTL; - session-scoped metadata:绑定 session id/version。 ### 10.7 大 schema 策略 禁止连接后串行加载全部表的全部字段。 推荐: 1. 初始只加载 catalog/database/schema/table/view 基础索引; 2. 当前 statement 引用的表优先加载 columns; 3. `alias.` 或 INSERT target 触发按表加载; 4. hover 触发 detail/DDL lazy load; 5. 使用 bounded concurrency; 6. 支持分页和 `incomplete`; 7. cache entry 记录 memory cost; 8. LRU 驱逐; 9. completion popup 本地响应预算内先返回,再增量补远端。 --- ## 11. Hover、对象详情与导航 ### 11.1 Identifier 定位 DBX 行为: - cursor 可位于 token 内,也可刚好位于 token 后; - 未加引号的 SQL keyword 不作为对象; - 支持一至三/四段 qualified identifier; - database/schema/table 含义按 dialect 解释; - metadata 查找可 case-insensitive,但 quoted state 必须保留; - local lookup 必须校验 connection/database/schema/object。 主要证据: - `queryCursorTableTarget.ts:32-108` - `queryCursorTableTarget.ts:155-181` ### 11.2 Hover resolve pipeline ```text pointer position → GPUI offset → SQL byte offset → token/qualified identifier → reject string/comment/keyword → semantic reference resolution → local metadata cache → optional remote detail/DDL → revision + scope validation → render popover ``` 失败行为: - 找不到对象:静默不显示; - metadata 请求失败:hover 内可显示轻量错误或静默关闭; - 不弹全局 error toast; - 旧请求返回:丢弃; - pointer 已离开目标:不显示。 ### 11.3 支持对象类型 至少: - table; - view; - materialized view; - procedure; - function; - package; - trigger。 建议扩展: - sequence; - schema; - database; - column。 ### 11.4 Table hover 内容 详情应包括: - object type; - catalog/database/schema; - comment; - columns; - type length/precision/scale; - nullable; - default; - generated/extra; - column comment; - primary key; - indexes; - foreign keys; - backend DDL; - companion `COMMENT ON` / `CREATE INDEX`。 ### 11.5 DDL 权威性 规则: 1. driver/backend `get_ddl` 是权威来源; 2. sanitize 只能清理展示噪声; 3. parse/reformat 不安全时展示 sanitized raw DDL; 4. 不得因为 formatter 失败而丢掉结构; 5. metadata 构造的 `CREATE TABLE` 只作 fallback; 6. fallback 必须标注“根据元数据生成的预览,不保证可执行”; 7. fallback 不得进入“复制并执行”默认路径。 DBX 证据: - `hoverTableSql.ts:5-117` - `hoverTableSql.ts:290-354` - `hoverTableSql.ts:753-825` ### 11.6 Hover layout 参考 DBX: - max width 900px; - width 80vw; - max height 约半个 viewport; - content max height 480px; - vertical scroll; - 超宽 SQL 支持 horizontal scroll; - wheel 和 Shift+wheel; - resize 时重新布局; - destroy 时清理 controller/listener。 GPUI 版本不必逐像素一致,但必须: - 不遮满整个编辑器; - DDL 可横向滚动; - 长 column list 可纵向滚动; - popover 可复制; - pointer 离开、editor destroy、tab deactivation 时清理异步任务与 listener。 ### 11.7 Navigation 交互: - Cmd/Ctrl + click; - context menu; - hover 中 action; - completion resolve action。 目标: - 打开对象结构; - 打开数据; - 查看 DDL/source; - 跳到已打开对象 tab。 Table actions: - View Data - Edit Structure - View DDL View/materialized view actions: - View Data - Edit View - View Source - View DDL 右键菜单必须使用本次 pointer 坐标同步出的 target,不能复用旧 hover/cursor target。 --- ## 12. Diagnostics ### 12.1 DBX 当前范围 DBX 核心 diagnostics 包括: - unknown table; - unknown column; - parser error; - database execution error 的 line/column 映射。 它不是完整 SQL lint 规则集。 ### 12.2 Contract ```rust pub struct SqlDiagnostic { pub id: u64, pub document_revision: u64, pub range: SqlTextRange, pub severity: SqlDiagnosticSeverity, pub code: Option>, pub message: Arc, pub source: SqlDiagnosticSource, pub related: Arc<[SqlDiagnosticRelatedInfo]>, } pub enum SqlDiagnosticSeverity { Error, Warning, Information, Hint, } pub enum SqlDiagnosticSource { Parser, Semantic, Metadata, Execution, } ``` ### 12.3 诊断逻辑 Parser: - unclosed string/comment; - invalid token; - parser recovery error; - line/column/span。 Semantic: - unknown table; - unknown column; - unknown alias; - ambiguous column 可作为 warning; - metadata 不完整时避免误报; - 多表同名字段不能直接报 unknown; - CTE、subquery、correlated scope 正确处理。 Execution: - 只有 result 对应的 SQL fingerprint/revision 与当前文档相符时显示; - driver line/column 转为 source range; - execution target 是 selection/exact range 时加上 source base offset; - 无法可靠映射时只在 result panel 显示,不在错误位置画波浪线。 ### 12.4 Viewport 分析 DBX 按可见 viewport 相交的完整 statements 分析。 Navop 策略: 1. 从 `visible_row_range()` 转为 byte range; 2. 用 statement snapshot 扩展到完整 statement; 3. 同一 statement 只分析一次; 4. cursor 所在超长 statement 即使只可见中段也必须完整分析或采用 safe window; 5. 视口外旧 diagnostics 可暂时保留; 6. 更新时只替换受影响 statement ranges; 7. Oracle PL/SQL、procedure/function batch 可先跳过 semantic unknown-column 规则; 8. Mongo/Elasticsearch 等非 SQL language mode 跳过 SQL diagnostics。 ### 12.5 Debounce 与 stale 使用独立 `diagnostic_run_id`,不得复用 completion request id。 - 文档变化:递增、清当前 stale decoration、重新调度; - 默认 debounce 500ms; - completion active 或用户处于 table-name 输入状态时可延长; - 每个 metadata await 后检查 run id/revision/generation; - tab deactivate 取消 timer 并使 run id 失效; - activate 后重新调度可见范围。 --- ## 13. 当前 Statement Frame 与 Decorations DBX 在以下条件显示当前 statement 边框: - setting 开启; - selection 为空; - cursor 可解析到 executable statement。 规则: - executable range 本身可以不含 `;`; - frame 可把紧邻 trailing `;` 纳入; - 注释、空行或非 delimiter 字符会阻断 frame 延伸; - selection 非空时 frame 隐藏,避免和 selection 视觉冲突。 Navop 可在 Input 增加: ```rust pub struct InputRangeDecoration { pub id: SharedString, pub range: Range, pub kind: InputRangeDecorationKind, pub style: InputRangeDecorationStyle, } ``` 建议绘制顺序: ```text line background → current statement frame → selection/search match → syntax text → semantic underline → diagnostics squiggle → hover highlight → caret → inline widget ``` --- ## 14. INSERT 值列名提示 ### 14.1 用户行为 在: ```sql INSERT INTO users (name, age) VALUES ('Alice', 18), ('Bob', 20); ``` 每个 value expression 前显示不可编辑的灰色提示: ```text name: 'Alice', age: 18 ``` ### 14.2 解析 需要识别: - target table; - database/schema/table; - explicit column list; - 每一行 `VALUES (...)`; - 每行顶层 expression 起点; - `INSERT ... SELECT` projection; - 无 explicit columns 时从 metadata 按 ordinal 获取表字段。 ### 14.3 性能 参考 DBX: - 只分析 viewport 与主 cursor 附近; - 单侧默认最多扩展 32 KiB; - doc/viewport 变化后约 80ms debounce; - 重解析前 widget range 随 edit mapping; - 同一 offset 去重; - metadata cache miss 时先触发异步加载,不显示错误列名。 ### 14.4 GPUI 表达 可以复用现有 inline completion 的布局基础,但必须区分: - inline completion 是可接受的 ghost text; - INSERT value hint 是不可接受、不可编辑的 decoration widget。 建议新增 `InputInlineWidget` 通用模型,或在 range decoration 中增加 `before_text`,但不要伪装为真实文档文本。 --- ## 15. 编辑辅助 ### 15.1 单引号 caret 行为: - 光标在自动生成的 `''` 中按 `'`:跳过右侧 closing quote; - 已有 opening quote 且缺少 closing quote:插入 SQL escaped quote; - 普通位置交给默认输入; - read-only、多 selection、非空 selection 时不拦截; - auto-close 关闭时不拦截。 ### 15.2 `IN (...)` 列表粘贴 输入来源: - 当前 selection; - clipboard。 支持: - comma; - tab; - newline; - 已有 `IN (...)`; - 简单 slash 列表; - `NULL`; - 单引号 escape。 保护: - 最大 1 MiB; - 最多 10,000 values; - 单个普通文本拒绝; - 日期、URL、绝对路径不能误判为 slash list; - cursor 已在 `IN` / `NOT IN` 后时只插括号内容。 ### 15.3 Selection case conversion 提供: - Uppercase; - Lowercase。 要求: - 只处理非空 selection; - 保持转换后的 range 选中; - string literal 保持原文; - PostgreSQL dollar quote 保持; - dialect-specific quoted string/identifier/executable comment 保护; - 不做简单的整个字符串 `to_uppercase()`。 ### 15.4 SQL 参数 支持 descriptor: ```rust pub enum SqlParameterSyntax { Positional, Named, Shell, MyBatis, SqlServer, } pub enum SqlParameterValueKind { String, Number, Boolean, Null, Raw, } ``` 执行前: - extract descriptors; - 去重但保留 occurrence; - 显示参数 dialog; - 类型和值输入; - 替换后 SQL preview; - execute。 Literal: - null → `NULL`; - raw → 原样; - number → 不加 quote; - string → dialect-aware quote/escape; - placeholder 在 string 内时使用 string fragment escape,不重复包裹。 MyBatis foreach: - item/index; - open/separator/close; - collection 展开; - enabled syntaxes 限制识别范围。 ### 15.5 `@set` SQL 变量 支持: ```sql @set ids = (1, 2, 3); SELECT * FROM users WHERE id IN ${ids}; ``` 规则: - 声明 key case-insensitive; - value 保留原始 SQL; - 不在 string/comment/quoted identifier 内替换; - `@@version` 等原生变量不误替换; - declaration context 可来自 full document; - 只删除本次 execution target 内的 declaration; - 未声明 placeholder 留给参数系统; - 变量展开先于参数 dialog。 ### 15.6 Comment、line edit 与 folding 必须保留或新增: - toggle line comment; - toggle block comment; - duplicate line; - delete line; - move line; - indent/outdent; - delete blank lines; - fold/unfold; - nested `BEGIN...END`; - CASE; - CTE/subquery; - UNION; - string/comment 中的关键字不参与 folding。 ### 15.7 Drag/drop table 与 column 建议支持: - schema tree 中 table 拖入 editor; - column 拖入 editor; - payload 带 source connection/database/schema/database type; - context 不完整时拒绝; - 按源 dialect quote identifier; - 不依赖系统 `dataTransfer` 再反查已失效对象; - multi-line selection/drop 位置正确。 --- ## 16. 格式化与压缩 ### 16.1 能力 - format selection; - format full document; - compress selection/document; - SQL; - Mongo; - Elasticsearch; - JSON; - XML。 ### 16.2 安全行为 - 输入上限建议 1,000,000 chars; - XML-looking 内容不送 SQL formatter; - editing surface 遇到 parse error 返回原文并提示; - display surface formatter 失败返回 sanitized raw text; - async format 返回时确认 document revision 和原 range 内容未变化; - formatter 不得覆盖用户在等待期间的新编辑。 ### 16.3 配置 - keyword case; - type case; - function case; - identifier case; - indentation; - tab width; - logical operator newline; - FROM layout; - expression width; - query spacing; - dense operators; - semicolon; - parameter style; - JSON import/export。 ### 16.4 Compress 必须保护: - string 内空白; - quoted identifier; - MySQL executable/versioned/optimizer comments; - PostgreSQL dollar quote; - nested block comments; - SQL Server bracket identifier; - 未闭合 block comment 原文。 --- ## 17. 快捷键、Toolbar 与 Context Menu ### 17.1 快捷键行为 至少: - execute; - execute in new result tab; - execute all; - save; - format; - compress; - `SELECT *` expansion; - find/replace; - indent/outdent; - duplicate/delete/move line; - undo/redo; - uppercase/lowercase; - line/block comment; - fold; - `IN` paste; - completion; - signature help; - next/previous snippet field。 DBX 的关键约束: - Enter 不是执行,而是插入保持缩进的新行; - Enter 先关闭 completion,并短暂抑制自动 completion; - Tab 只有在 selection 为空时才允许 completion/snippet 接管; - shortcut execution bypass picker; - Vim 模式时 Vim keymap 优先。 ### 17.2 Toolbar DBX toolbar 能力包括: - execute/cancel; - Explain/cancel Explain; - Explain Analyze/Autotrace; - Format; - Compress; - keyword case; - semantic diagnostics toggle; - dangerous command toggle; - save/open; - import result archive; - `IN` paste; - multi-database execute; - auto/manual transaction; - commit/rollback。 Navop 可按现有产品范围分期,但 action contract 应预留: ```rust pub enum SqlEditorAction { Execute, ExecuteAll, ExecuteNewResult, Cancel, Explain, ExplainAnalyze, Format, Compress, ExpandWildcard, PasteAsInList, ToggleDiagnostics, Commit, Rollback, } ``` ### 17.3 Context menu 同步顺序 严格顺序: 1. pointer coordinate → text offset; 2. 根据 pointer 同步 selection; 3. 同步 executable statement range; 4. 同步 object target; 5. 关闭旧 hover; 6. 构建并打开 menu。 不能先打开菜单,再异步更新 target。 菜单建议: - execute selection/current; - execute in new result tab; - object actions; - expand `SELECT *`; - comments; - format/compress; - copy/cut/paste; - uppercase/lowercase; - paste as SQL IN; - find/replace; - delete blank lines; - select all。 --- ## 18. 结果面板与编辑器联动 ### 18.1 DBX 能力 - editor/result split pane; - multiple result runs; - result/summary/chart/messages; - running/error/cancel/evicted/empty states; - statement summary; - statement status; - 点击 statement 预览; - 双击 statement 聚焦 source; - execution end 后可滚动到 cursor statement; - statement marker 与 result fingerprint 对齐。 ### 18.2 Navop source map ```rust pub struct SqlExecutionResultSource { pub request_id: u64, pub document_revision: u64, pub source_range: Option, pub sql_fingerprint: u64, pub statement_index: Option, } ``` 行为: - result row/run 保留 source identity; - 单击 result statement:编辑器 preview range; - 双击:如果 current document revision 相同,scroll and select/focus; - revision 不同但 fingerprint 唯一匹配时可提示用户跳转; - 无法匹配时只展示 SQL snapshot,不在当前文档错误定位; - 新 execution 不继承旧 execution 的 focused result index; - message result 与 data result 的默认 focus 规则明确。 ### 18.3 可编辑结果集 DBX 还有 SQL 分析支撑结果表 inline edit: - 识别单表可编辑 SELECT; - projection 到 source column 映射; - primary key identity; - join/quoted alias; - set operation、DISTINCT、aggregation、computed column 等保守拒绝; - 映射不唯一时只读,不猜测。 这部分可作为后续 phase,但 semantic model 设计不应阻断它。 --- ## 19. 编辑器生命周期与状态 ### 19.1 DBX 原则 DBX 使用: > 单一长期存活的 `EditorView` + Compartment 局部重配置 而不是 settings/props 每次变化时重建编辑器。 Navop 对应原则: - `InputState`/`SqlEditor` entity 长期存活; - theme、wrap、read-only、completion、diagnostics 开关通过状态更新; - 不因 connection/schema 刷新而重建文本 entity; - 保留 undo history、selection、viewport、composition。 ### 19.2 Update flow 文档变化: - increment revision; - invalidate completion; - invalidate diagnostics; - clear current execution marker projection; - schedule statement/semantic analysis; - emit model change; - persist selection/viewport(debounced)。 Selection/cursor 变化: - update current statement frame; - update signature help; - update context action target; - 不递增 document revision。 Viewport 变化: - schedule viewport diagnostics; - schedule INSERT hints; - update visible semantic highlights; - 不重算全文 metadata。 ### 19.3 IME Composition start: - invalidate completion; - 暂停会破坏 composition 的自动 edit; - 不高频回写外部 model。 Composition end: - flush final text; - increment revision once or按实际 transaction; - schedule diagnostics; - schedule completion; - 不接受 composition 前发出的 async result。 ### 19.4 Deactivate/activate Deactivate: - flush selection/viewport; - cancel hover pending; - invalidate completion; - cancel diagnostics timer; - stop background UI refresh; - unregister transient pointer/drop listeners; - 不销毁 text state。 Activate: - restore listeners; - restore viewport/selection; - schedule visible diagnostics; - refresh metadata-dependent decorations; - 按产品策略 restore focus。 Destroy: - cancel timers/tasks/animation frames; - remove window/pointer/scroll listeners; - destroy popovers; - release metadata subscriptions; - clear marker hitboxes; - 不让 callback 捕获已销毁 entity。 --- ## 20. Navop 当前能力与差距 ### 20.1 已有能力 `crates/db_view/src/sql_editor.rs`: - SQL code editor; - completion provider; - hover provider 注入; - actions; - line number; - soft wrap; - schema/table/column/function 基础 completion; - tokenizer + context inferrer + symbol table。 `crates/db_view/src/sql_editor_view.rs`: - connection/database/schema; - current/all/selected/cursor statement execution; - transaction/session; - result container; - toolbar/editor/result 布局。 `crates/ui/src/input/state.rs` 与 `element.rs`: - line number; - line decoration background; - diagnostics style; - hover provider; - completion menu; - inline completion; - visible row range; - mouse point → offset; - fold gutter; - line number hitbox; - range layout/paint。 ### 20.2 主要差距 | 层 | 缺口 | |---|---| | Input | 通用 marker lane、marker icon/state/tooltip/action、独立 hitbox | | Input | editor document revision 的公开 contract | | Input | SQL diagnostics 可消费的公共 range model | | Input | generic inline widget/decorations | | SQL tokenizer | 完整方言 lexical state、dollar quote、delimiter/routine | | Statement | editor-safe unified statement snapshot | | Semantic | CTE、derived table、projection、reference graph | | Completion | 多 source merge、stale request contract、qualified replacement | | Metadata | 作用域、object kind、detail、DDL、revision cache | | Hover | qualified symbol resolver 和 object detail renderer | | Diagnostics | parser/semantic/metadata/execution 统一模型 | | Execution | `ExecutionRequest`、source map、exact range | | Result | revision/fingerprint 绑定 | ### 20.3 Provider overwrite 风险 当前 `set_db_completion_info` 会重建 provider。如果直接新增 DBX 风格 provider,schema refresh 可能把它覆盖。 必须改为: - 一个长期存活的 `MergedSqlCompletionProvider`; - schema/DB completion info 只更新 metadata source 的数据; - 外部 provider 作为独立 source; - 不通过 setter 替换整个 provider object。 --- ## 21. 文件级实施落点 ### 21.1 `crates/db` #### 新增 ```text crates/db/src/sql_editor/document.rs crates/db/src/sql_editor/dialect.rs crates/db/src/sql_editor/identifier.rs crates/db/src/sql_editor/statement_ranges.rs crates/db/src/sql_editor/analysis.rs crates/db/src/sql_editor/semantic_model.rs crates/db/src/sql_editor/diagnostics.rs crates/db/src/sql_editor/metadata.rs ``` #### 修改 ```text crates/db/src/sql_editor/sql_tokenizer.rs crates/db/src/sql_editor/sql_symbol_table.rs crates/db/src/sql_editor/sql_context_inferrer.rs crates/db/src/sql_editor/mod.rs ``` 职责: - 纯 SQL 数据结构和算法; - 不依赖 GPUI; - byte offset; - deterministic unit tests; - incomplete SQL 保守恢复。 ### 21.2 `crates/ui` #### 修改 ```text crates/ui/src/input/state.rs crates/ui/src/input/element.rs crates/ui/src/input/lsp/hover.rs crates/ui/src/input/lsp/completions.rs crates/ui/src/input/popovers/completion_menu.rs ``` 职责: - 通用 gutter/decorations; - hitbox; - marker event; - async provider host; - tooltip/completion rendering; - 不出现 SQL-specific object types。 可按现有目录风格新增: ```text crates/ui/src/input/gutter.rs crates/ui/src/input/decorations.rs crates/ui/src/input/inline_widget.rs ``` ### 21.3 `crates/db_view` #### 修改 ```text crates/db_view/src/sql_editor.rs crates/db_view/src/sql_editor_view.rs ``` 职责: - SQL facade; - metadata provider; - analysis scheduling; - connection scope; - execution request; - result integration; - context menu; - toolbar/actions。 如文件继续膨胀,建议拆分: ```text crates/db_view/src/sql_editor/ ├── completion_provider.rs ├── hover_provider.rs ├── metadata_cache.rs ├── execution.rs ├── diagnostics.rs └── actions.rs ``` ### 21.4 不应修改的边界 - 不要把 SQL parser 逻辑写进 `render_sql_editor`; - 不要把 SQL-specific marker 写死在 `TextElement`; - 不要让 `SqlEditor` 自己串行拉全库所有 columns; - 不要让 completion 直接持有 stale connection entity; - 不要在未协调时覆盖 `crates/db/src/streaming_parser.rs` 的既有修改。 --- ## 22. 分阶段实施计划 ### Phase 0:Contract 与测试基线 交付: - `SqlTextRange` byte offset contract; - `SqlDocumentSnapshot` revision; - `SqlMetadataScope` generation; - `QualifiedIdentifier`; - `SqlExecutionRequest`; - `SqlCompletionRequest`; - 测试 fixture 与 DBX parity case list。 验收: - 所有模块只使用显式 range type; - 不再用不注明单位的 `(usize, usize)` 跨层传 SQL range; - 文档 revision 单调递增; - scope generation 可观测。 ### Phase 1:Statement Range Engine 交付: - quote/comment/dollar quote; - `;`; - `GO`; - `DELIMITER`; - Oracle `/`; - routine/block; - current statement lookup; - executable line; - cache。 验收: - gutter/current/frame 对同一 cursor 返回同一 statement; - 不依赖 UI; - 完成 DBX statement range 测试移植。 ### Phase 2:通用 GPUI Gutter 交付: - marker model; - lane layout; - independent hitbox; - icon/state/tooltip; - mouse event; - soft-wrap/fold/scroll 行为。 验收: - 多行 statement 只显示一次; - 点击不改变 selection/focus; - 文档变更清 marker; - UI snapshot/manual test 覆盖。 ### Phase 3:精确执行 交付: - `ExactRange`; - selection/current/all priority; - gutter execution; - statement identity; - running/success/error/cancel marker; - result source fingerprint。 验收: - gutter 永远执行点击的 statement; - 当前 cursor 在另一 statement 不影响; - 编辑文档后旧 marker 不落到新 statement; - SQL Server batch 正确。 ### Phase 4:Metadata Model 与 Cache 交付: - object/column/detail/DDL model; - scope-aware key; - generation guard; - lazy column fetch; - bounded concurrency; - cache invalidation。 验收: - 同名跨 schema table 不串数据; - connection 切换后旧响应不写 cache; - 大 schema 不执行逐表串行列加载。 ### Phase 5:Completion 交付: - merged provider; - table/schema/database; - fields; - alias-qualified fields; - CTE/derived table; - routine/signature; - snippets; - keyword; - wildcard expansion; - rank/dedupe; - stale cancellation。 验收: - 文档测试矩阵中 completion 核心 case 通过; - `alias.` 首屏响应不被全库扫描阻塞; - schema refresh 不覆盖 provider。 ### Phase 6:Hover 与 Navigation 交付: - qualified identifier; - semantic target; - object detail; - DDL preview; - Cmd/Ctrl-click; - context actions。 验收: - quoted/multi-part identifier 正确; - cache scope 正确; - old hover response 不显示; - DDL fallback 明确标注非权威。 ### Phase 7:Diagnostics 交付: - parser error; - unknown table/column; - execution error mapping; - viewport scheduling; - run id; - squiggle/hover detail。 验收: - 多表歧义不误报; - metadata incomplete 不误报; - stale result 不绘制; - long statement 中段可见仍能诊断。 ### Phase 8:Editing Utilities 交付: - format/compress; - comment/case; - wildcard expansion action; - INSERT value hints; - `IN` paste; - quote caret; - parameters; - variables; - snippets/signature。 ### Phase 9:Persistence 与 Result Integration 交付: - selection anchor/head; - viewport; - current statement frame; - result runs; - statement summary; - execution source navigation; - tab activate/deactivate lifecycle。 --- ## 23. 验收测试矩阵 ### 23.1 Statement ranges 必须覆盖: - 多条顶层 statement; - 末尾无分号; - string 中分号; - escaped quote; - double quote/backtick/bracket identifier; - line/block comment 中分号; - PostgreSQL dollar quote; - MyBatis placeholder 与 hash-comment; - MySQL `DELIMITER`; - procedure/function/trigger; - nested `CASE/BEGIN`; - SQL Server `GO`,并忽略 string/comment 中的 `GO`; - Oracle/Xugu/GaussDB/SAP HANA block; - cursor 在 statement 内容; - 前置缩进; - 同行分号后空白; - trailing comment; - 下一 statement 起点; - 单独下一行分号; - 空行/纯注释返回 None; - Elasticsearch REST request。 DBX 基准: - `apps/desktop/src/lib/__tests__/sql/sqlStatementRanges.spec.ts` ### 23.2 Gutter 必须覆盖: - 多行 statement 精确映射; - routine 只有一个 marker; - placeholder-only line; - directive 后 executable line; - SQL Server temp table; - 普通前导块注释不附着; - continuation line 不显示 marker; - delimiter gap; - trailing whitespace; - doc revision/dialect 变化重建 cache; - left mouse only; - click 不移动 cursor; - running/success/error state。 DBX 基准: - `apps/desktop/src/lib/__tests__/sql/executableStatementRangeCache.spec.ts` 注意:DBX 缺少完整 gutter UI render test,Navop 应新增 GPUI element/hitbox 测试。 ### 23.3 Completion 必须覆盖: - keyword typing trigger; - `ORDER BY DESC` 不误判为 table context; - quoted mixed-case schema/sequence; - escaped apostrophe; - dialect-isolated function; - existing `(` 不重复; - `*` 单表/多表/alias/重复字段/FROM 顺序; - stale/incomplete metadata 拒绝 wildcard; - qualified schema/database; - alias-qualified column; - JOIN; - CTE/subquery; - WHERE/INSERT/UPDATE; - alias generation; - Oracle no `AS`; - explicit completion 在受限模式仍可用; - snippet; - routine parameter/signature; - large catalog performance。 DBX 基准: - `apps/desktop/src/lib/__tests__/sql/sqlCompletion.context.spec.ts` - `apps/desktop/src/lib/__tests__/sql/sqlCompletion.signature.spec.ts` - `apps/desktop/src/lib/__tests__/sql/sqlCompletion.snippet.spec.ts` - `packages/app-tests/sqlCompletion.test.ts` - `packages/app-tests/sqlCompletionRoutineParameters.test.ts` - `packages/app-tests/sqlCompletionPerformance.test.ts` ### 23.4 Hover/navigation 必须覆盖: - no/single/composite PK; - empty columns; - SQL Server `varchar(max)` / `datetime2(7)`; - precision/scale; - indexes/comments/constraints; - partition/distribution; - sanitize MySQL/MariaDB charset/collation; - PostgreSQL access-control tail; - preserve companion statements; - raw DDL; - defaults containing comma; - unsupported type fallback; - catalog/database/schema cache scope; - cross-database bare-name rejection; - statement-local navigation target; - stale hover response。 DBX 基准: - `apps/desktop/src/lib/editor/__tests__/hoverTableSql.spec.ts` - `apps/desktop/src/lib/__tests__/sql/sqlNavigation.spec.ts` ### 23.5 Diagnostics 必须覆盖: - missing table/column; - empty/incomplete metadata; - alias; - correlated subquery; - nested scope; - multi-table ambiguity; - parser line/column; - severity/message/span; - viewport complete statement; - long statement middle viewport; - SQL Server `GO` batch; - procedure/function/Oracle PL/SQL skip; - Mongo/Elasticsearch skip; - stale document; - execution range base offset。 DBX 基准: - `packages/app-tests/sqlSemanticDiagnostics.test.ts` ### 23.6 Formatting 必须覆盖: - whitespace compress; - comment handling; - preserve strings/identifiers; - empty input; - already compressed; - executable comma placement; - unclosed block comment; - MySQL executable/versioned/optimizer comments; - backslash escape; - `#` comment; - MySQL `--` rule; - PostgreSQL dollar quote/nested comment/E-string; - SQL Server bracket identifier。 DBX 基准: - `packages/app-tests/sqlFormatter.test.ts` ### 23.7 Editing 必须覆盖: - quote caret; - large paste; - text edits; - newline indentation; - line/block comments; - selection case; - `IN` paste; - INSERT value hints; - trimmed selection; - folding; - context-menu target ordering; - table/column drag-drop; - parameters; - variables; - editable query conservative rejection。 DBX 基准: - `apps/desktop/src/lib/__tests__/sql/sqlQuoteCaret.spec.ts` - `apps/desktop/src/lib/__tests__/sql/sqlSelectionCase.spec.ts` - `apps/desktop/src/lib/__tests__/sql/sqlInListPaste.spec.ts` - `apps/desktop/src/lib/__tests__/editor/*` - `apps/desktop/src/components/editor/__tests__/QueryEditorContextMenu.spec.ts` - `packages/app-tests/sqlParameters.spec.ts` - `packages/app-tests/sqlVariables.spec.ts` - `packages/app-tests/sqlAnalysis.test.ts` - `packages/app-tests/queryEditorTableDrop.test.ts` ### 23.8 Execution/result 必须覆盖: - selection/current/all/exact range; - Mongo current command; - SQL Server `GO` batch; - trailing whitespace; - current frame 与 gutter range 一致; - stale marker; - cancel; - error source mapping; - new result tab; - result default focus; - result source double-click。 DBX 基准: - `packages/app-tests/sqlExecutionTarget.test.ts` - `packages/app-tests/sqlBatchScript.test.ts` - `apps/desktop/src/lib/__tests__/sql/currentStatementFrame.spec.ts` - `packages/app-tests/sqlserverResultFocus6189.test.ts` --- ## 24. 性能目标 以下为 Navop 建议目标,不是 DBX 源码中明确 SLA。 ### 24.1 编辑输入 - 普通 keypress 的同步 SQL 工作:P95 < 4ms; - UI thread 不进行远端 metadata I/O; - 不在每次 keypress 全文重建所有 columns; - statement range scanner 对普通文档 O(n),cache 后 cursor lookup O(log n); - 100k 字符文档滚动无明显卡顿; - 1M 字符文档仍可编辑,重分析按 viewport/statement。 ### 24.2 Completion - local semantic/keyword candidates:P95 < 30ms; - cache-hit table/column completion:P95 < 50ms; - remote metadata 不阻塞首批 local popup; - popup 最大 candidates 有上限; - large schema 搜索分页; - 每个 editor 同类 remote request 可合并/取消。 ### 24.3 Hover - cache hit:目标 50ms 内; - cache miss:显示 loading skeleton 或延迟出现; - pointer 移动后旧请求立即逻辑失效; - DDL formatting 在 background task。 ### 24.4 Diagnostics - 默认 debounce 500ms; - viewport analysis 优先; - metadata enrichment bounded concurrency; - 不因 diagnostics 阻塞输入或 completion。 --- ## 25. 高风险与强制规则 ### 25.1 Provider overwrite **风险**:`set_db_completion_info` 重建 provider,导致新 provider 被 schema refresh 覆盖。 **强制规则**:provider 长期存活,更新 source 数据,不替换 provider。 ### 25.2 Stale async **风险**:旧 completion/hover/metadata/diagnostics 返回后污染新文档。 **强制规则**:所有 async response 检查 request id + revision + scope generation。 ### 25.3 Statement splitter divergence **风险**:gutter 显示 A,Run Current 执行 B,driver 再切成 C。 **强制规则**:编辑器所有 target 使用同一 snapshot;driver 接收已解析 execution request,除协议必要外不二次猜 cursor statement。 ### 25.4 Offset mismatch **风险**:Rust byte、Rope char、UTF-16 混用,在中文/emoji 前后错位。 **强制规则**:内部 byte offset,边界显式转换,测试包含中文和 emoji。 ### 25.5 Multi-database semantics 必须显式处理: - Oracle schema; - MySQL `database.table`; - PostgreSQL `database.schema.table`; - `uses_schema_as_database`; - IPC schema switch; - session-scoped current database/schema。 ### 25.6 Quoted identifier 不能无条件 lowercase: - `"Foo"`; - `` `Foo` ``; - `[Foo]`。 ### 25.7 Large schema 禁止: - 连接时逐表串行加载 columns; - completion 每次遍历无限 catalog; - cache key 只有 table name; - popup 等待全量 remote 才显示。 ### 25.8 Hover DDL 禁止: - metadata fallback 冒充 backend DDL; - formatter parse error 后返回空; - sanitize 改变 statement 语义; - 在 hover 失败时弹打断用户的全局 toast。 ### 25.9 Right-click stale target 菜单 target 必须在打开前同步,异步菜单 action 绑定本次 context-menu identity。 ### 25.10 IME composition 期间不得触发会替换 composition range 的 completion/edit action。 ### 25.11 Result marker 旧 result 只能绑定旧 revision/fingerprint,不能按相同行号直接挂到新文档。 ### 25.12 Resource leak hover、popover、timer、pointer/scroll/window listener、background task 在 deactivate/destroy 时必须清理。 --- ## 26. Definition of Done 只有满足以下全部条件,才可认为“DBX 风格 SQL 编辑器核心改造”完成。 ### 26.1 Statement 与执行 - [ ] 每条 executable statement 起始行显示运行图标; - [ ] 多行 SQL 只显示一次; - [ ] comment/string/dialect delimiter 不误切; - [ ] gutter 精确执行且不移动 cursor; - [ ] current/all/selection/exact range 规则一致; - [ ] current statement frame 与 gutter range 一致; - [ ] execution marker 有 running/success/error/cancel; - [ ] 编辑后旧 marker 不错位。 ### 26.2 Completion - [ ] table/schema/database; - [ ] field completion; - [ ] alias-qualified fields; - [ ] JOIN/INSERT/UPDATE context; - [ ] CTE/derived table columns; - [ ] projection alias dialect rules; - [ ] routines/signatures; - [ ] keyword/snippet; - [ ] `SELECT *` safe expansion; - [ ] rank/filter/dedupe; - [ ] stale cancellation; - [ ] large schema 不阻塞。 ### 26.3 Hover/navigation - [ ] qualified/quoted identifier; - [ ] table/view/materialized view/routine; - [ ] columns/type/nullability/default/comment; - [ ] PK/index/FK; - [ ] backend DDL; - [ ] marked fallback DDL; - [ ] scope-safe cache; - [ ] Cmd/Ctrl-click 和 context actions; - [ ] stale hover 不显示。 ### 26.4 Diagnostics/editing - [ ] parser error; - [ ] unknown table/column; - [ ] execution error mapping; - [ ] viewport/stale guard; - [ ] formatter/compress; - [ ] quote caret; - [ ] `IN` paste; - [ ] case/comment actions; - [ ] parameters/variables; - [ ] INSERT value hints。 ### 26.5 Lifecycle/quality - [ ] document revision contract; - [ ] metadata generation contract; - [ ] byte offset contract; - [ ] deactivate/activate/destroy cleanup; - [ ] DBX 边界测试已移植; - [ ] GPUI gutter hitbox/render test; - [ ] 中文/emoji offset test; - [ ] large catalog performance test; - [ ] 没有覆盖用户现有 `streaming_parser.rs` 修改。 --- ## 27. DBX 源码索引 ### 27.1 Editor 主组件与布局 - `dbx/apps/desktop/src/components/editor/QueryEditor.vue` - `dbx/apps/desktop/src/components/layout/EditorToolbar.vue` - `dbx/apps/desktop/src/components/layout/ContentArea.vue` ### 27.2 Statement 与 execution - `dbx/apps/desktop/src/lib/sql/sqlStatementRanges.ts` - `dbx/apps/desktop/src/lib/sql/executableStatementRangeCache.ts` - `dbx/apps/desktop/src/lib/sql/statementDelimiter.ts` - `dbx/apps/desktop/src/lib/sql/sqlExecutionTarget.ts` - `dbx/apps/desktop/src/lib/sql/currentStatementFrame.ts` - `dbx/apps/desktop/src/lib/editor/codemirrorStatementGutter.ts` - `dbx/apps/desktop/src/lib/editor/codemirrorCurrentStatementFrameLayer.ts` ### 27.3 Completion 与 semantic - `dbx/apps/desktop/src/lib/sql/sqlCompletion.ts` - `dbx/apps/desktop/src/lib/sql/sqlCompletionLookupTarget.ts` - `dbx/apps/desktop/src/lib/sql/sqlSnippetTemplates.ts` - `dbx/apps/desktop/src/lib/sql/sqlSyntaxTreeWindow.ts` - `dbx/apps/desktop/src/lib/sql/semantic/completion.ts` - `dbx/apps/desktop/src/lib/sql/semantic/model.ts` - `dbx/apps/desktop/src/lib/sql/semantic/references.ts` - `dbx/apps/desktop/src/lib/metadata/completionTreeIndex.ts` - `dbx/apps/desktop/src/stores/connectionStore.ts` - `dbx/crates/dbx-core/src/types.rs` - `dbx/crates/dbx-core/src/schema.rs` ### 27.4 Hover/navigation - `dbx/apps/desktop/src/lib/sql/queryCursorTableTarget.ts` - `dbx/apps/desktop/src/lib/sql/sqlNavigation.ts` - `dbx/apps/desktop/src/lib/editor/hoverTableSql.ts` - `dbx/apps/desktop/src/lib/editor/sqlHoverLayout.ts` - `dbx/apps/desktop/src/lib/editor/sqlSignatureTooltip.ts` ### 27.5 Diagnostics - `dbx/apps/desktop/src/lib/sql/semantic/diagnostics.ts` - `dbx/apps/desktop/src/lib/sql/sqlDiagnostics.ts` ### 27.6 编辑辅助 - `dbx/apps/desktop/src/lib/sql/insertValueHints.ts` - `dbx/apps/desktop/src/lib/editor/codemirrorInsertValueHints.ts` - `dbx/apps/desktop/src/lib/sql/sqlQuoteCaret.ts` - `dbx/apps/desktop/src/lib/sql/sqlInListPaste.ts` - `dbx/apps/desktop/src/lib/sql/sqlSelectionCase.ts` - `dbx/apps/desktop/src/lib/sql/sqlParameters.ts` - `dbx/apps/desktop/src/lib/sql/sqlVariables.ts` - `dbx/apps/desktop/src/components/editor/SqlParameterDialog.vue` - `dbx/apps/desktop/src/lib/sql/sqlAnalysis.ts` ### 27.7 Format/history/save - `dbx/apps/desktop/src/lib/sql/sqlFormatter.ts` - `dbx/apps/desktop/src/lib/sql/sqlFormatterConfig.ts` - `dbx/apps/desktop/src/lib/sql/autoFormat.ts` - `dbx/apps/desktop/src/stores/historyStore.ts` - `dbx/apps/desktop/src/stores/savedSqlStore.ts` - `dbx/apps/desktop/src/lib/sql/sqlFileOpen.ts` - `dbx/apps/desktop/src/composables/useExternalSqlFileChanges.ts` --- ## 28. Navop 源码索引 - `navop/crates/db/src/sql_editor/sql_tokenizer.rs` - `navop/crates/db/src/sql_editor/sql_symbol_table.rs` - `navop/crates/db/src/sql_editor/sql_context_inferrer.rs` - `navop/crates/db/src/streaming_parser.rs` - `navop/crates/db_view/src/sql_editor.rs` - `navop/crates/db_view/src/sql_editor_view.rs` - `navop/crates/ui/src/input/state.rs` - `navop/crates/ui/src/input/element.rs` - `navop/crates/ui/src/input/lsp/hover.rs` - `navop/crates/ui/src/input/lsp/completions.rs` - `navop/crates/ui/src/input/popovers/completion_menu.rs` --- ## 29. 推荐给实施 Agent 的执行方式 1. 不要从 UI 图标开始孤立实现;先完成 Phase 0 contract; 2. Phase 1 先移植 statement range tests,再实现 scanner; 3. Phase 2 的 gutter 必须作为 GPUI Input 通用能力,不写死 SQL; 4. Phase 3 后即可交付用户最直观的“每条完整 SQL 左侧运行”能力; 5. metadata 和 completion 分开做,先改 provider 生命周期,避免后续被覆盖; 6. 每个 async 功能先写 stale-response test,再接远端; 7. hover 首先实现 cache-hit table detail,再逐步接 DDL 和 navigation; 8. diagnostics 必须在 statement/semantic snapshot 稳定后实现; 9. 每个 phase 都应保持 editor 可运行,不做大爆炸重写; 10. 所有涉及 `streaming_parser.rs` 的改动先确认并保留当前工作树中的既有修改。 最终架构的判断标准不是“看起来像 DBX”,而是: - SQL statement 语义一致; - 异步结果不会错位; - qualified/quoted identifier 不丢信息; - 大 schema 不阻塞; - execution、completion、hover、diagnostics 共用统一 snapshot; - GPUI Input 基础设施仍然是通用、可复用的。