mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
Merge pull request #12858 from Kilo-Org/sync-terminal-diff-viewer-dimensions
fix(vscode): sync Agent Manager inspector width
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Persist the Agent Manager inspector width and share it between the terminal and diff viewer.
|
||||
@@ -1,8 +1,10 @@
|
||||
import { expect, test } from "bun:test"
|
||||
import { readFileSync } from "node:fs"
|
||||
import { resolve } from "node:path"
|
||||
import { clampPanelWidth, maxPanelWidth, minPanelWidth } from "../../webview-ui/agent-manager/side-panel-layout"
|
||||
|
||||
const css = readFileSync(resolve(import.meta.dir, "../../webview-ui/agent-manager/agent-manager.css"), "utf8")
|
||||
const app = readFileSync(resolve(import.meta.dir, "../../webview-ui/agent-manager/AgentManagerApp.tsx"), "utf8")
|
||||
|
||||
test("xterm owns the padding used by FitAddon", () => {
|
||||
const host = css.match(/\.am-terminal-host\s*\{([^}]*)\}/)?.[1]
|
||||
@@ -13,3 +15,22 @@ test("xterm owns the padding used by FitAddon", () => {
|
||||
expect(host).not.toMatch(/\bpadding\s*:/)
|
||||
expect(term).toMatch(/\bpadding\s*:\s*8px\s*;/)
|
||||
})
|
||||
|
||||
test("uses one persisted width for the diff and terminal inspector", () => {
|
||||
expect(app).toContain("persisted?.sidePanelWidth")
|
||||
expect(app).toContain("setPanelWidth(pendingSideWidth!)")
|
||||
expect(app).not.toContain("diffWidth")
|
||||
expect(app).not.toContain("terminalWidth")
|
||||
})
|
||||
|
||||
test("clamps the restored inspector width to the shared layout bounds", () => {
|
||||
expect(clampPanelWidth(undefined, 1200)).toBe(600)
|
||||
expect(clampPanelWidth(500, 1200)).toBe(500)
|
||||
expect(clampPanelWidth(1000, 1000)).toBe(maxPanelWidth(1000))
|
||||
expect(clampPanelWidth(100, 1200)).toBe(minPanelWidth(1200))
|
||||
expect(clampPanelWidth("invalid", 1200)).toBe(600)
|
||||
expect(minPanelWidth(400)).toBe(200)
|
||||
expect(maxPanelWidth(400)).toBe(320)
|
||||
expect(clampPanelWidth(undefined, 400)).toBe(200)
|
||||
expect(clampPanelWidth(360, 400)).toBe(320)
|
||||
})
|
||||
|
||||
@@ -174,6 +174,7 @@ import { createMarkdownRender } from "./review-preferences"
|
||||
import { createSidebarCollapse } from "./sidebar-collapse"
|
||||
import { SidebarToggleButton } from "./SidebarToggleButton"
|
||||
import { setTabWidths } from "./tab-widths"
|
||||
import { clampPanelWidth, maxPanelWidth, minPanelWidth } from "./side-panel-layout"
|
||||
import { buildShortcutCategories } from "./shortcuts"
|
||||
import { tracker } from "./telemetry"
|
||||
import { createChatFocus, hasQuestionOption } from "./focus"
|
||||
@@ -274,7 +275,7 @@ const AgentManagerContent: Component = () => {
|
||||
const MAX_SIDEBAR_WIDTH_RATIO = 0.4
|
||||
|
||||
// Recover persisted local session IDs from webview state
|
||||
const persisted = vscode.getState<PersistedProjectTabs & { sidebarWidth?: number }>()
|
||||
const persisted = vscode.getState<PersistedProjectTabs & { sidebarWidth?: number; sidePanelWidth?: number }>()
|
||||
const registry = createProjectRegistry({
|
||||
persisted: persisted ?? {},
|
||||
activeId: () => currentProjectId() ?? "single",
|
||||
@@ -314,26 +315,15 @@ const AgentManagerContent: Component = () => {
|
||||
const diffLoading = diffs.diffLoading
|
||||
const setDiffLoading = diffs.setDiffLoading
|
||||
const diffNotices = diffs.diffNotices
|
||||
// The diff and terminal panels each remember their own width: a diff
|
||||
// benefits from half the window, a terminal only needs about a third.
|
||||
const TERMINAL_MIN_WIDTH = 360
|
||||
const TERMINAL_MAX_WIDTH = 640
|
||||
const [diffWidth, setDiffWidth] = createSignal(Math.round(window.innerWidth * 0.5))
|
||||
const [terminalWidth, setTerminalWidth] = createSignal(
|
||||
Math.min(TERMINAL_MAX_WIDTH, Math.max(TERMINAL_MIN_WIDTH, Math.round(window.innerWidth / 3))),
|
||||
)
|
||||
// The hidden-but-mounted host still fits the terminal, so pick the
|
||||
// terminal's width whenever one is alive and no other mode is showing.
|
||||
const widthMode = () => sidePanel() ?? (terms.sides().length > 0 ? "terminal" : null)
|
||||
const hostWidth = () => (widthMode() === "terminal" ? terminalWidth() : diffWidth())
|
||||
const sideMin = () => (widthMode() === "terminal" ? TERMINAL_MIN_WIDTH : 200)
|
||||
// Diff and terminal views share one inspector width, restored from webview
|
||||
// state so the user's divider position survives panel reloads.
|
||||
const [panelWidth, setPanelWidth] = createSignal(clampPanelWidth(persisted?.sidePanelWidth, window.innerWidth))
|
||||
const resizeSide = (width: number) => {
|
||||
pendingSideWidth = Math.max(sideMin(), Math.min(width, window.innerWidth * 0.8))
|
||||
pendingSideWidth = clampPanelWidth(width, window.innerWidth)
|
||||
if (sideRaf !== undefined) return
|
||||
sideRaf = requestAnimationFrame(() => {
|
||||
sideRaf = undefined
|
||||
if (widthMode() === "terminal") setTerminalWidth(pendingSideWidth!)
|
||||
else setDiffWidth(pendingSideWidth!)
|
||||
setPanelWidth(pendingSideWidth!)
|
||||
})
|
||||
}
|
||||
const showSideTerminal = () => {
|
||||
@@ -643,6 +633,7 @@ const AgentManagerContent: Component = () => {
|
||||
},
|
||||
key: () => registry.active().id,
|
||||
width: sidebarWidth,
|
||||
panelWidth,
|
||||
get: () => vscode.getState<Record<string, unknown>>(),
|
||||
set: (value) => vscode.setState(value),
|
||||
})
|
||||
@@ -2636,16 +2627,16 @@ const AgentManagerContent: Component = () => {
|
||||
<Show when={sidePanel() !== null || terms.sides().length > 0}>
|
||||
<div
|
||||
class={`am-diff-resize ${sidePanel() === null ? "am-side-host-hidden" : ""}`}
|
||||
style={{ width: `${hostWidth()}px` }}
|
||||
style={{ width: `${panelWidth()}px` }}
|
||||
inert={sidePanel() === null}
|
||||
>
|
||||
<Show when={sidePanel() !== null}>
|
||||
<ResizeHandle
|
||||
direction="horizontal"
|
||||
edge="start"
|
||||
size={hostWidth()}
|
||||
min={sideMin()}
|
||||
max={Math.round(window.innerWidth * 0.8)}
|
||||
size={panelWidth()}
|
||||
min={minPanelWidth(window.innerWidth)}
|
||||
max={maxPanelWidth(window.innerWidth)}
|
||||
onResize={resizeSide}
|
||||
/>
|
||||
</Show>
|
||||
|
||||
@@ -2,13 +2,14 @@ import { createEffect, createMemo, onCleanup } from "solid-js"
|
||||
import type { SessionInfo } from "../../src/types/messages/sessions"
|
||||
|
||||
/**
|
||||
* Persist open tabs and the sidebar width to webview state for recovery.
|
||||
* Persist open tabs and panel widths to webview state for recovery.
|
||||
* Debounced so a resize drag does not serialize state on every pixel.
|
||||
*/
|
||||
export function persistLocalTabs(opts: {
|
||||
tabs: () => Record<string, string[]>
|
||||
key: () => string
|
||||
width: () => number
|
||||
panelWidth?: () => number
|
||||
get: () => Record<string, unknown> | undefined
|
||||
set: (value: Record<string, unknown>) => void
|
||||
}): void {
|
||||
@@ -18,9 +19,16 @@ export function persistLocalTabs(opts: {
|
||||
const tabs = opts.tabs()
|
||||
const key = opts.key()
|
||||
const width = opts.width()
|
||||
const panel = opts.panelWidth?.()
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
opts.set({ ...(opts.get() ?? {}), localTabs: tabs, localSessionIDs: tabs[key] ?? [], sidebarWidth: width })
|
||||
opts.set({
|
||||
...(opts.get() ?? {}),
|
||||
localTabs: tabs,
|
||||
localSessionIDs: tabs[key] ?? [],
|
||||
sidebarWidth: width,
|
||||
...(panel === undefined ? {} : { sidePanelWidth: panel }),
|
||||
})
|
||||
}, 300)
|
||||
})
|
||||
onCleanup(() => clearTimeout(timer))
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
export const MIN_PANEL_WIDTH = 360
|
||||
const DEFAULT_PANEL_WIDTH_RATIO = 0.5
|
||||
const MAX_PANEL_WIDTH_RATIO = 0.8
|
||||
|
||||
function viewportWidth(viewport: number): number {
|
||||
return Number.isFinite(viewport) && viewport > 0 ? viewport : MIN_PANEL_WIDTH
|
||||
}
|
||||
|
||||
export function minPanelWidth(viewport: number): number {
|
||||
const width = viewportWidth(viewport)
|
||||
return Math.min(MIN_PANEL_WIDTH, Math.round(width * DEFAULT_PANEL_WIDTH_RATIO))
|
||||
}
|
||||
|
||||
export function maxPanelWidth(viewport: number): number {
|
||||
const width = viewportWidth(viewport)
|
||||
return Math.max(minPanelWidth(width), Math.round(width * MAX_PANEL_WIDTH_RATIO))
|
||||
}
|
||||
|
||||
/** Restore or constrain the shared inspector width without trusting saved state. */
|
||||
export function clampPanelWidth(value: unknown, viewport: number): number {
|
||||
const width = viewportWidth(viewport)
|
||||
const fallback = Math.round(width * DEFAULT_PANEL_WIDTH_RATIO)
|
||||
const candidate = typeof value === "number" && Number.isFinite(value) ? value : fallback
|
||||
return Math.round(Math.max(minPanelWidth(width), Math.min(candidate, maxPanelWidth(width))))
|
||||
}
|
||||
Reference in New Issue
Block a user