mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-21 10:16:03 +00:00
fix(tui): preserve shell preview boundaries
This commit is contained in:
@@ -66,7 +66,7 @@ import { useConfig } from "../../config"
|
||||
import { useClipboard } from "../../context/clipboard"
|
||||
import { nextThinkingMode, reasoningSummary, type ThinkingMode } from "../../context/thinking"
|
||||
import { getScrollAcceleration } from "../../util/scroll"
|
||||
import { collapseToolOutput } from "../../util/collapse-tool-output"
|
||||
import { collapseToolOutput, collapseToolOutputParts } from "../../util/collapse-tool-output"
|
||||
import { usePluginRuntime } from "../../plugin/runtime"
|
||||
import { OPENCODE_BASE_MODE, useBindings, useCommandShortcut } from "../../keymap"
|
||||
import { usePathFormatter } from "../../context/path-format"
|
||||
@@ -2384,16 +2384,10 @@ function Shell(props: ToolProps) {
|
||||
const maxLines = 10
|
||||
const maxChars = createMemo(() => maxLines * Math.max(20, ctx.width - 6))
|
||||
const input = createMemo(() => (command() ? `${isRunning() ? "" : "$ "}${command()}` : ""))
|
||||
const content = createMemo(() => [input(), output()].filter(Boolean).join("\n\n"))
|
||||
const collapsed = createMemo(() => collapseToolOutput(content(), maxLines, maxChars()))
|
||||
const collapsed = createMemo(() => collapseToolOutputParts(input(), output(), maxLines, maxChars()))
|
||||
const visible = createMemo(() => {
|
||||
const command = input()
|
||||
if (expanded()) return { input: command, output: output() }
|
||||
const preview = collapsed().overflow ? collapsed().output : content()
|
||||
return {
|
||||
input: preview.slice(0, command.length),
|
||||
output: preview.slice(command.length).replace(/^\n+/, ""),
|
||||
}
|
||||
if (expanded()) return { input: input(), output: output() }
|
||||
return collapsed()
|
||||
})
|
||||
const expandable = createMemo(() => Boolean(shellID()) || collapsed().overflow)
|
||||
const toggle = () => {
|
||||
|
||||
@@ -19,3 +19,26 @@ export function collapseToolOutput(output: string, maxLines: number, maxChars: n
|
||||
|
||||
return { output: preview, overflow: true }
|
||||
}
|
||||
|
||||
export function collapseToolOutputParts(input: string, output: string, maxLines: number, maxChars: number) {
|
||||
const separator = input && output ? "\n\n" : ""
|
||||
const collapsed = collapseToolOutput(`${input}${separator}${output}`, maxLines, maxChars)
|
||||
if (!collapsed.overflow) return { input, output, overflow: false }
|
||||
|
||||
const ellipsis = collapsed.output.endsWith("…") ? "…" : ""
|
||||
const preview = ellipsis ? collapsed.output.slice(0, -1) : collapsed.output
|
||||
const outputStart = input.length + separator.length
|
||||
if (preview.length <= outputStart) {
|
||||
return {
|
||||
input: preview.slice(0, input.length) + ellipsis,
|
||||
output: "",
|
||||
overflow: true,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
input,
|
||||
output: preview.slice(outputStart) + ellipsis,
|
||||
overflow: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { expect, test } from "bun:test"
|
||||
import { collapseToolOutput } from "../../../src/util/collapse-tool-output"
|
||||
import { collapseToolOutput, collapseToolOutputParts } from "../../../src/util/collapse-tool-output"
|
||||
|
||||
test("limits command input and output to the same line budget", () => {
|
||||
const command = Array.from({ length: 8 }, (_, index) => `command ${index + 1}`).join("\n")
|
||||
@@ -12,3 +12,33 @@ test("limits command input and output to the same line budget", () => {
|
||||
expect(collapsed.output).toContain("command 8\n\noutput 1…")
|
||||
expect(collapsed.output).not.toContain("output 2")
|
||||
})
|
||||
|
||||
test.each([
|
||||
{
|
||||
name: "inside the command",
|
||||
maxChars: 5,
|
||||
expected: { input: "$ co…", output: "", overflow: true },
|
||||
},
|
||||
{
|
||||
name: "after the command",
|
||||
maxChars: 10,
|
||||
expected: { input: "$ command…", output: "", overflow: true },
|
||||
},
|
||||
{
|
||||
name: "on the first separator newline",
|
||||
maxChars: 11,
|
||||
expected: { input: "$ command…", output: "", overflow: true },
|
||||
},
|
||||
{
|
||||
name: "on the second separator newline",
|
||||
maxChars: 12,
|
||||
expected: { input: "$ command…", output: "", overflow: true },
|
||||
},
|
||||
{
|
||||
name: "inside the output",
|
||||
maxChars: 15,
|
||||
expected: { input: "$ command", output: "out…", overflow: true },
|
||||
},
|
||||
])("keeps the ellipsis with the visible $name", ({ maxChars, expected }) => {
|
||||
expect(collapseToolOutputParts("$ command", "output", 10, maxChars)).toEqual(expected)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user