diff options
| author | Adam <[email protected]> | 2025-12-04 20:32:08 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-12-04 20:32:08 -0600 |
| commit | 09f522f0aa698be60c954e58bb7eee0e460c4439 (patch) | |
| tree | 8b936f4ab3cbafab391551e898412d1617dbd66b /packages/desktop/src/context | |
| parent | d82bd430f68b8227a93c39e0b7b617c9463ceea8 (diff) | |
| download | opencode-09f522f0aa698be60c954e58bb7eee0e460c4439.tar.gz opencode-09f522f0aa698be60c954e58bb7eee0e460c4439.zip | |
Reapply "feat(desktop): terminal pane (#5081)"
This reverts commit f9dcd979364acc5172fd0044c1c8b04dcaec9229.
Diffstat (limited to 'packages/desktop/src/context')
| -rw-r--r-- | packages/desktop/src/context/layout.tsx | 22 | ||||
| -rw-r--r-- | packages/desktop/src/context/sdk.tsx | 2 | ||||
| -rw-r--r-- | packages/desktop/src/context/session.tsx | 100 |
3 files changed, 110 insertions, 14 deletions
diff --git a/packages/desktop/src/context/layout.tsx b/packages/desktop/src/context/layout.tsx index 81e8b537a..ca736e84e 100644 --- a/packages/desktop/src/context/layout.tsx +++ b/packages/desktop/src/context/layout.tsx @@ -15,12 +15,16 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( opened: true, width: 280, }, + terminal: { + opened: false, + height: 280, + }, review: { state: "pane" as "pane" | "tab", }, }), { - name: "___default-layout", + name: "____default-layout", }, ) @@ -61,6 +65,22 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( setStore("sidebar", "width", width) }, }, + terminal: { + opened: createMemo(() => store.terminal.opened), + open() { + setStore("terminal", "opened", true) + }, + close() { + setStore("terminal", "opened", false) + }, + toggle() { + setStore("terminal", "opened", (x) => !x) + }, + height: createMemo(() => store.terminal.height), + resize(height: number) { + setStore("terminal", "height", height) + }, + }, review: { state: createMemo(() => store.review?.state ?? "closed"), pane() { diff --git a/packages/desktop/src/context/sdk.tsx b/packages/desktop/src/context/sdk.tsx index 81b32035a..144202ee2 100644 --- a/packages/desktop/src/context/sdk.tsx +++ b/packages/desktop/src/context/sdk.tsx @@ -27,6 +27,6 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ abort.abort() }) - return { directory: props.directory, client: sdk, event: emitter } + return { directory: props.directory, client: sdk, event: emitter, url: globalSDK.url } }, }) diff --git a/packages/desktop/src/context/session.tsx b/packages/desktop/src/context/session.tsx index 72098a939..4e9fe71f8 100644 --- a/packages/desktop/src/context/session.tsx +++ b/packages/desktop/src/context/session.tsx @@ -8,14 +8,25 @@ import { pipe, sumBy } from "remeda" import { AssistantMessage, UserMessage } from "@opencode-ai/sdk" import { useParams } from "@solidjs/router" import { base64Encode } from "@/utils" +import { useSDK } from "./sdk" + +export type LocalPTY = { + id: string + title: string + rows?: number + cols?: number + buffer?: string + scrollY?: number +} export const { use: useSession, provider: SessionProvider } = createSimpleContext({ name: "Session", init: () => { + const sdk = useSDK() const params = useParams() const sync = useSync() const name = createMemo( - () => `___${base64Encode(sync.data.project.worktree)}/session${params.id ? "/" + params.id : ""}`, + () => `______${base64Encode(sync.data.project.worktree)}/session${params.id ? "/" + params.id : ""}`, ) const [store, setStore] = makePersisted( @@ -23,16 +34,21 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex messageId?: string tabs: { active?: string - opened: string[] + all: string[] } prompt: Prompt cursor?: number + terminals: { + active?: string + all: LocalPTY[] + } }>({ tabs: { - opened: [], + all: [], }, prompt: clonePrompt(DEFAULT_PROMPT), cursor: undefined, + terminals: { all: [] }, }), { name: name(), @@ -138,7 +154,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex setStore("tabs", "active", tab) }, setOpenedTabs(tabs: string[]) { - setStore("tabs", "opened", tabs) + setStore("tabs", "all", tabs) }, async openTab(tab: string) { if (tab === "chat") { @@ -146,8 +162,8 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex return } if (tab !== "review") { - if (!store.tabs.opened.includes(tab)) { - setStore("tabs", "opened", [...store.tabs.opened, tab]) + if (!store.tabs.all.includes(tab)) { + setStore("tabs", "all", [...store.tabs.all, tab]) } } setStore("tabs", "active", tab) @@ -156,28 +172,88 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex batch(() => { setStore( "tabs", - "opened", - store.tabs.opened.filter((x) => x !== tab), + "all", + store.tabs.all.filter((x) => x !== tab), ) if (store.tabs.active === tab) { - const index = store.tabs.opened.findIndex((f) => f === tab) - const previous = store.tabs.opened[Math.max(0, index - 1)] + const index = store.tabs.all.findIndex((f) => f === tab) + const previous = store.tabs.all[Math.max(0, index - 1)] setStore("tabs", "active", previous) } }) }, moveTab(tab: string, to: number) { - const index = store.tabs.opened.findIndex((f) => f === tab) + const index = store.tabs.all.findIndex((f) => f === tab) if (index === -1) return setStore( "tabs", - "opened", + "all", produce((opened) => { opened.splice(to, 0, opened.splice(index, 1)[0]) }), ) }, }, + terminal: { + all: createMemo(() => Object.values(store.terminals.all)), + active: createMemo(() => store.terminals.active), + new() { + sdk.client.pty.create({ body: { title: `Terminal ${store.terminals.all.length + 1}` } }).then((pty) => { + const id = pty.data?.id + if (!id) return + batch(() => { + setStore("terminals", "all", [ + ...store.terminals.all, + { + id, + title: pty.data?.title ?? "Terminal", + // rows: pty.data?.rows ?? 24, + // cols: pty.data?.cols ?? 80, + // buffer: "", + // scrollY: 0, + }, + ]) + setStore("terminals", "active", id) + }) + }) + }, + update(pty: Partial<LocalPTY> & { id: string }) { + setStore("terminals", "all", (x) => x.map((x) => (x.id === pty.id ? { ...x, ...pty } : x))) + sdk.client.pty.update({ + path: { id: pty.id }, + body: { title: pty.title, size: pty.cols && pty.rows ? { rows: pty.rows, cols: pty.cols } : undefined }, + }) + }, + open(id: string) { + setStore("terminals", "active", id) + }, + async close(id: string) { + batch(() => { + setStore( + "terminals", + "all", + store.terminals.all.filter((x) => x.id !== id), + ) + if (store.terminals.active === id) { + const index = store.terminals.all.findIndex((f) => f.id === id) + const previous = store.tabs.all[Math.max(0, index - 1)] + setStore("terminals", "active", previous) + } + }) + await sdk.client.pty.remove({ path: { id } }) + }, + move(id: string, to: number) { + const index = store.terminals.all.findIndex((f) => f.id === id) + if (index === -1) return + setStore( + "terminals", + "all", + produce((all) => { + all.splice(to, 0, all.splice(index, 1)[0]) + }), + ) + }, + }, } }, }) |
