From d65eabe4941d28deac9b0172742ed11364da8ae8 Mon Sep 17 00:00:00 2001 From: Mike Sawka Date: Thu, 24 Oct 2024 11:01:39 -0700 Subject: [PATCH] termfontsize override (#1118) --- frontend/app/block/block.tsx | 2 +- frontend/app/view/term/term.tsx | 88 ++++++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/frontend/app/block/block.tsx b/frontend/app/block/block.tsx index 98120959c..12d879a70 100644 --- a/frontend/app/block/block.tsx +++ b/frontend/app/block/block.tsx @@ -36,7 +36,7 @@ type FullBlockProps = { function makeViewModel(blockId: string, blockView: string, nodeModel: NodeModel): ViewModel { if (blockView === "term") { - return makeTerminalModel(blockId); + return makeTerminalModel(blockId, nodeModel); } if (blockView === "preview") { return makePreviewModel(blockId, nodeModel); diff --git a/frontend/app/view/term/term.tsx b/frontend/app/view/term/term.tsx index bbba038b3..71cad44b4 100644 --- a/frontend/app/view/term/term.tsx +++ b/frontend/app/view/term/term.tsx @@ -6,7 +6,16 @@ import { waveEventSubscribe } from "@/app/store/wps"; import { RpcApi } from "@/app/store/wshclientapi"; import { WindowRpcClient } from "@/app/store/wshrpcutil"; import { VDomView } from "@/app/view/term/vdom"; -import { WOS, atoms, getConnStatusAtom, getSettingsKeyAtom, globalStore, useSettingsPrefixAtom } from "@/store/global"; +import { NodeModel } from "@/layout/index"; +import { + WOS, + atoms, + getConnStatusAtom, + getSettingsKeyAtom, + globalStore, + useBlockAtom, + useSettingsPrefixAtom, +} from "@/store/global"; import * as services from "@/store/services"; import * as keyutil from "@/util/keyutil"; import * as util from "@/util/util"; @@ -106,15 +115,19 @@ class TermViewModel { termMode: jotai.Atom; htmlElemFocusRef: React.RefObject; blockId: string; + nodeModel: NodeModel; viewIcon: jotai.Atom; viewName: jotai.Atom; blockBg: jotai.Atom; manageConnection: jotai.Atom; connStatus: jotai.Atom; + fontSizeAtom: jotai.Atom; + termThemeNameAtom: jotai.Atom; - constructor(blockId: string) { + constructor(blockId: string, nodeModel: NodeModel) { this.viewType = "term"; this.blockId = blockId; + this.nodeModel = nodeModel; this.blockAtom = WOS.getWaveObjectAtom(`block:${blockId}`); this.termMode = jotai.atom((get) => { const blockData = get(this.blockAtom); @@ -150,6 +163,25 @@ class TermViewModel { const connAtom = getConnStatusAtom(connName); return get(connAtom); }); + this.fontSizeAtom = useBlockAtom(blockId, "fontsizeatom", () => { + return jotai.atom((get) => { + const blockData = get(this.blockAtom); + const fsSettingsAtom = getSettingsKeyAtom("term:fontsize"); + const settingsFontSize = get(fsSettingsAtom); + const rtnFontSize = blockData?.meta?.["term:fontsize"] ?? settingsFontSize ?? 12; + if (typeof rtnFontSize != "number" || isNaN(rtnFontSize) || rtnFontSize < 4 || rtnFontSize > 64) { + return 12; + } + return rtnFontSize; + }); + }); + this.termThemeNameAtom = useBlockAtom(blockId, "termthemeatom", () => { + return jotai.atom((get) => { + const blockData = get(this.blockAtom); + const settingsKeyAtom = getSettingsKeyAtom("term:theme"); + return blockData?.meta?.["term:theme"] ?? get(settingsKeyAtom) ?? "default-dark"; + }); + }); } giveFocus(): boolean { @@ -179,6 +211,10 @@ class TermViewModel { const fullConfig = globalStore.get(atoms.fullConfigAtom); const termThemes = fullConfig?.termthemes ?? {}; const termThemeKeys = Object.keys(termThemes); + const curThemeName = globalStore.get(this.termThemeNameAtom); + const defaultFontSize = globalStore.get(getSettingsKeyAtom("term:fontsize")) ?? 12; + const blockData = globalStore.get(this.blockAtom); + const overrideFontSize = blockData?.meta?.["term:fontsize"]; termThemeKeys.sort((a, b) => { return termThemes[a]["display:order"] - termThemes[b]["display:order"]; @@ -187,13 +223,45 @@ class TermViewModel { const submenu: ContextMenuItem[] = termThemeKeys.map((themeName) => { return { label: termThemes[themeName]["display:name"] ?? themeName, + type: "checkbox", + checked: curThemeName == themeName, click: () => this.setTerminalTheme(themeName), }; }); + const fontSizeSubMenu: ContextMenuItem[] = [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18].map( + (fontSize: number) => { + return { + label: fontSize.toString() + "px", + type: "checkbox", + checked: overrideFontSize == fontSize, + click: () => { + RpcApi.SetMetaCommand(WindowRpcClient, { + oref: WOS.makeORef("block", this.blockId), + meta: { "term:fontsize": fontSize }, + }); + }, + }; + } + ); + fontSizeSubMenu.unshift({ + label: "Default (" + defaultFontSize + "px)", + type: "checkbox", + checked: overrideFontSize == null, + click: () => { + RpcApi.SetMetaCommand(WindowRpcClient, { + oref: WOS.makeORef("block", this.blockId), + meta: { "term:fontsize": null }, + }); + }, + }); fullMenu.push({ label: "Themes", submenu: submenu, }); + fullMenu.push({ + label: "Font Size", + submenu: fontSizeSubMenu, + }); fullMenu.push({ type: "separator" }); fullMenu.push({ label: "Force Restart Controller", @@ -215,8 +283,8 @@ class TermViewModel { } } -function makeTerminalModel(blockId: string): TermViewModel { - return new TermViewModel(blockId); +function makeTerminalModel(blockId: string, nodeModel: NodeModel): TermViewModel { + return new TermViewModel(blockId, nodeModel); } interface TerminalViewProps { @@ -258,6 +326,8 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { const termSettingsAtom = useSettingsPrefixAtom("term"); const termSettings = jotai.useAtomValue(termSettingsAtom); + const termFontSize = jotai.useAtomValue(model.fontSizeAtom); + React.useEffect(() => { function handleTerminalKeydown(event: KeyboardEvent): boolean { const waveEvent = keyutil.adaptFromReactOrNativeKeyEvent(event); @@ -321,12 +391,13 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { if (termScrollback > 10000) { termScrollback = 10000; } + const wasFocused = termRef.current != null && globalStore.get(model.nodeModel.isFocused); const termWrap = new TermWrap( blockId, connectElemRef.current, { theme: themeCopy, - fontSize: termSettings?.["term:fontsize"] ?? 12, + fontSize: termFontSize, fontFamily: termSettings?.["term:fontfamily"] ?? "Hack", drawBoldTextInBrightColors: false, fontWeight: "normal", @@ -346,11 +417,16 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { }); rszObs.observe(connectElemRef.current); termWrap.initTerminal(); + if (wasFocused) { + setTimeout(() => { + model.giveFocus(); + }, 10); + } return () => { termWrap.dispose(); rszObs.disconnect(); }; - }, [blockId, termSettings]); + }, [blockId, termSettings, termFontSize]); const handleHtmlKeyDown = (event: React.KeyboardEvent) => { const waveEvent = keyutil.adaptFromReactOrNativeKeyEvent(event);