Download packages/app/src/components/session/open-in-app.tsx from SaylorTwift/opencode: direct link, hf CLI and curl.
- Browser
- Download file 7.51 kB
-
https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/app/src/components/session/open-in-app.tsx
- Command line
-
hf download hf://SaylorTwift/opencode/packages/app/src/components/session/open-in-app.tsx
-
curl -L -o open-in-app.tsx https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/app/src/components/session/open-in-app.tsx
7.51 kB
| import { createEffect, createMemo } from "solid-js" | |
| import { createStore } from "solid-js/store" | |
| import { useLanguage } from "@/context/language" | |
| import { usePlatform } from "@/context/platform" | |
| import { useServer } from "@/context/server" | |
| import { Persist, persisted } from "@/utils/persist" | |
| import { showToast } from "@/utils/toast" | |
| export const OPEN_APPS = [ | |
| "vscode", | |
| "cursor", | |
| "zed", | |
| "textmate", | |
| "antigravity", | |
| "finder", | |
| "terminal", | |
| "iterm2", | |
| "ghostty", | |
| "warp", | |
| "xcode", | |
| "android-studio", | |
| "powershell", | |
| "sublime-text", | |
| ] as const | |
| export type OpenApp = (typeof OPEN_APPS)[number] | |
| export type OpenAppOS = "macos" | "windows" | "linux" | "unknown" | |
| export const MAC_OPEN_APPS = [ | |
| { | |
| id: "vscode", | |
| label: "session.header.open.app.vscode", | |
| icon: "vscode", | |
| openWith: "Visual Studio Code", | |
| }, | |
| { id: "cursor", label: "session.header.open.app.cursor", icon: "cursor", openWith: "Cursor" }, | |
| { id: "zed", label: "session.header.open.app.zed", icon: "zed", openWith: "Zed" }, | |
| { id: "textmate", label: "session.header.open.app.textmate", icon: "textmate", openWith: "TextMate" }, | |
| { | |
| id: "antigravity", | |
| label: "session.header.open.app.antigravity", | |
| icon: "antigravity", | |
| openWith: "Antigravity", | |
| }, | |
| { id: "terminal", label: "session.header.open.app.terminal", icon: "terminal", openWith: "Terminal" }, | |
| { id: "iterm2", label: "session.header.open.app.iterm2", icon: "iterm2", openWith: "iTerm" }, | |
| { id: "ghostty", label: "session.header.open.app.ghostty", icon: "ghostty", openWith: "Ghostty" }, | |
| { id: "warp", label: "session.header.open.app.warp", icon: "warp", openWith: "Warp" }, | |
| { id: "xcode", label: "session.header.open.app.xcode", icon: "xcode", openWith: "Xcode" }, | |
| { | |
| id: "android-studio", | |
| label: "session.header.open.app.androidStudio", | |
| icon: "android-studio", | |
| openWith: "Android Studio", | |
| }, | |
| { | |
| id: "sublime-text", | |
| label: "session.header.open.app.sublimeText", | |
| icon: "sublime-text", | |
| openWith: "Sublime Text", | |
| }, | |
| ] as const | |
| export const WINDOWS_OPEN_APPS = [ | |
| { id: "vscode", label: "session.header.open.app.vscode", icon: "vscode", openWith: "code" }, | |
| { id: "cursor", label: "session.header.open.app.cursor", icon: "cursor", openWith: "cursor" }, | |
| { id: "zed", label: "session.header.open.app.zed", icon: "zed", openWith: "zed" }, | |
| { | |
| id: "powershell", | |
| label: "session.header.open.app.powershell", | |
| icon: "powershell", | |
| openWith: "powershell", | |
| }, | |
| { | |
| id: "sublime-text", | |
| label: "session.header.open.app.sublimeText", | |
| icon: "sublime-text", | |
| openWith: "Sublime Text", | |
| }, | |
| ] as const | |
| export const LINUX_OPEN_APPS = [ | |
| { id: "vscode", label: "session.header.open.app.vscode", icon: "vscode", openWith: "code" }, | |
| { id: "cursor", label: "session.header.open.app.cursor", icon: "cursor", openWith: "cursor" }, | |
| { id: "zed", label: "session.header.open.app.zed", icon: "zed", openWith: "zed" }, | |
| { | |
| id: "sublime-text", | |
| label: "session.header.open.app.sublimeText", | |
| icon: "sublime-text", | |
| openWith: "Sublime Text", | |
| }, | |
| ] as const | |
| export function detectOpenAppOS(platform: ReturnType<typeof usePlatform>): OpenAppOS { | |
| if (platform.platform === "desktop" && platform.os) return platform.os | |
| if (typeof navigator !== "object") return "unknown" | |
| const value = navigator.platform || navigator.userAgent | |
| if (/Mac/i.test(value)) return "macos" | |
| if (/Win/i.test(value)) return "windows" | |
| if (/Linux/i.test(value)) return "linux" | |
| return "unknown" | |
| } | |
| export function openAppFileManager(os: OpenAppOS) { | |
| if (os === "macos") return { label: "session.header.open.finder", icon: "finder" as const } | |
| if (os === "windows") return { label: "session.header.open.fileExplorer", icon: "file-explorer" as const } | |
| return { label: "session.header.open.fileManager", icon: "finder" as const } | |
| } | |
| export function openAppsForOS(os: OpenAppOS) { | |
| if (os === "macos") return MAC_OPEN_APPS | |
| if (os === "windows") return WINDOWS_OPEN_APPS | |
| return LINUX_OPEN_APPS | |
| } | |
| const showRequestError = (language: ReturnType<typeof useLanguage>, err: unknown) => { | |
| showToast({ | |
| variant: "error", | |
| title: language.t("common.requestFailed"), | |
| description: err instanceof Error ? err.message : String(err), | |
| }) | |
| } | |
| export function useOpenInApp(input: { directory: () => string }) { | |
| const platform = usePlatform() | |
| const server = useServer() | |
| const language = useLanguage() | |
| const os = createMemo(() => detectOpenAppOS(platform)) | |
| const apps = createMemo(() => openAppsForOS(os())) | |
| const fileManager = createMemo(() => openAppFileManager(os())) | |
| const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({ | |
| finder: true, | |
| }) | |
| createEffect(() => { | |
| if (platform.platform !== "desktop") return | |
| if (!platform.checkAppExists) return | |
| const list = apps() | |
| setExists(Object.fromEntries(list.map((app) => [app.id, undefined])) as Partial<Record<OpenApp, boolean>>) | |
| void Promise.all( | |
| list.map((app) => | |
| Promise.resolve(platform.checkAppExists?.(app.openWith)) | |
| .then((value) => Boolean(value)) | |
| .catch(() => false) | |
| .then((ok) => [app.id, ok] as const), | |
| ), | |
| ).then((entries) => { | |
| setExists(Object.fromEntries(entries) as Partial<Record<OpenApp, boolean>>) | |
| }) | |
| }) | |
| const options = createMemo(() => { | |
| return [ | |
| { id: "finder", label: language.t(fileManager().label), icon: fileManager().icon }, | |
| ...apps() | |
| .filter((app) => exists[app.id]) | |
| .map((app) => ({ ...app, label: language.t(app.label) })), | |
| ] as const | |
| }) | |
| const [prefs, setPrefs] = persisted(Persist.global("open.app"), createStore({ app: "finder" as OpenApp | "finder" })) | |
| const [menu, setMenu] = createStore({ open: false }) | |
| const [openRequest, setOpenRequest] = createStore({ | |
| app: undefined as OpenApp | undefined, | |
| }) | |
| const canOpen = createMemo(() => platform.platform === "desktop" && !!platform.openPath && server.isLocal()) | |
| const current = createMemo( | |
| () => | |
| options().find((o) => o.id === prefs.app) ?? | |
| options()[0] ?? | |
| ({ id: "finder", label: fileManager().label, icon: fileManager().icon } as const), | |
| ) | |
| const opening = createMemo(() => openRequest.app !== undefined) | |
| const selectApp = (app: OpenApp | "finder") => { | |
| if (!options().some((item) => item.id === app)) return | |
| setPrefs("app", app) | |
| } | |
| const openDir = (app: OpenApp | "finder") => { | |
| if (opening() || !canOpen() || !platform.openPath) return | |
| const directory = input.directory() | |
| if (!directory) return | |
| const item = options().find((o) => o.id === app) | |
| const openWith = item && "openWith" in item ? item.openWith : undefined | |
| setOpenRequest("app", app) | |
| platform | |
| .openPath(directory, openWith) | |
| .catch((err: unknown) => showRequestError(language, err)) | |
| .finally(() => { | |
| setOpenRequest("app", undefined) | |
| }) | |
| } | |
| const copyPath = () => { | |
| const directory = input.directory() | |
| if (!directory) return | |
| navigator.clipboard | |
| .writeText(directory) | |
| .then(() => { | |
| showToast({ | |
| variant: "success", | |
| icon: "circle-check", | |
| title: language.t("session.share.copy.copied"), | |
| description: directory, | |
| }) | |
| }) | |
| .catch((err: unknown) => showRequestError(language, err)) | |
| } | |
| return { | |
| canOpen, | |
| opening, | |
| current, | |
| options, | |
| menu, | |
| setMenu, | |
| openDir, | |
| selectApp, | |
| copyPath, | |
| } | |
| } | |