From d525fbf82940442d8d47265b7d7d0a9af8c282bc Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 5 Nov 2025 11:55:31 -0600 Subject: feat(desktop): session router, interrupt agent, visual cleanup --- packages/desktop/src/pages/index.tsx | 857 -------------------------- packages/desktop/src/pages/layout.tsx | 75 +++ packages/desktop/src/pages/session-layout.tsx | 12 + packages/desktop/src/pages/session.tsx | 693 +++++++++++++++++++++ 4 files changed, 780 insertions(+), 857 deletions(-) delete mode 100644 packages/desktop/src/pages/index.tsx create mode 100644 packages/desktop/src/pages/layout.tsx create mode 100644 packages/desktop/src/pages/session-layout.tsx create mode 100644 packages/desktop/src/pages/session.tsx (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx deleted file mode 100644 index 5f04c3dbe..000000000 --- a/packages/desktop/src/pages/index.tsx +++ /dev/null @@ -1,857 +0,0 @@ -import { - Button, - List, - SelectDialog, - Tooltip, - IconButton, - Tabs, - Icon, - Accordion, - Diff, - Collapsible, - DiffChanges, - Message, - Typewriter, - Card, - Code, -} from "@opencode-ai/ui" -import { FileIcon } from "@/ui" -import FileTree from "@/components/file-tree" -import { MessageProgress } from "@/components/message-progress" -import { For, onCleanup, onMount, Show, Match, Switch, createSignal, createEffect, createMemo } from "solid-js" -import { useLocal, type LocalFile } from "@/context/local" -import { createStore } from "solid-js/store" -import { getDirectory, getFilename } from "@/utils" -import { ContentPart, PromptInput } from "@/components/prompt-input" -import { DateTime } from "luxon" -import { - DragDropProvider, - DragDropSensors, - DragOverlay, - SortableProvider, - closestCenter, - createSortable, - useDragDropContext, -} from "@thisbeyond/solid-dnd" -import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd" -import type { JSX } from "solid-js" -import { useSync } from "@/context/sync" -import { useSDK } from "@/context/sdk" -import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk" -import { Markdown } from "@opencode-ai/ui" -import { Spinner } from "@/components/spinner" - -export default function Page() { - const local = useLocal() - const sync = useSync() - const sdk = useSDK() - const [store, setStore] = createStore({ - clickTimer: undefined as number | undefined, - fileSelectOpen: false, - }) - let inputRef!: HTMLDivElement - let messageScrollElement!: HTMLDivElement - const [activeItem, setActiveItem] = createSignal(undefined) - - const MOD = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) ? "Meta" : "Control" - - onMount(() => { - document.addEventListener("keydown", handleKeyDown) - }) - - onCleanup(() => { - document.removeEventListener("keydown", handleKeyDown) - }) - - const handleKeyDown = (event: KeyboardEvent) => { - if (event.getModifierState(MOD) && event.shiftKey && event.key.toLowerCase() === "p") { - event.preventDefault() - return - } - if (event.getModifierState(MOD) && event.key.toLowerCase() === "p") { - event.preventDefault() - setStore("fileSelectOpen", true) - return - } - - const focused = document.activeElement === inputRef - if (focused) { - if (event.key === "Escape") { - inputRef?.blur() - } - return - } - - // if (local.file.active()) { - // const active = local.file.active()! - // if (event.key === "Enter" && active.selection) { - // local.context.add({ - // type: "file", - // path: active.path, - // selection: { ...active.selection }, - // }) - // return - // } - // - // if (event.getModifierState(MOD)) { - // if (event.key.toLowerCase() === "a") { - // return - // } - // if (event.key.toLowerCase() === "c") { - // return - // } - // } - // } - - if (event.key.length === 1 && event.key !== "Unidentified" && !(event.ctrlKey || event.metaKey)) { - inputRef?.focus() - } - } - - const resetClickTimer = () => { - if (!store.clickTimer) return - clearTimeout(store.clickTimer) - setStore("clickTimer", undefined) - } - - const startClickTimer = () => { - const newClickTimer = setTimeout(() => { - setStore("clickTimer", undefined) - }, 300) - setStore("clickTimer", newClickTimer as unknown as number) - } - - const handleFileClick = async (file: LocalFile) => { - if (store.clickTimer) { - resetClickTimer() - local.file.update(file.path, { ...file, pinned: true }) - } else { - local.file.open(file.path) - startClickTimer() - } - } - - // const navigateChange = (dir: 1 | -1) => { - // const active = local.file.active() - // if (!active) return - // const current = local.file.changeIndex(active.path) - // const next = current === undefined ? (dir === 1 ? 0 : -1) : current + dir - // local.file.setChangeIndex(active.path, next) - // } - - const handleTabChange = (path: string) => { - local.session.setActiveTab(path) - if (path === "chat") return - local.session.open(path) - } - - const handleTabClose = (file: LocalFile) => { - local.session.close(file.path) - } - - const handleDragStart = (event: unknown) => { - const id = getDraggableId(event) - if (!id) return - setActiveItem(id) - } - - const handleDragOver = (event: DragEvent) => { - const { draggable, droppable } = event - if (draggable && droppable) { - const currentFiles = local.session.tabs()?.opened.map((file) => file) - const fromIndex = currentFiles?.indexOf(draggable.id.toString()) - const toIndex = currentFiles?.indexOf(droppable.id.toString()) - if (fromIndex !== toIndex && toIndex !== undefined) { - local.session.move(draggable.id.toString(), toIndex) - } - } - } - - const handleDragEnd = () => { - setActiveItem(undefined) - } - - // const scrollDiffItem = (element: HTMLElement) => { - // element.scrollIntoView({ block: "start", behavior: "instant" }) - // } - - const handleDiffTriggerClick = (event: MouseEvent) => { - // disabling scroll to diff for now - return - // const target = event.currentTarget as HTMLElement - // queueMicrotask(() => { - // if (target.getAttribute("aria-expanded") !== "true") return - // const item = target.closest('[data-slot="accordion-item"]') as HTMLElement | null - // if (!item) return - // scrollDiffItem(item) - // }) - } - - const handlePromptSubmit = async (parts: ContentPart[]) => { - const existingSession = local.session.active() - let session = existingSession - if (!session) { - const created = await sdk.client.session.create() - session = created.data ?? undefined - } - if (!session) return - - local.session.setActive(session.id) - if (!existingSession) { - local.session.copyTabs("", session.id) - } - local.session.setActiveTab(undefined) - const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) - - const text = parts.map((part) => part.content).join("") - const attachments = parts.filter((part) => part.type === "file") - - // const activeFile = local.context.active() - // if (activeFile) { - // registerAttachment( - // activeFile.path, - // activeFile.selection, - // activeFile.name ?? formatAttachmentLabel(activeFile.path, activeFile.selection), - // ) - // } - - // for (const contextFile of local.context.all()) { - // registerAttachment( - // contextFile.path, - // contextFile.selection, - // formatAttachmentLabel(contextFile.path, contextFile.selection), - // ) - // } - - const attachmentParts = attachments.map((attachment) => { - const absolute = toAbsolutePath(attachment.path) - const query = attachment.selection - ? `?start=${attachment.selection.startLine}&end=${attachment.selection.endLine}` - : "" - return { - type: "file" as const, - mime: "text/plain", - url: `file://${absolute}${query}`, - filename: getFilename(attachment.path), - source: { - type: "file" as const, - text: { - value: attachment.content, - start: attachment.start, - end: attachment.end, - }, - path: absolute, - }, - } - }) - - await sdk.client.session.prompt({ - path: { id: session.id }, - body: { - agent: local.agent.current()!.name, - model: { - modelID: local.model.current()!.id, - providerID: local.model.current()!.provider.id, - }, - parts: [ - { - type: "text", - text, - }, - ...attachmentParts, - ], - }, - }) - } - - const handleNewSession = () => { - local.session.setActive(undefined) - inputRef?.focus() - } - - const TabVisual = (props: { file: LocalFile }): JSX.Element => { - return ( -
- - - {props.file.name} - - -
- ) - } - - const SortableTab = (props: { - file: LocalFile - onTabClick: (file: LocalFile) => void - onTabClose: (file: LocalFile) => void - }): JSX.Element => { - const sortable = createSortable(props.file.path) - - return ( - // @ts-ignore -
- -
- props.onTabClick(props.file)} - > - - props.onTabClose(props.file)} - /> - -
-
-
- ) - } - - const ConstrainDragYAxis = (): JSX.Element => { - const context = useDragDropContext() - if (!context) return <> - const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context - const transformer: Transformer = { - id: "constrain-y-axis", - order: 100, - callback: (transform) => ({ ...transform, y: 0 }), - } - onDragStart((event) => { - const id = getDraggableId(event) - if (!id) return - addTransformer("draggables", id, transformer) - }) - onDragEnd((event) => { - const id = getDraggableId(event) - if (!id) return - removeTransformer("draggables", id, transformer.id) - }) - return <> - } - - const getDraggableId = (event: unknown): string | undefined => { - if (typeof event !== "object" || event === null) return undefined - if (!("draggable" in event)) return undefined - const draggable = (event as { draggable?: { id?: unknown } }).draggable - if (!draggable) return undefined - return typeof draggable.id === "string" ? draggable.id : undefined - } - - return ( -
- -
-
-
- {getFilename(sync.data.path.directory)} -
-
- - x.id} - current={local.session.active()} - onSelect={(s) => local.session.setActive(s?.id)} - onHover={(s) => (!!s ? sync.session.sync(s?.id) : undefined)} - > - {(session) => { - const diffs = createMemo(() => session.summary?.diffs ?? []) - const filesChanged = createMemo(() => diffs().length) - const updated = DateTime.fromMillis(session.time.updated) - return ( - -
-
- - {session.title} - - - {Math.abs(updated.diffNow().as("seconds")) < 60 - ? "Now" - : updated - .toRelative({ style: "short", unit: ["days", "hours", "minutes"] }) - ?.replace(" ago", "") - ?.replace(/ days?/, "d") - ?.replace(" min.", "m") - ?.replace(" hr.", "h")} - -
-
- {`${filesChanged() || "No"} file${filesChanged() !== 1 ? "s" : ""} changed`} - -
-
-
- ) - }} -
-
-
-
- - - - -
- - -
Chat
- {/* */} - {/* */} - {/*
{local.session.context() ?? 0}%
*/} - {/*
*/} -
- {/* Review */} - - - {(file) => ( - - )} - - -
- setStore("fileSelectOpen", true)} - /> -
-
-
- -
- -
New session
-
- -
- {getDirectory(sync.data.path.directory)} - {getFilename(sync.data.path.directory)} -
-
-
- -
- Last modified  - - {DateTime.fromMillis(sync.data.project.time.created).toRelative()} - -
-
-
- } - > - {(session) => { - const [store, setStore] = createStore<{ - messageId?: string - }>() - - const messages = createMemo(() => sync.data.message[session().id] ?? []) - const userMessages = createMemo(() => - messages() - .filter((m) => m.role === "user") - .sort((a, b) => b.id.localeCompare(a.id)), - ) - const lastUserMessage = createMemo(() => { - return userMessages()?.at(0) - }) - const activeMessage = createMemo(() => { - if (!store.messageId) return lastUserMessage() - return userMessages()?.find((m) => m.id === store.messageId) - }) - - return ( -
-
- 1}> - - -
- - {(message) => { - const isActive = createMemo(() => activeMessage()?.id === message.id) - const [titled, setTitled] = createSignal(!!message.summary?.title) - const assistantMessages = createMemo(() => { - return sync.data.message[session().id]?.filter( - (m) => m.role === "assistant" && m.parentID == message.id, - ) as AssistantMessageType[] - }) - const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) - const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error()) - const [expanded, setExpanded] = createSignal(false) - const parts = createMemo(() => sync.data.part[message.id]) - const title = createMemo(() => message.summary?.title) - const summary = createMemo(() => message.summary?.body) - const diffs = createMemo(() => message.summary?.diffs ?? []) - const hasToolPart = createMemo(() => - assistantMessages() - ?.flatMap((m) => sync.data.part[m.id]) - .some((p) => p?.type === "tool"), - ) - const working = createMemo(() => !summary() && !error()) - - // allowing time for the animations to finish - createEffect(() => { - title() - setTimeout(() => setTitled(!!title()), 10_000) - }) - createEffect(() => { - const complete = !!summary() || !!error() - setTimeout(() => setCompleted(complete), 1200) - }) - - return ( - -
- {/* Title */} -
-
- - } - > -

- {title()} -

-
-
-
-
- -
- {/* Summary */} - -
-
-

- - Summary - Response - -

- - {(summary) => ( - *]:fade-up-text": !diffs().length }} - text={summary()} - /> - )} - -
- - - {(diff) => ( - - - -
-
- -
- - - {getDirectory(diff.file)}‎ - - - - {getFilename(diff.file)} - -
-
-
- - -
-
-
-
- - - -
- )} -
-
-
-
- - - {error()?.data?.message as string} - - - {/* Response */} -
- - - - - - - -
-
- - Hide details - Show details - -
- -
-
- -
- - {(assistantMessage) => { - const parts = createMemo( - () => sync.data.part[assistantMessage.id], - ) - return - }} - - - - {error()?.data?.message as string} - - -
-
-
-
-
-
-
-
- ) - }} -
-
-
-
- ) - }} - -
- - {/* */} - - {(file) => ( - - {(() => { - { - /* const view = local.file.view(file) */ - } - { - /* const showRaw = view === "raw" || !file.content?.diff */ - } - { - /* const code = showRaw ? (file.content?.content ?? "") : (file.content?.diff ?? "") */ - } - const node = local.file.node(file) - return ( - - ) - })()} - - )} - - - - {(() => { - const id = activeItem() - if (!id) return null - const draggedFile = local.file.node(id) - if (!draggedFile) return null - return ( -
- -
- ) - })()} -
- -
- { - inputRef = el - }} - onSubmit={handlePromptSubmit} - /> -
- - } - > -
    - - {(path) => ( -
  • - -
  • - )} -
    -
