Files
NetMesh/domain/terminalCjkFonts.ts
zhaolei 3c72efcb7f
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
[Init] Initial commit - NetMesh terminal manager
2026-09-13 18:24:01 +08:00

113 lines
3.4 KiB
TypeScript

export type TerminalCjkFontOptionKind =
| 'auto'
| 'recommended'
| 'installed'
| 'unverified'
| 'unavailable';
export interface TerminalCjkFontOption {
value: string;
kind: TerminalCjkFontOptionKind;
}
export const RECOMMENDED_CJK_FONT_FAMILIES = [
'Sarasa Mono SC',
'Sarasa Mono TC',
'Maple Mono CN',
'Source Han Mono SC',
'Noto Sans Mono CJK SC',
'LXGW WenKai Mono',
'SimSun',
] as const;
const recommendedByLower = new Map(
RECOMMENDED_CJK_FONT_FAMILIES.map((family) => [family.toLowerCase(), family]),
);
const normalize = (value: string): string => value.trim().toLowerCase();
interface BuildOptionsArgs {
installedFamilies: readonly string[] | null | undefined;
selectedValue: string;
availableRecommendedFamilies?: readonly string[];
}
export function buildTerminalCjkFontOptions({
installedFamilies,
selectedValue,
availableRecommendedFamilies = [],
}: BuildOptionsArgs): TerminalCjkFontOption[] {
const trimmedSelected = selectedValue.trim();
const selectedKey = normalize(trimmedSelected);
const preserveSelectedValue = (family: string): string =>
normalize(family) === selectedKey && trimmedSelected ? selectedValue : family;
const installedByLower = new Map<string, string>();
for (const rawFamily of installedFamilies ?? []) {
const family = rawFamily.trim();
if (!family) continue;
const key = normalize(family);
if (!installedByLower.has(key)) installedByLower.set(key, family);
}
const availableRecommended = new Set(
availableRecommendedFamilies.map(normalize),
);
const options: TerminalCjkFontOption[] = [{ value: '', kind: 'auto' }];
for (const family of RECOMMENDED_CJK_FONT_FAMILIES) {
const key = normalize(family);
if (!installedByLower.has(key) && !availableRecommended.has(key)) continue;
options.push({ value: preserveSelectedValue(family), kind: 'recommended' });
installedByLower.delete(key);
}
const remainingInstalled = [...installedByLower.values()].sort((a, b) =>
a.localeCompare(b, undefined, { sensitivity: 'base' }),
);
options.push(
...remainingInstalled.map((value) => ({
value: preserveSelectedValue(value),
kind: 'installed' as const,
})),
);
const alreadyVisible = options.some((option) => normalize(option.value) === selectedKey);
if (trimmedSelected && !alreadyVisible) {
options.push({
value: selectedValue,
kind: installedFamilies == null ? 'unverified' : 'unavailable',
});
}
return options;
}
export type TerminalCjkFontSelectionStatus =
| 'auto'
| 'recommended'
| 'alignment-risk'
| 'unavailable';
export function getTerminalCjkFontSelectionStatus(
value: string,
installedFamilies: readonly string[] | null | undefined,
availableRecommendedFamilies: readonly string[] = [],
selectedFontAvailable = false,
): TerminalCjkFontSelectionStatus {
const normalizedValue = normalize(value);
if (!normalizedValue) return 'auto';
const isInstalled = (installedFamilies ?? []).some(
(family) => normalize(family) === normalizedValue,
);
const isAvailableRecommended = availableRecommendedFamilies.some(
(family) => normalize(family) === normalizedValue,
);
const isAvailable = isInstalled || isAvailableRecommended || selectedFontAvailable;
if (recommendedByLower.has(normalizedValue) && isAvailable) {
return 'recommended';
}
if (installedFamilies == null) return 'alignment-risk';
return isAvailable ? 'alignment-risk' : 'unavailable';
}