mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
feat(vscode): use terminal.integrated font settings in Agent Manager xterm terminals
Reads terminal.integrated.fontFamily and terminal.integrated.fontSize (with editor font fallback) instead of the editor font CSS var. A config watcher broadcasts fontChanged messages so live terminals update without a reload. Nerd Font glyphs now render correctly in Agent Manager terminal tabs.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-vscode": patch
|
||||
---
|
||||
|
||||
Agent Manager terminals now use `terminal.integrated.fontFamily` and `terminal.integrated.fontSize` (including Nerd Font glyphs) instead of the editor font.
|
||||
@@ -36,6 +36,7 @@ import { parseToolRequest, startFromTool, type ToolRequest } from "./tool-start"
|
||||
import { stopSessionProcesses } from "../kilo-provider/background-process"
|
||||
|
||||
import { startSession } from "./mcp-warmup"
|
||||
import { readTerminalFont, watchTerminalFont } from "./terminal-font"
|
||||
import { buildKeybindingMap } from "./format-keybinding"
|
||||
import { resolveVersionModels, buildInitialMessages, type CreatedVersion } from "./multi-version"
|
||||
import { Semaphore } from "./semaphore"
|
||||
@@ -73,6 +74,7 @@ export class AgentManagerProvider implements Disposable {
|
||||
private cachedWorktreeStats: { type: "agentManager.worktreeStats"; stats: WorktreeStats[] } | undefined
|
||||
private cachedLocalStats: { type: "agentManager.localStats"; stats: LocalStats } | undefined
|
||||
private unsubTool: (() => void) | undefined
|
||||
private unsubFont: (() => void) | undefined
|
||||
private closing: Promise<void> | undefined
|
||||
private onVisibilityChange: ((visible: boolean) => void) | undefined
|
||||
|
||||
@@ -96,6 +98,10 @@ export class AgentManagerProvider implements Disposable {
|
||||
getWorktreePath: (id) => this.getStateManager()?.getWorktree(id)?.path,
|
||||
log: (...args) => this.log("[XTerm]", ...args),
|
||||
post: (msg) => this.postToWebview(msg),
|
||||
getTerminalFont: () => readTerminalFont(),
|
||||
})
|
||||
this.unsubFont = watchTerminalFont((font) => {
|
||||
this.postToWebview({ type: "agentManager.terminal.fontChanged", font })
|
||||
})
|
||||
this.run = new RunController({
|
||||
root: () => this.getRoot(),
|
||||
@@ -1791,6 +1797,7 @@ export class AgentManagerProvider implements Disposable {
|
||||
await this.stateReady?.catch((err) => this.log("dispose: stateReady rejected:", err))
|
||||
await this.state?.flush().catch((err) => this.log("dispose: state flush failed:", err))
|
||||
this.unsubTool?.()
|
||||
this.unsubFont?.()
|
||||
this.connectionService.unregisterFocused("agent-manager")
|
||||
this.connectionService.registerOpen("agent-manager", [])
|
||||
this.diffs.stop()
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Helpers to read and watch the user's integrated-terminal font settings.
|
||||
*
|
||||
* VS Code's integrated terminal mirrors editor font settings when terminal
|
||||
* font settings are unset. We replicate that same logic here so the Agent
|
||||
* Manager xterm instances look identical to VS Code's own terminal.
|
||||
*/
|
||||
|
||||
import * as vscode from "vscode"
|
||||
|
||||
export interface TerminalFont {
|
||||
fontFamily: string
|
||||
fontSize: number
|
||||
fontWeight?: string
|
||||
fontWeightBold?: string
|
||||
lineHeight?: number
|
||||
letterSpacing?: number
|
||||
}
|
||||
|
||||
const FALLBACK = "Menlo, Monaco, 'Courier New', monospace"
|
||||
|
||||
/** Resolve the user's integrated-terminal font, mirroring VS Code's own
|
||||
* fallback to the editor font when the terminal font is unset. */
|
||||
export function readTerminalFont(): TerminalFont {
|
||||
const term = vscode.workspace.getConfiguration("terminal.integrated")
|
||||
const editor = vscode.workspace.getConfiguration("editor")
|
||||
const family = term.get<string>("fontFamily")?.trim() || editor.get<string>("fontFamily")?.trim() || FALLBACK
|
||||
const size = term.get<number>("fontSize") || editor.get<number>("fontSize") || 13
|
||||
return {
|
||||
fontFamily: family,
|
||||
fontSize: size,
|
||||
fontWeight: term.get<string>("fontWeight") || undefined,
|
||||
fontWeightBold: term.get<string>("fontWeightBold") || undefined,
|
||||
lineHeight: term.get<number>("lineHeight") || undefined,
|
||||
letterSpacing: term.get<number>("letterSpacing") || undefined,
|
||||
}
|
||||
}
|
||||
|
||||
/** True when a config change touches any terminal/editor font setting. */
|
||||
export function affectsTerminalFont(e: vscode.ConfigurationChangeEvent): boolean {
|
||||
return (
|
||||
e.affectsConfiguration("terminal.integrated.fontFamily") ||
|
||||
e.affectsConfiguration("terminal.integrated.fontSize") ||
|
||||
e.affectsConfiguration("terminal.integrated.fontWeight") ||
|
||||
e.affectsConfiguration("terminal.integrated.fontWeightBold") ||
|
||||
e.affectsConfiguration("terminal.integrated.lineHeight") ||
|
||||
e.affectsConfiguration("terminal.integrated.letterSpacing") ||
|
||||
e.affectsConfiguration("editor.fontFamily") ||
|
||||
e.affectsConfiguration("editor.fontSize")
|
||||
)
|
||||
}
|
||||
|
||||
/** Subscribe to terminal-font config changes. Returns a cleanup function. */
|
||||
export function watchTerminalFont(callback: (font: TerminalFont) => void): () => void {
|
||||
const sub = vscode.workspace.onDidChangeConfiguration((e) => {
|
||||
if (affectsTerminalFont(e)) callback(readTerminalFont())
|
||||
})
|
||||
return () => sub.dispose()
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import type { KiloClient } from "@kilocode/sdk/v2/client"
|
||||
import type { AgentManagerInMessage, AgentManagerOutMessage } from "./types"
|
||||
import type { AgentManagerInMessage, AgentManagerOutMessage, TerminalFont } from "./types"
|
||||
import { TerminalManager } from "./terminal-manager"
|
||||
|
||||
interface ServerConfig {
|
||||
@@ -36,6 +36,8 @@ export interface TerminalRoutingDeps {
|
||||
log(...args: unknown[]): void
|
||||
/** Send a message back to the webview. */
|
||||
post(message: AgentManagerOutMessage): void
|
||||
/** Return the current terminal font settings. */
|
||||
getTerminalFont(): TerminalFont
|
||||
}
|
||||
|
||||
/** True iff the message belongs to the terminal-tab subsystem. */
|
||||
@@ -106,6 +108,7 @@ export class TerminalRouter {
|
||||
terminalId: created.terminalId,
|
||||
title: created.title,
|
||||
wsUrl: created.wsUrl,
|
||||
font: this.deps.getTerminalFont(),
|
||||
})
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
|
||||
@@ -14,6 +14,9 @@ import type { ApplyConflict } from "./GitOps"
|
||||
import type { BranchListItem, WorktreeSetupErrorCode } from "./git-import"
|
||||
import type { ExternalWorktreeItem } from "./WorktreeManager"
|
||||
import type { RunStatus } from "./run/manager"
|
||||
import type { TerminalFont } from "./terminal-font"
|
||||
|
||||
export type { TerminalFont }
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared payload types
|
||||
@@ -147,6 +150,7 @@ interface TerminalCreatedMessage {
|
||||
terminalId: string
|
||||
title: string
|
||||
wsUrl: string
|
||||
font: TerminalFont
|
||||
}
|
||||
|
||||
interface TerminalClosedMessage {
|
||||
@@ -160,6 +164,11 @@ interface TerminalErrorMessage {
|
||||
message: string
|
||||
}
|
||||
|
||||
interface TerminalFontChangedMessage {
|
||||
type: "agentManager.terminal.fontChanged"
|
||||
font: TerminalFont
|
||||
}
|
||||
|
||||
interface ErrorOutMessage {
|
||||
type: "error"
|
||||
message: string
|
||||
@@ -314,6 +323,7 @@ export type AgentManagerOutMessage =
|
||||
| TerminalCreatedMessage
|
||||
| TerminalClosedMessage
|
||||
| TerminalErrorMessage
|
||||
| TerminalFontChangedMessage
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Webview → Extension messages (onMessage)
|
||||
|
||||
@@ -653,6 +653,10 @@ const VSCODE_ALLOWED: Record<string, { note: string }> = {
|
||||
"run/task.ts": {
|
||||
note: "vscode adapter for Agent Manager run scripts",
|
||||
},
|
||||
// Reads terminal.integrated.* and editor.font* config for xterm font settings
|
||||
"terminal-font.ts": {
|
||||
note: "vscode config reader for integrated terminal font settings",
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
import { Component, createEffect, onCleanup, onMount } from "solid-js"
|
||||
import { Terminal } from "@xterm/xterm"
|
||||
import { Terminal, type FontWeight } from "@xterm/xterm"
|
||||
import { FitAddon } from "@xterm/addon-fit"
|
||||
import { WebLinksAddon } from "@xterm/addon-web-links"
|
||||
import { ClipboardAddon } from "@xterm/addon-clipboard"
|
||||
@@ -20,10 +20,14 @@ import "@xterm/xterm/css/xterm.css"
|
||||
import { useVSCode } from "../../src/context/vscode"
|
||||
import { useLanguage } from "../../src/context/language"
|
||||
import { formatReviewCommentsMarkdown } from "../../src/utils/review-comment-markdown"
|
||||
import type { TerminalFont } from "./state"
|
||||
|
||||
interface Props {
|
||||
terminalId: string
|
||||
wsUrl: string
|
||||
/** Terminal font settings forwarded from the extension host. Used on
|
||||
* initial mount; live changes arrive via `agentManager.terminal.fontChanged`. */
|
||||
font: TerminalFont
|
||||
/** Whether this terminal is currently the focused tab.
|
||||
*
|
||||
* The xterm subtree always stays in the paint tree (see the layer /
|
||||
@@ -126,12 +130,16 @@ export const TerminalTab: Component<Props> = (props) => {
|
||||
const term = new Terminal({
|
||||
convertEol: true,
|
||||
cursorBlink: true,
|
||||
fontFamily: cssVar("--vscode-editor-font-family", "Menlo, Monaco, 'Courier New', monospace"),
|
||||
fontSize: Number.parseFloat(cssVar("--font-size-base", "13px")),
|
||||
fontFamily: props.font.fontFamily,
|
||||
fontSize: props.font.fontSize,
|
||||
scrollback: 5000,
|
||||
theme: readTheme(),
|
||||
allowProposedApi: true,
|
||||
})
|
||||
if (props.font.fontWeight) term.options.fontWeight = props.font.fontWeight as FontWeight
|
||||
if (props.font.fontWeightBold) term.options.fontWeightBold = props.font.fontWeightBold as FontWeight
|
||||
if (props.font.lineHeight) term.options.lineHeight = props.font.lineHeight
|
||||
if (props.font.letterSpacing) term.options.letterSpacing = props.font.letterSpacing
|
||||
const fit = new FitAddon()
|
||||
term.loadAddon(fit)
|
||||
// Clickable URLs in terminal output (Cmd/Ctrl+click to open).
|
||||
@@ -288,12 +296,26 @@ export const TerminalTab: Component<Props> = (props) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (message.type === "agentManager.terminal.fontChanged") {
|
||||
const font = message.font as TerminalFont
|
||||
term.options.fontFamily = font.fontFamily
|
||||
term.options.fontSize = font.fontSize
|
||||
if (font.fontWeight) term.options.fontWeight = font.fontWeight as FontWeight
|
||||
if (font.fontWeightBold) term.options.fontWeightBold = font.fontWeightBold as FontWeight
|
||||
if (font.lineHeight) term.options.lineHeight = font.lineHeight
|
||||
if (font.letterSpacing) term.options.letterSpacing = font.letterSpacing
|
||||
fit.fit()
|
||||
syncSize()
|
||||
scheduleRepaint()
|
||||
return
|
||||
}
|
||||
|
||||
// fontSizeChanged/ready control the Kilo chat UI font — do not apply
|
||||
// them to the terminal, which has its own independent font settings.
|
||||
// Keep the repaint for any downstream layout side-effects.
|
||||
const size =
|
||||
message.type === "fontSizeChanged" ? message.fontSize : message.type === "ready" ? message.fontSize : undefined
|
||||
if (size === undefined) return
|
||||
term.options.fontSize = size
|
||||
fit.fit()
|
||||
syncSize()
|
||||
scheduleRepaint()
|
||||
})
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ export function renderTerminalLayer(props: { state: TerminalStateControls }): JS
|
||||
const visible = () => slotVisible(term.id, term.contextKey)
|
||||
return (
|
||||
<div class={`am-terminal-slot ${visible() ? "am-terminal-slot-visible" : ""}`}>
|
||||
<TerminalTab terminalId={term.id} wsUrl={term.wsUrl} active={visible()} />
|
||||
<TerminalTab terminalId={term.id} wsUrl={term.wsUrl} active={visible()} font={term.font} />
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -11,6 +11,16 @@ import { createMemo, createSignal } from "solid-js"
|
||||
import type { Accessor } from "solid-js"
|
||||
import { LOCAL } from "../navigate"
|
||||
|
||||
/** Font settings forwarded from the extension host (mirrors terminal-font.ts). */
|
||||
export interface TerminalFont {
|
||||
fontFamily: string
|
||||
fontSize: number
|
||||
fontWeight?: string
|
||||
fontWeightBold?: string
|
||||
lineHeight?: number
|
||||
letterSpacing?: number
|
||||
}
|
||||
|
||||
/** Prefix used for terminal tab IDs in the webview (mirrors terminal-manager.ts). */
|
||||
export const TERMINAL_PREFIX = "terminal:"
|
||||
|
||||
@@ -21,6 +31,7 @@ export interface TerminalTabState {
|
||||
id: string
|
||||
title: string
|
||||
wsUrl: string
|
||||
font: TerminalFont
|
||||
}
|
||||
|
||||
/** Terminal row enriched with the sidebar context it belongs to. Used by
|
||||
@@ -35,6 +46,7 @@ export interface TerminalCreatedEvent {
|
||||
terminalId: string
|
||||
title: string
|
||||
wsUrl: string
|
||||
font: TerminalFont
|
||||
}
|
||||
|
||||
export interface TerminalStateControls {
|
||||
@@ -335,7 +347,7 @@ export function createTerminalMessageHandler(deps: TerminalMessageHandlerDeps) {
|
||||
if (msg.type === "agentManager.terminal.created") {
|
||||
const ev = msg as unknown as TerminalCreatedEvent
|
||||
const contextKey = ev.worktreeId === null ? LOCAL : ev.worktreeId
|
||||
deps.state.add(ev.worktreeId, { id: ev.terminalId, title: ev.title, wsUrl: ev.wsUrl })
|
||||
deps.state.add(ev.worktreeId, { id: ev.terminalId, title: ev.title, wsUrl: ev.wsUrl, font: ev.font })
|
||||
deps.onCreated?.(contextKey, ev.terminalId)
|
||||
deps.saveTabMemory()
|
||||
deps.setSelection(contextKey)
|
||||
|
||||
Reference in New Issue
Block a user