mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 17:02:17 +00:00
* perf(vfs): list directories off the main thread and reuse the repository lookup Opening a folder on a network share (\\wsl.localhost\<distro>\...) is slow because every listing ran on the main thread and walked up to the repository root and ran a repository discovery again. - fs_read_dir runs on the blocking pool. - GitignoreStack::cached keeps the repository root and the repo-level rules for a few seconds. An edit of .git/info/exclude is still seen at once (its mtime and size are checked) and every .gitignore / .ignore is read fresh. Refs #916 * feat(remote): open WSL projects through a WSL transport A folder of a WSL distro (\\wsl.localhost\<distro>\... or \\wsl$\...) now opens as a remote project whose openidea-server runs inside the distro, so the terminal, SDK discovery, run, language servers and git are native Linux. - RemoteTarget (ssh | wsl) replaces the SSH configuration id in the remote launch, connection, session and recents; old recents are read as SSH and a WSL target never inherits the legacy trust migration. - remote_wsl: probe the distro, stream the server into ~/.openidea/server and start it with `wsl.exe -d <distro> --exec <bin> --stdio`. Distro names are validated and every command goes through --exec with positional arguments. - wsl_distros / wsl_resolve commands; File > Open, the CLI and recents route WSL folders to the distro and focus the window that already has them. - Remote Development dialog: SSH/WSL choice with the detected distros; the status bar shows `WSL: <distro>` / `SSH: <host>`. - ide-jsonrpc: skip the NUL left at the start of a line by UTF-16 output of wsl.exe, which made the first message of the server disappear. Not run on Windows yet: only a stand-in for wsl.exe is tested. Refs #925, #327, #721 * fix(remote): satisfy clippy in WSL output decoding * style(run): format run types * fix: regenerate bindings and drop untranslated WSL catalog entry * test(i18n): list WSL as an untranslated product name * fix(run): pick build wrappers and shell quoting by the execution host A remote window runs commands on its Linux or macOS server, so a Windows desktop no longer selects gradlew.bat, mvnw.cmd or Windows quoting for it. * fix(welcome): open legacy WSL UNC recents and sessions through the distro Recents and the restored session called the local openProject for a \\wsl.localhost folder saved before WSL projects, which fails with OS error 123. They now resolve it like the other entry points. * fix(windows): keep WSL files out of remote project launches path_launch tested the WSL share before is_dir, so a first-instance CLI launch with a WSL file opened a remote project instead of LightEdit. * fix(remote): run-command OS comes from the remote host, not an assumption The server's OS was dropped after connect, so a restored session had none and isWindows() assumed every remote host is Unix. Keep it on the connection and the session, and resolve it through hostOs(). --------- Co-authored-by: NguyenBang <[email protected]> Co-authored-by: NguyenBang <[email protected]> Co-authored-by: l0ng-ai <[email protected]>
78 lines
3.0 KiB
TypeScript
78 lines
3.0 KiB
TypeScript
/** Where a project opens when this window already has one: System Settings › Project › "Open project in". */
|
||
import { t } from "@/platform/i18n";
|
||
import { call, commands, type RemoteTarget } from "@/platform/ipc";
|
||
import { confirmLeaveProject, useProject } from "@/platform/project";
|
||
import { connectRemote, isRemoteWindow } from "@/platform/remote";
|
||
import { ask } from "./messages";
|
||
import { maybeEditorService } from "./contributions";
|
||
|
||
/** "Open project in": `new` | `same` | `attach` | `ask`. */
|
||
export function openPolicy(): "ask" | "new" | "same" | "attach" {
|
||
const v = useProject.getState().settings?.general?.openProjectIn;
|
||
return v === "new" || v === "same" || v === "attach" ? v : "ask";
|
||
}
|
||
|
||
/**
|
||
* The window to open project `name` in: this one when it has no project (or LightEdit session), else
|
||
* per "Open project in", asking when set to (and remembering "Don't ask again").
|
||
* `null`: cancelled.
|
||
*/
|
||
export async function chooseProjectWindow(name: string, allowAttach = true): Promise<"new" | "same" | "attach" | null> {
|
||
const { project, lightEdit } = useProject.getState();
|
||
if (!project && !lightEdit) return "same";
|
||
const canAttach = allowAttach && !!project && !isRemoteWindow();
|
||
const policy = openPolicy();
|
||
const mode = policy === "attach" && !canAttach ? "ask" : policy;
|
||
if (mode !== "ask") return mode;
|
||
const r = await ask({
|
||
title: t("app.window.askTitle"),
|
||
width: canAttach ? 640 : undefined,
|
||
body: t("app.window.askBody", { name }),
|
||
buttons: [
|
||
{ id: "cancel", label: t("common.cancel") },
|
||
...(canAttach ? [{ id: "attach", label: t("app.window.askAttach") }] : []),
|
||
{ id: "new", label: t("app.window.askNew") },
|
||
{ id: "same", label: t("app.window.askThis"), primary: true },
|
||
],
|
||
checkbox: t("app.window.askRemember"),
|
||
});
|
||
if (r.button !== "same" && r.button !== "new" && r.button !== "attach") return null;
|
||
if (r.checked) {
|
||
try {
|
||
useProject.setState({
|
||
settings: await call(commands.settingsSet("global", "general.openProjectIn", JSON.stringify(r.button))),
|
||
});
|
||
} catch {
|
||
/* the choice still applies to this open */
|
||
}
|
||
}
|
||
return r.button;
|
||
}
|
||
|
||
/**
|
||
* Opens folder `path` of `target` (an SSH host or a WSL distribution): focuses the
|
||
* window that has it, else opens it in a new window or (`here`) this one per
|
||
* "Open project in". `false`: cancelled.
|
||
*/
|
||
export async function openRemoteProject(
|
||
target: RemoteTarget,
|
||
path: string,
|
||
here: () => Promise<unknown> = () => connectRemote(target, path),
|
||
): Promise<boolean> {
|
||
if ((await call(commands.windowOpenRemote(target, path, false))).kind === "focused") return true;
|
||
const mode = await chooseProjectWindow(path.replace(/\/+$/, "").split("/").pop() || path, false);
|
||
if (!mode) return false;
|
||
if (mode === "new") {
|
||
await call(commands.windowOpenRemote(target, path, true));
|
||
return true;
|
||
}
|
||
if (!(await confirmLeaveProject())) return false;
|
||
try {
|
||
await here();
|
||
return true;
|
||
} catch (e) {
|
||
maybeEditorService()?.cancelClose?.();
|
||
throw e;
|
||
}
|
||
}
|