mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 08:07:49 +00:00
feat(vcs): Accept a diff change from the keyboard and step between diff files (#158)
- Accept Left Side / Accept Right Side copy the change at the caret to the other side of a side-by-side diff (⌃⌘→ / ⌃⌘← on macOS, Ctrl+Alt+R / Ctrl+Alt+A on Windows). - Compare Next File / Compare Previous File open the neighbouring file of the diff chain directly (⌃⇧→ / ⌃⇧← on macOS, Alt+Shift+→ / ← on Windows).
This commit is contained in:
@@ -66,6 +66,7 @@ describe("Download JDK dialog", () => {
|
||||
it("preselects the version a fix asks for", async () => {
|
||||
render(<DownloadJdkDialog initialVersion={21} onClose={() => {}} 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"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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<DiffNavigator>({ 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<DiffNavigator>({ 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(
|
||||
() => () => {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -316,6 +316,10 @@ export const intellijMacos: Record<string, string[]> = {
|
||||
"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
|
||||
|
||||
@@ -314,6 +314,10 @@ export const intellijWindows: Record<string, string[]> = {
|
||||
"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
|
||||
|
||||
@@ -324,6 +324,10 @@ export const vscodeMacos: Record<string, string[]> = {
|
||||
"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.
|
||||
|
||||
@@ -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": "比较上一个文件"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user