- -
- - - - x} - onOpenChange={(open) => setStore("fileSelectOpen", open)} - onSelect={(x) => (x ? local.session.open(x) : undefined)} - > - {(i) => ( -
-
- -
- - {getDirectory(i)} - - {getFilename(i)} -
-
-
-
- )} -
-
- - ) -} diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx new file mode 100644 index 000000000..afec9ee3c --- /dev/null +++ b/packages/desktop/src/pages/layout.tsx @@ -0,0 +1,75 @@ +import { Button, Tooltip, DiffChanges } from "@opencode-ai/ui" +import { createMemo, ParentProps } from "solid-js" +import { getFilename } from "@/utils" +import { DateTime } from "luxon" +import { useSync } from "@/context/sync" +import { VList } from "virtua/solid" +import { A, useParams } from "@solidjs/router" + +export default function Layout(props: ParentProps) { + const params = useParams() + const sync = useSync() + return ( +
+ +
+
+
+ {getFilename(sync.data.path.directory)} +
+ +
+
{props.children}
+
+
+ ) +} diff --git a/packages/desktop/src/pages/session-layout.tsx b/packages/desktop/src/pages/session-layout.tsx new file mode 100644 index 000000000..9a24608f0 --- /dev/null +++ b/packages/desktop/src/pages/session-layout.tsx @@ -0,0 +1,12 @@ +import { Show, type ParentProps } from "solid-js" +import { SessionProvider } from "@/context/session" +import { useParams } from "@solidjs/router" + +export default function Layout(props: ParentProps) { + const params = useParams() + return ( + + {props.children} + + ) +} diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx new file mode 100644 index 000000000..9c633f4f7 --- /dev/null +++ b/packages/desktop/src/pages/session.tsx @@ -0,0 +1,693 @@ +import { + SelectDialog, + IconButton, + Tabs, + Icon, + Accordion, + Diff, + Collapsible, + DiffChanges, + Message, + Typewriter, + Card, + Code, + Tooltip, + ProgressCircle, +} from "@opencode-ai/ui" +import { FileIcon } from "@/ui" +import { MessageProgress } from "@/components/message-progress" +import { + For, + onCleanup, + onMount, + Show, + Match, + Switch, + createSignal, + createEffect, + createMemo, + createResource, +} from "solid-js" +import { useLocal, type LocalFile } from "@/context/local" +import { createStore } from "solid-js/store" +import { getDirectory, getFilename } from "@/utils" +import { PromptInput } from "@/components/prompt-input" +import { DateTime } from "luxon" +import { + DragDropProvider, + DragDropSensors, + DragOverlay, + SortableProvider, + closestCenter, + createSortable, + useDragDropContext, +} from "@thisbeyond/solid-dnd" +import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd" +import type { JSX } from "solid-js" +import { useSync } from "@/context/sync" +import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk" +import { Markdown } from "@opencode-ai/ui" +import { Spinner } from "@/components/spinner" +import { useSession } from "@/context/session" + +export default function Page() { + const local = useLocal() + const sync = useSync() + const session = useSession() + const [store, setStore] = createStore({ + clickTimer: undefined as number | undefined, + fileSelectOpen: false, + activeDraggable: undefined as string | undefined, + }) + let inputRef!: HTMLDivElement + let messageScrollElement!: HTMLDivElement + + const MOD = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) ? "Meta" : "Control" + + onMount(() => { + document.addEventListener("keydown", handleKeyDown) + }) + + onCleanup(() => { + document.removeEventListener("keydown", handleKeyDown) + }) + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.getModifierState(MOD) && event.shiftKey && event.key.toLowerCase() === "p") { + event.preventDefault() + return + } + if (event.getModifierState(MOD) && event.key.toLowerCase() === "p") { + event.preventDefault() + setStore("fileSelectOpen", true) + return + } + + const focused = document.activeElement === inputRef + if (focused) { + if (event.key === "Escape") { + inputRef?.blur() + } + return + } + + // if (local.file.active()) { + // const active = local.file.active()! + // if (event.key === "Enter" && active.selection) { + // local.context.add({ + // type: "file", + // path: active.path, + // selection: { ...active.selection }, + // }) + // return + // } + // + // if (event.getModifierState(MOD)) { + // if (event.key.toLowerCase() === "a") { + // return + // } + // if (event.key.toLowerCase() === "c") { + // return + // } + // } + // } + + if (event.key.length === 1 && event.key !== "Unidentified" && !(event.ctrlKey || event.metaKey)) { + inputRef?.focus() + } + } + + const resetClickTimer = () => { + if (!store.clickTimer) return + clearTimeout(store.clickTimer) + setStore("clickTimer", undefined) + } + + const startClickTimer = () => { + const newClickTimer = setTimeout(() => { + setStore("clickTimer", undefined) + }, 300) + setStore("clickTimer", newClickTimer as unknown as number) + } + + const handleTabClick = async (tab: string) => { + if (store.clickTimer) { + resetClickTimer() + // local.file.update(file.path, { ...file, pinned: true }) + } else { + if (tab.startsWith("file://")) { + local.file.open(tab.replace("file://", "")) + } + startClickTimer() + } + } + + const handleDragStart = (event: unknown) => { + const id = getDraggableId(event) + if (!id) return + setStore("activeDraggable", id) + } + + const handleDragOver = (event: DragEvent) => { + const { draggable, droppable } = event + if (draggable && droppable) { + const currentTabs = session.layout.tabs.opened + const fromIndex = currentTabs?.indexOf(draggable.id.toString()) + const toIndex = currentTabs?.indexOf(droppable.id.toString()) + if (fromIndex !== toIndex && toIndex !== undefined) { + session.layout.moveTab(draggable.id.toString(), toIndex) + } + } + } + + const handleDragEnd = () => { + setStore("activeDraggable", undefined) + } + + const FileVisual = (props: { file: LocalFile }): JSX.Element => { + return ( +
+ + + {props.file.name} + + +
+ ) + } + + const SortableTab = (props: { + tab: string + onTabClick: (tab: string) => void + onTabClose: (tab: string) => void + }): JSX.Element => { + const sortable = createSortable(props.tab) + + const [file] = createResource( + () => props.tab, + async (tab) => { + if (tab.startsWith("file://")) { + return local.file.node(tab.replace("file://", "")) + } + return undefined + }, + ) + + return ( + // @ts-ignore +
+
+ props.onTabClick(props.tab)}> + + {(f) => } + + props.onTabClose(props.tab)} + /> + +
+
+ ) + } + + const ConstrainDragYAxis = (): JSX.Element => { + const context = useDragDropContext() + if (!context) return <> + const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context + const transformer: Transformer = { + id: "constrain-y-axis", + order: 100, + callback: (transform) => ({ ...transform, y: 0 }), + } + onDragStart((event) => { + const id = getDraggableId(event) + if (!id) return + addTransformer("draggables", id, transformer) + }) + onDragEnd((event) => { + const id = getDraggableId(event) + if (!id) return + removeTransformer("draggables", id, transformer.id) + }) + return <> + } + + const getDraggableId = (event: unknown): string | undefined => { + if (typeof event !== "object" || event === null) return undefined + if (!("draggable" in event)) return undefined + const draggable = (event as { draggable?: { id?: unknown } }).draggable + if (!draggable) return undefined + return typeof draggable.id === "string" ? draggable.id : undefined + } + + return ( +
+ + + + +
+ + +
Chat
+ + +
{session.usage.context() ?? 0}%
+
+
+ {/* Review */} + + + {(tab) => } + + +
+ setStore("fileSelectOpen", true)} + /> +
+
+
+ +
+ +
New session
+
+ +
+ {getDirectory(sync.data.path.directory)} + {getFilename(sync.data.path.directory)} +
+
+
+ +
+ Last modified  + + {DateTime.fromMillis(sync.data.project.time.created).toRelative()} + +
+
+
+ } + > + {(_) => { + return ( +
+
+ 1}> + + +
+ + {(message) => { + const isActive = createMemo(() => session.messages.active()?.id === message.id) + const [titled, setTitled] = createSignal(!!message.summary?.title) + const assistantMessages = createMemo(() => { + if (!session.id) return [] + return sync.data.message[session.id]?.filter( + (m) => m.role === "assistant" && m.parentID == message.id, + ) as AssistantMessageType[] + }) + const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) + const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error()) + const [detailsExpanded, setDetailsExpanded] = createSignal(false) + const parts = createMemo(() => sync.data.part[message.id]) + const hasToolPart = createMemo(() => + assistantMessages() + ?.flatMap((m) => sync.data.part[m.id]) + .some((p) => p?.type === "tool"), + ) + const working = createMemo(() => !message.summary?.body && !error()) + + // allowing time for the animations to finish + createEffect(() => { + const title = message.summary?.title + setTimeout(() => setTitled(!!title), 10_000) + }) + createEffect(() => { + const summary = message.summary?.body + const complete = !!summary || !!error() + setTimeout(() => setCompleted(complete), 1200) + }) + + return ( + +
+ {/* Title */} +
+
+ + } + > +

+ {message.summary?.title} +

+
+
+
+
+ +
+ {/* Summary */} + +
+
+

+ + Summary + Response + +

+ + {(summary) => ( + *]:fade-up-text": !message.summary?.diffs?.length, + }} + text={summary()} + /> + )} + +
+ + + {(diff) => ( + + + +
+
+ +
+ + + {getDirectory(diff.file)}‎ + + + + {getFilename(diff.file)} + +
+
+
+ + +
+
+
+
+ + + +
+ )} +
+
+
+
+ + + {error()?.data?.message as string} + + + {/* Response */} +
+ + + + + + + +
+
+ + Hide details + Show details + +
+ +
+
+ +
+ + {(assistantMessage) => { + const parts = createMemo(() => sync.data.part[assistantMessage.id]) + return + }} + + + + {error()?.data?.message as string} + + +
+
+
+
+
+
+
+
+ ) + }} +
+
+
+
+ ) + }} + +
+ + {/* */} + + {(tab) => { + const [file] = createResource( + () => tab, + async (tab) => { + if (tab.startsWith("file://")) { + return local.file.node(tab.replace("file://", "")) + } + return undefined + }, + ) + return ( + + + + {(f) => ( + + )} + + + + ) + }} + + + + + {(draggedFile) => { + const [file] = createResource( + () => draggedFile(), + async (tab) => { + if (tab.startsWith("file://")) { + return local.file.node(tab.replace("file://", "")) + } + return undefined + }, + ) + return ( +
+ {(f) => } +
+ ) + }} +
+
+ +
+ { + inputRef = el + }} + /> +
+ + }> +
    + + {(path) => ( +
  • + +
  • + )} +
    +
