diff options
| author | Adam <[email protected]> | 2025-12-04 15:37:29 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-04 15:37:29 -0600 |
| commit | d763c11a6d5bc57869f11c87f5a293f61e427e0a (patch) | |
| tree | 88fd0024e1c8a2fe5cee803ccf110a3cac6768d4 /packages/desktop/src/context/session.tsx | |
| parent | b1202ac6db1cbead1e8f205913524f1c47322970 (diff) | |
| download | opencode-d763c11a6d5bc57869f11c87f5a293f61e427e0a.tar.gz opencode-d763c11a6d5bc57869f11c87f5a293f61e427e0a.zip | |
feat(desktop): terminal pane (#5081)
Co-authored-by: Github Action <[email protected]>
Co-authored-by: Dax Raad <[email protected]>
Diffstat (limited to 'packages/desktop/src/context/session.tsx')
| -rw-r--r-- | packages/desktop/src/context/session.tsx | 100 |
1 files changed, 88 insertions, 12 deletions
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]) + }), + ) + }, + }, } }, }) |
