diff --git a/src/common/routes/preferences.ts b/src/common/routes/preferences.ts index 4c737fa08d..3afd81e614 100644 --- a/src/common/routes/preferences.ts +++ b/src/common/routes/preferences.ts @@ -34,6 +34,9 @@ export const extensionRoute: RouteProps = { path: `${preferencesRoute.path}/extensions`, }; +export const terminalRoute: RouteProps = { + path: `${preferencesRoute.path}/terminal`, +}; export const preferencesURL = buildURL(preferencesRoute.path); export const appURL = buildURL(appRoute.path); export const proxyURL = buildURL(proxyRoute.path); @@ -41,3 +44,4 @@ export const kubernetesURL = buildURL(kubernetesRoute.path); export const editorURL = buildURL(editorRoute.path); export const telemetryURL = buildURL(telemetryRoute.path); export const extensionURL = buildURL(extensionRoute.path); +export const terminalURL = buildURL(terminalRoute.path); diff --git a/src/common/user-store/preferences-helpers.ts b/src/common/user-store/preferences-helpers.ts index c2e9adce7e..228b754387 100644 --- a/src/common/user-store/preferences-helpers.ts +++ b/src/common/user-store/preferences-helpers.ts @@ -10,7 +10,7 @@ import { getAppVersion, ObservableToggleSet } from "../utils"; import type { editor } from "monaco-editor"; import merge from "lodash/merge"; import { SemVer } from "semver"; -import { defaultTheme } from "../vars"; +import { defaultTheme, defaultEditorFontFamily, defaultFontSize, defaultTerminalFontFamily } from "../vars"; export interface KubeconfigSyncEntry extends KubeconfigSyncValue { filePath: string; @@ -18,19 +18,29 @@ export interface KubeconfigSyncEntry extends KubeconfigSyncValue { export interface KubeconfigSyncValue { } +export interface TerminalConfig { + fontSize: number; + fontFamily: string; +} + +export const defaultTerminalConfig: TerminalConfig = { + fontSize: defaultFontSize, + fontFamily: defaultTerminalFontFamily, +}; export type EditorConfiguration = Pick; + "minimap" | "tabSize" | "lineNumbers" | "fontSize" | "fontFamily">; export const defaultEditorConfig: EditorConfiguration = { tabSize: 2, lineNumbers: "on", + fontSize: defaultFontSize, + fontFamily: defaultEditorFontFamily, minimap: { enabled: true, side: "right", }, }; - interface PreferenceDescription { fromStore(val: T | undefined): R; toStore(val: R): T | undefined; @@ -273,6 +283,15 @@ const editorConfiguration: PreferenceDescription = { + fromStore(val) { + return merge(defaultTerminalConfig, val); + }, + toStore(val) { + return val; + }, +}; + const updateChannels = new Map([ ["latest", { label: "Stable", @@ -358,6 +377,7 @@ export const DESCRIPTORS = { syncKubeconfigEntries, editorConfiguration, terminalCopyOnSelect, + terminalConfig, updateChannel, extensionRegistryUrl, }; diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index b0726d62ca..a1ffe65d66 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -12,7 +12,7 @@ import { getAppVersion } from "../utils/app-version"; import { kubeConfigDefaultPath } from "../kube-helpers"; import { appEventBus } from "../app-event-bus/event-bus"; import { ObservableToggleSet, toJS } from "../../renderer/utils"; -import { DESCRIPTORS, EditorConfiguration, ExtensionRegistry, KubeconfigSyncValue, UserPreferencesModel } from "./preferences-helpers"; +import { DESCRIPTORS, EditorConfiguration, ExtensionRegistry, KubeconfigSyncValue, UserPreferencesModel, TerminalConfig } from "./preferences-helpers"; import logger from "../../main/logger"; export interface UserStoreModel { @@ -57,6 +57,7 @@ export class UserStore extends BaseStore /* implements UserStore @observable downloadBinariesPath?: string; @observable kubectlBinariesPath?: string; @observable terminalCopyOnSelect: boolean; + @observable terminalConfig: TerminalConfig; @observable updateChannel?: string; @observable extensionRegistryUrl: ExtensionRegistry; @@ -185,6 +186,7 @@ export class UserStore extends BaseStore /* implements UserStore this.syncKubeconfigEntries.replace(DESCRIPTORS.syncKubeconfigEntries.fromStore(preferences?.syncKubeconfigEntries)); this.editorConfiguration = DESCRIPTORS.editorConfiguration.fromStore(preferences?.editorConfiguration); this.terminalCopyOnSelect = DESCRIPTORS.terminalCopyOnSelect.fromStore(preferences?.terminalCopyOnSelect); + this.terminalConfig = DESCRIPTORS.terminalConfig.fromStore(preferences?.terminalConfig); this.updateChannel = DESCRIPTORS.updateChannel.fromStore(preferences?.updateChannel); this.extensionRegistryUrl = DESCRIPTORS.extensionRegistryUrl.fromStore(preferences?.extensionRegistryUrl); } @@ -210,6 +212,7 @@ export class UserStore extends BaseStore /* implements UserStore syncKubeconfigEntries: DESCRIPTORS.syncKubeconfigEntries.toStore(this.syncKubeconfigEntries), editorConfiguration: DESCRIPTORS.editorConfiguration.toStore(this.editorConfiguration), terminalCopyOnSelect: DESCRIPTORS.terminalCopyOnSelect.toStore(this.terminalCopyOnSelect), + terminalConfig: DESCRIPTORS.terminalConfig.toStore(this.terminalConfig), updateChannel: DESCRIPTORS.updateChannel.toStore(this.updateChannel), extensionRegistryUrl: DESCRIPTORS.extensionRegistryUrl.toStore(this.extensionRegistryUrl), }, diff --git a/src/common/vars.ts b/src/common/vars.ts index de0d1abf98..abbf09e877 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -26,6 +26,9 @@ export const productName = packageInfo.productName; export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`; export const publicPath = "/build/" as string; export const defaultTheme = "lens-dark" as string; +export const defaultFontSize = 12; +export const defaultTerminalFontFamily = "RobotoMono"; +export const defaultEditorFontFamily = "RobotoMono"; // Webpack build paths export const contextDir = process.cwd(); diff --git a/src/renderer/components/+preferences/application.tsx b/src/renderer/components/+preferences/application.tsx index deaae917d0..93dd20a417 100644 --- a/src/renderer/components/+preferences/application.tsx +++ b/src/renderer/components/+preferences/application.tsx @@ -10,7 +10,6 @@ import { Select, SelectOption } from "../select"; import { ThemeStore } from "../../theme.store"; import { UserStore } from "../../../common/user-store"; import { Input } from "../input"; -import { isWindows } from "../../../common/vars"; import { Switch } from "../switch"; import moment from "moment-timezone"; import { CONSTANTS, defaultExtensionRegistryUrl, ExtensionRegistryLocation } from "../../../common/user-store/preferences-helpers"; @@ -36,16 +35,7 @@ interface Dependencies { const NonInjectedApplication: React.FC = ({ appPreferenceItems }) => { const userStore = UserStore.getInstance(); - const defaultShell = process.env.SHELL - || process.env.PTYSHELL - || ( - isWindows - ? "powershell.exe" - : "System default shell" - ); - const [customUrl, setCustomUrl] = React.useState(userStore.extensionRegistryUrl.customUrl || ""); - const [shell, setShell] = React.useState(userStore.shell || ""); const extensionSettings = appPreferenceItems.get().filter((preference) => preference.showInPreferencesTab === "application"); const themeStore = ThemeStore.getInstance(); @@ -62,43 +52,7 @@ const NonInjectedApplication: React.FC = ({ appPreferenceItems }) /> -
- -
- - userStore.shell = shell} - /> -
- -
- - userStore.terminalCopyOnSelect = !userStore.terminalCopyOnSelect} - > - Copy on select and paste on right-click - -
- -
+
diff --git a/src/renderer/components/+preferences/editor.tsx b/src/renderer/components/+preferences/editor.tsx index dceddff7b5..2f3e03fff5 100644 --- a/src/renderer/components/+preferences/editor.tsx +++ b/src/renderer/components/+preferences/editor.tsx @@ -69,6 +69,27 @@ export const Editor = observer(() => { onChange={value => editorConfiguration.tabSize = Number(value)} />
+
+ + editorConfiguration.fontSize = Number(value)} + /> +
+
+ + editorConfiguration.fontFamily = value} + /> +
); }); diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index 828433fe2f..ddb1e0077e 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -22,6 +22,8 @@ import { editorRoute, telemetryRoute, telemetryURL, + terminalRoute, + terminalURL, } from "../../../common/routes"; import { navigateWithoutHistoryChange, navigation } from "../../navigation"; import { SettingLayout } from "../layout/setting-layout"; @@ -29,6 +31,7 @@ import { Tab, Tabs } from "../tabs"; import { Application } from "./application"; import { Kubernetes } from "./kubernetes"; import { Editor } from "./editor"; +import { Terminal } from "./terminal"; import { LensProxy } from "./proxy"; import { Telemetry } from "./telemetry"; import { Extensions } from "./extensions"; @@ -56,6 +59,7 @@ const NonInjectedPreferences: React.FC = ({ appPreferenceItems }) + {(telemetryExtensions.length > 0 || !!sentryDsn) && } @@ -77,6 +81,7 @@ const NonInjectedPreferences: React.FC = ({ appPreferenceItems }) + diff --git a/src/renderer/components/+preferences/terminal.tsx b/src/renderer/components/+preferences/terminal.tsx new file mode 100644 index 0000000000..b76f2ba567 --- /dev/null +++ b/src/renderer/components/+preferences/terminal.tsx @@ -0,0 +1,82 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import React from "react"; +import { observer } from "mobx-react"; +import { UserStore } from "../../../common/user-store"; +import { SubTitle } from "../layout/sub-title"; +import { Input, InputValidators } from "../input"; +import { isWindows } from "../../../common/vars"; +import { Switch } from "../switch"; +import { Select } from "../select"; +import { ThemeStore } from "../../theme.store"; + +export const Terminal = observer(() => { + const userStore = UserStore.getInstance(); + const themeStore = ThemeStore.getInstance(); + const defaultShell = process.env.SHELL + || process.env.PTYSHELL + || ( + isWindows + ? "powershell.exe" + : "System default shell" + ); + + return (
+
+ + userStore.shell = value} + /> +
+ +
+ + userStore.terminalCopyOnSelect = !userStore.terminalCopyOnSelect} + > + Copy on select and paste on right-click + +
+ +
+ + userStore.terminalConfig.fontSize=Number(value)} + /> +
+
+ + userStore.terminalConfig.fontFamily=value} + /> +
+
); +}); diff --git a/src/renderer/components/dock/terminal/terminal.ts b/src/renderer/components/dock/terminal/terminal.ts index 39b42d6521..718c855b97 100644 --- a/src/renderer/components/dock/terminal/terminal.ts +++ b/src/renderer/components/dock/terminal/terminal.ts @@ -11,24 +11,28 @@ import type { DockStore, TabId } from "../dock-store/dock.store"; import { TerminalApi, TerminalChannels } from "../../../api/terminal-api"; import { ThemeStore } from "../../../theme.store"; import { disposer } from "../../../utils"; -import { isMac } from "../../../../common/vars"; +import { isMac, defaultTerminalFontFamily } from "../../../../common/vars"; import { once } from "lodash"; import { UserStore } from "../../../../common/user-store"; import { clipboard } from "electron"; import logger from "../../../../common/logger"; +import type { TerminalConfig } from "../../../../common/user-store/preferences-helpers"; interface Dependencies { dockStore: DockStore } export class Terminal { + + private terminalConfig: TerminalConfig = UserStore.getInstance().terminalConfig; + public static get spawningPool() { return document.getElementById("terminal-init"); } static async preloadFonts() { const fontPath = require("../../fonts/roboto-mono-nerd.ttf").default; // eslint-disable-line @typescript-eslint/no-var-requires - const fontFace = new FontFace("RobotoMono", `url(${fontPath})`); + const fontFace = new FontFace(defaultTerminalFontFamily, `url(${fontPath})`); await fontFace.load(); document.fonts.add(fontFace); @@ -37,8 +41,8 @@ export class Terminal { private xterm: XTerm | null = new XTerm({ cursorBlink: true, cursorStyle: "bar", - fontSize: 13, - fontFamily: "RobotoMono", + fontSize: this.terminalConfig.fontSize, + fontFamily: this.terminalConfig.fontFamily, }); private readonly fitAddon = new FitAddon(); private scrollPos = 0; @@ -97,6 +101,12 @@ export class Terminal { }, { fireImmediately: true, }), + reaction(() => UserStore.getInstance().terminalConfig.fontSize, this.setFontSize, { + fireImmediately: true, + }), + reaction(() => UserStore.getInstance().terminalConfig.fontFamily, this.setFontFamily, { + fireImmediately: true, + }), dependencies.dockStore.onResize(this.onResize), () => onDataHandler.dispose(), () => this.fitAddon.dispose(), @@ -192,6 +202,14 @@ export class Terminal { } }; + setFontSize = (size: number) => { + this.xterm.options.fontSize = size; + }; + + setFontFamily = (family: string) => { + this.xterm.options.fontFamily = family; + }; + keyHandler = (evt: KeyboardEvent): boolean => { const { code, ctrlKey, metaKey } = evt;