diff --git a/src/features/settings/__tests__/downloadJdk.test.tsx b/src/features/settings/__tests__/downloadJdk.test.tsx index f6e650d0..21a242ae 100644 --- a/src/features/settings/__tests__/downloadJdk.test.tsx +++ b/src/features/settings/__tests__/downloadJdk.test.tsx @@ -66,6 +66,7 @@ describe("Download JDK dialog", () => { it("preselects the version a fix asks for", async () => { render( {}} onDownloaded={() => {}} />); await waitFor(() => expect(screen.getByRole("button", { name: "Download" })).toBeEnabled()); - expect(screen.getByRole("button", { name: "Version" })).toHaveTextContent("21"); + // The version list loads after the Download button enables on a busy runner. + await waitFor(() => expect(screen.getByRole("button", { name: "Version" })).toHaveTextContent("21")); }); }); diff --git a/src/features/vcs/DiffEditor.tsx b/src/features/vcs/DiffEditor.tsx index 50e44556..658d02c0 100644 --- a/src/features/vcs/DiffEditor.tsx +++ b/src/features/vcs/DiffEditor.tsx @@ -24,7 +24,7 @@ import { tx } from "@/platform/i18n"; import { IconButton, Select, Spinner, T } from "@/ui"; import { editorService, type EditorInput } from "@/workbench/contributions"; import { languageFor, viewerBase } from "./cm"; -import { applyChunk, arrowControls, hoverRevert } from "./diffControls"; +import { applyChunk, arrowControls, chunkAt, hoverRevert } from "./diffControls"; import { HIGHLIGHT_OPTIONS, IGNORE_OPTIONS, @@ -586,10 +586,26 @@ export function DiffEditor({ input }: { input: EditorInput }) { e.stopPropagation(); }; - const nav = useRef({ next: () => step(1), prev: () => step(-1), jumpToSource }); + /** ⌃⌘→ / ⌃⌘←: the change at the caret applied toward the other, editable side. */ + const applyChange = (source: "a" | "b") => { + const views = viewsRef.current; + const merge = views?.merge; + if (!merge || !views.a || !(source === "a" ? editableB : editableA)) return false; + const side = focusedSide.current; + const view = side === "a" ? views.a : views.b; + const index = chunkAt(merge.chunks, side, view.state.selection.main.head, view.state.doc.length); + if (index < 0) return false; + applyChunk(merge, index, source); + return true; + }; + const file = (dir: 1 | -1) => { + const neighbour = chainNeighbour(data, dir); + if (neighbour) void openDiff(neighbour, { preview: true }); + }; + const nav = useRef({ next: () => step(1), prev: () => step(-1), jumpToSource, applyChange, file }); useEffect(() => { - nav.current = { next: () => step(1), prev: () => step(-1), jumpToSource }; - }, [step, jumpToSource]); + nav.current = { next: () => step(1), prev: () => step(-1), jumpToSource, applyChange, file }; + }); useEffect( () => () => { diff --git a/src/features/vcs/compare.tsx b/src/features/vcs/compare.tsx index cafaf8e9..f9f1de48 100644 --- a/src/features/vcs/compare.tsx +++ b/src/features/vcs/compare.tsx @@ -125,6 +125,40 @@ export function registerCompareActions(): () => void { when: "diffEditorFocus", run: () => focusedDiffNavigator()?.prev(), }, + { + id: "diff.nextFile", + title: "Compare Next File", + category: "Diff", + icon: "arrow-right", + when: "diffEditorFocus", + run: () => focusedDiffNavigator()?.file(1), + }, + { + id: "diff.prevFile", + title: "Compare Previous File", + category: "Diff", + icon: "arrow-left", + when: "diffEditorFocus", + run: () => focusedDiffNavigator()?.file(-1), + }, + { + id: "diff.applyLeftSide", + title: "Accept Left Side", + description: "Copies the change at the caret from the left side to the right one", + category: "Diff", + icon: "arrow-right", + when: "diffEditorFocus", + run: () => void focusedDiffNavigator()?.applyChange("a"), + }, + { + id: "diff.applyRightSide", + title: "Accept Right Side", + description: "Copies the change at the caret from the right side to the left one", + category: "Diff", + icon: "arrow-left", + when: "diffEditorFocus", + run: () => void focusedDiffNavigator()?.applyChange("b"), + }, { id: "diff.jumpToSource", title: "Jump to Source", diff --git a/src/features/vcs/diffControls.ts b/src/features/vcs/diffControls.ts index df978890..7b8af568 100644 --- a/src/features/vcs/diffControls.ts +++ b/src/features/vcs/diffControls.ts @@ -84,7 +84,7 @@ class RevertWidget extends WidgetType { } } -function chunkAt(chunks: readonly Chunk[], side: "a" | "b", pos: number, docLength: number): number { +export function chunkAt(chunks: readonly Chunk[], side: "a" | "b", pos: number, docLength: number): number { return chunks.findIndex((c) => { const [from, to] = side === "a" ? [c.fromA, c.toA] : [c.fromB, c.toB]; return from === to ? pos === from : pos >= from && pos < Math.max(to, from + 1) && pos <= docLength; diff --git a/src/features/vcs/diffNavigator.ts b/src/features/vcs/diffNavigator.ts index 69281013..afe80df4 100644 --- a/src/features/vcs/diffNavigator.ts +++ b/src/features/vcs/diffNavigator.ts @@ -4,6 +4,10 @@ export interface DiffNavigator { next(): void; prev(): void; jumpToSource(): void; + /** Apply the change at the caret from the left side to the right (`a`) or back (`b`). */ + applyChange(source: "a" | "b"): boolean; + /** Open the next / previous file of the diff chain (changes of a commit or change list). */ + file(dir: 1 | -1): void; } let focused: DiffNavigator | null = null; diff --git a/src/platform/keymaps/intellij-macos.ts b/src/platform/keymaps/intellij-macos.ts index 37ba17b5..d8af5b09 100644 --- a/src/platform/keymaps/intellij-macos.ts +++ b/src/platform/keymaps/intellij-macos.ts @@ -316,6 +316,10 @@ export const intellijMacos: Record = { "diff.nextDifference": ["F7"], "diff.prevDifference": ["Shift+F7"], "diff.jumpToSource": ["F4"], + "diff.applyLeftSide": ["Ctrl+Meta+Right"], + "diff.applyRightSide": ["Ctrl+Meta+Left"], + "diff.nextFile": ["Ctrl+Shift+Right"], + "diff.prevFile": ["Ctrl+Shift+Left"], // After Show Diff: ⌘D is Compare With… in the project view. "project.compareWith": ["Meta+D"], // Editing extras, image viewer (keyWhen: image focused) and Markdown editor layouts diff --git a/src/platform/keymaps/intellij-windows.ts b/src/platform/keymaps/intellij-windows.ts index 3700a59a..3c1ef2a9 100644 --- a/src/platform/keymaps/intellij-windows.ts +++ b/src/platform/keymaps/intellij-windows.ts @@ -314,6 +314,10 @@ export const intellijWindows: Record = { "diff.nextDifference": ["F7"], "diff.prevDifference": ["Shift+F7"], "diff.jumpToSource": ["F4"], + "diff.applyLeftSide": ["Ctrl+Alt+R"], + "diff.applyRightSide": ["Ctrl+Alt+A"], + "diff.nextFile": ["Alt+Shift+Right"], + "diff.prevFile": ["Alt+Shift+Left"], // After Show Diff: Ctrl+D is Compare With… in the project view. "project.compareWith": ["Ctrl+D"], // Editing extras, image viewer (keyWhen: image focused) and Markdown editor layouts diff --git a/src/platform/keymaps/vscode-macos.ts b/src/platform/keymaps/vscode-macos.ts index 83c52adb..a3f2b5e0 100644 --- a/src/platform/keymaps/vscode-macos.ts +++ b/src/platform/keymaps/vscode-macos.ts @@ -324,6 +324,10 @@ export const vscodeMacos: Record = { "markdown.previewOnly": ["Meta+Shift+V"], // Diff editor (VS Code: workbench.action.compareEditor.nextChange / previousChange) "diff.nextDifference": ["F7"], + "diff.applyLeftSide": [], + "diff.applyRightSide": [], + "diff.nextFile": [], + "diff.prevFile": [], "diff.prevDifference": ["Shift+F7"], "diff.jumpToSource": [], // HTTP Client / Database console: run the request or statement at the caret. diff --git a/src/platform/locales/text/zh.json b/src/platform/locales/text/zh.json index 0dda4795..3c4ed8d7 100644 --- a/src/platform/locales/text/zh.json +++ b/src/platform/locales/text/zh.json @@ -4599,5 +4599,11 @@ "Add Mouse Shortcut": "添加鼠标快捷键", "Click here with a mouse side button, holding any modifiers": "按住任意修饰键,用鼠标侧键点击此处", "Mouse shortcut": "鼠标快捷键", - "Mouse Shortcut: {action}": "鼠标快捷键:{action}" + "Mouse Shortcut: {action}": "鼠标快捷键:{action}", + "Accept Left Side": "接受左侧", + "Accept Right Side": "接受右侧", + "Copies the change at the caret from the left side to the right one": "将光标处的变更从左侧复制到右侧", + "Copies the change at the caret from the right side to the left one": "将光标处的变更从右侧复制到左侧", + "Compare Next File": "比较下一个文件", + "Compare Previous File": "比较上一个文件" }