summaryrefslogtreecommitdiffhomepage
path: root/packages/desktop/src/context
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-12-04 20:32:08 -0600
committerAdam <[email protected]>2025-12-04 20:32:08 -0600
commit09f522f0aa698be60c954e58bb7eee0e460c4439 (patch)
tree8b936f4ab3cbafab391551e898412d1617dbd66b /packages/desktop/src/context
parentd82bd430f68b8227a93c39e0b7b617c9463ceea8 (diff)
downloadopencode-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.tsx22
-rw-r--r--packages/desktop/src/context/sdk.tsx2
-rw-r--r--packages/desktop/src/context/session.tsx100
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])
+ }),
+ )
+ },
+ },
}
},
})