summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-11-10 11:46:53 -0600
committerAdam <[email protected]>2025-11-11 09:01:27 -0600
commit4f604b38399bea3ce08fdba3ce2ad8c7603ed4ea (patch)
treea529a6ccdececd1d549b72f91652f3cc5138418f /packages
parenta20489584e2cf3fb6913d7b55aa10813ea3bee25 (diff)
downloadopencode-4f604b38399bea3ce08fdba3ce2ad8c7603ed4ea.tar.gz
opencode-4f604b38399bea3ce08fdba3ce2ad8c7603ed4ea.zip
fix(desktop): color grouping
Diffstat (limited to 'packages')
-rw-r--r--packages/desktop/src/context/session.tsx125
-rw-r--r--packages/ui/src/components/diff.tsx7
2 files changed, 101 insertions, 31 deletions
diff --git a/packages/desktop/src/context/session.tsx b/packages/desktop/src/context/session.tsx
index 61fed945e..02c859a5b 100644
--- a/packages/desktop/src/context/session.tsx
+++ b/packages/desktop/src/context/session.tsx
@@ -1,6 +1,6 @@
import { createStore, produce } from "solid-js/store"
import { createSimpleContext } from "./helper"
-import { batch, createEffect, createMemo } from "solid-js"
+import { batch, createEffect, createMemo, createSignal, on } from "solid-js"
import { useSync } from "./sync"
import { makePersisted } from "@solid-primitives/storage"
import { TextSelection, useLocal } from "./local"
@@ -13,26 +13,74 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
const sync = useSync()
const local = useLocal()
- const [store, setStore] = makePersisted(
+ const seed = props.sessionId ?? "new-session"
+
+ const [persist, setPersist] = makePersisted(
createStore<{
- prompt: Prompt
- cursorPosition?: number
messageId?: string
tabs: {
active?: string
opened: string[]
}
}>({
- prompt: [{ type: "text", content: "", start: 0, end: 0 }],
tabs: {
opened: [],
},
}),
{
- name: props.sessionId ?? "new-session",
+ name: seed,
},
)
+ const [promptStore, setPromptStore] = createStore<{
+ prompt: Prompt
+ cursor?: number
+ }>({
+ prompt: clonePrompt(DEFAULT_PROMPT),
+ })
+
+ const key = createMemo(() => props.sessionId ?? "new-session")
+ const [ready, setReady] = createSignal(false)
+ const prefix = "session-prompt:"
+
+ createEffect(
+ on(
+ key,
+ (value) => {
+ setReady(false)
+ const record = localStorage.getItem(prefix + value)
+ if (!record) {
+ setPromptStore("prompt", clonePrompt(DEFAULT_PROMPT))
+ setPromptStore("cursor", undefined)
+ setReady(true)
+ return
+ }
+ const payload = JSON.parse(record) as { prompt?: Prompt; cursor?: number }
+ const parts = payload.prompt ?? DEFAULT_PROMPT
+ const cursor = typeof payload.cursor === "number" ? payload.cursor : undefined
+ setPromptStore("prompt", clonePrompt(parts))
+ setPromptStore("cursor", cursor)
+ setReady(true)
+ },
+ { defer: true },
+ ),
+ )
+
+ createEffect(() => {
+ if (!ready()) return
+ const value = key()
+ const isDefault = isPromptEqual(promptStore.prompt, DEFAULT_PROMPT)
+ if (isDefault && (promptStore.cursor === undefined || promptStore.cursor <= 0)) {
+ localStorage.removeItem(prefix + value)
+ return
+ }
+ const next = JSON.stringify({
+ prompt: clonePrompt(promptStore.prompt),
+ cursor: promptStore.cursor,
+ })
+ localStorage.setItem(prefix + value, next)
+ })
+
createEffect(() => {
if (!props.sessionId) return
sync.session.sync(props.sessionId)
@@ -49,8 +97,8 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
return userMessages()?.at(0)
})
const activeMessage = createMemo(() => {
- if (!store.messageId) return lastUserMessage()
- return userMessages()?.find((m) => m.id === store.messageId)
+ if (!persist.messageId) return lastUserMessage()
+ return userMessages()?.find((m) => m.id === persist.messageId)
})
const working = createMemo(() => {
if (!props.sessionId) return false
@@ -101,13 +149,14 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
working,
diffs,
prompt: {
- current: createMemo(() => store.prompt),
- cursor: createMemo(() => store.cursorPosition),
- dirty: createMemo(() => !isPromptEqual(store.prompt, DEFAULT_PROMPT)),
+ current: createMemo(() => promptStore.prompt),
+ cursor: createMemo(() => promptStore.cursor),
+ dirty: createMemo(() => !isPromptEqual(promptStore.prompt, DEFAULT_PROMPT)),
set(prompt: Prompt, cursorPosition?: number) {
+ const next = clonePrompt(prompt)
batch(() => {
- setStore("prompt", prompt)
- if (cursorPosition !== undefined) setStore("cursorPosition", cursorPosition)
+ setPromptStore("prompt", next)
+ if (cursorPosition !== undefined) setPromptStore("cursor", cursorPosition)
})
},
},
@@ -117,7 +166,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
last: lastUserMessage,
active: activeMessage,
setActive(id: string | undefined) {
- setStore("messageId", id)
+ setPersist("messageId", id)
},
},
usage: {
@@ -126,53 +175,52 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
context,
},
layout: {
- tabs: store.tabs,
+ tabs: persist.tabs,
setActiveTab(tab: string | undefined) {
- setStore("tabs", "active", tab)
+ setPersist("tabs", "active", tab)
},
setOpenedTabs(tabs: string[]) {
- setStore("tabs", "opened", tabs)
+ setPersist("tabs", "opened", tabs)
},
async openTab(tab: string) {
if (tab === "chat") {
- setStore("tabs", "active", undefined)
+ setPersist("tabs", "active", undefined)
return
}
if (tab.startsWith("file://")) {
await local.file.open(tab.replace("file://", ""))
}
if (tab !== "review") {
- if (!store.tabs.opened.includes(tab)) {
- setStore("tabs", "opened", [...store.tabs.opened, tab])
+ if (!persist.tabs.opened.includes(tab)) {
+ setPersist("tabs", "opened", [...persist.tabs.opened, tab])
}
}
- setStore("tabs", "active", tab)
+ setPersist("tabs", "active", tab)
},
closeTab(tab: string) {
batch(() => {
- setStore(
+ setPersist(
"tabs",
"opened",
- store.tabs.opened.filter((x) => x !== tab),
+ persist.tabs.opened.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)]
- setStore("tabs", "active", previous)
+ if (persist.tabs.active === tab) {
+ const index = persist.tabs.opened.findIndex((f) => f === tab)
+ const previous = persist.tabs.opened[Math.max(0, index - 1)]
+ setPersist("tabs", "active", previous)
}
})
},
moveTab(tab: string, to: number) {
- const index = store.tabs.opened.findIndex((f) => f === tab)
+ const index = persist.tabs.opened.findIndex((f) => f === tab)
if (index === -1) return
- setStore(
+ setPersist(
"tabs",
"opened",
produce((opened) => {
opened.splice(to, 0, opened.splice(index, 1)[0])
}),
)
- // setStore("node", path, "pinned", true)
},
},
}
@@ -215,3 +263,20 @@ export function isPromptEqual(promptA: Prompt, promptB: Prompt): boolean {
}
return true
}
+
+function cloneSelection(selection?: TextSelection) {
+ if (!selection) return undefined
+ return { ...selection }
+}
+
+function clonePart(part: ContentPart): ContentPart {
+ if (part.type === "text") return { ...part }
+ return {
+ ...part,
+ selection: cloneSelection(part.selection),
+ }
+}
+
+function clonePrompt(prompt: Prompt): Prompt {
+ return prompt.map(clonePart)
+}
diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx
index a53d5b3f3..d0c0036ed 100644
--- a/packages/ui/src/components/diff.tsx
+++ b/packages/ui/src/components/diff.tsx
@@ -232,13 +232,18 @@ registerCustomTheme("OpenCode", () => {
},
},
{
+ scope: ["meta.object.member"],
+ settings: {
+ foreground: "var(--syntax-primitive)",
+ },
+ },
+ {
scope: [
"variable.parameter.function",
"meta.jsx.children",
"meta.block",
"meta.tag.attributes",
"entity.name.constant",
- "meta.object.member",
"meta.embedded.expression",
"meta.template.expression",
"string.other.begin.yaml",