mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-30 17:14:40 +08:00
fix(vscode): extract side panel resize scheduler
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
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"
|
||||
import {
|
||||
clampPanelWidth,
|
||||
createPanelResize,
|
||||
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")
|
||||
@@ -22,14 +27,28 @@ test("xterm owns the padding used by FitAddon", () => {
|
||||
|
||||
test("uses one persisted width for the diff and terminal inspector", () => {
|
||||
expect(app).toContain("persisted?.sidePanelWidth")
|
||||
expect(app).toContain("setPanelWidth(pendingSideWidth!)")
|
||||
expect(app).toContain("createPanelResize(setPanelWidth")
|
||||
expect(app).not.toContain("diffWidth")
|
||||
expect(app).not.toContain("terminalWidth")
|
||||
})
|
||||
|
||||
test("limits inspector layout updates during resize", () => {
|
||||
expect(app).toContain("SIDE_RESIZE_INTERVAL_MS = 32")
|
||||
expect(app).toContain("time - sideResizeTime < SIDE_RESIZE_INTERVAL_MS")
|
||||
const frames: ((time: number) => void)[] = []
|
||||
const widths: number[] = []
|
||||
const resize = createPanelResize(
|
||||
(width) => widths.push(width),
|
||||
() => 1200,
|
||||
(frame) => frames.push(frame),
|
||||
)
|
||||
|
||||
resize(700)
|
||||
resize(720)
|
||||
expect(frames).toHaveLength(1)
|
||||
frames.shift()!(16)
|
||||
expect(frames).toHaveLength(1)
|
||||
expect(widths).toEqual([])
|
||||
frames.shift()!(32)
|
||||
expect(widths).toEqual([720])
|
||||
})
|
||||
|
||||
test("does not refit hidden terminal buffers during resize", () => {
|
||||
|
||||
@@ -177,7 +177,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 { clampPanelWidth, createPanelResize, maxPanelWidth, minPanelWidth } from "./side-panel-layout"
|
||||
import { buildShortcutCategories } from "./shortcuts"
|
||||
import { tracker } from "./telemetry"
|
||||
import { createChatFocus, hasQuestionOption } from "./focus"
|
||||
@@ -201,7 +201,6 @@ type SidePanel = "diff" | "pr" | "terminal" | null
|
||||
const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.userAgent)
|
||||
// Fallback keybindings before extension sends resolved ones
|
||||
const MAX_JUMP_INDEX = 9
|
||||
const SIDE_RESIZE_INTERVAL_MS = 32
|
||||
|
||||
const defaultBindings: Record<string, string> = {
|
||||
previousSession: isMac ? "⌘⌥↑" : "Ctrl+Alt+↑",
|
||||
@@ -322,9 +321,6 @@ const AgentManagerContent: Component = () => {
|
||||
// rAF coalescing for resize handlers — at most one signal write per frame
|
||||
let sidebarRaf: number | undefined
|
||||
let pendingSidebarWidth: number | undefined
|
||||
let sideRaf: number | undefined
|
||||
let pendingSideWidth: number | undefined
|
||||
let sideResizeTime = 0
|
||||
|
||||
const [history, setHistory] = createSignal(false)
|
||||
const [sidePanel, setSidePanel] = createSignal<SidePanel>(null)
|
||||
@@ -337,20 +333,7 @@ const AgentManagerContent: Component = () => {
|
||||
// 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 = clampPanelWidth(width, window.innerWidth)
|
||||
if (sideRaf !== undefined) return
|
||||
const flush = (time: number) => {
|
||||
if (time - sideResizeTime < SIDE_RESIZE_INTERVAL_MS) {
|
||||
sideRaf = requestAnimationFrame(flush)
|
||||
return
|
||||
}
|
||||
sideRaf = undefined
|
||||
sideResizeTime = time
|
||||
setPanelWidth(pendingSideWidth!)
|
||||
}
|
||||
sideRaf = requestAnimationFrame(flush)
|
||||
}
|
||||
const resizeSide = createPanelResize(setPanelWidth, () => window.innerWidth)
|
||||
const showSideTerminal = () => {
|
||||
setHistory(false)
|
||||
setReviewActive(false)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
export const MIN_PANEL_WIDTH = 360
|
||||
const DEFAULT_PANEL_WIDTH_RATIO = 0.5
|
||||
const MAX_PANEL_WIDTH_RATIO = 0.8
|
||||
export const SIDE_RESIZE_INTERVAL_MS = 32
|
||||
|
||||
type Frame = (callback: (time: number) => void) => number
|
||||
|
||||
function viewportWidth(viewport: number): number {
|
||||
return Number.isFinite(viewport) && viewport > 0 ? viewport : MIN_PANEL_WIDTH
|
||||
@@ -23,3 +26,27 @@ export function clampPanelWidth(value: unknown, viewport: number): number {
|
||||
const candidate = typeof value === "number" && Number.isFinite(value) ? value : fallback
|
||||
return Math.round(Math.max(minPanelWidth(width), Math.min(candidate, maxPanelWidth(width))))
|
||||
}
|
||||
|
||||
export function createPanelResize(
|
||||
update: (width: number) => void,
|
||||
viewport: () => number,
|
||||
frame: Frame = requestAnimationFrame,
|
||||
) {
|
||||
let raf: number | undefined
|
||||
let pending = 0
|
||||
let time = 0
|
||||
const flush = (now: number) => {
|
||||
if (now - time < SIDE_RESIZE_INTERVAL_MS) {
|
||||
raf = frame(flush)
|
||||
return
|
||||
}
|
||||
raf = undefined
|
||||
time = now
|
||||
update(pending)
|
||||
}
|
||||
return (width: number) => {
|
||||
pending = clampPanelWidth(width, viewport())
|
||||
if (raf !== undefined) return
|
||||
raf = frame(flush)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user