Compare commits
3 Commits
dev
...
tui-experi
| Author | SHA1 | Date |
|---|---|---|
|
|
b892d91bae | |
|
|
ad110878c9 | |
|
|
572fab3743 |
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"description": "AI-powered development tool",
|
"description": "AI-powered coding assistant that generates perfect code most of the time",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "bun@1.3.10",
|
"packageManager": "bun@1.3.10",
|
||||||
|
|
|
||||||
|
|
@ -814,24 +814,21 @@ export function Prompt(props: PromptProps) {
|
||||||
agentStyleId={agentStyleId}
|
agentStyleId={agentStyleId}
|
||||||
promptPartTypeId={() => promptPartTypeId}
|
promptPartTypeId={() => promptPartTypeId}
|
||||||
/>
|
/>
|
||||||
<box ref={(r) => (anchor = r)} visible={props.visible !== false}>
|
|
||||||
<box
|
<box
|
||||||
|
ref={(r) => (anchor = r)}
|
||||||
|
visible={props.visible !== false}
|
||||||
|
backgroundColor={theme.backgroundElement}
|
||||||
|
paddingBottom={1}
|
||||||
|
paddingLeft={1}
|
||||||
|
paddingRight={2}
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
borderColor={highlight()}
|
borderColor={highlight()}
|
||||||
customBorderChars={{
|
customBorderChars={{
|
||||||
...EmptyBorder,
|
...EmptyBorder,
|
||||||
vertical: "┃",
|
vertical: "▎",
|
||||||
bottomLeft: "╹",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<box
|
<box paddingTop={1} flexShrink={0} flexGrow={1}>
|
||||||
paddingLeft={2}
|
|
||||||
paddingRight={2}
|
|
||||||
paddingTop={1}
|
|
||||||
flexShrink={0}
|
|
||||||
backgroundColor={theme.backgroundElement}
|
|
||||||
flexGrow={1}
|
|
||||||
>
|
|
||||||
<textarea
|
<textarea
|
||||||
placeholder={placeholderText()}
|
placeholder={placeholderText()}
|
||||||
textColor={keybind.leader ? theme.textMuted : theme.text}
|
textColor={keybind.leader ? theme.textMuted : theme.text}
|
||||||
|
|
@ -1010,12 +1007,11 @@ export function Prompt(props: PromptProps) {
|
||||||
cursorColor={theme.text}
|
cursorColor={theme.text}
|
||||||
syntaxStyle={syntax()}
|
syntaxStyle={syntax()}
|
||||||
/>
|
/>
|
||||||
<box flexDirection="row" flexShrink={0} paddingTop={1} gap={1}>
|
<box flexDirection="row" flexShrink={0} paddingTop={1} gap={1} justifyContent="space-between">
|
||||||
<text fg={highlight()}>
|
<Switch>
|
||||||
{store.mode === "shell" ? "Shell" : Locale.titlecase(local.agent.current().name)}{" "}
|
<Match when={store.mode === "normal"}>
|
||||||
</text>
|
|
||||||
<Show when={store.mode === "normal"}>
|
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
|
<text fg={highlight()}>{Locale.titlecase(local.agent.current().name)} </text>
|
||||||
<text flexShrink={0} fg={keybind.leader ? theme.textMuted : theme.text}>
|
<text flexShrink={0} fg={keybind.leader ? theme.textMuted : theme.text}>
|
||||||
{local.model.parsed().model}
|
{local.model.parsed().model}
|
||||||
</text>
|
</text>
|
||||||
|
|
@ -1027,121 +1023,8 @@ export function Prompt(props: PromptProps) {
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
|
||||||
</box>
|
|
||||||
</box>
|
|
||||||
</box>
|
|
||||||
<box
|
|
||||||
height={1}
|
|
||||||
border={["left"]}
|
|
||||||
borderColor={highlight()}
|
|
||||||
customBorderChars={{
|
|
||||||
...EmptyBorder,
|
|
||||||
vertical: theme.backgroundElement.a !== 0 ? "╹" : " ",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<box
|
|
||||||
height={1}
|
|
||||||
border={["bottom"]}
|
|
||||||
borderColor={theme.backgroundElement}
|
|
||||||
customBorderChars={
|
|
||||||
theme.backgroundElement.a !== 0
|
|
||||||
? {
|
|
||||||
...EmptyBorder,
|
|
||||||
horizontal: "▀",
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
...EmptyBorder,
|
|
||||||
horizontal: " ",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</box>
|
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
|
||||||
<Show when={status().type !== "idle"} fallback={<text />}>
|
|
||||||
<box
|
|
||||||
flexDirection="row"
|
|
||||||
gap={1}
|
|
||||||
flexGrow={1}
|
|
||||||
justifyContent={status().type === "retry" ? "space-between" : "flex-start"}
|
|
||||||
>
|
|
||||||
<box flexShrink={0} flexDirection="row" gap={1}>
|
|
||||||
<box marginLeft={1}>
|
|
||||||
<Show when={kv.get("animations_enabled", true)} fallback={<text fg={theme.textMuted}>[⋯]</text>}>
|
|
||||||
<spinner color={spinnerDef().color} frames={spinnerDef().frames} interval={40} />
|
|
||||||
</Show>
|
|
||||||
</box>
|
|
||||||
<box flexDirection="row" gap={1} flexShrink={0}>
|
|
||||||
{(() => {
|
|
||||||
const retry = createMemo(() => {
|
|
||||||
const s = status()
|
|
||||||
if (s.type !== "retry") return
|
|
||||||
return s
|
|
||||||
})
|
|
||||||
const message = createMemo(() => {
|
|
||||||
const r = retry()
|
|
||||||
if (!r) return
|
|
||||||
if (r.message.includes("exceeded your current quota") && r.message.includes("gemini"))
|
|
||||||
return "gemini is way too hot right now"
|
|
||||||
if (r.message.length > 80) return r.message.slice(0, 80) + "..."
|
|
||||||
return r.message
|
|
||||||
})
|
|
||||||
const isTruncated = createMemo(() => {
|
|
||||||
const r = retry()
|
|
||||||
if (!r) return false
|
|
||||||
return r.message.length > 120
|
|
||||||
})
|
|
||||||
const [seconds, setSeconds] = createSignal(0)
|
|
||||||
onMount(() => {
|
|
||||||
const timer = setInterval(() => {
|
|
||||||
const next = retry()?.next
|
|
||||||
if (next) setSeconds(Math.round((next - Date.now()) / 1000))
|
|
||||||
}, 1000)
|
|
||||||
|
|
||||||
onCleanup(() => {
|
|
||||||
clearInterval(timer)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
const handleMessageClick = () => {
|
|
||||||
const r = retry()
|
|
||||||
if (!r) return
|
|
||||||
if (isTruncated()) {
|
|
||||||
DialogAlert.show(dialog, "Retry Error", r.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const retryText = () => {
|
|
||||||
const r = retry()
|
|
||||||
if (!r) return ""
|
|
||||||
const baseMessage = message()
|
|
||||||
const truncatedHint = isTruncated() ? " (click to expand)" : ""
|
|
||||||
const duration = formatDuration(seconds())
|
|
||||||
const retryInfo = ` [retrying ${duration ? `in ${duration} ` : ""}attempt #${r.attempt}]`
|
|
||||||
return baseMessage + truncatedHint + retryInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Show when={retry()}>
|
|
||||||
<box onMouseUp={handleMessageClick}>
|
|
||||||
<text fg={theme.error}>{retryText()}</text>
|
|
||||||
</box>
|
|
||||||
</Show>
|
|
||||||
)
|
|
||||||
})()}
|
|
||||||
</box>
|
|
||||||
</box>
|
|
||||||
<text fg={store.interrupt > 0 ? theme.primary : theme.text}>
|
|
||||||
esc{" "}
|
|
||||||
<span style={{ fg: store.interrupt > 0 ? theme.primary : theme.textMuted }}>
|
|
||||||
{store.interrupt > 0 ? "again to interrupt" : "interrupt"}
|
|
||||||
</span>
|
|
||||||
</text>
|
|
||||||
</box>
|
|
||||||
</Show>
|
|
||||||
<Show when={status().type !== "retry"}>
|
<Show when={status().type !== "retry"}>
|
||||||
<box gap={2} flexDirection="row">
|
<box gap={2} flexDirection="row">
|
||||||
<Switch>
|
|
||||||
<Match when={store.mode === "normal"}>
|
|
||||||
<Show when={local.model.variant.list().length > 0}>
|
<Show when={local.model.variant.list().length > 0}>
|
||||||
<text fg={theme.text}>
|
<text fg={theme.text}>
|
||||||
{keybind.print("variant_cycle")} <span style={{ fg: theme.textMuted }}>variants</span>
|
{keybind.print("variant_cycle")} <span style={{ fg: theme.textMuted }}>variants</span>
|
||||||
|
|
@ -1153,15 +1036,16 @@ export function Prompt(props: PromptProps) {
|
||||||
<text fg={theme.text}>
|
<text fg={theme.text}>
|
||||||
{keybind.print("command_list")} <span style={{ fg: theme.textMuted }}>commands</span>
|
{keybind.print("command_list")} <span style={{ fg: theme.textMuted }}>commands</span>
|
||||||
</text>
|
</text>
|
||||||
|
</box>
|
||||||
|
</Show>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={store.mode === "shell"}>
|
<Match when={store.mode === "shell"}>
|
||||||
<text fg={theme.text}>
|
<text fg={highlight()}>
|
||||||
esc <span style={{ fg: theme.textMuted }}>exit shell mode</span>
|
{store.mode === "shell" ? "Shell" : Locale.titlecase(local.agent.current().name)}{" "}
|
||||||
</text>
|
</text>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -93,9 +93,6 @@ export function Header() {
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
{...SplitBorder}
|
|
||||||
border={["left"]}
|
|
||||||
borderColor={theme.border}
|
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
backgroundColor={theme.backgroundPanel}
|
backgroundColor={theme.backgroundPanel}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import { Dynamic } from "solid-js/web"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { useRoute, useRouteData } from "@tui/context/route"
|
import { useRoute, useRouteData } from "@tui/context/route"
|
||||||
import { useSync } from "@tui/context/sync"
|
import { useSync } from "@tui/context/sync"
|
||||||
import { SplitBorder } from "@tui/component/border"
|
import { EmptyBorder, SplitBorder } from "@tui/component/border"
|
||||||
import { Spinner } from "@tui/component/spinner"
|
import { Spinner } from "@tui/component/spinner"
|
||||||
import { selectedForeground, useTheme } from "@tui/context/theme"
|
import { selectedForeground, useTheme } from "@tui/context/theme"
|
||||||
import {
|
import {
|
||||||
|
|
@ -1046,7 +1046,12 @@ export function Session() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<box flexDirection="row">
|
<box flexDirection="row">
|
||||||
<box flexGrow={1} paddingBottom={1} paddingTop={1} paddingLeft={2} paddingRight={2} gap={1}>
|
<box
|
||||||
|
flexGrow={1}
|
||||||
|
gap={1}
|
||||||
|
paddingX={sidebarVisible() && wide() ? 2 : 0}
|
||||||
|
paddingY={sidebarVisible() && wide() ? 1 : 0}
|
||||||
|
>
|
||||||
<Show when={session()}>
|
<Show when={session()}>
|
||||||
<Show when={showHeader() && (!sidebarVisible() || !wide())}>
|
<Show when={showHeader() && (!sidebarVisible() || !wide())}>
|
||||||
<Header />
|
<Header />
|
||||||
|
|
@ -1057,7 +1062,7 @@ export function Session() {
|
||||||
paddingRight: showScrollbar() ? 1 : 0,
|
paddingRight: showScrollbar() ? 1 : 0,
|
||||||
}}
|
}}
|
||||||
verticalScrollbarOptions={{
|
verticalScrollbarOptions={{
|
||||||
paddingLeft: 1,
|
paddingLeft: 0,
|
||||||
visible: showScrollbar(),
|
visible: showScrollbar(),
|
||||||
trackOptions: {
|
trackOptions: {
|
||||||
backgroundColor: theme.backgroundElement,
|
backgroundColor: theme.backgroundElement,
|
||||||
|
|
@ -1251,13 +1256,7 @@ function UserMessage(props: {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Show when={text()}>
|
<Show when={text()}>
|
||||||
<box
|
<box id={props.message.id} marginTop={props.index === 0 ? 0 : 1}>
|
||||||
id={props.message.id}
|
|
||||||
border={["left"]}
|
|
||||||
borderColor={color()}
|
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
|
||||||
marginTop={props.index === 0 ? 0 : 1}
|
|
||||||
>
|
|
||||||
<box
|
<box
|
||||||
onMouseOver={() => {
|
onMouseOver={() => {
|
||||||
setHover(true)
|
setHover(true)
|
||||||
|
|
@ -1268,9 +1267,15 @@ function UserMessage(props: {
|
||||||
onMouseUp={props.onMouseUp}
|
onMouseUp={props.onMouseUp}
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
backgroundColor={hover() ? theme.backgroundMenu : theme.backgroundMenu}
|
||||||
backgroundColor={hover() ? theme.backgroundElement : theme.backgroundPanel}
|
paddingLeft={1}
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
|
border={["left"]}
|
||||||
|
borderColor={color()}
|
||||||
|
customBorderChars={{
|
||||||
|
...EmptyBorder,
|
||||||
|
vertical: "▎",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<text fg={theme.text}>{text()?.text}</text>
|
<text fg={theme.text}>{text()?.text}</text>
|
||||||
<Show when={files().length}>
|
<Show when={files().length}>
|
||||||
|
|
@ -1331,6 +1336,7 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
|
||||||
const messages = createMemo(() => sync.data.message[props.message.sessionID] ?? [])
|
const messages = createMemo(() => sync.data.message[props.message.sessionID] ?? [])
|
||||||
|
|
||||||
const final = createMemo(() => {
|
const final = createMemo(() => {
|
||||||
|
if (props.message.error) return true
|
||||||
return props.message.finish && !["tool-calls", "unknown"].includes(props.message.finish)
|
return props.message.finish && !["tool-calls", "unknown"].includes(props.message.finish)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -1342,6 +1348,8 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
|
||||||
return props.message.time.completed - user.time.created
|
return props.message.time.completed - user.time.created
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const interrupted = createMemo(() => props.message.error?.name === "MessageAbortedError")
|
||||||
|
|
||||||
const keybind = useKeybind()
|
const keybind = useKeybind()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -1362,14 +1370,14 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
|
||||||
}}
|
}}
|
||||||
</For>
|
</For>
|
||||||
<Show when={props.parts.some((x) => x.type === "tool" && x.tool === "task")}>
|
<Show when={props.parts.some((x) => x.type === "tool" && x.tool === "task")}>
|
||||||
<box paddingTop={1} paddingLeft={3}>
|
<box paddingTop={1} paddingLeft={2}>
|
||||||
<text fg={theme.text}>
|
<text fg={theme.text}>
|
||||||
{keybind.print("session_child_first")}
|
{keybind.print("session_child_first")}
|
||||||
<span style={{ fg: theme.textMuted }}> view subagents</span>
|
<span style={{ fg: theme.textMuted }}> view subagents</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={props.message.error && props.message.error.name !== "MessageAbortedError"}>
|
<Show when={props.message.error && !interrupted()}>
|
||||||
<box
|
<box
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
|
|
@ -1384,28 +1392,26 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={props.last || final() || props.message.error?.name === "MessageAbortedError"}>
|
<Match when={props.last || final()}>
|
||||||
<box paddingLeft={3}>
|
<box paddingLeft={2} marginTop={1}>
|
||||||
<text marginTop={1}>
|
<Show when={!duration()}>
|
||||||
<span
|
<Spinner color={local.agent.color(props.message.agent)}>
|
||||||
style={{
|
|
||||||
fg:
|
|
||||||
props.message.error?.name === "MessageAbortedError"
|
|
||||||
? theme.textMuted
|
|
||||||
: local.agent.color(props.message.agent),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
▣{" "}
|
|
||||||
</span>{" "}
|
|
||||||
<span style={{ fg: theme.text }}>{Locale.titlecase(props.message.mode)}</span>
|
<span style={{ fg: theme.text }}>{Locale.titlecase(props.message.mode)}</span>
|
||||||
<span style={{ fg: theme.textMuted }}> · {props.message.modelID}</span>
|
<span style={{ fg: theme.textMuted }}> · {props.message.modelID}</span>
|
||||||
|
</Spinner>
|
||||||
|
</Show>
|
||||||
<Show when={duration()}>
|
<Show when={duration()}>
|
||||||
|
<text fg={interrupted() ? theme.textMuted : theme.text}>
|
||||||
|
<span style={{ fg: theme.text }}>{Locale.titlecase(props.message.mode)}</span>
|
||||||
|
<span style={{ fg: theme.textMuted }}> · {props.message.modelID}</span>
|
||||||
|
<Show when={!interrupted()}>
|
||||||
<span style={{ fg: theme.textMuted }}> · {Locale.duration(duration())}</span>
|
<span style={{ fg: theme.textMuted }}> · {Locale.duration(duration())}</span>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={props.message.error?.name === "MessageAbortedError"}>
|
<Show when={interrupted()}>
|
||||||
<span style={{ fg: theme.textMuted }}> · interrupted</span>
|
<span style={{ fg: theme.textMuted }}> · interrupted</span>
|
||||||
</Show>
|
</Show>
|
||||||
</text>
|
</text>
|
||||||
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
@ -1457,7 +1463,7 @@ function TextPart(props: { last: boolean; part: TextPart; message: AssistantMess
|
||||||
const { theme, syntax } = useTheme()
|
const { theme, syntax } = useTheme()
|
||||||
return (
|
return (
|
||||||
<Show when={props.part.text.trim()}>
|
<Show when={props.part.text.trim()}>
|
||||||
<box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0}>
|
<box id={"text-" + props.part.id} paddingLeft={2} marginTop={1} flexShrink={0}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={Flag.OPENCODE_EXPERIMENTAL_MARKDOWN}>
|
<Match when={Flag.OPENCODE_EXPERIMENTAL_MARKDOWN}>
|
||||||
<markdown
|
<markdown
|
||||||
|
|
@ -1625,7 +1631,7 @@ function GenericTool(props: ToolProps<any>) {
|
||||||
function ToolTitle(props: { fallback: string; when: any; icon: string; children: JSX.Element }) {
|
function ToolTitle(props: { fallback: string; when: any; icon: string; children: JSX.Element }) {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
return (
|
return (
|
||||||
<text paddingLeft={3} fg={props.when ? theme.textMuted : theme.text}>
|
<text paddingLeft={2} fg={props.when ? theme.textMuted : theme.text}>
|
||||||
<Show fallback={<>~ {props.fallback}</>} when={props.when}>
|
<Show fallback={<>~ {props.fallback}</>} when={props.when}>
|
||||||
<span style={{ bold: true }}>{props.icon}</span> {props.children}
|
<span style={{ bold: true }}>{props.icon}</span> {props.children}
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -1676,7 +1682,7 @@ function InlineTool(props: {
|
||||||
return (
|
return (
|
||||||
<box
|
<box
|
||||||
marginTop={margin()}
|
marginTop={margin()}
|
||||||
paddingLeft={3}
|
paddingLeft={2}
|
||||||
onMouseOver={() => props.onClick && setHover(true)}
|
onMouseOver={() => props.onClick && setHover(true)}
|
||||||
onMouseOut={() => setHover(false)}
|
onMouseOut={() => setHover(false)}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
|
|
@ -1711,7 +1717,7 @@ function InlineTool(props: {
|
||||||
<Spinner color={fg()} children={props.children} />
|
<Spinner color={fg()} children={props.children} />
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
<text paddingLeft={3} fg={fg()} attributes={denied() ? TextAttributes.STRIKETHROUGH : undefined}>
|
<text paddingLeft={2} fg={fg()} attributes={denied() ? TextAttributes.STRIKETHROUGH : undefined}>
|
||||||
<Show fallback={<>~ {props.pending}</>} when={props.complete}>
|
<Show fallback={<>~ {props.pending}</>} when={props.complete}>
|
||||||
<span style={{ fg: props.iconColor }}>{props.icon}</span> {props.children}
|
<span style={{ fg: props.iconColor }}>{props.icon}</span> {props.children}
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -1738,15 +1744,13 @@ function BlockTool(props: {
|
||||||
const error = createMemo(() => (props.part?.state.status === "error" ? props.part.state.error : undefined))
|
const error = createMemo(() => (props.part?.state.status === "error" ? props.part.state.error : undefined))
|
||||||
return (
|
return (
|
||||||
<box
|
<box
|
||||||
border={["left"]}
|
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
|
marginTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
marginTop={1}
|
paddingRight={2}
|
||||||
gap={1}
|
gap={1}
|
||||||
backgroundColor={hover() ? theme.backgroundMenu : theme.backgroundPanel}
|
backgroundColor={hover() ? theme.backgroundElement : theme.backgroundPanel}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
|
||||||
borderColor={theme.background}
|
|
||||||
onMouseOver={() => props.onClick && setHover(true)}
|
onMouseOver={() => props.onClick && setHover(true)}
|
||||||
onMouseOut={() => setHover(false)}
|
onMouseOut={() => setHover(false)}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
|
|
@ -1757,7 +1761,7 @@ function BlockTool(props: {
|
||||||
<Show
|
<Show
|
||||||
when={props.spinner}
|
when={props.spinner}
|
||||||
fallback={
|
fallback={
|
||||||
<text paddingLeft={3} fg={theme.textMuted}>
|
<text paddingLeft={2} fg={theme.textMuted}>
|
||||||
{props.title}
|
{props.title}
|
||||||
</text>
|
</text>
|
||||||
}
|
}
|
||||||
|
|
@ -1905,8 +1909,8 @@ function Read(props: ToolProps<typeof ReadTool>) {
|
||||||
</InlineTool>
|
</InlineTool>
|
||||||
<For each={loaded()}>
|
<For each={loaded()}>
|
||||||
{(filepath) => (
|
{(filepath) => (
|
||||||
<box paddingLeft={3}>
|
<box paddingLeft={2}>
|
||||||
<text paddingLeft={3} fg={theme.textMuted}>
|
<text paddingLeft={2} fg={theme.textMuted}>
|
||||||
↳ Loaded {normalizePath(filepath)}
|
↳ Loaded {normalizePath(filepath)}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -2056,7 +2060,7 @@ function Edit(props: ToolProps<typeof EditTool>) {
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={props.metadata.diff !== undefined}>
|
<Match when={props.metadata.diff !== undefined}>
|
||||||
<BlockTool title={"← Edit " + normalizePath(props.input.filePath!)} part={props.part}>
|
<BlockTool title={"← Edit " + normalizePath(props.input.filePath!)} part={props.part}>
|
||||||
<box paddingLeft={1}>
|
<box>
|
||||||
<diff
|
<diff
|
||||||
diff={diffContent()}
|
diff={diffContent()}
|
||||||
view={view()}
|
view={view()}
|
||||||
|
|
@ -2066,6 +2070,7 @@ function Edit(props: ToolProps<typeof EditTool>) {
|
||||||
width="100%"
|
width="100%"
|
||||||
wrapMode={ctx.diffWrapMode()}
|
wrapMode={ctx.diffWrapMode()}
|
||||||
fg={theme.text}
|
fg={theme.text}
|
||||||
|
bg={theme.background}
|
||||||
addedBg={theme.diffAddedBg}
|
addedBg={theme.diffAddedBg}
|
||||||
removedBg={theme.diffRemovedBg}
|
removedBg={theme.diffRemovedBg}
|
||||||
contextBg={theme.diffContextBg}
|
contextBg={theme.diffContextBg}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue