Open files in more installed editors (#2119)

* feat(desktop): open files in more installed editors

Detect bundled app commands as well as PATH launchers and preserve file positions through editor-specific launches.

* fix(desktop): preserve editor target compatibility

Keep existing file-manager preference ids, retain project context for file launches, and recognize Windows 64-bit IDE commands.
This commit is contained in:
Mohamed Boudra
2026-07-16 14:39:55 +02:00
committed by GitHub
parent 3e8dce7d7c
commit f4509fe044
50 changed files with 1665 additions and 1051 deletions
@@ -1,37 +0,0 @@
import { SquareTerminal } from "lucide-react-native";
import { useMemo } from "react";
import { Image, type ImageSourcePropType } from "react-native";
import { isKnownEditorTargetId, type EditorTargetId } from "@/workspace/editor-targets";
interface EditorAppIconProps {
editorId: EditorTargetId;
size?: number;
color?: string;
}
/* eslint-disable @typescript-eslint/no-require-imports */
const EDITOR_APP_IMAGES: Record<string, ImageSourcePropType> = {
cursor: require("../../../assets/images/editor-apps/cursor.png"),
vscode: require("../../../assets/images/editor-apps/vscode.png"),
webstorm: require("../../../assets/images/editor-apps/webstorm.png"),
zed: require("../../../assets/images/editor-apps/zed.png"),
antigravity: require("../../../assets/images/editor-apps/antigravity.png"),
finder: require("../../../assets/images/editor-apps/finder.png"),
explorer: require("../../../assets/images/editor-apps/file-explorer.png"),
"file-manager": require("../../../assets/images/editor-apps/file-explorer.png"),
};
/* eslint-enable @typescript-eslint/no-require-imports */
export function hasBundledEditorAppIcon(editorId: EditorTargetId): boolean {
return isKnownEditorTargetId(editorId) && EDITOR_APP_IMAGES[editorId] !== undefined;
}
export function EditorAppIcon({ editorId, size = 16, color }: EditorAppIconProps) {
const imageStyle = useMemo(() => ({ width: size, height: size }), [size]);
const source = EDITOR_APP_IMAGES[editorId];
if (!source) {
return <SquareTerminal size={size} color={color} />;
}
return <Image source={source} style={imageStyle} resizeMode="contain" />;
}
@@ -0,0 +1,27 @@
import { Folder, SquareTerminal } from "lucide-react-native";
import { useMemo } from "react";
import { Image } from "react-native";
import type { DesktopOpenTargetIcon } from "@/workspace/desktop-open-targets";
interface EditorTargetIconProps {
icon: DesktopOpenTargetIcon;
size?: number;
color?: string;
}
export function EditorTargetIcon({ icon, size = 16, color }: EditorTargetIconProps) {
const imageStyle = useMemo(() => ({ width: size, height: size }), [size]);
const imageSource = useMemo(
() => (icon.kind === "image" ? { uri: icon.dataUrl } : undefined),
[icon],
);
if (imageSource) {
return <Image source={imageSource} style={imageStyle} resizeMode="contain" />;
}
if (icon.kind === "symbol" && icon.name === "folder") {
return <Folder size={size} color={color} />;
}
return <SquareTerminal size={size} color={color} />;
}