- 桌面应用
- 开发者工具
- 人工智能
- AI 应用
- AI Agent
- 代码智能体
【免费下载链接】warp
Warp is an agentic development environment, born out of the terminal.
本篇技术指南基于 Warp 开源仓库中的 side-by-side 技术规格(配套产品规格见 product.md),系统讲解在 Code Review 面板中引入SideBySide(左右并排)Diff 布局的完整实现方案:从DiffLayout枚举与code.editor.diff_layout设置项的定义,到"基线 + 修改"双CodeEditorView实例经桥接包装器协同渲染的架构,再到行对齐(hunk alignment)、滚动同步、评论线程、遥测与无障碍设计。读完本文,你将掌握 Warp 如何在保持内联 Diff 零回归的前提下,用特性开关分阶段推出并排视图,以及其与DiffMode、DisplayMode两个既有概念的正交关系。
一、背景:为什么需要并排 Diff
Warp 当前把 Code Review 文件差异渲染为单列内联视图:删除行以-前缀、新增行以+前缀交错排布。内联视图本身没问题,但面对 AI 生成的大规模改动时存在两个现实痛点:
- 阅读负担:当一段 30 行的修改包含代码重排时,同一逻辑块在内联视图里被拆成两处——一处全是
-行、另一处全是+行,评审者需要在大脑中把两段重新拼合才能理解"改了什么"。 - 行业惯例:GitHub、GitLab、Phabricator、JetBrains IDE、VS Code 等主流工具均以并排视图作为 Diff 评审的事实标准,宽屏用户对此有明确预期。
因此 v1 的目标是:在Code Review 面板内提供可切换的Inline/SideBySide两种布局,并排视图左侧为基线内容(删除可见)、右侧为修改后文件(新增可见),通过 hunk 对齐让对应行保持在同一垂直位置。默认仍为Inline,存量用户零感知、按需开启。
二、核心抽象:DiffLayout与两个既有概念的边界
规格明确提出新增DiffLayout枚举,定义于app/src/code/diff_layout.rs,从 code/mod.rs 再导出:
use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum DiffLayout { #[default] Inline, SideBySide, } impl DiffLayout { pub fn is_side_by_side(&self) -> bool { matches!(self, DiffLayout::SideBySide) } }serde的snake_case表示("inline"/"side_by_side")与设置存储值一一对应;Copy派生使它可以无生命周期负担地在视图上下文中传递。
规格特别强调DiffLayout与两个既有概念严格正交:
DisplayMode:回答"这个 Diff 渲染在屏幕的哪里"——独立面板、嵌入视图还是内联横幅;DiffMode:回答"拿什么和什么比"——对比基是Head/MainBranch/OtherBranch(String)。这一枚举真实存在于仓库 diff_state/mod.rs 中,并带有from_branch构造方法;DiffLayout:回答"Diff 内容怎么排版"——单列还是双列。
三者互不干扰:改变布局不改变对比基,DiffMode选择器("Head / Main Branch / Other Branch")在并排模式下原样保留。v1 只在 Code Review 面板读取DiffLayout,即使存储值为side_by_side,AI block-list 与内联横幅两种宿主仍保持现有内联行为。
三、设置项:code.editor.diff_layout
布局偏好通过 settings/code.rs 中的define_settings_group!宏声明为CodeSettings的成员。仓库现有设置项(如format_on_save、auto_save)展示了该宏的字段结构:type、default、supported_platforms、sync_to_cloud、toml_path、description等。新设置项定义如下:
diff_layout: DiffLayoutSetting { type: crate::code::diff_layout::DiffLayout, default: crate::code::diff_layout::DiffLayout::Inline, supported_platforms: SupportedPlatforms::DESKTOP, sync_to_cloud: SyncToCloud::Globally(RespectUserSyncSetting::Yes), private: false, toml_path: "code.editor.diff_layout", description: "Layout for Code Review diff views: 'inline' or 'side_by_side'.", },设计要点:
- 默认
Inline:存量用户不受影响,除非主动切换; SyncToCloud::Globally:虽 v1 只有一个参与表面,但设置是全局存储,为 v2 扩展到其他表面预留空间,避免日后增加第二个设置名;- 类型系统天然支持枚举:设置组通过
serde承载强类型值,与仓库其他设置组的做法一致; - 声明不等于渲染:规格明确强调,仅声明设置项不会自动出现在设置页,必须在 UI 中显式注册控件。
四、设置页集成与遥测归属
code.editor.diff_layout的入口是Settings -> Code下新增的 "Diff layout" 分区,实现在 settings_view/code_page.rs:
- 新增
DiffLayoutWidget行,渲染一个双选项分段控件:"Inline" 与 "Side by side"; - 选中段读取自
CodeSettings::DiffLayout; - 段切换时通过设置存储写入
code.editor.diff_layout,并发出布局变更遥测事件; - 控件显式注册在 Code 设置组中、紧邻既有 Code Review 设置控件;
- 控件注册以
FeatureFlag::SideBySideDiffLayout.is_enabled()为门控,运行时开关关闭时整个控件隐藏。
同时明确职责边界:Diff 工具栏只保留视图级的临时控件(如空白符可见性),不暴露code.editor.diff_layout——布局是面向用户的 Code Review 级偏好。
遥测唯一归属:规格要求新增CodeReviewTelemetryEvent::DiffLayoutChanged { from: DiffLayout, to: DiffLayout }变体,登记于 telemetry_event.rs(该文件已定义CodeReviewTelemetryEvent枚举,并从CodeReviewTelemetryEventDiscriminants派生出name/description/enablement_state等元数据,通过warp_core::register_telemetry_event!注册)。事件只由 Settings -> Code 页面发出,Code Review 渲染层不得重复上报,避免重复埋点。若产品需要"按打开过的 Diff 统计采纳率",可另发渲染完成事件,但 v1 只保留一个设置变更事件拥有者。
五、特性开关SideBySideDiffLayout的分阶段投递
并排布局按 Warp 的标准特性开关流程落地,仓库中的真实位置如下:
- 枚举变体:在 crates/warp_features/src/lib.rs 的
FeatureFlag枚举中新增SideBySideDiffLayout,紧邻既有 Code Review 相关开关(如CodeReviewFind,位于该文件第 448 行)。 - 编译期注册:
- 在
app/Cargo.toml的[features]中新增side_by_side_diff_layout = [],沿用code_review_find = []的模式; - 在 app/src/lib.rs 的编译内特性列表中增加 cfg 门控条目:
#[cfg(feature = "side_by_side_diff_layout")] FeatureFlag::SideBySideDiffLayout,
- 在
- 运行时默认值:先加入 crates/warp_features/src/lib.rs 的
DOGFOOD_FLAGS(仓库注释表明该列表是"为开发团队启用的特性,预期会逐步进入 PREVIEW_FLAGS 后再发布");扩大范围时移入PREVIEW_FLAGS(第 1078 行,且预览开关自动包含于 dogfood 构建);在分阶段完成前不得加入RELEASE_FLAGS。 - 变更日志:为
description_for_changelog增加匹配臂,参照既有CodeReviewFind => Some("Enables the find bar in the code review pane.")(第 1163 行)的写法:SideBySideDiffLayout => Some("Enables a side-by-side diff layout in the code review pane."),
投递语义分三层:
- 编译期门控:
side_by_side_diff_layoutCargo feature 决定二进制是否包含FeatureFlag::SideBySideDiffLayout; - 运行时门控:特性开关服务决定当前渠道/用户下
is_enabled()的返回值; - 分发桥:Code Review 构造时先查运行时开关——关闭则无论存储值如何一律按
DiffLayout::Inline处理;开启则读取code.editor.diff_layout,分发到内联编辑路径或并排桥包装器。
默认排期:shipping 构建关闭 -> 5% dogfood -> 25% dogfood -> 100% dogfood -> preview -> release。开关隐藏时同时抑制设置控件与运行时布局路径。
六、架构核心:SideBySideDiffBridge双编辑器桥接
并排布局的实现策略是"两个CodeEditorView实例 + 一个父级桥接包装器",而不是改造编辑器内部。规格给出的结构:
pub struct SideBySideDiffBridge { baseline_view: CodeEditorView, modified_view: CodeEditorView, shared_diff_state: HunkAlignment, hidden_lines: HiddenLineRanges, scroll_anchor: SideBySideScrollAnchor, find_state: CodeReviewFindState, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Side { Baseline, Modified, }CodeEditorView真实存在于仓库 editor/view.rs,持有CodeEditorModel、Searcher、Find、VimModel、评论位置等字段,是渲染目标。v1 的两个实例分别是:select-only 的基线视图与正常的修改视图,由桥接器置于既有 Code Review 编辑器宿主内,等宽渲染、中间一条 1px 分隔线。
桥接器拥有的跨面板同步职责:
- 隐藏行区间:折叠的未改动区域只表示一次,同时应用到两个视图;任一侧展开隐藏行都更新共享隐藏行状态并重配两视图,保证高度对齐;
- 滚动位置:任一侧滚动都会更新共享行锚点,再驱动另一侧滚到对齐行。同步是行锚定而非像素锚定,避免字体、换行或行高差异累积漂移;
- 查找状态:一次 Code Review 查找会话横跨两个视图,两侧缓冲区中的命中都被高亮,"Next / Prev" 可跨面板遍历;
- 共享 Diff 状态:两个视图读取同一份 diff 结果与
HunkAlignment,从而对"哪些基线行是删除、哪些修改行是新增、视觉间隙该放哪里"达成一致。注意:共享的是 diff 状态,不是共享缓冲区。
两个缓冲区保持独立:基线视图的数据源是改动前内容,修改视图的数据源是工作文件的全局缓冲区条目。对修改缓冲区做编辑会重新触发 diff 计算,刷新后的 diff 更新两视图的装饰配置:新删除的基线行在基线视图中仍是普通可选中行,而修改视图将对应基线独有行渲染为间隙;新插入的修改行在修改视图中为普通行,在基线视图中则为间隙。
职责边界:编辑器内部(文本塑形、gutter、命中测试、选区、复制)留在各自子视图中;跨面板协调(事件目标判定、只转发可编辑事件给修改视图)全部收敛在桥接器中。
七、调用路由与面板内交互状态
调用者路由表
| 调用者 / 行为 | 面板感知路由 |
|---|---|
| 光标聚焦、本地选区、从修改侧复制 | 修改CodeEditorView |
| 从基线侧复制 | 基线CodeEditorView(仅选区聚焦) |
changed_lines | 修改CodeEditorView |
| Accept diff、保存 diff、拒绝回修改缓冲区的操作 | 修改CodeEditorView |
| Hunk 导航 | 桥接行对齐 + 修改侧聚焦 |
| 滚动保持 | 桥接滚动锚点 |
| 评论渲染与 gutter 标记 | 桥接HunkAlignment行映射 + 目标子视图 |
基线面板
- 恒为只读,使用基于基线内容的 select-only
CodeEditorView; - 所有基线行(包括被删除行区间,因为这些行在基线缓冲区中是真实行)都支持选择与复制;
- 不暴露插入光标、不消费键盘编辑事件、不参与文件落盘保存;
- 从桥接器接收删除装饰与隐藏行配置。
修改面板
- 使用基于工作文件全局缓冲区条目的正常
CodeEditorView; - 独占光标与全部可写交互,遵循既有 Code Review 的 accept / reject / save / revert / hunk 导航规则;
- 是唯一向
FileModel注册的一侧; - 使用"将基线独有行渲染为视觉间隙而非临时删除块"的装饰配置。
桥接器把 Code Review 交互状态应用于修改面板,基线面板的交互状态硬编码为只读选择/复制。其他表面的FullPane行为不在 v1 范围内。
面板内容构造管线
并排复用既有 unified-diff 解析器,但不复用内联的删除行渲染。管线如下:
- 用既有解析器把 unified diff 解析为
DiffHunk[],解析器零改动; - 基于基线内容、当前修改全局缓冲区内容与有序 hunk 行构建共享 diff 状态;
- 对有序 hunk 行执行 hunk 对齐,每个
AlignedRow映射到两个面板的行索引;间隙行在两侧源文件中都不存在,但桥接器把它们作为装饰元数据传给对应视图; - 用基线缓冲区行、删除装饰、隐藏行与基线侧对齐元数据配置基线视图;
- 用全局缓冲区条目、新增装饰、隐藏行与"基线独有行渲染为视觉间隙"的装饰配置配置修改视图。
apply_diffs_if_any保持为内联路径。并排激活时桥接器改走面板内容管线,最终渲染语义为:删除行在基线视图中是普通可选行、在修改视图中是间隙;新增行在修改视图中是普通可编辑行、在基线视图中是间隙;修改侧禁用内联临时删除块渲染以防"删除出血";accept / reject / save / changed-line 计算仍读取修改缓冲区,与内联行为一致。
八、RowIndex与 hunk 对齐算法
规格在 app/src/code/hunk_alignment.rs 定义对齐数据模型,核心是让"行号"不再是一个裸整数:
pub struct DiffHunk { pub header: UnifiedDiffHeader, pub lines: Vec<DiffLine>, } pub enum DiffLine { Context(String), Add(String), Delete(String), } pub struct AlignedHunk { pub rows: Vec<AlignedRow>, } pub struct AlignedRow { pub left: PaneLine, pub right: PaneLine, pub row_index: RowIndex, } pub enum PaneLine { Line { buffer_line: usize, text: String }, Gap, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum RowIndex { Baseline(usize), Modified(usize), Gap { after_row: usize }, } pub struct HunkAlignment { pub baseline_rows: Vec<RowIndex>, pub modified_rows: Vec<RowIndex>, pub row_map: Vec<(Option<RowIndex>, Option<RowIndex>)>, } impl HunkAlignment { pub fn from_diff_hunks(hunks: &[DiffHunk]) -> Self; }RowIndex语义:Baseline(n)对应基线缓冲区第 n 行;Modified(n)对应修改缓冲区第 n 行;Gap { after_row }是插入在对齐行after_row之后的纯渲染间隙,不对应任何一侧的源行号。
对齐生成器遍历 hunk 时按以下规则产出RowIndex:
- Context 行:左
Baseline(b)、右Modified(m); - 成对的删除/新增修改行:左
Baseline(b)、右Modified(m); - 纯删除行:左
Baseline(b)、右Gap { after_row }; - 纯新增行:左
Gap { after_row }、右Modified(m)。
桥接器保存对齐结果,只把各自一侧的行元数据传给对应编辑器视图:Baseline(n)映射为基线视图真实文本行;Modified(n)映射为修改视图真实文本行;Gap { after_row }在对侧视图映射为带 gutter 与背景元数据的全高空白行。选区、复制、光标、保存与查找都忽略间隙行的源文本;对间隙行做命中测试时解析到最近的有效行,用于滚动锚定与评论定位。
v1 单遍算法
v1 是单遍算法,先配对塌缩的删除/新增连段再发射间隙行:
for hunk in hunks: pending_deletes = [] pending_adds = [] for line in hunk.lines: if line is Context: flush_pending_pairs() emit row(left = context, right = context) if line is Delete: if pending_adds is not empty: flush_pending_pairs() pending_deletes.push(line) if line is Add: pending_adds.push(line) flush_pending_pairs() flush_pending_pairs(): pair_count = min(pending_deletes.len, pending_adds.len) emit pair_count rows with left delete and right add emit remaining deletes with right Gap emit remaining adds with left Gap clear pending_deletes and pending_adds工作示例
Input hunk lines: Context("fn old() {") Delete(" a();") Delete(" b();") Add(" c();") Add(" d();") Context("}") Aligned rows: 1. left Context("fn old() {") | right Context("fn old() {") 2. left Delete(" a();") | right Add(" c();") 3. left Delete(" b();") | right Add(" d();") 4. left Context("}") | right Context("}")边界情况
- 纯插入块:行对为左
Gap、右Add,基线视图收到间隙装饰; - 纯删除块:行对为左
Delete、右Gap,修改视图收到间隙装饰; - Context 重置配对窗口:修改段中间的 Context 先把之前的删除冲刷掉,之后的新增另起配对;
- 按位置配对:删除连段后跟内容不相关的新增连段仍按位置配对;词级高亮超出 v1 范围,v1 只保证行对齐。
九、桥接滚动同步
滚动同步由桥接器所有,规格给出:
pub struct SideBySideScrollAnchor { focused_side: Side, anchor_row: RowIndex, anchor_side: Side, horizontal_scroll_by_side: BTreeMap<Side, ScrollOffset>, } impl SideBySideScrollAnchor { pub fn on_scroll_wheel(&mut self, side: Side, anchor_row: RowIndex); pub fn corresponding_row( &self, side: Side, row_index: RowIndex, alignment: &HunkAlignment, ) -> Option<RowIndex>; }滚动同步是行锚定的:任一视图的滚轮事件或 hunk 导航事件更新共享行锚点,桥接器再请另一视图从HunkAlignment揭晓对应行。水平滚动保持每面板独立。光标移动属于修改侧:当光标导航改变修改行时,corresponding_row计算最近的基线行仅供可见性对齐,不移动基线光标;hunk 导航更新共享滚动锚点与修改侧光标。若实现需要给事件打源标签以避免递归更新,该状态属于桥接器。规格同时提到可复用 scroll_preservation.rs 中现成的滚动保持工具。
十、Code Review 面板集成要点
并排路径走既有的 Code Review 编辑器宿主,而不是每个文件的InlineDiffView实例:
- 并排编辑器状态表示为两个
CodeReviewEditorState切片(或一个含baseline_sub_state/modified_sub_state的切片),两个子视图生命周期必须独立,即使父 reducer 入口共享; - Code Review 编辑器构造时计算有效布局:开关关闭用
Inline,开启则读code.editor.diff_layout; - 内联模式保持既有单编辑器路径;并排模式在渲染编辑器的既有容器(若是
LocalCodeEditorView,则在该路径下以桥接器替换单个LocalCodeEditorView实例)内渲染桥接器; - Code Review 宿主订阅设置更新:
code.editor.diff_layout变更时重建可见编辑器为目标布局,并借助 scroll_preservation.rs 保持滚动位置; - find-in-diff 在并排激活时获得一个
Side感知迭代器,可遍历两个子编辑器视图;内联只返回修改侧; - 隐藏行展开更新桥接器共享的隐藏行与对齐状态,再把相同塌缩区间应用到两个子视图。
架构中不存在InlineDiffView迁移步骤。
十一、v2 延后项与评论线程
AI block-list 与内联横幅延后到 v2
v1 明确排除两个表面:ai/blocklist/inline_action/code_diff_view.rs 继续构造内联 diff,InlineBanner继续走内联渲染路径;设置页帮助文本只提 Code Review;遥测不宣称这两个表面的采纳。v2 可在 Code Review 架构验证后复用同一个DiffLayout设置。
评论线程
code_review/comments/ 中的评论线程锚定在EditorLineLocation上,评论仍附着于这些位置并渲染在被指向行下方。并排集成要点:
- 并排行渲染器检查每条评论的
CommentSide(取自既有评论元数据),把线程渲染到匹配面板的行下; - 对侧面板在同行 gutter 显示一个小标记字形,提示"另一侧有线程",该标记在规格中不可交互;
- 横跨删除与新增区域的多行评论区间仍渲染在其最初撰写所针对的一侧。
由于两侧面板都读取桥接器共享的HunkAlignment,评论定位走共享行映射,无需在无关的 diff 模型间做临时坐标转换。
十二、无障碍设计
并排布局带来以下无障碍要求:
- VoiceOver:桥接器暴露两个带可访问标签的逻辑区域——基线为 "Original",修改为 "Modified";
- 编辑聚焦唯一性:修改面板是唯一编辑聚焦区域、唯一拥有光标区域;基线面板只在平台无障碍 API 允许"不暴露编辑动作"的前提下接收聚焦以支持选择/复制;
- 成对行朗读:对齐行成对读出为 "Original:
<text>; Modified:<text>",让非视障评审者也能同时听到两侧; - 键盘导航:
Tab到达修改编辑区;基线聚焦仅用于选择/复制;若实现Cmd+Option+Left/Right,则循环切换逻辑面板焦点但不把编辑所有权移出修改侧; - 颜色对比:间隙行背景使用专用主题令牌
diff.gap.background,在明暗两种主题下相对编辑器背景满足 3:1 对比度; - 开放风险:若平台无障碍树无法以可接受的读屏行为表示这两个桥接编辑器视图,在 side-by-side 发布到 dogfood 之外前必须升级处理。
十三、测试计划
单元测试
- app/src/code/hunk_alignment_tests.rs:空 diff 时每个 Context 行 row_map 为匹配的
Baseline(n)/Modified(n)且无间隙;纯新增为(Gap { after_row }, Modified(m));纯删除为(Baseline(b), Gap { after_row });塌缩修改Context Delete Delete Add Add Context产出 4 行对齐(1 上下文 + 2 配对 + 1 上下文);删除/新增序列中间的 Context 重置配对窗口;多 hunk 文件跨未改动 Context 正确组合;5,000 行 / 200 hunk 的大 diff 在 50ms 内完成(规格设定的验收预算); - app/src/code/editor/side_by_side_bridge_tests.rs:
DiffType::Update时基线视图持改动前内容带删除装饰、修改视图持改动后内容带新增装饰;DiffType::Create时基线视图为空含间隙、修改视图持新文件内容;DiffType::Delete反之;并排激活时apply_diffs_if_any不被调用;删除行在基线可选、在修改为间隙;新增行在修改可编辑、在基线为间隙;两侧间隙行渲染高度一致; - app/src/code/editor/side_by_side_interaction_tests.rs:基线子视图只读且无编辑光标;修改子视图是唯一注册
FileModel的一侧;基线选择可复制包括删除行区间;光标移动只影响修改侧;Inline与SideBySide互切后滚动位置误差在一行以内; - app/src/code/editor/side_by_side_scroll_tests.rs:滚轮增量更新桥接滚动锚点并在两面板揭晓对应行;修改侧光标移动把基线滚到对应行;光标位于
(Gap { after_row }, Modified(m))行时基线滚到最近的上下文行;桥接器抑制递归滚动更新。
集成测试
- app/src/settings_view/code_page_tests.rs:
SideBySideDiffLayout开启时 Code 页渲染DiffLayoutWidget;运行时开关关闭时控件隐藏;选择 "Side by side" 写入code.editor.diff_layout = "side_by_side";帮助文本只提 Code Review; - app/src/code_review/code_review_view_tests.rs:单文件 diff 在并排模式渲染两个
CodeEditorView子实例;多文件 diff 每个文件遵守同一布局;打开时翻转设置会重建每个可见编辑器并保持滚动;find-in-diff 命中两个子编辑器视图;hunk 导航(f/F)在两面板同步推进焦点 hunk 而光标留在修改侧;基线行评论线程渲染在基线面板行下、修改面板显示 gutter 标记;隐藏行展开从桥接共享对齐模型更新两个子视图。
无障碍验证
- 快照测试断言并排面板的可访问标签 "Original" / "Modified";
- 键盘测试覆盖
Tab与实现阶段选定的面板切换快捷键; - 测试断言基线聚焦不暴露编辑动作或插入光标;
- 主题测试断言
diff.gap.background在明暗主题下对编辑器背景满足 3:1 对比度; - macOS VoiceOver 人工冒烟测试:成对修改行朗读为一个逻辑原/改行。
手动冒烟测试(摘自规格)
- macOS M1 MacBook Air dogfood 构建(
SideBySideDiffLayout开启):Settings -> Code 切换 "Diff layout" 为 "Side by side",确认可见 Code Review diff 在 200ms 内刷新(规格设定的验收预算);打开 200 文件 diff 确认活动 diff 渲染为两个桥接编辑器视图;滚轮滚动两面板无抖动同步;基线面板拖选可复制(含删除行区间);修改面板选区不越界;光标只出现在修改面板;Cmd-A 只选中所在面板可选中内容;窗口缩窄到并排局促时两面板水平滚动条独立、分隔线保持 50%;AI block-list 嵌入 diff 与内联横幅 diff 在 v1 仍渲染为内联; - Linux(Ubuntu 24.04)与 Windows 11 各重复设置切换冒烟测试,确认渲染与键绑定。
编译并行检查清单
所有在match中解构DisplayMode的位置必须在新改动后仍可编译,规格列出的现有调用点包括 app/src/code/diff_viewer.rs(trait 辅助,因DiffLayout是新正交轴而不变)、app/src/ai/blocklist/inline_action/code_diff_view.rs(v1 不变)、app/src/ai/blocklist/block/view_impl/output.rs(匹配DisplayMode::FullPane,不变)。同时排查所有假定"单个编辑器状态"的 Code Review 站点:写、保存、光标、accept/reject 路径继续指向修改视图;渲染、评论、查找、选择与无障碍调用点在并排激活时经桥接器路由。
十四、未决问题与修订说明
规格留有 6 个未决问题,供实现评审阶段确认:
- 状态管理形态:
CodeReviewEditorState保持单切片 +baseline_sub_state/modified_sub_state,还是拆成两个并行切片?单切片保留既有 reducer 签名,双切片则清晰隔离两个视图生命周期; - diff 结果所有权:桥接器直接持有 diff 状态,还是上提给父级 Code Review 容器?前者封装性好,后者可被其他 Code Review 消费者复用;
- 查找跨面板 UX:"Next match" 跨面板时焦点是按匹配逐个跳转,还是留在当前面板直到其匹配全部访问完?需与产品确认是设计行为还是桥接内部细节;
- 对侧 gutter 评论标记:规格中不可交互,是否可点击是 Code Review SME 的 UX 决策,可作后续跟进项;
- 分段控件原语:
DiffLayoutWidget引用的既有设置分段控件,其实际原语名与导入路径需在实现评审中确认; - 可调分隔条:首次发布不包含(产品 Non-goals),是否后续重访取决于遥测与用户反馈。
修订说明(v4):v1 范围收窄到仅 Code Review,AI block-list 与内联横幅延后到 v2;恢复"两个CodeEditorView+ 桥接包装器"架构;明确右侧专属编辑与光标不变量;用RowIndex取代含糊的line_index;集成目标重定向到CodeReviewEditorState/LocalCodeEditorView;按已确认的桥接方向更新未决问题。
小结
DiffLayout与并排桥接架构在 Warp 中的定位是"不改编辑器内核、只在外部组合":DiffLayout枚举回答排版方式、code.editor.diff_layout负责持久化、SideBySideDiffLayout特性开关掌控投递节奏,而SideBySideDiffBridge用两个既有的CodeEditorView实例与行锚定同步把"左基线、右修改"拼装起来。这种设计让内联路径保持逐字节不变,同时为 v2 向 AI block-list 与内联横幅扩展留好了同一个设置入口。相关完整规格与代码入口见 tech.md、product.md、diff_state/mod.rs、settings/code.rs 与 crates/warp_features/src/lib.rs。
- 桌面应用
- 开发者工具
- 人工智能
- AI 应用
- AI Agent
- 代码智能体
【免费下载链接】warp
Warp is an agentic development environment, born out of the terminal.
相关推荐
Warp Code Review 头部 UI 重构:基于 GitOperationsInCodeReview 特性开关的双层布局实现解析
Warp Code Review 头部 UI 重构:基于 GitOperationsInCodeReview 特性开关的双层布局实现解析 导读 本文以 Warp
桌面应用开发者工具人工智能AI 应用AI Agent代码智能体Warp Notebook 编辑器 Mermaid 代码块 Raw/Rendered 切换开关:技术设计与实现解析
Warp Notebook 编辑器 Mermaid 代码块 Raw/Rendered 切换开关:技术设计与实现解析 导读 Warp 的 Notebook 编辑器
桌面应用开发者工具人工智能AI 应用AI Agent代码智能体Warp Notebook 编辑器 Mermaid 代码块 Raw/Rendered 双模式切换:设计规范与源码实现解析
Warp Notebook 编辑器 Mermaid 代码块 Raw/Rendered 双模式切换:设计规范与源码实现解析 导读 :本文以 Warp 仓库内产品规
桌面应用开发者工具人工智能AI 应用AI Agent代码智能体
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考