дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
Merge remote-tracking branch 'origin/main' into feat/remote-development
Цей коміт міститься в:
коміт
0217586e2e
6 files changed
+238
-47
No files matched your search
Створено
+30
-30
@@ -3974,7 +3974,7 @@ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||
|
||||
[[package]]
|
||||
name = "ide-agent"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"ide-jsonrpc",
|
||||
@@ -3992,7 +3992,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-analysis"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ast-grep-core",
|
||||
"ide-core",
|
||||
@@ -4006,7 +4006,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-build"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"dirs 6.0.0",
|
||||
"dunce",
|
||||
@@ -4021,11 +4021,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-clipboard"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
|
||||
[[package]]
|
||||
name = "ide-core"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"serde",
|
||||
@@ -4037,7 +4037,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-coverage"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"ide-run",
|
||||
@@ -4051,7 +4051,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-dap"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"ide-jsonrpc",
|
||||
@@ -4068,7 +4068,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-db"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"dirs 6.0.0",
|
||||
"futures",
|
||||
@@ -4087,7 +4087,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-docker"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"libc",
|
||||
@@ -4101,7 +4101,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-github"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"ide-vcs",
|
||||
@@ -4156,7 +4156,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-http"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"parking_lot",
|
||||
@@ -4174,7 +4174,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-index"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"criterion",
|
||||
@@ -4196,7 +4196,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-jsonrpc"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"futures",
|
||||
@@ -4212,7 +4212,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-language"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"criterion",
|
||||
@@ -4265,7 +4265,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-lsp"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"globset",
|
||||
@@ -4288,7 +4288,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-plugin"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"ide-language",
|
||||
@@ -4306,7 +4306,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-profiler"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"ide-run",
|
||||
@@ -4336,7 +4336,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-run"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"ide-core",
|
||||
@@ -4356,7 +4356,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-sdk"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"ide-core",
|
||||
@@ -4375,7 +4375,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-search"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"globset",
|
||||
@@ -4395,7 +4395,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-spell"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"parking_lot",
|
||||
@@ -4427,7 +4427,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-syntax"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"ide-language",
|
||||
@@ -4442,7 +4442,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-terminal"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"libc",
|
||||
@@ -4455,7 +4455,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-text"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"ide-core",
|
||||
@@ -4467,7 +4467,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-tools"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"hex",
|
||||
@@ -4487,7 +4487,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-vcs"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"gix",
|
||||
@@ -4504,7 +4504,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-vfs"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"chardetng",
|
||||
"dunce",
|
||||
@@ -4525,7 +4525,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-web"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"ide-core",
|
||||
"open",
|
||||
@@ -4541,7 +4541,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ide-workspace"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"dunce",
|
||||
@@ -5966,7 +5966,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openidea"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"dirs 6.0.0",
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ resolver = "3"
|
||||
members = ["crates/*", "src-tauri"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
edition = "2024"
|
||||
rust-version = "1.96"
|
||||
license = "Apache-2.0"
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"name": "openidea",
|
||||
"private": true,
|
||||
"description": "An open-source IDE inspired by IntelliJ IDEA",
|
||||
"version": "0.1.17",
|
||||
"version": "0.1.18",
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "OpenIDEA",
|
||||
"version": "0.1.17",
|
||||
"version": "0.1.18",
|
||||
"identifier": "ai.l0ng.openidea",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
goToPreviousChunk,
|
||||
rejectChunk,
|
||||
unifiedMergeView,
|
||||
type Chunk,
|
||||
Chunk,
|
||||
} from "@codemirror/merge";
|
||||
import { attachDocument, embeddedEditorExtensions, type DocumentAttachment } from "@/editor/api";
|
||||
import { setContext } from "@/platform/context";
|
||||
@@ -82,6 +82,23 @@ export function chunkLines(chunk: Chunk, a: Text, b: Text) {
|
||||
return { fromA: fromA!, toA: toA!, fromB: fromB!, toB: toB! };
|
||||
}
|
||||
|
||||
/** The 0-based line of `to` matching `line` of `from`, given the chunks between them. */
|
||||
export function mapLine(chunks: readonly Chunk[], line: number, from: Text, to: Text): number {
|
||||
const span = (start: number, end: number, doc: Text) => {
|
||||
const first = doc.lineAt(Math.min(start, doc.length)).number - 1;
|
||||
return [first, end > start ? doc.lineAt(Math.min(end - 1, doc.length)).number : first] as const;
|
||||
};
|
||||
let shift = 0;
|
||||
for (const c of chunks) {
|
||||
const [fromA, toA] = span(c.fromA, c.toA, from);
|
||||
if (line < fromA) break;
|
||||
const [fromB, toB] = span(c.fromB, c.toB, to);
|
||||
if (line < toA) return Math.min(fromB + (line - fromA), Math.max(fromB, toB - 1));
|
||||
shift = toB - toA;
|
||||
}
|
||||
return Math.max(0, Math.min(line + shift, to.lines - 1));
|
||||
}
|
||||
|
||||
/** Joins the open document of a file-backed side (working file, Compare Files); null for revisions / texts. */
|
||||
async function attachSide(side: DiffSide, path: string): Promise<DocumentAttachment | null> {
|
||||
const file = sideFile(side, path);
|
||||
@@ -372,21 +389,49 @@ export function DiffEditor({ input }: { input: EditorInput }) {
|
||||
[updateChunkInfo, data],
|
||||
);
|
||||
|
||||
// A file-backed side is the source; for a diff of revisions (Git Log, Compare) the
|
||||
// working copy of the path is, while it exists. Probed once per diff.
|
||||
const fileSource = sideFile(left, path) ?? sideFile(right, path);
|
||||
const [onDisk, setOnDisk] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
if (fileSource) return;
|
||||
let alive = true;
|
||||
void call(commands.fsProbe(path)).then(
|
||||
() => alive && setOnDisk(path),
|
||||
() => alive && setOnDisk(null),
|
||||
);
|
||||
return () => {
|
||||
alive = false;
|
||||
};
|
||||
}, [path, fileSource]);
|
||||
const worktreeSource = onDisk === path ? path : null;
|
||||
const source = fileSource ?? worktreeSource;
|
||||
|
||||
const jumpToSource = useCallback(() => {
|
||||
const views = viewsRef.current;
|
||||
const fileA = sideFile(left, path);
|
||||
const fileB = sideFile(right, path);
|
||||
const useA = focusedSide.current === "a" && !!views?.a && !!fileA;
|
||||
const v = useA ? views!.a! : views?.b;
|
||||
const file = useA ? fileA : (fileB ?? fileA);
|
||||
const onA = focusedSide.current === "a" && !!views?.a;
|
||||
const v = onA ? views!.a! : views?.b;
|
||||
const own = onA ? fileA : fileB;
|
||||
const file = own ?? fileB ?? fileA ?? worktreeSource;
|
||||
if (!file) return;
|
||||
const head = v ? v.state.selection.main.head : 0;
|
||||
const line = v ? v.state.doc.lineAt(head) : null;
|
||||
void editorService().openFile(file, {
|
||||
selection: { line: line ? line.number - 1 : 0, col: line ? head - line.from : 0 },
|
||||
focus: true,
|
||||
const open = (line: number, col: number) =>
|
||||
void editorService().openFile(file, { selection: { line, col }, focus: true });
|
||||
if (!v) return open(0, 0);
|
||||
const head = v.state.selection.main.head;
|
||||
const at = v.state.doc.lineAt(head);
|
||||
if (own) return open(at.number - 1, head - at.from);
|
||||
// The pane shows another version of the file: follow the diff to the line there.
|
||||
const from = v.state.doc;
|
||||
const known = file === fileB ? views?.b.state.doc : file === fileA ? views?.a?.state.doc : undefined;
|
||||
void (known ? Promise.resolve(known.toString()) : readWorkingText(file)).then((text) => {
|
||||
if (text === null) return open(at.number - 1, head - at.from);
|
||||
const to = Text.of(text.split(/\r?\n/));
|
||||
const line = mapLine(Chunk.build(from, to), at.number - 1, from, to);
|
||||
open(line, to.line(line + 1).text === at.text ? head - at.from : 0);
|
||||
});
|
||||
}, [left, right, path]);
|
||||
}, [left, right, path, worktreeSource]);
|
||||
|
||||
const currentChunk = (): { chunk: Chunk; index: number } | undefined => {
|
||||
const v = viewsRef.current?.b;
|
||||
@@ -456,7 +501,7 @@ export function DiffEditor({ input }: { input: EditorInput }) {
|
||||
const identical = ready && chunkInfo.count === 0 && (attached?.a?.text() ?? statics?.a) === (attached?.b?.text() ?? statics?.b);
|
||||
// Staging applies to local changes against HEAD / the index only.
|
||||
const canStage = editableB && isWorktree(right) && left.type === "rev" && !!useVcs.getState().root;
|
||||
const hasSource = !!sideFile(left, path) || !!sideFile(right, path);
|
||||
const hasSource = !!source;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -475,6 +520,9 @@ export function DiffEditor({ input }: { input: EditorInput }) {
|
||||
<div className={styles.toolbar} role="toolbar" aria-label={tx("Diff")}>
|
||||
<IconButton icon="arrow-up" title="Previous Difference" shortcut={shortcutLabel("diff.prevDifference")} size="small" onClick={() => step(-1)} />
|
||||
<IconButton icon="arrow-down" title="Next Difference" shortcut={shortcutLabel("diff.nextDifference")} size="small" onClick={() => step(1)} />
|
||||
{hasSource && (
|
||||
<IconButton icon="edit" title="Jump to Source" shortcut={shortcutLabel("diff.jumpToSource")} size="small" onClick={jumpToSource} />
|
||||
)}
|
||||
<span className={styles.sep} />
|
||||
<IconButton
|
||||
icon="split"
|
||||
@@ -538,9 +586,6 @@ export function DiffEditor({ input }: { input: EditorInput }) {
|
||||
)}
|
||||
<span className={styles.sep} />
|
||||
<IconButton icon="refresh" title="Refresh" size="small" onClick={() => void reload()} />
|
||||
{hasSource && (
|
||||
<IconButton icon="external-link" title="Jump to Source" shortcut={shortcutLabel("diff.jumpToSource")} size="small" onClick={jumpToSource} />
|
||||
)}
|
||||
<span className={styles.count}>
|
||||
{!ready
|
||||
? ""
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { render, screen, waitFor, within } from "@testing-library/react";
|
||||
import type { EditorInput } from "@/workbench/contributions";
|
||||
import { Chunk } from "@codemirror/merge";
|
||||
import { Text } from "@codemirror/state";
|
||||
import { EditorView } from "@codemirror/view";
|
||||
import { iconMarkup } from "@/ui";
|
||||
|
||||
const probe = vi.fn();
|
||||
const openFile = vi.fn();
|
||||
const texts: Record<string, string> = { HEAD: "a\n", abc123: "a\n" };
|
||||
let working = "a\n";
|
||||
|
||||
vi.mock("@/platform/ipc", async (importOriginal) => {
|
||||
const real = await importOriginal<typeof import("@/platform/ipc")>();
|
||||
return {
|
||||
...real,
|
||||
commands: {
|
||||
...real.commands,
|
||||
fsProbe: (path: string) => probe(path),
|
||||
vcsFileAt: (_path: string, rev: string) => Promise.resolve({ status: "ok", data: texts[rev] }),
|
||||
fsReadText: () => Promise.resolve({ status: "ok", data: working }),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("@/workbench/contributions", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("@/workbench/contributions")>()),
|
||||
editorService: () => ({ openFile }),
|
||||
}));
|
||||
|
||||
import { DiffEditor, mapLine } from "../DiffEditor";
|
||||
|
||||
/** Git Log opens a commit's file: both sides are revisions. */
|
||||
const input = {
|
||||
kind: "diff",
|
||||
key: "diff:test",
|
||||
data: {
|
||||
path: "/p/a.ts",
|
||||
left: { type: "rev", rev: "HEAD" },
|
||||
right: { type: "rev", rev: "abc123" },
|
||||
},
|
||||
} as unknown as EditorInput;
|
||||
|
||||
/** `d` attributes of an SVG, which is what tells two icons apart. */
|
||||
const paths = (html: string) => [...html.matchAll(/ d="([^"]+)"/g)].map((m) => m[1]);
|
||||
|
||||
beforeEach(() => {
|
||||
probe.mockReset();
|
||||
openFile.mockReset();
|
||||
texts.HEAD = texts.abc123 = working = "a\n";
|
||||
probe.mockResolvedValue({ status: "ok", data: { size: 3, binary: false, tooLarge: false } });
|
||||
});
|
||||
|
||||
describe("Diff toolbar", () => {
|
||||
it("puts Jump to Source right after Next Difference, in the navigation group", async () => {
|
||||
render(<DiffEditor input={input} />);
|
||||
await screen.findByRole("button", { name: "Jump to Source" });
|
||||
const toolbar = screen.getByRole("toolbar", { name: "Diff" });
|
||||
const buttons = within(toolbar).getAllByRole("button");
|
||||
expect(buttons.slice(0, 3).map((b) => b.getAttribute("aria-label"))).toEqual([
|
||||
"Previous Difference",
|
||||
"Next Difference",
|
||||
"Jump to Source",
|
||||
]);
|
||||
// One group: no separator between the three, one after them.
|
||||
expect(buttons[1]!.nextElementSibling).toBe(buttons[2]);
|
||||
expect(buttons[2]!.nextElementSibling).not.toBe(buttons[3]);
|
||||
});
|
||||
|
||||
it("shows a pencil for Jump to Source", async () => {
|
||||
render(<DiffEditor input={input} />);
|
||||
const button = await screen.findByRole("button", { name: "Jump to Source" });
|
||||
expect(paths(button.querySelector("svg")!.innerHTML)).toEqual(paths(iconMarkup("edit", 14)!));
|
||||
});
|
||||
|
||||
it("jumps to the working copy of a file shown at a revision", async () => {
|
||||
render(<DiffEditor input={input} />);
|
||||
await screen.findByRole("button", { name: "Jump to Source" });
|
||||
expect(probe).toHaveBeenCalledWith("/p/a.ts");
|
||||
});
|
||||
|
||||
it("has no Jump to Source when the file is gone from the working tree", async () => {
|
||||
probe.mockRejectedValue(new Error("no such file"));
|
||||
render(<DiffEditor input={input} />);
|
||||
await waitFor(() => expect(probe).toHaveBeenCalled());
|
||||
await waitFor(() => expect(screen.queryByRole("button", { name: "Jump to Source" })).toBeNull());
|
||||
});
|
||||
});
|
||||
|
||||
const doc = (s: string) => Text.of(s.split("\n"));
|
||||
|
||||
describe("mapLine", () => {
|
||||
const from = doc("a\nb\nc\nd\ne\nf\ng\n");
|
||||
const to = doc("a\nX\nY\nb\nc\ne\nF1\nF2\ng\n");
|
||||
const map = (line: number) => mapLine(Chunk.build(from, to), line, from, to);
|
||||
|
||||
it("shifts lines past an insertion and keeps lines before it", () => {
|
||||
expect(map(0)).toBe(0);
|
||||
expect(map(1)).toBe(3);
|
||||
expect(map(2)).toBe(4);
|
||||
});
|
||||
|
||||
it("lands on the line after a removed block", () => {
|
||||
expect(map(3)).toBe(5);
|
||||
expect(map(4)).toBe(5);
|
||||
});
|
||||
|
||||
it("keeps the offset inside a changed block and shifts past it", () => {
|
||||
expect(map(5)).toBe(6);
|
||||
expect(map(6)).toBe(8);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Jump to Source of a revision diff", () => {
|
||||
/** Parent, commit and working copy each add a line above the previous. */
|
||||
const setUp = () => {
|
||||
texts.HEAD = "a\nb\nc\nd\n";
|
||||
texts.abc123 = "a\nX\nY\nb\nc\nd\n";
|
||||
working = "new\na\nX\nY\nb\nc\nd\n";
|
||||
};
|
||||
const pane = async (index: number) => {
|
||||
await waitFor(() => expect(document.querySelectorAll(".cm-mergeViewEditor .cm-editor").length).toBe(2));
|
||||
return EditorView.findFromDOM(document.querySelectorAll<HTMLElement>(".cm-mergeViewEditor .cm-editor")[index]!)!;
|
||||
};
|
||||
const jumpFrom = async (index: number, line: number) => {
|
||||
const v = await pane(index);
|
||||
v.dispatch({ selection: { anchor: v.state.doc.line(line + 1).from + 1 } });
|
||||
v.contentDOM.dispatchEvent(new FocusEvent("focus"));
|
||||
(await screen.findByRole("button", { name: "Jump to Source" })).click();
|
||||
await waitFor(() => expect(openFile).toHaveBeenCalled());
|
||||
return openFile.mock.calls[0];
|
||||
};
|
||||
|
||||
it("maps a line of the commit to the working copy", async () => {
|
||||
setUp();
|
||||
render(<DiffEditor input={input} />);
|
||||
expect(await jumpFrom(1, 2)).toEqual(["/p/a.ts", { selection: { line: 3, col: 1 }, focus: true }]);
|
||||
});
|
||||
|
||||
it("maps a line of the parent through the diff to the working copy", async () => {
|
||||
setUp();
|
||||
render(<DiffEditor input={input} />);
|
||||
expect(await jumpFrom(0, 2)).toEqual(["/p/a.ts", { selection: { line: 5, col: 1 }, focus: true }]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Заблокувати користувача