+ + + + x} + onOpenChange={(open) => setStore("fileSelectOpen", open)} + onSelect={(x) => (x ? session.layout.openTab("file://" + x) : undefined)} + > + {(i) => ( +
+
+ +
+ + {getDirectory(i)} + + {getFilename(i)} +
+
+
+
+ )} +
+
+ + ) +} -- cgit v1.2.3 From c59ec71918ecf2796a12e2eefdf09176f536c0a2 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:00:17 -0600 Subject: fix(desktop): max height on message diffs, session stats --- packages/desktop/src/pages/layout.tsx | 8 +++----- packages/desktop/src/pages/session.tsx | 6 +++--- packages/ui/src/components/diff-changes.tsx | 18 ++++++++++-------- packages/ui/src/components/message-part.tsx | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index afec9ee3c..22f0a50de 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -1,5 +1,5 @@ import { Button, Tooltip, DiffChanges } from "@opencode-ai/ui" -import { createMemo, ParentProps } from "solid-js" +import { createMemo, ParentProps, Show } from "solid-js" import { getFilename } from "@/utils" import { DateTime } from "luxon" import { useSync } from "@/context/sync" @@ -25,8 +25,6 @@ export default function Layout(props: ParentProps) { {(session) => { - const diffs = createMemo(() => session.summary?.diffs ?? []) - const filesChanged = createMemo(() => diffs().length) const updated = createMemo(() => DateTime.fromMillis(session.time.updated)) return (
- {`${filesChanged() || "No"} file${filesChanged() !== 1 ? "s" : ""} changed`} - + {`${session.summary?.files || "No"} file${session.summary?.files !== 1 ? "s" : ""} changed`} + {(summary) => }
diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 9c633f4f7..36eed718a 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -362,7 +362,7 @@ export default function Page() { - +
- +
- + props.variant ?? "default" const additions = createMemo(() => - Array.isArray(props.diff) - ? props.diff.reduce((acc, diff) => acc + (diff.additions ?? 0), 0) - : props.diff.additions, + Array.isArray(props.changes) + ? props.changes.reduce((acc, diff) => acc + (diff.additions ?? 0), 0) + : props.changes.additions, ) const deletions = createMemo(() => - Array.isArray(props.diff) - ? props.diff.reduce((acc, diff) => acc + (diff.deletions ?? 0), 0) - : props.diff.deletions, + Array.isArray(props.changes) + ? props.changes.reduce((acc, diff) => acc + (diff.deletions ?? 0), 0) + : props.changes.deletions, ) const total = createMemo(() => (additions() ?? 0) + (deletions() ?? 0)) diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 01a58025a..38870b5a3 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -364,7 +364,7 @@ ToolRegistry.register({
- +
-- cgit v1.2.3 From e006e3355cff3de25e023edcee0b59985e7db66b Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:32:05 -0600 Subject: feat(desktop): incrementally load sessions in side nav --- packages/desktop/src/context/sync.tsx | 22 +++++--- packages/desktop/src/pages/layout.tsx | 95 ++++++++++++++++++++--------------- 2 files changed, 70 insertions(+), 47 deletions(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/context/sync.tsx b/packages/desktop/src/context/sync.tsx index c60206b0b..1e960397b 100644 --- a/packages/desktop/src/context/sync.tsx +++ b/packages/desktop/src/context/sync.tsx @@ -16,6 +16,8 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ config: Config path: Path session: Session[] + limit: number + more: boolean message: { [sessionID: string]: Message[] } @@ -32,6 +34,8 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ agent: [], provider: [], session: [], + limit: 10, + more: false, message: {}, part: {}, node: [], @@ -106,12 +110,14 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ path: () => sdk.client.path.get().then((x) => setStore("path", x.data!)), agent: () => sdk.client.app.agents().then((x) => setStore("agent", x.data ?? [])), session: () => - sdk.client.session.list().then((x) => - setStore( - "session", - (x.data ?? []).slice().sort((a, b) => a.id.localeCompare(b.id)), - ), - ), + sdk.client.session.list().then((x) => { + const sessions = (x.data ?? []) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)) + .slice(0, store.limit) + setStore("session", sessions) + setStore("more", sessions.length === store.limit) + }), config: () => sdk.client.config.get().then((x) => setStore("config", x.data!)), changes: () => sdk.client.file.status().then((x) => setStore("changes", x.data!)), node: () => sdk.client.file.list({ query: { path: "/" } }).then((x) => setStore("node", x.data!)), @@ -184,6 +190,10 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ }), ) }, + fetch: async (count = 10) => { + setStore("limit", (x) => x + count) + await load.session() + }, }, load, absolute, diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 22f0a50de..1d9669604 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -1,5 +1,5 @@ import { Button, Tooltip, DiffChanges } from "@opencode-ai/ui" -import { createMemo, ParentProps, Show } from "solid-js" +import { createMemo, For, ParentProps, Show } from "solid-js" import { getFilename } from "@/utils" import { DateTime } from "luxon" import { useSync } from "@/context/sync" @@ -9,61 +9,74 @@ import { A, useParams } from "@solidjs/router" export default function Layout(props: ParentProps) { const params = useParams() const sync = useSync() + return (
-
+
{getFilename(sync.data.path.directory)}
-
+
- - {(session) => { - const updated = createMemo(() => DateTime.fromMillis(session.time.updated)) - return ( - - -
+
+ + + ) + }} + + + + + +
{props.children}
-- cgit v1.2.3 From 146bae82cb584c253a42ed4565d423d9cded93a6 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 6 Nov 2025 06:24:39 -0600 Subject: fix(desktop): button styles --- packages/desktop/src/pages/layout.tsx | 9 +++------ packages/ui/src/components/button.css | 8 +++----- 2 files changed, 6 insertions(+), 11 deletions(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 1d9669604..85f55e8bd 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -3,7 +3,6 @@ import { createMemo, For, ParentProps, Show } from "solid-js" import { getFilename } from "@/utils" import { DateTime } from "luxon" import { useSync } from "@/context/sync" -import { VList } from "virtua/solid" import { A, useParams } from "@solidjs/router" export default function Layout(props: ParentProps) { @@ -19,11 +18,9 @@ export default function Layout(props: ParentProps) { {getFilename(sync.data.path.directory)}
- - - +
diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx index cef6c5555..9dacc7100 100644 --- a/packages/desktop/src/context/local.tsx +++ b/packages/desktop/src/context/local.tsx @@ -5,6 +5,7 @@ import type { FileContent, FileNode, Model, Provider, File as FileStatus } from import { createSimpleContext } from "./helper" import { useSDK } from "./sdk" import { useSync } from "./sync" +import { makePersisted } from "@solid-primitives/storage" export type LocalFile = FileNode & Partial<{ @@ -456,11 +457,45 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ } })() + const layout = (() => { + const [store, setStore] = makePersisted( + createStore({ + sidebar: { + opened: true, + width: 240, + }, + }), + { + name: "layout", + }, + ) + + return { + sidebar: { + opened: createMemo(() => store.sidebar.opened), + open() { + setStore("sidebar", "opened", true) + }, + close() { + setStore("sidebar", "opened", false) + }, + toggle() { + setStore("sidebar", "opened", (x) => !x) + }, + width: createMemo(() => store.sidebar.width), + resize(width: number) { + setStore("sidebar", "width", width) + }, + }, + } + })() + const result = { model, agent, file, context, + layout, } return result }, diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 85f55e8bd..e1560accb 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -1,27 +1,42 @@ -import { Button, Tooltip, DiffChanges } from "@opencode-ai/ui" +import { Button, Tooltip, DiffChanges, IconButton } from "@opencode-ai/ui" import { createMemo, For, ParentProps, Show } from "solid-js" -import { getFilename } from "@/utils" import { DateTime } from "luxon" import { useSync } from "@/context/sync" import { A, useParams } from "@solidjs/router" +import { useLocal } from "@/context/local" export default function Layout(props: ParentProps) { const params = useParams() const sync = useSync() + const local = useLocal() return (
-
-
- {getFilename(sync.data.path.directory)} -
-
- -
+
+
+
+ + + +
+
+ + + + +
+ +
+ + + + +
{props.children}
diff --git a/packages/ui/src/components/button.css b/packages/ui/src/components/button.css index f5a08067a..f76d7465b 100644 --- a/packages/ui/src/components/button.css +++ b/packages/ui/src/components/button.css @@ -7,6 +7,7 @@ border-radius: 6px; text-decoration: none; user-select: none; + cursor: default; outline: none; &[data-variant="primary"] { @@ -93,11 +94,12 @@ gap: 8px; + /* text-12-medium */ font-family: var(--font-family-sans); - font-size: var(--font-size-base); + font-size: var(--font-size-small); font-style: normal; font-weight: var(--font-weight-medium); - line-height: var(--line-height-large); /* 171.429% */ + line-height: var(--line-height-large); /* 166.667% */ letter-spacing: var(--letter-spacing-normal); } diff --git a/packages/ui/src/components/icon-button.css b/packages/ui/src/components/icon-button.css index 6fe95fccf..a491074fe 100644 --- a/packages/ui/src/components/icon-button.css +++ b/packages/ui/src/components/icon-button.css @@ -2,20 +2,11 @@ display: inline-flex; align-items: center; justify-content: center; - border-radius: 100%; + border-radius: 6px; text-decoration: none; user-select: none; aspect-ratio: 1; - - &:disabled { - background-color: var(--icon-strong-disabled); - color: var(--icon-invert-base); - cursor: not-allowed; - } - - &:focus { - outline: none; - } + flex-shrink: 0; &[data-variant="primary"] { background-color: var(--icon-strong-base); @@ -51,45 +42,62 @@ } &[data-variant="secondary"] { + border: transparent; background-color: var(--button-secondary-base); color: var(--text-strong); + box-shadow: var(--shadow-xs-border); &:hover:not(:disabled) { - background-color: var(--surface-hover); + background-color: var(--button-secondary-hover); } &:active:not(:disabled) { - background-color: var(--surface-active); + background-color: var(--button-secondary-base); } &:focus:not(:disabled) { - background-color: var(--surface-focus); + background-color: var(--button-secondary-base); + } + &:focus-visible:not(:active) { + background-color: var(--button-secondary-base); + box-shadow: var(--shadow-xs-border-focus); + } + &:focus-visible:active { + box-shadow: none; + } + + [data-slot="icon"] { + color: var(--icon-strong-base); } } &[data-variant="ghost"] { background-color: transparent; + /* color: var(--icon-base); */ [data-slot="icon"] { - color: var(--icon-weak-base); + color: var(--icon-base); + } - &:hover:not(:disabled) { - color: var(--icon-weak-hover); + &:hover:not(:disabled) { + background-color: var(--surface-base-hover); + + [data-slot="icon"] { + color: var(--icon-hover); } - &:active:not(:disabled) { - color: var(--icon-string-active); + } + &:active:not(:disabled) { + [data-slot="icon"] { + color: var(--icon-active); } } - - /* color: var(--text-strong); */ - /**/ - /* &:hover:not(:disabled) { */ - /* background-color: var(--surface-hover); */ - /* } */ - /* &:active:not(:disabled) { */ - /* background-color: var(--surface-active); */ - /* } */ - /* &:focus:not(:disabled) { */ - /* background-color: var(--surface-focus); */ - /* } */ + &:selected:not(:disabled) { + background-color: var(--surface-base-active); + [data-slot="icon"] { + color: var(--icon-selected); + } + } + &:focus:not(:disabled) { + background-color: var(--surface-focus); + } } &[data-size="normal"] { @@ -103,9 +111,14 @@ &[data-size="large"] { height: 32px; - padding: 0 8px 0 6px; + /* padding: 0 8px 0 6px; */ gap: 8px; + [data-slot="icon"] { + height: 16px; + width: 16px; + } + /* text-12-medium */ font-family: var(--font-family-sans); font-size: var(--font-size-small); @@ -114,4 +127,14 @@ line-height: var(--line-height-large); /* 166.667% */ letter-spacing: var(--letter-spacing-normal); } + + &:disabled { + background-color: var(--icon-strong-disabled); + color: var(--icon-invert-base); + cursor: not-allowed; + } + + &:focus { + outline: none; + } } diff --git a/packages/ui/src/components/icon-button.tsx b/packages/ui/src/components/icon-button.tsx index abc82609b..fccdebd04 100644 --- a/packages/ui/src/components/icon-button.tsx +++ b/packages/ui/src/components/icon-button.tsx @@ -2,7 +2,7 @@ import { Button as Kobalte } from "@kobalte/core/button" import { type ComponentProps, splitProps } from "solid-js" import { Icon, IconProps } from "./icon" -export interface IconButtonProps { +export interface IconButtonProps extends ComponentProps { icon: IconProps["name"] size?: "normal" | "large" iconSize?: IconProps["size"] @@ -22,7 +22,11 @@ export function IconButton(props: ComponentProps<"button"> & IconButtonProps) { [split.class ?? ""]: !!split.class, }} > - + ) } diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 2e96b9d85..082bbea90 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -152,6 +152,8 @@ const newIcons = { "circle-ban-sign": ``, stop: ``, enter: ``, + "layout-left": ``, + "speech-bubble": ``, } export interface IconProps extends ComponentProps<"svg"> { diff --git a/packages/ui/src/components/tabs.css b/packages/ui/src/components/tabs.css index 1d786fb4a..67f289283 100644 --- a/packages/ui/src/components/tabs.css +++ b/packages/ui/src/components/tabs.css @@ -7,7 +7,7 @@ overflow: clip; [data-slot="list"] { - height: 40px; + height: 48px; width: 100%; position: relative; display: flex; @@ -39,7 +39,7 @@ [data-slot="trigger"] { position: relative; height: 100%; - padding: 8px 24px; + padding: 14px 24px; display: flex; align-items: center; color: var(--text-base); diff --git a/packages/web/astro.config.mjs b/packages/web/astro.config.mjs index 24987ca35..d67bebe0a 100644 --- a/packages/web/astro.config.mjs +++ b/packages/web/astro.config.mjs @@ -110,6 +110,7 @@ export default defineConfig({ ], redirects: { "/discord": "https://discord.gg/opencode", + "/desktop-feedback": "https://discord.gg/h5TNnkFVNy", }, }) -- cgit v1.2.3 From 492bf51a0dfa4fd278337b6e75da807048d44ff1 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 6 Nov 2025 09:56:46 -0600 Subject: fix(desktop): sidebar collapsed width --- packages/desktop/src/pages/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index e1560accb..c5957a2d2 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -16,7 +16,7 @@ export default function Layout(props: ParentProps) {
Date: Thu, 6 Nov 2025 15:13:02 -0600 Subject: feat(desktop): review flow --- packages/desktop/src/components/prompt-input.tsx | 1 + packages/desktop/src/context/local.tsx | 17 +- packages/desktop/src/context/session.tsx | 8 +- packages/desktop/src/context/sync.tsx | 59 +++-- packages/desktop/src/pages/layout.tsx | 4 +- packages/desktop/src/pages/session.tsx | 299 +++++++++++++++++++---- packages/ui/src/components/accordion.tsx | 11 +- packages/ui/src/components/button.css | 5 +- packages/ui/src/components/diff-changes.tsx | 7 +- packages/ui/src/components/icon.tsx | 3 + packages/ui/src/components/tooltip.tsx | 2 +- 11 files changed, 340 insertions(+), 76 deletions(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 74443d6a5..15bc54c49 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -338,6 +338,7 @@ export const PromptInput: Component = (props) => { // session.layout.copyTabs("", session.id) } session.layout.setActiveTab(undefined) + session.messages.setActive(undefined) const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) const attachments = session.prompt.current().filter((part) => part.type === "file") diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx index 9dacc7100..1785bdf0c 100644 --- a/packages/desktop/src/context/local.tsx +++ b/packages/desktop/src/context/local.tsx @@ -464,9 +464,12 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ opened: true, width: 240, }, + review: { + state: "closed" as "open" | "closed" | "tab", + }, }), { - name: "layout", + name: "default-layout", }, ) @@ -487,6 +490,18 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ setStore("sidebar", "width", width) }, }, + review: { + state: createMemo(() => store.review?.state ?? "closed"), + open() { + setStore("review", "state", "open") + }, + close() { + setStore("review", "state", "closed") + }, + tab() { + setStore("review", "state", "tab") + }, + }, } })() diff --git a/packages/desktop/src/context/session.tsx b/packages/desktop/src/context/session.tsx index 77ab3bc25..61fed945e 100644 --- a/packages/desktop/src/context/session.tsx +++ b/packages/desktop/src/context/session.tsx @@ -80,6 +80,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex const model = createMemo(() => last() ? sync.data.provider.find((x) => x.id === last().providerID)?.models[last().modelID] : undefined, ) + const diffs = createMemo(() => (props.sessionId ? (sync.data.session_diff[props.sessionId] ?? []) : [])) const tokens = createMemo(() => { if (!last()) return @@ -98,6 +99,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex id: props.sessionId, info, working, + diffs, prompt: { current: createMemo(() => store.prompt), cursor: createMemo(() => store.cursorPosition), @@ -139,8 +141,10 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex if (tab.startsWith("file://")) { await local.file.open(tab.replace("file://", "")) } - if (!store.tabs.opened.includes(tab)) { - setStore("tabs", "opened", [...store.tabs.opened, tab]) + if (tab !== "review") { + if (!store.tabs.opened.includes(tab)) { + setStore("tabs", "opened", [...store.tabs.opened, tab]) + } } setStore("tabs", "active", tab) }, diff --git a/packages/desktop/src/context/sync.tsx b/packages/desktop/src/context/sync.tsx index 1e960397b..c5b169a38 100644 --- a/packages/desktop/src/context/sync.tsx +++ b/packages/desktop/src/context/sync.tsx @@ -1,4 +1,17 @@ -import type { Message, Agent, Provider, Session, Part, Config, Path, File, FileNode, Project } from "@opencode-ai/sdk" +import type { + Message, + Agent, + Provider, + Session, + Part, + Config, + Path, + File, + FileNode, + Project, + FileDiff, + Todo, +} from "@opencode-ai/sdk" import { createStore, produce, reconcile } from "solid-js/store" import { createMemo } from "solid-js" import { Binary } from "@/utils/binary" @@ -16,8 +29,13 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ config: Config path: Path session: Session[] + session_diff: { + [sessionID: string]: FileDiff[] + } + todo: { + [sessionID: string]: Todo[] + } limit: number - more: boolean message: { [sessionID: string]: Message[] } @@ -34,8 +52,9 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ agent: [], provider: [], session: [], + session_diff: {}, + todo: {}, limit: 10, - more: false, message: {}, part: {}, node: [], @@ -60,6 +79,12 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ ) break } + case "session.diff": + setStore("session_diff", event.properties.sessionID, event.properties.diff) + break + case "todo.updated": + setStore("todo", event.properties.sessionID, event.properties.todos) + break case "message.updated": { const messages = store.message[event.properties.info.sessionID] if (!messages) { @@ -116,7 +141,6 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ .sort((a, b) => a.id.localeCompare(b.id)) .slice(0, store.limit) setStore("session", sessions) - setStore("more", sessions.length === store.limit) }), config: () => sdk.client.config.get().then((x) => setStore("config", x.data!)), changes: () => sdk.client.file.status().then((x) => setStore("changes", x.data!)), @@ -161,22 +185,19 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ if (match.found) return store.session[match.index] return undefined }, - async sync(sessionID: string, isRetry = false) { - const [session, messages] = await Promise.all([ - sdk.client.session.get({ path: { id: sessionID } }), + async sync(sessionID: string, _isRetry = false) { + const [session, messages, todo, diff] = await Promise.all([ + sdk.client.session.get({ path: { id: sessionID }, throwOnError: true }), sdk.client.session.messages({ path: { id: sessionID } }), + sdk.client.session.todo({ path: { id: sessionID } }), + sdk.client.session.diff({ path: { id: sessionID } }), ]) - - // If no messages and this might be a new session, retry after a delay - if (!isRetry && messages.data!.length === 0) { - setTimeout(() => this.sync(sessionID, true), 500) - return - } - setStore( produce((draft) => { const match = Binary.search(draft.session, sessionID, (s) => s.id) - draft.session[match.index] = session.data! + if (match.found) draft.session[match.index] = session.data! + if (!match.found) draft.session.splice(match.index, 0, session.data!) + draft.todo[sessionID] = todo.data ?? [] draft.message[sessionID] = messages .data!.map((x) => x.info) .slice() @@ -187,13 +208,21 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ .map(sanitizePart) .sort((a, b) => a.id.localeCompare(b.id)) } + draft.session_diff[sessionID] = diff.data ?? [] }), ) + + // If no messages and this might be a new session, retry after a delay + // if (!isRetry && messages.data!.length === 0) { + // setTimeout(() => this.sync(sessionID, true), 500) + // return + // } }, fetch: async (count = 10) => { setStore("limit", (x) => x + count) await load.session() }, + more: createMemo(() => store.session.length === store.limit), }, load, absolute, diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index c5957a2d2..d88564007 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -80,7 +80,7 @@ export default function Layout(props: ParentProps) { }} - +
-
- -
New session
-
- -
- {getDirectory(sync.data.path.directory)} - {getFilename(sync.data.path.directory)} -
+ +
New session
+
+ +
+ {getDirectory(sync.data.path.directory)} + {getFilename(sync.data.path.directory)}
-
- -
- Last modified  - - {DateTime.fromMillis(sync.data.project.time.created).toRelative()} - -
+
+
+ +
+ Last modified  + + {DateTime.fromMillis(sync.data.project.time.created).toRelative()} +
- } - > - {(_) => { - return ( -
-
+
+ } + > + {(_) => { + return ( +
+
+
+ + + +
+
1}>
+ } + > + +
+ ) + }} + - {/* */} + + +
+
+
+
+
All changes
+
+ + + {(diff) => ( + + + +
+
+ +
+ + {getDirectory(diff.file)}‎ + + {getFilename(diff.file)} +
+
+
+ + +
+
+
+
+ + + +
+ )} +
+
+
+
+
+
{(tab) => { const [file] = createResource( diff --git a/packages/ui/src/components/accordion.tsx b/packages/ui/src/components/accordion.tsx index 535d38e3d..02f00b7be 100644 --- a/packages/ui/src/components/accordion.tsx +++ b/packages/ui/src/components/accordion.tsx @@ -1,9 +1,11 @@ import { Accordion as Kobalte } from "@kobalte/core/accordion" -import { splitProps } from "solid-js" +import { createSignal, splitProps } from "solid-js" import type { ComponentProps, ParentProps } from "solid-js" export interface AccordionProps extends ComponentProps {} -export interface AccordionItemProps extends ComponentProps {} +export interface AccordionItemProps extends ComponentProps { + defaultOpen?: boolean +} export interface AccordionHeaderProps extends ComponentProps {} export interface AccordionTriggerProps extends ComponentProps {} export interface AccordionContentProps extends ComponentProps {} @@ -23,11 +25,14 @@ function AccordionRoot(props: AccordionProps) { } function AccordionItem(props: AccordionItemProps) { - const [split, rest] = splitProps(props, ["class", "classList"]) + const [split, rest] = splitProps(props, ["class", "classList", "defaultOpen"]) + const [open, setOpen] = createSignal(split.defaultOpen ?? false) return ( 0 : true}> -
+
diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 082bbea90..b61a54fe1 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -153,7 +153,10 @@ const newIcons = { stop: ``, enter: ``, "layout-left": ``, + "layout-right": ``, "speech-bubble": ``, + "align-right": ``, + expand: ``, } export interface IconProps extends ComponentProps<"svg"> { diff --git a/packages/ui/src/components/tooltip.tsx b/packages/ui/src/components/tooltip.tsx index c3d1947d3..e3784ed8e 100644 --- a/packages/ui/src/components/tooltip.tsx +++ b/packages/ui/src/components/tooltip.tsx @@ -29,7 +29,7 @@ export function Tooltip(props: TooltipProps) { }) return ( - + {c()} -- cgit v1.2.3 From 957c43aa09a2ceea0a9544fde4d0e2d21d91863f Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:34:47 -0600 Subject: fix(desktop): review tab padding --- packages/desktop/src/pages/session.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 9f72191bc..22f9c47f5 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -728,7 +728,7 @@ export default function Page() { "relative px-6 py-2 w-full flex flex-col gap-6 flex-1 min-h-0": true, }} > -
+
All changes
-- cgit v1.2.3 From e5804f64f96a3b2fbcbb4dd9ad10c6ca40a6e083 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 06:26:26 -0600 Subject: fix(desktop): layout quirks --- packages/desktop/src/pages/session.tsx | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 22f9c47f5..30b8eab91 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -358,12 +358,12 @@ export default function Page() { return (
-
+
@@ -382,7 +382,7 @@ export default function Page() { role="list" classList={{ "mr-8 shrink-0 flex flex-col items-start": true, - "absolute right-full w-60 @7xl:gap-2": local.layout.review.state() !== "open", + "absolute right-full w-60 @7xl:gap-2": true, // local.layout.review.state() !== "open", "": local.layout.review.state() === "open", }} > @@ -498,7 +498,7 @@ export default function Page() {
{/* Title */}
@@ -645,6 +645,14 @@ export default function Page() { }}
+ +
+ { + inputRef = el + }} + /> +
@@ -826,13 +834,6 @@ export default function Page() { -
- { - inputRef = el - }} - /> -
-- cgit v1.2.3 From 3a1d1a6284b66aaf385c3c97bb842a8e1d8985cb Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 12:48:12 -0600 Subject: feat(desktop): custom syntax colors --- packages/desktop/src/context/sync.tsx | 8 +- packages/desktop/src/pages/session.tsx | 3 +- packages/ui/src/components/code.tsx | 3 +- packages/ui/src/components/diff.tsx | 3937 +++------------------------- packages/ui/src/styles/tailwind/colors.css | 5 + packages/ui/src/styles/theme.css | 59 +- theme-test.java | 461 ++++ theme-test.md | 669 +++++ theme-test.tsx | 68 + 9 files changed, 1622 insertions(+), 3591 deletions(-) create mode 100644 theme-test.java create mode 100644 theme-test.md (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/context/sync.tsx b/packages/desktop/src/context/sync.tsx index c5b169a38..bc9491fd3 100644 --- a/packages/desktop/src/context/sync.tsx +++ b/packages/desktop/src/context/sync.tsx @@ -188,7 +188,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ async sync(sessionID: string, _isRetry = false) { const [session, messages, todo, diff] = await Promise.all([ sdk.client.session.get({ path: { id: sessionID }, throwOnError: true }), - sdk.client.session.messages({ path: { id: sessionID } }), + sdk.client.session.messages({ path: { id: sessionID }, query: { limit: 100 } }), sdk.client.session.todo({ path: { id: sessionID } }), sdk.client.session.diff({ path: { id: sessionID } }), ]) @@ -211,12 +211,6 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ draft.session_diff[sessionID] = diff.data ?? [] }), ) - - // If no messages and this might be a new session, retry after a delay - // if (!isRetry && messages.data!.length === 0) { - // setTimeout(() => this.sync(sessionID, true), 500) - // return - // } }, fetch: async (count = 10) => { setStore("limit", (x) => x + count) diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 30b8eab91..3dcc24e61 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -736,7 +736,7 @@ export default function Page() { "relative px-6 py-2 w-full flex flex-col gap-6 flex-1 min-h-0": true, }} > -
+
All changes
@@ -766,6 +766,7 @@ export default function Page() { (props: CodeProps) { createEffect(() => { const instance = new File({ - theme: { dark: "oc-1-dark", light: "oc-1-light" }, // or any Shiki theme + theme: { dark: "oc-1-dark", light: "oc-1-light" }, + // theme: { dark: "pierre-dark", light: "pierre-light" }, overflow: "wrap", // or 'scroll' themeType: "system", // 'system', 'light', or 'dark' disableFileHeader: true, diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx index 6297a6422..09085b44c 100644 --- a/packages/ui/src/components/diff.tsx +++ b/packages/ui/src/components/diff.tsx @@ -57,6 +57,7 @@ export function Diff(props: DiffProps) { const instance = new FileDiff({ // theme: "pierre-light", theme: { dark: "oc-1-dark", light: "oc-1-light" }, + // theme: { dark: "pierre-dark", light: "pierre-light" }, // When using the 'themes' prop, 'themeType' allows you to force 'dark' // or 'light' theme, or inherit from the OS ('system') theme. themeType: "system", @@ -180,1788 +181,385 @@ export function Diff(props: DiffProps) { ) } -registerCustomTheme("oc-1-light", () => { - return Promise.resolve({ - name: "oc-1-light", - type: "light", - colors: { - "editor.background": "transparent", - "editor.foreground": "#070707", - foreground: "#070707", - focusBorder: "#008cff", - "selection.background": "#dfe7ff", - "editor.selectionBackground": "#008cff2e", - "editor.lineHighlightBackground": "#dfe7ff8c", - "editorCursor.foreground": "#008cff", - "editorLineNumber.foreground": "#84848A", - "editorLineNumber.activeForeground": "#6C6C71", - "editorIndentGuide.background": "#eeeeef", - "editorIndentGuide.activeBackground": "#dbdbdd", - "diffEditor.insertedTextBackground": "#00cab133", - "diffEditor.deletedTextBackground": "#ff2e3f33", - "sideBar.background": "#f8f8f8", - "sideBar.foreground": "#6C6C71", - "sideBar.border": "#eeeeef", - "sideBarTitle.foreground": "#070707", - "sideBarSectionHeader.background": "#f8f8f8", - "sideBarSectionHeader.foreground": "#6C6C71", - "sideBarSectionHeader.border": "#eeeeef", - "activityBar.background": "#f8f8f8", - "activityBar.foreground": "#070707", - "activityBar.border": "#eeeeef", - "activityBar.activeBorder": "#008cff", - "activityBarBadge.background": "#008cff", - "activityBarBadge.foreground": "#ffffff", - "titleBar.activeBackground": "#f8f8f8", - "titleBar.activeForeground": "#070707", - "titleBar.inactiveBackground": "#f8f8f8", - "titleBar.inactiveForeground": "#84848A", - "titleBar.border": "#eeeeef", - "list.activeSelectionBackground": "#dfe7ffcc", - "list.activeSelectionForeground": "#070707", - "list.inactiveSelectionBackground": "#dfe7ff73", - "list.hoverBackground": "#dfe7ff59", - "list.focusOutline": "#008cff", - "tab.activeBackground": "#ffffff", - "tab.activeForeground": "#070707", - "tab.activeBorderTop": "#008cff", - "tab.inactiveBackground": "#f8f8f8", - "tab.inactiveForeground": "#84848A", - "tab.border": "#eeeeef", - "editorGroupHeader.tabsBackground": "#f8f8f8", - "editorGroupHeader.tabsBorder": "#eeeeef", - "panel.background": "#f8f8f8", - "panel.border": "#eeeeef", - "panelTitle.activeBorder": "#008cff", - "panelTitle.activeForeground": "#070707", - "panelTitle.inactiveForeground": "#84848A", - "statusBar.background": "#f8f8f8", - "statusBar.foreground": "#6C6C71", - "statusBar.border": "#eeeeef", - "statusBar.noFolderBackground": "#f8f8f8", - "statusBar.debuggingBackground": "#ffca00", - "statusBar.debuggingForeground": "#ffffff", - "statusBarItem.remoteBackground": "#f8f8f8", - "statusBarItem.remoteForeground": "#6C6C71", - "input.background": "#f2f2f3", - "input.border": "#dbdbdd", - "input.foreground": "#070707", - "input.placeholderForeground": "#8E8E95", - "dropdown.background": "#f2f2f3", - "dropdown.border": "#dbdbdd", - "dropdown.foreground": "#070707", - "button.background": "#008cff", - "button.foreground": "#ffffff", - "button.hoverBackground": "#1a98ff", - "textLink.foreground": "#008cff", - "textLink.activeForeground": "#008cff", - "gitDecoration.addedResourceForeground": "#00cab1", - "gitDecoration.conflictingResourceForeground": "#ffca00", - "gitDecoration.modifiedResourceForeground": "#008cff", - "gitDecoration.deletedResourceForeground": "#ff2e3f", - "gitDecoration.untrackedResourceForeground": "#00cab1", - "gitDecoration.ignoredResourceForeground": "#84848A", - "terminal.titleForeground": "#6C6C71", - "terminal.titleInactiveForeground": "#84848A", - "terminal.background": "#f8f8f8", - "terminal.foreground": "#6C6C71", - "terminal.ansiBlack": "#1F1F21", - "terminal.ansiRed": "#ff2e3f", - "terminal.ansiGreen": "#0dbe4e", - "terminal.ansiYellow": "#ffca00", - "terminal.ansiBlue": "#008cff", - "terminal.ansiMagenta": "#c635e4", - "terminal.ansiCyan": "#08c0ef", - "terminal.ansiWhite": "#c6c6c8", - "terminal.ansiBrightBlack": "#1F1F21", - "terminal.ansiBrightRed": "#ff2e3f", - "terminal.ansiBrightGreen": "#0dbe4e", - "terminal.ansiBrightYellow": "#ffca00", - "terminal.ansiBrightBlue": "#008cff", - "terminal.ansiBrightMagenta": "#c635e4", - "terminal.ansiBrightCyan": "#08c0ef", - "terminal.ansiBrightWhite": "#c6c6c8", +const colors = { + "editor.background": "transparent", + "editor.foreground": "var(--text-base)", + "gitDecoration.addedResourceForeground": "var(--syntax-diff-add)", + "gitDecoration.deletedResourceForeground": "var(--syntax-diff-delete)", + // "gitDecoration.conflictingResourceForeground": "#ffca00", + // "gitDecoration.modifiedResourceForeground": "#1a76d4", + // "gitDecoration.untrackedResourceForeground": "#00cab1", + // "gitDecoration.ignoredResourceForeground": "#84848A", + // "terminal.titleForeground": "#adadb1", + // "terminal.titleInactiveForeground": "#84848A", + // "terminal.background": "#141415", + // "terminal.foreground": "#adadb1", + // "terminal.ansiBlack": "#141415", + // "terminal.ansiRed": "#ff2e3f", + // "terminal.ansiGreen": "#0dbe4e", + // "terminal.ansiYellow": "#ffca00", + // "terminal.ansiBlue": "#008cff", + // "terminal.ansiMagenta": "#c635e4", + // "terminal.ansiCyan": "#08c0ef", + // "terminal.ansiWhite": "#c6c6c8", + // "terminal.ansiBrightBlack": "#141415", + // "terminal.ansiBrightRed": "#ff2e3f", + // "terminal.ansiBrightGreen": "#0dbe4e", + // "terminal.ansiBrightYellow": "#ffca00", + // "terminal.ansiBrightBlue": "#008cff", + // "terminal.ansiBrightMagenta": "#c635e4", + // "terminal.ansiBrightCyan": "#08c0ef", + // "terminal.ansiBrightWhite": "#c6c6c8", +} + +const tokenColors = [ + { + scope: ["comment", "punctuation.definition.comment", "string.comment"], + settings: { + foreground: "var(--syntax-comment)", }, - tokenColors: [ - { - scope: ["comment", "punctuation.definition.comment"], - settings: { - foreground: "#84848A", - }, - }, - { - scope: "comment markup.link", - settings: { - foreground: "#84848A", - }, - }, - { - scope: ["string", "constant.other.symbol"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: ["punctuation.definition.string.begin", "punctuation.definition.string.end"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: ["constant.numeric", "constant.language.boolean"], - settings: { - foreground: "#1ca1c7", - }, - }, - { - scope: "constant", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "punctuation.definition.constant", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "constant.language", - settings: { - foreground: "#1ca1c7", - }, - }, - { - scope: "variable.other.constant", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.control", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["storage", "storage.type", "storage.modifier"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "token.storage", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: [ - "keyword.operator.new", - "keyword.operator.expression.instanceof", - "keyword.operator.expression.typeof", - "keyword.operator.expression.void", - "keyword.operator.expression.delete", - "keyword.operator.expression.in", - "keyword.operator.expression.of", - "keyword.operator.expression.keyof", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.operator.delete", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["variable", "identifier", "meta.definition.variable"], - settings: { - foreground: "#d47628", - }, - }, - { - scope: [ - "variable.other.readwrite", - "meta.object-literal.key", - "support.variable.property", - "support.variable.object.process", - "support.variable.object.node", - ], - settings: { - foreground: "#d47628", - }, - }, - { - scope: "variable.language", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "variable.parameter.function", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "function.parameter", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "variable.parameter", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "variable.parameter.function.language.python", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "variable.parameter.function.python", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "support.function", - "entity.name.function", - "meta.function-call", - "meta.require", - "support.function.any-method", - "variable.function", - ], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "keyword.other.special-method", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "entity.name.function", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "support.function.console", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: ["support.type", "entity.name.type", "entity.name.class", "storage.type"], - settings: { - foreground: "#c635e4", - }, - }, - { - scope: ["support.class", "entity.name.type.class"], - settings: { - foreground: "#c635e4", - }, - }, - { - scope: ["entity.name.class", "variable.other.class.js", "variable.other.class.ts"], - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "entity.name.class.identifier.namespace.type", - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "entity.name.type.namespace", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.other.inherited-class", - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "entity.name.namespace", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["keyword.operator.logical", "keyword.operator.bitwise", "keyword.operator.channel"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: [ - "keyword.operator.arithmetic", - "keyword.operator.comparison", - "keyword.operator.relational", - "keyword.operator.increment", - "keyword.operator.decrement", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.assignment", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.assignment.compound", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: [ - "keyword.operator.assignment.compound.js", - "keyword.operator.assignment.compound.ts", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.ternary", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.operator.optional", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "punctuation", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.separator.delimiter", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.separator.key-value", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.terminator", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace.square", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace.round", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "function.brace", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["punctuation.definition.parameters", "punctuation.definition.typeparameters"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["punctuation.definition.block", "punctuation.definition.tag"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["meta.tag.tsx", "meta.tag.jsx", "meta.tag.js", "meta.tag.ts"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "keyword.operator.expression.import", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "keyword.operator.module", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "support.type.object.console", - settings: { - foreground: "#d47628", - }, - }, - { - scope: ["support.module.node", "support.type.object.module", "entity.name.type.module"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "support.constant.math", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "support.constant.property.math", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "support.constant.json", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "support.type.object.dom", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["support.variable.dom", "support.variable.property.dom"], - settings: { - foreground: "#d47628", - }, - }, - { - scope: "support.variable.property.process", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.property.object", - settings: { - foreground: "#d47628", - }, - }, - { - scope: "variable.parameter.function.js", - settings: { - foreground: "#d47628", - }, - }, - { - scope: ["keyword.other.template.begin", "keyword.other.template.end"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: ["keyword.other.substitution.begin", "keyword.other.substitution.end"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: [ - "punctuation.definition.template-expression.begin", - "punctuation.definition.template-expression.end", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "meta.template.expression", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.section.embedded", - settings: { - foreground: "#d47628", - }, - }, - { - scope: "variable.interpolation", - settings: { - foreground: "#d47628", - }, - }, - { - scope: ["punctuation.section.embedded.begin", "punctuation.section.embedded.end"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "punctuation.quasi.element", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: [ - "support.type.primitive.ts", - "support.type.builtin.ts", - "support.type.primitive.tsx", - "support.type.builtin.tsx", - ], - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "support.type.type.flowtype", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "support.type.primitive", - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "support.variable.magic.python", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "variable.parameter.function.language.special.self.python", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "punctuation.separator.period.python", - "punctuation.separator.element.python", - "punctuation.parenthesis.begin.python", - "punctuation.parenthesis.end.python", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "punctuation.definition.arguments.begin.python", - "punctuation.definition.arguments.end.python", - "punctuation.separator.arguments.python", - "punctuation.definition.list.begin.python", - "punctuation.definition.list.end.python", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.type.python", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.logical.python", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "meta.function-call.generic.python", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "constant.character.format.placeholder.other.python", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.function.decorator.python", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: ["support.token.decorator.python", "meta.function.decorator.identifier.python"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "storage.modifier.lifetime.rust", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.function.std.rust", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "entity.name.lifetime.rust", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "variable.language.rust", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "keyword.operator.misc.rust", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "keyword.operator.sigil.rust", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "support.constant.core.rust", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["meta.function.c", "meta.function.cpp"], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: [ - "punctuation.section.block.begin.bracket.curly.cpp", - "punctuation.section.block.end.bracket.curly.cpp", - "punctuation.terminator.statement.c", - "punctuation.section.block.begin.bracket.curly.c", - "punctuation.section.block.end.bracket.curly.c", - "punctuation.section.parens.begin.bracket.round.c", - "punctuation.section.parens.end.bracket.round.c", - "punctuation.section.parameters.begin.bracket.round.c", - "punctuation.section.parameters.end.bracket.round.c", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "keyword.operator.assignment.c", - "keyword.operator.comparison.c", - "keyword.operator.c", - "keyword.operator.increment.c", - "keyword.operator.decrement.c", - "keyword.operator.bitwise.shift.c", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: [ - "keyword.operator.assignment.cpp", - "keyword.operator.comparison.cpp", - "keyword.operator.cpp", - "keyword.operator.increment.cpp", - "keyword.operator.decrement.cpp", - "keyword.operator.bitwise.shift.cpp", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["punctuation.separator.c", "punctuation.separator.cpp"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["support.type.posix-reserved.c", "support.type.posix-reserved.cpp"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["keyword.operator.sizeof.c", "keyword.operator.sizeof.cpp"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "variable.c", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["storage.type.annotation.java", "storage.type.object.array.java"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "source.java", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: [ - "punctuation.section.block.begin.java", - "punctuation.section.block.end.java", - "punctuation.definition.method-parameters.begin.java", - "punctuation.definition.method-parameters.end.java", - "meta.method.identifier.java", - "punctuation.section.method.begin.java", - "punctuation.section.method.end.java", - "punctuation.terminator.java", - "punctuation.section.class.begin.java", - "punctuation.section.class.end.java", - "punctuation.section.inner-class.begin.java", - "punctuation.section.inner-class.end.java", - "meta.method-call.java", - "punctuation.section.class.begin.bracket.curly.java", - "punctuation.section.class.end.bracket.curly.java", - "punctuation.section.method.begin.bracket.curly.java", - "punctuation.section.method.end.bracket.curly.java", - "punctuation.separator.period.java", - "punctuation.bracket.angle.java", - "punctuation.definition.annotation.java", - "meta.method.body.java", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.method.java", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: ["storage.modifier.import.java", "storage.type.java", "storage.type.generic.java"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator.instanceof.java", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "meta.definition.variable.name.java", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "token.variable.parameter.java", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "import.storage.java", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "token.package.keyword", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "token.package", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "token.storage.type.java", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator.assignment.go", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["keyword.operator.arithmetic.go", "keyword.operator.address.go"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "entity.name.package.go", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "support.other.namespace.use.php", - "support.other.namespace.use-as.php", - "support.other.namespace.php", - "entity.other.alias.php", - "meta.interface.php", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator.error-control.php", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.operator.type.php", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["punctuation.section.array.begin.php", "punctuation.section.array.end.php"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "storage.type.php", - "meta.other.type.phpdoc.php", - "keyword.other.type.php", - "keyword.other.array.phpdoc.php", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "meta.function-call.php", - "meta.function-call.object.php", - "meta.function-call.static.php", - ], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: [ - "punctuation.definition.parameters.begin.bracket.round.php", - "punctuation.definition.parameters.end.bracket.round.php", - "punctuation.separator.delimiter.php", - "punctuation.section.scope.begin.php", - "punctuation.section.scope.end.php", - "punctuation.terminator.expression.php", - "punctuation.definition.arguments.begin.bracket.round.php", - "punctuation.definition.arguments.end.bracket.round.php", - "punctuation.definition.storage-type.begin.bracket.round.php", - "punctuation.definition.storage-type.end.bracket.round.php", - "punctuation.definition.array.begin.bracket.round.php", - "punctuation.definition.array.end.bracket.round.php", - "punctuation.definition.begin.bracket.round.php", - "punctuation.definition.end.bracket.round.php", - "punctuation.definition.begin.bracket.curly.php", - "punctuation.definition.end.bracket.curly.php", - "punctuation.definition.section.switch-block.end.bracket.curly.php", - "punctuation.definition.section.switch-block.start.bracket.curly.php", - "punctuation.definition.section.switch-block.begin.bracket.curly.php", - "punctuation.definition.section.switch-block.end.bracket.curly.php", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "support.constant.ext.php", - "support.constant.std.php", - "support.constant.core.php", - "support.constant.parser-token.php", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["entity.name.goto-label.php", "support.other.php"], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: [ - "keyword.operator.logical.php", - "keyword.operator.bitwise.php", - "keyword.operator.arithmetic.php", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.regexp.php", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.operator.comparison.php", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["keyword.operator.heredoc.php", "keyword.operator.nowdoc.php"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "variable.other.class.php", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "invalid.illegal.non-null-typehinted.php", - settings: { - foreground: "#f44747", - }, - }, - { - scope: "variable.other.generic-type.haskell", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "storage.type.haskell", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "storage.type.cs", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.name.variable.local.cs", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "entity.name.label.cs", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "entity.name.scope-resolution.function.call", - "entity.name.scope-resolution.function.definition", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "punctuation.definition.delayed.unison", - "punctuation.definition.list.begin.unison", - "punctuation.definition.list.end.unison", - "punctuation.definition.ability.begin.unison", - "punctuation.definition.ability.end.unison", - "punctuation.operator.assignment.as.unison", - "punctuation.separator.pipe.unison", - "punctuation.separator.delimiter.unison", - "punctuation.definition.hash.unison", - ], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "support.constant.edge", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "support.type.prelude.elm", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.constant.elm", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.global.clojure", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.symbol.clojure", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "constant.keyword.clojure", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["meta.arguments.coffee", "variable.parameter.function.coffee"], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "storage.modifier.import.groovy", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.method.groovy", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "meta.definition.variable.name.groovy", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "meta.definition.class.inherited.classes.groovy", - settings: { - foreground: "#199f43", - }, - }, - { - scope: "support.variable.semantic.hlsl", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "support.type.texture.hlsl", - "support.type.sampler.hlsl", - "support.type.object.hlsl", - "support.type.object.rw.hlsl", - "support.type.fx.hlsl", - "support.type.object.hlsl", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["text.variable", "text.bracketed"], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: ["support.type.swift", "support.type.vb.asp"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.scope.prerequisites.makefile", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "source.makefile", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "source.ini", - settings: { - foreground: "#199f43", - }, - }, - { - scope: "constant.language.symbol.ruby", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["function.parameter.ruby", "function.parameter.cs"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "constant.language.symbol.elixir", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: - "text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: - "text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "entity.name.function.xi", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.name.class.xi", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "constant.character.character-class.regexp.xi", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "constant.regexp.xi", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.control.xi", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "invalid.xi", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "beginning.punctuation.definition.quote.markdown.xi", - settings: { - foreground: "#199f43", - }, - }, - { - scope: "beginning.punctuation.definition.list.markdown.xi", - settings: { - foreground: "#84848A", - }, - }, - { - scope: "constant.character.xi", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "accent.xi", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "wikiword.xi", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "constant.other.color.rgb-value.xi", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "punctuation.definition.tag.xi", - settings: { - foreground: "#84848A", - }, - }, - { - scope: ["support.constant.property-value.scss", "support.constant.property-value.css"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["keyword.operator.css", "keyword.operator.scss", "keyword.operator.less"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: [ - "support.constant.color.w3c-standard-color-name.css", - "support.constant.color.w3c-standard-color-name.scss", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "punctuation.separator.list.comma.css", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.type.vendored.property-name.css", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name.css", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.constant.property-value", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.constant.font-name", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.other.attribute-name.class.css", - settings: { - foreground: "#16a994", - fontStyle: "normal", - }, - }, - { - scope: "entity.other.attribute-name.id", - settings: { - foreground: "#7b43f8", - fontStyle: "normal", - }, - }, - { - scope: [ - "entity.other.attribute-name.pseudo-element", - "entity.other.attribute-name.pseudo-class", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "meta.selector", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "selector.sass", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "rgb-value", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "inline-color-decoration rgb-value", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "less rgb-value", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "control.elements", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator.less", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.name.tag", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "entity.other.attribute-name", - settings: { - foreground: "#16a994", - fontStyle: "normal", - }, - }, - { - scope: "constant.character.entity", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "meta.tag", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "invalid.illegal.bad-ampersand.html", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "markup.heading", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: ["markup.heading punctuation.definition.heading", "entity.name.section"], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "entity.name.section.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "punctuation.definition.heading.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "markup.heading.setext", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["markup.heading.setext.1.markdown", "markup.heading.setext.2.markdown"], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: ["markup.bold", "todo.bold"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "punctuation.definition.bold", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "punctuation.definition.bold.markdown", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["markup.italic", "punctuation.definition.italic", "todo.emphasis"], - settings: { - foreground: "#fc2b73", - fontStyle: "italic", - }, - }, - { - scope: "emphasis md", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "markup.italic.markdown", - settings: { - fontStyle: "italic", - }, - }, - { - scope: ["markup.underline.link.markdown", "markup.underline.link.image.markdown"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["string.other.link.title.markdown", "string.other.link.description.markdown"], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "punctuation.definition.metadata.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: ["markup.inline.raw.markdown", "markup.inline.raw.string.markdown"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: "punctuation.definition.list.begin.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "punctuation.definition.list.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "beginning.punctuation.definition.list.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: [ - "punctuation.definition.string.begin.markdown", - "punctuation.definition.string.end.markdown", - ], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "markup.quote.markdown", - settings: { - foreground: "#84848A", - }, - }, - { - scope: "keyword.other.unit", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "markup.changed.diff", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "meta.diff.header.from-file", - "meta.diff.header.to-file", - "punctuation.definition.from-file.diff", - "punctuation.definition.to-file.diff", - ], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "markup.inserted.diff", - settings: { - foreground: "#199f43", - }, - }, - { - scope: "markup.deleted.diff", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "string.regexp", - settings: { - foreground: "#17a5af", - }, - }, - { - scope: "constant.other.character-class.regexp", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "keyword.operator.quantifier.regexp", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "constant.character.escape", - settings: { - foreground: "#1ca1c7", - }, - }, - { - scope: "source.json meta.structure.dictionary.json > string.quoted.json", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: - "source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: [ - "source.json meta.structure.dictionary.json > value.json > string.quoted.json", - "source.json meta.structure.array.json > value.json > string.quoted.json", - "source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation", - "source.json meta.structure.array.json > value.json > string.quoted.json > punctuation", - ], - settings: { - foreground: "#199f43", - }, - }, - { - scope: [ - "source.json meta.structure.dictionary.json > constant.language.json", - "source.json meta.structure.array.json > constant.language.json", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name.json", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "support.type.property-name.json punctuation", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "punctuation.definition.block.sequence.item.yaml", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "block.scope.end", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "block.scope.begin", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "token.info-token", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "token.warn-token", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "token.error-token", - settings: { - foreground: "#f44747", - }, - }, - { - scope: "token.debug-token", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "invalid.illegal", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.broken", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.deprecated", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.unimplemented", - settings: { - foreground: "#ffffff", - }, - }, + }, + { + scope: ["entity.other.attribute-name"], + settings: { + foreground: "var(--syntax-property)", // maybe attribute + }, + }, + { + scope: [ + "constant", + "entity.name.constant", + "variable.other.constant", + "variable.language", + "entity", + ], + settings: { + foreground: "var(--syntax-constant)", + }, + }, + { + scope: ["entity.name", "meta.export.default", "meta.definition.variable"], + settings: { + foreground: "var(--syntax-type)", + }, + }, + { + 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", + "string.other.end.yaml", + ], + settings: { + foreground: "var(--syntax-punctuation)", + }, + }, + { + scope: ["entity.name.function", "support.type.primitive"], + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: ["support.class.component"], + settings: { + foreground: "var(--syntax-type)", + }, + }, + { + scope: "keyword", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: [ + "keyword.operator", + "storage.type.function.arrow", + "punctuation.separator.key-value.css", + "entity.name.tag.yaml", + "punctuation.separator.key-value.mapping.yaml", ], - semanticTokenColors: { - comment: "#84848A", - string: "#199f43", - number: "#1ca1c7", - regexp: "#17a5af", - keyword: "#fc2b73", - variable: "#d47628", - parameter: "#79797F", - property: "#d47628", - function: "#7b43f8", - method: "#7b43f8", - type: "#c635e4", - class: "#c635e4", - namespace: "#d5a910", - enumMember: "#08c0ef", - "variable.constant": "#d5a910", - "variable.defaultLibrary": "#d5a910", + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: ["storage", "storage.type"], + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: ["storage.modifier.package", "storage.modifier.import", "storage.type.java"], + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: [ + "string", + "punctuation.definition.string", + "string punctuation.section.embedded source", + "entity.name.tag", + ], + settings: { + foreground: "var(--syntax-string)", + }, + }, + { + scope: "support", + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: [ + "support.type.object.module", + "variable.other.object", + "support.type.property-name.css", + ], + settings: { + foreground: "var(--syntax-object)", + }, + }, + { + scope: "meta.property-name", + settings: { + foreground: "var(--syntax-property)", + }, + }, + { + scope: "variable", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "variable.other", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: [ + "invalid.broken", + "invalid.illegal", + "invalid.unimplemented", + "invalid.deprecated", + "message.error", + "markup.deleted", + "meta.diff.header.from-file", + "punctuation.definition.deleted", + "brackethighlighter.unmatched", + "token.error-token", + ], + settings: { + foreground: "var(--syntax-critical)", + }, + }, + { + scope: "carriage-return", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "string source", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "string variable", + settings: { + foreground: "var(--syntax-constant)", + }, + }, + { + scope: [ + "source.regexp", + "string.regexp", + "string.regexp.character-class", + "string.regexp constant.character.escape", + "string.regexp source.ruby.embedded", + "string.regexp string.regexp.arbitrary-repitition", + "string.regexp constant.character.escape", + ], + settings: { + foreground: "var(--syntax-regexp)", + }, + }, + { + scope: "support.constant", + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: "support.variable", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "meta.module-reference", + settings: { + foreground: "var(--syntax-info)", + }, + }, + { + scope: "punctuation.definition.list.begin.markdown", + settings: { + foreground: "var(--syntax-punctuation)", + }, + }, + { + scope: ["markup.heading", "markup.heading entity.name"], + settings: { + fontStyle: "bold", + foreground: "var(--syntax-info)", + }, + }, + { + scope: "markup.quote", + settings: { + foreground: "var(--syntax-info)", + }, + }, + { + scope: "markup.italic", + settings: { + fontStyle: "italic", + // foreground: "", + }, + }, + { + scope: "markup.bold", + settings: { + fontStyle: "bold", + foreground: "var(--text-strong)", + }, + }, + { + scope: [ + "markup.raw", + "markup.inserted", + "meta.diff.header.to-file", + "punctuation.definition.inserted", + "markup.changed", + "punctuation.definition.changed", + "markup.ignored", + "markup.untracked", + ], + settings: { + foreground: "var(--text-base)", + }, + }, + { + scope: "meta.diff.range", + settings: { + fontStyle: "bold", + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.diff.header", + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.separator", + settings: { + fontStyle: "bold", + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.output", + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.export.default", + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: [ + "brackethighlighter.tag", + "brackethighlighter.curly", + "brackethighlighter.round", + "brackethighlighter.square", + "brackethighlighter.angle", + "brackethighlighter.quote", + ], + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: ["constant.other.reference.link", "string.other.link"], + settings: { + fontStyle: "underline", + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "token.info-token", + settings: { + foreground: "var(--syntax-info)", + }, + }, + { + scope: "token.warn-token", + settings: { + foreground: "var(--syntax-warning)", }, + }, + { + scope: "token.debug-token", + settings: { + foreground: "var(--syntax-info)", + }, + }, +] + +const semanticTokenColors = { + comment: "var(--syntax-comment)", + string: "var(--syntax-string)", + number: "var(--syntax-constant)", + regexp: "var(--syntax-regexp)", + keyword: "var(--syntax-keyword)", + variable: "var(--syntax-variable)", + parameter: "var(--syntax-variable)", + property: "var(--syntax-property)", + function: "var(--syntax-primitive)", + method: "var(--syntax-primitive)", + type: "var(--syntax-type)", + class: "var(--syntax-type)", + namespace: "var(--syntax-type)", + enumMember: "var(--syntax-primitive)", + "variable.constant": "var(--syntax-constant)", + "variable.defaultLibrary": "var(--syntax-unknown)", +} + +registerCustomTheme("oc-1-light", () => { + return Promise.resolve({ + type: "light", + name: "oc-1-light", + colors, + tokenColors, + semanticTokenColors, } as unknown as ThemeRegistrationResolved) }) @@ -1969,1783 +567,8 @@ registerCustomTheme("oc-1-dark", () => { return Promise.resolve({ name: "oc-1-dark", type: "dark", - colors: { - "editor.background": "transparent", - "editor.foreground": "#fbfbfb", - foreground: "#fbfbfb", - focusBorder: "#1a76d4", - "selection.background": "#19253c", - "editor.selectionBackground": "#1a76d44d", - "editor.lineHighlightBackground": "#19253c8c", - "editorCursor.foreground": "#1a76d4", - "editorLineNumber.foreground": "#84848A", - "editorLineNumber.activeForeground": "#adadb1", - "editorIndentGuide.background": "#39393c", - "editorIndentGuide.activeBackground": "#2e2e30", - "diffEditor.insertedTextBackground": "#00cab11a", - "diffEditor.deletedTextBackground": "#ff2e3f1a", - "sideBar.background": "#141415", - "sideBar.foreground": "#adadb1", - "sideBar.border": "#070707", - "sideBarTitle.foreground": "#fbfbfb", - "sideBarSectionHeader.background": "#141415", - "sideBarSectionHeader.foreground": "#adadb1", - "sideBarSectionHeader.border": "#070707", - "activityBar.background": "#141415", - "activityBar.foreground": "#fbfbfb", - "activityBar.border": "#070707", - "activityBar.activeBorder": "#1a76d4", - "activityBarBadge.background": "#1a76d4", - "activityBarBadge.foreground": "#070707", - "titleBar.activeBackground": "#141415", - "titleBar.activeForeground": "#fbfbfb", - "titleBar.inactiveBackground": "#141415", - "titleBar.inactiveForeground": "#84848A", - "titleBar.border": "#070707", - "list.activeSelectionBackground": "#19253c99", - "list.activeSelectionForeground": "#fbfbfb", - "list.inactiveSelectionBackground": "#19253c73", - "list.hoverBackground": "#19253c59", - "list.focusOutline": "#1a76d4", - "tab.activeBackground": "#070707", - "tab.activeForeground": "#fbfbfb", - "tab.activeBorderTop": "#1a76d4", - "tab.inactiveBackground": "#141415", - "tab.inactiveForeground": "#84848A", - "tab.border": "#070707", - "editorGroupHeader.tabsBackground": "#141415", - "editorGroupHeader.tabsBorder": "#070707", - "panel.background": "#141415", - "panel.border": "#070707", - "panelTitle.activeBorder": "#1a76d4", - "panelTitle.activeForeground": "#fbfbfb", - "panelTitle.inactiveForeground": "#84848A", - "statusBar.background": "#141415", - "statusBar.foreground": "#adadb1", - "statusBar.border": "#070707", - "statusBar.noFolderBackground": "#141415", - "statusBar.debuggingBackground": "#ffca00", - "statusBar.debuggingForeground": "#070707", - "statusBarItem.remoteBackground": "#141415", - "statusBarItem.remoteForeground": "#adadb1", - "input.background": "#1F1F21", - "input.border": "#424245", - "input.foreground": "#fbfbfb", - "input.placeholderForeground": "#79797F", - "dropdown.background": "#1F1F21", - "dropdown.border": "#424245", - "dropdown.foreground": "#fbfbfb", - "button.background": "#1a76d4", - "button.foreground": "#070707", - "button.hoverBackground": "#186bc0", - "textLink.foreground": "#1a76d4", - "textLink.activeForeground": "#1a76d4", - "gitDecoration.addedResourceForeground": "#00cab1", - "gitDecoration.conflictingResourceForeground": "#ffca00", - "gitDecoration.modifiedResourceForeground": "#1a76d4", - "gitDecoration.deletedResourceForeground": "#ff2e3f", - "gitDecoration.untrackedResourceForeground": "#00cab1", - "gitDecoration.ignoredResourceForeground": "#84848A", - "terminal.titleForeground": "#adadb1", - "terminal.titleInactiveForeground": "#84848A", - "terminal.background": "#141415", - "terminal.foreground": "#adadb1", - "terminal.ansiBlack": "#141415", - "terminal.ansiRed": "#ff2e3f", - "terminal.ansiGreen": "#0dbe4e", - "terminal.ansiYellow": "#ffca00", - "terminal.ansiBlue": "#008cff", - "terminal.ansiMagenta": "#c635e4", - "terminal.ansiCyan": "#08c0ef", - "terminal.ansiWhite": "#c6c6c8", - "terminal.ansiBrightBlack": "#141415", - "terminal.ansiBrightRed": "#ff2e3f", - "terminal.ansiBrightGreen": "#0dbe4e", - "terminal.ansiBrightYellow": "#ffca00", - "terminal.ansiBrightBlue": "#008cff", - "terminal.ansiBrightMagenta": "#c635e4", - "terminal.ansiBrightCyan": "#08c0ef", - "terminal.ansiBrightWhite": "#c6c6c8", - }, - tokenColors: [ - { - scope: ["comment", "punctuation.definition.comment"], - settings: { - foreground: "#84848A", - }, - }, - { - scope: "comment markup.link", - settings: { - foreground: "#84848A", - }, - }, - { - scope: ["string", "constant.other.symbol"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: ["punctuation.definition.string.begin", "punctuation.definition.string.end"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: ["constant.numeric", "constant.language.boolean"], - settings: { - foreground: "#68cdf2", - }, - }, - { - scope: "constant", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "punctuation.definition.constant", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "constant.language", - settings: { - foreground: "#68cdf2", - }, - }, - { - scope: "variable.other.constant", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.control", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["storage", "storage.type", "storage.modifier"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "token.storage", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: [ - "keyword.operator.new", - "keyword.operator.expression.instanceof", - "keyword.operator.expression.typeof", - "keyword.operator.expression.void", - "keyword.operator.expression.delete", - "keyword.operator.expression.in", - "keyword.operator.expression.of", - "keyword.operator.expression.keyof", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.operator.delete", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["variable", "identifier", "meta.definition.variable"], - settings: { - foreground: "#ffa359", - }, - }, - { - scope: [ - "variable.other.readwrite", - "meta.object-literal.key", - "support.variable.property", - "support.variable.object.process", - "support.variable.object.node", - ], - settings: { - foreground: "#ffa359", - }, - }, - { - scope: "variable.language", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "variable.parameter.function", - settings: { - foreground: "#adadb1", - }, - }, - { - scope: "function.parameter", - settings: { - foreground: "#adadb1", - }, - }, - { - scope: "variable.parameter", - settings: { - foreground: "#adadb1", - }, - }, - { - scope: "variable.parameter.function.language.python", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "variable.parameter.function.python", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: [ - "support.function", - "entity.name.function", - "meta.function-call", - "meta.require", - "support.function.any-method", - "variable.function", - ], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "keyword.other.special-method", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "entity.name.function", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "support.function.console", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: ["support.type", "entity.name.type", "entity.name.class", "storage.type"], - settings: { - foreground: "#d568ea", - }, - }, - { - scope: ["support.class", "entity.name.type.class"], - settings: { - foreground: "#d568ea", - }, - }, - { - scope: ["entity.name.class", "variable.other.class.js", "variable.other.class.ts"], - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "entity.name.class.identifier.namespace.type", - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "entity.name.type.namespace", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "entity.other.inherited-class", - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "entity.name.namespace", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword.operator", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["keyword.operator.logical", "keyword.operator.bitwise", "keyword.operator.channel"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: [ - "keyword.operator.arithmetic", - "keyword.operator.comparison", - "keyword.operator.relational", - "keyword.operator.increment", - "keyword.operator.decrement", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.assignment", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.assignment.compound", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: [ - "keyword.operator.assignment.compound.js", - "keyword.operator.assignment.compound.ts", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.ternary", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.operator.optional", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "punctuation", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.separator.delimiter", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.separator.key-value", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.terminator", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace.square", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace.round", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "function.brace", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["punctuation.definition.parameters", "punctuation.definition.typeparameters"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["punctuation.definition.block", "punctuation.definition.tag"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["meta.tag.tsx", "meta.tag.jsx", "meta.tag.js", "meta.tag.ts"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "keyword.operator.expression.import", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "keyword.operator.module", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "support.type.object.console", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: ["support.module.node", "support.type.object.module", "entity.name.type.module"], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "support.constant.math", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "support.constant.property.math", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "support.constant.json", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "support.type.object.dom", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["support.variable.dom", "support.variable.property.dom"], - settings: { - foreground: "#ffa359", - }, - }, - { - scope: "support.variable.property.process", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "meta.property.object", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: "variable.parameter.function.js", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: ["keyword.other.template.begin", "keyword.other.template.end"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: ["keyword.other.substitution.begin", "keyword.other.substitution.end"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: [ - "punctuation.definition.template-expression.begin", - "punctuation.definition.template-expression.end", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "meta.template.expression", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.section.embedded", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: "variable.interpolation", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: ["punctuation.section.embedded.begin", "punctuation.section.embedded.end"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "punctuation.quasi.element", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: [ - "support.type.primitive.ts", - "support.type.builtin.ts", - "support.type.primitive.tsx", - "support.type.builtin.tsx", - ], - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "support.type.type.flowtype", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "support.type.primitive", - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "support.variable.magic.python", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "variable.parameter.function.language.special.self.python", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "punctuation.separator.period.python", - "punctuation.separator.element.python", - "punctuation.parenthesis.begin.python", - "punctuation.parenthesis.end.python", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "punctuation.definition.arguments.begin.python", - "punctuation.definition.arguments.end.python", - "punctuation.separator.arguments.python", - "punctuation.definition.list.begin.python", - "punctuation.definition.list.end.python", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.type.python", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.logical.python", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "meta.function-call.generic.python", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "constant.character.format.placeholder.other.python", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "meta.function.decorator.python", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: ["support.token.decorator.python", "meta.function.decorator.identifier.python"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "storage.modifier.lifetime.rust", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.function.std.rust", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "entity.name.lifetime.rust", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "variable.language.rust", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "keyword.operator.misc.rust", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "keyword.operator.sigil.rust", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "support.constant.core.rust", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: ["meta.function.c", "meta.function.cpp"], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: [ - "punctuation.section.block.begin.bracket.curly.cpp", - "punctuation.section.block.end.bracket.curly.cpp", - "punctuation.terminator.statement.c", - "punctuation.section.block.begin.bracket.curly.c", - "punctuation.section.block.end.bracket.curly.c", - "punctuation.section.parens.begin.bracket.round.c", - "punctuation.section.parens.end.bracket.round.c", - "punctuation.section.parameters.begin.bracket.round.c", - "punctuation.section.parameters.end.bracket.round.c", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "keyword.operator.assignment.c", - "keyword.operator.comparison.c", - "keyword.operator.c", - "keyword.operator.increment.c", - "keyword.operator.decrement.c", - "keyword.operator.bitwise.shift.c", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: [ - "keyword.operator.assignment.cpp", - "keyword.operator.comparison.cpp", - "keyword.operator.cpp", - "keyword.operator.increment.cpp", - "keyword.operator.decrement.cpp", - "keyword.operator.bitwise.shift.cpp", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["punctuation.separator.c", "punctuation.separator.cpp"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["support.type.posix-reserved.c", "support.type.posix-reserved.cpp"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["keyword.operator.sizeof.c", "keyword.operator.sizeof.cpp"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "variable.c", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["storage.type.annotation.java", "storage.type.object.array.java"], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "source.java", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: [ - "punctuation.section.block.begin.java", - "punctuation.section.block.end.java", - "punctuation.definition.method-parameters.begin.java", - "punctuation.definition.method-parameters.end.java", - "meta.method.identifier.java", - "punctuation.section.method.begin.java", - "punctuation.section.method.end.java", - "punctuation.terminator.java", - "punctuation.section.class.begin.java", - "punctuation.section.class.end.java", - "punctuation.section.inner-class.begin.java", - "punctuation.section.inner-class.end.java", - "meta.method-call.java", - "punctuation.section.class.begin.bracket.curly.java", - "punctuation.section.class.end.bracket.curly.java", - "punctuation.section.method.begin.bracket.curly.java", - "punctuation.section.method.end.bracket.curly.java", - "punctuation.separator.period.java", - "punctuation.bracket.angle.java", - "punctuation.definition.annotation.java", - "meta.method.body.java", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.method.java", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: ["storage.modifier.import.java", "storage.type.java", "storage.type.generic.java"], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword.operator.instanceof.java", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "meta.definition.variable.name.java", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "token.variable.parameter.java", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "import.storage.java", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "token.package.keyword", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "token.package", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "token.storage.type.java", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword.operator.assignment.go", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: ["keyword.operator.arithmetic.go", "keyword.operator.address.go"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "entity.name.package.go", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "support.other.namespace.use.php", - "support.other.namespace.use-as.php", - "support.other.namespace.php", - "entity.other.alias.php", - "meta.interface.php", - ], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword.operator.error-control.php", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.operator.type.php", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["punctuation.section.array.begin.php", "punctuation.section.array.end.php"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "storage.type.php", - "meta.other.type.phpdoc.php", - "keyword.other.type.php", - "keyword.other.array.phpdoc.php", - ], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "meta.function-call.php", - "meta.function-call.object.php", - "meta.function-call.static.php", - ], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: [ - "punctuation.definition.parameters.begin.bracket.round.php", - "punctuation.definition.parameters.end.bracket.round.php", - "punctuation.separator.delimiter.php", - "punctuation.section.scope.begin.php", - "punctuation.section.scope.end.php", - "punctuation.terminator.expression.php", - "punctuation.definition.arguments.begin.bracket.round.php", - "punctuation.definition.arguments.end.bracket.round.php", - "punctuation.definition.storage-type.begin.bracket.round.php", - "punctuation.definition.storage-type.end.bracket.round.php", - "punctuation.definition.array.begin.bracket.round.php", - "punctuation.definition.array.end.bracket.round.php", - "punctuation.definition.begin.bracket.round.php", - "punctuation.definition.end.bracket.round.php", - "punctuation.definition.begin.bracket.curly.php", - "punctuation.definition.end.bracket.curly.php", - "punctuation.definition.section.switch-block.end.bracket.curly.php", - "punctuation.definition.section.switch-block.start.bracket.curly.php", - "punctuation.definition.section.switch-block.begin.bracket.curly.php", - "punctuation.definition.section.switch-block.end.bracket.curly.php", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "support.constant.ext.php", - "support.constant.std.php", - "support.constant.core.php", - "support.constant.parser-token.php", - ], - settings: { - foreground: "#ffd452", - }, - }, - { - scope: ["entity.name.goto-label.php", "support.other.php"], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: [ - "keyword.operator.logical.php", - "keyword.operator.bitwise.php", - "keyword.operator.arithmetic.php", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.regexp.php", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.operator.comparison.php", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["keyword.operator.heredoc.php", "keyword.operator.nowdoc.php"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "variable.other.class.php", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "invalid.illegal.non-null-typehinted.php", - settings: { - foreground: "#f44747", - }, - }, - { - scope: "variable.other.generic-type.haskell", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "storage.type.haskell", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "storage.type.cs", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "entity.name.variable.local.cs", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "entity.name.label.cs", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "entity.name.scope-resolution.function.call", - "entity.name.scope-resolution.function.definition", - ], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "punctuation.definition.delayed.unison", - "punctuation.definition.list.begin.unison", - "punctuation.definition.list.end.unison", - "punctuation.definition.ability.begin.unison", - "punctuation.definition.ability.end.unison", - "punctuation.operator.assignment.as.unison", - "punctuation.separator.pipe.unison", - "punctuation.separator.delimiter.unison", - "punctuation.definition.hash.unison", - ], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "support.constant.edge", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "support.type.prelude.elm", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.constant.elm", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "entity.global.clojure", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "meta.symbol.clojure", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "constant.keyword.clojure", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["meta.arguments.coffee", "variable.parameter.function.coffee"], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "storage.modifier.import.groovy", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "meta.method.groovy", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "meta.definition.variable.name.groovy", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "meta.definition.class.inherited.classes.groovy", - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "support.variable.semantic.hlsl", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "support.type.texture.hlsl", - "support.type.sampler.hlsl", - "support.type.object.hlsl", - "support.type.object.rw.hlsl", - "support.type.fx.hlsl", - "support.type.object.hlsl", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["text.variable", "text.bracketed"], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: ["support.type.swift", "support.type.vb.asp"], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "meta.scope.prerequisites.makefile", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "source.makefile", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "source.ini", - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "constant.language.symbol.ruby", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["function.parameter.ruby", "function.parameter.cs"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "constant.language.symbol.elixir", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: - "text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: - "text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "entity.name.function.xi", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "entity.name.class.xi", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "constant.character.character-class.regexp.xi", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "constant.regexp.xi", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.control.xi", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "invalid.xi", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "beginning.punctuation.definition.quote.markdown.xi", - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "beginning.punctuation.definition.list.markdown.xi", - settings: { - foreground: "#84848A", - }, - }, - { - scope: "constant.character.xi", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "accent.xi", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "wikiword.xi", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "constant.other.color.rgb-value.xi", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "punctuation.definition.tag.xi", - settings: { - foreground: "#84848A", - }, - }, - { - scope: ["support.constant.property-value.scss", "support.constant.property-value.css"], - settings: { - foreground: "#ffd452", - }, - }, - { - scope: ["keyword.operator.css", "keyword.operator.scss", "keyword.operator.less"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: [ - "support.constant.color.w3c-standard-color-name.css", - "support.constant.color.w3c-standard-color-name.scss", - ], - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "punctuation.separator.list.comma.css", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.type.vendored.property-name.css", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name.css", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.constant.property-value", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.constant.font-name", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "entity.other.attribute-name.class.css", - settings: { - foreground: "#61d5c0", - fontStyle: "normal", - }, - }, - { - scope: "entity.other.attribute-name.id", - settings: { - foreground: "#9d6afb", - fontStyle: "normal", - }, - }, - { - scope: [ - "entity.other.attribute-name.pseudo-element", - "entity.other.attribute-name.pseudo-class", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "meta.selector", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "selector.sass", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "rgb-value", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "inline-color-decoration rgb-value", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "less rgb-value", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "control.elements", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "keyword.operator.less", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "entity.name.tag", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "entity.other.attribute-name", - settings: { - foreground: "#61d5c0", - fontStyle: "normal", - }, - }, - { - scope: "constant.character.entity", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "meta.tag", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "invalid.illegal.bad-ampersand.html", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "markup.heading", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: ["markup.heading punctuation.definition.heading", "entity.name.section"], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "entity.name.section.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "punctuation.definition.heading.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "markup.heading.setext", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["markup.heading.setext.1.markdown", "markup.heading.setext.2.markdown"], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: ["markup.bold", "todo.bold"], - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "punctuation.definition.bold", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "punctuation.definition.bold.markdown", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: ["markup.italic", "punctuation.definition.italic", "todo.emphasis"], - settings: { - foreground: "#ff678d", - fontStyle: "italic", - }, - }, - { - scope: "emphasis md", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "markup.italic.markdown", - settings: { - fontStyle: "italic", - }, - }, - { - scope: ["markup.underline.link.markdown", "markup.underline.link.image.markdown"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["string.other.link.title.markdown", "string.other.link.description.markdown"], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "punctuation.definition.metadata.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: ["markup.inline.raw.markdown", "markup.inline.raw.string.markdown"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "punctuation.definition.list.begin.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "punctuation.definition.list.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "beginning.punctuation.definition.list.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: [ - "punctuation.definition.string.begin.markdown", - "punctuation.definition.string.end.markdown", - ], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "markup.quote.markdown", - settings: { - foreground: "#84848A", - }, - }, - { - scope: "keyword.other.unit", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "markup.changed.diff", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "meta.diff.header.from-file", - "meta.diff.header.to-file", - "punctuation.definition.from-file.diff", - "punctuation.definition.to-file.diff", - ], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "markup.inserted.diff", - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "markup.deleted.diff", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "string.regexp", - settings: { - foreground: "#64d1db", - }, - }, - { - scope: "constant.other.character-class.regexp", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "keyword.operator.quantifier.regexp", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "constant.character.escape", - settings: { - foreground: "#68cdf2", - }, - }, - { - scope: "source.json meta.structure.dictionary.json > string.quoted.json", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: - "source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: [ - "source.json meta.structure.dictionary.json > value.json > string.quoted.json", - "source.json meta.structure.array.json > value.json > string.quoted.json", - "source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation", - "source.json meta.structure.array.json > value.json > string.quoted.json > punctuation", - ], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: [ - "source.json meta.structure.dictionary.json > constant.language.json", - "source.json meta.structure.array.json > constant.language.json", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name.json", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "support.type.property-name.json punctuation", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "punctuation.definition.block.sequence.item.yaml", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "block.scope.end", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "block.scope.begin", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "token.info-token", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "token.warn-token", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "token.error-token", - settings: { - foreground: "#f44747", - }, - }, - { - scope: "token.debug-token", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "invalid.illegal", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.broken", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.deprecated", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.unimplemented", - settings: { - foreground: "#ffffff", - }, - }, - ], - semanticTokenColors: { - comment: "#84848A", - string: "#5ecc71", - number: "#68cdf2", - regexp: "#64d1db", - keyword: "#ff678d", - variable: "#ffa359", - parameter: "#adadb1", - property: "#ffa359", - function: "#9d6afb", - method: "#9d6afb", - type: "#d568ea", - class: "#d568ea", - namespace: "#ffca00", - enumMember: "#08c0ef", - "variable.constant": "#ffd452", - "variable.defaultLibrary": "#ffca00", - }, + colors, + tokenColors, + semanticTokenColors, } as unknown as ThemeRegistrationResolved) }) diff --git a/packages/ui/src/styles/tailwind/colors.css b/packages/ui/src/styles/tailwind/colors.css index a5f982d6f..95a497ba9 100644 --- a/packages/ui/src/styles/tailwind/colors.css +++ b/packages/ui/src/styles/tailwind/colors.css @@ -196,15 +196,20 @@ --color-icon-diff-delete-base: var(--icon-diff-delete-base); --color-icon-diff-delete-hover: var(--icon-diff-delete-hover); --color-syntax-comment: var(--syntax-comment); + --color-syntax-regexp: var(--syntax-regexp); --color-syntax-string: var(--syntax-string); --color-syntax-keyword: var(--syntax-keyword); --color-syntax-function: var(--syntax-function); --color-syntax-number: var(--syntax-number); --color-syntax-operator: var(--syntax-operator); --color-syntax-variable: var(--syntax-variable); + --color-syntax-property: var(--syntax-property); + --color-syntax-parameter: var(--syntax-parameter); --color-syntax-type: var(--syntax-type); --color-syntax-constant: var(--syntax-constant); --color-syntax-punctuation: var(--syntax-punctuation); + --color-syntax-namespace: var(--syntax-namespace); + --color-syntax-enum: var(--syntax-enum); --color-syntax-success: var(--syntax-success); --color-syntax-warning: var(--syntax-warning); --color-syntax-critical: var(--syntax-critical); diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css index 6187eef9d..431d811da 100644 --- a/packages/ui/src/styles/theme.css +++ b/packages/ui/src/styles/theme.css @@ -268,20 +268,25 @@ --icon-diff-add-active: var(--mint-light-12); --icon-diff-delete-base: var(--ember-light-10); --icon-diff-delete-hover: var(--ember-light-11); - --syntax-comment: #8a8a8a; - --syntax-string: #d68c27; - --syntax-keyword: #3b7dd8; - --syntax-function: #d1383d; - --syntax-number: #3d9a57; - --syntax-operator: #d68c27; - --syntax-variable: #b0851f; - --syntax-type: #318795; - --syntax-constant: #953170; - --syntax-punctuation: #1a1a1a; - --syntax-success: var(--apple-dark-10); + --syntax-comment: var(--text-weaker); + --syntax-regexp: var(--text-base); + --syntax-string: var(--mint-light-11); + --syntax-keyword: var(--text-weak); + --syntax-primitive: var(--ember-light-11); + --syntax-operator: var(--text-weak); + --syntax-variable: var(--text-strong); + --syntax-property: var(--lilac-light-11); + --syntax-type: var(--cobalt-light-11); + --syntax-constant: var(--lilac-light-11); + --syntax-punctuation: var(--text-weak); + --syntax-object: var(--blue-light-11); + --syntax-success: var(--apple-light-10); --syntax-warning: var(--amber-light-10); - --syntax-critical: var(--ember-dark-9); - --syntax-info: var(--lilac-dark-11); + --syntax-critical: var(--ember-light-9); + --syntax-info: var(--lilac-light-11); + --syntax-diff-add: var(--mint-light-11); + --syntax-diff-delete: var(--ember-light-11); + --syntax-unknown: red; --markdown-heading: #d68c27; --markdown-text: #1a1a1a; --markdown-link: #3b7dd8; @@ -503,20 +508,24 @@ --icon-diff-add-active: var(--mint-dark-11); --icon-diff-delete-base: var(--ember-dark-9); --icon-diff-delete-hover: var(--ember-dark-10); - --syntax-comment: #808080; - --syntax-string: #9d7cd8; - --syntax-keyword: #fab283; - --syntax-function: #e06c75; - --syntax-number: #7fd88f; - --syntax-operator: #f5a742; - --syntax-variable: #e5c07b; - --syntax-type: #56b6c2; - --syntax-constant: #c2569a; - --syntax-punctuation: #eeeeee; + --syntax-comment: var(--text-weaker); + --syntax-regexp: var(--text-base); + --syntax-string: var(--mint-dark-11); + --syntax-keyword: var(--text-weak); + --syntax-primitive: var(--ember-dark-11); + --syntax-operator: var(--text-weak); + --syntax-variable: var(--text-strong); + --syntax-property: var(--lilac-dark-11); + --syntax-type: var(--cobalt-dark-11); + --syntax-constant: var(--lilac-dark-11); + --syntax-punctuation: var(--text-weak); + --syntax-object: var(--blue-dark-11); --syntax-success: var(--apple-dark-10); --syntax-warning: var(--amber-dark-10); - --syntax-critical: var(--ember-dark-10); - --syntax-info: var(--lilac-dark-10); + --syntax-critical: var(--ember-dark-9); + --syntax-info: var(--lilac-dark-11); + --syntax-diff-add: var(--mint-dark-11); + --syntax-diff-delete: var(--ember-dark-11); --markdown-heading: #9d7cd8; --markdown-text: #eeeeee; --markdown-link: #fab283; diff --git a/theme-test.java b/theme-test.java new file mode 100644 index 000000000..7c1b582af --- /dev/null +++ b/theme-test.java @@ -0,0 +1,461 @@ +package com.example.theme; + +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.stream.*; +import java.time.*; +import java.time.format.*; +import java.net.*; +import java.io.*; +import java.nio.file.*; +import java.sql.*; +import java.lang.annotation.*; +import java.math.BigDecimal; +import java.math.BigInteger; + +// Enum definition +public enum LogLevel { + DEBUG(0, "Debug"), + INFO(1, "Info"), + WARN(2, "Warning"), + ERROR(3, "Error"); + + private final int level; + private final String description; + + LogLevel(int level, String description) { + this.level = level; + this.description = description; + } + + public int getLevel() { return level; } + public String getDescription() { return description; } +} + +// Interface with generics +public interface Repository { + Optional findById(Long id); + List findAll(); + T save(T entity); + void delete(Long id); + Stream stream(); + + @FunctionalInterface + interface Predicate { + boolean test(T t); + } +} + +// Abstract class +public abstract class AbstractService implements Repository { + protected final Map cache = new ConcurrentHashMap<>(); + protected volatile boolean initialized = false; + + @Override + public Optional findById(Long id) { + return Optional.ofNullable(cache.get(id)); + } + + @Override + public List findAll() { + return new ArrayList<>(cache.values()); + } + + @Override + public Stream stream() { + return cache.values().stream(); + } + + protected abstract void validate(T entity) throws ValidationException; +} + +// Annotation definition +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface Service { + String value() default ""; + boolean transactional() default true; + Class[] exceptions() = {}; +} + +// Record class (Java 14+) +public record User( + Long id, + String username, + String email, + @Deprecated String fullName, + LocalDateTime createdAt, + boolean active +) implements Entity { + + public User { + Objects.requireNonNull(username, "Username cannot be null"); + Objects.requireNonNull(email, "Email cannot be null"); + Objects.requireNonNull(createdAt, "Created date cannot be null"); + } + + public static User of(String username, String email) { + return new User(null, username, email, null, LocalDateTime.now(), true); + } + + public User withId(Long id) { + return new User(id, username, email, fullName, createdAt, active); + } +} + +// Exception classes +public class ValidationException extends RuntimeException { + private final List errors; + + public ValidationException(String message) { + super(message); + this.errors = List.of(message); + } + + public ValidationException(List errors) { + super(String.join(", ", errors)); + this.errors = Collections.unmodifiableList(errors); + } + + public List getErrors() { return errors; } +} + +public class ResourceNotFoundException extends RuntimeException { + public ResourceNotFoundException(String resource, Long id) { + super(String.format("%s with id %d not found", resource, id)); + } +} + +// Service implementation +@Service(value = "userService", transactional = true) +public class UserService extends AbstractService { + + private static final Logger logger = LoggerFactory.getLogger(UserService.class); + private static final int MAX_RETRY_ATTEMPTS = 3; + private static final Duration TIMEOUT = Duration.ofSeconds(30); + + private final EmailService emailService; + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + @Inject + public UserService(EmailService emailService, + UserRepository userRepository, + PasswordEncoder passwordEncoder) { + this.emailService = emailService; + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + } + + @Override + protected void validate(User user) throws ValidationException { + List errors = new ArrayList<>(); + + if (user.username() == null || user.username().trim().isEmpty()) { + errors.add("Username is required"); + } else if (!user.username().matches("^[a-zA-Z0-9_]{3,20}$")) { + errors.add("Username must be 3-20 characters, alphanumeric and underscore only"); + } + + if (user.email() == null || !user.email().matches("^[A-Za-z0-9+_.-]+@(.+)$")) { + errors.add("Valid email is required"); + } + + if (!errors.isEmpty()) { + throw new ValidationException(errors); + } + } + + @Transactional + public User createUser(CreateUserRequest request) throws ValidationException { + logger.info("Creating new user: {}", request.username()); + + // Check if user already exists + if (userRepository.findByUsername(request.username()).isPresent()) { + throw new ValidationException("Username already exists"); + } + + if (userRepository.findByEmail(request.email()).isPresent()) { + throw new ValidationException("Email already exists"); + } + + // Create new user + User user = User.of(request.username(), request.email()) + .withId(generateId()); + + validate(user); + + try { + User savedUser = userRepository.save(user); + cache.put(savedUser.id(), savedUser); + + // Send welcome email asynchronously + CompletableFuture.runAsync(() -> + emailService.sendWelcomeEmail(savedUser) + ).exceptionally(throwable -> { + logger.error("Failed to send welcome email to user {}", savedUser.id(), throwable); + return null; + }); + + logger.info("Successfully created user with ID: {}", savedUser.id()); + return savedUser; + + } catch (DataAccessException e) { + logger.error("Database error while creating user", e); + throw new ServiceException("Failed to create user", e); + } + } + + public Optional findByUsername(String username) { + return cache.values().stream() + .filter(user -> user.username().equals(username)) + .findFirst(); + } + + public List findActiveUsers() { + return cache.values().stream() + .filter(User::active) + .sorted(Comparator.comparing(User::createdAt).reversed()) + .collect(Collectors.toList()); + } + + @Retry(maxAttempts = MAX_RETRY_ATTEMPTS, backoff = @Backoff(delay = 1000)) + public User updateUser(Long id, UpdateUserRequest request) { + User existingUser = findById(id) + .orElseThrow(() -> new ResourceNotFoundException("User", id)); + + User updatedUser = new User( + id, + request.username() != null ? request.username() : existingUser.username(), + request.email() != null ? request.email() : existingUser.email(), + existingUser.fullName(), + existingUser.createdAt(), + request.active() != null ? request.active() : existingUser.active() + ); + + validate(updatedUser); + + try { + User savedUser = userRepository.save(updatedUser); + cache.put(id, savedUser); + return savedUser; + } catch (DataAccessException e) { + logger.error("Failed to update user with ID: {}", id, e); + throw new ServiceException("Failed to update user", e); + } + } + + @Async + public CompletableFuture deleteUser(Long id) { + return CompletableFuture.runAsync(() -> { + try { + userRepository.deleteById(id); + cache.remove(id); + logger.info("Successfully deleted user with ID: {}", id); + } catch (DataAccessException e) { + logger.error("Failed to delete user with ID: {}", id, e); + throw new ServiceException("Failed to delete user", e); + } + }); + } + + private Long generateId() { + return System.currentTimeMillis() + (long)(Math.random() * 1000); + } +} + +// Utility class +public final class DateUtils { + + private DateUtils() { + // Utility class - prevent instantiation + } + + private static final DateTimeFormatter ISO_FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + + public static String formatIsoDateTime(LocalDateTime dateTime) { + return dateTime.atZone(ZoneId.systemDefault()).format(ISO_FORMATTER); + } + + public static LocalDateTime parseIsoDateTime(String isoString) { + return LocalDateTime.parse(isoString, ISO_FORMATTER); + } + + public static boolean isWithinLastDays(LocalDateTime dateTime, int days) { + return dateTime.isAfter(LocalDateTime.now().minusDays(days)); + } +} + +// Builder pattern +public class UserQueryBuilder { + private String username; + private String email; + private Boolean active; + private LocalDateTime createdAfter; + private LocalDateTime createdBefore; + private SortOrder sortOrder = SortOrder.ASC; + private String sortBy = "createdAt"; + private int limit = 100; + private int offset = 0; + + public UserQueryBuilder withUsername(String username) { + this.username = username; + return this; + } + + public UserQueryBuilder withEmail(String email) { + this.email = email; + return this; + } + + public UserQueryBuilder activeOnly(boolean active) { + this.active = active; + return this; + } + + public UserQueryBuilder createdAfter(LocalDateTime date) { + this.createdAfter = date; + return this; + } + + public UserQueryBuilder createdBefore(LocalDateTime date) { + this.createdBefore = date; + return this; + } + + public UserQueryBuilder sortBy(String field, SortOrder order) { + this.sortBy = field; + this.sortOrder = order; + return this; + } + + public UserQueryBuilder limit(int limit) { + this.limit = Math.max(1, Math.min(limit, 1000)); + return this; + } + + public UserQueryBuilder offset(int offset) { + this.offset = Math.max(0, offset); + return this; + } + + public UserQuery build() { + return new UserQuery(username, email, active, createdAfter, createdBefore, + sortBy, sortOrder, limit, offset); + } +} + +// Lambda expressions and streams +public class StreamProcessor { + + private static final Map> TYPE_CONVERTERS = Map.of( + "string", s -> s, + "int", Integer::parseInt, + "double", Double::parseDouble, + "boolean", Boolean::parseBoolean, + "bigdecimal", BigDecimal::new, + "bigint", BigInteger::new + ); + + public Map processConfig(Properties properties) { + return properties.entrySet().stream() + .filter(entry -> entry.getKey() instanceof String) + .filter(entry -> entry.getValue() != null) + .collect(Collectors.toMap( + entry -> (String) entry.getKey(), + entry -> convertValue((String) entry.getKey(), (String) entry.getValue()) + )); + } + + private Object convertValue(String key, String value) { + String type = determineType(key, value); + return TYPE_CONVERTERS.getOrDefault(type, Function.identity()).apply(value); + } + + private String determineType(String key, String value) { + if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) { + return "boolean"; + } else if (value.matches("-?\\d+")) { + return "int"; + } else if (value.matches("-?\\d*\\.\\d+")) { + return "double"; + } else if (key.toLowerCase().contains("amount") || key.toLowerCase().contains("price")) { + return "bigdecimal"; + } + return "string"; + } + + public List validateEmails(List emails) { + return emails.stream() + .filter(Objects::nonNull) + .map(String::trim) + .filter(email -> !email.isEmpty()) + .filter(email -> email.matches("^[A-Za-z0-9+_.-]+@(.+)$")) + .distinct() + .collect(Collectors.toList()); + } + + public CompletableFuture> processUsersAsync(List users) { + return CompletableFuture.supplyAsync(() -> + users.parallelStream() + .filter(User::active) + .filter(user -> user.createdAt().isAfter(LocalDateTime.now().minusYears(1))) + .sorted(Comparator.comparing(User::username)) + .collect(Collectors.toList()) + ); + } +} + +// Main class for testing +public class Main { + private static final Logger logger = LoggerFactory.getLogger(Main.class); + + public static void main(String[] args) { + try { + // Initialize application context + ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); + + // Get service bean + UserService userService = context.getBean(UserService.class); + + // Create test users + List users = Arrays.asList( + User.of("john_doe", "john@example.com"), + User.of("jane_smith", "jane@example.com"), + User.of("bob_wilson", "bob@example.com") + ); + + // Process users + List> futures = users.stream() + .map(user -> { + try { + return CompletableFuture.completedFuture(userService.createUser( + new CreateUserRequest(user.username(), user.email()) + )); + } catch (ValidationException e) { + logger.error("Failed to create user: {}", user.username(), e); + return CompletableFuture.failedFuture(e); + } + }) + .collect(Collectors.toList()); + + // Wait for all to complete + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenRun(() -> { + logger.info("All users created successfully"); + System.out.println("Application started successfully!"); + }) + .exceptionally(throwable -> { + logger.error("Failed to initialize users", throwable); + System.err.println("Application startup failed!"); + return null; + }); + + } catch (Exception e) { + logger.error("Application startup failed", e); + System.exit(1); + } + } +} \ No newline at end of file diff --git a/theme-test.md b/theme-test.md new file mode 100644 index 000000000..3863cc325 --- /dev/null +++ b/theme-test.md @@ -0,0 +1,669 @@ +# TextMate Grammar Token Examples + +This file contains examples of every major TextMate token style for theme testing. + +## Comments + + + +// Single line comment +/_ Multi-line comment _/ + +# Shell comment + +/_ JSDoc comment with @param and @return _/ + +## Strings + +"Double quoted string" +'Single quoted string' +`Backtick string` +"String with \"escaped\" quotes" +'String with \'escaped\' quotes' +`String with \`escaped\` backticks` + +## Template Literals + +`Simple template literal` +`Template with ${variable} interpolation` +`Template with ${function.call()} expression` +Multi-line template with ${nested.interpolation} + +## Numbers + +42 +-17 +3.14159 +-0.001 +1e10 +-2.5e-8 +0xFF +0o755 +0b1010 + +## Keywords + +if else elif for while do switch case default +function class extends implements import export +return break continue throw try catch finally +var let const static async await yield +new this super null undefined true false + +## Storage Types + +int float double string boolean char void +static final abstract private public protected +readonly volatile transient synchronized + +## Constants + +MAX_VALUE +DEFAULT_TIMEOUT +API_ENDPOINT +PI +E + +## Variables + +variableName +\_privateVariable +$specialVariable +camelCase +snake_case +PascalCase +kebab-case + +## Functions + +functionName() +method.call() +object.property() +array[index] +arrowFunction => expression + +## Operators + +- - - / % ++ -- + == === != !== > < >= <= + && || ! & | ^ ~ << >> >>> + = += -= \*= /= %= &= |= ^= <<= >>= >>>= + +## Punctuation + +, ; : . ... ( ) [ ] { } < > / \\ + +# @ $ % ^ & \* - \_ + = | ~ ` ? + +## Entities + +ClassName +InterfaceName +EnumName +TypeName +MethodName +PropertyName + +## Tags + +
+ +

+ +description + +## Attributes + +class="container" +id="main" +data-value="123" +disabled +required +readonly + +## CSS Selectors & Properties + +.container +#header +.button:hover +input[type="text"] +::before +::after + +color: #ffffff; +background: linear-gradient(45deg, #ff0000, #00ff00); +font-size: 16px; +margin: 0 auto; +padding: 10px 20px; + +## Regular Expressions + +/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ +/\d{3}-\d{3}-\d{4}/g +/(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})/ + +## URLs & Paths + +https://example.com/path/to/resource +file:///Users/username/project +./relative/path +../parent/directory +/home/user/documents + +## JSON + +{ +"name": "example", +"version": "1.0.0", +"dependencies": { +"react": "^18.0.0", +"typescript": "^4.9.0" +}, +"scripts": { +"start": "node index.js", +"test": "jest" +} +} + +## XML/HTML + + + + + + + Document + + +

+ + + +## SQL + +SELECT u.id, u.name, u.email, COUNT(o.id) as order_count +FROM users u +LEFT JOIN orders o ON u.id = o.user_id +WHERE u.active = true +AND o.created_at >= '2023-01-01' +GROUP BY u.id, u.name, u.email +HAVING COUNT(o.id) > 5 +ORDER BY order_count DESC +LIMIT 10; + +## GraphQL + +query GetUserProfile($userId: ID!, $includePosts: Boolean!) { +user(id: $userId) { +id +name +email +avatar +createdAt +posts @include(if: $includePosts) { +id +title +content +publishedAt +comments(first: 10) { +edges { +node { +id +author +content +createdAt +} +} +} +} +} +} + +## Shell/Bash + +#!/bin/bash + +# Variables + +PROJECT*DIR="/home/user/projects" +BACKUP_DIR="$PROJECT_DIR/backups" +TIMESTAMP=$(date +"%Y%m%d*%H%M%S") + +# Functions + +create*backup() { +local source_dir=$1 + local backup_file="$BACKUP_DIR/backup*$TIMESTAMP.tar.gz" + + echo "Creating backup of $source_dir..." + tar -czf "$backup_file" "$source_dir" + echo "Backup created: $backup_file" + +} + +# Conditional logic + +if [ -d "$PROJECT_DIR" ]; then +create_backup "$PROJECT_DIR" +else +echo "Project directory not found: $PROJECT_DIR" +exit 1 +fi + +## Python + +import os +import sys +from typing import List, Dict, Optional +import requests +from dataclasses import dataclass + +@dataclass +class User: +id: int +name: str +email: Optional[str] = None +active: bool = True + + def __post_init__(self): + if not self.name.strip(): + raise ValueError("Name cannot be empty") + +class UserService: +def **init**(self, api_url: str): +self.api_url = api_url +self.session = requests.Session() + + async def get_user(self, user_id: int) -> Optional[User]: + """Fetch user data from API.""" + try: + response = await self.session.get(f"{self.api_url}/users/{user_id}") + response.raise_for_status() + data = response.json() + return User(**data) + except requests.RequestException as e: + print(f"Error fetching user {user_id}: {e}") + return None + +## Rust + +use std::collections::HashMap; +use std::fs::File; +use std::io::{self, Read}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct User { +pub id: u64, +pub name: String, +pub email: Option, #[serde(default)] +pub active: bool, +pub created_at: chrono::DateTime, +} + +impl User { +pub fn new(id: u64, name: String, email: Option) -> Self { +Self { +id, +name, +email, +active: true, +created_at: chrono::Utc::now(), +} +} + + pub fn display_name(&self) -> String { + match &self.email { + Some(email) => format!("{} <{}>", self.name, email), + None => self.name.clone(), + } + } + +} + +pub struct UserService { +api_url: String, +client: reqwest::Client, +} + +impl UserService { +pub fn new(api_url: String) -> Self { +Self { +api_url, +client: reqwest::Client::new(), +} +} + + pub async fn get_user(&self, user_id: u64) -> Result> { + let url = format!("{}/users/{}", self.api_url, user_id); + let response = self.client.get(&url).send().await?; + let user: User = response.json().await?; + Ok(user) + } + +} + +## Go + +package main + +import ( +"context" +"encoding/json" +"fmt" +"log" +"net/http" +"time" +"github.com/gorilla/mux" +) + +type User struct { +ID int64 `json:"id"` +Name string `json:"name"` +Email \*string `json:"email,omitempty"` +Active bool `json:"active"` +CreatedAt time.Time `json:"created_at"` +} + +type UserService struct { +re UserRepository +} + +func NewUserService(repo UserRepository) \*UserService { +return &UserService{repo: repo} +} + +func (s *UserService) GetUser(ctx context.Context, id int64) (*User, error) { +user, err := s.repo.FindByID(ctx, id) +if err != nil { +return nil, fmt.Errorf("failed to get user %d: %w", id, err) +} +return user, nil +} + +func (s *UserService) CreateUser(ctx context.Context, req *CreateUserRequest) (\*User, error) { +user := &User{ +Name: req.Name, +Email: req.Email, +Active: true, +CreatedAt: time.Now(), +} +if err := s.repo.Create(ctx, user); err != nil { +return nil, fmt.Errorf("failed to create user: %w", err) +} +return user, nil +} + +## YAML + +apiVersion: apps/v1 +kind: Deployment +metadata: +name: web-app +namespace: production +labels: +app: web-app +version: v1.2.3 +spec: +replicas: 3 +selector: +matchLabels: +app: web-app +template: +metadata: +labels: +app: web-app +tier: frontend +spec: +containers: - name: web-app +image: nginx:1.21-alpine +ports: - containerPort: 80 +protocol: TCP +env: - name: NODE_ENV +value: "production" - name: API_URL +valueFrom: +secretKeyRef: +name: app-secrets +key: api-url +resources: +requests: +memory: "64Mi" +cpu: "250m" +limits: +memory: "128Mi" +cpu: "500m" +livenessProbe: +httpGet: +path: /health +port: 80 +initialDelaySeconds: 30 +periodSeconds: 10 +readinessProbe: +httpGet: +path: /ready +port: 80 +initialDelaySeconds: 5 +periodSeconds: 5 + +## TOML + +[project] +name = "example-app" +version = "1.0.0" +description = "An example application" +authors = ["John Doe "] +license = "MIT" +readme = "README.md" +homepage = "https://example.com" +repository = "https://github.com/johndoe/example-app" +keywords = ["web", "api", "rust"] +categories = ["web-programming"] +edition = "2021" + +[dependencies] +tokio = { version = "1.0", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +reqwest = { version = "0.11", features = ["json"] } +chrono = { version = "0.4", features = ["serde"] } +log = "0.4" +env_logger = "0.10" + +[dev-dependencies] +tokio-test = "0.4" +mockito = "1.0" + +[[bin]] +name = "server" +path = "src/main.rs" + +[[bin]] +name = "client" +path = "src/client.rs" + +## Dockerfile + +FROM node:18-alpine AS base + +# Install dependencies only when needed + +FROM base AS deps + +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. + +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Install dependencies based on the preferred package manager + +COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml\* ./ +RUN \ + if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ + elif [ -f package-lock.json ]; then npm ci; \ + elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \ + else echo "Lockfile not found." && exit 1; \ + fi + +# Rebuild the source code only when needed + +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Next.js collects completely anonymous telemetry data about general usage. + +# Learn more here: https://nextjs.org/telemetry + +# Uncomment the following line in case you want to disable telemetry during the build. + +# ENV NEXT_TELEMETRY_DISABLED 1 + +RUN \ + if [ -f yarn.lock ]; then yarn run build; \ + elif [ -f package-lock.json ]; then npm run build; \ + elif [ -f pnpm-lock.yaml ]; then pnpm run build; \ + else echo "Lockfile not found." && exit 1; \ + fi + +# Production image, copy all the files and run next + +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production + +# Uncomment the following line in case you want to disable telemetry during runtime. + +# ENV NEXT_TELEMETRY_DISABLED 1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +# Set the correct permission for prerender cache + +RUN mkdir .next +RUN chown nextjs:nodejs .next + +# Automatically leverage output traces to reduce image size + +# https://nextjs.org/docs/advanced-features/output-file-tracing + +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 + +# set hostname to localhost + +ENV HOSTNAME "0.0.0.0" + +# server.js is created by next build from the standalone output + +# https://nextjs.org/docs/pages/api-reference/next-config-js/output + +CMD ["node", "server.js"] + +## Makefile + +.PHONY: help build test clean install dev lint format + +# Default target + +.DEFAULT_GOAL := help + +# Variables + +APP_NAME := myapp +VERSION := $(shell git describe --tags --always --dirty) +BUILD_DIR := ./build +DIST_DIR := ./dist +GO_FILES := $(shell find . -name '\*.go' -type f) + +help: ## Show this help message +@echo "Available targets:" +@grep -E '^[a-zA-Z_-]+:._?## ._$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.\*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +install: ## Install dependencies +go mod download +npm install + +build: ## Build the application +@echo "Building $(APP_NAME) version $(VERSION)..." + mkdir -p $(BUILD_DIR) + go build -ldflags "-X main.version=$(VERSION)" -o $(BUILD_DIR)/$(APP_NAME) ./cmd/main.go + +test: ## Run tests +go test -v ./... +npm test + +lint: ## Run linters +golangci-lint run +npx eslint . + +format: ## Format code +go fmt ./... +npx prettier --write . + +dev: ## Run in development mode +go run ./cmd/main.go --dev + +clean: ## Clean build artifacts +rm -rf $(BUILD_DIR) +rm -rf $(DIST_DIR) +go clean -cache + +docker-build: ## Build Docker image +docker build -t $(APP_NAME):$(VERSION) . +docker tag $(APP_NAME):$(VERSION) $(APP_NAME):latest + +docker-run: ## Run Docker container +docker run -p 8080:8080 $(APP_NAME):latest + +release: ## Create a new release +@echo "Creating release $(VERSION)" +git tag -a $(VERSION) -m "Release $(VERSION)" +git push origin $(VERSION) +goreleaser release --rm-dist + +## Git Diff + +diff --git a/src/components/UserProfile.tsx b/src/components/UserProfile.tsx +index 1234567..abcdefg 100644 +--- a/src/components/UserProfile.tsx ++++ b/src/components/UserProfile.tsx +@@ -10,7 +10,7 @@ interface User { +id: number +name: string +email?: string + +- createdAt: Date + +* readonly createdAt: Date + active: boolean + } + +@@ -25,8 +25,12 @@ const UserProfile: FC<{ user: User }> = ({ user }) => { +const [isEditing, setIsEditing] = useState(false) +const [formData, setFormData] = useState(user) + +- const handleSubmit = async (e: React.FormEvent) => { +- e.preventDefault() +- // Handle form submission +- } +- return ( + +*
+ +-
+

{user.name}

+

{user.email}

+
diff --git a/theme-test.tsx b/theme-test.tsx index 16559bf70..61837473e 100644 --- a/theme-test.tsx +++ b/theme-test.tsx @@ -29,6 +29,8 @@ class Repository { } public find(id: number): T | undefined { + const x = undefined + type x = { foo: undefined } return this.items.find((item) => item.id === id) } @@ -66,6 +68,72 @@ const sql = ` AND created_at > '${new Date().toISOString()}' ` +// String source examples (CSS-in-JS, GraphQL, etc.) +const styledComponent = css` + .container { + display: flex; + justify-content: center; + align-items: center; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + padding: 2rem; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + + &:hover { + transform: translateY(-2px); + box-shadow: 0 8px 12px rgba(0, 0, 0, 0.15); + } + + .title { + font-size: 1.5rem; + font-weight: bold; + color: white; + margin-bottom: 1rem; + } + } +` + +const graphqlQuery = ` + query GetUserProfile($userId: ID!) { + user(id: $userId) { + id + name + email + avatar + createdAt + posts { + id + title + content + publishedAt + comments { + id + author + content + createdAt + } + } + } + } +` + +const htmlTemplate = ` +
+ ${user.name} + +
+ + +
+
+` + // Arrow functions const debounce = any>( func: T, -- cgit v1.2.3 From 89922a8598bf344ed24fb1b472307f383ef2b18a Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 12:56:07 -0600 Subject: fix(desktop): prompt input missing on new session --- packages/desktop/src/pages/session.tsx | 728 ++++++++++++++++----------------- 1 file changed, 361 insertions(+), 367 deletions(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 3dcc24e61..b872c1434 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -330,142 +330,39 @@ export default function Page() {
- -
New session
-
- -
- {getDirectory(sync.data.path.directory)} - {getFilename(sync.data.path.directory)} -
-
-
- -
- Last modified  - - {DateTime.fromMillis(sync.data.project.time.created).toRelative()} - -
-
-
- } +
- {(_) => { - return ( -
-
-
- - - -
-
- 1}> -
    - - {(message) => { - const assistantMessages = createMemo(() => { - if (!session.id) return [] - return sync.data.message[session.id]?.filter( - (m) => m.role === "assistant" && m.parentID == message.id, - ) as AssistantMessageType[] - }) - const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) - const working = createMemo(() => !message.summary?.body && !error()) - - const handleClick = () => session.messages.setActive(message.id) - - return ( -
  • - - - {message.summary?.title} -
- } - > - - - - - ) - }} - - - -
+
+ + +
+ + + +
+
+ 1}> +
    {(message) => { - const isActive = createMemo(() => session.messages.active()?.id === message.id) - const [titled, setTitled] = createSignal(!!message.summary?.title) const assistantMessages = createMemo(() => { if (!session.id) return [] return sync.data.message[session.id]?.filter( @@ -473,261 +370,358 @@ export default function Page() { ) as AssistantMessageType[] }) const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) - const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error()) - const [detailsExpanded, setDetailsExpanded] = createSignal(false) - const parts = createMemo(() => sync.data.part[message.id]) - const hasToolPart = createMemo(() => - assistantMessages() - ?.flatMap((m) => sync.data.part[m.id]) - .some((p) => p?.type === "tool"), - ) const working = createMemo(() => !message.summary?.body && !error()) - // allowing time for the animations to finish - createEffect(() => { - const title = message.summary?.title - setTimeout(() => setTitled(!!title), 10_000) - }) - createEffect(() => { - const summary = message.summary?.body - const complete = !!summary || !!error() - setTimeout(() => setCompleted(complete), 1200) - }) + const handleClick = () => session.messages.setActive(message.id) return ( - -
    + + + {message.summary?.title} +
    + } > - {/* Title */} -
    -
    - div]:bg-icon-strong-base data-[active=true]:[&>div]:w-full": true, + "@7xl:hidden": local.layout.review.state() !== "open", + }} + > +
    + + + + + ) + }} + +
+
+
+ + {(message) => { + const isActive = createMemo(() => session.messages.active()?.id === message.id) + const [titled, setTitled] = createSignal(!!message.summary?.title) + const assistantMessages = createMemo(() => { + if (!session.id) return [] + return sync.data.message[session.id]?.filter( + (m) => m.role === "assistant" && m.parentID == message.id, + ) as AssistantMessageType[] + }) + const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) + const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error()) + const [detailsExpanded, setDetailsExpanded] = createSignal(false) + const parts = createMemo(() => sync.data.part[message.id]) + const hasToolPart = createMemo(() => + assistantMessages() + ?.flatMap((m) => sync.data.part[m.id]) + .some((p) => p?.type === "tool"), + ) + const working = createMemo(() => !message.summary?.body && !error()) + + // allowing time for the animations to finish + createEffect(() => { + const title = message.summary?.title + setTimeout(() => setTitled(!!title), 10_000) + }) + createEffect(() => { + const summary = message.summary?.body + const complete = !!summary || !!error() + setTimeout(() => setCompleted(complete), 1200) + }) + + return ( + +
+ {/* Title */} +
+
+ + } + > +

+ {message.summary?.title} +

+
+
+
+
+ +
+ {/* Summary */} + +
+
+

+ + Summary + Response + +

+ + {(summary) => ( + *]:fade-up-text": !message.summary?.diffs?.length, + }} + text={summary()} /> - } - > -

- {message.summary?.title} -

+ )}
-
-
- -
- {/* Summary */} - -
-
-

- - Summary - Response - -

- - {(summary) => ( - *]:fade-up-text": !message.summary?.diffs?.length, - }} - text={summary()} - /> - )} - -
- - - {(diff) => ( - - - -
-
- -
- - - {getDirectory(diff.file)}‎ - - - - {getFilename(diff.file)} + + + {(diff) => ( + + + +
+
+ +
+ + + {getDirectory(diff.file)}‎ -
-
-
- - + + + {getFilename(diff.file)} +
-
-
- - - -
- )} -
-
-
- - - - {error()?.data?.message as string} - - - {/* Response */} -
- - - - - - - -
-
- - Hide details - Show details - -
- -
-
- -
- - {(assistantMessage) => { - const parts = createMemo(() => sync.data.part[assistantMessage.id]) - return +
+ + +
+
+ + + + - - - {error()?.data?.message as string} - - -
- - - - + after={{ + name: diff.file!, + contents: diff.after!, + }} + /> + + + )} + +
+ + + + {error()?.data?.message as string} + + + {/* Response */} +
+ + + + + + + +
+
+ + Hide details + Show details + +
+ +
+
+ +
+ + {(assistantMessage) => { + const parts = createMemo(() => sync.data.part[assistantMessage.id]) + return + }} + + + + {error()?.data?.message as string} + + +
+
+
+
+
- - ) - }} - +
+ + ) + }} +
+
+
+ + +
+
New session
+
+ +
+ {getDirectory(sync.data.path.directory)} + {getFilename(sync.data.path.directory)}
- -
- { - inputRef = el - }} - /> +
+
+ +
+ Last modified  + + {DateTime.fromMillis(sync.data.project.time.created).toRelative()} +
- -
-
-
- - - - - { - local.layout.review.tab() - session.layout.setActiveTab("review") + + +
+ { + inputRef = el + }} + /> +
+
+ +
+
+
+ + + + + { + local.layout.review.tab() + session.layout.setActiveTab("review") + }} + /> + +
+
+
All changes
+
+ + + {(diff) => ( + + + +
+
+ +
+ + + {getDirectory(diff.file)}‎ + + + {getFilename(diff.file)} +
+
+
+ + +
+
+
+
+ + - -
-
-
All changes
-
- - - {(diff) => ( - - - -
-
- -
- - - {getDirectory(diff.file)}‎ - - - {getFilename(diff.file)} -
-
-
- - -
-
-
-
- - - -
- )} -
-
-
-
- + + + )} + +
- ) - }} -
+
+
+
-- cgit v1.2.3 From 7adbc3ad443af942b400923b66119436589c676c Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:14:57 -0600 Subject: fix(desktop): code tab padding --- packages/desktop/src/pages/session.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index b872c1434..1c92941d0 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -791,14 +791,14 @@ export default function Page() { }, ) return ( - + {(f) => ( )} -- cgit v1.2.3 From 45fabec0919ba3268b6bd0b9566ec98cac0ed3d7 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:54:18 -0600 Subject: fix(desktop): prompt input on non-chat tabs --- packages/desktop/src/pages/session.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'packages/desktop/src/pages') diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 1c92941d0..23d44cfcb 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -829,6 +829,15 @@ export default function Page() { + +
+ { + inputRef = el + }} + /> +
+
-- cgit v1.2.3