diff --git a/app/config.ts b/app/config.ts index cf112f51..6c3d66cc 100644 --- a/app/config.ts +++ b/app/config.ts @@ -78,8 +78,30 @@ export const getConfigDir = () => { return cfgDir; }; +export const getDefaultProfile = () => { + return cfg.config.defaultProfile || cfg.config.profiles[0]?.name || 'default'; +}; + +// get config for the default profile, keeping it for backward compatibility export const getConfig = () => { - return cfg.config; + return getProfileConfig(getDefaultProfile()); +}; + +export const getProfiles = () => { + return cfg.config.profiles; +}; + +export const getProfileConfig = (profileName: string): configOptions => { + const {profiles, defaultProfile, ...baseConfig} = cfg.config; + const profileConfig = profiles.find((p) => p.name === profileName)?.config || {}; + for (const key in profileConfig) { + if (typeof baseConfig[key] === 'object' && !Array.isArray(baseConfig[key])) { + baseConfig[key] = {...baseConfig[key], ...profileConfig[key]}; + } else { + baseConfig[key] = profileConfig[key]; + } + } + return {...baseConfig, defaultProfile, profiles}; }; export const openConfig = () => { diff --git a/app/config/config-default.json b/app/config/config-default.json index ca87a774..2a6a66ff 100644 --- a/app/config/config-default.json +++ b/app/config/config-default.json @@ -62,7 +62,14 @@ "autoUpdatePlugins": true, "preserveCWD": true, "screenReaderMode": false, - "imageSupport": true + "imageSupport": true, + "defaultProfile": "default", + "profiles": [ + { + "name": "default", + "config": {} + } + ] }, "plugins": [], "localPlugins": [], diff --git a/app/config/init.ts b/app/config/init.ts index 959e9bac..00a58bbd 100644 --- a/app/config/init.ts +++ b/app/config/init.ts @@ -32,7 +32,19 @@ const _init = (userCfg: rawConfig, defaultCfg: rawConfig): parsedConfig => { return { config: (() => { if (userCfg?.config) { - return _.merge({}, defaultCfg.config, userCfg.config); + const conf = userCfg.config; + conf.defaultProfile = conf.defaultProfile || 'default'; + conf.profiles = conf.profiles || []; + conf.profiles = conf.profiles.length > 0 ? conf.profiles : [{name: 'default', config: {}}]; + conf.profiles = conf.profiles.map((p, i) => ({ + ...p, + name: p.name || `profile-${i + 1}`, + config: p.config || {} + })); + if (!conf.profiles.map((p) => p.name).includes(conf.defaultProfile)) { + conf.defaultProfile = conf.profiles[0].name; + } + return _.merge({}, defaultCfg.config, conf); } else { notify('Error reading configuration: `config` key is missing'); return defaultCfg.config || ({} as configOptions); diff --git a/app/config/schema.json b/app/config/schema.json index e87cd3b8..bb18c2c2 100644 --- a/app/config/schema.json +++ b/app/config/schema.json @@ -24,157 +24,9 @@ } ], "description": "A string or number representing text font weight." - } - }, - "properties": { - "config": { + }, + "Partial": { "properties": { - "autoUpdatePlugins": { - "description": "if `true` (default), Hyper will update plugins every 5 hours\nyou can also set it to a custom time e.g. `1d` or `2h`", - "type": [ - "string", - "boolean" - ] - }, - "backgroundColor": { - "description": "terminal background color\n\nopacity is only supported on macOS", - "type": "string" - }, - "bell": { - "description": "Supported Options:\n1. 'SOUND' -> Enables the bell as a sound\n2. false: turns off the bell", - "type": "string" - }, - "bellSound": { - "description": "base64 encoded string of the sound file to use for the bell\nif null, the default bell will be used", - "type": [ - "string", - "null" - ] - }, - "bellSoundURL": { - "description": "An absolute file path to a sound file on the machine.", - "type": [ - "string", - "null" - ] - }, - "borderColor": { - "description": "border color (window, tabs)", - "type": "string" - }, - "colors": { - "description": "the full list. if you're going to provide the full color palette,\nincluding the 6 x 6 color cubes and the grayscale map, just provide\nan array here instead of a color map object", - "properties": { - "black": { - "type": "string" - }, - "blue": { - "type": "string" - }, - "cyan": { - "type": "string" - }, - "green": { - "type": "string" - }, - "lightBlack": { - "type": "string" - }, - "lightBlue": { - "type": "string" - }, - "lightCyan": { - "type": "string" - }, - "lightGreen": { - "type": "string" - }, - "lightMagenta": { - "type": "string" - }, - "lightRed": { - "type": "string" - }, - "lightWhite": { - "type": "string" - }, - "lightYellow": { - "type": "string" - }, - "magenta": { - "type": "string" - }, - "red": { - "type": "string" - }, - "white": { - "type": "string" - }, - "yellow": { - "type": "string" - } - }, - "required": [ - "black", - "blue", - "cyan", - "green", - "lightBlack", - "lightBlue", - "lightCyan", - "lightGreen", - "lightMagenta", - "lightRed", - "lightWhite", - "lightYellow", - "magenta", - "red", - "white", - "yellow" - ], - "type": "object" - }, - "copyOnSelect": { - "description": "if `true` selected text will automatically be copied to the clipboard", - "type": "boolean" - }, - "css": { - "description": "custom CSS to embed in the main window", - "type": "string" - }, - "cursorAccentColor": { - "description": "terminal text color under BLOCK cursor", - "type": "string" - }, - "cursorBlink": { - "description": "set to `true` for blinking cursor", - "type": "boolean" - }, - "cursorColor": { - "description": "terminal cursor background color and opacity (hex, rgb, hsl, hsv, hwb or cmyk)", - "type": "string" - }, - "cursorShape": { - "description": "`'BEAM'` for |, `'UNDERLINE'` for _, `'BLOCK'` for █", - "enum": [ - "BEAM", - "BLOCK", - "UNDERLINE" - ], - "type": "string" - }, - "defaultSSHApp": { - "description": "if `true` hyper will be set as the default protocol client for SSH", - "type": "boolean" - }, - "disableAutoUpdates": { - "description": "if `true` hyper will not check for updates", - "type": "boolean" - }, - "disableLigatures": { - "description": "if `false` Hyper will use ligatures provided by some fonts", - "type": "boolean" - }, "env": { "additionalProperties": { "type": "string" @@ -182,80 +34,6 @@ "description": "for environment variables", "type": "object" }, - "fontFamily": { - "description": "font family with optional fallbacks", - "type": "string" - }, - "fontSize": { - "description": "default font size in pixels for all tabs", - "type": "number" - }, - "fontWeight": { - "$ref": "#/definitions/FontWeight", - "description": "default font weight eg:'normal', '400', 'bold'" - }, - "fontWeightBold": { - "$ref": "#/definitions/FontWeight", - "description": "font weight for bold characters eg:'normal', '600', 'bold'" - }, - "foregroundColor": { - "description": "color of the text", - "type": "string" - }, - "imageSupport": { - "description": "Whether to enable Sixel and iTerm2 inline image protocol support or not.", - "type": "boolean" - }, - "letterSpacing": { - "description": "letter spacing as a relative unit", - "type": "number" - }, - "lineHeight": { - "description": "line height as a relative unit", - "type": "number" - }, - "macOptionSelectionMode": { - "description": "choose either `'vertical'`, if you want the column mode when Option key is hold during selection (Default)\nor `'force'`, if you want to force selection regardless of whether the terminal is in mouse events mode\n(inside tmux or vim with mouse mode enabled for example).", - "type": "string" - }, - "modifierKeys": { - "properties": { - "altIsMeta": { - "type": "boolean" - }, - "cmdIsMeta": { - "type": "boolean" - } - }, - "required": [ - "altIsMeta", - "cmdIsMeta" - ], - "type": "object" - }, - "padding": { - "description": "custom padding (CSS format, i.e.: `top right bottom left` or `top horizontal bottom` or `vertical horizontal` or `all`)", - "type": "string" - }, - "preserveCWD": { - "description": "set to true to preserve working directory when creating splits or tabs", - "type": "boolean" - }, - "quickEdit": { - "description": "if `true` on right click selected text will be copied or pasted if no\nselection is present (`true` by default on Windows and disables the context menu feature)", - "type": "boolean" - }, - "screenReaderMode": { - "description": "set to true to enable screen reading apps (like NVDA) to read the contents of the terminal", - "type": "boolean" - }, - "scrollback": { - "type": "number" - }, - "selectionColor": { - "description": "terminal selection color", - "type": "string" - }, "shell": { "description": "the shell to run when spawning a new session (e.g. /usr/local/bin/fish)\nif left empty, your system's login shell will be used by default\n\nWindows\n- Make sure to use a full path if the binary name doesn't work\n- Remove `--login` in shellArgs\n\nWindows Subsystem for Linux (WSL) - previously Bash on Windows\n- Example: `C:\\\\Windows\\\\System32\\\\wsl.exe`\n\nGit-bash on Windows\n- Example: `C:\\\\Program Files\\\\Git\\\\bin\\\\bash.exe`\n\nPowerShell on Windows\n- Example: `C:\\\\WINDOWS\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe`\n\nCygwin\n- Example: `C:\\\\cygwin64\\\\bin\\\\bash.exe`\n\nGit Bash\n- Example: `C:\\\\Program Files\\\\Git\\\\git-cmd.exe`\nThen Add `--command=usr/bin/bash.exe` to shellArgs", "type": "string" @@ -267,120 +45,416 @@ }, "type": "array" }, - "showHamburgerMenu": { - "description": "if you're using a Linux setup which show native menus, set to false\n\ndefault: `true` on Linux, `true` on Windows, ignored on macOS", - "enum": [ - "", - false, - true - ] - }, - "showWindowControls": { - "description": "set to `false` if you want to hide the minimize, maximize and close buttons\n\nadditionally, set to `'left'` if you want them on the left, like in Ubuntu\n\ndefault: `true` on Windows and Linux, ignored on macOS", - "enum": [ - "", - false, - "left", - true - ] - }, - "termCSS": { - "description": "custom CSS to embed in the terminal window", - "type": "string" - }, - "uiFontFamily": { - "type": "string" - }, - "updateChannel": { - "description": "choose either `'stable'` for receiving highly polished, or `'canary'` for less polished but more frequent updates", - "enum": [ - "canary", - "stable" - ], - "type": "string" - }, - "useConpty": { - "type": "boolean" - }, - "webGLRenderer": { - "description": "Whether to use the WebGL renderer. Set it to false to use canvas-based\nrendering (slower, but supports transparent backgrounds)", - "type": "boolean" - }, - "webLinksActivationKey": { - "description": "keypress required for weblink activation: [ctrl | alt | meta | shift]", - "enum": [ - "", - "alt", - "ctrl", - "meta", - "shift" - ], - "type": "string" - }, - "windowSize": { - "description": "Initial window size in pixels", - "items": [ - { - "type": "number" - }, - { - "type": "number" - } - ], - "maxItems": 2, - "minItems": 2, - "type": "array" - }, "workingDirectory": { "description": "set custom startup directory (must be an absolute path)", "type": "string" } }, - "required": [ - "autoUpdatePlugins", - "backgroundColor", - "bell", - "bellSound", - "bellSoundURL", - "borderColor", - "colors", - "copyOnSelect", - "css", - "cursorAccentColor", - "cursorBlink", - "cursorColor", - "cursorShape", - "defaultSSHApp", - "disableAutoUpdates", - "disableLigatures", - "env", - "fontFamily", - "fontSize", - "fontWeight", - "fontWeightBold", - "foregroundColor", - "imageSupport", - "letterSpacing", - "lineHeight", - "macOptionSelectionMode", - "padding", - "preserveCWD", - "quickEdit", - "screenReaderMode", - "scrollback", - "selectionColor", - "shell", - "shellArgs", - "showHamburgerMenu", - "showWindowControls", - "termCSS", - "updateChannel", - "webGLRenderer", - "webLinksActivationKey", - "workingDirectory" - ], "type": "object" }, + "configOptions": { + "allOf": [ + { + "properties": { + "autoUpdatePlugins": { + "description": "if `true` (default), Hyper will update plugins every 5 hours\nyou can also set it to a custom time e.g. `1d` or `2h`", + "type": [ + "string", + "boolean" + ] + }, + "backgroundColor": { + "description": "terminal background color\n\nopacity is only supported on macOS", + "type": "string" + }, + "bell": { + "description": "Supported Options:\n1. 'SOUND' -> Enables the bell as a sound\n2. false: turns off the bell", + "type": "string" + }, + "bellSound": { + "description": "base64 encoded string of the sound file to use for the bell\nif null, the default bell will be used", + "type": [ + "string", + "null" + ] + }, + "bellSoundURL": { + "description": "An absolute file path to a sound file on the machine.", + "type": [ + "string", + "null" + ] + }, + "borderColor": { + "description": "border color (window, tabs)", + "type": "string" + }, + "colors": { + "description": "the full list. if you're going to provide the full color palette,\nincluding the 6 x 6 color cubes and the grayscale map, just provide\nan array here instead of a color map object", + "properties": { + "black": { + "type": "string" + }, + "blue": { + "type": "string" + }, + "cyan": { + "type": "string" + }, + "green": { + "type": "string" + }, + "lightBlack": { + "type": "string" + }, + "lightBlue": { + "type": "string" + }, + "lightCyan": { + "type": "string" + }, + "lightGreen": { + "type": "string" + }, + "lightMagenta": { + "type": "string" + }, + "lightRed": { + "type": "string" + }, + "lightWhite": { + "type": "string" + }, + "lightYellow": { + "type": "string" + }, + "magenta": { + "type": "string" + }, + "red": { + "type": "string" + }, + "white": { + "type": "string" + }, + "yellow": { + "type": "string" + } + }, + "required": [ + "black", + "blue", + "cyan", + "green", + "lightBlack", + "lightBlue", + "lightCyan", + "lightGreen", + "lightMagenta", + "lightRed", + "lightWhite", + "lightYellow", + "magenta", + "red", + "white", + "yellow" + ], + "type": "object" + }, + "copyOnSelect": { + "description": "if `true` selected text will automatically be copied to the clipboard", + "type": "boolean" + }, + "css": { + "description": "custom CSS to embed in the main window", + "type": "string" + }, + "cursorAccentColor": { + "description": "terminal text color under BLOCK cursor", + "type": "string" + }, + "cursorBlink": { + "description": "set to `true` for blinking cursor", + "type": "boolean" + }, + "cursorColor": { + "description": "terminal cursor background color and opacity (hex, rgb, hsl, hsv, hwb or cmyk)", + "type": "string" + }, + "cursorShape": { + "description": "`'BEAM'` for |, `'UNDERLINE'` for _, `'BLOCK'` for █", + "enum": [ + "BEAM", + "BLOCK", + "UNDERLINE" + ], + "type": "string" + }, + "defaultSSHApp": { + "description": "if `true` hyper will be set as the default protocol client for SSH", + "type": "boolean" + }, + "disableAutoUpdates": { + "description": "if `true` hyper will not check for updates", + "type": "boolean" + }, + "disableLigatures": { + "description": "if `false` Hyper will use ligatures provided by some fonts", + "type": "boolean" + }, + "fontFamily": { + "description": "font family with optional fallbacks", + "type": "string" + }, + "fontSize": { + "description": "default font size in pixels for all tabs", + "type": "number" + }, + "fontWeight": { + "$ref": "#/definitions/FontWeight", + "description": "default font weight eg:'normal', '400', 'bold'" + }, + "fontWeightBold": { + "$ref": "#/definitions/FontWeight", + "description": "font weight for bold characters eg:'normal', '600', 'bold'" + }, + "foregroundColor": { + "description": "color of the text", + "type": "string" + }, + "imageSupport": { + "description": "Whether to enable Sixel and iTerm2 inline image protocol support or not.", + "type": "boolean" + }, + "letterSpacing": { + "description": "letter spacing as a relative unit", + "type": "number" + }, + "lineHeight": { + "description": "line height as a relative unit", + "type": "number" + }, + "macOptionSelectionMode": { + "description": "choose either `'vertical'`, if you want the column mode when Option key is hold during selection (Default)\nor `'force'`, if you want to force selection regardless of whether the terminal is in mouse events mode\n(inside tmux or vim with mouse mode enabled for example).", + "type": "string" + }, + "modifierKeys": { + "properties": { + "altIsMeta": { + "type": "boolean" + }, + "cmdIsMeta": { + "type": "boolean" + } + }, + "required": [ + "altIsMeta", + "cmdIsMeta" + ], + "type": "object" + }, + "padding": { + "description": "custom padding (CSS format, i.e.: `top right bottom left` or `top horizontal bottom` or `vertical horizontal` or `all`)", + "type": "string" + }, + "preserveCWD": { + "description": "set to true to preserve working directory when creating splits or tabs", + "type": "boolean" + }, + "quickEdit": { + "description": "if `true` on right click selected text will be copied or pasted if no\nselection is present (`true` by default on Windows and disables the context menu feature)", + "type": "boolean" + }, + "screenReaderMode": { + "description": "set to true to enable screen reading apps (like NVDA) to read the contents of the terminal", + "type": "boolean" + }, + "scrollback": { + "type": "number" + }, + "selectionColor": { + "description": "terminal selection color", + "type": "string" + }, + "showHamburgerMenu": { + "description": "if you're using a Linux setup which show native menus, set to false\n\ndefault: `true` on Linux, `true` on Windows, ignored on macOS", + "enum": [ + "", + false, + true + ] + }, + "showWindowControls": { + "description": "set to `false` if you want to hide the minimize, maximize and close buttons\n\nadditionally, set to `'left'` if you want them on the left, like in Ubuntu\n\ndefault: `true` on Windows and Linux, ignored on macOS", + "enum": [ + "", + false, + "left", + true + ] + }, + "termCSS": { + "description": "custom CSS to embed in the terminal window", + "type": "string" + }, + "uiFontFamily": { + "type": "string" + }, + "updateChannel": { + "description": "choose either `'stable'` for receiving highly polished, or `'canary'` for less polished but more frequent updates", + "enum": [ + "canary", + "stable" + ], + "type": "string" + }, + "useConpty": { + "type": "boolean" + }, + "webGLRenderer": { + "description": "Whether to use the WebGL renderer. Set it to false to use canvas-based\nrendering (slower, but supports transparent backgrounds)", + "type": "boolean" + }, + "webLinksActivationKey": { + "description": "keypress required for weblink activation: [ctrl | alt | meta | shift]", + "enum": [ + "", + "alt", + "ctrl", + "meta", + "shift" + ], + "type": "string" + }, + "windowSize": { + "description": "Initial window size in pixels", + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ], + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "autoUpdatePlugins", + "backgroundColor", + "bell", + "bellSound", + "bellSoundURL", + "borderColor", + "colors", + "copyOnSelect", + "css", + "cursorAccentColor", + "cursorBlink", + "cursorColor", + "cursorShape", + "defaultSSHApp", + "disableAutoUpdates", + "disableLigatures", + "fontFamily", + "fontSize", + "fontWeight", + "fontWeightBold", + "foregroundColor", + "imageSupport", + "letterSpacing", + "lineHeight", + "macOptionSelectionMode", + "padding", + "preserveCWD", + "quickEdit", + "screenReaderMode", + "scrollback", + "selectionColor", + "showHamburgerMenu", + "showWindowControls", + "termCSS", + "updateChannel", + "webGLRenderer", + "webLinksActivationKey" + ], + "type": "object" + }, + { + "properties": { + "env": { + "additionalProperties": { + "type": "string" + }, + "description": "for environment variables", + "type": "object" + }, + "shell": { + "description": "the shell to run when spawning a new session (e.g. /usr/local/bin/fish)\nif left empty, your system's login shell will be used by default\n\nWindows\n- Make sure to use a full path if the binary name doesn't work\n- Remove `--login` in shellArgs\n\nWindows Subsystem for Linux (WSL) - previously Bash on Windows\n- Example: `C:\\\\Windows\\\\System32\\\\wsl.exe`\n\nGit-bash on Windows\n- Example: `C:\\\\Program Files\\\\Git\\\\bin\\\\bash.exe`\n\nPowerShell on Windows\n- Example: `C:\\\\WINDOWS\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe`\n\nCygwin\n- Example: `C:\\\\cygwin64\\\\bin\\\\bash.exe`\n\nGit Bash\n- Example: `C:\\\\Program Files\\\\Git\\\\git-cmd.exe`\nThen Add `--command=usr/bin/bash.exe` to shellArgs", + "type": "string" + }, + "shellArgs": { + "description": "for setting shell arguments (e.g. for using interactive shellArgs: `['-i']`)\nby default `['--login']` will be used", + "items": { + "type": "string" + }, + "type": "array" + }, + "workingDirectory": { + "description": "set custom startup directory (must be an absolute path)", + "type": "string" + } + }, + "required": [ + "env", + "shell", + "shellArgs", + "workingDirectory" + ], + "type": "object" + }, + { + "properties": { + "defaultProfile": { + "description": "The default profile name to use when launching a new session", + "type": "string" + }, + "profiles": { + "description": "A list of profiles to use", + "items": { + "properties": { + "config": { + "$ref": "#/definitions/Partial", + "description": "Specify all the options you want to override for each profile.\nOptions set here override the defaults set in the root." + }, + "name": { + "type": "string" + } + }, + "required": [ + "config", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "defaultProfile", + "profiles" + ], + "type": "object" + } + ] + } + }, + "properties": { + "config": { + "$ref": "#/definitions/configOptions" + }, "keymaps": { "additionalProperties": { "anyOf": [ diff --git a/app/index.ts b/app/index.ts index 2b145b6d..a0c428d9 100644 --- a/app/index.ts +++ b/app/index.ts @@ -92,7 +92,7 @@ app.on('ready', () => fn?: (win: BrowserWindow) => void, options: {size?: [number, number]; position?: [number, number]} = {} ) { - const cfg = plugins.getDecoratedConfig(); + const cfg = plugins.getDecoratedConfig(config.getDefaultProfile()); const winSet = config.getWin(); let [startX, startY] = winSet.position; diff --git a/app/plugins.ts b/app/plugins.ts index d153ba6f..ecfe75f2 100644 --- a/app/plugins.ts +++ b/app/plugins.ts @@ -425,8 +425,12 @@ export const getDecoratedEnv = (baseEnv: Record) => { return decorateObject(baseEnv, 'decorateEnv'); }; -export const getDecoratedConfig = () => { - const baseConfig = config.getConfig(); +export const getDefaultProfile = () => { + return config.getDefaultProfile(); +}; + +export const getDecoratedConfig = (profile: string) => { + const baseConfig = config.getProfileConfig(profile); const decoratedConfig = decorateObject(baseConfig, 'decorateConfig'); const fixedConfig = config.fixConfigDefaults(decoratedConfig); const translatedConfig = config.htermConfigTranslate(fixedConfig); diff --git a/app/ui/window.ts b/app/ui/window.ts index f239c8f6..087c41b7 100644 --- a/app/ui/window.ts +++ b/app/ui/window.ts @@ -20,6 +20,7 @@ import type {configOptions} from '../../lib/config'; import {getWorkingDirectoryFromPID} from 'native-process-working-directory'; import {existsSync} from 'fs'; import type {sessionExtraOptions} from '../../common'; +import {getDefaultProfile} from '../config'; export function newWindow( options_: BrowserWindowConstructorOptions, @@ -62,7 +63,7 @@ export function newWindow( const sessions = new Map(); const updateBackgroundColor = () => { - const cfg_ = app.plugins.getDecoratedConfig(); + const cfg_ = app.plugins.getDecoratedConfig(getDefaultProfile()); window.setBackgroundColor(toElectronBackgroundColor(cfg_.backgroundColor || '#000')); }; @@ -83,7 +84,7 @@ export function newWindow( // config changes const cfgUnsubscribe = app.config.subscribe(() => { - const cfg_ = app.plugins.getDecoratedConfig(); + const cfg_ = app.plugins.getDecoratedConfig(getDefaultProfile()); // notify renderer window.webContents.send('config change'); diff --git a/app/updater.ts b/app/updater.ts index dc3ee6fd..e38f75bc 100644 --- a/app/updater.ts +++ b/app/updater.ts @@ -8,6 +8,7 @@ import retry from 'async-retry'; import {version} from './package.json'; import {getDecoratedConfig} from './plugins'; import autoUpdaterLinux from './auto-updater-linux'; +import {getDefaultProfile} from './config'; const {platform} = process; const isLinux = platform === 'linux'; @@ -16,7 +17,7 @@ const autoUpdater: AutoUpdater = isLinux ? autoUpdaterLinux : electron.autoUpdat const getDecoratedConfigWithRetry = async () => { return await retry(() => { - const content = getDecoratedConfig(); + const content = getDecoratedConfig(getDefaultProfile()); if (!content) { throw new Error('No config content loaded'); } diff --git a/lib/config.d.ts b/lib/config.d.ts index 9669f046..4038bf96 100644 --- a/lib/config.d.ts +++ b/lib/config.d.ts @@ -19,7 +19,44 @@ export type ColorMap = { yellow: string; }; -export type configOptions = { +type profileConfigOptions = { + /** for environment variables */ + env: {[k: string]: string}; + /** + * the shell to run when spawning a new session (e.g. /usr/local/bin/fish) + * if left empty, your system's login shell will be used by default + * + * Windows + * - Make sure to use a full path if the binary name doesn't work + * - Remove `--login` in shellArgs + * + * Windows Subsystem for Linux (WSL) - previously Bash on Windows + * - Example: `C:\\Windows\\System32\\wsl.exe` + * + * Git-bash on Windows + * - Example: `C:\\Program Files\\Git\\bin\\bash.exe` + * + * PowerShell on Windows + * - Example: `C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe` + * + * Cygwin + * - Example: `C:\\cygwin64\\bin\\bash.exe` + * + * Git Bash + * - Example: `C:\\Program Files\\Git\\git-cmd.exe` + * Then Add `--command=usr/bin/bash.exe` to shellArgs + */ + shell: string; + /** + * for setting shell arguments (e.g. for using interactive shellArgs: `['-i']`) + * by default `['--login']` will be used + */ + shellArgs: string[]; + /** set custom startup directory (must be an absolute path) */ + workingDirectory: string; +}; + +type rootConfigOptions = { /** * if `true` (default), Hyper will update plugins every 5 hours * you can also set it to a custom time e.g. `1d` or `2h` @@ -74,8 +111,6 @@ export type configOptions = { disableAutoUpdates: boolean; /** if `false` Hyper will use ligatures provided by some fonts */ disableLigatures: boolean; - /** for environment variables */ - env: {[k: string]: string}; /** font family with optional fallbacks */ fontFamily: string; /** default font size in pixels for all tabs */ @@ -122,36 +157,6 @@ export type configOptions = { scrollback: number; /** terminal selection color */ selectionColor: string; - /** - * the shell to run when spawning a new session (e.g. /usr/local/bin/fish) - * if left empty, your system's login shell will be used by default - * - * Windows - * - Make sure to use a full path if the binary name doesn't work - * - Remove `--login` in shellArgs - * - * Windows Subsystem for Linux (WSL) - previously Bash on Windows - * - Example: `C:\\Windows\\System32\\wsl.exe` - * - * Git-bash on Windows - * - Example: `C:\\Program Files\\Git\\bin\\bash.exe` - * - * PowerShell on Windows - * - Example: `C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe` - * - * Cygwin - * - Example: `C:\\cygwin64\\bin\\bash.exe` - * - * Git Bash - * - Example: `C:\\Program Files\\Git\\git-cmd.exe` - * Then Add `--command=usr/bin/bash.exe` to shellArgs - */ - shell: string; - /** - * for setting shell arguments (e.g. for using interactive shellArgs: `['-i']`) - * by default `['--login']` will be used - */ - shellArgs: string[]; /** * if you're using a Linux setup which show native menus, set to false * @@ -184,10 +189,27 @@ export type configOptions = { webLinksActivationKey: 'ctrl' | 'alt' | 'meta' | 'shift' | ''; /** Initial window size in pixels */ windowSize?: [number, number]; - /** set custom startup directory (must be an absolute path) */ - workingDirectory: string; }; +export type configOptions = rootConfigOptions & + profileConfigOptions & { + /** + * The default profile name to use when launching a new session + */ + defaultProfile: string; + /** + * A list of profiles to use + */ + profiles: { + name: string; + /** + * Specify all the options you want to override for each profile. + * Options set here override the defaults set in the root. + */ + config: Partial; + }[]; + }; + export type rawConfig = { config?: configOptions; /** diff --git a/lib/hyper.d.ts b/lib/hyper.d.ts index a0bb1648..428aede6 100644 --- a/lib/hyper.d.ts +++ b/lib/hyper.d.ts @@ -39,7 +39,7 @@ export type ITermState = Immutable<{ export type cursorShapes = 'BEAM' | 'UNDERLINE' | 'BLOCK'; import type {FontWeight, IWindowsPty, Terminal} from 'xterm'; -import type {ColorMap} from './config'; +import type {ColorMap, configOptions} from './config'; export type uiState = Immutable<{ _lastUpdate: number | null; @@ -105,6 +105,8 @@ export type uiState = Immutable<{ webGLRenderer: boolean; webLinksActivationKey: 'ctrl' | 'alt' | 'meta' | 'shift' | ''; windowsPty?: IWindowsPty; + defaultProfile: string; + profiles: configOptions['profiles']; }>; export type session = { diff --git a/lib/reducers/ui.ts b/lib/reducers/ui.ts index 0f08ace3..9ccfbd1e 100644 --- a/lib/reducers/ui.ts +++ b/lib/reducers/ui.ts @@ -113,7 +113,9 @@ const initial: uiState = Immutable>({ webLinksActivationKey: '', macOptionSelectionMode: 'vertical', disableLigatures: true, - screenReaderMode: false + screenReaderMode: false, + defaultProfile: '', + profiles: [] }); const reducer: IUiReducer = (state = initial, action) => { @@ -287,6 +289,14 @@ const reducer: IUiReducer = (state = initial, action) => { ret.imageSupport = config.imageSupport; } + if (config.defaultProfile !== undefined) { + ret.defaultProfile = config.defaultProfile; + } + + if (config.profiles !== undefined) { + ret.profiles = config.profiles; + } + ret._lastUpdate = now; return ret; diff --git a/lib/utils/config.ts b/lib/utils/config.ts index 07dde205..b3539422 100644 --- a/lib/utils/config.ts +++ b/lib/utils/config.ts @@ -5,7 +5,7 @@ import {require as remoteRequire} from '@electron/remote'; const plugins = remoteRequire('./plugins') as typeof import('../../app/plugins'); export function getConfig() { - return plugins.getDecoratedConfig(); + return plugins.getDecoratedConfig(plugins.getDefaultProfile()); } export function subscribe(fn: (event: Electron.IpcRendererEvent, ...args: any[]) => void) {