feat: 终端二级设置支持自定义字体(字体族 + 9–32px 字号,实时生效)
- SidebarPrefs 新增 terminalFontFamily(空 = 跟随主题等宽字体)/ terminalFontSize(9–32,默认 13),PrefsSchema 与 parsePrefs 同步校验 - 声明式设置 API 扩展:SidebarSettingToggle 支持 type: 'switch' | 'text' | 'number'(缺省 switch,向后兼容)+ min/max/placeholder/unit - 终端卡片齿轮弹窗新增「终端字体」「终端字号」两行:blur/Enter 提交、number 钳制、提交失败回滚草稿 - TerminalView 经 store 订阅实时应用字体(options + re-fit + resize),懒加载 chunk 无新增依赖 - 新增 resolveTerminalFont 纯函数(回退链:用户字体 → 主题 token → 内置等宽栈)并单测 - 版本 0.11.0,README/AGENTS.md/设计文档同步
This commit is contained in:
@@ -337,6 +337,17 @@
|
||||
width: 76px;
|
||||
}
|
||||
|
||||
/* Text/number rows in the settings popup: the free-form input (e.g. the
|
||||
terminal font family) gets a generous width; numeric rows (font size)
|
||||
keep the compact width of the general number inputs. */
|
||||
.typedInput {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.typedInputNumber {
|
||||
width: 76px;
|
||||
}
|
||||
|
||||
.suffix {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
|
||||
+111
-20
@@ -141,37 +141,105 @@ function Switch(props: {
|
||||
|
||||
/**
|
||||
* The body of a feature's secondary settings popup: one row (title/desc +
|
||||
* custom switch) per declared toggle. Extracted so the rows are testable
|
||||
* control) per declared setting. Switches render the custom switch; text and
|
||||
* number rows render a free-form / numeric input committed on blur/Enter
|
||||
* (clamped to the declared min/max). Extracted so the rows are testable
|
||||
* without opening the Modal (the Modal portal renders only while open).
|
||||
*/
|
||||
export function FeatureSettingsRows(props: {
|
||||
toggles: readonly SidebarSettingToggle[]
|
||||
prefs: SidebarPrefs
|
||||
onToggle: (toggle: SidebarSettingToggle, next: boolean) => void
|
||||
/** Commit one text/number row; returns the canonical value the row should
|
||||
* display (clamped for numbers, the current pref when the input is
|
||||
* invalid). Optional: rows with no handler keep their draft. */
|
||||
onCommit?: (toggle: SidebarSettingToggle, raw: string) => string
|
||||
}) {
|
||||
const { toggles, prefs, onToggle } = props
|
||||
const { toggles, prefs, onToggle, onCommit } = props
|
||||
return (
|
||||
<div className={css.popupRows}>
|
||||
{toggles.map(toggle => {
|
||||
const title = textOf(toggle.title)
|
||||
if ((toggle.type ?? 'switch') === 'switch') {
|
||||
return (
|
||||
<div key={toggle.key} className={css.popupRow}>
|
||||
<span className={css.rowText}>
|
||||
<span className={css.title}>{title}</span>
|
||||
{textOf(toggle.desc) !== '' && <span className={css.desc}>{textOf(toggle.desc)}</span>}
|
||||
</span>
|
||||
<Switch
|
||||
label={title}
|
||||
checked={prefBool(prefs, toggle.key)}
|
||||
onChange={(next) => { onToggle(toggle, next) }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const value = String((prefs as unknown as Record<string, unknown>)[toggle.key] ?? '')
|
||||
// Keyed by the committed value: a failed commit reverts prefs, the
|
||||
// key changes, and the row remounts with the stored value (typing
|
||||
// never changes the key, so mid-edit drafts survive re-renders).
|
||||
return (
|
||||
<div key={toggle.key} className={css.popupRow}>
|
||||
<span className={css.rowText}>
|
||||
<span className={css.title}>{title}</span>
|
||||
{textOf(toggle.desc) !== '' && <span className={css.desc}>{textOf(toggle.desc)}</span>}
|
||||
</span>
|
||||
<Switch
|
||||
label={title}
|
||||
checked={prefBool(prefs, toggle.key)}
|
||||
onChange={(next) => { onToggle(toggle, next) }}
|
||||
/>
|
||||
</div>
|
||||
<TypedRow
|
||||
key={`${toggle.key}:${value}`}
|
||||
toggle={toggle}
|
||||
title={title}
|
||||
value={value}
|
||||
onCommit={onCommit}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* One text/number row: a controlled input whose draft is local state,
|
||||
* committed on blur/Enter through the parent's onCommit. The parent's
|
||||
* canonical return is adopted (clamped numbers, stored value for invalid
|
||||
* input); a `unit` suffix renders after the input (e.g. 'px').
|
||||
*/
|
||||
function TypedRow(props: {
|
||||
toggle: SidebarSettingToggle
|
||||
title: string
|
||||
value: string
|
||||
onCommit?: (toggle: SidebarSettingToggle, raw: string) => string
|
||||
}) {
|
||||
const { toggle, title, value, onCommit } = props
|
||||
const [draft, setDraft] = useState(value)
|
||||
const commit = (): void => {
|
||||
const canonical = onCommit?.(toggle, draft) ?? draft
|
||||
setDraft(canonical)
|
||||
}
|
||||
const number = toggle.type === 'number'
|
||||
return (
|
||||
<div className={css.popupRow}>
|
||||
<span className={css.rowText}>
|
||||
<span className={css.title}>{title}</span>
|
||||
{textOf(toggle.desc) !== '' && <span className={css.desc}>{textOf(toggle.desc)}</span>}
|
||||
</span>
|
||||
<span className={css.control}>
|
||||
<Input
|
||||
type={number ? 'number' : 'text'}
|
||||
className={number ? css.typedInputNumber : css.typedInput}
|
||||
value={draft}
|
||||
min={toggle.min}
|
||||
max={toggle.max}
|
||||
step={1}
|
||||
placeholder={toggle.placeholder}
|
||||
aria-label={title}
|
||||
onChange={event => { setDraft(event.currentTarget.value) }}
|
||||
onBlur={commit}
|
||||
onKeyDown={event => {
|
||||
if (event.key === 'Enter') event.currentTarget.blur()
|
||||
}}
|
||||
/>
|
||||
{toggle.unit !== undefined && <span className={css.suffix}>{toggle.unit}</span>}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the Side card preferences section.
|
||||
* @param props - composed slot props (runtime share + injected store/service).
|
||||
@@ -251,8 +319,8 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
|
||||
setWidthDraft(String(settled.defaultWidthPercent))
|
||||
}
|
||||
|
||||
/** Optimistically flip one boolean pref, then commit (revert on failure). */
|
||||
const togglePref = (patch: Record<string, unknown>): void => {
|
||||
/** Optimistically apply one pref patch, then commit (revert on failure). */
|
||||
const applyPref = (patch: Record<string, unknown>): void => {
|
||||
const previous = prefs
|
||||
setPrefs({ ...previous, ...patch } as SidebarPrefs)
|
||||
setError(null)
|
||||
@@ -260,22 +328,44 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
|
||||
}
|
||||
|
||||
const onToggle = (next: boolean): void => {
|
||||
togglePref({ openByDefault: next })
|
||||
applyPref({ openByDefault: next })
|
||||
}
|
||||
|
||||
/** Flip one per-tab enable switch (merge into the tabsEnabled map). */
|
||||
const onToggleTab = (id: string, next: boolean): void => {
|
||||
togglePref({ tabsEnabled: { ...prefs.tabsEnabled, [id]: next } })
|
||||
applyPref({ tabsEnabled: { ...prefs.tabsEnabled, [id]: next } })
|
||||
}
|
||||
|
||||
/** Flip one per-viewer enable switch (merge into the viewersEnabled map). */
|
||||
const onToggleViewer = (id: string, next: boolean): void => {
|
||||
togglePref({ viewersEnabled: { ...prefs.viewersEnabled, [id]: next } })
|
||||
applyPref({ viewersEnabled: { ...prefs.viewersEnabled, [id]: next } })
|
||||
}
|
||||
|
||||
/** Flip one declaratively-declared toggle (a SidebarPrefs boolean field). */
|
||||
const onToggleSetting = (toggle: SidebarSettingToggle, next: boolean): void => {
|
||||
togglePref({ [toggle.key]: next })
|
||||
applyPref({ [toggle.key]: next })
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit one declaratively-declared text/number row. Numbers are parsed
|
||||
* and clamped to the toggle's declared min/max (an unparsable input falls
|
||||
* back to the CURRENT stored value, mirroring the width row); text rows
|
||||
* persist as-is (empty is meaningful, e.g. the theme-default font).
|
||||
* Returns the canonical value the row should display.
|
||||
*/
|
||||
const onCommitSetting = (toggle: SidebarSettingToggle, raw: string): string => {
|
||||
if (toggle.type === 'number') {
|
||||
const parsed = Number(raw)
|
||||
const fallback = String((prefs as unknown as Record<string, unknown>)[toggle.key] ?? '')
|
||||
if (!Number.isFinite(parsed)) return fallback
|
||||
let clamped = Math.round(parsed)
|
||||
if (toggle.min !== undefined) clamped = Math.max(toggle.min, clamped)
|
||||
if (toggle.max !== undefined) clamped = Math.min(toggle.max, clamped)
|
||||
applyPref({ [toggle.key]: clamped })
|
||||
return String(clamped)
|
||||
}
|
||||
applyPref({ [toggle.key]: raw })
|
||||
return raw
|
||||
}
|
||||
|
||||
const commitWidth = (): void => {
|
||||
@@ -397,7 +487,7 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
|
||||
<Switch
|
||||
label={t('settingsOpenPathTitle')}
|
||||
checked={prefs.interceptOpenPath}
|
||||
onChange={(next) => { togglePref({ interceptOpenPath: next }) }}
|
||||
onChange={(next) => { applyPref({ interceptOpenPath: next }) }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -476,6 +566,7 @@ export function SideCardSection({ store, service }: SideCardSectionProps) {
|
||||
toggles={settingsFor.settings?.toggles ?? []}
|
||||
prefs={prefs}
|
||||
onToggle={onToggleSetting}
|
||||
onCommit={onCommitSetting}
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
|
||||
@@ -27,6 +27,7 @@ import { t } from './locales.ts'
|
||||
import type { SessionScope } from './api.ts'
|
||||
import { agentUuidOf, isAgentTabId, type SidebarStore } from './state.ts'
|
||||
import { isDarkScheme, subscribeColorScheme, tokenValue } from './theme.ts'
|
||||
import { resolveTerminalFont } from './terminal-font.ts'
|
||||
import css from './sidebar.module.css'
|
||||
|
||||
/** How many consecutive unreasoned failures before showing the error banner. */
|
||||
@@ -82,10 +83,13 @@ export function TerminalView(props: { scope: SessionScope; tabId: string; store:
|
||||
useEffect(() => {
|
||||
const host = hostRef.current
|
||||
if (host === null) return
|
||||
// The custom font prefs (side card settings, terminal card) resolve at
|
||||
// mount; store changes re-apply them live below.
|
||||
const font = resolveTerminalFont(store.getPrefs(), tokenValue('--ds-font-family-code'))
|
||||
const term = new Terminal({
|
||||
cursorBlink: true,
|
||||
fontSize: 13,
|
||||
fontFamily: tokenValue('--ds-font-family-code') || '"SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
|
||||
fontSize: font.fontSize,
|
||||
fontFamily: font.fontFamily,
|
||||
allowTransparency: true,
|
||||
convertEol: false,
|
||||
scrollback: 4000,
|
||||
@@ -185,11 +189,31 @@ export function TerminalView(props: { scope: SessionScope; tabId: string; store:
|
||||
})
|
||||
observer.observe(host)
|
||||
|
||||
// Custom font prefs (the terminal card's secondary settings) apply LIVE:
|
||||
// on any store change re-resolve and diff the two options, re-fitting
|
||||
// when they moved (the grid dimensions may change with the font). The
|
||||
// subscribe fires on every store change (tabs, panels…), so the diff is
|
||||
// what keeps this cheap.
|
||||
const fontSub = store.subscribe(() => {
|
||||
const next = resolveTerminalFont(store.getPrefs(), tokenValue('--ds-font-family-code'))
|
||||
if (next.fontFamily !== term.options.fontFamily || next.fontSize !== term.options.fontSize) {
|
||||
term.options.fontFamily = next.fontFamily
|
||||
term.options.fontSize = next.fontSize
|
||||
try {
|
||||
fit.fit()
|
||||
sendResize()
|
||||
} catch {
|
||||
// The terminal may be mid-dispose; ignore.
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
connect()
|
||||
return () => {
|
||||
closed = true
|
||||
window.clearTimeout(retry)
|
||||
observer.disconnect()
|
||||
fontSub()
|
||||
schemeSub()
|
||||
inputSub.dispose()
|
||||
// The close frame tells the host the owning tab is GONE (immediate
|
||||
|
||||
@@ -19,6 +19,7 @@ import { DiffTab } from '../DiffTab.tsx'
|
||||
import { SubagentView } from '../SubagentView.tsx'
|
||||
import { BrowserView } from '../BrowserView.tsx'
|
||||
import { IconTerminalOutline16, IconDiffOutline16, IconGlobeOutline16 } from '../icons.tsx'
|
||||
import { TERMINAL_FONT_SIZE_MAX, TERMINAL_FONT_SIZE_MIN } from '../../prefs-shared.ts'
|
||||
import type { ComponentType } from 'react'
|
||||
import type { SessionScope } from '../api.ts'
|
||||
import type { SidebarStore } from '../state.ts'
|
||||
@@ -137,10 +138,11 @@ export function builtinTabs(ctx: Context): readonly TabDescriptor[] {
|
||||
icon: (size: number) => <IconTerminalOutline16 size={size} />,
|
||||
order: 40,
|
||||
available: (_ctx, _scope, state) => uiTerminalCount(state) < TERMINAL_LIMIT,
|
||||
// Declarative settings: the model-facing terminal tools switch and the
|
||||
// bottom-panel first-expansion auto-terminal switch render under this
|
||||
// row in the Side card settings page (the Terminal page's own related
|
||||
// settings; the host gates the toolset on the tools one independently).
|
||||
// Declarative settings: the model-facing terminal tools switch, the
|
||||
// bottom-panel first-expansion auto-terminal switch, and the custom
|
||||
// font family/size rows render under this card in the Side card
|
||||
// settings page (the host gates the toolset on the tools one
|
||||
// independently; the font rows apply live to every terminal).
|
||||
settings: {
|
||||
toggles: [{
|
||||
key: 'agentTerminalTools',
|
||||
@@ -150,6 +152,20 @@ export function builtinTabs(ctx: Context): readonly TabDescriptor[] {
|
||||
key: 'bottomPanelAutoTerminal',
|
||||
title: () => t('settingsBottomTerminalTitle'),
|
||||
desc: () => t('settingsBottomTerminalDesc'),
|
||||
}, {
|
||||
key: 'terminalFontFamily',
|
||||
type: 'text',
|
||||
title: () => t('settingsFontFamilyTitle'),
|
||||
desc: () => t('settingsFontFamilyDesc'),
|
||||
placeholder: t('settingsFontFamilyPlaceholder'),
|
||||
}, {
|
||||
key: 'terminalFontSize',
|
||||
type: 'number',
|
||||
title: () => t('settingsFontSizeTitle'),
|
||||
desc: () => t('settingsFontSizeDesc'),
|
||||
min: TERMINAL_FONT_SIZE_MIN,
|
||||
max: TERMINAL_FONT_SIZE_MAX,
|
||||
unit: 'px',
|
||||
}],
|
||||
},
|
||||
createTab: (state) => {
|
||||
|
||||
@@ -136,6 +136,12 @@ export const zh = {
|
||||
settingsToolsDesc: '开启后,模型可通过 terminal_create 等 8 个工具创建并操作侧边栏终端(默认关闭)',
|
||||
settingsBottomTerminalTitle: '底部面板首次展开自动开终端',
|
||||
settingsBottomTerminalDesc: '每次会话中第一次展开底部面板时,尝试在底部面板自动打开一个新终端标签(终端数量上限仍会限制;默认开启)',
|
||||
settingsFontFamilyTitle: '终端字体',
|
||||
settingsFontFamilyDesc: '自定义终端字体族(CSS font-family,如 "JetBrains Mono", monospace;留空跟随主题等宽字体)',
|
||||
settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace',
|
||||
settingsFontSizeTitle: '终端字号',
|
||||
settingsFontSizeDesc: '终端字号(9–32,默认 13)',
|
||||
settingsFontSizeSuffix: 'px',
|
||||
settingsTabsTitle: '侧边栏内容',
|
||||
settingsViewersTitle: '文件预览',
|
||||
settingsGeneralTitle: '常规',
|
||||
@@ -340,6 +346,12 @@ export const en: Record<keyof typeof zh, string> = {
|
||||
settingsToolsDesc: 'When enabled, the model can create and drive sidebar terminals through the 8 terminal_* tools (off by default)',
|
||||
settingsBottomTerminalTitle: 'Auto-open a terminal on the bottom panel\'s first expansion',
|
||||
settingsBottomTerminalDesc: 'When the bottom panel is expanded for the first time in a session, try to open a fresh terminal tab there (the terminal quota still applies; on by default)',
|
||||
settingsFontFamilyTitle: 'Terminal font family',
|
||||
settingsFontFamilyDesc: 'Custom terminal font family (a CSS font-family stack like "JetBrains Mono", monospace; leave empty to follow the theme\'s monospace font)',
|
||||
settingsFontFamilyPlaceholder: '"JetBrains Mono", monospace',
|
||||
settingsFontSizeTitle: 'Terminal font size',
|
||||
settingsFontSizeDesc: 'Terminal font size in px (9–32, default 13)',
|
||||
settingsFontSizeSuffix: 'px',
|
||||
settingsTabsTitle: 'Sidebar content',
|
||||
settingsViewersTitle: 'File viewers',
|
||||
settingsGeneralTitle: 'General',
|
||||
|
||||
+8
-1
@@ -10,12 +10,13 @@
|
||||
*/
|
||||
import type { api } from './api.ts'
|
||||
import {
|
||||
clampTerminalFontSize,
|
||||
clampWidthPercent,
|
||||
SIDEBAR_PREFS_DEFAULTS,
|
||||
type SidebarPrefs,
|
||||
} from '../prefs-shared.ts'
|
||||
|
||||
export { SIDEBAR_PREFS_DEFAULTS, clampWidthPercent }
|
||||
export { SIDEBAR_PREFS_DEFAULTS, clampTerminalFontSize, clampWidthPercent }
|
||||
export type { SidebarPrefs }
|
||||
|
||||
/** The settings wire face the preferences need (a subset of the plugin api). */
|
||||
@@ -49,6 +50,12 @@ export function parsePrefs(value: unknown): SidebarPrefs {
|
||||
bottomPanelAutoTerminal: typeof record.bottomPanelAutoTerminal === 'boolean'
|
||||
? record.bottomPanelAutoTerminal
|
||||
: SIDEBAR_PREFS_DEFAULTS.bottomPanelAutoTerminal,
|
||||
terminalFontFamily: typeof record.terminalFontFamily === 'string'
|
||||
? record.terminalFontFamily
|
||||
: SIDEBAR_PREFS_DEFAULTS.terminalFontFamily,
|
||||
terminalFontSize: typeof record.terminalFontSize === 'number' && Number.isFinite(record.terminalFontSize)
|
||||
? clampTerminalFontSize(record.terminalFontSize)
|
||||
: SIDEBAR_PREFS_DEFAULTS.terminalFontSize,
|
||||
interceptOpenPath: typeof record.interceptOpenPath === 'boolean'
|
||||
? record.interceptOpenPath
|
||||
: SIDEBAR_PREFS_DEFAULTS.interceptOpenPath,
|
||||
|
||||
+22
-5
@@ -28,9 +28,15 @@ import {
|
||||
import { isNarrowWidth } from './breakpoints.ts'
|
||||
import type { SessionScope } from './api.ts'
|
||||
|
||||
/** One declarative boolean setting of a tab/viewer, rendered as a nested
|
||||
* switch row in the Side card settings page (e.g. the Subagent page's
|
||||
* "auto-open when a subagent appears"). */
|
||||
/** The row control a declarative setting renders as in the settings popup. */
|
||||
export type SidebarSettingToggleType = 'switch' | 'text' | 'number'
|
||||
|
||||
/** One declarative setting of a tab/viewer, rendered as a nested row in the
|
||||
* Side card settings page (e.g. the Subagent page's "auto-open when a
|
||||
* subagent appears" switch, or the terminal's custom font rows). `type`
|
||||
* selects the control: 'switch' (default) renders the custom switch,
|
||||
* 'text' a free-form input committed on blur/Enter, 'number' a numeric
|
||||
* input clamped to `min`/`max`. */
|
||||
export interface SidebarSettingToggle {
|
||||
/** The SidebarPrefs field this toggle reads and writes ('autoOpenSubagent'). */
|
||||
key: string
|
||||
@@ -38,15 +44,26 @@ export interface SidebarSettingToggle {
|
||||
title: string | (() => string)
|
||||
/** Row description (i18n friendly). */
|
||||
desc?: string | (() => string)
|
||||
/** Row control type; defaults to 'switch' (backward compatible). */
|
||||
type?: SidebarSettingToggleType
|
||||
/** Lower bound for `type: 'number'` rows (clamped on commit). */
|
||||
min?: number
|
||||
/** Upper bound for `type: 'number'` rows (clamped on commit). */
|
||||
max?: number
|
||||
/** Input placeholder for `type: 'text'` rows. */
|
||||
placeholder?: string
|
||||
/** Unit suffix rendered after the input (e.g. 'px' for a size row). */
|
||||
unit?: string
|
||||
}
|
||||
|
||||
/** Declarative settings of one registered tab or file viewer. */
|
||||
export interface SidebarSettingsDeclaration {
|
||||
/**
|
||||
* Extra boolean toggles rendered under the feature's own row in the
|
||||
* Extra settings rows rendered under the feature's own row in the
|
||||
* settings page (only while the feature is enabled). Keys must be fields
|
||||
* of the host's PrefsSchema (built-ins: 'autoOpenSubagent',
|
||||
* 'agentTerminalTools'); unknown keys are dropped by the settings seam.
|
||||
* 'agentTerminalTools', 'terminalFontFamily'); unknown keys are dropped
|
||||
* by the settings seam.
|
||||
*/
|
||||
toggles?: readonly SidebarSettingToggle[]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Terminal font resolution: the user's custom font prefs (SidebarPrefs,
|
||||
* configured under the terminal card's secondary settings) turned into the
|
||||
* xterm options. Kept as a pure module (no DOM, no xterm) so the fallback
|
||||
* chain and clamping are unit-testable without mounting a terminal.
|
||||
*/
|
||||
import { clampTerminalFontSize, type SidebarPrefs } from '../prefs-shared.ts'
|
||||
|
||||
/** The built-in fallback stack when neither the user nor the theme sets one. */
|
||||
export const DEFAULT_TERMINAL_FONT_FAMILY = '"SF Mono", Menlo, Consolas, "Liberation Mono", monospace'
|
||||
|
||||
/**
|
||||
* Resolve the xterm font options for the given prefs.
|
||||
* @param prefs - the current side card preferences.
|
||||
* @param themeFontFamily - the app's theme code font (`--ds-font-family-code`
|
||||
* token value, read live by the caller); undefined when the token is absent.
|
||||
* @returns the `fontFamily` / `fontSize` xterm options.
|
||||
*/
|
||||
export function resolveTerminalFont(
|
||||
prefs: SidebarPrefs,
|
||||
themeFontFamily: string | undefined,
|
||||
): { fontFamily: string; fontSize: number } {
|
||||
const custom = prefs.terminalFontFamily.trim()
|
||||
return {
|
||||
fontFamily: custom !== '' ? custom : (themeFontFamily || DEFAULT_TERMINAL_FONT_FAMILY),
|
||||
fontSize: clampTerminalFontSize(prefs.terminalFontSize),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user