mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-18 14:38:40 -09:00
port config/, ui/ & commands.js in app/ to ts
This commit is contained in:
parent
1ea935988f
commit
c04b51874c
10 changed files with 63 additions and 36 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
import {app, Menu} from 'electron';
|
import {app, Menu, BrowserWindow} from 'electron';
|
||||||
import {openConfig, getConfig} from './config';
|
import {openConfig, getConfig} from './config';
|
||||||
import {updatePlugins} from './plugins';
|
import {updatePlugins} from './plugins';
|
||||||
import {installCLI} from './utils/cli-install';
|
import {installCLI} from './utils/cli-install';
|
||||||
|
|
||||||
const commands = {
|
const commands: Record<string, (focusedWindow?: BrowserWindow) => void> = {
|
||||||
'window:new': () => {
|
'window:new': () => {
|
||||||
// If window is created on the same tick, it will consume event too
|
// If window is created on the same tick, it will consume event too
|
||||||
setTimeout(app.createWindow, 0);
|
setTimeout(app.createWindow, 0);
|
||||||
|
|
@ -31,7 +31,7 @@ const commands = {
|
||||||
focusedWindow && focusedWindow.rpc.emit('session clear req');
|
focusedWindow && focusedWindow.rpc.emit('session clear req');
|
||||||
},
|
},
|
||||||
'editor:selectAll': focusedWindow => {
|
'editor:selectAll': focusedWindow => {
|
||||||
focusedWindow.rpc.emit('term selectAll');
|
focusedWindow && focusedWindow.rpc.emit('term selectAll');
|
||||||
},
|
},
|
||||||
'plugins:update': () => {
|
'plugins:update': () => {
|
||||||
updatePlugins();
|
updatePlugins();
|
||||||
|
|
@ -112,20 +112,20 @@ const commands = {
|
||||||
},
|
},
|
||||||
'window:hamburgerMenu': () => {
|
'window:hamburgerMenu': () => {
|
||||||
if (getConfig().showHamburgerMenu) {
|
if (getConfig().showHamburgerMenu) {
|
||||||
Menu.getApplicationMenu().popup({x: 15, y: 15});
|
Menu.getApplicationMenu()!.popup({x: 15, y: 15});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//Special numeric command
|
//Special numeric command
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 'last'].forEach(cmdIndex => {
|
([1, 2, 3, 4, 5, 6, 7, 8, 'last'] as const).forEach(cmdIndex => {
|
||||||
const index = cmdIndex === 'last' ? cmdIndex : cmdIndex - 1;
|
const index = cmdIndex === 'last' ? cmdIndex : cmdIndex - 1;
|
||||||
commands[`tab:jump:${cmdIndex}`] = focusedWindow => {
|
commands[`tab:jump:${cmdIndex}`] = focusedWindow => {
|
||||||
focusedWindow && focusedWindow.rpc.emit('move jump req', index);
|
focusedWindow && focusedWindow.rpc.emit('move jump req', index);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export const execCommand = (command, focusedWindow) => {
|
export const execCommand = (command: string, focusedWindow?: BrowserWindow) => {
|
||||||
const fn = commands[command];
|
const fn = commands[command];
|
||||||
if (fn) {
|
if (fn) {
|
||||||
fn(focusedWindow);
|
fn(focusedWindow);
|
||||||
|
|
@ -4,13 +4,13 @@ import {defaultCfg, cfgPath, legacyCfgPath, plugs, defaultPlatformKeyPath} from
|
||||||
import {_init, _extractDefault} from './init';
|
import {_init, _extractDefault} from './init';
|
||||||
import notify from '../notify';
|
import notify from '../notify';
|
||||||
|
|
||||||
let defaultConfig;
|
let defaultConfig: Record<string, any> | undefined;
|
||||||
|
|
||||||
const _write = (path, data) => {
|
const _write = (path: string, data: any) => {
|
||||||
// This method will take text formatted as Unix line endings and transform it
|
// This method will take text formatted as Unix line endings and transform it
|
||||||
// to text formatted with DOS line endings. We do this because the default
|
// to text formatted with DOS line endings. We do this because the default
|
||||||
// text editor on Windows (notepad) doesn't Deal with LF files. Still. In 2017.
|
// text editor on Windows (notepad) doesn't Deal with LF files. Still. In 2017.
|
||||||
const crlfify = str => {
|
const crlfify = (str: string) => {
|
||||||
return str.replace(/\r?\n/g, '\r\n');
|
return str.replace(/\r?\n/g, '\r\n');
|
||||||
};
|
};
|
||||||
const format = process.platform === 'win32' ? crlfify(data.toString()) : data;
|
const format = process.platform === 'win32' ? crlfify(data.toString()) : data;
|
||||||
|
|
@ -19,7 +19,7 @@ const _write = (path, data) => {
|
||||||
|
|
||||||
// Saves a file as backup by appending '.backup' or '.backup2', '.backup3', etc.
|
// Saves a file as backup by appending '.backup' or '.backup2', '.backup3', etc.
|
||||||
// so as to not override any existing files
|
// so as to not override any existing files
|
||||||
const saveAsBackup = src => {
|
const saveAsBackup = (src: string) => {
|
||||||
let attempt = 1;
|
let attempt = 1;
|
||||||
while (attempt < 100) {
|
while (attempt < 100) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -99,7 +99,7 @@ const _importConf = () => {
|
||||||
// Importing platform specific keymap
|
// Importing platform specific keymap
|
||||||
try {
|
try {
|
||||||
const content = readFileSync(defaultPlatformKeyPath(), 'utf8');
|
const content = readFileSync(defaultPlatformKeyPath(), 'utf8');
|
||||||
const mapping = JSON.parse(content);
|
const mapping = JSON.parse(content) as Record<string, string | string[]>;
|
||||||
_defaultCfg.keymaps = mapping;
|
_defaultCfg.keymaps = mapping;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
//eslint-disable-next-line no-console
|
//eslint-disable-next-line no-console
|
||||||
|
|
@ -122,14 +122,14 @@ const _importConf = () => {
|
||||||
|
|
||||||
export const _import = () => {
|
export const _import = () => {
|
||||||
const imported = _importConf();
|
const imported = _importConf();
|
||||||
defaultConfig = imported.defaultCfg;
|
defaultConfig = imported?.defaultCfg;
|
||||||
const result = _init(imported);
|
const result = _init(imported!);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDefaultConfig = () => {
|
export const getDefaultConfig = () => {
|
||||||
if (!defaultConfig) {
|
if (!defaultConfig) {
|
||||||
defaultConfig = _extractDefault(_importConf().defaultCfg);
|
defaultConfig = _importConf()?.defaultCfg;
|
||||||
}
|
}
|
||||||
return defaultConfig;
|
return defaultConfig;
|
||||||
};
|
};
|
||||||
|
|
@ -2,16 +2,16 @@ import vm from 'vm';
|
||||||
import notify from '../notify';
|
import notify from '../notify';
|
||||||
import mapKeys from '../utils/map-keys';
|
import mapKeys from '../utils/map-keys';
|
||||||
|
|
||||||
const _extract = script => {
|
const _extract = (script?: vm.Script): Record<string, any> => {
|
||||||
const module = {};
|
const module: Record<string, any> = {};
|
||||||
script.runInNewContext({module});
|
script?.runInNewContext({module});
|
||||||
if (!module.exports) {
|
if (!module.exports) {
|
||||||
throw new Error('Error reading configuration: `module.exports` not set');
|
throw new Error('Error reading configuration: `module.exports` not set');
|
||||||
}
|
}
|
||||||
return module.exports;
|
return module.exports;
|
||||||
};
|
};
|
||||||
|
|
||||||
const _syntaxValidation = cfg => {
|
const _syntaxValidation = (cfg: string) => {
|
||||||
try {
|
try {
|
||||||
return new vm.Script(cfg, {filename: '.hyper.js', displayErrors: true});
|
return new vm.Script(cfg, {filename: '.hyper.js', displayErrors: true});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -19,12 +19,12 @@ const _syntaxValidation = cfg => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const _extractDefault = cfg => {
|
const _extractDefault = (cfg: string) => {
|
||||||
return _extract(_syntaxValidation(cfg));
|
return _extract(_syntaxValidation(cfg));
|
||||||
};
|
};
|
||||||
|
|
||||||
// init config
|
// init config
|
||||||
const _init = cfg => {
|
const _init = (cfg: {userCfg: string; defaultCfg: Record<string, any>}) => {
|
||||||
const script = _syntaxValidation(cfg.userCfg);
|
const script = _syntaxValidation(cfg.userCfg);
|
||||||
if (script) {
|
if (script) {
|
||||||
const _cfg = _extract(script);
|
const _cfg = _extract(script);
|
||||||
|
|
@ -5,12 +5,12 @@ export default () => Promise.resolve(shell.openItem(cfgPath));
|
||||||
// Windows opens .js files with WScript.exe by default
|
// Windows opens .js files with WScript.exe by default
|
||||||
// If the user hasn't set up an editor for .js files, we fallback to notepad.
|
// If the user hasn't set up an editor for .js files, we fallback to notepad.
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
const Registry = require('winreg');
|
const Registry = require('winreg') as typeof import('winreg');
|
||||||
const {exec} = require('child_process');
|
const {exec} = require('child_process') as typeof import('child_process');
|
||||||
|
|
||||||
const getUserChoiceKey = async () => {
|
const getUserChoiceKey = async () => {
|
||||||
// Load FileExts keys for .js files
|
// Load FileExts keys for .js files
|
||||||
const keys = await new Promise((resolve, reject) => {
|
const keys: Winreg.Registry[] = await new Promise((resolve, reject) => {
|
||||||
new Registry({
|
new Registry({
|
||||||
hive: Registry.HKCU,
|
hive: Registry.HKCU,
|
||||||
key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\.js'
|
key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\.js'
|
||||||
|
|
@ -29,11 +29,11 @@ if (process.platform === 'win32') {
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasDefaultSet = async () => {
|
const hasDefaultSet = async () => {
|
||||||
let userChoice = await getUserChoiceKey();
|
const userChoice = await getUserChoiceKey();
|
||||||
if (!userChoice) return false;
|
if (!userChoice) return false;
|
||||||
|
|
||||||
// Load key values
|
// Load key values
|
||||||
let values = await new Promise((resolve, reject) => {
|
const values: string[] = await new Promise((resolve, reject) => {
|
||||||
userChoice.values((error, items) => {
|
userChoice.values((error, items) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
|
|
@ -51,7 +51,7 @@ if (process.platform === 'win32') {
|
||||||
};
|
};
|
||||||
|
|
||||||
// This mimics shell.openItem, true if it worked, false if not.
|
// This mimics shell.openItem, true if it worked, false if not.
|
||||||
const openNotepad = file =>
|
const openNotepad = (file: string) =>
|
||||||
new Promise(resolve => {
|
new Promise(resolve => {
|
||||||
exec(`start notepad.exe ${file}`, error => {
|
exec(`start notepad.exe ${file}`, error => {
|
||||||
resolve(!error);
|
resolve(!error);
|
||||||
|
|
@ -20,7 +20,7 @@ const applicationDirectory =
|
||||||
|
|
||||||
let cfgDir = applicationDirectory;
|
let cfgDir = applicationDirectory;
|
||||||
let cfgPath = join(applicationDirectory, cfgFile);
|
let cfgPath = join(applicationDirectory, cfgFile);
|
||||||
let legacyCfgPath = join(homeDirectory, cfgFile); // Hyper 2 config location
|
const legacyCfgPath = join(homeDirectory, cfgFile); // Hyper 2 config location
|
||||||
|
|
||||||
const devDir = resolve(__dirname, '../..');
|
const devDir = resolve(__dirname, '../..');
|
||||||
const devCfg = join(devDir, cfgFile);
|
const devCfg = join(devDir, cfgFile);
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import Config from 'electron-store';
|
import Config from 'electron-store';
|
||||||
|
import {BrowserWindow} from 'electron';
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
windowPosition: [50, 50],
|
windowPosition: [50, 50],
|
||||||
|
|
@ -15,7 +16,7 @@ export default {
|
||||||
const size = cfg.get('windowSize');
|
const size = cfg.get('windowSize');
|
||||||
return {position, size};
|
return {position, size};
|
||||||
},
|
},
|
||||||
recordState(win) {
|
recordState(win: BrowserWindow) {
|
||||||
cfg.set('windowPosition', win.getPosition());
|
cfg.set('windowPosition', win.getPosition());
|
||||||
cfg.set('windowSize', win.getSize());
|
cfg.set('windowSize', win.getSize());
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +36,7 @@ export class Server extends EventEmitter {
|
||||||
super.emit(ev, data);
|
super.emit(ev, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(ch: string, data: any): any {
|
emit(ch: string, data: any = {}): any {
|
||||||
// This check is needed because data-batching can cause extra data to be
|
// This check is needed because data-batching can cause extra data to be
|
||||||
// emitted after the window has already closed
|
// emitted after the window has already closed
|
||||||
if (!this.win.isDestroyed()) {
|
if (!this.win.isDestroyed()) {
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,30 @@ import editMenu from '../menus/menus/edit';
|
||||||
import shellMenu from '../menus/menus/shell';
|
import shellMenu from '../menus/menus/shell';
|
||||||
import {execCommand} from '../commands';
|
import {execCommand} from '../commands';
|
||||||
import {getDecoratedKeymaps} from '../plugins';
|
import {getDecoratedKeymaps} from '../plugins';
|
||||||
const separator = {type: 'separator'};
|
import {MenuItemConstructorOptions, BrowserWindow} from 'electron';
|
||||||
|
const separator: MenuItemConstructorOptions = {type: 'separator'};
|
||||||
|
|
||||||
const getCommandKeys = keymaps =>
|
const getCommandKeys = (keymaps: Record<string, string[]>): Record<string, string> =>
|
||||||
Object.keys(keymaps).reduce((commandKeys, command) => {
|
Object.keys(keymaps).reduce((commandKeys: Record<string, string>, command) => {
|
||||||
return Object.assign(commandKeys, {
|
return Object.assign(commandKeys, {
|
||||||
[command]: keymaps[command][0]
|
[command]: keymaps[command][0]
|
||||||
});
|
});
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
// only display cut/copy when there's a cursor selection
|
// only display cut/copy when there's a cursor selection
|
||||||
const filterCutCopy = (selection, menuItem) => {
|
const filterCutCopy = (selection: string, menuItem: MenuItemConstructorOptions) => {
|
||||||
if (/^cut$|^copy$/.test(menuItem.role) && !selection) {
|
if (/^cut$|^copy$/.test(menuItem.role!) && !selection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return menuItem;
|
return menuItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (createWindow, selection) => {
|
export default (
|
||||||
|
createWindow: (fn?: (win: BrowserWindow) => void, options?: Record<string, any>) => BrowserWindow,
|
||||||
|
selection: string
|
||||||
|
) => {
|
||||||
const commandKeys = getCommandKeys(getDecoratedKeymaps());
|
const commandKeys = getCommandKeys(getDecoratedKeymaps());
|
||||||
const _shell = shellMenu(commandKeys, execCommand).submenu;
|
const _shell = shellMenu(commandKeys, execCommand).submenu as MenuItemConstructorOptions[];
|
||||||
const _edit = editMenu(commandKeys, execCommand).submenu.filter(filterCutCopy.bind(null, selection));
|
const _edit = editMenu(commandKeys, execCommand).submenu.filter(filterCutCopy.bind(null, selection));
|
||||||
return _edit
|
return _edit
|
||||||
.concat(separator, _shell)
|
.concat(separator, _shell)
|
||||||
|
|
@ -300,6 +300,8 @@
|
||||||
"@types/color": "3.0.0",
|
"@types/color": "3.0.0",
|
||||||
"@types/columnify": "^1.5.0",
|
"@types/columnify": "^1.5.0",
|
||||||
"@types/electron-devtools-installer": "2.2.0",
|
"@types/electron-devtools-installer": "2.2.0",
|
||||||
|
"@types/fs-extra": "8.0.1",
|
||||||
|
"@types/mkdirp": "0.5.2",
|
||||||
"@types/mousetrap": "^1.6.3",
|
"@types/mousetrap": "^1.6.3",
|
||||||
"@types/node": "^12.12.21",
|
"@types/node": "^12.12.21",
|
||||||
"@types/pify": "3.0.2",
|
"@types/pify": "3.0.2",
|
||||||
|
|
@ -311,6 +313,7 @@
|
||||||
"@types/styled-jsx": "2.2.8",
|
"@types/styled-jsx": "2.2.8",
|
||||||
"@types/uuid": "3.4.6",
|
"@types/uuid": "3.4.6",
|
||||||
"@types/webdriverio": "^4.8.0",
|
"@types/webdriverio": "^4.8.0",
|
||||||
|
"@types/winreg": "1.2.30",
|
||||||
"@typescript-eslint/eslint-plugin": "2.11.0",
|
"@typescript-eslint/eslint-plugin": "2.11.0",
|
||||||
"@typescript-eslint/parser": "2.12.0",
|
"@typescript-eslint/parser": "2.12.0",
|
||||||
"ava": "2.4.0",
|
"ava": "2.4.0",
|
||||||
|
|
|
||||||
19
yarn.lock
19
yarn.lock
|
|
@ -650,6 +650,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
||||||
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
|
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
|
||||||
|
|
||||||
|
"@types/fs-extra@8.0.1":
|
||||||
|
version "8.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.1.tgz#a2378d6e7e8afea1564e44aafa2e207dadf77686"
|
||||||
|
integrity sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/glob@^7.1.1":
|
"@types/glob@^7.1.1":
|
||||||
version "7.1.1"
|
version "7.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
|
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
|
||||||
|
|
@ -689,6 +696,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||||
|
|
||||||
|
"@types/mkdirp@0.5.2":
|
||||||
|
version "0.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f"
|
||||||
|
integrity sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/mousetrap@^1.6.3":
|
"@types/mousetrap@^1.6.3":
|
||||||
version "1.6.3"
|
version "1.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.3.tgz#3159a01a2b21c9155a3d8f85588885d725dc987d"
|
resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.3.tgz#3159a01a2b21c9155a3d8f85588885d725dc987d"
|
||||||
|
|
@ -780,6 +794,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/winreg@1.2.30":
|
||||||
|
version "1.2.30"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/winreg/-/winreg-1.2.30.tgz#91d6710e536d345b9c9b017c574cf6a8da64c518"
|
||||||
|
integrity sha1-kdZxDlNtNFucmwF8V0z2qNpkxRg=
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@2.11.0":
|
"@typescript-eslint/eslint-plugin@2.11.0":
|
||||||
version "2.11.0"
|
version "2.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.11.0.tgz#4477c33491ccf0a9a3f4a30ef84978fa0ea0cad2"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.11.0.tgz#4477c33491ccf0a9a3f4a30ef84978fa0ea0cad2"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue