feat(tui): add semantic file path truncation (#36352)
This commit is contained in:
parent
5945a8d429
commit
e3f7637eb2
8 changed files with 312 additions and 57 deletions
|
|
@ -4,24 +4,45 @@ import { createMemo, Match, Show, Switch } from "solid-js"
|
|||
import { abbreviateHome } from "../../runtime"
|
||||
import { useTuiPaths } from "../../context/runtime"
|
||||
import { useHomeSessionDestination } from "../../routes/home/session-destination"
|
||||
import { FilePath } from "../../ui/file-path"
|
||||
import { useTerminalDimensions } from "@opentui/solid"
|
||||
|
||||
const id = "internal:home-footer"
|
||||
|
||||
function Directory(props: { api: TuiPluginApi }) {
|
||||
function Directory(props: { api: TuiPluginApi; maxWidth: number }) {
|
||||
const theme = () => props.api.theme.current
|
||||
const destination = useHomeSessionDestination()
|
||||
const paths = useTuiPaths()
|
||||
const dir = createMemo(() => {
|
||||
const selected = destination?.destination()
|
||||
if (!selected || selected.type === "new") return
|
||||
const out = abbreviateHome(selected.directory, paths.home)
|
||||
const branch =
|
||||
selected.directory === (props.api.state.path.directory || paths.cwd) ? props.api.state.vcs?.branch : undefined
|
||||
if (branch) return out + ":" + branch
|
||||
return out
|
||||
return { path: abbreviateHome(selected.directory, paths.home), branch }
|
||||
})
|
||||
|
||||
return <Show when={dir()}>{(value) => <text fg={theme().textMuted}>{value()}</text>}</Show>
|
||||
return (
|
||||
<Show when={dir()}>
|
||||
{(value) => {
|
||||
const suffix = () => (value().branch ? `:${value().branch}` : "")
|
||||
const suffixWidth = () => Math.min(Bun.stringWidth(suffix()), Math.max(0, props.maxWidth - 2))
|
||||
return (
|
||||
<box flexDirection="row" minWidth={0}>
|
||||
<FilePath
|
||||
value={value().path}
|
||||
maxWidth={Math.max(2, props.maxWidth - suffixWidth())}
|
||||
fg={theme().textMuted}
|
||||
/>
|
||||
<Show when={suffix()}>
|
||||
<text width={suffixWidth()} wrapMode="none" truncate fg={theme().textMuted}>
|
||||
{suffix()}
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
)
|
||||
}}
|
||||
</Show>
|
||||
)
|
||||
}
|
||||
|
||||
function Mcp(props: { api: TuiPluginApi }) {
|
||||
|
|
@ -62,6 +83,16 @@ function Version(props: { api: TuiPluginApi }) {
|
|||
}
|
||||
|
||||
function View(props: { api: TuiPluginApi }) {
|
||||
const dimensions = useTerminalDimensions()
|
||||
const mcpWidth = createMemo(() => {
|
||||
const list = props.api.state.mcp()
|
||||
if (list.length === 0) return 0
|
||||
const count = list.filter((item) => item.status === "connected").length
|
||||
return Bun.stringWidth(`⊙ ${count} MCP /status`) + 2
|
||||
})
|
||||
const directoryWidth = createMemo(() =>
|
||||
Math.max(2, dimensions().width - 8 - Bun.stringWidth(props.api.app.version) - mcpWidth()),
|
||||
)
|
||||
return (
|
||||
<box
|
||||
width="100%"
|
||||
|
|
@ -73,7 +104,7 @@ function View(props: { api: TuiPluginApi }) {
|
|||
flexShrink={0}
|
||||
gap={2}
|
||||
>
|
||||
<Directory api={props.api} />
|
||||
<Directory api={props.api} maxWidth={directoryWidth()} />
|
||||
<Mcp api={props.api} />
|
||||
<box flexGrow={1} />
|
||||
<Version api={props.api} />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { TuiPlugin, TuiPluginApi } from "@opencode-ai/plugin/tui"
|
||||
import type { BuiltinTuiPlugin } from "../builtins"
|
||||
import { createMemo, For, Show, createSignal } from "solid-js"
|
||||
import { Locale } from "../../util/locale"
|
||||
import { FilePath } from "../../ui/file-path"
|
||||
|
||||
const id = "internal:sidebar-files"
|
||||
|
||||
|
|
@ -31,9 +31,11 @@ function View(props: { api: TuiPluginApi; session_id: string }) {
|
|||
<For each={list()}>
|
||||
{(item) => (
|
||||
<box flexDirection="row" gap={1} justifyContent="space-between">
|
||||
<text fg={theme().textMuted} wrapMode="none">
|
||||
{Locale.truncateLeft(item.file, Math.max(2, 36 - changeCountWidth(item)))}
|
||||
</text>
|
||||
<FilePath
|
||||
value={item.file}
|
||||
maxWidth={Math.max(2, 36 - changeCountWidth(item))}
|
||||
fg={theme().textMuted}
|
||||
/>
|
||||
<box flexDirection="row" gap={1} flexShrink={0}>
|
||||
<Show when={item.additions}>
|
||||
<text fg={theme().diffAdded}>+{item.additions}</text>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import type { BuiltinTuiPlugin } from "../builtins"
|
|||
import { createMemo, Show } from "solid-js"
|
||||
import { abbreviateHome } from "../../runtime"
|
||||
import { useTuiPaths } from "../../context/runtime"
|
||||
import { FilePath } from "../../ui/file-path"
|
||||
|
||||
const id = "internal:sidebar-footer"
|
||||
|
||||
|
|
@ -16,16 +17,12 @@ function View(props: { api: TuiPluginApi; directory: string }) {
|
|||
)
|
||||
const done = createMemo(() => props.api.kv.get("dismissed_getting_started", false))
|
||||
const show = createMemo(() => !has() && !done())
|
||||
const path = createMemo(() => {
|
||||
const out = abbreviateHome(props.directory, paths.home)
|
||||
const location = createMemo(() => {
|
||||
const branch = props.directory === props.api.state.path.directory ? props.api.state.vcs?.branch : undefined
|
||||
const text = branch ? out + ":" + branch : out
|
||||
const list = text.split("/")
|
||||
return {
|
||||
parent: list.slice(0, -1).join("/"),
|
||||
name: list.at(-1) ?? "",
|
||||
}
|
||||
return { path: abbreviateHome(props.directory, paths.home), branch }
|
||||
})
|
||||
const suffix = createMemo(() => (location().branch ? `:${location().branch}` : ""))
|
||||
const suffixWidth = createMemo(() => Math.min(Bun.stringWidth(suffix()), 36))
|
||||
|
||||
return (
|
||||
<box gap={1}>
|
||||
|
|
@ -62,10 +59,19 @@ function View(props: { api: TuiPluginApi; directory: string }) {
|
|||
</box>
|
||||
</box>
|
||||
</Show>
|
||||
<text>
|
||||
<span style={{ fg: theme().textMuted }}>{path().parent}/</span>
|
||||
<span style={{ fg: theme().text }}>{path().name}</span>
|
||||
</text>
|
||||
<box flexDirection="row" minWidth={0}>
|
||||
<FilePath
|
||||
value={location().path}
|
||||
maxWidth={Math.max(2, 38 - suffixWidth())}
|
||||
fg={theme().textMuted}
|
||||
basenameFg={theme().text}
|
||||
/>
|
||||
<Show when={suffix()}>
|
||||
<text width={suffixWidth()} wrapMode="none" truncate fg={theme().textMuted}>
|
||||
{suffix()}
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
<text fg={theme().textMuted}>
|
||||
<span style={{ fg: theme().success }}>•</span> <b>Open</b>
|
||||
<span style={{ fg: theme().text }}>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue