Warp Code Review 并排 Diff 布局(Side-by-Side)产品规格解读:从 `code.editor.diff_layout` 到 hunk 对齐渲染
桌面应用开发者工具人工智能AI 应用AI Agent代码智能体【免费下载链接】warpWarp is an agentic development environment, born out of the terminal.项目地址https://gitcode.com/GitHub_Trending/wa/warp点击查看免费下载导读Warp 的 Code Review代码评审面板当前以单列内联inline方式渲染文件差异删除行显示在-行、新增行显示在行两者交错排列。本文基于仓库内 GH7043 产品规格书及其配套的 技术规格书完整解读 Warp 如何在 Code Review 面板中引入并排Side-by-SideDiff 布局包括新增的DiffLayout枚举、code.editor.diff_layout云同步设置、Settings - Code 下的 Diff layout 分段控件、hunk 对齐算法、跨窗格滚动同步以及右窗格独占编辑的交互约束。读完本文你将掌握该特性的设计动机、行为细节、源码落点与测试计划能够理解其在 Warp 仓库中的实现边界与 v2 演进方向。1. 需求背景为什么 Code Review 需要并排布局1.1 现状单列内联渲染的局限Warp 的 Code Review 面板目前将文件 diff 渲染为单列内联视图删除行以-行呈现新增行以行呈现二者交错混合在同一列中。从规格书的描述看Code Review 面板通过LocalCodeEditorView、CodeReviewEditorState、CodeEditorView等编辑器与 diff 原语消费差异数据而当前没有布局layout相关的调节旋钮。1.2 两个真实代价规格书指出了内联布局带来的两个实际问题行业惯例的缺失并排视图是 GitHub、GitLab、Phabricator、JetBrains IDE、VS Code 以及 Beyond Compare 等工具上 diff 评审的事实标准。宽屏显示器的用户天然期待这种视图Warp 用户反馈中反复出现这一诉求。本规格所对应的 issuewarpdotdev/warp#7043原始诉求是since we arent writing the code ourselves既然不是我们自己写代码评审者需要并行阅读两个版本而不是在单列中靠脑内重建差异。AI 生成编辑的形态放大问题Warp 的评审界面更多由 AI 生成编辑塑造而非手写提交。AI agent 经常在单个 block 中同时触碰几十个无关区域。在内联布局下一段 30 行的、包含代码重排的修改很难追踪——同一个逻辑块在某一处是-行、在另一处是行并排布局则把 before 和 after 并置在同一行天然可读。1.3 关联但范围外的问题与并排布局密切相关的两个既有 issue——#9017diff 与 Markdown 中的自动换行与 #9040diff 中的自动换行——都假设存在单一 diff 布局并在该布局内讨论换行行为。它们不在本规格范围内但一旦并排布局存在它们就更有价值因为换行行为与列宽相互作用。2. 目标与边界V1 只做 Code Review2.1 V1 目标清单规格书明确列出 V1 的目标引入DiffLayout二值选择Inline今天的行为与SideBySide对所有存量用户默认Inline改动为显式 opt-in在 Settings - Code 下新增 Diff layout 小节作为入口将选择持久化为同步用户设置code.editor.diff_layout跨会话、跨机器生效V1 仅将所选布局应用到 Code Review 面板SideBySide下左侧渲染 baseline基线/修改前右侧渲染 modified修改后通过 hunk 对齐填充使未变更的上下文行、修改行、纯新增/纯删除行在两侧位于同一垂直位置编辑能力约束在右侧 modified 窗格左侧 baseline 窗格永远不可编辑文本光标只存在于右侧 modified 窗格左侧窗格不暴露插入光标左侧窗格允许选中用于复制包括被删除行范围两种布局下完整保留 Code Review 现有 diff 能力hunk 导航f/F、accept接受、reject拒绝、save保存、revert to base回退到基线、评论线程、隐藏行、diff 内查找、现有导航栏Inline布局逐字节保持与今天一致默认路径零回归。2.2 明确的 Non-goalsV1 不做不对 AI block-list diffs 应用并排布局推迟到 v2不对 inline banner diffs 应用并排布局推迟到 v2不为上述两类 diff 在 V1 增加 settings 菜单入口不做词级/字符级 diff 高亮#9017 与 #9040 是自然的后续规格不做纵向 stacked 布局baseline 在上、modified 在下——路线图与 issue 明确要求并排stacked 变体可另立规格不做跨窗格选择V1 中 selection 为每窗格独立与 GitHub Desktop、GitLab MR review 一致不做每窗格宽度控制分割固定为 50/50可调分割可后续跟进不为每个 surface 单独设布局选择V1 只有一个参与 surfaceCode Review不修改现有DiffMode枚举Head/MainBranch/OtherBranch(String)见 app/src/code_review/diff_state/mod.rs。2.3 关键概念正交性DiffMode vs DiffLayout仓库源码中DiffMode枚举位于 app/src/code_review/diff_state/mod.rs#L303-L312#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Serialize)] pub enum DiffMode { /// Show changes in working directory against latest commit (git diff) #[default] Head, /// Show changes in working directory against main branch (git diff $(git merge-base HEAD origin/master)) MainBranch, /// Show changes in working directory against an arbitrary branch (git diff $(git merge-base HEAD branch)) OtherBranch(#[serde(skip_serializing)] String), }规格书明确指出二者正交DiffMode回答比较什么HEAD vs 主干分支 vs 其他分支而新增的DiffLayout回答如何渲染 diff 内容单列 vs 双列。配套技术规格specs/GH7043/tech.md进一步厘清三层职责DisplayMode该 diff 显示在哪里独立窗格 vs 嵌入式 vs inline bannerDiffMode比较的基准是什么head / 主干 / 其他分支DiffLayoutdiff 内容如何渲染一列 vs 两列。技术规格还强调V1 仅在 Code Review 面板读取DiffLayout即使存储值为side_by_sideAI block-list 与 inline banner 宿主仍保持当前的内联行为对应 app/src/ai/blocklist/inline_action/code_diff_view.rs 与InlineBanner的既有路径。3. 核心行为规格SideBySide 布局详解3.1 基本渲染当code.editor.diff_layout未设置或为inline时Warp 的 Code Review diff 与今天完全一致默认路径零回归。当设置为side_by_side时布局为 50/50 垂直分割面板 chrome 中有一条 1 像素分隔线两侧共享垂直滚动位置水平滚动条各自独立因为是否换行的行为是每窗格独立的baseline 窗格显示 diff 之前的文件内容删除可见modified 窗格显示 diff 之后的文件内容新增可见未变更的上下文行在两个窗格的同一垂直位置出现V1 中无论存储设置如何AI block-list diffs 与 inline banner diffs 仍以内联方式渲染。3.2 Hunk 对齐填充算法核心中的核心Hunk 对齐填充保证对应行跨窗格对齐。算法在 hunk 内把删除行与新增行按序配对使修改渲染为两个窗格上的一个共享行未变更行两侧同一行、同一内容修改Modificationshunk 内删除行与新增行按顺序配对。设 hunk 有D个删除行、A个新增行前min(D, A)对渲染在共享行上左侧第 N 行为删除行右侧第 N 行为新增行。共享行正是before/after评审可读性的来源多余删除D A尾部D - A行仅渲染在左侧连续行上右侧相同位置渲染为空白填充——这是纯删除情况的未配对后缀多余新增A D尾部A - D行仅渲染在右侧连续行上左侧相同位置渲染为空白填充——这是纯新增情况的未配对后缀填充行在视觉上与普通行同高并使用对应窗格的 gutter保证两侧垂直位置始终一致配对修改行上不做词级/字符级高亮见 Non-goals一行配对完整显示左侧删除行与右侧新增行。3.3 同步垂直滚动任一窗格的滚轮事件按相同 delta 驱动两侧光标上移/下移只移动右侧窗格光标baseline 窗格滚动但不暴露/不移动光标以保持对应行在视野内hunk 导航动作f/F/Next change/Previous change同时在两侧移动聚焦的 hunk并将 modified 窗格聚焦到匹配行查找与 find-next 使两侧保持滚动到匹配行匹配高亮显示在包含该匹配的窗格。3.4 每窗格独立的选择行为在一个窗格上鼠标拖选绝不会延伸到另一个窗格modified 窗格中的 Cmd-A 只选择 modified 窗格内容baseline 窗格中的 Cmd-A 只选择 baseline 窗格中可复制的内容从某个窗格复制只复制该窗格的选中文本剪贴板内容是窗格渲染内容不添加 diff 标记baseline 窗格中删除行范围可选中复制此行为与 GitHub Desktop、GitLab MR review 一致跨窗格选择超出范围。3.5 Settings - Code 入口Code 设置页新增 Diff layout 小节含两选项分段控件Inline 与 Side by side选择任一选项即更新code.editor.diff_layout并在不重新拉取 diff 数据、不丢失当前滚动位置的前提下刷新可见的 Code Review diffs当前激活的布局显示为选中段diff 工具栏继续暴露每视图的临时性控件如空白可见性但不暴露code.editor.diff_layout——布局是 Code Review V1 的用户级偏好。3.6 设置的读取时机与热切换Code Review 构造时读取code.editor.diff_layout分派到内联渲染或DiffLayout::SideBySide渲染Code Review 面板订阅设置更新将新布局应用到每个可见 diff滚出视口的 diff 在下次渲染时懒重建在 diff 打开期间切换设置会保留当前滚动位置与光标行——用户无需回滚到原位置。4. 交互一致性accept / reject / save / revert / 评论 / 隐藏行 / 查找规格书逐条规定了并排布局下既有能力的等价行为Accept接受写入的内容与内联布局会写入的内容完全一致都写 modified 文件。Reject拒绝在两侧同时丢弃修改结果回到 baseline。Revert to base回退到基线将编辑器恢复到 baseline 内容随后并排渲染器显示两个相同的窗格重建为一个无操作 diff。Save保存与今天一样通过FileModel写入修改后的内容。评论线程在 baseline 窗格某行发表的评论渲染在该窗格对应行下方在 modified 窗格某行发表的评论渲染在该窗格对应行下方对侧窗格在同行的 gutter 显示一个小评论标记字形指示对侧存在线程跨越删除与新增区域的多行评论范围仍渲染在其最初撰写的一侧与今天相同。隐藏行折叠的未变更上下文两侧在同一垂直位置出现相同的 Show N more lines 交互任一侧展开隐藏行都会同时在两侧展开因为上下文行在两个文件中都存在。Find-in-diff当两侧都包含搜索词时两侧都高亮匹配只有一侧包含时仅高亮匹配窗格。用cmd-G/cmd-shift-G循环匹配时搜索位置跨窗格推进当下一匹配位于 baseline 侧时焦点仍保持在 modified 窗格。Code Review 头部与 DiffMode 选择器不变app/src/code_review/code_review_header/ 与现有 diff 菜单的DiffMode选择器Head / Main Branch / Other Branch不受影响——它们控制比较基准布局与之正交。5. 遥测、性能预算与 Feature Flag 门控5.1 遥测用户在 Settings - Code 中更改布局时发出一个携带新布局值的CodeReviewTelemetryEvent。布局变更率是衡量该特性采用的指标。技术规格明确Settings - Code 是布局变更事件的唯一所有者Code Review 渲染代码不应再发出第二个设置变更事件见 app/src/code_review/telemetry_event.rs。5.2 性能预算在 5,000 行的 diff 上切换布局从设置变更到新布局首次绘制需在 M1 MacBook Air 上 200ms 内完成SideBySide的内存开销被约束为渲染 baseline 窗格所需的额外状态。5.3 Feature Flag 门控该改动以SideBySideDiffLayoutFeatureFlag发布定义在 crates/warp_features/src/lib.rs规范的 flag 枚举由 app/src/features.rs 再导出默认在正式发布构建中关闭、在 dogfood/preview 构建中开启稳定后移除 flag设置成为用户可见控件flag 关闭时Settings 页面不渲染 Diff layout 控件且无论存储值如何设置都被视为Inline。技术规格给出了完整的 flag 接线步骤在crates/warp_features/src/lib.rs::FeatureFlag中新增SideBySideDiffLayout变体靠近CodeReviewFind等相关 Code Review flags在app/Cargo.toml的[features]中加入side_by_side_diff_layout []仿照既有code_review_find []模式在 app/src/lib.rs 中以#[cfg(feature side_by_side_diff_layout)]门控注册依次加入DOGFOOD_FLAGS与PREVIEW_FLAGSpreview 自动包含于 dogfood 构建不加入RELEASE_FLAGS直到分阶段发布完成并为description_for_changelog添加匹配分支Enables a side-by-side diff layout in the code review pane.。默认发布节奏为正式构建关闭 → 5% dogfood → 25% dogfood → 100% dogfood → preview → release。6. 技术规格源码落点新增DiffLayout枚举与设置声明6.1DiffLayout枚举技术规格建议新增 app/src/code/diff_layout.rsuse 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) } }枚举从app/src/code/mod.rs再导出Copy保证它能在视图上下文中传递而无生命周期问题serde表示inline/side_by_side与设置值一致。6.2code.editor.diff_layout设置声明在 app/src/settings/code.rs 的define_settings_group!中扩展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., },要点设置类型系统通过serde已支持枚举默认值为Inline存量用户除非显式 opt-in 否则不受影响该设置为全局存储即使 V1 只有一个参与 surface为 v2 的更多 surface 留出空间而无需新增第二个设置名。6.3 设置页集成app/src/settings_view/code_page.rs 是显式的 Code 设置 UI。技术规格强调声明一个设置条目并不会自动渲染它页面需要在 Code 分区注册具体 widget。V1 计划添加DiffLayoutWidget行渲染 Inline / Side by side 两段式分段控件选中段读取CodeSettings::DiffLayout段变更通过 settings store 写入code.editor.diff_layout并发出布局变更遥测事件widget 注册以FeatureFlag::SideBySideDiffLayout.is_enabled()门控运行时 flag 关闭时隐藏。7. SideBySide 桥接架构两个 CodeEditorView 一个 bridge7.1 架构选择技术规格确定的架构是DiffLayout::SideBySide实现为两个CodeEditorView实例由 Code Review 桥接组件bridge包裹。baseline 视图以 select-only 模式渲染基础内容modified 视图渲染工作文件的全局 buffer 条目。bridge 拥有跨窗格同步隐藏行、滚动位置、查找状态、共享 diff 状态同时保持两个视图的 buffer 相互独立。bridge 位于现有 Code Review 编辑器宿主内渲染两个等宽编辑器视图与一条分隔线并双向传播共享状态变更。核心结构示意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, }7.2 Bridge 拥有的同步职责隐藏行范围折叠的未变更区域只表示一次同时应用到两个视图任一侧展开隐藏行即更新共享隐藏行状态并重配置两个视图以保持高度对齐滚动位置任一侧滚动更新共享行锚点再驱动另一侧到对应对齐行同步是行锚定而非像素级的这样字体、换行或行高差异不会累积漂移查找状态单一 Code Review 查找会话跨两个视图任一 buffer 的匹配都被高亮Next/Prev 可跨窗格遍历共享 diff 状态两个视图读取同一 diff 结果与HunkAlignment从而对哪些 baseline 行是删除、哪些 modified 行是插入、视觉空隙落在哪里达成一致。这个共享 diff 状态不是共享 buffer。7.3 两个 buffer 保持独立baseline 视图的 buffer 来源是修改前的基准内容modified 视图的 buffer 来源是工作文件的全局 buffer 条目对 modified buffer 的编辑重新触发 diff刷新后的 diff 更新两个视图的装饰配置新删除的 baseline 行在 baseline 视图中保持普通可选行modified 视图将对应 baseline-only 行渲染为空隙新插入的 modified 行在 modified 视图中渲染为普通行、在 baseline 视图中渲染为空隙。7.4 调用方路由表调用方 / 行为感知窗格的路径光标焦点、本地选择、从 modified 侧复制modifiedCodeEditorView从 baseline 侧复制baselineCodeEditorView仅选择焦点changed_linesmodifiedCodeEditorViewAccept diff、save diff、reject-to-modified-buffer 操作modifiedCodeEditorViewHunk 导航Bridge 行对齐 modified 侧焦点滚动保持Bridge 滚动锚点评论渲染与 gutter 标记BridgeHunkAlignment行映射 目标子视图仅右侧可编辑通过仅对 modified buffer 使用普通编辑器视图来强制实现baseline 编辑器为 select-only从不暴露插入光标。8. 窗格内容构建与 RowIndex / Hunk 对齐模型8.1 SideBySide 内容管线并排复用现有 unified-diff 解析器但不复用内联删除行渲染。管线为用现有解析器把 unified diff 解析为DiffHunk[]解析器无需改动由基础内容、当前 modified 全局 buffer 内容与有序 hunk 行构建共享 diff 状态对有序 hunk 行运行 hunk 对齐每个AlignedRow映射到两个窗格中的行索引空隙行在两个源文件中都不存在但 bridge 把它们作为装饰元数据传给对应视图配置 baseline 视图base buffer 行、删除装饰、隐藏行、baseline 侧对齐元数据配置 modified 视图全局 buffer 条目、新增装饰、隐藏行以及把 baseline-only 行渲染为视觉空隙的装饰配置。当DiffLayout::SideBySide激活时bridge 使用上述窗格内容管线取代apply_diffs_if_any的内联路径。移除行在 baseline 视图中渲染为普通可选行新增行在 modified 视图中渲染为普通可编辑 buffer 行baseline-only 行在 modified 视图中渲染为视觉空隙modified-only 行在 baseline 视图中渲染为视觉空隙为防删除渗漏modified 侧禁用内联临时块删除渲染Accept、reject、save 与 changed-line 计算继续读取 modified buffer与内联行为一致。8.2 RowIndex 语义技术规格用RowIndex取代模糊的line_index使 baseline 行、modified 行与纯渲染空隙可区分RowIndex::Baseline(n)该对齐行对应 baseline buffer 第 n 行RowIndex::Modified(n)该对齐行对应 modified buffer 第 n 行RowIndex::Gap { after_row }该对齐行是在对齐行after_row之后插入的纯渲染空隙不对应任何一侧的源行号。对齐器遍历 hunk 时按如下规则产出RowIndex上下文行左侧Baseline(b)右侧Modified(m)配对的删除/新增修改行左侧Baseline(b)右侧Modified(m)纯删除行左侧Baseline(b)右侧Gap { after_row }纯新增行左侧Gap { after_row }右侧Modified(m)。bridge 存储对齐结果只把每侧需要的行元数据传给对应编辑器视图。选择、复制、光标、保存与查找都会忽略空隙行作为源文本对空隙行做 hit-testing 时解析为最近的有效行用于滚动锚定与评论定位。8.3 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的行baseline 视图收到空隙装饰纯删除块产生左侧Delete、右侧Gap的行modified 视图收到空隙装饰修改序列中间的Context重置配对窗口context 前的删除在考虑 context 后的新增之前被 flush文本无关的删除段后接新增段仍按位置配对。词级高亮超出范围V1 保证行对齐。8.4 Bridge 滚动同步滚动同步由 bridge 拥有同样为行锚定pub struct SideBySideScrollAnchor { focused_side: Side, anchor_row: RowIndex, anchor_side: Side, horizontal_scroll_by_side: BTreeMapSide, 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, ) - OptionRowIndex; }任一视图中发生滚轮或 hunk 导航事件更新共享行锚点bridge 请求另一视图从HunkAlignment显示对应行水平滚动保持每窗格独立。光标移动属于 modified 侧光标导航改变 modified 行时corresponding_row计算最近的 baseline 行用于可见性但不会移动 baseline 光标。若实现需要事件源标记以避免递归更新该状态属于 bridge。9. 每窗格交互状态与辅助功能Accessibility9.1 Baseline 窗格只读始终只读使用基于基础内容的 select-onlyCodeEditorView实例支持所有 baseline 行的文本选择与复制包括被删除行范围因为这些范围在 baseline buffer 中是真实行不暴露插入光标不消费键盘编辑事件不参与文件后备保存从 bridge 接收删除装饰与隐藏行配置。9.2 Modified 窗格唯一可写使用基于工作文件全局 buffer 条目的普通CodeEditorView实例拥有光标拥有所有可写交互遵循现有 Code Review 的 accept、reject、save、revert、hunk 导航规则是唯一注册FileModel的一侧使用把 baseline-only 行渲染为视觉空隙而非临时删除块的装饰配置。bridge 把 Code Review 交互状态应用到 modified 窗格并把 baseline 交互状态硬编码为只读选择/复制。其他 surface 的FullPane行为不属于 V1。9.3 辅助功能要求两个窗格带可访问标签Originalbaseline与 Modifieddiff 后窗格modified 窗格是唯一获得编辑焦点的区域、唯一有光标的区域baseline 窗格可接收焦点用于选择/复制前提是平台辅助功能 API 能表达这一点且不暴露编辑动作对齐行作为单个逻辑行播报Original:; Modified:使非视觉评审者也能听到两侧内容键盘导航Tab到达 modified 编辑区baseline 焦点仅为选择/复制CmdOptionLeft/Right若实现循环逻辑窗格焦点但不把编辑所有权移出 modified颜色对比空隙行背景使用专用主题 tokendiff.gap.background在浅色与深色主题下均满足对编辑器背景 3:1 的对比度颜色不是变更的唯一信号每个变更行在对应窗格携带或-的 gutter 字形与今天的内联 gutter 一致。技术规格记录了一个开放风险如果平台辅助功能树无法以可接受的屏幕阅读器行为表示两个桥接编辑器视图则必须在并排特性超出 dogfood 之前升级处理。10. 测试计划从单元测试到手动冒烟10.1 单元测试app/src/code/hunk_alignment_tests.rs空 diffrow_map 对每个上下文行含匹配的Baseline(n)/Modified(n)无空隙纯新增(Gap { after_row }, Modified(m))baseline 视图收到对应空隙元数据纯删除(Baseline(b), Gap { after_row })modified 视图收到对应空隙元数据折叠修改Context Delete Delete Add Add Context产生四个对齐行一个上下文行、两个配对修改行、一个上下文行delete/add 序列中的 Context 重置配对窗口多 hunk 文件跨 hunk 正确组合大型 diff5,000 行、200 hunk50ms 内完成app/src/code/editor/side_by_side_bridge_tests.rsDiffType::Update下窗格内容baseline 持有 diff 前内容 删除装饰modified 持有 diff 后内容 新增装饰DiffType::Createbaseline 为空 空隙modified 持有新文件内容DiffType::Deletemodified 为空 空隙baseline 持有原始内容DiffLayout::SideBySide激活时不使用apply_diffs_if_any移除行在 baseline 中可选、在 modified 中为空隙新增行在 modified 中可编辑、在 baseline 中为空隙空隙行两侧渲染同高app/src/code/editor/side_by_side_interaction_tests.rsbaseline 子视图只读且不暴露编辑光标modified 子视图是唯一注册FileModel的一侧baseline 选择可复制可选内容含删除行范围光标移动只影响 modified 侧Inline与SideBySide来回切换保持滚动位置在一行误差内app/src/code/editor/side_by_side_scroll_tests.rs滚轮 delta 更新 bridge 滚动锚点并在两侧显示对应行modified 上的光标移动把 baseline 滚到对应行光标位于(Gap { after_row }, Modified(m))纯新增行时 baseline 滚到下一段周边上下文行bridge 抑制递归滚动更新。10.2 集成测试app/src/settings_view/code_page_tests.rsSideBySideDiffLayout启用时 Code 页面渲染DiffLayoutWidget运行时 flag 关闭时 widget 隐藏选择 Side by side 写入code.editor.diff_layout side_by_side辅助文本只提到 Code Reviewapp/src/code_review/code_review_view_tests.rs单文件 diff 在并排模式下于 bridge 内渲染两个CodeEditorView子视图多文件 diff 每个文件遵守同一布局打开时切换设置重建每个可见编辑器为所选布局并保持滚动find-in-diff 匹配两个子编辑器视图hunk 导航f/F同时在两侧推进聚焦 hunk 且光标保持在 modified 侧baseline 侧某行的评论线程渲染在 baseline 窗格行下方modified 窗格显示 gutter 标记隐藏行展开通过 bridge 的共享对齐模型更新两个子视图。10.3 辅助功能验证与手动冒烟快照测试断言 bridge 内并排窗格的可访问标签 Original 与 Modified键盘测试覆盖Tab与实现中选定的窗格切换快捷键测试断言 baseline 焦点不暴露编辑动作或插入光标主题测试断言diff.gap.background在浅色与深色主题下均满足对编辑器背景 3:1 对比度手动屏幕阅读器冒烟macOS VoiceOver将配对修改行读作一个逻辑 original/modified 行手动冒烟清单M1 MacBook Air dogfood 构建开 flag下Settings - Code 切换布局并在 200ms 内刷新可见 diff200 文件 diff 渲染为两个桥接编辑器视图两侧滚轮同步无抖动baseline 拖选复制含删除行范围modified 拖选不越界光标只在 modified 窗格各窗格 Cmd-A 只选本窗格窗口收窄后各窗格水平滚动条独立且分隔线保持 50%AI block-list 嵌入 diff 与 inline banner diff 在 V1 仍内联LinuxUbuntu 24.04与 Windows 11 上重复设置切换冒烟验证渲染与键位。10.4 编译一致性检查清单每个解构DisplayMode的match站点都必须在改动后可编译app/src/code/diff_viewer.rstrait helpers因DiffLayout是新的正交轴而无需改动app/src/ai/blocklist/inline_action/code_diff_view.rsV1 不改继续内联渲染app/src/ai/blocklist/block/view_impl/output.rs对DisplayMode::FullPane的 match不改。所有假定单一编辑器状态的 Code Review 站点都应检查既有 write、save、cursor、accept/reject 路径继续瞄准 modified 视图rendering、comments、find、selection、accessibility 调用点在并排激活时经 bridge 路由。11. 配套仓库源码印证以下是在当前仓库中可进一步深入阅读的实现落点DiffMode枚举与 diff 状态模型app/src/code_review/diff_state/mod.rsCode Review 编辑器状态宿主CodeReviewEditorStateapp/src/code_review/editor_state.rs本地编辑器宿主LocalCodeEditorViewapp/src/code/local_code_editor.rs编辑器渲染目标与 wrapperCodeEditorViewapp/src/code/editor/view.rs与EditorWrapperapp/src/code/editor/element.rs编辑器级 diff 行装饰与 gutter 渲染DiffLineTypeContext/Add/Delete/HunkHeader见 app/src/code/editor/diff.rshunk 解析器app/src/code_review/comments/diff_hunk_parser.rs滚动保持辅助app/src/code_review/scroll_preservation.rs评论渲染app/src/code_review/comments/comment.rs 与 app/src/code_review/comments/comment_list_view.rs遥测事件app/src/code_review/telemetry_event.rsfind-in-diff 状态模型app/src/code_review/find_model.rs设置组声明app/src/settings/code.rs设置 UIapp/src/settings_view/code_page.rsFeatureFlag 定义crates/warp_features/src/lib.rs再导出于 app/src/features.rs12. 开放问题与演进方向技术规格在 v4 修订中收窄了 V1 范围、恢复了两个CodeEditorView bridge wrapper架构、用RowIndex取代了模糊的line_index并明确了几个开放问题状态管理形态CodeReviewEditorState保留为单一 slice含baseline_sub_state/modified_sub_state还是拆分为两个并行 slice单 slice 保持现有 Code Review reducer 签名分 slice 则干净分离两个视图生命周期diff 结果所有权bridge 直接持有 diff 状态还是提升到父 Code Review 容器前者封装性好后者可供其他 Code Review 消费者复用find 状态 UX当 Next match 跨窗格时焦点是逐个匹配跳转还是停留在一个窗格直到其中所有匹配都被访问评论 gutter 标记交互对侧 gutter 标记本规格中为非交互是否可点击是 Code Review SME 的 UX 决策与候选后续项分段控件原语DiffLayoutWidget使用的分段控件原语名与导入路径需在实现评审中确认可调分割可调整的窗格分割在首次发布中明确排除产品 Non-goals是否后续跟进取决于发布后的遥测与用户反馈。v2 方向在规格中已经预留同一DiffLayout设置可扩展到 AI block-list diffs 与 inline banner diffs#9017 与 #9040diff 内词级/字符级高亮与换行是自然的后续规格纵向 stacked 布局与可调分割可另立规格。V1 的核心承诺清晰且克制只改 Code Review默认零回归并排时左右对称、右可编辑、左可复制让before/after的评审体验在 Warp 中落地。阅读提示本文以 specs/GH7043/product.md 为主体辅以同目录 specs/GH7043/tech.md 的实现细节与仓库源码落点。规格所述实现属规划内容文中标注的app/src/code/diff_layout.rs、app/src/code/hunk_alignment.rs等为新文件/新逻辑的规划路径其余引用的既有文件路径均已在当前仓库中确认存在。赞分享桌面应用开发者工具人工智能AI 应用AI Agent代码智能体【免费下载链接】warpWarp is an agentic development environment, born out of the terminal.项目地址https://gitcode.com/GitHub_Trending/wa/warp点击查看免费下载相关推荐delta 分屏并排视图side-by-side完全指南配置、行号、换行与命令行开关delta 分屏并排视图side by side完全指南配置、行号、换行与命令行开关 本篇指南以 delta 官方手册的 side by side vie开发工具CLIDelta 官方截图配置详解用 Features、Side-by-Side 与装饰样式复现高颜值 diff 输出Delta 官方截图配置详解用 Features、Side by Side 与装饰样式复现高颜值 diff 输出 导读 delta当前仓库即 delta 本开发工具CLIHunk 快速上手用 hunk diff --files 对比两个 TypeScript 文件并完成首次 ReviewHunk 快速上手用 hunk diff files 对比两个 TypeScript 文件并完成首次 Review 本篇技术指南围绕 Hunk 仓库中最小可运开发工具代码评审CLIAI 应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

高速窄脉冲峰值保持电路设计:从原理到PCB布局的工程实践

高速窄脉冲峰值保持电路设计:从原理到PCB布局的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 10:00:42 阅读更多 →
Python区分广度优先深度优先宽度优先的区别

Python区分广度优先深度优先宽度优先的区别

先说明:广度优先搜索(BFS)就是宽度优先搜索,二者通常没有区别;真正相对的是 深度优先搜索(DFS)。所以严格说只有 DFS 和 BFS 两类。下面写三段代码:DFS、BFS(广度/宽度&a…

2026/10/5 9:59:42 阅读更多 →
计算机网络基础说课PPT课件:用数据包旅程主线展示教学设计

计算机网络基础说课PPT课件:用数据包旅程主线展示教学设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 9:59:42 阅读更多 →

最新新闻

Superpowers工作流:AI原生开发的认知增强层实战指南

Superpowers工作流:AI原生开发的认知增强层实战指南

1. 项目概述:Superpowers 不是超能力,而是开发者工具链的“认知增强层”你搜“superpowers”时看到的满屏 Claude Code、Antigravity、Codex CLI、Cursor,不是漫威电影彩蛋,也不是某个神秘组织的代号——这是2024年中后期&#xf…

2026/10/5 11:15:55 阅读更多 →
Beyond Compare 5文件夹比较总显示相同?3步设置内容比对

Beyond Compare 5文件夹比较总显示相同?3步设置内容比对

用Beyond Compare 5做文件夹比较,很多人都会遇到一个让人抓狂的情况:两个文件夹里明明有文件被改过了,可软件死活显示“相同”,左边右边一模一样,怎么看都没有差异。有人以为是自己记错了版本,有人以为是文…

2026/10/5 11:15:55 阅读更多 →
插件体系设计指南:plugin.json、TypeScript SDK与CLI管理实践

插件体系设计指南:plugin.json、TypeScript SDK与CLI管理实践

1. 从“plugins”这个词说起:它到底在解决什么问题但凡折腾过现代开发工具的人,对plugins这个词都不会陌生。它字面意思就是“插件”,但真正理解它的人知道,这背后其实是一整套可扩展架构的设计哲学。你用的编辑器、命令行工具、构…

2026/10/5 11:15:55 阅读更多 →
生成式AI在零售电商的落地实践:从场景拆解到RAG工程避坑指南

生成式AI在零售电商的落地实践:从场景拆解到RAG工程避坑指南

简介:一份面向零售电商行业决策者、数字化负责人及AI落地团队的生成式AI行业白皮书,聚焦生成式AI在商品研发、供应链、营销与客户旅程、企业决策四大场景中的价值,并给出从技术选型到实施路线图的完整路径。包内含1个PDF文档,压缩…

2026/10/5 11:15:55 阅读更多 →
C++台球游戏源码解析:从物理模拟到编译避坑指南

C++台球游戏源码解析:从物理模拟到编译避坑指南

简介:游戏开发中,物理模拟、主循环与碰撞检测是决定核心体验的技术基石。固定时间步长保证球速与帧率无关,冲量公式处理球间碰撞,摩擦衰减与库边反弹塑造真实手感,坐标换算则直接影响瞄准精度。这些原理在C台球游戏源码…

2026/10/5 11:15:55 阅读更多 →
MySQL面试高频考点全解析:索引、事务与实战排查

MySQL面试高频考点全解析:索引、事务与实战排查

最近好多朋友私信问我MySQL面试题到底怎么准备,尤其是那些准备跳槽的Java开发和C后端。说实话,我当年也干过把网上几百道题背下来的傻事,结果一上考场,面试官随口问一句“联合索引最左前缀到底是怎么匹配的”,我当场就…

2026/10/5 11:14:55 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →