mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
fix(ui): harden shell highlighting rendering
This commit is contained in:
@@ -251,7 +251,7 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] {
|
||||
[data-component="shell-expanded-output"] .shiki code {
|
||||
font-family: var(--font-family-mono);
|
||||
font-feature-settings: var(--font-family-mono--font-feature-settings);
|
||||
font-size: 13px;
|
||||
font-size: var(--font-size-small);
|
||||
line-height: var(--line-height-large);
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
|
||||
@@ -2053,13 +2053,14 @@ function BashCopyButton(props: { value: () => string; label: string }) {
|
||||
)
|
||||
}
|
||||
|
||||
function BashHighlightedOutput(props: { cmd: string; output: string; outputPath?: string }) {
|
||||
function BashHighlightedOutput(props: { cmd: string; output: string; outputPath?: string; active?: boolean }) {
|
||||
const data = useData()
|
||||
const i18n = useI18n()
|
||||
let cmdRef: HTMLDivElement | undefined
|
||||
let outRef: HTMLDivElement | undefined
|
||||
|
||||
createEffect(() => {
|
||||
if (!props.active) return
|
||||
const cmd = props.cmd
|
||||
if (!cmdRef || !cmd) return
|
||||
cmdRef.innerHTML = `<pre data-slot="bash-pre"><code data-lang="shellscript">${escapeHtml(cmd)}</code></pre>`
|
||||
@@ -2067,6 +2068,7 @@ function BashHighlightedOutput(props: { cmd: string; output: string; outputPath?
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (!props.active) return
|
||||
const out = props.output
|
||||
if (!outRef || !out) return
|
||||
outRef.innerHTML = `<pre data-slot="bash-pre"><code data-lang="log">${escapeHtml(out)}</code></pre>`
|
||||
@@ -2128,6 +2130,7 @@ ToolRegistry.register({
|
||||
const pending = () => busy(props.status)
|
||||
const reveal = useToolReveal(pending, () => props.reveal !== false)
|
||||
const subtitle = () => props.input.description ?? props.metadata.description
|
||||
const [open, setOpen] = createSignal(props.defaultOpen ?? true)
|
||||
|
||||
// also apply processCarriageReturns for Windows CLI tools
|
||||
const cmd = createMemo(() => {
|
||||
@@ -2148,6 +2151,7 @@ ToolRegistry.register({
|
||||
icon="console"
|
||||
animated
|
||||
defaultOpen={props.defaultOpen ?? true}
|
||||
onOpenChange={setOpen}
|
||||
allowPendingToggle
|
||||
trigger={
|
||||
<div data-slot="basic-tool-tool-info-structured">
|
||||
@@ -2160,7 +2164,7 @@ ToolRegistry.register({
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<BashHighlightedOutput cmd={cmd()} output={out()} outputPath={props.metadata.outputPath} />
|
||||
<BashHighlightedOutput cmd={cmd()} output={out()} outputPath={props.metadata.outputPath} active={open()} />
|
||||
</BasicTool>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -59,10 +59,11 @@ function ShellRollingCommand(props: { text: string; animate?: boolean }) {
|
||||
)
|
||||
}
|
||||
|
||||
function ShellOutputHighlight(props: { code: string }) {
|
||||
function ShellOutputHighlight(props: { code: string; active?: boolean }) {
|
||||
let ref: HTMLDivElement | undefined
|
||||
|
||||
createEffect(() => {
|
||||
if (!props.active) return
|
||||
const code = props.code
|
||||
if (!ref || !code) return
|
||||
ref.innerHTML = `<pre data-slot="shell-expanded-pre"><code data-lang="log">${escapeHtml(code)}</code></pre>`
|
||||
@@ -171,7 +172,7 @@ function ShellExpanded(props: { cmd: string; out: string; open: boolean }) {
|
||||
onScroll={updateMask}
|
||||
style={{ "max-height": `${cap()}px` }}
|
||||
>
|
||||
<ShellOutputHighlight code={props.out} />
|
||||
<ShellOutputHighlight code={props.out} active={props.open} />
|
||||
</div>
|
||||
</>
|
||||
</Show>
|
||||
|
||||
@@ -607,6 +607,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
await routeSuggestionWebviewMessage(this.questionCtx, message)
|
||||
if (await ModelState.handleMessage(message.type, message, this.client, (msg) => this.postMessage(msg))) return
|
||||
if (await routeAutocompleteMessage(message, (msg) => this.postMessage(msg))) return
|
||||
if (this.handleEditorOpenMessage(message)) return
|
||||
if (
|
||||
await handleSidebarWorktreeMessage(message, {
|
||||
post: (msg) => this.postMessage(msg),
|
||||
@@ -771,16 +772,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
break
|
||||
case "saveImage":
|
||||
return saveImage(this.getWorkspaceDirectory(this.currentSession?.id), message)
|
||||
case "openFile":
|
||||
if (message.filePath) {
|
||||
this.handleOpenFile(message.filePath, message.line, message.column)
|
||||
}
|
||||
break
|
||||
case "openContent":
|
||||
if (message.content) {
|
||||
this.handleOpenContent(message.content, message.language)
|
||||
}
|
||||
break
|
||||
case "requestProviders":
|
||||
this.fetchAndSendProviders().catch((e) => console.error("[Kilo New] fetchAndSendProviders failed:", e))
|
||||
break
|
||||
@@ -2902,8 +2893,27 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
.then(open, (err) => console.error("[Kilo New] KiloProvider: Failed to preview image:", err))
|
||||
}
|
||||
|
||||
private handleEditorOpenMessage(message: {
|
||||
type?: string
|
||||
filePath?: string
|
||||
line?: number
|
||||
column?: number
|
||||
content?: string
|
||||
language?: string
|
||||
}): boolean {
|
||||
if (message.type === "openFile") {
|
||||
if (message.filePath) this.handleOpenFile(message.filePath, message.line, message.column)
|
||||
return true
|
||||
}
|
||||
if (message.type === "openContent") {
|
||||
if (message.content) this.handleOpenContent(message.content, message.language)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle openContent request — open arbitrary text in an untitled VS Code editor tab.
|
||||
* Handle openContent request - open arbitrary text in an untitled VS Code editor tab.
|
||||
*/
|
||||
private handleOpenContent(content: string, language?: string): void {
|
||||
vscode.workspace.openTextDocument({ content, language: language || "log" }).then(
|
||||
|
||||
@@ -35,6 +35,7 @@ export interface BasicToolProps {
|
||||
animated?: boolean
|
||||
allowPendingToggle?: boolean // kilocode_change
|
||||
onSubtitleClick?: () => void
|
||||
onOpenChange?: (open: boolean) => void // kilocode_change
|
||||
onTriggerClick?: JSX.EventHandlerUnion<HTMLElement, MouseEvent>
|
||||
triggerHref?: string
|
||||
clickable?: boolean
|
||||
@@ -124,6 +125,7 @@ export function BasicTool(props: BasicToolProps) {
|
||||
if (props.hideDetails) return // kilocode_change
|
||||
if (props.locked && !value) return
|
||||
setState("open", value)
|
||||
props.onOpenChange?.(value) // kilocode_change
|
||||
}
|
||||
|
||||
const trigger = () => (
|
||||
|
||||
Reference in New Issue
Block a user