mirror of
https://github.com/Eugeny/tabby.git
synced 2025-09-02 22:51:50 +00:00
Compare commits
36 Commits
v1.0.0-alp
...
v1.0.0-alp
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ed0bfb39f3 | ||
![]() |
60ce10d1e3 | ||
![]() |
e64126af37 | ||
![]() |
19565fba2c | ||
![]() |
f39443b0ff | ||
![]() |
5dde5479d8 | ||
![]() |
3d29b99ddf | ||
![]() |
4ba7cf106f | ||
![]() |
23c7acde51 | ||
![]() |
c41efbd62b | ||
![]() |
1643ca2bd5 | ||
![]() |
b640abd85d | ||
![]() |
dcf9817075 | ||
![]() |
6f8f83d178 | ||
![]() |
475c4f91be | ||
![]() |
29a6fb60de | ||
![]() |
42007f4fef | ||
![]() |
92c0df7629 | ||
![]() |
e70cb25180 | ||
![]() |
980834df6f | ||
![]() |
50968508df | ||
![]() |
8ee93297be | ||
![]() |
dc9b2553ae | ||
![]() |
a6f7f7aa05 | ||
![]() |
c087a969d6 | ||
![]() |
f4eb03fee0 | ||
![]() |
deb4b963cd | ||
![]() |
9834b27b8d | ||
![]() |
fc060acd88 | ||
![]() |
709ffadc7c | ||
![]() |
536d9537ff | ||
![]() |
94217f0b01 | ||
![]() |
80762e92d6 | ||
![]() |
e6ef21fa9d | ||
![]() |
da89560d6b | ||
![]() |
c0c2373ed6 |
98
app/main.js
98
app/main.js
@@ -8,8 +8,8 @@ if (process.argv.indexOf('--debug') !== -1) {
|
||||
|
||||
let app = electron.app
|
||||
|
||||
let secondInstance = app.makeSingleInstance((argv) => {
|
||||
app.window.webContents.send('host:second-instance')
|
||||
let secondInstance = app.makeSingleInstance((argv, cwd) => {
|
||||
app.window.webContents.send('host:second-instance', argv, cwd)
|
||||
})
|
||||
|
||||
if (secondInstance) {
|
||||
@@ -30,28 +30,18 @@ if (!process.env.TERMINUS_PLUGINS) {
|
||||
}
|
||||
|
||||
setupWindowManagement = () => {
|
||||
let windowCloseable
|
||||
|
||||
app.window.on('show', () => {
|
||||
app.window.webContents.send('host:window-shown')
|
||||
})
|
||||
|
||||
app.window.on('close', (e) => {
|
||||
windowConfig.set('windowBoundaries', app.window.getBounds())
|
||||
if (!windowCloseable) {
|
||||
app.window.minimize()
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
app.window.on('closed', () => {
|
||||
app.window = null
|
||||
})
|
||||
|
||||
electron.ipcMain.on('window-closeable', (event, flag) => {
|
||||
windowCloseable = flag
|
||||
})
|
||||
|
||||
electron.ipcMain.on('window-focus', () => {
|
||||
app.window.focus()
|
||||
})
|
||||
@@ -102,31 +92,83 @@ setupWindowManagement = () => {
|
||||
electron.ipcMain.on('window-set-always-on-top', (event, flag) => {
|
||||
app.window.setAlwaysOnTop(flag)
|
||||
})
|
||||
|
||||
app.on('before-quit', () => windowCloseable = true)
|
||||
}
|
||||
|
||||
|
||||
setupMenu = () => {
|
||||
var template = [{
|
||||
let template = [{
|
||||
label: "Application",
|
||||
submenu: [
|
||||
{ type: "separator" },
|
||||
{ label: "Quit", accelerator: "CmdOrCtrl+Q", click: () => {
|
||||
app.window.webContents.send('host:quit-request')
|
||||
}}
|
||||
{ role: 'about', label: 'About Terminus' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Preferences',
|
||||
accelerator: 'Cmd+,',
|
||||
click () {
|
||||
app.window.webContents.send('host:preferences-menu')
|
||||
}
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ role: 'services', submenu: [] },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideothers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Cmd+Q',
|
||||
click () {
|
||||
app.quit()
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
label: "Edit",
|
||||
submenu: [
|
||||
{ label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
|
||||
{ label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
|
||||
{ type: "separator" },
|
||||
{ label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
|
||||
{ label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
|
||||
{ label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
|
||||
{ label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" }
|
||||
{role: 'undo'},
|
||||
{role: 'redo'},
|
||||
{type: 'separator'},
|
||||
{role: 'cut'},
|
||||
{role: 'copy'},
|
||||
{role: 'paste'},
|
||||
{role: 'pasteandmatchstyle'},
|
||||
{role: 'delete'},
|
||||
{role: 'selectall'}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{role: 'reload'},
|
||||
{role: 'forcereload'},
|
||||
{role: 'toggledevtools'},
|
||||
{type: 'separator'},
|
||||
{role: 'resetzoom'},
|
||||
{role: 'zoomin'},
|
||||
{role: 'zoomout'},
|
||||
{type: 'separator'},
|
||||
{role: 'togglefullscreen'}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{role: 'close'},
|
||||
{role: 'minimize'},
|
||||
{role: 'zoom'},
|
||||
{type: 'separator'},
|
||||
{role: 'front'}
|
||||
]
|
||||
},
|
||||
{
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Website',
|
||||
click () { electron.shell.openExternal('https://eugeny.github.io/terminus') }
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
||||
|
@@ -12,14 +12,14 @@
|
||||
"watch": "webpack --progress --color --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "4.0.1",
|
||||
"@angular/common": "4.0.1",
|
||||
"@angular/compiler": "4.0.1",
|
||||
"@angular/core": "4.0.1",
|
||||
"@angular/forms": "4.0.1",
|
||||
"@angular/platform-browser": "4.0.1",
|
||||
"@angular/platform-browser-dynamic": "4.0.1",
|
||||
"@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.22",
|
||||
"@angular/animations": "4.3.0",
|
||||
"@angular/common": "4.3.0",
|
||||
"@angular/compiler": "4.3.0",
|
||||
"@angular/core": "4.3.0",
|
||||
"@angular/forms": "4.3.0",
|
||||
"@angular/platform-browser": "4.3.0",
|
||||
"@angular/platform-browser-dynamic": "4.3.0",
|
||||
"@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.28",
|
||||
"devtron": "1.4.0",
|
||||
"electron-config": "0.2.1",
|
||||
"electron-debug": "^1.0.1",
|
||||
@@ -29,7 +29,7 @@
|
||||
"mz": "^2.6.0",
|
||||
"path": "0.12.7",
|
||||
"rxjs": "5.3.0",
|
||||
"zone.js": "0.8.4"
|
||||
"zone.js": "0.8.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mz": "0.0.31"
|
||||
|
@@ -12,7 +12,7 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
|
||||
import { getRootModule } from './app.module'
|
||||
import { findPlugins, loadPlugins } from './plugins'
|
||||
|
||||
if (process.platform == 'win32') {
|
||||
if (process.platform === 'win32') {
|
||||
process.env.HOME = process.env.HOMEDRIVE + process.env.HOMEPATH
|
||||
}
|
||||
|
||||
|
@@ -44,6 +44,7 @@ export interface IPluginInfo {
|
||||
packageName: string
|
||||
isBuiltin: boolean
|
||||
version: string
|
||||
author: string
|
||||
homepage?: string
|
||||
path?: string
|
||||
info?: any
|
||||
@@ -116,12 +117,15 @@ export async function findPlugins (): Promise<IPluginInfo[]> {
|
||||
if (!info.keywords || info.keywords.indexOf('terminus-plugin') === -1) {
|
||||
continue
|
||||
}
|
||||
let author = info.author
|
||||
author = author.name || author
|
||||
foundPlugins.push({
|
||||
name: pluginName.substring('terminus-'.length),
|
||||
packageName: pluginName,
|
||||
isBuiltin: pluginDir === builtinPluginsPath,
|
||||
version: info.version,
|
||||
description: info.description,
|
||||
author,
|
||||
path: pluginPath,
|
||||
info,
|
||||
})
|
||||
|
@@ -2,37 +2,51 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@angular/animations@4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.0.1.tgz#154420c8ee5c22fbaf1434b6d156150cf5218da6"
|
||||
"@angular/animations@4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.3.0.tgz#56f34b84649379202ac359929b82eb0b915e9c72"
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
|
||||
"@angular/common@4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.0.1.tgz#df488eada842b2d841ded750712292b18387b5b0"
|
||||
"@angular/common@4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.3.0.tgz#13a54a6929dd52f9729b16ae446fad58fe163053"
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
|
||||
"@angular/compiler@4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-4.0.1.tgz#15721edb148167a2d83b6f9324817e658eac8280"
|
||||
"@angular/compiler@4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-4.3.0.tgz#55503bf27a1f062f71b9495393f3311903a8fc43"
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
|
||||
"@angular/core@4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.0.1.tgz#0b110a001012076ea696460ccd922707bcdf51ba"
|
||||
"@angular/core@4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.3.0.tgz#bd2249c3de1224a7c6536c4aba728d6565329334"
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
|
||||
"@angular/forms@4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-4.0.1.tgz#b9ebdbbb8ace0f9a3bf9e53c299eafdfab1d5041"
|
||||
"@angular/forms@4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-4.3.0.tgz#7d0c7a854737e9a30a5fd9665f8d4f56a1b91bd8"
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
|
||||
"@angular/platform-browser-dynamic@4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.0.1.tgz#fd5debb2d3f6474350965e71c2674e2170d7cfcb"
|
||||
"@angular/platform-browser-dynamic@4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.3.0.tgz#551fb18851b27ee8f3e4b0ee25aad10bd7b312e3"
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
|
||||
"@angular/platform-browser@4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.0.1.tgz#4b9efbeb2fbb900de188743b988802d3aa2b33ff"
|
||||
"@angular/platform-browser@4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.3.0.tgz#02389489185185c3becf06359346100e5479c7e1"
|
||||
dependencies:
|
||||
tslib "^1.7.1"
|
||||
|
||||
"@ng-bootstrap/ng-bootstrap@1.0.0-alpha.22":
|
||||
version "1.0.0-alpha.22"
|
||||
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-1.0.0-alpha.22.tgz#aaad058cc39293ea6184e4b9b849f298c0b11a86"
|
||||
"@ng-bootstrap/ng-bootstrap@^1.0.0-alpha.28":
|
||||
version "1.0.0-alpha.28"
|
||||
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-1.0.0-alpha.28.tgz#30a6503bf7f94f9d3187591fb3267b59cc0cdaad"
|
||||
|
||||
"@types/mz@0.0.31":
|
||||
version "0.0.31"
|
||||
@@ -41,8 +55,8 @@
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*":
|
||||
version "8.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.7.tgz#fb0ad04b5b6f6eabe0372a32a8f1fbba5c130cae"
|
||||
version "8.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.13.tgz#530f0f9254209b0335bf5cc6387822594ef47093"
|
||||
|
||||
accessibility-developer-tools@^2.11.0:
|
||||
version "2.12.0"
|
||||
@@ -244,12 +258,16 @@ thenify-all@^1.0.0:
|
||||
dependencies:
|
||||
any-promise "^1.0.0"
|
||||
|
||||
tslib@^1.7.1:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec"
|
||||
|
||||
util@^0.10.3:
|
||||
version "0.10.3"
|
||||
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
|
||||
dependencies:
|
||||
inherits "2.0.1"
|
||||
|
||||
zone.js@0.8.4:
|
||||
version "0.8.4"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.4.tgz#cc40ae5a1c879601c5ebba2096b5c80f0c4c3602"
|
||||
zone.js@0.8.12:
|
||||
version "0.8.12"
|
||||
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.12.tgz#86ff5053c98aec291a0bf4bbac501d694a05cfbb"
|
||||
|
@@ -87,6 +87,7 @@
|
||||
"build": "webpack --color --config app/webpack.config.js && webpack --color --config terminus-core/webpack.config.js && webpack --color --config terminus-settings/webpack.config.js && webpack --color --config terminus-terminal/webpack.config.js && webpack --color --config terminus-settings/webpack.config.js && webpack --color --config terminus-plugin-manager/webpack.config.js && webpack --color --config terminus-community-color-schemes/webpack.config.js",
|
||||
"watch": "webpack --progress --color --watch",
|
||||
"start": "cross-env DEV=1 electron --js-flags='--ignition' app --debug",
|
||||
"prod": "cross-env DEV=1 electron --js-flags='--ignition' app",
|
||||
"lint": "tslint -c tslint.json -t stylish terminus-*/src/**/*.ts terminus-*/src/*.ts app/src/*.ts",
|
||||
"postinstall": "install-app-deps"
|
||||
},
|
||||
|
@@ -5,21 +5,18 @@ const vars = require('./vars')
|
||||
const log = require('npmlog')
|
||||
|
||||
log.info('deps', 'app')
|
||||
sh.exec('npm prune')
|
||||
sh.exec('npm install')
|
||||
sh.exec('npm update --dev')
|
||||
sh.exec('yarn prune')
|
||||
sh.exec('yarn install')
|
||||
|
||||
sh.cd('app')
|
||||
sh.exec('npm prune')
|
||||
sh.exec('npm install')
|
||||
sh.exec('npm update --dev')
|
||||
sh.exec('yarn prune')
|
||||
sh.exec('yarn install')
|
||||
sh.cd('..')
|
||||
|
||||
vars.builtinPlugins.forEach(plugin => {
|
||||
log.info('deps', plugin)
|
||||
sh.cd(plugin)
|
||||
sh.exec('npm prune')
|
||||
sh.exec('npm install')
|
||||
sh.exec('npm update --dev')
|
||||
sh.exec('yarn prune')
|
||||
sh.exec('yarn install')
|
||||
sh.cd('..')
|
||||
})
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-community-color-schemes",
|
||||
"version": "1.0.0-alpha.14.3",
|
||||
"version": "1.0.0-alpha.16-8-gfc060ac",
|
||||
"description": "Community color schemes for Terminus",
|
||||
"keywords": [
|
||||
"terminus-plugin"
|
||||
|
@@ -12,27 +12,27 @@
|
||||
!
|
||||
! Red
|
||||
*.color1: #ab4642
|
||||
*.color9: #dc9656
|
||||
*.color9: #ab4642
|
||||
!
|
||||
! Green
|
||||
*.color2: #a1b56c
|
||||
*.color10: #282828
|
||||
*.color10: #a1b56c
|
||||
!
|
||||
! Yellow
|
||||
*.color3: #f7ca88
|
||||
*.color11: #383838
|
||||
*.color11: #f7ca88
|
||||
!
|
||||
! Blue
|
||||
*.color4: #7cafc2
|
||||
*.color12: #b8b8b8
|
||||
*.color12: #7cafc2
|
||||
!
|
||||
! Magenta
|
||||
*.color5: #ba8baf
|
||||
*.color13: #e8e8e8
|
||||
*.color13: #ba8baf
|
||||
!
|
||||
! Cyan
|
||||
*.color6: #86c1b9
|
||||
*.color14: #a16946
|
||||
*.color14: #86c1b9
|
||||
!
|
||||
! White
|
||||
*.color7: #d8d8d8
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-core",
|
||||
"version": "1.0.0-alpha.14",
|
||||
"version": "1.0.0-alpha.16-8-gfc060ac",
|
||||
"description": "Terminus core",
|
||||
"keywords": [
|
||||
"terminus-plugin"
|
||||
@@ -17,14 +17,13 @@
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.22",
|
||||
"@types/js-yaml": "^3.5.29",
|
||||
"@types/node": "^7.0.12",
|
||||
"@types/js-yaml": "^3.9.0",
|
||||
"@types/node": "^7.0.37",
|
||||
"@types/webpack-env": "^1.13.0",
|
||||
"bootstrap": "4.0.0-alpha.6",
|
||||
"core-js": "^2.4.1",
|
||||
"ngx-perfect-scrollbar": "4.0.0",
|
||||
"typescript": "^2.4.0"
|
||||
"typescript": "^2.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/animations": "4.0.1",
|
||||
@@ -37,8 +36,8 @@
|
||||
"zone.js": "0.8.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"deepmerge": "^1.4.4",
|
||||
"js-yaml": "^3.8.4"
|
||||
"deepmerge": "^1.5.0",
|
||||
"js-yaml": "^3.9.0"
|
||||
},
|
||||
"false": {}
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import { ElectronService } from '../services/electron.service'
|
||||
import { HostAppService, Platform } from '../services/hostApp.service'
|
||||
import { HotkeysService } from '../services/hotkeys.service'
|
||||
import { Logger, LogService } from '../services/log.service'
|
||||
import { QuitterService } from '../services/quitter.service'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { DockingService } from '../services/docking.service'
|
||||
import { TabRecoveryService } from '../services/tabRecovery.service'
|
||||
@@ -28,9 +27,16 @@ import { AppService, IToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
'flex-basis': '1px',
|
||||
'width': '1px',
|
||||
}),
|
||||
animate('250ms ease-in-out')
|
||||
animate('250ms ease-in-out', style({
|
||||
'flex-basis': '200px',
|
||||
'width': '200px',
|
||||
}))
|
||||
]),
|
||||
transition(':leave', [
|
||||
style({
|
||||
'flex-basis': '200px',
|
||||
'width': '200px',
|
||||
}),
|
||||
animate('250ms ease-in-out', style({
|
||||
'flex-basis': '1px',
|
||||
'width': '1px',
|
||||
@@ -57,7 +63,6 @@ export class AppRootComponent {
|
||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
log: LogService,
|
||||
_themes: ThemesService,
|
||||
_quitter: QuitterService,
|
||||
) {
|
||||
this.logger = log.create('main')
|
||||
this.logger.info('v', electron.app.getVersion())
|
||||
@@ -93,7 +98,7 @@ export class AppRootComponent {
|
||||
this.docking.dock()
|
||||
})
|
||||
|
||||
this.hostApp.secondInstance.subscribe(() => {
|
||||
this.hostApp.secondInstance$.subscribe(() => {
|
||||
this.onGlobalHotkey()
|
||||
})
|
||||
this.hotkeys.globalHotkey.subscribe(() => {
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { Subject, BehaviorSubject } from 'rxjs'
|
||||
import { Subject } from 'rxjs'
|
||||
import { ViewRef } from '@angular/core'
|
||||
|
||||
export abstract class BaseTabComponent {
|
||||
private static lastTabID = 0
|
||||
id: number
|
||||
title$ = new BehaviorSubject<string>(null)
|
||||
title: string
|
||||
customTitle: string
|
||||
scrollable: boolean
|
||||
hasActivity = false
|
||||
focused$ = new Subject<void>()
|
||||
@@ -33,6 +34,5 @@ export abstract class BaseTabComponent {
|
||||
destroy (): void {
|
||||
this.focused$.complete()
|
||||
this.blurred$.complete()
|
||||
this.title$.complete()
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,6 @@
|
||||
.modal-body
|
||||
input.form-control(type='text', [(ngModel)]='value', (keyup.enter)='save()', autofocus)
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-outline-primary((click)='save()') Save
|
||||
button.btn.btn-outline-secondary((click)='close()') Cancel
|
22
terminus-core/src/components/renameTabModal.component.ts
Normal file
22
terminus-core/src/components/renameTabModal.component.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
@Component({
|
||||
selector: 'rename-tab-modal',
|
||||
template: require('./renameTabModal.component.pug'),
|
||||
})
|
||||
export class RenameTabModalComponent {
|
||||
@Input() value: string
|
||||
|
||||
constructor (
|
||||
private modalInstance: NgbActiveModal
|
||||
) { }
|
||||
|
||||
save () {
|
||||
this.modalInstance.close(this.value)
|
||||
}
|
||||
|
||||
close () {
|
||||
this.modalInstance.dismiss()
|
||||
}
|
||||
}
|
@@ -1,3 +1,3 @@
|
||||
.index {{index + 1}}
|
||||
.name {{tab.title$ | async}}
|
||||
.name {{tab.customTitle || tab.title}}
|
||||
button((click)='closeClicked.emit()') ×
|
||||
|
@@ -1,5 +1,7 @@
|
||||
import { Component, Input, Output, EventEmitter, HostBinding } from '@angular/core'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { Component, Input, Output, EventEmitter, HostBinding, HostListener } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { BaseTabComponent } from './baseTab.component'
|
||||
import { RenameTabModalComponent } from './renameTabModal.component'
|
||||
|
||||
@Component({
|
||||
selector: 'tab-header',
|
||||
@@ -12,4 +14,22 @@ export class TabHeaderComponent {
|
||||
@Input() @HostBinding('class.has-activity') hasActivity: boolean
|
||||
@Input() tab: BaseTabComponent
|
||||
@Output() closeClicked = new EventEmitter()
|
||||
|
||||
constructor (
|
||||
private ngbModal: NgbModal,
|
||||
) { }
|
||||
|
||||
@HostListener('dblclick') onDoubleClick (): void {
|
||||
let modal = this.ngbModal.open(RenameTabModalComponent)
|
||||
modal.componentInstance.value = this.tab.customTitle || this.tab.title
|
||||
modal.result.then(result => {
|
||||
this.tab.customTitle = result
|
||||
}).catch(() => null)
|
||||
}
|
||||
|
||||
@HostListener('auxclick', ['$event']) onAuxClick ($event: MouseEvent): void {
|
||||
if ($event.which === 2) {
|
||||
this.closeClicked.emit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ import { ElectronService } from './services/electron.service'
|
||||
import { HostAppService } from './services/hostApp.service'
|
||||
import { LogService } from './services/log.service'
|
||||
import { HotkeysService, AppHotkeyProvider } from './services/hotkeys.service'
|
||||
import { QuitterService } from './services/quitter.service'
|
||||
import { DockingService } from './services/docking.service'
|
||||
import { TabRecoveryService } from './services/tabRecovery.service'
|
||||
import { ThemesService } from './services/themes.service'
|
||||
@@ -22,6 +21,7 @@ import { StartPageComponent } from './components/startPage.component'
|
||||
import { TabHeaderComponent } from './components/tabHeader.component'
|
||||
import { TitleBarComponent } from './components/titleBar.component'
|
||||
import { WindowControlsComponent } from './components/windowControls.component'
|
||||
import { RenameTabModalComponent } from './components/renameTabModal.component'
|
||||
|
||||
import { HotkeyProvider } from './api/hotkeyProvider'
|
||||
import { ConfigProvider } from './api/configProvider'
|
||||
@@ -42,7 +42,6 @@ const PROVIDERS = [
|
||||
LogService,
|
||||
TabRecoveryService,
|
||||
ThemesService,
|
||||
QuitterService,
|
||||
{ provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true },
|
||||
{ provide: Theme, useClass: StandardTheme, multi: true },
|
||||
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
|
||||
@@ -65,7 +64,11 @@ const PROVIDERS = [
|
||||
TabHeaderComponent,
|
||||
TitleBarComponent,
|
||||
WindowControlsComponent,
|
||||
RenameTabModalComponent,
|
||||
],
|
||||
entryComponents: [
|
||||
RenameTabModalComponent,
|
||||
]
|
||||
})
|
||||
export default class AppModule {
|
||||
static forRoot (): ModuleWithProviders {
|
||||
|
@@ -9,12 +9,12 @@ export class ElectronService {
|
||||
clipboard: any
|
||||
globalShortcut: any
|
||||
screen: any
|
||||
remote: any
|
||||
private electron: any
|
||||
private remoteElectron: any
|
||||
|
||||
constructor () {
|
||||
this.electron = require('electron')
|
||||
this.remoteElectron = this.remoteRequire('electron')
|
||||
this.remote = this.electron.remote
|
||||
this.app = this.electron.remote.app
|
||||
this.screen = this.electron.remote.screen
|
||||
this.dialog = this.electron.remote.dialog
|
||||
@@ -25,6 +25,6 @@ export class ElectronService {
|
||||
}
|
||||
|
||||
remoteRequire (name: string): any {
|
||||
return this.electron.remote.require(name)
|
||||
return this.remote.require(name)
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { Subject } from 'rxjs'
|
||||
import { Injectable, NgZone, EventEmitter } from '@angular/core'
|
||||
import { ElectronService } from '../services/electron.service'
|
||||
import { Logger, LogService } from '../services/log.service'
|
||||
@@ -17,10 +18,10 @@ export interface Bounds {
|
||||
export class HostAppService {
|
||||
platform: Platform
|
||||
nodePlatform: string
|
||||
quitRequested = new EventEmitter<any>()
|
||||
preferencesMenu$ = new Subject<void>()
|
||||
ready = new EventEmitter<any>()
|
||||
shown = new EventEmitter<any>()
|
||||
secondInstance = new EventEmitter<any>()
|
||||
secondInstance$ = new Subject<{ argv: string[], cwd: string }>()
|
||||
|
||||
private logger: Logger
|
||||
|
||||
@@ -37,18 +38,18 @@ export class HostAppService {
|
||||
linux: Platform.Linux
|
||||
}[this.nodePlatform]
|
||||
|
||||
electron.ipcRenderer.on('host:quit-request', () => this.zone.run(() => this.quitRequested.emit()))
|
||||
electron.ipcRenderer.on('host:preferences-menu', () => this.zone.run(() => this.preferencesMenu$.next()))
|
||||
|
||||
electron.ipcRenderer.on('uncaughtException', (err) => {
|
||||
electron.ipcRenderer.on('uncaughtException', ($event, err) => {
|
||||
this.logger.error('Unhandled exception:', err)
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('host:window-shown', () => {
|
||||
this.shown.emit()
|
||||
this.zone.run(() => this.shown.emit())
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('host:second-instance', () => {
|
||||
this.secondInstance.emit()
|
||||
electron.ipcRenderer.on('host:second-instance', ($event, argv: string[], cwd: string) => {
|
||||
this.zone.run(() => this.secondInstance$.next({ argv, cwd }))
|
||||
})
|
||||
|
||||
this.ready.subscribe(() => {
|
||||
@@ -76,10 +77,6 @@ export class HostAppService {
|
||||
this.getWindow().webContents.openDevTools()
|
||||
}
|
||||
|
||||
setCloseable (flag: boolean) {
|
||||
this.electron.ipcRenderer.send('window-set-closeable', flag)
|
||||
}
|
||||
|
||||
focusWindow () {
|
||||
this.electron.ipcRenderer.send('window-focus')
|
||||
}
|
||||
|
@@ -45,7 +45,9 @@ export function stringifyKeySequence (events: NativeKeyEvent[]): string[] {
|
||||
// TODO make this optional?
|
||||
continue
|
||||
}
|
||||
if (event.key.length === 1) {
|
||||
if (event.key === ' ') {
|
||||
itemKeys.push('Space')
|
||||
} else if (event.key.length === 1) {
|
||||
itemKeys.push(event.key.toUpperCase())
|
||||
} else {
|
||||
itemKeys.push(event.key)
|
||||
|
@@ -1,18 +0,0 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService } from '../services/hostApp.service'
|
||||
|
||||
@Injectable()
|
||||
export class QuitterService {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
hostApp.quitRequested.subscribe(() => {
|
||||
this.quit()
|
||||
})
|
||||
}
|
||||
|
||||
quit () {
|
||||
this.hostApp.setCloseable(true)
|
||||
this.hostApp.quit()
|
||||
}
|
||||
}
|
@@ -23,6 +23,7 @@ $body-color: #aaa;
|
||||
$font-family-sans-serif: "Source Sans Pro";
|
||||
$font-size-base: 14rem / 16;
|
||||
|
||||
$btn-border-radius: 0;
|
||||
$btn-secondary-color: #ccc;
|
||||
$btn-secondary-bg: #222;
|
||||
$btn-secondary-border: #444;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-plugin-manager",
|
||||
"version": "1.0.0-alpha.14",
|
||||
"version": "1.0.0-alpha.16-8-gfc060ac",
|
||||
"description": "Terminus' plugin manager",
|
||||
"keywords": [
|
||||
"terminus-plugin"
|
||||
@@ -19,10 +19,10 @@
|
||||
"devDependencies": {
|
||||
"@types/mz": "0.0.31",
|
||||
"@types/node": "7.0.12",
|
||||
"@types/semver": "^5.3.31",
|
||||
"@types/semver": "^5.3.32",
|
||||
"@types/webpack-env": "1.13.0",
|
||||
"ngx-pipes": "^1.6.1",
|
||||
"css-loader": "^0.28.0",
|
||||
"ngx-pipes": "^1.6.1",
|
||||
"semver": "^5.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -36,7 +36,8 @@
|
||||
"rxjs": "5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.16.2"
|
||||
"axios": "^0.16.2",
|
||||
"mz": "^2.6.0"
|
||||
},
|
||||
"false": {}
|
||||
}
|
||||
|
@@ -15,7 +15,9 @@ h3 Installed
|
||||
.mr-auto.d-flex.flex-column
|
||||
strong {{plugin.name}}
|
||||
small.text-muted.mb-0 {{plugin.description}}
|
||||
p.mb-0.mr-3 {{plugin.version}}
|
||||
.d-flex.flex-column.align-items-end.mr-3
|
||||
div {{plugin.version}}
|
||||
small.text-muted {{plugin.author}}
|
||||
button.btn.btn-outline-primary(
|
||||
*ngIf='npmInstalled',
|
||||
(click)='upgradePlugin(plugin)',
|
||||
@@ -31,7 +33,10 @@ h3 Installed
|
||||
.mr-auto.d-flex.flex-column
|
||||
strong {{plugin.name}}
|
||||
small.text-muted.mb-0 {{plugin.description}}
|
||||
p.mb-0.mr-3 {{plugin.version}}
|
||||
.d-flex.flex-column.align-items-end.mr-3
|
||||
div {{plugin.version}}
|
||||
small.text-muted {{plugin.author}}
|
||||
i.fa.fa-check.text-success.ml-1(*ngIf='plugin.isOfficial', title='Official')
|
||||
button.btn.btn-outline-danger(
|
||||
(click)='uninstallPlugin(plugin)',
|
||||
*ngIf='!plugin.isBuiltin && npmInstalled',
|
||||
@@ -73,7 +78,10 @@ div(*ngIf='npmInstalled')
|
||||
.mr-auto.d-flex.flex-column
|
||||
strong {{plugin.name}}
|
||||
small.text-muted.mb-0 {{plugin.description}}
|
||||
p.mb-0.mr-3 {{plugin.version}}
|
||||
.d-flex.flex-column.align-items-end.mr-3
|
||||
div {{plugin.version}}
|
||||
small.text-muted {{plugin.author}}
|
||||
i.fa.fa-check.text-success.ml-1(*ngIf='plugin.isOfficial', title='Official')
|
||||
button.btn.btn-outline-primary(
|
||||
(click)='installPlugin(plugin)',
|
||||
[disabled]='busy[plugin.name] != undefined'
|
||||
|
@@ -1,19 +1,24 @@
|
||||
import { Observable } from 'rxjs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { Logger, LogService, ConfigService } from 'terminus-core'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'mz/fs'
|
||||
import { exec } from 'mz/child_process'
|
||||
import axios from 'axios'
|
||||
import { Observable } from 'rxjs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { Logger, LogService, ConfigService, HostAppService, Platform } from 'terminus-core'
|
||||
|
||||
const NAME_PREFIX = 'terminus-'
|
||||
const KEYWORD = 'terminus-plugin'
|
||||
const OFFICIAL_NPM_ACCOUNT = 'eugenepankov'
|
||||
|
||||
export interface IPluginInfo {
|
||||
name: string
|
||||
description: string
|
||||
packageName: string
|
||||
isBuiltin: boolean
|
||||
isOfficial: boolean
|
||||
version: string
|
||||
homepage?: string
|
||||
author: string
|
||||
path?: string
|
||||
}
|
||||
|
||||
@@ -23,17 +28,38 @@ export class PluginManagerService {
|
||||
builtinPluginsPath: string = (window as any).builtinPluginsPath
|
||||
userPluginsPath: string = (window as any).userPluginsPath
|
||||
installedPlugins: IPluginInfo[] = (window as any).installedPlugins
|
||||
npmPath: string
|
||||
|
||||
constructor (
|
||||
log: LogService,
|
||||
private config: ConfigService,
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
this.logger = log.create('pluginManager')
|
||||
this.detectPath()
|
||||
}
|
||||
|
||||
async detectPath () {
|
||||
this.npmPath = this.config.store.npm
|
||||
if (await fs.exists(this.npmPath)) {
|
||||
return
|
||||
}
|
||||
if (this.hostApp.platform !== Platform.Windows) {
|
||||
let searchPaths = (await exec('bash -c -l "echo $PATH"'))[0].toString().trim().split(':')
|
||||
for (let searchPath of searchPaths) {
|
||||
if (await fs.exists(path.join(searchPath, 'npm'))) {
|
||||
this.logger.debug('Found npm in', searchPath)
|
||||
this.npmPath = path.join(searchPath, 'npm')
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async isNPMInstalled (): Promise<boolean> {
|
||||
await this.detectPath()
|
||||
try {
|
||||
await exec(`${this.config.store.npm} -v`)
|
||||
await exec(`${this.npmPath} -v`)
|
||||
return true
|
||||
} catch (_) {
|
||||
return false
|
||||
@@ -45,25 +71,28 @@ export class PluginManagerService {
|
||||
.fromPromise(
|
||||
axios.get(`https://www.npmjs.com/-/search?text=keywords:${KEYWORD}+${encodeURIComponent(query || '')}&from=0&size=1000`)
|
||||
)
|
||||
.do(response => console.log(response.data.objects))
|
||||
.map(response => response.data.objects.map(item => ({
|
||||
name: item.package.name.substring(NAME_PREFIX.length),
|
||||
packageName: item.package.name,
|
||||
description: item.package.description,
|
||||
version: item.package.version,
|
||||
homepage: item.package.links.homepage,
|
||||
author: (item.package.author || {}).name,
|
||||
isOfficial: item.package.publisher.username === OFFICIAL_NPM_ACCOUNT,
|
||||
})))
|
||||
.map(plugins => plugins.filter(x => x.packageName.startsWith(NAME_PREFIX)))
|
||||
}
|
||||
|
||||
async installPlugin (plugin: IPluginInfo) {
|
||||
let result = await exec(`${this.config.store.npm} --prefix "${this.userPluginsPath}" install ${plugin.packageName}@${plugin.version}`)
|
||||
let result = await exec(`${this.npmPath} --prefix "${this.userPluginsPath}" install ${plugin.packageName}@${plugin.version}`)
|
||||
console.log(result)
|
||||
this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
|
||||
this.installedPlugins.push(plugin)
|
||||
}
|
||||
|
||||
async uninstallPlugin (plugin: IPluginInfo) {
|
||||
await exec(`${this.config.store.npm} --prefix "${this.userPluginsPath}" remove ${plugin.packageName}`)
|
||||
await exec(`${this.npmPath} --prefix "${this.userPluginsPath}" remove ${plugin.packageName}`)
|
||||
this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
|
||||
}
|
||||
}
|
||||
|
@@ -37,10 +37,10 @@ module.exports = {
|
||||
},
|
||||
externals: [
|
||||
'fs',
|
||||
'fs-promise',
|
||||
'font-manager',
|
||||
'path',
|
||||
'node-pty',
|
||||
'mz/fs',
|
||||
'mz/child_process',
|
||||
'winreg',
|
||||
/^rxjs/,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-settings",
|
||||
"version": "1.0.0-alpha.14",
|
||||
"version": "1.0.0-alpha.16-8-gfc060ac",
|
||||
"description": "Terminus terminal settings page",
|
||||
"keywords": [
|
||||
"terminus-plugin"
|
||||
|
@@ -1,14 +1,16 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ToolbarButtonProvider, IToolbarButton, AppService } from 'terminus-core'
|
||||
import { ToolbarButtonProvider, IToolbarButton, AppService, HostAppService } from 'terminus-core'
|
||||
|
||||
import { SettingsTabComponent } from './components/settingsTab.component'
|
||||
|
||||
@Injectable()
|
||||
export class ButtonProvider extends ToolbarButtonProvider {
|
||||
constructor (
|
||||
hostApp: HostAppService,
|
||||
private app: AppService,
|
||||
) {
|
||||
super()
|
||||
hostApp.preferencesMenu$.subscribe(() => this.open())
|
||||
}
|
||||
|
||||
provide (): IToolbarButton[] {
|
||||
@@ -16,14 +18,16 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
icon: 'sliders',
|
||||
title: 'Settings',
|
||||
weight: 10,
|
||||
click: () => {
|
||||
let settingsTab = this.app.tabs.find((tab) => tab instanceof SettingsTabComponent)
|
||||
if (settingsTab) {
|
||||
this.app.selectTab(settingsTab)
|
||||
} else {
|
||||
this.app.openNewTab(SettingsTabComponent)
|
||||
}
|
||||
}
|
||||
click: () => this.open(),
|
||||
}]
|
||||
}
|
||||
|
||||
open (): void {
|
||||
let settingsTab = this.app.tabs.find((tab) => tab instanceof SettingsTabComponent)
|
||||
if (settingsTab) {
|
||||
this.app.selectTab(settingsTab)
|
||||
} else {
|
||||
this.app.openNewTab(SettingsTabComponent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -73,6 +73,7 @@ export class HotkeyInputModalComponent {
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.hotkeys.clearCurrentKeystrokes()
|
||||
this.hotkeys.enable()
|
||||
clearInterval(this.keyTimeoutInterval)
|
||||
}
|
||||
|
@@ -2,9 +2,9 @@ button.btn.btn-outline-warning.btn-block(*ngIf='config.restartRequested', '(clic
|
||||
|
||||
ngb-tabset.vertical(type='tabs')
|
||||
ngb-tab
|
||||
template(ngbTabTitle)
|
||||
ng-template(ngbTabTitle)
|
||||
| Application
|
||||
template(ngbTabContent)
|
||||
ng-template(ngbTabContent)
|
||||
.row
|
||||
.col.col-lg-6
|
||||
.form-group
|
||||
@@ -153,9 +153,9 @@ ngb-tabset.vertical(type='tabs')
|
||||
)
|
||||
|
||||
ngb-tab
|
||||
template(ngbTabTitle)
|
||||
ng-template(ngbTabTitle)
|
||||
| Hotkeys
|
||||
template(ngbTabContent)
|
||||
ng-template(ngbTabContent)
|
||||
input.form-control(type='search', placeholder='Search hotkeys', [(ngModel)]='hotkeyFilter')
|
||||
.form-group
|
||||
table.hotkeys-table
|
||||
@@ -173,7 +173,7 @@ ngb-tabset.vertical(type='tabs')
|
||||
)
|
||||
|
||||
ngb-tab(*ngFor='let provider of settingsProviders')
|
||||
template(ngbTabTitle)
|
||||
ng-template(ngbTabTitle)
|
||||
| {{provider.title}}
|
||||
template(ngbTabContent)
|
||||
ng-template(ngbTabContent)
|
||||
settings-tab-body([provider]='provider')
|
||||
|
@@ -27,7 +27,7 @@ export class SettingsTabComponent extends BaseTabComponent {
|
||||
) {
|
||||
super()
|
||||
this.hotkeyDescriptions = hotkeyProviders.map(x => x.hotkeys).reduce((a, b) => a.concat(b))
|
||||
this.title$.next('Settings')
|
||||
this.title = 'Settings'
|
||||
this.scrollable = true
|
||||
this.screens = this.docking.getScreens()
|
||||
}
|
||||
|
@@ -38,10 +38,8 @@ module.exports = {
|
||||
},
|
||||
externals: [
|
||||
'fs',
|
||||
'fs-promise',
|
||||
'path',
|
||||
'node-pty',
|
||||
'fs-promise',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-terminal",
|
||||
"version": "1.0.0-alpha.14",
|
||||
"version": "1.0.0-alpha.16-8-gfc060ac",
|
||||
"description": "Terminus' terminal emulation core",
|
||||
"keywords": [
|
||||
"terminus-plugin"
|
||||
@@ -23,7 +23,8 @@
|
||||
"@types/webpack-env": "1.13.0",
|
||||
"@types/winreg": "^1.2.30",
|
||||
"dataurl": "0.1.0",
|
||||
"deep-equal": "1.0.1"
|
||||
"deep-equal": "1.0.1",
|
||||
"file-loader": "^0.11.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "4.0.1",
|
||||
@@ -31,16 +32,16 @@
|
||||
"@angular/forms": "4.0.1",
|
||||
"@angular/platform-browser": "4.0.1",
|
||||
"@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.22",
|
||||
"rxjs": "5.3.0",
|
||||
"terminus-core": "*",
|
||||
"terminus-settings": "*",
|
||||
"rxjs": "5.3.0"
|
||||
"terminus-settings": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"font-manager": "0.2.2",
|
||||
"fs-promise": "2.0.2",
|
||||
"hterm-umdjs": "1.2.0",
|
||||
"hterm-umdjs": "1.1.3",
|
||||
"mz": "^2.6.0",
|
||||
"node-pty": "0.6.2",
|
||||
"node-pty": "0.6.8",
|
||||
"runes": "^0.4.2",
|
||||
"winreg": "^1.2.3"
|
||||
},
|
||||
"false": {}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import * as path from 'path'
|
||||
import { exec } from 'mz/child_process'
|
||||
import * as fs from 'mz/fs'
|
||||
import * as path from 'path'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService, ConfigService, ElectronService, HostAppService, Platform } from 'terminus-core'
|
||||
import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService, ConfigService, HostAppService, Platform, ElectronService } from 'terminus-core'
|
||||
|
||||
import { SessionsService } from './services/sessions.service'
|
||||
import { ShellsService } from './services/shells.service'
|
||||
import { TerminalTabComponent } from './components/terminalTab.component'
|
||||
|
||||
@Injectable()
|
||||
@@ -13,8 +13,9 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
private app: AppService,
|
||||
private sessions: SessionsService,
|
||||
private config: ConfigService,
|
||||
private electron: ElectronService,
|
||||
private shells: ShellsService,
|
||||
private hostApp: HostAppService,
|
||||
electron: ElectronService,
|
||||
hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
@@ -23,46 +24,50 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
this.openNewTab()
|
||||
}
|
||||
})
|
||||
hostApp.secondInstance$.subscribe(async ({argv, cwd}) => {
|
||||
if (argv.length === 2) {
|
||||
let arg = path.resolve(cwd, argv[1])
|
||||
if (await fs.exists(arg)) {
|
||||
this.openNewTab(arg)
|
||||
}
|
||||
}
|
||||
})
|
||||
if (!electron.remote.process.env.DEV) {
|
||||
setImmediate(async () => {
|
||||
let argv: string[] = electron.remote.process.argv
|
||||
for (let arg of argv.slice(1).concat([electron.remote.process.argv0])) {
|
||||
if (await fs.exists(arg)) {
|
||||
if ((await fs.stat(arg)).isDirectory()) {
|
||||
this.openNewTab(arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async openNewTab (): Promise<void> {
|
||||
let cwd = null
|
||||
if (this.app.activeTab instanceof TerminalTabComponent) {
|
||||
async openNewTab (cwd?: string): Promise<void> {
|
||||
if (!cwd && this.app.activeTab instanceof TerminalTabComponent) {
|
||||
cwd = await this.app.activeTab.session.getWorkingDirectory()
|
||||
}
|
||||
let command = this.config.store.terminal.shell
|
||||
let args = []
|
||||
// TODO move this?
|
||||
let env: any = {}
|
||||
let args: string[] = []
|
||||
if (command === '~clink~') {
|
||||
command = 'cmd.exe'
|
||||
args = [
|
||||
'/k',
|
||||
path.join(
|
||||
path.dirname(this.electron.app.getPath('exe')),
|
||||
(process.platform === 'darwin') ? '../Resources' : 'resources',
|
||||
'clink',
|
||||
`clink_${process.arch}.exe`,
|
||||
),
|
||||
'inject',
|
||||
]
|
||||
({ command, args } = this.shells.getClinkOptions())
|
||||
}
|
||||
if (command === '~default-shell~') {
|
||||
if (this.hostApp.platform === Platform.Linux) {
|
||||
let line = (await fs.readFile('/etc/passwd', { encoding: 'utf-8' }))
|
||||
.split('\n').find(x => x.startsWith(process.env.LOGNAME + ':'))
|
||||
if (!line) {
|
||||
console.warn('Could not detect user shell')
|
||||
command = '/bin/sh'
|
||||
} else {
|
||||
command = line.split(':')[6]
|
||||
}
|
||||
}
|
||||
if (this.hostApp.platform === Platform.macOS) {
|
||||
let shellEntry = (await exec(`dscl . -read /Users/${process.env.LOGNAME} UserShell`))[0].toString()
|
||||
command = shellEntry.split(':')[1].trim()
|
||||
}
|
||||
command = await this.shells.getDefaultShell()
|
||||
}
|
||||
let sessionOptions = await this.sessions.prepareNewSession({ command, args, cwd })
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
env.TERM = 'cygwin'
|
||||
}
|
||||
let sessionOptions = await this.sessions.prepareNewSession({
|
||||
command,
|
||||
args,
|
||||
cwd,
|
||||
env,
|
||||
})
|
||||
this.app.openNewTab(
|
||||
TerminalTabComponent,
|
||||
{ sessionOptions }
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import * as fs from 'fs-promise'
|
||||
import * as fs from 'mz/fs'
|
||||
import * as path from 'path'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TerminalColorSchemeProvider, ITerminalColorScheme } from './api'
|
||||
|
@@ -68,11 +68,10 @@ export class TerminalSettingsTabComponent {
|
||||
|
||||
// Detect Cygwin
|
||||
let cygwinPath = await new Promise<string>(resolve => {
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup' })
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x64' })
|
||||
reg.get('rootdir', (err, item) => {
|
||||
if (err) {
|
||||
resolve(null)
|
||||
return
|
||||
return resolve(null)
|
||||
}
|
||||
resolve(item.value)
|
||||
})
|
||||
@@ -81,6 +80,20 @@ export class TerminalSettingsTabComponent {
|
||||
this.shells.push({ name: 'Cygwin', command: path.join(cygwinPath, 'bin', 'bash.exe') })
|
||||
}
|
||||
|
||||
// Detect 32-bit Cygwin
|
||||
let cygwin32Path = await new Promise<string>(resolve => {
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x86' })
|
||||
reg.get('rootdir', (err, item) => {
|
||||
if (err) {
|
||||
return resolve(null)
|
||||
}
|
||||
resolve(item.value)
|
||||
})
|
||||
})
|
||||
if (cygwin32Path) {
|
||||
this.shells.push({ name: 'Cygwin (32 bit)', command: path.join(cygwin32Path, 'bin', 'bash.exe') })
|
||||
}
|
||||
|
||||
// Detect Git-Bash
|
||||
let gitBashPath = await new Promise<string>(resolve => {
|
||||
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\GitForWindows' })
|
||||
|
@@ -47,7 +47,7 @@ export class TerminalTabComponent extends BaseTabComponent {
|
||||
) {
|
||||
super()
|
||||
this.decorators = this.decorators || []
|
||||
this.title$.next('Terminal')
|
||||
this.title = 'Terminal'
|
||||
this.configSubscription = config.changed$.subscribe(() => {
|
||||
this.configure()
|
||||
})
|
||||
@@ -69,6 +69,15 @@ export class TerminalTabComponent extends BaseTabComponent {
|
||||
this.session.releaseInitialDataBuffer()
|
||||
})
|
||||
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
|
||||
if (!this.hasFocus) {
|
||||
return
|
||||
}
|
||||
if (hotkey === 'copy') {
|
||||
this.hterm.copySelectionToClipboard()
|
||||
}
|
||||
if (hotkey === 'clear') {
|
||||
this.clear()
|
||||
}
|
||||
if (hotkey === 'zoom-in') {
|
||||
this.zoomIn()
|
||||
}
|
||||
@@ -134,7 +143,7 @@ export class TerminalTabComponent extends BaseTabComponent {
|
||||
attachHTermHandlers (hterm: any) {
|
||||
hterm.setWindowTitle = (title) => {
|
||||
this.zone.run(() => {
|
||||
this.title$.next(title)
|
||||
this.title = title
|
||||
})
|
||||
}
|
||||
|
||||
@@ -146,6 +155,8 @@ export class TerminalTabComponent extends BaseTabComponent {
|
||||
|
||||
hterm.primaryScreen_.syncSelectionCaret = () => null
|
||||
hterm.alternateScreen_.syncSelectionCaret = () => null
|
||||
hterm.primaryScreen_.terminal = hterm
|
||||
hterm.alternateScreen_.terminal = hterm
|
||||
|
||||
const _onPaste = hterm.scrollPort_.onPaste_.bind(hterm.scrollPort_)
|
||||
hterm.scrollPort_.onPaste_ = (event) => {
|
||||
@@ -228,9 +239,14 @@ export class TerminalTabComponent extends BaseTabComponent {
|
||||
this.io.writeUTF8(data)
|
||||
}
|
||||
|
||||
clear () {
|
||||
this.hterm.wipeContents()
|
||||
this.hterm.onVTKeystroke('\f')
|
||||
}
|
||||
|
||||
async configure (): Promise<void> {
|
||||
let config = this.config.store
|
||||
preferenceManager.set('font-family', config.terminal.font)
|
||||
preferenceManager.set('font-family', `"${config.terminal.font}", "monospace-fallback", monospace`)
|
||||
this.setFontSize()
|
||||
preferenceManager.set('enable-bold', true)
|
||||
preferenceManager.set('audible-bell-sound', '')
|
||||
@@ -307,8 +323,10 @@ export class TerminalTabComponent extends BaseTabComponent {
|
||||
decorator.detach(this)
|
||||
})
|
||||
this.configSubscription.unsubscribe()
|
||||
this.sessionCloseSubscription.unsubscribe()
|
||||
this.hotkeysSubscription.unsubscribe()
|
||||
if (this.sessionCloseSubscription) {
|
||||
this.sessionCloseSubscription.unsubscribe()
|
||||
}
|
||||
this.resize$.complete()
|
||||
this.input$.complete()
|
||||
this.output$.complete()
|
||||
@@ -320,7 +338,9 @@ export class TerminalTabComponent extends BaseTabComponent {
|
||||
|
||||
async destroy () {
|
||||
super.destroy()
|
||||
await this.session.destroy()
|
||||
if (this.session && this.session.open) {
|
||||
await this.session.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
private setFontSize () {
|
||||
|
@@ -44,6 +44,12 @@ export class TerminalConfigProvider extends ConfigProvider {
|
||||
shell: '~default-shell~',
|
||||
},
|
||||
hotkeys: {
|
||||
'copy': [
|
||||
'⌘-C',
|
||||
],
|
||||
'clear': [
|
||||
'⌘-K',
|
||||
],
|
||||
'zoom-in': [
|
||||
'⌘-=',
|
||||
'⌘-Shift-+',
|
||||
@@ -69,6 +75,12 @@ export class TerminalConfigProvider extends ConfigProvider {
|
||||
shell: '~clink~',
|
||||
},
|
||||
hotkeys: {
|
||||
'copy': [
|
||||
'Ctrl-Shift-C',
|
||||
],
|
||||
'clear': [
|
||||
'Ctrl-L',
|
||||
],
|
||||
'zoom-in': [
|
||||
'Ctrl-=',
|
||||
'Ctrl-Shift-+',
|
||||
@@ -93,6 +105,12 @@ export class TerminalConfigProvider extends ConfigProvider {
|
||||
shell: '~default-shell~',
|
||||
},
|
||||
hotkeys: {
|
||||
'copy': [
|
||||
'Ctrl-Shift-C',
|
||||
],
|
||||
'clear': [
|
||||
'Ctrl-L',
|
||||
],
|
||||
'zoom-in': [
|
||||
'Ctrl-=',
|
||||
'Ctrl-Shift-+',
|
||||
|
BIN
terminus-terminal/src/fonts/Meslo.otf
Normal file
BIN
terminus-terminal/src/fonts/Meslo.otf
Normal file
Binary file not shown.
@@ -4,6 +4,14 @@ import { IHotkeyDescription, HotkeyProvider } from 'terminus-core'
|
||||
@Injectable()
|
||||
export class TerminalHotkeyProvider extends HotkeyProvider {
|
||||
hotkeys: IHotkeyDescription[] = [
|
||||
{
|
||||
id: 'copy',
|
||||
name: 'Copy to clipboard',
|
||||
},
|
||||
{
|
||||
id: 'clear',
|
||||
name: 'Clear terminal',
|
||||
},
|
||||
{
|
||||
id: 'zoom-in',
|
||||
name: 'Zoom in',
|
||||
|
@@ -9,3 +9,8 @@ a:hover {
|
||||
x-screen {
|
||||
transition: 0.125s ease background;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "monospace-fallback";
|
||||
src: url(fonts/Meslo.otf) format("opentype");
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ import { TerminalSettingsTabComponent } from './components/terminalSettingsTab.c
|
||||
import { ColorPickerComponent } from './components/colorPicker.component'
|
||||
|
||||
import { SessionsService } from './services/sessions.service'
|
||||
import { ShellsService } from './services/shells.service'
|
||||
|
||||
import { ScreenPersistenceProvider } from './persistenceProviders'
|
||||
import { ButtonProvider } from './buttonProvider'
|
||||
@@ -31,6 +32,7 @@ import { hterm } from './hterm'
|
||||
],
|
||||
providers: [
|
||||
SessionsService,
|
||||
ShellsService,
|
||||
ScreenPersistenceProvider,
|
||||
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
||||
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import * as fs from 'fs-promise'
|
||||
import * as fs from 'mz/fs'
|
||||
import { exec, spawn } from 'mz/child_process'
|
||||
import { exec as execCallback } from 'child_process'
|
||||
|
||||
@@ -88,7 +88,8 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
|
||||
await fs.writeFile(configPath, `
|
||||
escape ^^^
|
||||
vbell on
|
||||
deflogin off
|
||||
deflogin on
|
||||
defflow off
|
||||
term xterm-color
|
||||
bindkey "^[OH" beginning-of-line
|
||||
bindkey "^[OF" end-of-line
|
||||
@@ -98,6 +99,8 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
|
||||
defhstatus "^Et"
|
||||
hardstatus off
|
||||
altscreen on
|
||||
defutf8 on
|
||||
defencoding utf8
|
||||
`, 'utf-8')
|
||||
let recoveryId = `term-tab-${Date.now()}`
|
||||
let args = ['-d', '-m', '-c', configPath, '-U', '-S', recoveryId, '-T', 'xterm-256color', '--', '-' + options.command].concat(options.args || [])
|
||||
@@ -110,6 +113,10 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
|
||||
}
|
||||
|
||||
async terminateSession (recoveryId: string): Promise<void> {
|
||||
await exec(`screen -S ${recoveryId} -X quit`)
|
||||
try {
|
||||
await exec(`screen -S ${recoveryId} -X quit`)
|
||||
} catch (_) {
|
||||
// screen has already quit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import * as nodePTY from 'node-pty'
|
||||
import * as fs from 'fs-promise'
|
||||
import * as fs from 'mz/fs'
|
||||
import { Subject } from 'rxjs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { Logger, LogService } from 'terminus-core'
|
||||
@@ -25,8 +25,20 @@ export class Session {
|
||||
|
||||
let env = {
|
||||
...process.env,
|
||||
...options.env,
|
||||
TERM: 'xterm-256color',
|
||||
...options.env,
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin' && !process.env.LC_ALL) {
|
||||
let locale = process.env.LC_CTYPE || 'en_US.UTF-8'
|
||||
Object.assign(env, {
|
||||
LANG: locale,
|
||||
LC_ALL: locale,
|
||||
LC_MESSAGES: locale,
|
||||
LC_NUMERIC: locale,
|
||||
LC_COLLATE: locale,
|
||||
LC_MONETARY: locale,
|
||||
})
|
||||
}
|
||||
this.pty = nodePTY.spawn(options.command, options.args || [], {
|
||||
name: 'xterm-256color',
|
||||
@@ -54,6 +66,12 @@ export class Session {
|
||||
}
|
||||
})
|
||||
|
||||
this.pty.on('exit', () => {
|
||||
if (this.open) {
|
||||
this.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
this.pty.on('close', () => {
|
||||
if (this.open) {
|
||||
this.destroy()
|
||||
@@ -68,11 +86,15 @@ export class Session {
|
||||
}
|
||||
|
||||
resize (columns, rows) {
|
||||
this.pty.resize(columns, rows)
|
||||
if (this.pty.writable) {
|
||||
this.pty.resize(columns, rows)
|
||||
}
|
||||
}
|
||||
|
||||
write (data) {
|
||||
this.pty.write(Buffer.from(data, 'utf-8'))
|
||||
if (this.pty.writable) {
|
||||
this.pty.write(Buffer.from(data, 'utf-8'))
|
||||
}
|
||||
}
|
||||
|
||||
kill (signal?: string) {
|
||||
@@ -114,7 +136,11 @@ export class Session {
|
||||
async getWorkingDirectory (): Promise<string> {
|
||||
if (process.platform === 'darwin') {
|
||||
let lines = (await exec(`lsof -p ${this.truePID} -Fn`))[0].toString().split('\n')
|
||||
return lines[2].substring(1)
|
||||
if (lines[1] === 'fcwd') {
|
||||
return lines[2].substring(1)
|
||||
} else {
|
||||
return lines[1].substring(1)
|
||||
}
|
||||
}
|
||||
if (process.platform === 'linux') {
|
||||
return await fs.readlink(`/proc/${this.truePID}/cwd`)
|
||||
|
58
terminus-terminal/src/services/shells.service.ts
Normal file
58
terminus-terminal/src/services/shells.service.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import * as path from 'path'
|
||||
import { exec } from 'mz/child_process'
|
||||
import * as fs from 'mz/fs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ElectronService, HostAppService, Platform, Logger, LogService } from 'terminus-core'
|
||||
|
||||
@Injectable()
|
||||
export class ShellsService {
|
||||
private logger: Logger
|
||||
|
||||
constructor (
|
||||
log: LogService,
|
||||
private electron: ElectronService,
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
this.logger = log.create('shells')
|
||||
}
|
||||
|
||||
getClinkOptions (): { command, args } {
|
||||
return {
|
||||
command: 'cmd.exe',
|
||||
args: [
|
||||
'/k',
|
||||
path.join(
|
||||
path.dirname(this.electron.app.getPath('exe')),
|
||||
'resources',
|
||||
'clink',
|
||||
`clink_${process.arch}.exe`,
|
||||
),
|
||||
'inject',
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
async getDefaultShell (): Promise<string> {
|
||||
if (this.hostApp.platform === Platform.macOS) {
|
||||
return this.getDefaultMacOSShell()
|
||||
} else {
|
||||
return this.getDefaultLinuxShell()
|
||||
}
|
||||
}
|
||||
|
||||
async getDefaultMacOSShell (): Promise<string> {
|
||||
let shellEntry = (await exec(`dscl . -read /Users/${process.env.LOGNAME} UserShell`))[0].toString()
|
||||
return shellEntry.split(' ')[1].trim()
|
||||
}
|
||||
|
||||
async getDefaultLinuxShell (): Promise<string> {
|
||||
let line = (await fs.readFile('/etc/passwd', { encoding: 'utf-8' }))
|
||||
.split('\n').find(x => x.startsWith(process.env.LOGNAME + ':'))
|
||||
if (!line) {
|
||||
this.logger.warn('Could not detect user shell')
|
||||
return '/bin/sh'
|
||||
} else {
|
||||
return line.split(':')[6]
|
||||
}
|
||||
}
|
||||
}
|
@@ -34,14 +34,21 @@ module.exports = {
|
||||
{ test: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
|
||||
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||
{ test: /\.css$/, use: ['to-string-loader', 'css-loader'] },
|
||||
{
|
||||
test: /\.(ttf|eot|otf|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
loader: "url-loader",
|
||||
options: {
|
||||
limit: 999999999999,
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
externals: [
|
||||
'fs',
|
||||
'fs-promise',
|
||||
'font-manager',
|
||||
'path',
|
||||
'node-pty',
|
||||
'mz/fs',
|
||||
'mz/child_process',
|
||||
'winreg',
|
||||
/^rxjs/,
|
||||
|
119
terminus-terminal/yarn.lock
Normal file
119
terminus-terminal/yarn.lock
Normal file
@@ -0,0 +1,119 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/deep-equal@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/deep-equal/-/deep-equal-1.0.0.tgz#9ebeaa73d1fc4791f038a5f1440e0449ea968495"
|
||||
|
||||
"@types/mz@0.0.31":
|
||||
version "0.0.31"
|
||||
resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.31.tgz#a4d80c082fefe71e40a7c0f07d1e6555bbbc7b52"
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@7.0.12":
|
||||
version "7.0.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.12.tgz#ae5f67a19c15f752148004db07cbbb372e69efc9"
|
||||
|
||||
"@types/webpack-env@1.13.0":
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.0.tgz#3044381647e11ee973c5af2e925323930f691d80"
|
||||
|
||||
"@types/winreg@^1.2.30":
|
||||
version "1.2.30"
|
||||
resolved "https://registry.yarnpkg.com/@types/winreg/-/winreg-1.2.30.tgz#91d6710e536d345b9c9b017c574cf6a8da64c518"
|
||||
|
||||
any-promise@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||
|
||||
big.js@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
|
||||
|
||||
dataurl@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/dataurl/-/dataurl-0.1.0.tgz#1f4734feddec05ffe445747978d86759c4b33199"
|
||||
|
||||
deep-equal@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
|
||||
|
||||
emojis-list@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
|
||||
|
||||
file-loader@^0.11.2:
|
||||
version "0.11.2"
|
||||
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.2.tgz#4ff1df28af38719a6098093b88c82c71d1794a34"
|
||||
dependencies:
|
||||
loader-utils "^1.0.2"
|
||||
|
||||
font-manager@0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/font-manager/-/font-manager-0.2.2.tgz#18a1c5b6ec7f91e22a17c71cbbaa0ea4e68e3a44"
|
||||
dependencies:
|
||||
nan "~2.2.0"
|
||||
|
||||
hterm-umdjs@1.1.3:
|
||||
version "1.1.3+1.58.sha.15ed490"
|
||||
resolved "https://registry.yarnpkg.com/hterm-umdjs/-/hterm-umdjs-1.1.3.tgz#8b57bcaded5ba9541d6c8e32a82b34abb93e885e"
|
||||
|
||||
json5@^0.5.0:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
|
||||
|
||||
loader-utils@^1.0.2:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
|
||||
dependencies:
|
||||
big.js "^3.1.3"
|
||||
emojis-list "^2.0.0"
|
||||
json5 "^0.5.0"
|
||||
|
||||
mz@^2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mz/-/mz-2.6.0.tgz#c8b8521d958df0a4f2768025db69c719ee4ef1ce"
|
||||
dependencies:
|
||||
any-promise "^1.0.0"
|
||||
object-assign "^4.0.1"
|
||||
thenify-all "^1.0.0"
|
||||
|
||||
nan@2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.0.tgz#aa8f1e34531d807e9e27755b234b4a6ec0c152a8"
|
||||
|
||||
nan@~2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.2.1.tgz#d68693f6b34bb41d66bc68b3a4f9defc79d7149b"
|
||||
|
||||
node-pty@0.6.8:
|
||||
version "0.6.8"
|
||||
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.6.8.tgz#a7b145397bef23a719128a75b20d4821726dfe90"
|
||||
dependencies:
|
||||
nan "2.5.0"
|
||||
|
||||
object-assign@^4.0.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
||||
runes@^0.4.2:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/runes/-/runes-0.4.2.tgz#1ddc1ea41de769cb32fc068a64fbbc45cd21052e"
|
||||
|
||||
thenify-all@^1.0.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
|
||||
dependencies:
|
||||
thenify ">= 3.1.0 < 4"
|
||||
|
||||
"thenify@>= 3.1.0 < 4":
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839"
|
||||
dependencies:
|
||||
any-promise "^1.0.0"
|
||||
|
||||
winreg@^1.2.3:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
|
Reference in New Issue
Block a user