Compare commits

...

56 Commits

Author SHA1 Message Date
Eugene Pankov
33f67503bd pass alt-numbers to the shell (fixes #217) 2017-10-22 22:10:48 +02:00
Eugene Pankov
21e1656780 only show drag space on Win & Linux with thin titlebar (ref #219) 2017-10-22 21:23:53 +02:00
Eugene Pankov
ceacf5c760 added tab context menu (ref #219) 2017-10-22 21:01:31 +02:00
Eugene Pankov
e0c0cd17bd Handle multiple arguments in custom shell 2017-10-21 22:11:27 +02:00
Eugene Pankov
e81e5034b9 explicitly specify --login for POSIX shells 2017-10-20 21:44:34 +02:00
Eugene Pankov
11e0c36ebc properly position context menu (fixes #215) 2017-10-13 20:33:10 +02:00
Eugene Pankov
e52fd0a3dd theming fix 2017-10-08 14:56:51 +02:00
Eugene Pankov
48ccc538e5 fixed button group appearance in settings 2017-10-08 14:48:59 +02:00
Eugene Pankov
53ac39232c a compact theme 2017-10-08 14:47:14 +02:00
Eugene Pankov
f68e06c9ed . 2017-10-07 18:09:22 +02:00
Eugene Pankov
6c884e090c blinking cursor (fixes #191) 2017-10-07 18:07:57 +02:00
Eugene Pankov
38cda117e2 option to auto-start a terminal tab (fixes #107) 2017-10-07 17:47:04 +02:00
Eugene Pankov
fb64ca08d3 custom shells (fixes #50) 2017-10-07 17:27:58 +02:00
Eugene Pankov
0fe7edc5b5 auto reposition window on resolution changes (fixes #150) 2017-10-07 16:47:37 +02:00
Eugene Pankov
1614405c62 link plugin pages in the plugin list 2017-09-28 20:47:19 +02:00
Eugene Pankov
87730ba7b3 fixed #204 2017-09-28 20:34:37 +02:00
Eugene Pankov
eb2eef64fc fixed #133 2017-09-28 20:27:16 +02:00
Eugene Pankov
766ab48e1a ci fix 2017-09-10 09:22:28 +02:00
Eugene Pankov
e255ca7737 context menu (fixes #42) 2017-09-09 21:42:48 +02:00
Eugene Pankov
558c72bb42 update checker (fixes #166, #99) 2017-09-09 14:09:27 +02:00
Eugene Pankov
ede59ed4d4 ignore stray tmux responses (fixes #178) 2017-09-09 13:25:12 +02:00
Eugene Pankov
3ced784568 drop x86 2017-09-09 12:55:20 +02:00
Eugene Pankov
6b12196761 properly close hotkey input windows (fixes #198) 2017-09-09 12:53:30 +02:00
Eugene Pankov
9f58e9f183 ci 2017-09-09 12:36:06 +02:00
Eugene Pankov
607efaa075 appveyor 2017-09-09 11:43:21 +02:00
Eugene Pankov
706f2042af travis 2017-09-09 11:33:06 +02:00
Eugene Pankov
fa2650cd1f appveyor fix 2017-09-06 17:07:14 +02:00
Eugene Pankov
33514cb073 bumped ng-bootstrap 2017-08-30 11:47:49 +02:00
Eugene Pankov
4d2be9ec89 handle Hyper plugin crashes (fixes #71) 2017-08-30 11:23:51 +02:00
Eugene Pankov
1b2236eb90 fixed #187, fixed #188 2017-08-30 11:12:04 +02:00
Eugene Pankov
f84fd07857 invert scroll-zoom (fixes #184) 2017-08-26 20:02:15 +02:00
Eugene Pankov
24c59b88ca Merge branch 'master' of https://github.com/Eugeny/terminus 2017-08-20 19:31:17 +02:00
Eugene Pankov
e45090cc89 handle compose key on Windows (fixes #17) 2017-08-20 19:31:15 +02:00
Eugene Pankov
f53b96eba8 detect git-bash when installed for current user only (closes #161) 2017-08-18 18:28:38 +03:00
Eugene Pankov
80699ee13f handle plugin loading errors 2017-08-13 15:13:04 +03:00
Eugene Pankov
7e7d537868 allow null values in config (fixes #165) 2017-08-11 19:47:52 +03:00
Eugene Pankov
1afb1e718b change default tmux hotkey (fixes #171) 2017-08-11 19:26:24 +03:00
Eugene Pankov
f71f518058 store Screen configuration in Terminus user directory (fixes #177) 2017-08-11 19:21:32 +03:00
Eugene Pankov
7a005132cc Merge branch 'master' of github.com:Eugeny/terminus 2017-08-11 19:17:54 +03:00
Eugene Pankov
34ef809aee handle null results from winreg (fixes #174) 2017-08-11 19:16:58 +03:00
Eugene Pankov
6352f22c48 Merge pull request #167 from koraktor/patch-1
Start an interactive logon shell for Git Bash
2017-08-07 13:52:54 +02:00
Sebastian Staudt
d0f378764f Start an interactive logon shell for Git Bash
Provide additional arguments to `bash.exe` to get an interactive login shell.
This ensures e.g. `.profile` and `.bash_profile` are sourced. As there’s no way
to have an existing session under Windows, `--login` is mandatory. Each bash
session must be started from scratch.

Fixes #105
2017-08-07 10:07:07 +02:00
Eugene Pankov
7885badbfd make line padding adjustable (fixes #141) 2017-08-05 16:57:00 +02:00
Eugene Pankov
5999d169bc mac & windows icons 2017-08-05 16:27:25 +02:00
Eugene Pankov
40b0f8cb69 added tmux dependency 2017-08-05 10:15:07 +02:00
Eugene Pankov
f428be5ae7 ignore unavaiable persistence providers in SessionsService (fixes #159) 2017-08-05 09:25:25 +02:00
Eugene Pankov
39183b1205 Merge branch 'master' of github.com:Eugeny/terminus 2017-08-04 14:42:06 +02:00
Eugene Pankov
36f82545ae fixed #155 2017-08-04 14:41:36 +02:00
Eugene Pankov
1ef8343ea9 default to tmux if available on Linux 2017-08-04 14:40:49 +02:00
fossabot
c9e24819ae Add license scan report and status 2017-08-04 13:39:41 +02:00
Eugene Pankov
e2f0ceef19 README 2017-08-04 13:26:08 +02:00
Eugene Pankov
acd6995bcc README 2017-08-04 13:25:14 +02:00
Eugene Pankov
ca5e6079bc README 2017-08-04 13:22:38 +02:00
Eugene Pankov
48ad16946b README 2017-08-04 13:20:44 +02:00
Eugene Pankov
0a8af12a93 branding 2017-08-04 13:17:50 +02:00
Eugene Pankov
7e602a3612 bump 2017-08-02 15:22:32 +02:00
82 changed files with 2033 additions and 302 deletions

View File

@@ -32,12 +32,3 @@ addons:
- rpm - rpm
- wine - wine
- mono-runtime - mono-runtime
deploy:
provider: releases
api_key: $GITHUB_TOKEN
file_glob: true
file: "dist/terminus*"
skip_cleanup: true
on:
tags: true

View File

@@ -1,7 +1,16 @@
# Terminus α <div align="center">
*A terminal for a more modern age* <img src="https://raw.githubusercontent.com/Eugeny/terminus/master/build/icons/128x128.png">
[![Build Status](https://travis-ci.org/Eugeny/terminus.svg?branch=master)](https://travis-ci.org/Eugeny/terminus) [![Build status](https://ci.appveyor.com/api/projects/status/wnnq4hm5mbd9rgoy?svg=true)](https://ci.appveyor.com/project/Eugeny/terminus) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Eugeny/terminus/master/LICENSE) [![Downloads](https://img.shields.io/badge/downloads-latest_release-brightgreen.svg)](https://github.com/Eugeny/terminus/releases/latest) <h1>Terminus α</h1>
<p>
<i>A terminal for a more modern age</i>
</p>
<br/>
<br/>
<br/>
</div>
[![Build Status](https://travis-ci.org/Eugeny/terminus.svg?branch=master)](https://travis-ci.org/Eugeny/terminus) [![Build status](https://ci.appveyor.com/api/projects/status/wnnq4hm5mbd9rgoy?svg=true)](https://ci.appveyor.com/project/Eugeny/terminus) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Eugeny/terminus/master/LICENSE) [![Downloads](https://img.shields.io/badge/downloads-latest_release-brightgreen.svg)](https://github.com/Eugeny/terminus/releases/latest)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FEugeny%2Fterminus.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FEugeny%2Fterminus?ref=badge_shield)
---- ----
@@ -37,3 +46,7 @@ Plugins can be installed directly from the Settings view inside Terminus.
Pull requests and plugins are welcome! Publish your plugin on NPM with a `terminus-plugin` keyword to make them appear in the Plugin Manager. Pull requests and plugins are welcome! Publish your plugin on NPM with a `terminus-plugin` keyword to make them appear in the Plugin Manager.
See [HACKING.md](https://github.com/Eugeny/terminus/blob/master/HACKING.md) for a very brief plugin development tutorial! See [HACKING.md](https://github.com/Eugeny/terminus/blob/master/HACKING.md) for a very brief plugin development tutorial!
## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FEugeny%2Fterminus.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FEugeny%2Fterminus?ref=badge_large)

View File

@@ -13,22 +13,9 @@ html
app-root app-root
.preload-logo .preload-logo
div div
.terminus-logo.animated .terminus-logo
.part(style='transform: rotateZ(0deg)')
div
.part(style='transform: rotateZ(51deg)')
div
.part(style='transform: rotateZ(102deg)')
div
.part(style='transform: rotateZ(154deg)')
div
.part(style='transform: rotateZ(205deg)')
div
.part(style='transform: rotateZ(257deg)')
div
.part(style='transform: rotateZ(308deg)')
div
h1.terminus-title Terminus h1.terminus-title Terminus
sup α
.progress .progress
.bar(style='width: 0%') .bar(style='width: 0%')

View File

@@ -192,7 +192,6 @@ start = () => {
let options = { let options = {
width: 800, width: 800,
height: 600, height: 600,
//icon: `${app.getAppPath()}/assets/img/icon.png`,
title: 'Terminus', title: 'Terminus',
minWidth: 400, minWidth: 400,
minHeight: 300, minHeight: 300,

View File

@@ -19,7 +19,7 @@
"@angular/forms": "4.3.0", "@angular/forms": "4.3.0",
"@angular/platform-browser": "4.3.0", "@angular/platform-browser": "4.3.0",
"@angular/platform-browser-dynamic": "4.3.0", "@angular/platform-browser-dynamic": "4.3.0",
"@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.28", "@ng-bootstrap/ng-bootstrap": "^1.0.0-beta.2",
"devtron": "1.4.0", "devtron": "1.4.0",
"electron-config": "0.2.1", "electron-config": "0.2.1",
"electron-debug": "^1.0.1", "electron-debug": "^1.0.1",

View File

@@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser' import { BrowserModule } from '@angular/platform-browser'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
export async function getRootModule (plugins: any[]): Promise<any> { export function getRootModule (plugins: any[]) {
let imports = [ let imports = [
BrowserModule, BrowserModule,
...(plugins.map(x => x.default.forRoot ? x.default.forRoot() : x.default)), ...(plugins.map(x => x.default.forRoot ? x.default.forRoot() : x.default)),

View File

@@ -6,11 +6,11 @@ import 'rxjs'
// Always land on the start view // Always land on the start view
location.hash = '' location.hash = ''
import { enableProdMode } from '@angular/core' import { enableProdMode, NgModuleRef } from '@angular/core'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { getRootModule } from './app.module' import { getRootModule } from './app.module'
import { findPlugins, loadPlugins } from './plugins' import { findPlugins, loadPlugins, IPluginInfo } from './plugins'
if (process.platform === 'win32') { if (process.platform === 'win32') {
process.env.HOME = process.env.HOMEDRIVE + process.env.HOMEPATH process.env.HOME = process.env.HOMEDRIVE + process.env.HOMEPATH
@@ -22,10 +22,29 @@ if (require('electron-is-dev')) {
enableProdMode() enableProdMode()
} }
findPlugins().then(async plugins => { async function bootstrap (plugins: IPluginInfo[], safeMode = false): Promise<NgModuleRef<any>> {
if (safeMode) {
plugins = plugins.filter(x => x.isBuiltin)
}
let pluginsModules = await loadPlugins(plugins, (current, total) => { let pluginsModules = await loadPlugins(plugins, (current, total) => {
(document.querySelector('.progress .bar') as HTMLElement).style.width = 100 * current / total + '%' (document.querySelector('.progress .bar') as HTMLElement).style.width = 100 * current / total + '%'
}) })
let module = await getRootModule(pluginsModules) let module = getRootModule(pluginsModules)
platformBrowserDynamic().bootstrapModule(module) return await platformBrowserDynamic().bootstrapModule(module)
}
findPlugins().then(async plugins => {
console.log('Starting with plugins:', plugins)
try {
await bootstrap(plugins)
} catch (error) {
console.error('Angular bootstrapping error:', error)
console.warn('Trying safe mode')
window['safeModeReason'] = error
try {
await bootstrap(plugins, true)
} catch (error) {
console.error('Bootstrap failed:', error)
}
}
}) })

89
app/src/logo.svg Normal file
View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="150mm"
height="150mm"
viewBox="0 0 150 150"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="logo.svg"
inkscape:export-filename="/home/eugene/Work/term/build/icons/16x16.png"
inkscape:export-xdpi="2.7093334"
inkscape:export-ydpi="2.7093334">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="134.39743"
inkscape:cy="340.43068"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:window-width="1366"
inkscape:window-height="692"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-10.356544,-82.309525)">
<path
inkscape:connector-curvature="0"
id="path138"
style="opacity:0.9;fill:#ccccff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 39.305965,108.47713 60.922105,35.13225 0.0945,21.68327 -61.016595,-37.11662 z"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
id="path116"
style="opacity:0.9;fill:#6666cc;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 136.19445,144.4429 0.0455,20.67266 -78.028381,44.11611 -0.0031,-19.78119 z"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
id="path118"
style="opacity:0.9;fill:#ccccff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 39.471179,178.6501 18.737341,10.818 0.0031,19.78099 -18.740409,-10.88245 z"
sodipodi:nodetypes="ccccc" />
<path
style="opacity:0.9;fill:#b4e2ff;fill-rule:evenodd;stroke:none;stroke-width:1.00546169px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 56.43263,98.242186 -17.391087,10.041014 61.186527,35.32618 -61.020778,35.23005 18.839694,10.87703 61.020784,-35.23005 17.39108,-10.04102 z"
id="path134"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -20,7 +20,7 @@ if (process.env.DEV) {
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath())) nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
} }
const builtinPluginsPath = path.join((process as any).resourcesPath, 'builtin-plugins') const builtinPluginsPath = process.env.DEV ? path.dirname(require('electron').remote.app.getAppPath()) : path.join((process as any).resourcesPath, 'builtin-plugins')
const userPluginsPath = path.join( const userPluginsPath = path.join(
require('electron').remote.app.getPath('appData'), require('electron').remote.app.getPath('appData'),

View File

@@ -1,6 +1,3 @@
$color: rgba(66, 142, 173, 0.75);
.preload-logo { .preload-logo {
-webkit-app-region: drag; -webkit-app-region: drag;
position: fixed; position: fixed;
@@ -24,7 +21,7 @@ $color: rgba(66, 142, 173, 0.75);
.bar { .bar {
transition: 1s ease-out width; transition: 1s ease-out width;
background: $color; background: #a1c5e4;
height: 3px; height: 3px;
} }
} }
@@ -42,63 +39,22 @@ $color: rgba(66, 142, 173, 0.75);
.terminus-logo { .terminus-logo {
width: 160px; width: 160px;
height: 160px; height: 160px;
background: url('./logo.svg');
background-repeat: none;
background-size: contain;
margin: auto; margin: auto;
position: relative;
transform: rotateZ(-14.5deg);
.part {
position: absolute;
width: 160px;
height: 160px;
div {
position: absolute;
top: 33px;
left: 24px;
width: 44px;
height: 44px;
background: $color;
transform: rotateX(52deg) rotateY(-42deg);
animation: terminusLogoPartOnce ease-out 1s;
}
}
&.animated .part div {
animation: terminusLogoPart infinite ease-out 2s;
}
} }
.terminus-title { .terminus-title {
color: $color; color: #a1c5e4;
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
text-align: center; text-align: center;
font-weight: normal; font-weight: normal;
font-size: 42px; font-size: 42px;
margin: 0; margin: 0;
}
sup {
@keyframes terminusLogoPart { color: #842fe0;
0% {
transform: rotateX(90deg) rotateY(-90deg);
}
25% {
transform: rotateX(52deg) rotateY(-42deg);
}
75% {
transform: rotateX(52deg) rotateY(-42deg);
}
100% {
transform: rotateX(-90deg) rotateY(-90deg);
}
}
@keyframes terminusLogoPartOnce {
0% {
transform: rotateX(90deg) rotateY(-90deg);
}
100% {
transform: rotateX(52deg) rotateY(-42deg);
} }
} }

View File

@@ -44,9 +44,9 @@
dependencies: dependencies:
tslib "^1.7.1" tslib "^1.7.1"
"@ng-bootstrap/ng-bootstrap@^1.0.0-alpha.28": "@ng-bootstrap/ng-bootstrap@^1.0.0-beta.2":
version "1.0.0-alpha.28" version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-1.0.0-alpha.28.tgz#30a6503bf7f94f9d3187591fb3267b59cc0cdaad" resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-1.0.0-beta.2.tgz#3d4b567b0334a9ee631b73c72156cd3a9d3cd29f"
"@types/mz@0.0.31": "@types/mz@0.0.31":
version "0.0.31" version "0.0.31"

View File

@@ -24,14 +24,3 @@ build_script:
artifacts: artifacts:
- path: 'dist\win\*.exe' - path: 'dist\win\*.exe'
deploy:
provider: GitHub
auth_token:
secure: wvxHVlprvhfdOHgmVEDIwjCHYlmuDykteIEHpAfpi807+1lJD3ld2/OS6+0fgU4e
artifact: /.*\.exe/
draft: false
prerelease: false
force_update: true
on:
branch: master
appveyor_repo_tag: true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

118
build/icons/icon.svg Normal file
View File

@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="150mm"
height="150mm"
viewBox="0 0 150 150"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="icon.svg">
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
id="linearGradient4649">
<stop
style="stop-color:#000916;stop-opacity:1"
offset="0"
id="stop4645" />
<stop
style="stop-color:#004565;stop-opacity:1"
offset="1"
id="stop4647" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4649"
id="linearGradient4651"
x1="89.26284"
y1="85.146751"
x2="89.26284"
y2="229.47229"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="134.39743"
inkscape:cy="340.43068"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:window-width="1366"
inkscape:window-height="692"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-10.356544,-82.309525)">
<rect
id="rect168"
width="150"
height="150"
x="10.356544"
y="82.309525"
style="fill:url(#linearGradient4651);fill-opacity:1;stroke-width:0.26458332"
rx="10"
ry="10" />
<path
inkscape:connector-curvature="0"
id="path138"
style="opacity:0.9;fill:#ccccff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 39.305965,108.47713 60.922105,35.13225 0.0945,21.68327 -61.016595,-37.11662 z"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
id="path116"
style="opacity:0.9;fill:#6666cc;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 136.19445,144.4429 0.0455,20.67266 -78.028381,44.11611 -0.0031,-19.78119 z"
sodipodi:nodetypes="ccccc" />
<path
inkscape:connector-curvature="0"
id="path118"
style="opacity:0.9;fill:#ccccff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 39.471179,178.6501 18.737341,10.818 0.0031,19.78099 -18.740409,-10.88245 z"
sodipodi:nodetypes="ccccc" />
<path
style="opacity:0.9;fill:#b4e2ff;fill-rule:evenodd;stroke:none;stroke-width:1.00546169px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 56.43263,98.242186 -17.391087,10.041014 61.186527,35.32618 -61.020778,35.23005 18.839694,10.87703 61.020784,-35.23005 17.39108,-10.04102 z"
id="path134"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 361 KiB

View File

@@ -52,19 +52,26 @@
"clink" "clink"
], ],
"win": { "win": {
"icon": "./build/windows/icon.ico" "icon": "./build/windows/icon.ico",
"publish": ["github"]
}, },
"squirrelWindows": { "squirrelWindows": {
"iconUrl": "https://github.com/Eugeny/terminus/raw/master/build/windows/icon.ico" "iconUrl": "https://github.com/Eugeny/terminus/raw/master/build/windows/icon.ico",
"artifactName": "terminus-${version}-${os}-${arch}.exe"
}, },
"mac": { "mac": {
"category": "public.app-category.video", "category": "public.app-category.video",
"icon": "./build/mac/icon.icns", "icon": "./build/mac/icon.icns",
"identity": null "identity": null,
"publish": ["github"]
},
"dmg": {
"artifactName": "terminus-${version}-${os}-${arch}.dmg"
}, },
"linux": { "linux": {
"category": "Utilities", "category": "Utilities",
"icon": "./build/icons" "icon": "./build/icons",
"publish": ["github"]
}, },
"deb": { "deb": {
"depends": [ "depends": [
@@ -74,13 +81,16 @@
"libnotify4", "libnotify4",
"libappindicator1", "libappindicator1",
"libxtst6", "libxtst6",
"libnss3" "libnss3",
] "tmux"
],
"artifactName": "terminus-${version}-${os}-${arch}.deb"
}, },
"rpm": { "rpm": {
"depends": [ "depends": [
"screen" "screen"
] ],
"artifactName": "terminus-${version}-${os}-${arch}.rpm"
} }
}, },
"scripts": { "scripts": {

View File

@@ -8,4 +8,6 @@ builder({
extraMetadata: { extraMetadata: {
version: vars.version, version: vars.version,
}, },
publish: 'onTag',
draft: false
}) })

View File

@@ -8,4 +8,6 @@ builder({
extraMetadata: { extraMetadata: {
version: vars.version, version: vars.version,
}, },
publish: 'onTag',
draft: false
}) })

View File

@@ -8,4 +8,6 @@ builder({
extraMetadata: { extraMetadata: {
version: vars.version, version: vars.version,
}, },
publish: 'onTag',
draft: false
}) })

View File

@@ -5,18 +5,15 @@ const vars = require('./vars')
const log = require('npmlog') const log = require('npmlog')
log.info('deps', 'app') log.info('deps', 'app')
sh.exec('yarn prune')
sh.exec('yarn install') sh.exec('yarn install')
sh.cd('app') sh.cd('app')
sh.exec('yarn prune')
sh.exec('yarn install') sh.exec('yarn install')
sh.cd('..') sh.cd('..')
vars.builtinPlugins.forEach(plugin => { vars.builtinPlugins.forEach(plugin => {
log.info('deps', plugin) log.info('deps', plugin)
sh.cd(plugin) sh.cd(plugin)
sh.exec('yarn prune')
sh.exec('yarn install') sh.exec('yarn install')
sh.cd('..') sh.cd('..')
}) })

View File

@@ -15,5 +15,5 @@ exports.builtinPlugins = [
'terminus-community-color-schemes', 'terminus-community-color-schemes',
'terminus-plugin-manager', 'terminus-plugin-manager',
] ]
exports.nativeModules = ['node-pty', 'font-manager'] exports.nativeModules = ['node-pty-tmp', 'font-manager']
exports.electronVersion = pkgInfo.devDependencies.electron exports.electronVersion = pkgInfo.devDependencies.electron

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-community-color-schemes", "name": "terminus-community-color-schemes",
"version": "1.0.0-alpha.23-8-gcdc7daf", "version": "1.0.0-alpha.24",
"description": "Community color schemes for Terminus", "description": "Community color schemes for Terminus",
"keywords": [ "keywords": [
"terminus-plugin" "terminus-plugin"

View File

@@ -0,0 +1,11 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@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.1"
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.1.tgz#b45c222e24301bd006e3edfc762cc6b51bda236a"

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-core", "name": "terminus-core",
"version": "1.0.0-alpha.23-8-gcdc7daf", "version": "1.0.0-alpha.24",
"description": "Terminus core", "description": "Terminus core",
"keywords": [ "keywords": [
"terminus-plugin" "terminus-plugin"
@@ -20,8 +20,10 @@
"@types/js-yaml": "^3.9.0", "@types/js-yaml": "^3.9.0",
"@types/node": "^7.0.37", "@types/node": "^7.0.37",
"@types/webpack-env": "^1.13.0", "@types/webpack-env": "^1.13.0",
"axios": "0.16.2",
"bootstrap": "4.0.0-alpha.6", "bootstrap": "4.0.0-alpha.6",
"core-js": "^2.4.1", "core-js": "^2.4.1",
"electron-updater": "^2.8.9",
"ngx-perfect-scrollbar": "4.0.0", "ngx-perfect-scrollbar": "4.0.0",
"typescript": "^2.4.1" "typescript": "^2.4.1"
}, },

View File

@@ -19,7 +19,6 @@ title-bar(
[class.drag-region]='hostApp.platform == Platform.macOS', [class.drag-region]='hostApp.platform == Platform.macOS',
@animateTab, @animateTab,
(click)='app.selectTab(tab)', (click)='app.selectTab(tab)',
(closeClicked)='app.closeTab(tab, true)',
) )
.btn-group .btn-group
@@ -30,7 +29,7 @@ title-bar(
) )
i.fa([class]='"fa fa-" + button.icon') i.fa([class]='"fa fa-" + button.icon')
.drag-space .drag-space(*ngIf='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS')
.btn-group .btn-group
button.btn.btn-secondary.btn-tab-bar( button.btn.btn-secondary.btn-tab-bar(
@@ -39,6 +38,13 @@ title-bar(
(click)='button.click()', (click)='button.click()',
) )
i.fa([class]='"fa fa-" + button.icon') i.fa([class]='"fa fa-" + button.icon')
button.btn.btn-secondary.btn-tab-bar(
*ngIf='appUpdate',
title='Update available',
(click)='updateApp()',
)
i.fa.fa-arrow-up.text-info
span.text-info Update
window-controls( window-controls(
*ngIf='config.store.appearance.frame == "thin" && (hostApp.platform == Platform.Windows || hostApp.platform == Platform.Linux)', *ngIf='config.store.appearance.frame == "thin" && (hostApp.platform == Platform.Windows || hostApp.platform == Platform.Linux)',

View File

@@ -1,5 +1,6 @@
import { Component, Inject, Input, HostListener } from '@angular/core' import { Component, Inject, Input, HostListener } from '@angular/core'
import { trigger, style, animate, transition, state } from '@angular/animations' import { trigger, style, animate, transition, state } from '@angular/animations'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { ElectronService } from '../services/electron.service' import { ElectronService } from '../services/electron.service'
import { HostAppService, Platform } from '../services/hostApp.service' import { HostAppService, Platform } from '../services/hostApp.service'
@@ -9,7 +10,9 @@ import { ConfigService } from '../services/config.service'
import { DockingService } from '../services/docking.service' import { DockingService } from '../services/docking.service'
import { TabRecoveryService } from '../services/tabRecovery.service' import { TabRecoveryService } from '../services/tabRecovery.service'
import { ThemesService } from '../services/themes.service' import { ThemesService } from '../services/themes.service'
import { UpdaterService, Update } from '../services/updater.service'
import { SafeModeModalComponent } from './safeModeModal.component'
import { AppService, IToolbarButton, ToolbarButtonProvider } from '../api' import { AppService, IToolbarButton, ToolbarButtonProvider } from '../api'
@Component({ @Component({
@@ -51,17 +54,20 @@ export class AppRootComponent {
@Input() leftToolbarButtons: IToolbarButton[] @Input() leftToolbarButtons: IToolbarButton[]
@Input() rightToolbarButtons: IToolbarButton[] @Input() rightToolbarButtons: IToolbarButton[]
private logger: Logger private logger: Logger
private appUpdate: Update
constructor ( constructor (
private docking: DockingService, private docking: DockingService,
private electron: ElectronService, private electron: ElectronService,
private tabRecovery: TabRecoveryService, private tabRecovery: TabRecoveryService,
private hotkeys: HotkeysService, private hotkeys: HotkeysService,
private updater: UpdaterService,
public hostApp: HostAppService, public hostApp: HostAppService,
public config: ConfigService, public config: ConfigService,
public app: AppService, public app: AppService,
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[], @Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
log: LogService, log: LogService,
ngbModal: NgbModal,
_themes: ThemesService, _themes: ThemesService,
) { ) {
this.logger = log.create('main') this.logger = log.create('main')
@@ -104,6 +110,14 @@ export class AppRootComponent {
this.hotkeys.globalHotkey.subscribe(() => { this.hotkeys.globalHotkey.subscribe(() => {
this.onGlobalHotkey() this.onGlobalHotkey()
}) })
if (window['safeModeReason']) {
ngbModal.open(SafeModeModalComponent)
}
this.updater.check().then(update => {
this.appUpdate = update
})
} }
onGlobalHotkey () { onGlobalHotkey () {
@@ -136,6 +150,8 @@ export class AppRootComponent {
if (this.app.tabs.length === 0) { if (this.app.tabs.length === 0) {
this.app.openDefaultTab() this.app.openDefaultTab()
} }
this.app.emitReady()
} }
@HostListener('dragover') @HostListener('dragover')
@@ -148,6 +164,10 @@ export class AppRootComponent {
return false return false
} }
updateApp () {
this.electron.shell.openExternal(this.appUpdate.url)
}
private getToolbarButtons (aboveZero: boolean): IToolbarButton[] { private getToolbarButtons (aboveZero: boolean): IToolbarButton[] {
let buttons: IToolbarButton[] = [] let buttons: IToolbarButton[] = []
this.toolbarButtonProviders.forEach((provider) => { this.toolbarButtonProviders.forEach((provider) => {

View File

@@ -0,0 +1,7 @@
.modal-body
.alert.alert-danger Terminus could not start with your plugins, so all third party plugins have been disabled in this session. The error was:
pre {{error}}
.modal-footer
button.btn.btn-outline-primary((click)='close()') Close

View File

@@ -0,0 +1,19 @@
import { Component, Input } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
@Component({
template: require('./safeModeModal.component.pug'),
})
export class SafeModeModalComponent {
@Input() error: Error
constructor (
public modalInstance: NgbActiveModal,
) {
this.error = window['safeModeReason']
}
close () {
this.modalInstance.dismiss()
}
}

View File

@@ -1,28 +1,15 @@
div div
.terminus-logo .terminus-logo
.part(style='transform: rotateZ(0deg)')
div
.part(style='transform: rotateZ(51deg)')
div
.part(style='transform: rotateZ(102deg)')
div
.part(style='transform: rotateZ(154deg)')
div
.part(style='transform: rotateZ(205deg)')
div
.part(style='transform: rotateZ(257deg)')
div
.part(style='transform: rotateZ(308deg)')
div
h1.terminus-title Terminus h1.terminus-title Terminus
span.text-muted α sup α
button.btn.btn-primary.btn-lg.btn-block( .list-group
*ngFor='let button of getButtons()', a.list-group-item.list-group-item-action(
(click)='button.click()', *ngFor='let button of getButtons()',
) (click)='button.click()',
i.fa([class]='"fa fa-" + button.icon') )
span {{button.title}} i([class]='"fa fa-fw fa-" + button.icon')
span {{button.title}}
footer footer
.pull-right .pull-right

View File

@@ -24,6 +24,6 @@ footer {
background: rgba(0,0,0,.5); background: rgba(0,0,0,.5);
} }
button { a, button {
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
} }

View File

@@ -1,3 +1,3 @@
.index {{index + 1}} .index {{index + 1}}
.name([title]='tab.customTitle || tab.title') {{tab.customTitle || tab.title}} .name([title]='tab.customTitle || tab.title') {{tab.customTitle || tab.title}}
button((click)='closeClicked.emit()') &times; button((click)='app.closeTab(tab, true)') &times;

View File

@@ -1,7 +1,6 @@
$tabs-height: 36px; $tabs-height: 36px;
:host { :host {
line-height: $tabs-height - 2px;
cursor: pointer; cursor: pointer;
flex: 1000 1 200px; flex: 1000 1 200px;
@@ -24,9 +23,9 @@ $tabs-height: 36px;
margin-left: 10px; margin-left: 10px;
width: 20px; width: 20px;
border-radius: 10px; border-radius: 10px;
line-height: 35px;
text-align: center; text-align: center;
transition: 0.25s all; transition: 0.25s all;
align-self: center;
} }
.name { .name {
@@ -36,6 +35,7 @@ $tabs-height: 36px;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
min-width: 0; min-width: 0;
align-self: center;
} }
button { button {
@@ -49,7 +49,7 @@ $tabs-height: 36px;
height: $button-size; height: $button-size;
border-radius: $button-size / 2; border-radius: $button-size / 2;
line-height: $button-size * 0.87; line-height: $button-size * 0.87;
margin-top: ($tabs-height - $button-size) * 0.5; align-self: center;
margin-right: 10px; margin-right: 10px;
text-align: center; text-align: center;

View File

@@ -1,7 +1,9 @@
import { Component, Input, Output, EventEmitter, HostBinding, HostListener } from '@angular/core' import { Component, Input, HostBinding, HostListener, NgZone } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { BaseTabComponent } from './baseTab.component' import { BaseTabComponent } from './baseTab.component'
import { RenameTabModalComponent } from './renameTabModal.component' import { RenameTabModalComponent } from './renameTabModal.component'
import { ElectronService } from '../services/electron.service'
import { AppService } from '../services/app.service'
@Component({ @Component({
selector: 'tab-header', selector: 'tab-header',
@@ -13,11 +15,55 @@ export class TabHeaderComponent {
@Input() @HostBinding('class.active') active: boolean @Input() @HostBinding('class.active') active: boolean
@Input() @HostBinding('class.has-activity') hasActivity: boolean @Input() @HostBinding('class.has-activity') hasActivity: boolean
@Input() tab: BaseTabComponent @Input() tab: BaseTabComponent
@Output() closeClicked = new EventEmitter() private contextMenu: any
constructor ( constructor (
zone: NgZone,
electron: ElectronService,
public app: AppService,
private ngbModal: NgbModal, private ngbModal: NgbModal,
) { } ) {
this.contextMenu = electron.remote.Menu.buildFromTemplate([
{
label: 'Close',
click: () => {
zone.run(() => {
app.closeTab(this.tab, true)
})
}
},
{
label: 'Close other tabs',
click: () => {
zone.run(() => {
for (let tab of app.tabs.filter(x => x !== this.tab)) {
app.closeTab(tab, true)
}
})
}
},
{
label: 'Close tabs to the right',
click: () => {
zone.run(() => {
for (let tab of app.tabs.slice(app.tabs.indexOf(this.tab) + 1)) {
app.closeTab(tab, true)
}
})
}
},
{
label: 'Close tabs to the left',
click: () => {
zone.run(() => {
for (let tab of app.tabs.slice(0, app.tabs.indexOf(this.tab))) {
app.closeTab(tab, true)
}
})
}
},
])
}
@HostListener('dblclick') onDoubleClick (): void { @HostListener('dblclick') onDoubleClick (): void {
let modal = this.ngbModal.open(RenameTabModalComponent) let modal = this.ngbModal.open(RenameTabModalComponent)
@@ -29,7 +75,15 @@ export class TabHeaderComponent {
@HostListener('auxclick', ['$event']) onAuxClick ($event: MouseEvent): void { @HostListener('auxclick', ['$event']) onAuxClick ($event: MouseEvent): void {
if ($event.which === 2) { if ($event.which === 2) {
this.closeClicked.emit() this.app.closeTab(this.tab, true)
}
if ($event.which === 3) {
this.contextMenu.popup({
x: $event.pageX,
y: $event.pageY,
async: true,
})
event.preventDefault()
} }
} }
} }

View File

@@ -14,9 +14,11 @@ import { HotkeysService, AppHotkeyProvider } from './services/hotkeys.service'
import { DockingService } from './services/docking.service' import { DockingService } from './services/docking.service'
import { TabRecoveryService } from './services/tabRecovery.service' import { TabRecoveryService } from './services/tabRecovery.service'
import { ThemesService } from './services/themes.service' import { ThemesService } from './services/themes.service'
import { UpdaterService } from './services/updater.service'
import { AppRootComponent } from './components/appRoot.component' import { AppRootComponent } from './components/appRoot.component'
import { TabBodyComponent } from './components/tabBody.component' import { TabBodyComponent } from './components/tabBody.component'
import { SafeModeModalComponent } from './components/safeModeModal.component'
import { StartPageComponent } from './components/startPage.component' import { StartPageComponent } from './components/startPage.component'
import { TabHeaderComponent } from './components/tabHeader.component' import { TabHeaderComponent } from './components/tabHeader.component'
import { TitleBarComponent } from './components/titleBar.component' import { TitleBarComponent } from './components/titleBar.component'
@@ -27,7 +29,7 @@ import { HotkeyProvider } from './api/hotkeyProvider'
import { ConfigProvider } from './api/configProvider' import { ConfigProvider } from './api/configProvider'
import { Theme } from './api/theme' import { Theme } from './api/theme'
import { StandardTheme } from './theme' import { StandardTheme, StandardCompactTheme } from './theme'
import { CoreConfigProvider } from './config' import { CoreConfigProvider } from './config'
import 'perfect-scrollbar/dist/css/perfect-scrollbar.css' import 'perfect-scrollbar/dist/css/perfect-scrollbar.css'
@@ -42,8 +44,10 @@ const PROVIDERS = [
LogService, LogService,
TabRecoveryService, TabRecoveryService,
ThemesService, ThemesService,
UpdaterService,
{ provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true }, { provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true },
{ provide: Theme, useClass: StandardTheme, multi: true }, { provide: Theme, useClass: StandardTheme, multi: true },
{ provide: Theme, useClass: StandardCompactTheme, multi: true },
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true }, { provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
] ]
@@ -52,7 +56,7 @@ const PROVIDERS = [
BrowserModule, BrowserModule,
BrowserAnimationsModule, BrowserAnimationsModule,
FormsModule, FormsModule,
NgbModule, NgbModule.forRoot(),
PerfectScrollbarModule.forRoot({ PerfectScrollbarModule.forRoot({
suppressScrollX: true, suppressScrollX: true,
}), }),
@@ -65,9 +69,11 @@ const PROVIDERS = [
TitleBarComponent, TitleBarComponent,
WindowControlsComponent, WindowControlsComponent,
RenameTabModalComponent, RenameTabModalComponent,
SafeModeModalComponent,
], ],
entryComponents: [ entryComponents: [
RenameTabModalComponent, RenameTabModalComponent,
SafeModeModalComponent,
] ]
}) })
export default class AppModule { export default class AppModule {

View File

@@ -1,4 +1,4 @@
import { Subject } from 'rxjs' import { Subject, AsyncSubject } from 'rxjs'
import { Injectable, ComponentFactoryResolver, Injector, Optional } from '@angular/core' import { Injectable, ComponentFactoryResolver, Injector, Optional } from '@angular/core'
import { DefaultTabProvider } from '../api/defaultTabProvider' import { DefaultTabProvider } from '../api/defaultTabProvider'
import { BaseTabComponent } from '../components/baseTab.component' import { BaseTabComponent } from '../components/baseTab.component'
@@ -12,7 +12,8 @@ export class AppService {
activeTab: BaseTabComponent activeTab: BaseTabComponent
lastTabIndex = 0 lastTabIndex = 0
logger: Logger logger: Logger
tabsChanged$ = new Subject() tabsChanged$ = new Subject<void>()
ready$ = new AsyncSubject<void>()
constructor ( constructor (
private componentFactoryResolver: ComponentFactoryResolver, private componentFactoryResolver: ComponentFactoryResolver,
@@ -97,4 +98,9 @@ export class AppService {
} }
this.tabsChanged$.next() this.tabsChanged$.next()
} }
emitReady () {
this.ready$.next(null)
this.ready$.complete()
}
} }

View File

@@ -38,7 +38,7 @@ export class ConfigProxy {
{ {
enumerable: true, enumerable: true,
configurable: false, configurable: false,
get: () => real[key] || defaults[key], get: () => (real[key] !== undefined) ? real[key] : defaults[key],
set: (value) => { set: (value) => {
real[key] = value real[key] = value
} }

View File

@@ -14,7 +14,10 @@ export class DockingService {
private electron: ElectronService, private electron: ElectronService,
private config: ConfigService, private config: ConfigService,
private hostApp: HostAppService, private hostApp: HostAppService,
) {} ) {
electron.screen.on('display-removed', () => this.repositionWindow())
electron.screen.on('display-metrics-changed', () => this.repositionWindow())
}
dock () { dock () {
let display = this.electron.screen.getAllDisplays() let display = this.electron.screen.getAllDisplays()
@@ -71,4 +74,20 @@ export class DockingService {
} }
}) })
} }
getWindow () {
return this.electron.app.window
}
repositionWindow () {
let [x, y] = this.getWindow().getPosition()
for (let screen of this.electron.screen.getAllDisplays()) {
let bounds = screen.bounds
if (x >= bounds.x && x <= bounds.x + bounds.width && y >= bounds.y && y <= bounds.y + bounds.height) {
return
}
}
let screen = this.electron.screen.getPrimaryDisplay()
this.getWindow().setPosition(screen.bounds.x, screen.bounds.y)
}
} }

View File

@@ -15,13 +15,13 @@ export class ElectronService {
constructor () { constructor () {
this.electron = require('electron') this.electron = require('electron')
this.remote = this.electron.remote this.remote = this.electron.remote
this.app = this.electron.remote.app this.app = this.remote.app
this.screen = this.electron.remote.screen this.screen = this.remote.screen
this.dialog = this.electron.remote.dialog this.dialog = this.remote.dialog
this.shell = this.electron.shell this.shell = this.electron.shell
this.clipboard = this.electron.clipboard this.clipboard = this.electron.clipboard
this.ipcRenderer = this.electron.ipcRenderer this.ipcRenderer = this.electron.ipcRenderer
this.globalShortcut = this.electron.remote.globalShortcut this.globalShortcut = this.remote.globalShortcut
} }
remoteRequire (name: string): any { remoteRequire (name: string): any {

View File

@@ -0,0 +1,36 @@
import axios from 'axios'
import { Injectable } from '@angular/core'
import { Logger, LogService } from './log.service'
import { ElectronService } from './electron.service'
const UPDATES_URL = 'https://api.github.com/repos/eugeny/terminus/releases/latest'
export interface Update {
version: string
url: string
}
@Injectable()
export class UpdaterService {
private logger: Logger
constructor (
log: LogService,
private electron: ElectronService,
) {
this.logger = log.create('updater')
}
async check (): Promise<Update> {
this.logger.debug('Checking for updates')
let response = await axios.get(UPDATES_URL)
let data = response.data
let version = data.tag_name.substring(1)
if (this.electron.app.getVersion() !== version) {
this.logger.info('Update available:', version)
return { version, url: data.html_url }
}
this.logger.info('No updates')
return null
}
}

View File

@@ -0,0 +1,15 @@
@import './theme.scss';
app-root {
.tab-bar {
height: 27px !important;
.btn-tab-bar {
line-height: 29px !important;
}
}
terminaltab .content {
margin: 5px !important;
}
}

View File

@@ -71,7 +71,18 @@ $dropdown-link-disabled-color: #333;
$dropdown-header-color: #333; $dropdown-header-color: #333;
$list-group-color: $body-color; $list-group-color: $body-color;
$list-group-bg: $body-bg2; $list-group-bg: rgba(255,255,255,.05);
$list-group-border-color: rgba(255,255,255,.1);
$list-group-hover-bg: rgba(255,255,255,.1);
$list-group-link-active-bg: rgba(255,255,255,.2);
$pre-bg: $dropdown-bg;
$pre-color: $dropdown-link-color;
$alert-danger-bg: $body-bg2;
$alert-danger-text: $red;
$alert-danger-border: $red;
@import '~bootstrap/scss/bootstrap.scss'; @import '~bootstrap/scss/bootstrap.scss';
@@ -120,6 +131,7 @@ app-root {
background: $body-bg2; background: $body-bg2;
border-left: 1px solid transparent; border-left: 1px solid transparent;
border-right: 1px solid transparent; border-right: 1px solid transparent;
border-top: 1px solid transparent;
.index { .index {
color: #555; color: #555;
@@ -148,10 +160,12 @@ app-root {
tab-header { tab-header {
border-top: 1px solid transparent; border-top: 1px solid transparent;
border-bottom: 1px solid $border-color;
margin-bottom: -1px;
&.active { &.active {
border-top: 1px solid $teal; border-top: 1px solid $teal;
margin-bottom: -1px; border-bottom-color: transparent;
} }
&.has-activity:not(.active) { &.has-activity:not(.active) {
@@ -165,6 +179,8 @@ app-root {
tab-header { tab-header {
border-bottom: 1px solid transparent; border-bottom: 1px solid transparent;
border-top: 1px solid $border-color;
margin-top: -1px;
&.active { &.active {
border-bottom: 1px solid $teal; border-bottom: 1px solid $teal;
@@ -271,12 +287,6 @@ hotkey-input-modal {
} }
} }
start-page {
.terminus-title {
color: $blue;
}
}
.form-group label { .form-group label {
margin-bottom: 2px; margin-bottom: 2px;
} }
@@ -314,3 +324,11 @@ ngb-tabset .tab-content {
.input-group > select.form-control { .input-group > select.form-control {
flex-direction: row; flex-direction: row;
} }
.list-group-item {
transition: 0.25s background;
i + * {
margin-left: 10px;
}
}

View File

@@ -7,3 +7,10 @@ export class StandardTheme extends Theme {
css = require('./theme.scss') css = require('./theme.scss')
terminalBackground = '#1D272D' terminalBackground = '#1D272D'
} }
@Injectable()
export class StandardCompactTheme extends Theme {
name = 'Compact'
css = require('./theme.compact.scss')
terminalBackground = '#1D272D'
}

216
terminus-core/yarn.lock Normal file
View File

@@ -0,0 +1,216 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/js-yaml@^3.9.0":
version "3.9.1"
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.9.1.tgz#2f3c142771bb345829ce690c5838760b6b9ba553"
"@types/node@^7.0.37":
version "7.0.43"
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c"
"@types/webpack-env@^1.13.0":
version "1.13.1"
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.1.tgz#b45c222e24301bd006e3edfc762cc6b51bda236a"
argparse@^1.0.7:
version "1.0.9"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
dependencies:
sprintf-js "~1.0.2"
axios@0.16.2:
version "0.16.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.2.tgz#ba4f92f17167dfbab40983785454b9ac149c3c6d"
dependencies:
follow-redirects "^1.2.3"
is-buffer "^1.1.5"
bluebird-lst@^1.0.2, bluebird-lst@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/bluebird-lst/-/bluebird-lst-1.0.3.tgz#cc56c18660eff0a0b86e2c33d1659618f7005158"
dependencies:
bluebird "^3.5.0"
bluebird@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c"
bootstrap@4.0.0-alpha.6:
version "4.0.0-alpha.6"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.0.0-alpha.6.tgz#4f54dd33ac0deac3b28407bc2df7ec608869c9c8"
dependencies:
jquery ">=1.9.1"
tether "^1.4.0"
core-js@^2.4.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b"
debug@^2.4.5:
version "2.6.8"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
dependencies:
ms "2.0.0"
debug@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.0.1.tgz#0564c612b521dc92d9f2988f0549e34f9c98db64"
dependencies:
ms "2.0.0"
deepmerge@^1.5.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.1.tgz#c053bf06fd7276f1994f70c09a0760cb61a56237"
electron-builder-http@~19.27.5:
version "19.27.5"
resolved "https://registry.yarnpkg.com/electron-builder-http/-/electron-builder-http-19.27.5.tgz#800865df2e618ffab9e5b3b895c15b4ce7fd7f17"
dependencies:
bluebird-lst "^1.0.3"
debug "^3.0.1"
fs-extra-p "^4.4.0"
electron-is-dev@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/electron-is-dev/-/electron-is-dev-0.3.0.tgz#14e6fda5c68e9e4ecbeff9ccf037cbd7c05c5afe"
electron-updater@^2.8.9:
version "2.8.9"
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-2.8.9.tgz#e2525dcbd7c27ff173bdfd2e87056d67310e2555"
dependencies:
bluebird-lst "^1.0.3"
debug "^3.0.1"
electron-builder-http "~19.27.5"
electron-is-dev "^0.3.0"
fs-extra-p "^4.4.0"
js-yaml "^3.9.1"
lazy-val "^1.0.2"
lodash.isequal "^4.5.0"
semver "^5.4.1"
source-map-support "^0.4.16"
uuid-1345 "^0.99.6"
xelement "^1.0.16"
esprima@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
follow-redirects@^1.2.3:
version "1.2.4"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.4.tgz#355e8f4d16876b43f577b0d5ce2668b9723214ea"
dependencies:
debug "^2.4.5"
fs-extra-p@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/fs-extra-p/-/fs-extra-p-4.4.0.tgz#729c601c4f4c701328921adc7cfe9b236f100660"
dependencies:
bluebird-lst "^1.0.2"
fs-extra "^4.0.0"
fs-extra@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.1.tgz#7fc0c6c8957f983f57f306a24e5b9ddd8d0dd880"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^3.0.0"
universalify "^0.1.0"
graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
is-buffer@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
jquery@>=1.9.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787"
js-yaml@^3.9.0, js-yaml@^3.9.1:
version "3.9.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.1.tgz#08775cebdfdd359209f0d2acd383c8f86a6904a0"
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
jsonfile@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66"
optionalDependencies:
graceful-fs "^4.1.6"
lazy-val@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.2.tgz#d9b07fb1fce54cbc99b3c611de431b83249369b6"
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
macaddress@^0.2.7:
version "0.2.8"
resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
ngx-perfect-scrollbar@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/ngx-perfect-scrollbar/-/ngx-perfect-scrollbar-4.0.0.tgz#f1e19449fa97d7f16e1ceb1fe1739e4bb646bebe"
dependencies:
perfect-scrollbar "~0.6.0"
perfect-scrollbar@~0.6.0:
version "0.6.16"
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-0.6.16.tgz#b1d61a5245cf3962bb9a8407a3fc669d923212fc"
sax@^1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
semver@^5.4.1:
version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
source-map-support@^0.4.16:
version "0.4.17"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.17.tgz#6f2150553e6375375d0ccb3180502b78c18ba430"
dependencies:
source-map "^0.5.6"
source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
tether@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/tether/-/tether-1.4.0.tgz#0f9fa171f75bf58485d8149e94799d7ae74d1c1a"
typescript@^2.4.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.2.tgz#038a95f7d9bbb420b1bf35ba31d4c5c1dd3ffe34"
universalify@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
uuid-1345@^0.99.6:
version "0.99.6"
resolved "https://registry.yarnpkg.com/uuid-1345/-/uuid-1345-0.99.6.tgz#b1270ae015a7721c7adec6c46ec169c6098aed40"
dependencies:
macaddress "^0.2.7"
xelement@^1.0.16:
version "1.0.16"
resolved "https://registry.yarnpkg.com/xelement/-/xelement-1.0.16.tgz#900bb46c20fc2dffadff778a9d2dc36699d0ff7e"
dependencies:
sax "^1.2.1"

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-plugin-manager", "name": "terminus-plugin-manager",
"version": "1.0.0-alpha.23-8-gcdc7daf", "version": "1.0.0-alpha.24",
"description": "Terminus' plugin manager", "description": "Terminus' plugin manager",
"keywords": [ "keywords": [
"terminus-plugin" "terminus-plugin"

View File

@@ -14,7 +14,7 @@ h3 Installed
.d-flex.w-100 .d-flex.w-100
.mr-auto.d-flex.flex-column .mr-auto.d-flex.flex-column
strong {{plugin.name}} strong {{plugin.name}}
small.text-muted.mb-0 {{plugin.description}} small.text-muted.mb-0((click)='showPluginInfo(plugin)') {{plugin.description}}
.d-flex.flex-column.align-items-end.mr-3 .d-flex.flex-column.align-items-end.mr-3
div {{plugin.version}} div {{plugin.version}}
small.text-muted {{plugin.author}} small.text-muted {{plugin.author}}
@@ -32,7 +32,8 @@ h3 Installed
.d-flex.w-100 .d-flex.w-100
.mr-auto.d-flex.flex-column .mr-auto.d-flex.flex-column
strong {{plugin.name}} strong {{plugin.name}}
small.text-muted.mb-0 {{plugin.description}} a.text-muted.mb-0((click)='showPluginInfo(plugin)')
small {{plugin.description}}
.d-flex.flex-column.align-items-end.mr-3 .d-flex.flex-column.align-items-end.mr-3
div {{plugin.version}} div {{plugin.version}}
small.text-muted {{plugin.author}} small.text-muted {{plugin.author}}
@@ -77,7 +78,8 @@ div(*ngIf='npmInstalled')
.d-flex.w-100 .d-flex.w-100
.mr-auto.d-flex.flex-column .mr-auto.d-flex.flex-column
strong {{plugin.name}} strong {{plugin.name}}
small.text-muted.mb-0 {{plugin.description}} a.text-muted.mb-0((click)='showPluginInfo(plugin)')
small {{plugin.description}}
.d-flex.flex-column.align-items-end.mr-3 .d-flex.flex-column.align-items-end.mr-3
div {{plugin.version}} div {{plugin.version}}
small.text-muted {{plugin.author}} small.text-muted {{plugin.author}}

View File

@@ -2,7 +2,7 @@ import { BehaviorSubject, Observable } from 'rxjs'
import * as semver from 'semver' import * as semver from 'semver'
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { ConfigService, HostAppService } from 'terminus-core' import { ConfigService, HostAppService, ElectronService } from 'terminus-core'
import { IPluginInfo, PluginManagerService } from '../services/pluginManager.service' import { IPluginInfo, PluginManagerService } from '../services/pluginManager.service'
enum BusyState { Installing, Uninstalling } enum BusyState { Installing, Uninstalling }
@@ -24,6 +24,7 @@ export class PluginsSettingsTabComponent {
@Input() npmMissing = false @Input() npmMissing = false
constructor ( constructor (
private electron: ElectronService,
private config: ConfigService, private config: ConfigService,
private hostApp: HostAppService, private hostApp: HostAppService,
public pluginManager: PluginManagerService public pluginManager: PluginManagerService
@@ -100,4 +101,8 @@ export class PluginsSettingsTabComponent {
async upgradePlugin (plugin: IPluginInfo): Promise<void> { async upgradePlugin (plugin: IPluginInfo): Promise<void> {
return this.installPlugin(this.knownUpgrades[plugin.name]) return this.installPlugin(this.knownUpgrades[plugin.name])
} }
showPluginInfo (plugin: IPluginInfo) {
this.electron.shell.openExternal('https://www.npmjs.com/package/' + plugin.packageName)
}
} }

View File

@@ -71,7 +71,6 @@ export class PluginManagerService {
.fromPromise( .fromPromise(
axios.get(`https://www.npmjs.com/-/search?text=keywords:${KEYWORD}+${encodeURIComponent(query || '')}&from=0&size=1000`) 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 => ({ .map(response => response.data.objects.map(item => ({
name: item.package.name.substring(NAME_PREFIX.length), name: item.package.name.substring(NAME_PREFIX.length),
packageName: item.package.name, packageName: item.package.name,
@@ -85,8 +84,7 @@ export class PluginManagerService {
} }
async installPlugin (plugin: IPluginInfo) { async installPlugin (plugin: IPluginInfo) {
let result = await exec(`${this.npmPath} --prefix "${this.userPluginsPath}" install ${plugin.packageName}@${plugin.version}`) 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 = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
this.installedPlugins.push(plugin) this.installedPlugins.push(plugin)
} }

View File

@@ -39,7 +39,6 @@ module.exports = {
'fs', 'fs',
'font-manager', 'font-manager',
'path', 'path',
'node-pty',
'mz/fs', 'mz/fs',
'mz/child_process', 'mz/child_process',
'winreg', 'winreg',

View File

@@ -0,0 +1,853 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@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/semver@^5.3.32":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.4.0.tgz#f3658535af7f1f502acd6da7daf405ffeb1f7ee4"
"@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"
alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
ansi-styles@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
dependencies:
color-convert "^1.9.0"
any-promise@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
argparse@^1.0.7:
version "1.0.9"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
dependencies:
sprintf-js "~1.0.2"
autoprefixer@^6.3.1:
version "6.7.7"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
dependencies:
browserslist "^1.7.6"
caniuse-db "^1.0.30000634"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss "^5.2.16"
postcss-value-parser "^3.2.3"
axios@^0.16.2:
version "0.16.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.2.tgz#ba4f92f17167dfbab40983785454b9ac149c3c6d"
dependencies:
follow-redirects "^1.2.3"
is-buffer "^1.1.5"
babel-code-frame@^6.11.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
dependencies:
chalk "^1.1.3"
esutils "^2.0.2"
js-tokens "^3.0.2"
balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
big.js@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
version "1.7.7"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
dependencies:
caniuse-db "^1.0.30000639"
electron-to-chromium "^1.2.7"
caniuse-api@^1.5.2:
version "1.6.1"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
dependencies:
browserslist "^1.3.6"
caniuse-db "^1.0.30000529"
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000726"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000726.tgz#9bb742f8d026a62df873bc03c06843d2255b60d7"
chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
ansi-styles "^2.2.1"
escape-string-regexp "^1.0.2"
has-ansi "^2.0.0"
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
dependencies:
ansi-styles "^3.1.0"
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"
clap@^1.0.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.0.tgz#59c90fe3e137104746ff19469a27a634ff68c857"
dependencies:
chalk "^1.1.3"
clone@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
coa@~1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd"
dependencies:
q "^1.1.2"
color-convert@^1.3.0, color-convert@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
dependencies:
color-name "^1.1.1"
color-name@^1.0.0, color-name@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
color-string@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991"
dependencies:
color-name "^1.0.0"
color@^0.11.0:
version "0.11.4"
resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
dependencies:
clone "^1.0.2"
color-convert "^1.3.0"
color-string "^0.3.0"
colormin@^1.0.5:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133"
dependencies:
color "^0.11.0"
css-color-names "0.0.4"
has "^1.0.1"
colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
css-color-names@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
css-loader@^0.28.0:
version "0.28.7"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.7.tgz#5f2ee989dd32edd907717f953317656160999c1b"
dependencies:
babel-code-frame "^6.11.0"
css-selector-tokenizer "^0.7.0"
cssnano ">=2.6.1 <4"
icss-utils "^2.1.0"
loader-utils "^1.0.2"
lodash.camelcase "^4.3.0"
object-assign "^4.0.1"
postcss "^5.0.6"
postcss-modules-extract-imports "^1.0.0"
postcss-modules-local-by-default "^1.0.1"
postcss-modules-scope "^1.0.0"
postcss-modules-values "^1.1.0"
postcss-value-parser "^3.3.0"
source-list-map "^2.0.0"
css-selector-tokenizer@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86"
dependencies:
cssesc "^0.1.0"
fastparse "^1.1.1"
regexpu-core "^1.0.0"
cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
"cssnano@>=2.6.1 <4":
version "3.10.0"
resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
dependencies:
autoprefixer "^6.3.1"
decamelize "^1.1.2"
defined "^1.0.0"
has "^1.0.1"
object-assign "^4.0.1"
postcss "^5.0.14"
postcss-calc "^5.2.0"
postcss-colormin "^2.1.8"
postcss-convert-values "^2.3.4"
postcss-discard-comments "^2.0.4"
postcss-discard-duplicates "^2.0.1"
postcss-discard-empty "^2.0.1"
postcss-discard-overridden "^0.1.1"
postcss-discard-unused "^2.2.1"
postcss-filter-plugins "^2.0.0"
postcss-merge-idents "^2.1.5"
postcss-merge-longhand "^2.0.1"
postcss-merge-rules "^2.0.3"
postcss-minify-font-values "^1.0.2"
postcss-minify-gradients "^1.0.1"
postcss-minify-params "^1.0.4"
postcss-minify-selectors "^2.0.4"
postcss-normalize-charset "^1.1.0"
postcss-normalize-url "^3.0.7"
postcss-ordered-values "^2.1.0"
postcss-reduce-idents "^2.2.2"
postcss-reduce-initial "^1.0.0"
postcss-reduce-transforms "^1.0.3"
postcss-svgo "^2.1.1"
postcss-unique-selectors "^2.0.2"
postcss-value-parser "^3.2.3"
postcss-zindex "^2.0.1"
csso@~2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85"
dependencies:
clap "^1.0.9"
source-map "^0.5.3"
debug@^2.4.5:
version "2.6.8"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
dependencies:
ms "2.0.0"
decamelize@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
electron-to-chromium@^1.2.7:
version "1.3.21"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.21.tgz#a967ebdcfe8ed0083fc244d1894022a8e8113ea2"
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
esprima@^2.6.0:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
follow-redirects@^1.2.3:
version "1.2.4"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.4.tgz#355e8f4d16876b43f577b0d5ce2668b9723214ea"
dependencies:
debug "^2.4.5"
function-bind@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
dependencies:
ansi-regex "^2.0.0"
has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
has@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28"
dependencies:
function-bind "^1.0.2"
html-comment-regex@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
icss-utils@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962"
dependencies:
postcss "^6.0.1"
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
is-absolute-url@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
is-buffer@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
is-plain-obj@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
is-svg@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
dependencies:
html-comment-regex "^1.1.0"
js-base64@^2.1.9:
version "2.1.9"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce"
js-tokens@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
js-yaml@~3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
dependencies:
argparse "^1.0.7"
esprima "^2.6.0"
jsesc@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
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"
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
macaddress@^0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"
math-expression-evaluator@^1.2.14:
version "1.2.17"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
minimist "0.0.8"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
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"
ngx-pipes@^1.6.1:
version "1.6.5"
resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-1.6.5.tgz#7dfe7bf1425b2e661ecde0e8a419e82be575dfa1"
normalize-range@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
normalize-url@^1.4.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c"
dependencies:
object-assign "^4.0.1"
prepend-http "^1.0.0"
query-string "^4.1.0"
sort-keys "^1.0.0"
num2fraction@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
object-assign@^4.0.1, object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
postcss-calc@^5.2.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
dependencies:
postcss "^5.0.2"
postcss-message-helpers "^2.0.0"
reduce-css-calc "^1.2.6"
postcss-colormin@^2.1.8:
version "2.2.2"
resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b"
dependencies:
colormin "^1.0.5"
postcss "^5.0.13"
postcss-value-parser "^3.2.3"
postcss-convert-values@^2.3.4:
version "2.6.1"
resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d"
dependencies:
postcss "^5.0.11"
postcss-value-parser "^3.1.2"
postcss-discard-comments@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d"
dependencies:
postcss "^5.0.14"
postcss-discard-duplicates@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932"
dependencies:
postcss "^5.0.4"
postcss-discard-empty@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5"
dependencies:
postcss "^5.0.14"
postcss-discard-overridden@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58"
dependencies:
postcss "^5.0.16"
postcss-discard-unused@^2.2.1:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433"
dependencies:
postcss "^5.0.14"
uniqs "^2.0.0"
postcss-filter-plugins@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c"
dependencies:
postcss "^5.0.4"
uniqid "^4.0.0"
postcss-merge-idents@^2.1.5:
version "2.1.7"
resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
dependencies:
has "^1.0.1"
postcss "^5.0.10"
postcss-value-parser "^3.1.1"
postcss-merge-longhand@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658"
dependencies:
postcss "^5.0.4"
postcss-merge-rules@^2.0.3:
version "2.1.2"
resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721"
dependencies:
browserslist "^1.5.2"
caniuse-api "^1.5.2"
postcss "^5.0.4"
postcss-selector-parser "^2.2.2"
vendors "^1.0.0"
postcss-message-helpers@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e"
postcss-minify-font-values@^1.0.2:
version "1.0.5"
resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69"
dependencies:
object-assign "^4.0.1"
postcss "^5.0.4"
postcss-value-parser "^3.0.2"
postcss-minify-gradients@^1.0.1:
version "1.0.5"
resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1"
dependencies:
postcss "^5.0.12"
postcss-value-parser "^3.3.0"
postcss-minify-params@^1.0.4:
version "1.2.2"
resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3"
dependencies:
alphanum-sort "^1.0.1"
postcss "^5.0.2"
postcss-value-parser "^3.0.2"
uniqs "^2.0.0"
postcss-minify-selectors@^2.0.4:
version "2.1.1"
resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf"
dependencies:
alphanum-sort "^1.0.2"
has "^1.0.1"
postcss "^5.0.14"
postcss-selector-parser "^2.0.0"
postcss-modules-extract-imports@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85"
dependencies:
postcss "^6.0.1"
postcss-modules-local-by-default@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
dependencies:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
postcss-modules-scope@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
dependencies:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
postcss-modules-values@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20"
dependencies:
icss-replace-symbols "^1.1.0"
postcss "^6.0.1"
postcss-normalize-charset@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1"
dependencies:
postcss "^5.0.5"
postcss-normalize-url@^3.0.7:
version "3.0.8"
resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222"
dependencies:
is-absolute-url "^2.0.0"
normalize-url "^1.4.0"
postcss "^5.0.14"
postcss-value-parser "^3.2.3"
postcss-ordered-values@^2.1.0:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d"
dependencies:
postcss "^5.0.4"
postcss-value-parser "^3.0.1"
postcss-reduce-idents@^2.2.2:
version "2.4.0"
resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3"
dependencies:
postcss "^5.0.4"
postcss-value-parser "^3.0.2"
postcss-reduce-initial@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea"
dependencies:
postcss "^5.0.4"
postcss-reduce-transforms@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1"
dependencies:
has "^1.0.1"
postcss "^5.0.8"
postcss-value-parser "^3.0.1"
postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90"
dependencies:
flatten "^1.0.2"
indexes-of "^1.0.1"
uniq "^1.0.1"
postcss-svgo@^2.1.1:
version "2.1.6"
resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d"
dependencies:
is-svg "^2.0.0"
postcss "^5.0.14"
postcss-value-parser "^3.2.3"
svgo "^0.7.0"
postcss-unique-selectors@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d"
dependencies:
alphanum-sort "^1.0.1"
postcss "^5.0.4"
uniqs "^2.0.0"
postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
postcss-zindex@^2.0.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22"
dependencies:
has "^1.0.1"
postcss "^5.0.4"
uniqs "^2.0.0"
postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16:
version "5.2.17"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.17.tgz#cf4f597b864d65c8a492b2eabe9d706c879c388b"
dependencies:
chalk "^1.1.3"
js-base64 "^2.1.9"
source-map "^0.5.6"
supports-color "^3.2.3"
postcss@^6.0.1:
version "6.0.11"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.11.tgz#f48db210b1d37a7f7ab6499b7a54982997ab6f72"
dependencies:
chalk "^2.1.0"
source-map "^0.5.7"
supports-color "^4.4.0"
prepend-http@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
q@^1.1.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1"
query-string@^4.1.0:
version "4.3.4"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
dependencies:
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"
reduce-css-calc@^1.2.6:
version "1.3.0"
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
dependencies:
balanced-match "^0.4.2"
math-expression-evaluator "^1.2.14"
reduce-function-call "^1.0.1"
reduce-function-call@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99"
dependencies:
balanced-match "^0.4.2"
regenerate@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
regexpu-core@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
dependencies:
regenerate "^1.2.1"
regjsgen "^0.2.0"
regjsparser "^0.1.4"
regjsgen@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
regjsparser@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
dependencies:
jsesc "~0.5.0"
sax@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
semver@^5.3.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
sort-keys@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
dependencies:
is-plain-obj "^1.0.0"
source-list-map@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085"
source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
strip-ansi@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
dependencies:
ansi-regex "^2.0.0"
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
supports-color@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
dependencies:
has-flag "^1.0.0"
supports-color@^4.0.0, supports-color@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e"
dependencies:
has-flag "^2.0.0"
svgo@^0.7.0:
version "0.7.2"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
dependencies:
coa "~1.0.1"
colors "~1.1.2"
csso "~2.3.1"
js-yaml "~3.7.0"
mkdirp "~0.5.1"
sax "~1.2.1"
whet.extend "~0.9.9"
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"
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
uniqid@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1"
dependencies:
macaddress "^0.2.8"
uniqs@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
vendors@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22"
whet.extend@~0.9.9:
version "0.9.9"
resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-settings", "name": "terminus-settings",
"version": "1.0.0-alpha.23-8-gcdc7daf", "version": "1.0.0-alpha.24",
"description": "Terminus terminal settings page", "description": "Terminus terminal settings page",
"keywords": [ "keywords": [
"terminus-plugin" "terminus-plugin"

View File

@@ -73,6 +73,7 @@ export class HotkeyInputModalComponent {
} }
ngOnDestroy () { ngOnDestroy () {
this.keySubscription.unsubscribe()
this.hotkeys.clearCurrentKeystrokes() this.hotkeys.clearCurrentKeystrokes()
this.hotkeys.enable() this.hotkeys.enable()
clearInterval(this.keyTimeoutInterval) clearInterval(this.keyTimeoutInterval)

View File

@@ -18,20 +18,22 @@ ngb-tabset.vertical(type='tabs')
.form-group .form-group
label Show tabs label Show tabs
br br
div( .btn-group(
'[(ngModel)]'='config.store.appearance.tabsLocation', '[(ngModel)]'='config.store.appearance.tabsLocation',
(ngModelChange)='config.save()', (ngModelChange)='config.save()',
ngbRadioGroup ngbRadioGroup
) )
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"top"' [value]='"top"'
) )
| On the top | On the top
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"bottom"' [value]='"bottom"'
) )
| At the bottom | At the bottom
@@ -39,26 +41,29 @@ ngb-tabset.vertical(type='tabs')
.form-group .form-group
label Window frame label Window frame
br br
div( .btn-group(
'[(ngModel)]'='config.store.appearance.frame' '[(ngModel)]'='config.store.appearance.frame'
'(ngModelChange)'='config.save(); config.requestRestart()' '(ngModelChange)'='config.save(); config.requestRestart()'
ngbRadioGroup ngbRadioGroup
) )
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"native"' [value]='"native"'
) )
| Native | Native
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"thin"' [value]='"thin"'
) )
| Thin | Thin
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"full"' [value]='"full"'
) )
| Full | Full
@@ -69,38 +74,43 @@ ngb-tabset.vertical(type='tabs')
.form-group .form-group
label Dock the terminal label Dock the terminal
br br
div( .btn-group(
'[(ngModel)]'='config.store.appearance.dock' '[(ngModel)]'='config.store.appearance.dock'
'(ngModelChange)'='config.save(); docking.dock()' '(ngModelChange)'='config.save(); docking.dock()'
ngbRadioGroup ngbRadioGroup
) )
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"off"' [value]='"off"'
) )
| Off | Off
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"top"' [value]='"top"'
) )
| Top | Top
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"left"' [value]='"left"'
) )
| Left | Left
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"right"' [value]='"right"'
) )
| Right | Right
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"bottom"' [value]='"bottom"'
) )
| Bottom | Bottom
@@ -113,15 +123,17 @@ ngb-tabset.vertical(type='tabs')
(ngModelChange)='config.save(); docking.dock()', (ngModelChange)='config.save(); docking.dock()',
ngbRadioGroup ngbRadioGroup
) )
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
value='current' value='current'
) )
| Current | Current
label.btn.btn-secondary(*ngFor='let screen of screens') label.btn.btn-secondary(*ngFor='let screen of screens', ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='screen.id' [value]='screen.id'
) )
| {{screen.name}} | {{screen.name}}

View File

@@ -39,7 +39,6 @@ module.exports = {
externals: [ externals: [
'fs', 'fs',
'path', 'path',
'node-pty',
/^rxjs/, /^rxjs/,
/^@angular/, /^@angular/,
/^@ng-bootstrap/, /^@ng-bootstrap/,

View File

@@ -0,0 +1,19 @@
# 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/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"
ngx-pipes@^1.6.1:
version "1.6.5"
resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-1.6.5.tgz#7dfe7bf1425b2e661ecde0e8a419e82be575dfa1"

View File

@@ -1,6 +1,6 @@
{ {
"name": "terminus-terminal", "name": "terminus-terminal",
"version": "1.0.0-alpha.23-8-gcdc7daf", "version": "1.0.0-alpha.24",
"description": "Terminus' terminal emulation core", "description": "Terminus' terminal emulation core",
"keywords": [ "keywords": [
"terminus-plugin" "terminus-plugin"
@@ -42,7 +42,7 @@
"font-manager": "0.2.2", "font-manager": "0.2.2",
"hterm-umdjs": "1.1.3", "hterm-umdjs": "1.1.3",
"mz": "^2.6.0", "mz": "^2.6.0",
"node-pty": "0.6.8", "node-pty-tmp": "0.7.1",
"ps-node": "^0.1.6", "ps-node": "^0.1.6",
"runes": "^0.4.2", "runes": "^0.4.2",
"winreg": "^1.2.3" "winreg": "^1.2.3"

View File

@@ -1,15 +1,12 @@
import { AsyncSubject } from 'rxjs'
import * as fs from 'mz/fs' import * as fs from 'mz/fs'
import * as path from 'path' import * as path from 'path'
import { Injectable, Inject } from '@angular/core' import { Injectable } from '@angular/core'
import { HotkeysService, ToolbarButtonProvider, IToolbarButton, ConfigService, HostAppService, ElectronService, Logger, LogService } from 'terminus-core' import { HotkeysService, ToolbarButtonProvider, IToolbarButton, ConfigService, HostAppService, ElectronService, Logger, LogService } from 'terminus-core'
import { IShell, ShellProvider } from './api'
import { TerminalService } from './services/terminal.service' import { TerminalService } from './services/terminal.service'
@Injectable() @Injectable()
export class ButtonProvider extends ToolbarButtonProvider { export class ButtonProvider extends ToolbarButtonProvider {
private shells$ = new AsyncSubject<IShell[]>()
private logger: Logger private logger: Logger
constructor ( constructor (
@@ -17,16 +14,11 @@ export class ButtonProvider extends ToolbarButtonProvider {
private config: ConfigService, private config: ConfigService,
log: LogService, log: LogService,
hostApp: HostAppService, hostApp: HostAppService,
@Inject(ShellProvider) shellProviders: ShellProvider[],
electron: ElectronService, electron: ElectronService,
hotkeys: HotkeysService, hotkeys: HotkeysService,
) { ) {
super() super()
this.logger = log.create('newTerminalButton') this.logger = log.create('newTerminalButton')
Promise.all(shellProviders.map(x => x.provide())).then(shellLists => {
this.shells$.next(shellLists.reduce((a, b) => a.concat(b)))
this.shells$.complete()
})
hotkeys.matchedHotkey.subscribe(async (hotkey) => { hotkeys.matchedHotkey.subscribe(async (hotkey) => {
if (hotkey === 'new-tab') { if (hotkey === 'new-tab') {
this.openNewTab() this.openNewTab()
@@ -55,8 +47,8 @@ export class ButtonProvider extends ToolbarButtonProvider {
} }
async openNewTab (cwd?: string): Promise<void> { async openNewTab (cwd?: string): Promise<void> {
let shells = await this.shells$.first().toPromise() let shells = await this.terminal.shells$.first().toPromise()
let shell = shells.find(x => x.id === this.config.store.terminal.shell) || shells[0] let shell = shells.find(x => x.id === this.config.store.terminal.shell)
this.terminal.openTab(shell, cwd) this.terminal.openTab(shell, cwd)
} }

View File

@@ -13,35 +13,39 @@ export class HyperColorSchemes extends TerminalColorSchemeProvider {
let themes: ITerminalColorScheme[] = [] let themes: ITerminalColorScheme[] = []
plugins.forEach(plugin => { plugins.forEach(plugin => {
let module = (global as any).require(path.join(pluginsPath, plugin)) try {
if (module.decorateConfig) { let module = (global as any).require(path.join(pluginsPath, plugin))
let config = module.decorateConfig({}) if (module.decorateConfig) {
if (config.colors) { let config = module.decorateConfig({})
themes.push({ if (config.colors) {
name: plugin, themes.push({
foreground: config.foregroundColor, name: plugin,
background: config.backgroundColor, foreground: config.foregroundColor,
cursor: config.cursorColor, background: config.backgroundColor,
colors: config.colors.black ? [ cursor: config.cursorColor,
config.colors.black, colors: config.colors.black ? [
config.colors.red, config.colors.black,
config.colors.green, config.colors.red,
config.colors.yellow, config.colors.green,
config.colors.blue, config.colors.yellow,
config.colors.magenta, config.colors.blue,
config.colors.cyan, config.colors.magenta,
config.colors.white, config.colors.cyan,
config.colors.lightBlack, config.colors.white,
config.colors.lightRed, config.colors.lightBlack,
config.colors.lightGreen, config.colors.lightRed,
config.colors.lightYellow, config.colors.lightGreen,
config.colors.lightBlue, config.colors.lightYellow,
config.colors.lightMagenta, config.colors.lightBlue,
config.colors.lightCyan, config.colors.lightMagenta,
config.colors.lightWhite, config.colors.lightCyan,
] : config.colors, config.colors.lightWhite,
}) ] : config.colors,
})
}
} }
} catch (err) {
console.debug('Skipping Hyper plugin', plugin, err)
} }
}) })

View File

@@ -178,46 +178,52 @@
.form-group.mr-3 .form-group.mr-3
label Terminal background label Terminal background
br br
div( .btn-group(
'[(ngModel)]'='config.store.terminal.background', '[(ngModel)]'='config.store.terminal.background',
(ngModelChange)='config.save()', (ngModelChange)='config.save()',
ngbRadioGroup ngbRadioGroup
) )
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"theme"' [value]='"theme"'
) )
| From theme | From theme
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"colorScheme"' [value]='"colorScheme"'
) )
| From colors | From colors
.form-group .form-group
label Cursor shape label Cursor shape
br br
div( .btn-group(
[(ngModel)]='config.store.terminal.cursor', [(ngModel)]='config.store.terminal.cursor',
(ngModelChange)='config.save()', (ngModelChange)='config.save()',
ngbRadioGroup ngbRadioGroup
) )
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"block"' [value]='"block"'
) )
| █ | █
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"beam"' [value]='"beam"'
) )
| | | |
label.btn.btn-secondary label.btn.btn-secondary(ngbButtonLabel)
input( input(
type='radio', type='radio',
ngbButton,
[value]='"underline"' [value]='"underline"'
) )
| ▁ | ▁
@@ -230,35 +236,70 @@
) )
option( option(
*ngFor='let shell of shells', *ngFor='let shell of shells',
[ngValue]='shell.command' [ngValue]='shell.id'
) {{shell.name}} ) {{shell.name}}
.form-group .form-group(*ngIf='config.store.terminal.shell == "custom"')
label Terminal bell label Custom shell
br input.form-control(
div( type='text',
'[(ngModel)]'='config.store.terminal.bell', '[(ngModel)]'='config.store.terminal.customShell',
(ngModelChange)='config.save()', (ngModelChange)='config.save()',
ngbRadioGroup
) )
label.btn.btn-secondary
input( .d-flex
type='radio', .form-group.mr-3
[value]='"off"' label Terminal bell
) br
| Off .btn-group(
label.btn.btn-secondary '[(ngModel)]'='config.store.terminal.bell',
input( (ngModelChange)='config.save()',
type='radio', ngbRadioGroup
[value]='"visual"' )
) label.btn.btn-secondary(ngbButtonLabel)
| Visual input(
label.btn.btn-secondary type='radio',
input( ngbButton,
type='radio', [value]='"off"'
[value]='"audible"' )
) | Off
| Audible label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"visual"'
)
| Visual
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"audible"'
)
| Audible
.form-group
label Blink cursor
br
.btn-group(
'[(ngModel)]'='config.store.terminal.cursorBlink',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='false'
)
| Off
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='true'
)
| On
.form-group .form-group
label Session persistence label Session persistence
@@ -271,3 +312,26 @@
*ngFor='let provider of persistenceProviders', *ngFor='let provider of persistenceProviders',
[ngValue]='provider.id' [ngValue]='provider.id'
) {{provider.displayName}} ) {{provider.displayName}}
.form-group
label Auto-open a terminal on app start
br
.btn-group(
'[(ngModel)]'='config.store.terminal.autoOpen',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='false'
)
| Off
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='true'
)
| On

View File

@@ -1,16 +1,24 @@
import { BehaviorSubject, Subject, Subscription } from 'rxjs' import { BehaviorSubject, Subject, Subscription } from 'rxjs'
import 'rxjs/add/operator/bufferTime' import 'rxjs/add/operator/bufferTime'
import { Component, NgZone, Inject, Optional, ViewChild, HostBinding, Input } from '@angular/core' import { Component, NgZone, Inject, Optional, ViewChild, HostBinding, Input } from '@angular/core'
import { AppService, ConfigService, BaseTabComponent, ThemesService, HostAppService, HotkeysService, Platform } from 'terminus-core' import { AppService, ConfigService, BaseTabComponent, ElectronService, ThemesService, HostAppService, HotkeysService, Platform } from 'terminus-core'
import { IShell } from '../api'
import { Session, SessionsService } from '../services/sessions.service' import { Session, SessionsService } from '../services/sessions.service'
import { TerminalService } from '../services/terminal.service'
import { TerminalDecorator, ResizeEvent, SessionOptions } from '../api' import { TerminalDecorator, ResizeEvent, SessionOptions } from '../api'
import { hterm, preferenceManager } from '../hterm' import { hterm, preferenceManager } from '../hterm'
@Component({ @Component({
selector: 'terminalTab', selector: 'terminalTab',
template: '<div #content class="content" [style.opacity]="htermVisible ? 1 : 0"></div>', template: `
<div
#content
class="content"
[style.opacity]="htermVisible ? 1 : 0"
></div>
`,
styles: [require('./terminalTab.component.scss')], styles: [require('./terminalTab.component.scss')],
}) })
export class TerminalTabComponent extends BaseTabComponent { export class TerminalTabComponent extends BaseTabComponent {
@@ -31,8 +39,10 @@ export class TerminalTabComponent extends BaseTabComponent {
alternateScreenActive$ = new BehaviorSubject(false) alternateScreenActive$ = new BehaviorSubject(false)
mouseEvent$ = new Subject<Event>() mouseEvent$ = new Subject<Event>()
htermVisible = false htermVisible = false
shell: IShell
private bellPlayer: HTMLAudioElement private bellPlayer: HTMLAudioElement
private io: any private io: any
private contextMenu: any
constructor ( constructor (
private zone: NgZone, private zone: NgZone,
@@ -41,6 +51,8 @@ export class TerminalTabComponent extends BaseTabComponent {
private hostApp: HostAppService, private hostApp: HostAppService,
private hotkeys: HotkeysService, private hotkeys: HotkeysService,
private sessions: SessionsService, private sessions: SessionsService,
private electron: ElectronService,
private terminalService: TerminalService,
public config: ConfigService, public config: ConfigService,
@Optional() @Inject(TerminalDecorator) private decorators: TerminalDecorator[], @Optional() @Inject(TerminalDecorator) private decorators: TerminalDecorator[],
) { ) {
@@ -142,6 +154,35 @@ export class TerminalTabComponent extends BaseTabComponent {
} }
// TODO audible // TODO audible
}) })
this.contextMenu = this.electron.remote.Menu.buildFromTemplate([
{
label: 'New terminal',
click: () => {
this.zone.run(() => {
this.terminalService.openTab(this.shell)
})
}
},
{
label: 'Copy',
click: () => {
this.zone.run(() => {
setTimeout(() => {
this.hterm.copySelectionToClipboard()
})
})
}
},
{
label: 'Paste',
click: () => {
this.zone.run(() => {
this.sendInput(this.electron.clipboard.readText())
})
}
},
])
} }
attachHTermHandlers (hterm: any) { attachHTermHandlers (hterm: any) {
@@ -180,9 +221,20 @@ export class TerminalTabComponent extends BaseTabComponent {
const _onMouse = hterm.onMouse_.bind(hterm) const _onMouse = hterm.onMouse_.bind(hterm)
hterm.onMouse_ = (event) => { hterm.onMouse_ = (event) => {
this.mouseEvent$.next(event) this.mouseEvent$.next(event)
if (event.type === 'mousedown') {
if (event.which === 3) {
this.contextMenu.popup({
x: event.pageX + this.content.nativeElement.getBoundingClientRect().left,
y: event.pageY + this.content.nativeElement.getBoundingClientRect().top,
async: true,
})
event.preventDefault()
return
}
}
if (event.type === 'mousewheel') { if (event.type === 'mousewheel') {
if (event.ctrlKey || event.metaKey) { if (event.ctrlKey || event.metaKey) {
if (event.wheelDeltaY < 0) { if (event.wheelDeltaY > 0) {
this.zoomIn() this.zoomIn()
} else { } else {
this.zoomOut() this.zoomOut()
@@ -214,6 +266,13 @@ export class TerminalTabComponent extends BaseTabComponent {
return ret return ret
} }
} }
const _measureCharacterSize = hterm.scrollPort_.measureCharacterSize.bind(hterm.scrollPort_)
hterm.scrollPort_.measureCharacterSize = () => {
let size = _measureCharacterSize()
size.height += this.config.store.terminal.linePadding
return size
}
} }
attachIOHandlers (io: any) { attachIOHandlers (io: any) {
@@ -261,6 +320,10 @@ export class TerminalTabComponent extends BaseTabComponent {
preferenceManager.set('ctrl-plus-minus-zero-zoom', false) preferenceManager.set('ctrl-plus-minus-zero-zoom', false)
preferenceManager.set('scrollbar-visible', this.hostApp.platform === Platform.macOS) preferenceManager.set('scrollbar-visible', this.hostApp.platform === Platform.macOS)
preferenceManager.set('copy-on-select', false) preferenceManager.set('copy-on-select', false)
preferenceManager.set('alt-sends-what', 'browser-key')
preferenceManager.set('alt-gr-mode', 'ctrl-alt')
preferenceManager.set('pass-alt-number', true)
preferenceManager.set('cursor-blink', config.terminal.cursorBlink)
if (config.terminal.colorScheme.foreground) { if (config.terminal.colorScheme.foreground) {
preferenceManager.set('foreground-color', config.terminal.colorScheme.foreground) preferenceManager.set('foreground-color', config.terminal.colorScheme.foreground)
@@ -307,6 +370,10 @@ export class TerminalTabComponent extends BaseTabComponent {
beam: hterm.hterm.Terminal.cursorShape.BEAM, beam: hterm.hterm.Terminal.cursorShape.BEAM,
}[config.terminal.cursor] }[config.terminal.cursor]
this.hterm.applyCursorShape() this.hterm.applyCursorShape()
this.hterm.setCursorBlink(config.terminal.cursorBlink)
if (config.terminal.cursorBlink) {
this.hterm.onCursorBlink_()
}
} }
zoomIn () { zoomIn () {

View File

@@ -3,12 +3,16 @@ import { ConfigProvider, Platform } from 'terminus-core'
export class TerminalConfigProvider extends ConfigProvider { export class TerminalConfigProvider extends ConfigProvider {
defaults = { defaults = {
terminal: { terminal: {
autoOpen: false,
fontSize: 14, fontSize: 14,
linePadding: 0,
bell: 'off', bell: 'off',
bracketedPaste: false, bracketedPaste: false,
background: 'theme', background: 'theme',
ligatures: false, ligatures: false,
cursor: 'block', cursor: 'block',
cursorBlink: true,
customShell: '',
colorScheme: { colorScheme: {
__nonStructural: true, __nonStructural: true,
name: 'Material', name: 'Material',
@@ -42,7 +46,7 @@ export class TerminalConfigProvider extends ConfigProvider {
[Platform.macOS]: { [Platform.macOS]: {
terminal: { terminal: {
font: 'Menlo', font: 'Menlo',
shell: '~default-shell~', shell: 'default',
persistence: 'screen', persistence: 'screen',
}, },
hotkeys: { hotkeys: {
@@ -74,7 +78,7 @@ export class TerminalConfigProvider extends ConfigProvider {
[Platform.Windows]: { [Platform.Windows]: {
terminal: { terminal: {
font: 'Consolas', font: 'Consolas',
shell: '~clink~', shell: 'clink',
persistence: null, persistence: null,
}, },
hotkeys: { hotkeys: {
@@ -105,8 +109,8 @@ export class TerminalConfigProvider extends ConfigProvider {
[Platform.Linux]: { [Platform.Linux]: {
terminal: { terminal: {
font: 'Liberation Mono', font: 'Liberation Mono',
shell: '~default-shell~', shell: 'default',
persistence: 'screen', persistence: 'tmux',
}, },
hotkeys: { hotkeys: {
'copy': [ 'copy': [

View File

@@ -10,6 +10,11 @@ x-screen {
transition: 0.125s ease background; transition: 0.125s ease background;
} }
x-row > span {
display: inline-block;
height: inherit;
}
@font-face { @font-face {
font-family: "monospace-fallback"; font-family: "monospace-fallback";
src: url(fonts/Meslo.otf) format("opentype"); src: url(fonts/Meslo.otf) format("opentype");

View File

@@ -3,7 +3,7 @@ import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { ToolbarButtonProvider, TabRecoveryProvider, ConfigProvider, HotkeysService, HotkeyProvider } from 'terminus-core' import { ToolbarButtonProvider, TabRecoveryProvider, ConfigProvider, HotkeysService, HotkeyProvider, AppService, ConfigService } from 'terminus-core'
import { SettingsTabProvider } from 'terminus-settings' import { SettingsTabProvider } from 'terminus-settings'
import { TerminalTabComponent } from './components/terminalTab.component' import { TerminalTabComponent } from './components/terminalTab.component'
@@ -24,6 +24,7 @@ import { TerminalConfigProvider } from './config'
import { TerminalHotkeyProvider } from './hotkeys' import { TerminalHotkeyProvider } from './hotkeys'
import { HyperColorSchemes } from './colorSchemes' import { HyperColorSchemes } from './colorSchemes'
import { CustomShellProvider } from './shells/custom'
import { Cygwin32ShellProvider } from './shells/cygwin32' import { Cygwin32ShellProvider } from './shells/cygwin32'
import { Cygwin64ShellProvider } from './shells/cygwin64' import { Cygwin64ShellProvider } from './shells/cygwin64'
import { GitBashShellProvider } from './shells/gitBash' import { GitBashShellProvider } from './shells/gitBash'
@@ -59,6 +60,7 @@ import { hterm } from './hterm'
{ provide: ShellProvider, useClass: WindowsStockShellsProvider, multi: true }, { provide: ShellProvider, useClass: WindowsStockShellsProvider, multi: true },
{ provide: ShellProvider, useClass: MacOSDefaultShellProvider, multi: true }, { provide: ShellProvider, useClass: MacOSDefaultShellProvider, multi: true },
{ provide: ShellProvider, useClass: LinuxDefaultShellProvider, multi: true }, { provide: ShellProvider, useClass: LinuxDefaultShellProvider, multi: true },
{ provide: ShellProvider, useClass: CustomShellProvider, multi: true },
{ provide: ShellProvider, useClass: Cygwin32ShellProvider, multi: true }, { provide: ShellProvider, useClass: Cygwin32ShellProvider, multi: true },
{ provide: ShellProvider, useClass: Cygwin64ShellProvider, multi: true }, { provide: ShellProvider, useClass: Cygwin64ShellProvider, multi: true },
{ provide: ShellProvider, useClass: GitBashShellProvider, multi: true }, { provide: ShellProvider, useClass: GitBashShellProvider, multi: true },
@@ -76,7 +78,12 @@ import { hterm } from './hterm'
], ],
}) })
export default class TerminalModule { export default class TerminalModule {
constructor (hotkeys: HotkeysService) { constructor (
app: AppService,
config: ConfigService,
hotkeys: HotkeysService,
terminal: TerminalService,
) {
let events = [ let events = [
{ {
name: 'keydown', name: 'keydown',
@@ -101,6 +108,11 @@ export default class TerminalModule {
hotkeys.emitKeyEvent(nativeEvent) hotkeys.emitKeyEvent(nativeEvent)
} }
}) })
if (config.store.terminal.autoOpen) {
app.ready$.subscribe(() => {
terminal.openTab()
})
}
} }
} }

View File

@@ -1,10 +1,11 @@
import * as fs from 'mz/fs' import * as fs from 'mz/fs'
import * as path from 'path'
import { exec, spawn } from 'mz/child_process' import { exec, spawn } from 'mz/child_process'
import { exec as execAsync, execFileSync } from 'child_process' import { exec as execAsync, execFileSync } from 'child_process'
import { AsyncSubject } from 'rxjs' import { AsyncSubject } from 'rxjs'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Logger, LogService } from 'terminus-core' import { Logger, LogService, ElectronService } from 'terminus-core'
import { SessionOptions, SessionPersistenceProvider } from '../api' import { SessionOptions, SessionPersistenceProvider } from '../api'
declare function delay (ms: number): Promise<void> declare function delay (ms: number): Promise<void>
@@ -35,6 +36,7 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
constructor ( constructor (
log: LogService, log: LogService,
private electron: ElectronService,
) { ) {
super() super()
this.logger = log.create('main') this.logger = log.create('main')
@@ -115,7 +117,7 @@ export class ScreenPersistenceProvider extends SessionPersistenceProvider {
} }
private async prepareConfig (): Promise<string> { private async prepareConfig (): Promise<string> {
let configPath = '/tmp/.termScreenConfig' let configPath = path.join(this.electron.app.getPath('userData'), 'screen-config.tmp')
await fs.writeFile(configPath, ` await fs.writeFile(configPath, `
escape ^^^ escape ^^^
vbell off vbell off

View File

@@ -5,6 +5,8 @@ import { ConnectableObservable, AsyncSubject, Subject } from 'rxjs'
import * as childProcess from 'child_process' import * as childProcess from 'child_process'
import { SessionOptions, SessionPersistenceProvider } from '../api' import { SessionOptions, SessionPersistenceProvider } from '../api'
declare function delay (ms: number): Promise<void>
const TMUX_CONFIG = ` const TMUX_CONFIG = `
set -g status off set -g status off
set -g focus-events on set -g focus-events on
@@ -15,6 +17,7 @@ const TMUX_CONFIG = `
set -g set-titles-string "#W" set -g set-titles-string "#W"
set -g window-status-format '#I:#(pwd="#{pane_current_path}"; echo \${pwd####*/})#F' set -g window-status-format '#I:#(pwd="#{pane_current_path}"; echo \${pwd####*/})#F'
set -g window-status-current-format '#I:#(pwd="#{pane_current_path}"; echo \${pwd####*/})#F' set -g window-status-current-format '#I:#(pwd="#{pane_current_path}"; echo \${pwd####*/})#F'
set-option -g prefix C-^
set-option -g status-interval 1 set-option -g status-interval 1
` `
@@ -96,7 +99,7 @@ export class TMuxCommandProcess {
} }
}) })
this.response$ = this.block$.skip(1).publish() this.response$ = this.block$.publish()
this.response$.connect() this.response$.connect()
this.block$.subscribe(block => { this.block$.subscribe(block => {
@@ -133,15 +136,23 @@ export class TMuxCommandProcess {
export class TMux { export class TMux {
private process: TMuxCommandProcess private process: TMuxCommandProcess
private ready: Promise<void>
constructor () { constructor () {
this.process = new TMuxCommandProcess() this.process = new TMuxCommandProcess()
TMUX_CONFIG.split('\n').filter(x => x).forEach(async (line) => { this.ready = (async () => {
await this.process.command(line) for (let line of TMUX_CONFIG.split('\n')) {
}) if (line) {
await this.process.command(line)
}
}
// Tmux sometimes sends a stray response block at start
await delay(500)
})()
} }
async create (id: string, options: SessionOptions): Promise<void> { async create (id: string, options: SessionOptions): Promise<void> {
await this.ready
let args = [options.command].concat(options.args) let args = [options.command].concat(options.args)
let cmd = args.map(x => `"${x.replace('"', '\\"')}"`) let cmd = args.map(x => `"${x.replace('"', '\\"')}"`)
await this.process.command( await this.process.command(
@@ -152,11 +163,13 @@ export class TMux {
} }
async list (): Promise<string[]> { async list (): Promise<string[]> {
await this.ready
let block = await this.process.command('list-sessions -F "#{session_name}"') let block = await this.process.command('list-sessions -F "#{session_name}"')
return block.lines return block.lines
} }
async getPID (id: string): Promise<number|null> { async getPID (id: string): Promise<number|null> {
await this.ready
let response = await this.process.command(`list-panes -t ${id} -F "#{pane_pid}"`) let response = await this.process.command(`list-panes -t ${id} -F "#{pane_pid}"`)
if (response.lines.length === 0) { if (response.lines.length === 0) {
return null return null
@@ -166,6 +179,7 @@ export class TMux {
} }
async terminate (id: string): Promise<void> { async terminate (id: string): Promise<void> {
await this.ready
this.process.command(`kill-session -t ${id}`).catch(() => { this.process.command(`kill-session -t ${id}`).catch(() => {
console.debug('Session already killed') console.debug('Session already killed')
}) })

View File

@@ -1,5 +1,4 @@
const psNode = require('ps-node') const psNode = require('ps-node')
// import * as nodePTY from 'node-pty'
let nodePTY let nodePTY
import * as fs from 'mz/fs' import * as fs from 'mz/fs'
import { Subject } from 'rxjs' import { Subject } from 'rxjs'
@@ -94,13 +93,13 @@ export class Session {
} }
resize (columns, rows) { resize (columns, rows) {
if (this.pty.writable) { if (this.pty._writable) {
this.pty.resize(columns, rows) this.pty.resize(columns, rows)
} }
} }
write (data) { write (data) {
if (this.pty.writable) { if (this.pty._writable) {
this.pty.write(Buffer.from(data, 'utf-8')) this.pty.write(Buffer.from(data, 'utf-8'))
} }
} }
@@ -156,6 +155,9 @@ export class Session {
} }
async getWorkingDirectory (): Promise<string> { async getWorkingDirectory (): Promise<string> {
if (!this.truePID) {
return null
}
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
let lines = (await exec(`lsof -p ${this.truePID} -Fn`))[0].toString().split('\n') let lines = (await exec(`lsof -p ${this.truePID} -Fn`))[0].toString().split('\n')
if (lines[1] === 'fcwd') { if (lines[1] === 'fcwd') {
@@ -183,8 +185,9 @@ export class SessionsService {
electron: ElectronService, electron: ElectronService,
log: LogService, log: LogService,
) { ) {
nodePTY = electron.remoteRequirePluginModule('terminus-terminal', 'node-pty', global as any) nodePTY = electron.remoteRequirePluginModule('terminus-terminal', 'node-pty-tmp', global as any)
this.logger = log.create('sessions') this.logger = log.create('sessions')
this.persistenceProviders = this.persistenceProviders.filter(x => x.isAvailable())
} }
async prepareNewSession (options: SessionOptions): Promise<SessionOptions> { async prepareNewSession (options: SessionOptions): Promise<SessionOptions> {
@@ -220,6 +223,9 @@ export class SessionsService {
} }
private getPersistence (): SessionPersistenceProvider { private getPersistence (): SessionPersistenceProvider {
if (!this.config.store.terminal.persistence) {
return null
}
return this.persistenceProviders.find(x => x.id === this.config.store.terminal.persistence) || null return this.persistenceProviders.find(x => x.id === this.config.store.terminal.persistence) || null
} }
} }

View File

@@ -1,25 +1,45 @@
import { Injectable } from '@angular/core' import { AsyncSubject } from 'rxjs'
import { AppService, Logger, LogService } from 'terminus-core' import { Injectable, Inject } from '@angular/core'
import { IShell } from '../api' import { AppService, Logger, LogService, ConfigService } from 'terminus-core'
import { IShell, ShellProvider } from '../api'
import { SessionsService } from './sessions.service' import { SessionsService } from './sessions.service'
import { TerminalTabComponent } from '../components/terminalTab.component' import { TerminalTabComponent } from '../components/terminalTab.component'
@Injectable() @Injectable()
export class TerminalService { export class TerminalService {
shells$ = new AsyncSubject<IShell[]>()
private logger: Logger private logger: Logger
constructor ( constructor (
private app: AppService, private app: AppService,
private sessions: SessionsService, private sessions: SessionsService,
private config: ConfigService,
@Inject(ShellProvider) private shellProviders: ShellProvider[],
log: LogService, log: LogService,
) { ) {
this.logger = log.create('terminal') this.logger = log.create('terminal')
this.reloadShells()
config.changed$.subscribe(() => {
this.reloadShells()
})
} }
async openTab (shell: IShell, cwd?: string): Promise<TerminalTabComponent> { async reloadShells () {
this.shells$ = new AsyncSubject<IShell[]>()
let shellLists = await Promise.all(this.shellProviders.map(x => x.provide()))
this.shells$.next(shellLists.reduce((a, b) => a.concat(b)))
this.shells$.complete()
}
async openTab (shell?: IShell, cwd?: string): Promise<TerminalTabComponent> {
if (!cwd && this.app.activeTab instanceof TerminalTabComponent) { if (!cwd && this.app.activeTab instanceof TerminalTabComponent) {
cwd = await this.app.activeTab.session.getWorkingDirectory() cwd = await this.app.activeTab.session.getWorkingDirectory()
} }
if (!shell) {
let shells = await this.shells$.toPromise()
shell = shells.find(x => x.id === this.config.store.terminal.shell) || shells[0]
}
let env: any = Object.assign({}, process.env, shell.env || {}) let env: any = Object.assign({}, process.env, shell.env || {})
this.logger.log(`Starting shell ${shell.name}`, shell) this.logger.log(`Starting shell ${shell.name}`, shell)
@@ -34,7 +54,7 @@ export class TerminalService {
return this.app.openNewTab( return this.app.openNewTab(
TerminalTabComponent, TerminalTabComponent,
{ sessionOptions } { sessionOptions, shell }
) as TerminalTabComponent ) as TerminalTabComponent
} }
} }

View File

@@ -0,0 +1,23 @@
import { Injectable } from '@angular/core'
import { ConfigService } from 'terminus-core'
import { ShellProvider, IShell } from '../api'
@Injectable()
export class CustomShellProvider extends ShellProvider {
constructor (
private config: ConfigService,
) {
super()
}
async provide (): Promise<IShell[]> {
let args = this.config.store.terminal.customShell.split(' ')
return [{
id: 'custom',
name: 'Custom',
command: args[0],
args: args.slice(1),
}]
}
}

View File

@@ -25,7 +25,7 @@ export class Cygwin32ShellProvider extends ShellProvider {
let cygwinPath = await new Promise<string>(resolve => { let cygwinPath = await new Promise<string>(resolve => {
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x86' }) let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x86' })
reg.get('rootdir', (err, item) => { reg.get('rootdir', (err, item) => {
if (err) { if (err || !item) {
return resolve(null) return resolve(null)
} }
resolve(item.value) resolve(item.value)

View File

@@ -25,7 +25,7 @@ export class Cygwin64ShellProvider extends ShellProvider {
let cygwinPath = await new Promise<string>(resolve => { let cygwinPath = await new Promise<string>(resolve => {
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x64' }) let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\Cygwin\\setup', arch: 'x64' })
reg.get('rootdir', (err, item) => { reg.get('rootdir', (err, item) => {
if (err) { if (err || !item) {
return resolve(null) return resolve(null)
} }
resolve(item.value) resolve(item.value)

View File

@@ -25,7 +25,7 @@ export class GitBashShellProvider extends ShellProvider {
let gitBashPath = await new Promise<string>(resolve => { let gitBashPath = await new Promise<string>(resolve => {
let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\GitForWindows' }) let reg = new Registry({ hive: Registry.HKLM, key: '\\Software\\GitForWindows' })
reg.get('InstallPath', (err, item) => { reg.get('InstallPath', (err, item) => {
if (err) { if (err || !item) {
resolve(null) resolve(null)
return return
} }
@@ -33,6 +33,19 @@ export class GitBashShellProvider extends ShellProvider {
}) })
}) })
if (!gitBashPath) {
gitBashPath = await new Promise<string>(resolve => {
let reg = new Registry({ hive: Registry.HKCU, key: '\\Software\\GitForWindows' })
reg.get('InstallPath', (err, item) => {
if (err || !item) {
resolve(null)
return
}
resolve(item.value)
})
})
}
if (!gitBashPath) { if (!gitBashPath) {
return [] return []
} }
@@ -41,6 +54,7 @@ export class GitBashShellProvider extends ShellProvider {
id: 'git-bash', id: 'git-bash',
name: 'Git-Bash', name: 'Git-Bash',
command: path.join(gitBashPath, 'bin', 'bash.exe'), command: path.join(gitBashPath, 'bin', 'bash.exe'),
args: [ '--login', '-i' ],
env: { env: {
TERM: 'cygwin', TERM: 'cygwin',
} }

View File

@@ -33,7 +33,8 @@ export class LinuxDefaultShellProvider extends ShellProvider {
return [{ return [{
id: 'default', id: 'default',
name: 'User default', name: 'User default',
command: line.split(':')[6] command: line.split(':')[6],
args: ['--login'],
}] }]
} }
} }

View File

@@ -20,7 +20,8 @@ export class MacOSDefaultShellProvider extends ShellProvider {
return [{ return [{
id: 'default', id: 'default',
name: 'User default', name: 'User default',
command: shellEntry.split(' ')[1].trim() command: shellEntry.split(' ')[1].trim(),
args: ['--login'],
}] }]
} }
} }

View File

@@ -24,6 +24,7 @@ export class POSIXShellsProvider extends ShellProvider {
id: x, id: x,
name: x, name: x,
command: x, command: x,
args: ['--login'],
})) }))
} }
} }

View File

@@ -48,7 +48,7 @@ module.exports = {
'fs', 'fs',
'font-manager', 'font-manager',
'path', 'path',
'node-pty', 'node-pty-tmp',
'mz/fs', 'mz/fs',
'mz/child_process', 'mz/child_process',
'winreg', 'winreg',

View File

@@ -2,6 +2,10 @@
# yarn lockfile v1 # yarn lockfile v1
"@types/async-lock@0.0.19":
version "0.0.19"
resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-0.0.19.tgz#4bdb7f8d9ac2826588b98068903aedbd9d95dce8"
"@types/deep-equal@^1.0.0": "@types/deep-equal@^1.0.0":
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/deep-equal/-/deep-equal-1.0.0.tgz#9ebeaa73d1fc4791f038a5f1440e0449ea968495" resolved "https://registry.yarnpkg.com/@types/deep-equal/-/deep-equal-1.0.0.tgz#9ebeaa73d1fc4791f038a5f1440e0449ea968495"
@@ -28,6 +32,10 @@ any-promise@^1.0.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
async-lock@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.0.0.tgz#b81abbdbd2a6e516773a044b7e6917ae2001f370"
big.js@^3.1.3: big.js@^3.1.3:
version "3.1.3" version "3.1.3"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
@@ -84,19 +92,19 @@ mz@^2.6.0:
object-assign "^4.0.1" object-assign "^4.0.1"
thenify-all "^1.0.0" thenify-all "^1.0.0"
nan@2.5.0: nan@^2.6.2:
version "2.5.0" version "2.7.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.0.tgz#aa8f1e34531d807e9e27755b234b4a6ec0c152a8" resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46"
nan@~2.2.0: nan@~2.2.0:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.2.1.tgz#d68693f6b34bb41d66bc68b3a4f9defc79d7149b" resolved "https://registry.yarnpkg.com/nan/-/nan-2.2.1.tgz#d68693f6b34bb41d66bc68b3a4f9defc79d7149b"
node-pty@0.6.8: node-pty-tmp@0.7.1:
version "0.6.8" version "0.7.1"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.6.8.tgz#a7b145397bef23a719128a75b20d4821726dfe90" resolved "https://registry.yarnpkg.com/node-pty-tmp/-/node-pty-tmp-0.7.1.tgz#0a81179f9087b21f968206c886e543db20650d7a"
dependencies: dependencies:
nan "2.5.0" nan "^2.6.2"
object-assign@^4.0.1: object-assign@^4.0.1:
version "4.1.1" version "4.1.1"

View File

@@ -15,8 +15,10 @@
"skipLibCheck": true, "skipLibCheck": true,
"lib": [ "lib": [
"dom", "dom",
"es2015", "es5",
"es7" "es6",
"es7",
"es2015"
] ]
} }
} }