mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-24 19:24:22 +01:00
wip: desktop work
This commit is contained in:
@@ -2,7 +2,7 @@ import { bundledLanguages, type BundledLanguage, type ShikiTransformer } from "s
|
||||
import { splitProps, type ComponentProps, createEffect, onMount, onCleanup, createMemo, createResource } from "solid-js"
|
||||
import { useLocal, type TextSelection } from "@/context/local"
|
||||
import { getFileExtension, getNodeOffsetInLine, getSelectionInContainer } from "@/utils"
|
||||
import { useShiki } from "@/context/shiki"
|
||||
import { useShiki } from "@opencode-ai/ui"
|
||||
|
||||
type DefinedSelection = Exclude<TextSelection, undefined>
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { useMarked } from "@/context/marked"
|
||||
import { createResource } from "solid-js"
|
||||
|
||||
function strip(text: string): string {
|
||||
const wrappedRe = /^\s*<([A-Za-z]\w*)>\s*([\s\S]*?)\s*<\/\1>\s*$/
|
||||
const match = text.match(wrappedRe)
|
||||
return match ? match[2] : text
|
||||
}
|
||||
export function Markdown(props: { text: string; class?: string }) {
|
||||
const marked = useMarked()
|
||||
const [html] = createResource(
|
||||
() => strip(props.text),
|
||||
async (markdown) => {
|
||||
return marked.parse(markdown)
|
||||
},
|
||||
)
|
||||
return (
|
||||
<div
|
||||
class={`min-w-0 max-w-full overflow-auto no-scrollbar text-14-regular text-text-base ${props.class ?? ""}`}
|
||||
innerHTML={html()}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,304 +0,0 @@
|
||||
import type { Part, TextPart, ToolPart, Message } from "@opencode-ai/sdk"
|
||||
import { createMemo, For, Match, Show, Switch } from "solid-js"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
import { Markdown } from "./markdown"
|
||||
import { Card, Checkbox, Diff, Icon } from "@opencode-ai/ui"
|
||||
import { Message as MessageDisplay, registerPartComponent } from "@opencode-ai/ui"
|
||||
import { BasicTool, GenericTool, ToolRegistry, DiffChanges } from "@opencode-ai/ui"
|
||||
import { getDirectory, getFilename } from "@/utils"
|
||||
|
||||
export function Message(props: { message: Message; parts: Part[] }) {
|
||||
return <MessageDisplay message={props.message} parts={props.parts} />
|
||||
}
|
||||
|
||||
registerPartComponent("text", function TextPartDisplay(props) {
|
||||
const part = props.part as TextPart
|
||||
return (
|
||||
<Show when={part.text.trim()}>
|
||||
<Markdown text={part.text.trim()} class="mt-8" />
|
||||
</Show>
|
||||
)
|
||||
})
|
||||
|
||||
registerPartComponent("reasoning", function ReasoningPartDisplay(props) {
|
||||
const part = props.part as any
|
||||
return (
|
||||
<Show when={part.text.trim()}>
|
||||
<Markdown text={part.text.trim()} />
|
||||
</Show>
|
||||
)
|
||||
})
|
||||
|
||||
registerPartComponent("tool", function ToolPartDisplay(props) {
|
||||
const part = props.part as ToolPart
|
||||
const component = createMemo(() => {
|
||||
const render = ToolRegistry.render(part.tool) ?? GenericTool
|
||||
const metadata = part.state.status === "pending" ? {} : (part.state.metadata ?? {})
|
||||
const input = part.state.status === "completed" ? part.state.input : {}
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={part.state.status === "error" && part.state.error}>
|
||||
{(error) => {
|
||||
const cleaned = error().replace("Error: ", "")
|
||||
const [title, ...rest] = cleaned.split(": ")
|
||||
return (
|
||||
<Card variant="error">
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon name="circle-ban-sign" size="small" class="text-icon-critical-active" />
|
||||
<Switch>
|
||||
<Match when={title}>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="text-12-medium text-[var(--ember-light-11)] capitalize">{title}</div>
|
||||
<span>{rest.join(": ")}</span>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={true}>{cleaned}</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}}
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<Dynamic
|
||||
component={render}
|
||||
input={input}
|
||||
tool={part.tool}
|
||||
metadata={metadata}
|
||||
output={part.state.status === "completed" ? part.state.output : undefined}
|
||||
hideDetails={props.hideDetails}
|
||||
/>
|
||||
</Match>
|
||||
</Switch>
|
||||
)
|
||||
})
|
||||
|
||||
return <Show when={component()}>{component()}</Show>
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "read",
|
||||
render(props) {
|
||||
return (
|
||||
<BasicTool
|
||||
icon="glasses"
|
||||
trigger={{ title: "Read", subtitle: props.input.filePath ? getFilename(props.input.filePath) : "" }}
|
||||
/>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "list",
|
||||
render(props) {
|
||||
return (
|
||||
<BasicTool icon="bullet-list" trigger={{ title: "List", subtitle: getDirectory(props.input.path || "/") }}>
|
||||
<Show when={false && props.output}>
|
||||
<div class="whitespace-pre">{props.output}</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "glob",
|
||||
render(props) {
|
||||
return (
|
||||
<BasicTool
|
||||
icon="magnifying-glass-menu"
|
||||
trigger={{
|
||||
title: "Glob",
|
||||
subtitle: getDirectory(props.input.path || "/"),
|
||||
args: props.input.pattern ? ["pattern=" + props.input.pattern] : [],
|
||||
}}
|
||||
>
|
||||
<Show when={false && props.output}>
|
||||
<div class="whitespace-pre">{props.output}</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "grep",
|
||||
render(props) {
|
||||
const args = []
|
||||
if (props.input.pattern) args.push("pattern=" + props.input.pattern)
|
||||
if (props.input.include) args.push("include=" + props.input.include)
|
||||
return (
|
||||
<BasicTool
|
||||
icon="magnifying-glass-menu"
|
||||
trigger={{
|
||||
title: "Grep",
|
||||
subtitle: getDirectory(props.input.path || "/"),
|
||||
args,
|
||||
}}
|
||||
>
|
||||
<Show when={false && props.output}>
|
||||
<div class="whitespace-pre">{props.output}</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "webfetch",
|
||||
render(props) {
|
||||
return (
|
||||
<BasicTool
|
||||
icon="window-cursor"
|
||||
trigger={{
|
||||
title: "Webfetch",
|
||||
subtitle: props.input.url || "",
|
||||
args: props.input.format ? ["format=" + props.input.format] : [],
|
||||
action: (
|
||||
<div class="size-6 flex items-center justify-center">
|
||||
<Icon name="square-arrow-top-right" size="small" />
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Show when={false && props.output}>
|
||||
<div class="whitespace-pre">{props.output}</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "task",
|
||||
render(props) {
|
||||
return (
|
||||
<BasicTool
|
||||
icon="task"
|
||||
trigger={{
|
||||
title: `${props.input.subagent_type || props.tool} Agent`,
|
||||
titleClass: "capitalize",
|
||||
subtitle: props.input.description,
|
||||
}}
|
||||
>
|
||||
<Show when={false && props.output}>
|
||||
<div class="whitespace-pre">{props.output}</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "bash",
|
||||
render(props) {
|
||||
return (
|
||||
<BasicTool
|
||||
icon="console"
|
||||
trigger={{
|
||||
title: "Shell",
|
||||
subtitle: "Ran " + props.input.command,
|
||||
}}
|
||||
>
|
||||
<Show when={false && props.output}>
|
||||
<div class="whitespace-pre">{props.output}</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "edit",
|
||||
render(props) {
|
||||
return (
|
||||
<BasicTool
|
||||
icon="code-lines"
|
||||
trigger={
|
||||
<div class="flex items-center justify-between w-full">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="text-12-medium text-text-base capitalize">Edit</div>
|
||||
<div class="flex">
|
||||
<Show when={props.input.filePath?.includes("/")}>
|
||||
<span class="text-text-weak">{getDirectory(props.input.filePath!)}</span>
|
||||
</Show>
|
||||
<span class="text-text-strong">{getFilename(props.input.filePath ?? "")}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-4 items-center justify-end">
|
||||
<Show when={props.metadata.filediff}>
|
||||
<DiffChanges diff={props.metadata.filediff} />
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Show when={props.metadata.filediff}>
|
||||
<div class="border-t border-border-weaker-base">
|
||||
<Diff
|
||||
before={{ name: getFilename(props.metadata.filediff.path), contents: props.metadata.filediff.before }}
|
||||
after={{ name: getFilename(props.metadata.filediff.path), contents: props.metadata.filediff.after }}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "write",
|
||||
render(props) {
|
||||
return (
|
||||
<BasicTool
|
||||
icon="code-lines"
|
||||
trigger={
|
||||
<div class="flex items-center justify-between w-full">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="text-12-medium text-text-base capitalize">Write</div>
|
||||
<div class="flex">
|
||||
<Show when={props.input.filePath?.includes("/")}>
|
||||
<span class="text-text-weak">{getDirectory(props.input.filePath!)}</span>
|
||||
</Show>
|
||||
<span class="text-text-strong">{getFilename(props.input.filePath ?? "")}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-4 items-center justify-end">{/* <DiffChanges diff={diff} /> */}</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Show when={false && props.output}>
|
||||
<div class="whitespace-pre">{props.output}</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
ToolRegistry.register({
|
||||
name: "todowrite",
|
||||
render(props) {
|
||||
return (
|
||||
<BasicTool
|
||||
icon="checklist"
|
||||
trigger={{
|
||||
title: "To-dos",
|
||||
subtitle: `${props.input.todos?.filter((t: any) => t.status === "completed").length}/${props.input.todos?.length}`,
|
||||
}}
|
||||
>
|
||||
<Show when={props.input.todos?.length}>
|
||||
<div class="px-12 pt-2.5 pb-6 flex flex-col gap-2">
|
||||
<For each={props.input.todos}>
|
||||
{(todo: any) => (
|
||||
<Checkbox readOnly checked={todo.status === "completed"}>
|
||||
<div classList={{ "line-through text-text-weaker": todo.status === "completed" }}>{todo.content}</div>
|
||||
</Checkbox>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -480,8 +480,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
const getMessageText = (message: Message | Message[] | undefined): string => {
|
||||
if (!message) return ""
|
||||
if (Array.isArray(message)) return message.map((m) => getMessageText(m)).join(" ")
|
||||
const fileParts = sync.data.part[message.id]?.filter((p) => p.type === "file")
|
||||
|
||||
return sync.data.part[message.id]
|
||||
?.filter((p) => p.type === "text")
|
||||
?.filter((p) => !p.synthetic)
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { marked } from "marked"
|
||||
import markedShiki from "marked-shiki"
|
||||
import { bundledLanguages, type BundledLanguage } from "shiki"
|
||||
|
||||
import { createSimpleContext } from "./helper"
|
||||
import { useShiki } from "./shiki"
|
||||
|
||||
export const { use: useMarked, provider: MarkedProvider } = createSimpleContext({
|
||||
name: "Marked",
|
||||
init: () => {
|
||||
const highlighter = useShiki()
|
||||
return marked.use(
|
||||
markedShiki({
|
||||
async highlight(code, lang) {
|
||||
if (!(lang in bundledLanguages)) {
|
||||
lang = "text"
|
||||
}
|
||||
if (!highlighter.getLoadedLanguages().includes(lang)) {
|
||||
await highlighter.loadLanguage(lang as BundledLanguage)
|
||||
}
|
||||
return highlighter.codeToHtml(code, {
|
||||
lang: lang || "text",
|
||||
theme: "opencode",
|
||||
tabindex: false,
|
||||
})
|
||||
},
|
||||
}),
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -1,573 +0,0 @@
|
||||
import { createSimpleContext } from "./helper"
|
||||
import { createHighlighter, type ThemeInput } from "shiki"
|
||||
|
||||
const theme: ThemeInput = {
|
||||
colors: {
|
||||
"actionBar.toggledBackground": "var(--surface-raised-base)",
|
||||
"activityBarBadge.background": "var(--surface-brand-base)",
|
||||
"checkbox.border": "var(--border-base)",
|
||||
"editor.background": "transparent",
|
||||
"editor.foreground": "var(--text-base)",
|
||||
"editor.inactiveSelectionBackground": "var(--surface-raised-base)",
|
||||
"editor.selectionHighlightBackground": "var(--border-active)",
|
||||
"editorIndentGuide.activeBackground1": "var(--border-weak-base)",
|
||||
"editorIndentGuide.background1": "var(--border-weak-base)",
|
||||
"input.placeholderForeground": "var(--text-weak)",
|
||||
"list.activeSelectionIconForeground": "var(--text-base)",
|
||||
"list.dropBackground": "var(--surface-raised-base)",
|
||||
"menu.background": "var(--surface-base)",
|
||||
"menu.border": "var(--border-base)",
|
||||
"menu.foreground": "var(--text-base)",
|
||||
"menu.selectionBackground": "var(--surface-interactive-base)",
|
||||
"menu.separatorBackground": "var(--border-base)",
|
||||
"ports.iconRunningProcessForeground": "var(--icon-success-base)",
|
||||
"sideBarSectionHeader.background": "transparent",
|
||||
"sideBarSectionHeader.border": "var(--border-weak-base)",
|
||||
"sideBarTitle.foreground": "var(--text-weak)",
|
||||
"statusBarItem.remoteBackground": "var(--surface-success-base)",
|
||||
"statusBarItem.remoteForeground": "var(--text-base)",
|
||||
"tab.lastPinnedBorder": "var(--border-weak-base)",
|
||||
"tab.selectedBackground": "var(--surface-raised-base)",
|
||||
"tab.selectedForeground": "var(--text-weak)",
|
||||
"terminal.inactiveSelectionBackground": "var(--surface-raised-base)",
|
||||
"widget.border": "var(--border-base)",
|
||||
},
|
||||
displayName: "opencode",
|
||||
name: "opencode",
|
||||
semanticHighlighting: true,
|
||||
semanticTokenColors: {
|
||||
customLiteral: "var(--syntax-function)",
|
||||
newOperator: "var(--syntax-operator)",
|
||||
numberLiteral: "var(--syntax-number)",
|
||||
stringLiteral: "var(--syntax-string)",
|
||||
},
|
||||
tokenColors: [
|
||||
{
|
||||
scope: [
|
||||
"meta.embedded",
|
||||
"source.groovy.embedded",
|
||||
"string meta.image.inline.markdown",
|
||||
"variable.legacy.builtin.python",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--text-base)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "emphasis",
|
||||
settings: {
|
||||
fontStyle: "italic",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "strong",
|
||||
settings: {
|
||||
fontStyle: "bold",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "header",
|
||||
settings: {
|
||||
foreground: "var(--markdown-heading)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "comment",
|
||||
settings: {
|
||||
foreground: "var(--syntax-comment)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "constant.language",
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"constant.numeric",
|
||||
"variable.other.enummember",
|
||||
"keyword.operator.plus.exponent",
|
||||
"keyword.operator.minus.exponent",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-number)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "constant.regexp",
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "entity.name.tag",
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["entity.name.tag.css", "entity.name.tag.less"],
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "entity.other.attribute-name",
|
||||
settings: {
|
||||
foreground: "var(--syntax-variable)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"entity.other.attribute-name.class.css",
|
||||
"source.css entity.other.attribute-name.class",
|
||||
"entity.other.attribute-name.id.css",
|
||||
"entity.other.attribute-name.parent-selector.css",
|
||||
"entity.other.attribute-name.parent.less",
|
||||
"source.css entity.other.attribute-name.pseudo-class",
|
||||
"entity.other.attribute-name.pseudo-element.css",
|
||||
"source.css.less entity.other.attribute-name.id",
|
||||
"entity.other.attribute-name.scss",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "invalid",
|
||||
settings: {
|
||||
foreground: "var(--syntax-critical)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "markup.underline",
|
||||
settings: {
|
||||
fontStyle: "underline",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "markup.bold",
|
||||
settings: {
|
||||
fontStyle: "bold",
|
||||
foreground: "var(--markdown-strong)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "markup.heading",
|
||||
settings: {
|
||||
fontStyle: "bold",
|
||||
foreground: "var(--theme-markdown-heading)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "markup.italic",
|
||||
settings: {
|
||||
fontStyle: "italic",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "markup.strikethrough",
|
||||
settings: {
|
||||
fontStyle: "strikethrough",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "markup.inserted",
|
||||
settings: {
|
||||
foreground: "var(--text-diff-add-base)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "markup.deleted",
|
||||
settings: {
|
||||
foreground: "var(--text-diff-delete-base)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "markup.changed",
|
||||
settings: {
|
||||
foreground: "var(--text-base)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "punctuation.definition.quote.begin.markdown",
|
||||
settings: {
|
||||
foreground: "var(--markdown-block-quote)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "punctuation.definition.list.begin.markdown",
|
||||
settings: {
|
||||
foreground: "var(--markdown-list-enumeration)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "markup.inline.raw",
|
||||
settings: {
|
||||
foreground: "var(--markdown-code)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "punctuation.definition.tag",
|
||||
settings: {
|
||||
foreground: "var(--syntax-punctuation)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["meta.preprocessor", "entity.name.function.preprocessor"],
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "meta.preprocessor.string",
|
||||
settings: {
|
||||
foreground: "var(--syntax-string)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "meta.preprocessor.numeric",
|
||||
settings: {
|
||||
foreground: "var(--syntax-number)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "meta.structure.dictionary.key.python",
|
||||
settings: {
|
||||
foreground: "var(--syntax-variable)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "meta.diff.header",
|
||||
settings: {
|
||||
foreground: "var(--text-weak)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "storage",
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "storage.type",
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["storage.modifier", "keyword.operator.noexcept"],
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["string", "meta.embedded.assembly"],
|
||||
settings: {
|
||||
foreground: "var(--syntax-string)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "string.tag",
|
||||
settings: {
|
||||
foreground: "var(--syntax-string)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "string.value",
|
||||
settings: {
|
||||
foreground: "var(--syntax-string)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "string.regexp",
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"punctuation.definition.template-expression.begin",
|
||||
"punctuation.definition.template-expression.end",
|
||||
"punctuation.section.embedded",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["meta.template.expression"],
|
||||
settings: {
|
||||
foreground: "var(--text-base)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"support.type.vendored.property-name",
|
||||
"support.type.property-name",
|
||||
"source.css variable",
|
||||
"source.coffee.embedded",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-variable)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "keyword",
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "keyword.control",
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "keyword.operator",
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"keyword.operator.new",
|
||||
"keyword.operator.expression",
|
||||
"keyword.operator.cast",
|
||||
"keyword.operator.sizeof",
|
||||
"keyword.operator.alignof",
|
||||
"keyword.operator.typeid",
|
||||
"keyword.operator.alignas",
|
||||
"keyword.operator.instanceof",
|
||||
"keyword.operator.logical.python",
|
||||
"keyword.operator.wordlike",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "keyword.other.unit",
|
||||
settings: {
|
||||
foreground: "var(--syntax-number)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["punctuation.section.embedded.begin.php", "punctuation.section.embedded.end.php"],
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "support.function.git-rebase",
|
||||
settings: {
|
||||
foreground: "var(--syntax-variable)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "constant.sha.git-rebase",
|
||||
settings: {
|
||||
foreground: "var(--syntax-number)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["storage.modifier.import.java", "variable.language.wildcard.java", "storage.modifier.package.java"],
|
||||
settings: {
|
||||
foreground: "var(--text-base)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "variable.language",
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"entity.name.function",
|
||||
"support.function",
|
||||
"support.constant.handlebars",
|
||||
"source.powershell variable.other.member",
|
||||
"entity.name.operator.custom-literal",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-function)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"support.class",
|
||||
"support.type",
|
||||
"entity.name.type",
|
||||
"entity.name.namespace",
|
||||
"entity.other.attribute",
|
||||
"entity.name.scope-resolution",
|
||||
"entity.name.class",
|
||||
"storage.type.numeric.go",
|
||||
"storage.type.byte.go",
|
||||
"storage.type.boolean.go",
|
||||
"storage.type.string.go",
|
||||
"storage.type.uintptr.go",
|
||||
"storage.type.error.go",
|
||||
"storage.type.rune.go",
|
||||
"storage.type.cs",
|
||||
"storage.type.generic.cs",
|
||||
"storage.type.modifier.cs",
|
||||
"storage.type.variable.cs",
|
||||
"storage.type.annotation.java",
|
||||
"storage.type.generic.java",
|
||||
"storage.type.java",
|
||||
"storage.type.object.array.java",
|
||||
"storage.type.primitive.array.java",
|
||||
"storage.type.primitive.java",
|
||||
"storage.type.token.java",
|
||||
"storage.type.groovy",
|
||||
"storage.type.annotation.groovy",
|
||||
"storage.type.parameters.groovy",
|
||||
"storage.type.generic.groovy",
|
||||
"storage.type.object.array.groovy",
|
||||
"storage.type.primitive.array.groovy",
|
||||
"storage.type.primitive.groovy",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-type)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"meta.type.cast.expr",
|
||||
"meta.type.new.expr",
|
||||
"support.constant.math",
|
||||
"support.constant.dom",
|
||||
"support.constant.json",
|
||||
"entity.other.inherited-class",
|
||||
"punctuation.separator.namespace.ruby",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-type)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"keyword.control",
|
||||
"source.cpp keyword.operator.new",
|
||||
"keyword.operator.delete",
|
||||
"keyword.other.using",
|
||||
"keyword.other.directive.using",
|
||||
"keyword.other.operator",
|
||||
"entity.name.operator",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"variable",
|
||||
"meta.definition.variable.name",
|
||||
"support.variable",
|
||||
"entity.name.variable",
|
||||
"constant.other.placeholder",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-variable)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["variable.other.constant", "variable.other.enummember"],
|
||||
settings: {
|
||||
foreground: "var(--syntax-variable)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["meta.object-literal.key"],
|
||||
settings: {
|
||||
foreground: "var(--syntax-variable)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"support.constant.property-value",
|
||||
"support.constant.font-name",
|
||||
"support.constant.media-type",
|
||||
"support.constant.media",
|
||||
"constant.other.color.rgb-value",
|
||||
"constant.other.rgb-value",
|
||||
"support.constant.color",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-string)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"punctuation.definition.group.regexp",
|
||||
"punctuation.definition.group.assertion.regexp",
|
||||
"punctuation.definition.character-class.regexp",
|
||||
"punctuation.character.set.begin.regexp",
|
||||
"punctuation.character.set.end.regexp",
|
||||
"keyword.operator.negation.regexp",
|
||||
"support.other.parenthesis.regexp",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-string)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: [
|
||||
"constant.character.character-class.regexp",
|
||||
"constant.other.character-class.set.regexp",
|
||||
"constant.other.character-class.regexp",
|
||||
"constant.character.set.regexp",
|
||||
],
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["keyword.operator.or.regexp", "keyword.control.anchor.regexp"],
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "keyword.operator.quantifier.regexp",
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: ["constant.character", "constant.other.option"],
|
||||
settings: {
|
||||
foreground: "var(--syntax-keyword)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "constant.character.escape",
|
||||
settings: {
|
||||
foreground: "var(--syntax-operator)",
|
||||
},
|
||||
},
|
||||
{
|
||||
scope: "entity.name.label",
|
||||
settings: {
|
||||
foreground: "var(--text-weak)",
|
||||
},
|
||||
},
|
||||
],
|
||||
type: "dark",
|
||||
}
|
||||
|
||||
const highlighter = await createHighlighter({
|
||||
themes: [theme],
|
||||
langs: [],
|
||||
})
|
||||
|
||||
export const { use: useShiki, provider: ShikiProvider } = createSimpleContext({
|
||||
name: "Shiki",
|
||||
init: () => {
|
||||
return highlighter
|
||||
},
|
||||
})
|
||||
@@ -3,9 +3,7 @@ import "@/index.css"
|
||||
import { render } from "solid-js/web"
|
||||
import { Router, Route } from "@solidjs/router"
|
||||
import { MetaProvider } from "@solidjs/meta"
|
||||
import { Fonts } from "@opencode-ai/ui"
|
||||
import { ShikiProvider } from "./context/shiki"
|
||||
import { MarkedProvider } from "./context/marked"
|
||||
import { Fonts, ShikiProvider, MarkedProvider } from "@opencode-ai/ui"
|
||||
import { SDKProvider } from "./context/sdk"
|
||||
import { SyncProvider } from "./context/sync"
|
||||
import { LocalProvider } from "./context/local"
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
Part,
|
||||
DiffChanges,
|
||||
ProgressCircle,
|
||||
Message,
|
||||
} from "@opencode-ai/ui"
|
||||
import { FileIcon } from "@/ui"
|
||||
import FileTree from "@/components/file-tree"
|
||||
@@ -35,9 +36,8 @@ import type { JSX } from "solid-js"
|
||||
import { Code } from "@/components/code"
|
||||
import { useSync } from "@/context/sync"
|
||||
import { useSDK } from "@/context/sdk"
|
||||
import { Message } from "@/components/message"
|
||||
import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk"
|
||||
import { Markdown } from "@/components/markdown"
|
||||
import { Markdown } from "@opencode-ai/ui"
|
||||
|
||||
export default function Page() {
|
||||
const local = useLocal()
|
||||
|
||||
Reference in New Issue
Block a user