mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
add support for "Hack" font family (#309)
* testing hack font * updates to allow font to be variable * allow setting of font-family. get initial font family from electron (needed for loading) * add termfontfamily * update wave logos for README * hook up fontfamily setting, remove old dropdown active var * get app to reload on font change. reload fonts * on termfontsize change, bump render version as well
This commit is contained in:
parent
743d6d8622
commit
3f83b30b06
@ -1,3 +1,4 @@
|
|||||||
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVBDxyg/GY/QdcIEZw=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
|
BIN
public/fonts/hack-bold.woff2
Normal file
BIN
public/fonts/hack-bold.woff2
Normal file
Binary file not shown.
BIN
public/fonts/hack-bolditalic.woff2
Normal file
BIN
public/fonts/hack-bolditalic.woff2
Normal file
Binary file not shown.
BIN
public/fonts/hack-italic.woff2
Normal file
BIN
public/fonts/hack-italic.woff2
Normal file
Binary file not shown.
BIN
public/fonts/hack-regular.woff2
Normal file
BIN
public/fonts/hack-regular.woff2
Normal file
Binary file not shown.
@ -1,12 +1,5 @@
|
|||||||
@import "./common/themes/themes.less";
|
@import "./common/themes/themes.less";
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Martian Mono";
|
|
||||||
src: url("./assets/fonts/MartianMono-VariableFont_wdth,wght.ttf") format("truetype");
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--fa-style-family: "Font Awesome 6 Sharp";
|
--fa-style-family: "Font Awesome 6 Sharp";
|
||||||
}
|
}
|
||||||
@ -98,7 +91,7 @@ body a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body code {
|
body code {
|
||||||
font-family: @terminal-font;
|
font-family: var(--termfontfamily);
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +305,7 @@ a.a-block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mono {
|
.mono {
|
||||||
font-family: @terminal-font;
|
font-family: var(--termfontfamily);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,8 +105,15 @@ class App extends React.Component<{}, {}> {
|
|||||||
if (dcWait) {
|
if (dcWait) {
|
||||||
setTimeout(() => this.updateDcWait(false), 0);
|
setTimeout(() => this.updateDcWait(false), 0);
|
||||||
}
|
}
|
||||||
|
// used to force a full reload of the application
|
||||||
|
let renderVersion = GlobalModel.renderVersion.get();
|
||||||
return (
|
return (
|
||||||
<div id="main" className={"platform-" + platform} onContextMenu={this.handleContextMenu}>
|
<div
|
||||||
|
key={"version-" + renderVersion}
|
||||||
|
id="main"
|
||||||
|
className={"platform-" + platform}
|
||||||
|
onContextMenu={this.handleContextMenu}
|
||||||
|
>
|
||||||
<div ref={this.mainContentRef} className="main-content">
|
<div ref={this.mainContentRef} className="main-content">
|
||||||
<MainSideBar parentRef={this.mainContentRef} clientData={clientData} />
|
<MainSideBar parentRef={this.mainContentRef} clientData={clientData} />
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
padding: 0 18px 0 30px;
|
padding: 0 18px 0 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wave-dropdown {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
// just marked these as important since we're keeping the
|
// just marked these as important since we're keeping the
|
||||||
// settings-field styles below this intact until we figure out what do with them
|
// settings-field styles below this intact until we figure out what do with them
|
||||||
.settings-field {
|
.settings-field {
|
||||||
|
@ -15,9 +15,6 @@ import "./clientsettings.less";
|
|||||||
|
|
||||||
@mobxReact.observer
|
@mobxReact.observer
|
||||||
class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
|
class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hoveredItemId: string }> {
|
||||||
fontSizeDropdownActive: OV<boolean> = mobx.observable.box(false, {
|
|
||||||
name: "clientSettings-fontSizeDropdownActive",
|
|
||||||
});
|
|
||||||
errorMessage: OV<string> = mobx.observable.box(null, { name: "ClientSettings-errorMessage" });
|
errorMessage: OV<string> = mobx.observable.box(null, { name: "ClientSettings-errorMessage" });
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
@ -30,7 +27,6 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
|||||||
@boundMethod
|
@boundMethod
|
||||||
handleChangeFontSize(fontSize: string): void {
|
handleChangeFontSize(fontSize: string): void {
|
||||||
const newFontSize = Number(fontSize);
|
const newFontSize = Number(fontSize);
|
||||||
this.fontSizeDropdownActive.set(false);
|
|
||||||
if (GlobalModel.termFontSize.get() == newFontSize) {
|
if (GlobalModel.termFontSize.get() == newFontSize) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -39,10 +35,12 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
|||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
togglefontSizeDropdown(): void {
|
handleChangeFontFamily(fontFamily: string): void {
|
||||||
mobx.action(() => {
|
if (GlobalModel.getTermFontFamily() == fontFamily) {
|
||||||
this.fontSizeDropdownActive.set(!this.fontSizeDropdownActive.get());
|
return;
|
||||||
})();
|
}
|
||||||
|
const prtn = GlobalCommandRunner.setTermFontFamily(fontFamily, false);
|
||||||
|
commandRtnHandler(prtn, this.errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
@ -75,6 +73,13 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
|||||||
return availableFontSizes;
|
return availableFontSizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFontFamilies(): DropdownItem[] {
|
||||||
|
const availableFontFamilies: DropdownItem[] = [];
|
||||||
|
availableFontFamilies.push({ label: "JetBrains Mono", value: "JetBrains Mono" });
|
||||||
|
availableFontFamilies.push({ label: "Hack", value: "Hack" });
|
||||||
|
return availableFontFamilies;
|
||||||
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
inlineUpdateOpenAIModel(newModel: string): void {
|
inlineUpdateOpenAIModel(newModel: string): void {
|
||||||
const prtn = GlobalCommandRunner.setClientOpenAISettings({ model: newModel });
|
const prtn = GlobalCommandRunner.setClientOpenAISettings({ model: newModel });
|
||||||
@ -140,6 +145,7 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
|||||||
openAIOpts.maxtokens == null || openAIOpts.maxtokens == 0 ? 1000 : openAIOpts.maxtokens
|
openAIOpts.maxtokens == null || openAIOpts.maxtokens == 0 ? 1000 : openAIOpts.maxtokens
|
||||||
);
|
);
|
||||||
const curFontSize = GlobalModel.termFontSize.get();
|
const curFontSize = GlobalModel.termFontSize.get();
|
||||||
|
const curFontFamily = GlobalModel.getTermFontFamily();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("view clientsettings-view")}>
|
<div className={cn("view clientsettings-view")}>
|
||||||
@ -161,6 +167,17 @@ class ClientSettingsView extends React.Component<{ model: RemotesModel }, { hove
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="settings-field">
|
||||||
|
<div className="settings-label">Term Font Family</div>
|
||||||
|
<div className="settings-input">
|
||||||
|
<Dropdown
|
||||||
|
className="font-size-dropdown"
|
||||||
|
options={this.getFontFamilies()}
|
||||||
|
defaultValue={curFontFamily}
|
||||||
|
onChange={this.handleChangeFontFamily}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="settings-field">
|
<div className="settings-field">
|
||||||
<div className="settings-label">Client ID</div>
|
<div className="settings-label">Client ID</div>
|
||||||
<div className="settings-input">{cdata.clientid}</div>
|
<div className="settings-input">{cdata.clientid}</div>
|
||||||
|
@ -10,14 +10,14 @@
|
|||||||
code {
|
code {
|
||||||
background-color: @markdown-highlight;
|
background-color: @markdown-highlight;
|
||||||
color: @term-white;
|
color: @term-white;
|
||||||
font-family: @terminal-font;
|
font-family: var(--termfontfamily);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
code.inline {
|
code.inline {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
font-family: @terminal-font;
|
font-family: var(--termfontfamily);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
@import "@/common/themes/themes.less";
|
@import "@/common/themes/themes.less";
|
||||||
|
|
||||||
.term-prompt {
|
.term-prompt {
|
||||||
font-weight: 300;
|
font-weight: normal;
|
||||||
|
font-family: var(--termfontfamily);
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
margin: 0 4px 0 2px;
|
margin: 0 4px 0 2px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
@ -69,7 +69,6 @@
|
|||||||
|
|
||||||
// @font-face declaration lives in app.less
|
// @font-face declaration lives in app.less
|
||||||
@fixed-font: "Martian Mono", sans-serif;
|
@fixed-font: "Martian Mono", sans-serif;
|
||||||
@terminal-font: "JetBrains Mono", sans-serif;
|
|
||||||
|
|
||||||
@text-s1-font: "Martian Mono", sans-serif;
|
@text-s1-font: "Martian Mono", sans-serif;
|
||||||
|
|
||||||
|
@ -492,7 +492,8 @@ class LineCmd extends React.Component<
|
|||||||
maxSize: screen.getMaxContentSize(),
|
maxSize: screen.getMaxContentSize(),
|
||||||
idealSize: screen.getIdealContentSize(),
|
idealSize: screen.getIdealContentSize(),
|
||||||
termOpts: cmd.getTermOpts(),
|
termOpts: cmd.getTermOpts(),
|
||||||
termFontSize: GlobalModel.termFontSize.get(),
|
termFontSize: GlobalModel.getTermFontSize(),
|
||||||
|
termFontFamily: GlobalModel.getTermFontFamily(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.cmd-rtnstate-label {
|
.cmd-rtnstate-label {
|
||||||
font-family: @terminal-font;
|
font-family: var(--termfontfamily);
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
@ -145,7 +145,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cmd-rtnstate-diff {
|
.cmd-rtnstate-diff {
|
||||||
font-family: @terminal-font;
|
font-family: var(--termfontfamily);
|
||||||
color: @term-white;
|
color: @term-white;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
|
@ -137,7 +137,8 @@
|
|||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
font-family: @terminal-font;
|
font-family: var(--termfontfamily);
|
||||||
|
font-weight: normal;
|
||||||
&.display-disabled {
|
&.display-disabled {
|
||||||
background-color: #444;
|
background-color: #444;
|
||||||
}
|
}
|
||||||
@ -229,7 +230,8 @@
|
|||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
font-family: @terminal-font;
|
font-family: var(--termfontfamily);
|
||||||
|
font-weight: normal;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
@ -31,6 +31,7 @@ let oldConsoleLog = console.log;
|
|||||||
let wasActive = true;
|
let wasActive = true;
|
||||||
let wasInFg = true;
|
let wasInFg = true;
|
||||||
let currentGlobalShortcut: string | null = null;
|
let currentGlobalShortcut: string | null = null;
|
||||||
|
let initialClientData: ClientDataType = null;
|
||||||
|
|
||||||
checkPromptMigrate();
|
checkPromptMigrate();
|
||||||
ensureDir(waveHome);
|
ensureDir(waveHome);
|
||||||
@ -519,6 +520,11 @@ electron.ipcMain.on("wavesrv-status", (event) => {
|
|||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
electron.ipcMain.on("get-initial-termfontfamily", (event) => {
|
||||||
|
event.returnValue = initialClientData?.feopts?.termfontfamily;
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
electron.ipcMain.on("restart-server", (event) => {
|
electron.ipcMain.on("restart-server", (event) => {
|
||||||
if (waveSrvProc != null) {
|
if (waveSrvProc != null) {
|
||||||
waveSrvProc.kill();
|
waveSrvProc.kill();
|
||||||
@ -709,6 +715,7 @@ async function createMainWindowWrap() {
|
|||||||
let clientData: ClientDataType | null = null;
|
let clientData: ClientDataType | null = null;
|
||||||
try {
|
try {
|
||||||
clientData = await getClientDataPoll(1);
|
clientData = await getClientDataPoll(1);
|
||||||
|
initialClientData = clientData;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("error getting wavesrv clientdata", e.toString());
|
console.log("error getting wavesrv clientdata", e.toString());
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ contextBridge.exposeInMainWorld("api", {
|
|||||||
ipcRenderer.send("get-last-logs", numberOfLines);
|
ipcRenderer.send("get-last-logs", numberOfLines);
|
||||||
ipcRenderer.once("last-logs", (event, data) => callback(data));
|
ipcRenderer.once("last-logs", (event, data) => callback(data));
|
||||||
},
|
},
|
||||||
|
getInitialTermFontFamily: () => ipcRenderer.sendSync("get-initial-termfontfamily"),
|
||||||
restartWaveSrv: () => ipcRenderer.sendSync("restart-server"),
|
restartWaveSrv: () => ipcRenderer.sendSync("restart-server"),
|
||||||
reloadWindow: () => ipcRenderer.sendSync("reload-window"),
|
reloadWindow: () => ipcRenderer.sendSync("reload-window"),
|
||||||
reregisterGlobalShortcut: (shortcut) => ipcRenderer.sendSync("reregister-global-shortcut", shortcut),
|
reregisterGlobalShortcut: (shortcut) => ipcRenderer.sendSync("reregister-global-shortcut", shortcut),
|
||||||
|
@ -9,13 +9,18 @@ import { App } from "@/app/app";
|
|||||||
import * as DOMPurify from "dompurify";
|
import * as DOMPurify from "dompurify";
|
||||||
import { loadFonts } from "./util/util";
|
import { loadFonts } from "./util/util";
|
||||||
import * as textmeasure from "./util/textmeasure";
|
import * as textmeasure from "./util/textmeasure";
|
||||||
|
import { getApi } from "@/models";
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
let VERSION = __WAVETERM_VERSION__;
|
let VERSION = __WAVETERM_VERSION__;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
let BUILD = __WAVETERM_BUILD__;
|
let BUILD = __WAVETERM_BUILD__;
|
||||||
|
|
||||||
loadFonts();
|
let initialFontFamily = getApi().getInitialTermFontFamily();
|
||||||
|
if (initialFontFamily == null) {
|
||||||
|
initialFontFamily = "JetBrains Mono";
|
||||||
|
}
|
||||||
|
loadFonts(initialFontFamily);
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
let reactElem = React.createElement(App, null, null);
|
let reactElem = React.createElement(App, null, null);
|
||||||
@ -26,6 +31,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// put some items on the window for debugging
|
||||||
(window as any).mobx = mobx;
|
(window as any).mobx = mobx;
|
||||||
(window as any).sprintf = sprintf;
|
(window as any).sprintf = sprintf;
|
||||||
(window as any).DOMPurify = DOMPurify;
|
(window as any).DOMPurify = DOMPurify;
|
||||||
|
@ -353,6 +353,14 @@ class CommandRunner {
|
|||||||
return GlobalModel.submitCommand("client", "set", null, kwargs, interactive);
|
return GlobalModel.submitCommand("client", "set", null, kwargs, interactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTermFontFamily(fontFamily: string, interactive: boolean): Promise<CommandRtnType> {
|
||||||
|
let kwargs = {
|
||||||
|
nohist: "1",
|
||||||
|
termfontfamily: fontFamily,
|
||||||
|
};
|
||||||
|
return GlobalModel.submitCommand("client", "set", null, kwargs, interactive);
|
||||||
|
}
|
||||||
|
|
||||||
setClientOpenAISettings(opts: { model?: string; apitoken?: string; maxtokens?: string }): Promise<CommandRtnType> {
|
setClientOpenAISettings(opts: { model?: string; apitoken?: string; maxtokens?: string }): Promise<CommandRtnType> {
|
||||||
let kwargs = {
|
let kwargs = {
|
||||||
nohist: "1",
|
nohist: "1",
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
genMergeSimpleData,
|
genMergeSimpleData,
|
||||||
isModKeyPress,
|
isModKeyPress,
|
||||||
isBlank,
|
isBlank,
|
||||||
|
loadFonts,
|
||||||
} from "@/util/util";
|
} from "@/util/util";
|
||||||
import { WSControl } from "./ws";
|
import { WSControl } from "./ws";
|
||||||
import { cmdStatusIsRunning } from "@/app/line/lineutil";
|
import { cmdStatusIsRunning } from "@/app/line/lineutil";
|
||||||
@ -120,6 +121,10 @@ class Model {
|
|||||||
});
|
});
|
||||||
packetSeqNum: number = 0;
|
packetSeqNum: number = 0;
|
||||||
|
|
||||||
|
renderVersion: OV<number> = mobx.observable.box(0, {
|
||||||
|
name: "renderVersion",
|
||||||
|
});
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
this.clientId = getApi().getId();
|
this.clientId = getApi().getId();
|
||||||
this.isDev = getApi().getIsDev();
|
this.isDev = getApi().getIsDev();
|
||||||
@ -185,6 +190,12 @@ class Model {
|
|||||||
return (window as any).GlobalModel;
|
return (window as any).GlobalModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bumpRenderVersion() {
|
||||||
|
mobx.action(() => {
|
||||||
|
this.renderVersion.set(this.renderVersion.get() + 1);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
getNextPacketSeqNum(): number {
|
getNextPacketSeqNum(): number {
|
||||||
this.packetSeqNum++;
|
this.packetSeqNum++;
|
||||||
return this.packetSeqNum;
|
return this.packetSeqNum;
|
||||||
@ -314,6 +325,19 @@ class Model {
|
|||||||
return appconst.ProdServerEndpoint;
|
return appconst.ProdServerEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTermFontFamily(): string {
|
||||||
|
let cdata = this.clientData.get();
|
||||||
|
let ff = cdata?.feopts?.termfontfamily;
|
||||||
|
if (ff == null) {
|
||||||
|
ff = "JetBrains Mono, monospace";
|
||||||
|
}
|
||||||
|
return ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTermFontSize(): number {
|
||||||
|
return this.termFontSize.get();
|
||||||
|
}
|
||||||
|
|
||||||
setTermFontSize(fontSize: number) {
|
setTermFontSize(fontSize: number) {
|
||||||
if (fontSize < appconst.MinFontSize) {
|
if (fontSize < appconst.MinFontSize) {
|
||||||
fontSize = appconst.MinFontSize;
|
fontSize = appconst.MinFontSize;
|
||||||
@ -323,6 +347,7 @@ class Model {
|
|||||||
}
|
}
|
||||||
mobx.action(() => {
|
mobx.action(() => {
|
||||||
this.termFontSize.set(fontSize);
|
this.termFontSize.set(fontSize);
|
||||||
|
this.bumpRenderVersion();
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1114,6 +1139,15 @@ class Model {
|
|||||||
shortcut = clientData?.clientopts?.globalshortcut;
|
shortcut = clientData?.clientopts?.globalshortcut;
|
||||||
}
|
}
|
||||||
getApi().reregisterGlobalShortcut(shortcut);
|
getApi().reregisterGlobalShortcut(shortcut);
|
||||||
|
let fontFamily = clientData?.feopts?.termfontfamily;
|
||||||
|
if (fontFamily == null) {
|
||||||
|
fontFamily = "JetBrains Mono";
|
||||||
|
}
|
||||||
|
loadFonts(fontFamily);
|
||||||
|
document.fonts.ready.then(() => {
|
||||||
|
clearMonoFontCache();
|
||||||
|
this.bumpRenderVersion();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
submitCommandPacket(cmdPk: FeCmdPacketType, interactive: boolean): Promise<CommandRtnType> {
|
submitCommandPacket(cmdPk: FeCmdPacketType, interactive: boolean): Promise<CommandRtnType> {
|
||||||
@ -1452,4 +1486,4 @@ class Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Model };
|
export { Model, getApi };
|
||||||
|
@ -190,7 +190,8 @@ class RemotesModel {
|
|||||||
},
|
},
|
||||||
focusHandler: this.setRemoteTermWrapFocus.bind(this),
|
focusHandler: this.setRemoteTermWrapFocus.bind(this),
|
||||||
isRunning: true,
|
isRunning: true,
|
||||||
fontSize: this.globalModel.termFontSize.get(),
|
fontSize: this.globalModel.getTermFontSize(),
|
||||||
|
fontFamily: this.globalModel.getTermFontFamily(),
|
||||||
ptyDataSource: getTermPtyData,
|
ptyDataSource: getTermPtyData,
|
||||||
onUpdateContentHeight: null,
|
onUpdateContentHeight: null,
|
||||||
});
|
});
|
||||||
|
@ -588,7 +588,8 @@ class Screen {
|
|||||||
focusHandler: (focus: boolean) => this.setLineFocus(line.linenum, focus),
|
focusHandler: (focus: boolean) => this.setLineFocus(line.linenum, focus),
|
||||||
isRunning: cmd.isRunning(),
|
isRunning: cmd.isRunning(),
|
||||||
customKeyHandler: this.termCustomKeyHandler.bind(this),
|
customKeyHandler: this.termCustomKeyHandler.bind(this),
|
||||||
fontSize: this.globalModel.termFontSize.get(),
|
fontSize: this.globalModel.getTermFontSize(),
|
||||||
|
fontFamily: this.globalModel.getTermFontFamily(),
|
||||||
ptyDataSource: getTermPtyData,
|
ptyDataSource: getTermPtyData,
|
||||||
onUpdateContentHeight: (termContext: RendererContext, height: number) => {
|
onUpdateContentHeight: (termContext: RendererContext, height: number) => {
|
||||||
this.globalModel.setContentHeight(termContext, height);
|
this.globalModel.setContentHeight(termContext, height);
|
||||||
|
@ -90,7 +90,8 @@ class SpecialLineContainer {
|
|||||||
focusHandler: null,
|
focusHandler: null,
|
||||||
isRunning: cmd.isRunning(),
|
isRunning: cmd.isRunning(),
|
||||||
customKeyHandler: null,
|
customKeyHandler: null,
|
||||||
fontSize: this.globalModel.termFontSize.get(),
|
fontSize: this.globalModel.getTermFontSize(),
|
||||||
|
fontFamily: this.globalModel.getTermFontFamily(),
|
||||||
ptyDataSource: getTermPtyData,
|
ptyDataSource: getTermPtyData,
|
||||||
onUpdateContentHeight: null,
|
onUpdateContentHeight: null,
|
||||||
});
|
});
|
||||||
|
@ -337,8 +337,8 @@ class SourceCodeRenderer extends React.Component<
|
|||||||
onMount={this.handleEditorDidMount}
|
onMount={this.handleEditorDidMount}
|
||||||
options={{
|
options={{
|
||||||
scrollBeyondLastLine: false,
|
scrollBeyondLastLine: false,
|
||||||
fontSize: GlobalModel.termFontSize.get() * 0.9,
|
fontSize: GlobalModel.getTermFontSize(),
|
||||||
/* fontFamily: "Martian Mono", */
|
fontFamily: GlobalModel.getTermFontFamily(),
|
||||||
readOnly: !this.getAllowEditing(),
|
readOnly: !this.getAllowEditing(),
|
||||||
}}
|
}}
|
||||||
onChange={this.handleEditorChange}
|
onChange={this.handleEditorChange}
|
||||||
|
@ -31,6 +31,7 @@ type TermWrapOpts = {
|
|||||||
isRunning: boolean;
|
isRunning: boolean;
|
||||||
customKeyHandler?: (event: any, termWrap: TermWrap) => boolean;
|
customKeyHandler?: (event: any, termWrap: TermWrap) => boolean;
|
||||||
fontSize: number;
|
fontSize: number;
|
||||||
|
fontFamily: string;
|
||||||
ptyDataSource: (termContext: TermContextUnion) => Promise<PtyDataType>;
|
ptyDataSource: (termContext: TermContextUnion) => Promise<PtyDataType>;
|
||||||
onUpdateContentHeight: (termContext: RendererContext, height: number) => void;
|
onUpdateContentHeight: (termContext: RendererContext, height: number) => void;
|
||||||
};
|
};
|
||||||
@ -53,6 +54,7 @@ class TermWrap {
|
|||||||
focusHandler: (focus: boolean) => void;
|
focusHandler: (focus: boolean) => void;
|
||||||
isRunning: boolean;
|
isRunning: boolean;
|
||||||
fontSize: number;
|
fontSize: number;
|
||||||
|
fontFamily: string;
|
||||||
onUpdateContentHeight: (termContext: RendererContext, height: number) => void;
|
onUpdateContentHeight: (termContext: RendererContext, height: number) => void;
|
||||||
ptyDataSource: (termContext: TermContextUnion) => Promise<PtyDataType>;
|
ptyDataSource: (termContext: TermContextUnion) => Promise<PtyDataType>;
|
||||||
initializing: boolean;
|
initializing: boolean;
|
||||||
@ -67,6 +69,7 @@ class TermWrap {
|
|||||||
this.focusHandler = opts.focusHandler;
|
this.focusHandler = opts.focusHandler;
|
||||||
this.isRunning = opts.isRunning;
|
this.isRunning = opts.isRunning;
|
||||||
this.fontSize = opts.fontSize;
|
this.fontSize = opts.fontSize;
|
||||||
|
this.fontFamily = opts.fontFamily;
|
||||||
this.ptyDataSource = opts.ptyDataSource;
|
this.ptyDataSource = opts.ptyDataSource;
|
||||||
this.onUpdateContentHeight = opts.onUpdateContentHeight;
|
this.onUpdateContentHeight = opts.onUpdateContentHeight;
|
||||||
this.initializing = true;
|
this.initializing = true;
|
||||||
@ -88,7 +91,7 @@ class TermWrap {
|
|||||||
rows: this.termSize.rows,
|
rows: this.termSize.rows,
|
||||||
cols: this.termSize.cols,
|
cols: this.termSize.cols,
|
||||||
fontSize: opts.fontSize,
|
fontSize: opts.fontSize,
|
||||||
fontFamily: "JetBrains Mono",
|
fontFamily: opts.fontFamily,
|
||||||
theme: { foreground: terminal.foreground, background: terminal.background },
|
theme: { foreground: terminal.foreground, background: terminal.background },
|
||||||
});
|
});
|
||||||
this.terminal.loadAddon(
|
this.terminal.loadAddon(
|
||||||
|
10
src/types/custom.d.ts
vendored
10
src/types/custom.d.ts
vendored
@ -471,6 +471,7 @@ declare global {
|
|||||||
idealSize: WindowSize;
|
idealSize: WindowSize;
|
||||||
termOpts: TermOptsType;
|
termOpts: TermOptsType;
|
||||||
termFontSize: number;
|
termFontSize: number;
|
||||||
|
termFontFamily: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RendererOptsUpdate = {
|
type RendererOptsUpdate = {
|
||||||
@ -558,6 +559,7 @@ declare global {
|
|||||||
|
|
||||||
type FeOptsType = {
|
type FeOptsType = {
|
||||||
termfontsize: number;
|
termfontsize: number;
|
||||||
|
termfontfamily: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ConfirmFlagsType = {
|
type ConfirmFlagsType = {
|
||||||
@ -589,6 +591,13 @@ declare global {
|
|||||||
fullscreen: boolean;
|
fullscreen: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type KeyModsType = {
|
||||||
|
meta?: boolean;
|
||||||
|
ctrl?: boolean;
|
||||||
|
alt?: boolean;
|
||||||
|
shift?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
type ClientDataType = {
|
type ClientDataType = {
|
||||||
clientid: string;
|
clientid: string;
|
||||||
userid: string;
|
userid: string;
|
||||||
@ -847,6 +856,7 @@ declare global {
|
|||||||
getPlatform: () => string;
|
getPlatform: () => string;
|
||||||
getAuthKey: () => string;
|
getAuthKey: () => string;
|
||||||
getWaveSrvStatus: () => boolean;
|
getWaveSrvStatus: () => boolean;
|
||||||
|
getInitialTermFontFamily: () => string;
|
||||||
restartWaveSrv: () => boolean;
|
restartWaveSrv: () => boolean;
|
||||||
reloadWindow: () => void;
|
reloadWindow: () => void;
|
||||||
openExternalLink: (url: string) => void;
|
openExternalLink: (url: string) => void;
|
||||||
|
@ -242,9 +242,19 @@ function incObs(inum: mobx.IObservableValue<number>) {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @check:font
|
function addToFontFaceSet(fontFaceSet: FontFaceSet, fontFace: FontFace) {
|
||||||
function loadFonts() {
|
// any cast to work around typing issue
|
||||||
const jbmFontNormal = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-regular.woff2')", {
|
(fontFaceSet as any).add(fontFace);
|
||||||
|
}
|
||||||
|
|
||||||
|
let isJetBrainsMonoLoaded = false;
|
||||||
|
|
||||||
|
function loadJetBrainsMonoFont() {
|
||||||
|
if (isJetBrainsMonoLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isJetBrainsMonoLoaded = true;
|
||||||
|
let jbmFontNormal = new FontFace("JetBrains Mono", "url('public/fonts/jetbrains-mono-v13-latin-regular.woff2')", {
|
||||||
style: "normal",
|
style: "normal",
|
||||||
weight: "400",
|
weight: "400",
|
||||||
});
|
});
|
||||||
@ -256,19 +266,78 @@ function loadFonts() {
|
|||||||
style: "normal",
|
style: "normal",
|
||||||
weight: "700",
|
weight: "700",
|
||||||
});
|
});
|
||||||
const faFont = new FontFace("FontAwesome", "url(public/fonts/fontawesome-webfont-4.7.woff2)", {
|
addToFontFaceSet(document.fonts, jbmFontNormal);
|
||||||
style: "normal",
|
addToFontFaceSet(document.fonts, jbmFont200);
|
||||||
weight: "normal",
|
addToFontFaceSet(document.fonts, jbmFont700);
|
||||||
});
|
|
||||||
const docFonts: any = document.fonts; // work around ts typing issue
|
|
||||||
docFonts.add(jbmFontNormal);
|
|
||||||
docFonts.add(jbmFont200);
|
|
||||||
docFonts.add(jbmFont700);
|
|
||||||
docFonts.add(faFont);
|
|
||||||
jbmFontNormal.load();
|
jbmFontNormal.load();
|
||||||
jbmFont200.load();
|
jbmFont200.load();
|
||||||
jbmFont700.load();
|
jbmFont700.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
let isHackFontLoaded = false;
|
||||||
|
|
||||||
|
function loadHackFont() {
|
||||||
|
if (isHackFontLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isHackFontLoaded = true;
|
||||||
|
let hackRegular = new FontFace("Hack", "url('public/fonts/hack-regular.woff2')", {
|
||||||
|
style: "normal",
|
||||||
|
weight: "400",
|
||||||
|
});
|
||||||
|
let hackBold = new FontFace("Hack", "url('public/fonts/hack-bold.woff2')", {
|
||||||
|
style: "normal",
|
||||||
|
weight: "700",
|
||||||
|
});
|
||||||
|
let hackItalic = new FontFace("Hack", "url('public/fonts/hack-italic.woff2')", {
|
||||||
|
style: "italic",
|
||||||
|
weight: "400",
|
||||||
|
});
|
||||||
|
let hackBoldItalic = new FontFace("Hack", "url('public/fonts/hack-bolditalic.woff2')", {
|
||||||
|
style: "italic",
|
||||||
|
weight: "700",
|
||||||
|
});
|
||||||
|
addToFontFaceSet(document.fonts, hackRegular);
|
||||||
|
addToFontFaceSet(document.fonts, hackBold);
|
||||||
|
addToFontFaceSet(document.fonts, hackItalic);
|
||||||
|
addToFontFaceSet(document.fonts, hackBoldItalic);
|
||||||
|
hackRegular.load();
|
||||||
|
hackBold.load();
|
||||||
|
hackItalic.load();
|
||||||
|
hackBoldItalic.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
let isBaseFontsLoaded = false;
|
||||||
|
|
||||||
|
function loadBaseFonts() {
|
||||||
|
if (isBaseFontsLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isBaseFontsLoaded = true;
|
||||||
|
let faFont = new FontFace("FontAwesome", "url(public/fonts/fontawesome-webfont-4.7.woff2)", {
|
||||||
|
style: "normal",
|
||||||
|
weight: "normal",
|
||||||
|
});
|
||||||
|
let mmFont = new FontFace("Martian Mono", "url(public/fonts/MartianMono-VariableFont_wdth,wght.ttf)", {
|
||||||
|
style: "normal",
|
||||||
|
weight: "normal",
|
||||||
|
});
|
||||||
|
addToFontFaceSet(document.fonts, faFont);
|
||||||
|
addToFontFaceSet(document.fonts, mmFont);
|
||||||
faFont.load();
|
faFont.load();
|
||||||
|
mmFont.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadFonts(termFont: string) {
|
||||||
|
loadBaseFonts();
|
||||||
|
loadJetBrainsMonoFont();
|
||||||
|
if (termFont == "Hack") {
|
||||||
|
loadHackFont();
|
||||||
|
}
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--termfontfamily",
|
||||||
|
'"' + termFont + '"' + ', "JetBrains Mono", monospace'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const DOW_STRS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
const DOW_STRS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||||
|
@ -5134,6 +5134,24 @@ func validateOpenAIModel(model string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MaxFontFamilyLen = 50
|
||||||
|
|
||||||
|
var fontfamilyRe = regexp.MustCompile(`^[a-zA-Z0-9_ -]+$`)
|
||||||
|
|
||||||
|
func validateFontFamily(fontFamily string) error {
|
||||||
|
if len(fontFamily) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(fontFamily) > MaxFontFamilyLen {
|
||||||
|
return fmt.Errorf("invalid font family, too long")
|
||||||
|
}
|
||||||
|
m := fontfamilyRe.MatchString(fontFamily)
|
||||||
|
if !m {
|
||||||
|
return fmt.Errorf("invalid font family, must match %q", fontfamilyRe.String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.UpdatePacket, error) {
|
func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (scbus.UpdatePacket, error) {
|
||||||
clientData, err := sstore.EnsureClientData(ctx)
|
clientData, err := sstore.EnsureClientData(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -5156,6 +5174,20 @@ func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sc
|
|||||||
}
|
}
|
||||||
varsUpdated = append(varsUpdated, "termfontsize")
|
varsUpdated = append(varsUpdated, "termfontsize")
|
||||||
}
|
}
|
||||||
|
if fontFamilyStr, found := pk.Kwargs["termfontfamily"]; found {
|
||||||
|
newFontFamily := fontFamilyStr
|
||||||
|
err = validateFontFamily(newFontFamily)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
feOpts := clientData.FeOpts
|
||||||
|
feOpts.TermFontFamily = newFontFamily
|
||||||
|
err = sstore.UpdateClientFeOpts(ctx, feOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error updating client feopts: %v", err)
|
||||||
|
}
|
||||||
|
varsUpdated = append(varsUpdated, "termfontfamily")
|
||||||
|
}
|
||||||
if apiToken, found := pk.Kwargs["openaiapitoken"]; found {
|
if apiToken, found := pk.Kwargs["openaiapitoken"]; found {
|
||||||
err = validateOpenAIAPIToken(apiToken)
|
err = validateOpenAIAPIToken(apiToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -5244,7 +5276,7 @@ func ClientSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(varsUpdated) == 0 {
|
if len(varsUpdated) == 0 {
|
||||||
return nil, fmt.Errorf("/client:set requires a value to set: %s", formatStrs([]string{"termfontsize", "openaiapitoken", "openaimodel", "openaibaseurl", "openaimaxtokens", "openaimaxchoices"}, "or", false))
|
return nil, fmt.Errorf("/client:set requires a value to set: %s", formatStrs([]string{"termfontsize", "termfontfamily", "openaiapitoken", "openaimodel", "openaibaseurl", "openaimaxtokens", "openaimaxchoices"}, "or", false))
|
||||||
}
|
}
|
||||||
clientData, err = sstore.EnsureClientData(ctx)
|
clientData, err = sstore.EnsureClientData(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -296,6 +296,7 @@ type ClientOptsType struct {
|
|||||||
|
|
||||||
type FeOptsType struct {
|
type FeOptsType struct {
|
||||||
TermFontSize int `json:"termfontsize,omitempty"`
|
TermFontSize int `json:"termfontsize,omitempty"`
|
||||||
|
TermFontFamily string `json:"termfontfamily,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReleaseInfoType struct {
|
type ReleaseInfoType struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user