Compare commits

...

46 Commits

Author SHA1 Message Date
Eugene Pankov
e68cafdb70 fullscreen mode (fixes #283) 2018-02-12 17:04:49 +01:00
Eugene Pankov
fde16b8699 fixed #291 2018-02-12 16:54:04 +01:00
Eugene Pankov
245c65d750 bumped electron 2018-02-12 16:52:40 +01:00
Eugene Pankov
c7d9f944d5 Merge pull request #285 from VaultVulp/master
Fixed typo in SSH client's configuration window.
2018-02-03 10:11:17 +01:00
Pavel Alimpiev
4ca806e142 Fixed typo in SSH client's configuration window. 2018-02-03 01:15:55 +03:00
Eugene Pankov
0255985bc6 icon update 2018-01-24 19:39:51 +01:00
Eugene Pankov
104f1ee7aa yarn.lock 2018-01-24 16:40:35 +01:00
Eugene Pankov
132d0553ae fixed alt-arrow keys on Mac as well as Home and End combinations (fixes #255) 2018-01-24 16:40:30 +01:00
Eugene Pankov
b007ff6ff6 scrollbar fix 2018-01-24 16:01:32 +01:00
Eugene Pankov
2bea4b9d6c bump 2018-01-19 15:57:33 +01:00
Eugene Pankov
4a76c12f15 ignore Hyper theme errors 2018-01-19 15:53:14 +01:00
Eugene Pankov
181f3e3d33 Merge branch 'master' of github.com:Eugeny/terminus 2018-01-19 15:37:51 +01:00
Eugene Pankov
ee2fadbf60 added message popups 2018-01-19 15:31:28 +01:00
Eugene Pankov
4259d3b53d enforce GPU composition 2018-01-19 15:30:52 +01:00
Eugene Pankov
65aaa131ef removed Screen hotkeys from the standard macOS config 2018-01-04 21:38:17 +01:00
Eugene Pankov
46d9aabbdd configure() doesn't have to be async 2018-01-04 21:38:02 +01:00
Eugene Pankov
692045ce77 fixed button alignment on macOS 2018-01-04 21:20:42 +01:00
Eugene Pankov
9c257b0002 allow specifying the SSH port (fixes #269) 2018-01-04 21:13:46 +01:00
Eugene Pankov
15c23eb7dd deps 2018-01-04 21:04:44 +01:00
Eugene Pankov
5fc67d3648 launch devtools in detached mode 2018-01-04 21:04:31 +01:00
Eugene Pankov
571884f39c Merge branch 'master' of github.com:Eugeny/terminus 2017-12-27 23:12:50 +01:00
Eugene Pankov
ccbcd30813 support encrypted private ssh keys (fixes #262) 2017-12-27 23:11:28 +01:00
Eugene Pankov
30666c2838 Merge pull request #241 from tnguyen14/base16-xresources
use base16-xresources
2017-12-15 19:07:55 +01:00
Tri Nguyen
953558a866 process #define variables 2017-12-14 23:51:21 -05:00
Eugene Pankov
ace81aced2 Merge pull request #261 from kwonoj/feat-tab-cycle
feat(tab): enable cycle tab selection
2017-12-14 19:48:48 +01:00
OJ Kwon
dc781deeb0 feat(tab): enable cycle tab selection 2017-12-14 08:40:00 -08:00
Eugene Pankov
e24d3d56eb Revert "Delete icon.ico"
This reverts commit aaac14dbd5.
2017-12-14 17:32:41 +01:00
Eugene Pankov
6f35e60468 added missing hotkeys 2017-12-14 15:03:51 +01:00
Eugene Pankov
110b57bc64 added Ctrl-Tab hotkeys for tab switching 2017-12-14 14:56:59 +01:00
Eugene Pankov
fd47a32bdb use yarn for Travis builds 2017-12-14 14:55:31 +01:00
Eugene Pankov
dfd1ffbffc ssh agent support (closes #251) 2017-12-07 20:47:25 +01:00
Eugene Pankov
f841cfeb5e Merge branch 'master' of github.com:Eugeny/terminus 2017-12-07 20:21:58 +01:00
Eugene Pankov
9d2398bc12 fixed tmux argument list handling (closes #231) 2017-12-07 20:21:02 +01:00
Eugene Pankov
da9cee0792 Delete Info.plist 2017-12-05 12:26:39 +01:00
Eugene Pankov
aaac14dbd5 Delete icon.ico 2017-12-05 12:25:40 +01:00
Eugene Pankov
23396b5c53 Delete build.wxs 2017-12-05 12:25:30 +01:00
Eugene Pankov
021390952a Delete elements.wxs 2017-12-05 12:25:16 +01:00
Eugene Pankov
ad59baa4f5 Delete wix-theme.xml 2017-12-05 12:25:06 +01:00
Eugene Pankov
0420b2dbb9 Merge pull request #254 from tnguyen14/update-hacking-npm-install
update instruction to use npx
2017-12-01 15:42:02 +01:00
Tri Nguyen
fab9429707 update instruction to use npx 2017-12-01 09:31:00 -05:00
Eugene Pankov
5b62d5f92a Merge pull request #252 from tnguyen14/local-npx
Include all build tools in project's dependencies
2017-12-01 09:00:30 +01:00
Eugene Pankov
298637a150 Merge branch 'master' of github.com:Eugeny/terminus 2017-11-28 22:02:43 +01:00
Eugene Pankov
49c738451e fixed the private key selection dialog 2017-11-28 22:02:28 +01:00
Eugene Pankov
892b18df4d fixed #250 2017-11-28 20:30:06 +01:00
Tri Nguyen
de6e545f8f Include all build tools in project's dependencies 2017-11-28 00:19:38 -05:00
Tri Nguyen
e3d1d5e61e use base16-xresources 2017-11-27 23:37:07 -05:00
58 changed files with 2354 additions and 1060 deletions

View File

@@ -14,12 +14,12 @@ cache:
- app/node_modules
before_install:
- npm i
- yarn install
- scripts/install-deps.js
script:
- scripts/build-native.js
- npm run build
- yarn run build
- scripts/prepackage-plugins.js
- scripts/build-$BUILD_FOR.js
@@ -32,3 +32,7 @@ addons:
- rpm
- wine
- mono-runtime
- yarn
sources:
- sourceline: 'deb https://dl.yarnpkg.com/debian/ stable main'
key_url: 'https://dl.yarnpkg.com/debian/pubkey.gpg'

View File

@@ -10,14 +10,13 @@ First, install the dependencies:
```
# macOS/Linux:
sudo npm -g install yarn node-gyp
yarn install
npm install
./scripts/install-deps.js
./scripts/build-native.js
# Windows:
npm -g install yarn node-gyp windows-build-tools
yarn install
npm -g install windows-build-tools
npm install
node scripts\install-deps.js
node scripts\build-native.js
```

View File

@@ -27,6 +27,7 @@
"electron-squirrel-startup": "^1.0.0",
"js-yaml": "3.8.2",
"mz": "^2.6.0",
"ngx-toastr": "^8.0.0",
"path": "0.12.7",
"rxjs": "5.3.0",
"zone.js": "0.8.12"

View File

@@ -1,12 +1,18 @@
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { ToastrModule } from 'ngx-toastr'
export function getRootModule (plugins: any[]) {
let imports = [
BrowserModule,
...plugins,
NgbModule.forRoot(),
ToastrModule.forRoot({
positionClass: 'toast-bottom-center',
preventDuplicates: true,
extendedTimeOut: 5000,
}),
]
let bootstrap = [
...(plugins.filter(x => x.bootstrap).map(x => x.bootstrap)),

View File

@@ -1,5 +1,6 @@
import 'source-sans-pro'
import 'font-awesome/css/font-awesome.css'
import 'ngx-toastr/toastr.css'
import './preload.scss'
import * as Raven from 'raven-js'

View File

@@ -14,11 +14,11 @@
viewBox="0 0 150 150"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
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">
inkscape:export-filename="/home/eugene/Work/term/build/icons/512x512.png"
inkscape:export-xdpi="86.699997"
inkscape:export-ydpi="86.699997">
<defs
id="defs2" />
<sodipodi:namedview
@@ -29,8 +29,8 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="134.39743"
inkscape:cy="340.43068"
inkscape:cx="85.897128"
inkscape:cy="375.72042"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
@@ -43,7 +43,9 @@
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
fit-margin-bottom="0"
inkscape:snap-intersection-paths="true"
inkscape:object-paths="true" />
<metadata
id="metadata5">
<rdf:RDF>
@@ -64,24 +66,24 @@
<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"
style="opacity:0.9;fill:#bfd9f1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.12037313px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="M 33.048081,103.66303 101.30357,143.02426 80.80219,154.86063 33.048089,125.73315 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"
style="opacity:0.9;fill:#6666af;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.12037313px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 141.59934,143.95811 0.051,23.16109 -87.420905,49.42651 -0.0034,-22.16232 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"
style="opacity:0.9;fill:#bfd9f1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.12037313px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 33.233182,182.28294 20.992812,12.1202 0.0034,22.16208 -20.996251,-12.19239 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"
style="opacity:0.9;fill:#9dbef0;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.12649226px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 52.236336,92.196079 -19.484508,11.249681 68.551742,39.5785 -68.366041,39.4708 21.107487,12.18633 68.366044,-39.4708 19.48451,-11.24968 z"
id="path134"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -59,6 +59,7 @@ const builtinModules = [
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@ng-bootstrap/ng-bootstrap',
'ngx-toastr',
'rxjs',
'terminus-core',
'terminus-settings',

View File

@@ -58,6 +58,7 @@ module.exports = {
'child_process': 'commonjs child_process',
'electron': 'commonjs electron',
'electron-is-dev': 'commonjs electron-is-dev',
'ngx-toastr': 'commonjs ngx-toastr',
'module': 'commonjs module',
'mz': 'commonjs mz',
'path': 'commonjs path',

View File

@@ -195,6 +195,10 @@ mz@^2.6.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
ngx-toastr@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-8.0.0.tgz#f3bc53146b2f7da3eabf3daa1b1bbdf65cb49697"
object-assign@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

View File

@@ -15,19 +15,22 @@
viewBox="0 0 150 150"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="icon.svg">
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="icon.svg"
inkscape:export-filename="/home/eugene/Work/term/build/icons/512x512.png"
inkscape:export-xdpi="86.699997"
inkscape:export-ydpi="86.699997">
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
id="linearGradient4649">
<stop
style="stop-color:#000916;stop-opacity:1"
style="stop-color:#000316;stop-opacity:1"
offset="0"
id="stop4645" />
<stop
style="stop-color:#004565;stop-opacity:1"
style="stop-color:#190065;stop-opacity:1"
offset="1"
id="stop4647" />
</linearGradient>
@@ -39,7 +42,8 @@
y1="85.146751"
x2="89.26284"
y2="229.47229"
gradientUnits="userSpaceOnUse" />
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.82182032,0,0,0.82182032,15.208802,28.029361)" />
</defs>
<sodipodi:namedview
id="base"
@@ -49,8 +53,8 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="134.39743"
inkscape:cy="340.43068"
inkscape:cx="85.897128"
inkscape:cy="375.72042"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
@@ -63,7 +67,9 @@
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
fit-margin-bottom="0"
inkscape:snap-intersection-paths="true"
inkscape:object-paths="true" />
<metadata
id="metadata5">
<rdf:RDF>
@@ -83,34 +89,34 @@
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" />
width="123.27305"
height="123.27305"
x="23.72002"
y="95.673004"
style="fill:url(#linearGradient4651);fill-opacity:1;stroke-width:0.21743995"
rx="8.2182035"
ry="8.2182035" />
<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"
style="opacity:0.9;fill:#bfd9f1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.82182032px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 47.511243,117.17807 50.067023,28.8724 -15.038249,8.68226 -35.028768,-21.3657 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"
style="opacity:0.9;fill:#6666af;fill-rule:evenodd;stroke:none;stroke-width:0.82182032px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
d="m 127.13617,146.73547 0.0374,16.98921 -64.125308,36.25552 -0.0025,-16.25659 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"
style="opacity:0.9;fill:#bfd9f1;fill-rule:evenodd;stroke:none;stroke-width:0.82182032px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
d="m 47.647019,174.84764 15.398727,8.89046 0.0025,16.25641 -15.401249,-8.94341 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"
style="opacity:0.9;fill:#9dbef0;fill-rule:evenodd;stroke:none;stroke-width:0.82630885px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;fill-opacity:1"
d="m 61.586284,108.76679 -14.292349,8.25191 50.284331,29.03177 -50.148115,28.95277 15.482843,8.93896 50.148116,-28.95277 14.29235,-8.25191 z"
id="path134"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en_US</string>
<key>CFBundleExecutable</key>
<string>ELEMENTS</string>
<key>CFBundleIdentifier</key>
<string>com.syslink.elements</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${VERSION}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>Elements Client</string>
<key>CFBundleURLSchemes</key>
<array>
<string>elements-client</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>619</string>
<key>LSMinimumSystemVersion</key>
<string>10.8.0</string>
<key>LSUIElement</key>
<false/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Syslink GmbH. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>AtomApplication</string>
</dict>
</plist>

Binary file not shown.

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix RequiredVersion="3.6.2830.0" xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Name="ELEMENTS" Version="$(var.Version)" Manufacturer="ELEMENTS.tv" UpgradeCode="508475fc-0e76-4cd1-8e98-6953023ba518"
HelpUrl="http://elements.tv"
Copyright="Copyright © 2016 ELEMENTS" IconSourceFile="build/icon.ico"
AboutUrl="http://elements.tv">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense">
<bal:WixStandardBootstrapperApplication
LicenseUrl=""
LogoFile="build\logo.png"
ThemeFile="build\windows\wix-theme.xml"
/>
</BootstrapperApplicationRef>
<Chain>
<MsiPackage
Id="ClientMSI"
Compressed="yes"
ForcePerMachine="yes"
SourceFile="dist\elements-app.msi"
Vital="yes">
</MsiPackage>
<MsiPackage
Id="DriverMSI"
Compressed="yes"
ForcePerMachine="yes"
SourceFile="build/windows/ElementsDriver_x64.msi"
Vital="yes">
</MsiPackage>
</Chain>
</Bundle>
</Wix>

View File

@@ -1,84 +0,0 @@
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="37484543-5276-2386-5427-275941245342"
Name="ELEMENTS" Version="$(var.ProductVersion)" Manufacturer="ELEMENTS.tv" Language="1033">
<Package InstallerVersion="200"
Compressed="yes"
Comments="Windows Installer Package"
Platform="x64"
InstallScope="perMachine"
InstallPrivileges="elevated" />
<MajorUpgrade AllowDowngrades="yes" Schedule="afterInstallValidate" />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes"/>
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="RegistryEntries" />
<ComponentRef Id="AppDir"/>
<ComponentRef Id="AvidSharedStorageAccess"/>
<ComponentRef Id="ApplicationShortcutDesktop"/>
<ComponentGroupRef Id="Files" />
</Feature>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="DesktopFolder" Name="Desktop">
<Component Id="ApplicationShortcutDesktop" Guid="*">
<Shortcut Id="ApplicationDesktopShortcut"
Name="ELEMENTS"
Description="ELEMENTS client app"
Target="[INSTALLDIR]\\Elements.exe"
WorkingDirectory="INSTALLDIR"/>
<RemoveFolder Id="DesktopFolder" On="uninstall"/>
<RegistryValue
Root="HKCU"
Key="Software\ELEMENTS"
Name="installed"
Type="integer"
Value="1"
KeyPath="yes"/>
</Component>
</Directory>
<Directory Id="ProgramFiles64Folder">
<Directory Id="ElementsDir" Name="ELEMENTS">
<Directory Id="INSTALLDIR" Name="ELEMENTS Client">
<Component Id="AppDir" Guid="284957a6-a462-4e34-babd-c17800f11054" Win64="yes">
<CreateFolder />
<!--RemoveFile Id="RemoveFilesFromAppDirectory" Name="*.*" On="uninstall" /-->
<!--RemoveFolder Id="AppDir" On="uninstall"/-->
</Component>
</Directory>
</Directory>
</Directory>
<Component Id="RegistryEntries" Guid="572998d8-719e-4124-8fe6-6d4f8b855d7b">
<RegistryKey Root="HKLM"
Key="system\currentcontrolset\services\AvidFs"
Action="create">
<RegistryValue Type="string" Name="Description" Value="AIFMRX" />
<RegistryValue Type="string" Name="DisplayName" Value="AIFMRX" />
<RegistryValue Type="integer" Name="ErrorControl" Value="1" />
<RegistryValue Type="string" Name="Group" Value="Network" />
<RegistryValue Type="string" Name="ImagePath" Value="System32\DRIVERS\aifmrx.sys" />
<RegistryValue Type="integer" Name="Start" Value="1" />
<RegistryValue Type="integer" Name="Type" Value="2" />
</RegistryKey>
<RegistryKey Root="HKLM"
Key="system\currentcontrolset\services\AifMRx\NetworkProvider"
Action="create">
<RegistryValue Type="string" Name="DeviceName" Value="\Device\AvidFs" />
<RegistryValue Type="string" Name="Name" Value="Interface Network" />
<RegistryValue Type="string" Name="ProviderPath" Value="System32\aifmrxnp.dll" />
</RegistryKey>
<RegistryKey Root="HKLM"
Key="system\CurrentControlSet\services\LanmanWorkstation\Parameters"
Action="create">
<RegistryValue Type="integer" Name="DisableLargeMtu" Value="0" KeyPath="yes" />
<RegistryValue Type="integer" Name="DisableBandwidthThrottling" Value="1" />
<RegistryValue Type="integer" Name="EnableWsd" Value="0" />
</RegistryKey>
</Component>
<Directory Id="System64Folder" Name="SystemFolder">
<Component Id="AvidSharedStorageAccess" Guid="972c67f2-ee17-4b20-8939-b92cfa13fcf6" NeverOverwrite="yes" Win64="yes" Permanent="yes">
<File Id="AvidSharedStorageAccess.dll" Source="build\windows\AvidSharedStorageAccess.dll" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
</Product>
</Wix>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 361 KiB

View File

@@ -1,80 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
<Window Width="300" Height="360" HexStyle="100a0000" FontId="0">#(loc.Caption)</Window>
<Font Id="0" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
<Font Id="1" Height="-24" Weight="500" Foreground="000000">Segoe UI</Font>
<Font Id="2" Height="-22" Weight="500" Foreground="666666">Segoe UI</Font>
<Font Id="3" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
<Font Id="4" Height="-12" Weight="500" Foreground="ff0000" Background="FFFFFF" Underline="yes">Segoe UI</Font>
<Image X="30" Y="30" Width="256" Height="60" ImageFile="logo.png" Visible="yes"/>
<Page Name="Help">
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Text>
<Text X="11" Y="112" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Text>
<Button Name="HelpCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.HelpCloseButton)</Button>
</Page>
<Page Name="Install">
<!--Hypertext Name="EulaHyperlink" X="11" Y="121" Width="-11" Height="51" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallLicenseLinkText)</Hypertext>
<Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="260" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox-->
<Button Name="InstallButton" X="90" Y="-120" Width="120" Height="50" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
<Button Name="WelcomeCancelButton" X="110" Y="-80" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.InstallCloseButton)</Button>
</Page>
<Page Name="Options">
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Text>
<Text X="11" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OptionsLocationLabel)</Text>
<Editbox Name="FolderEditbox" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
<Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">#(loc.OptionsBrowseButton)</Button>
<Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.OptionsOkButton)</Button>
<Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.OptionsCancelButton)</Button>
</Page>
<Page Name="FilesInUse">
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.FilesInUseHeader)</Text>
<Text X="11" Y="121" Width="-11" Height="34" FontId="3" DisablePrefix="yes">#(loc.FilesInUseLabel)</Text>
<Text Name="FilesInUseText" X="11" Y="150" Width="-11" Height="-86" FontId="3" DisablePrefix="yes" HexStyle="0x0000C000"></Text>
<Button Name="FilesInUseCloseRadioButton" X="11" Y="-60" Width="-11" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes" HexStyle="0x000009">#(loc.FilesInUseCloseRadioButton)</Button>
<Button Name="FilesInUseDontCloseRadioButton" X="11" Y="-40" Width="-11" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes" HexStyle="0x000009">#(loc.FilesInUseDontCloseRadioButton)</Button>
<Button Name="FilesInUseOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FilesInUseOkButton)</Button>
<Button Name="FilesInUseCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.FilesInUseCancelButton)</Button>
</Page>
<Page Name="Progress">
<Text X="30" Y="120" Width="-30" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Text>
<Text X="30" Y="150" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Text>
<Text Name="OverallProgressPackageText" X="30" Y="200" Width="-30" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Text>
<Progressbar Name="OverallCalculatedProgressbar" X="30" Y="220" Width="-30" Height="20" />
<Button Name="ProgressCancelButton" X="110" Y="-40" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
</Page>
<Page Name="Modify">
<Text X="30" Y="110" Width="-30" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Text>
<Button Name="UninstallButton" X="90" Y="-100" Width="120" Height="50" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
<Button Name="RepairButton" X="110" Y="-60" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.ModifyRepairButton)</Button>
<Button Name="ModifyCancelButton" X="110" Y="-30" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.ModifyCloseButton)</Button>
</Page>
<Page Name="Success">
<Text Name="SuccessHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Success</Text>
<Text Name="SuccessInstallHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Installed successfully</Text>
<Text Name="SuccessRepairHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Repaired successfully</Text>
<Text Name="SuccessUninstallHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Uninstalled successfully</Text>
<Button Name="LaunchButton" X="90" Y="-100" Width="120" Height="50" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
<Button Name="SuccessCancelButton" X="110" Y="-60" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.SuccessCloseButton)</Button>
</Page>
<Page Name="Failure">
<Text Name="FailureHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureHeader)</Text>
<Text Name="FailureInstallHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Setup failed</Text>
<Text Name="FailureUninstallHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Uninstall failed</Text>
<Text Name="FailureRepairHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Repair failed</Text>
<Hypertext Name="FailureLogFileLink" X="30" Y="145" Width="-30" Height="50" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
<Hypertext Name="FailureMessageText" X="30" Y="195" Width="-30" Height="50" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
<Text Name="FailureRestartText" X="-30" Y="255" Width="400" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Text>
<Button Name="FailureRestartButton" X="90" Y="-100" Width="120" Height="50" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
<Button Name="FailureCloseButton" X="110" Y="-60" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.FailureCloseButton)</Button>
</Page>
</Theme>

View File

@@ -9,7 +9,7 @@
"core-js": "2.4.1",
"cross-env": "4.0.0",
"css-loader": "0.28.0",
"electron": "1.6.11",
"electron": "1.6.16",
"electron-builder": "17.1.1",
"electron-builder-squirrel-windows": "17.0.1",
"electron-rebuild": "1.5.11",
@@ -24,6 +24,7 @@
"node-gyp": "^3.6.2",
"node-sass": "^4.5.3",
"npmlog": "4.1.0",
"npx": "^9.7.1",
"pug": "2.0.0-beta11",
"pug-html-loader": "1.0.9",
"pug-loader": "2.3.0",
@@ -42,7 +43,8 @@
"url-loader": "0.5.7",
"val-loader": "0.5.0",
"webpack": "^3.0.0",
"yaml-loader": "0.4.0"
"yaml-loader": "0.4.0",
"yarn": "^1.3.2"
},
"build": {
"appId": "org.terminus",

View File

@@ -4,16 +4,19 @@ const path = require('path')
const vars = require('./vars')
const log = require('npmlog')
const localBinPath = path.resolve(__dirname, '../node_modules/.bin');
const npx = `${localBinPath}/npx`;
log.info('deps', 'app')
sh.exec('yarn install')
sh.exec(`${npx} yarn install`)
sh.cd('app')
sh.exec('yarn install')
sh.exec(`${npx} yarn install`)
sh.cd('..')
vars.builtinPlugins.forEach(plugin => {
log.info('deps', plugin)
sh.cd(plugin)
sh.exec('yarn install')
sh.exec(`${npx} yarn install`)
sh.cd('..')
})

View File

@@ -1,44 +1,54 @@
!
! Generated with :
! XRDB2Xreources.py
!
*.foreground: #d8d8d8
*.background: #181818
*.cursorColor: #d8d8d8
!
! Black
*.color0: #181818
*.color8: #585858
!
! Red
*.color1: #ab4642
*.color9: #ab4642
!
! Green
*.color2: #a1b56c
*.color10: #a1b56c
!
! Yellow
*.color3: #f7ca88
*.color11: #f7ca88
!
! Blue
*.color4: #7cafc2
*.color12: #7cafc2
!
! Magenta
*.color5: #ba8baf
*.color13: #ba8baf
!
! Cyan
*.color6: #86c1b9
*.color14: #86c1b9
!
! White
*.color7: #d8d8d8
*.color15: #f8f8f8
!
! Bold, Italic, Underline
*.colorBD: #d8d8d8
!*.colorIT:
!*.colorUL:
! Base16 Default Dark
! Scheme: Chris Kempson (http://chriskempson.com)
#define base00 #181818
#define base01 #282828
#define base02 #383838
#define base03 #585858
#define base04 #b8b8b8
#define base05 #d8d8d8
#define base06 #e8e8e8
#define base07 #f8f8f8
#define base08 #ab4642
#define base09 #dc9656
#define base0A #f7ca88
#define base0B #a1b56c
#define base0C #86c1b9
#define base0D #7cafc2
#define base0E #ba8baf
#define base0F #a16946
*.foreground: base05
#ifdef background_opacity
*.background: [background_opacity]base00
#else
*.background: base00
#endif
*.cursorColor: base05
*.color0: base00
*.color1: base08
*.color2: base0B
*.color3: base0A
*.color4: base0D
*.color5: base0E
*.color6: base0C
*.color7: base05
*.color8: base03
*.color9: base08
*.color10: base0B
*.color11: base0A
*.color12: base0D
*.color13: base0E
*.color14: base0C
*.color15: base07
! Note: colors beyond 15 might not be loaded (e.g., xterm, urxvt),
! use 'shell' template to set these if necessary
*.color16: base09
*.color17: base0F
*.color18: base01
*.color19: base02
*.color20: base04
*.color21: base06

View File

@@ -10,13 +10,23 @@ export class ColorSchemes extends TerminalColorSchemeProvider {
schemeContents.keys().forEach(schemeFile => {
let lines = (schemeContents(schemeFile) as string).split('\n')
// process #define variables
let variables: any = {}
lines
.filter(x => x.startsWith('#define'))
.map(x => x.split(' ').map(v => v.trim()))
.forEach(([ignore, variableName, variableValue]) => {
variables[variableName] = variableValue
})
let values: any = {}
lines
.filter(x => x.startsWith('*.'))
.map(x => x.substring(2))
.map(x => x.split(':').map(v => v.trim()))
.forEach(([key, value]) => {
values[key] = value
values[key] = variables[value] ? variables[value] : value
})
let colors: string[] = []

View File

@@ -1,12 +1,13 @@
title-bar(
*ngIf='config.store.appearance.frame == "full" && config.store.appearance.dock == "off"',
*ngIf='!hostApp.getWindow().isFullScreen() && config.store.appearance.frame == "full" && config.store.appearance.dock == "off"',
[class.inset]='hostApp.platform == Platform.macOS'
)
.content(
[class.tabs-on-top]='config.store.appearance.tabsLocation == "top"'
[class.tabs-on-top]='config.store.appearance.tabsLocation == "top"'
)
.tab-bar(
*ngIf='!hostApp.getWindow().isFullScreen()',
[class.inset]='hostApp.platform == Platform.macOS && config.store.appearance.frame == "thin" && config.store.appearance.tabsLocation == "top"'
)
.tabs
@@ -20,7 +21,7 @@ title-bar(
@animateTab,
(click)='app.selectTab(tab)',
)
.btn-group
button.btn.btn-secondary.btn-tab-bar(
*ngFor='let button of leftToolbarButtons',
@@ -28,9 +29,9 @@ title-bar(
(click)='button.click()',
)
i.fa([class]='"fa fa-" + button.icon')
.drag-space(*ngIf='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS')
.drag-space([class.persistent]='config.store.appearance.frame == "thin" && hostApp.platform != Platform.macOS')
.btn-group
button.btn.btn-secondary.btn-tab-bar(
*ngFor='let button of rightToolbarButtons',
@@ -53,7 +54,7 @@ title-bar(
start-page(*ngIf='ready && app.tabs.length == 0')
tab-body(
*ngFor='let tab of app.tabs; trackBy: tab?.id',
*ngFor='let tab of app.tabs; trackBy: tab?.id',
[active]='tab == app.activeTab',
[tab]='tab',
[scrollable]='tab.scrollable',

View File

@@ -7,6 +7,7 @@
-webkit-user-select: none;
-webkit-user-drag: none;
-webkit-font-smoothing: antialiased;
will-change: transform;
cursor: default;
animation: 0.5s ease-out fadeIn;
}
@@ -55,15 +56,20 @@ $tab-border-radius: 4px;
}
&>.drag-space {
min-width: 100px;
flex: 1 0 25%;
min-width: 1px;
flex: 1 0 1%;
-webkit-app-region: drag;
&.persistent {
min-width: 100px;
flex: 1 0 25%;
}
}
&.inset {
padding-left: 85px;
}
window-controls {
margin-left: 10px;
}

View File

@@ -97,6 +97,9 @@ export class AppRootComponent {
this.app.previousTab()
}
}
if (hotkey === 'toggle-fullscreen') {
this.hostApp.toggleFullscreen()
}
})
this.docking.dock()

View File

@@ -1,6 +1,8 @@
hotkeys:
toggle-window:
- 'Ctrl+Space'
toggle-fullscreen:
- 'F11'
close-tab:
- 'Ctrl-Shift-W'
- ['Ctrl-A', 'K']
@@ -10,9 +12,11 @@ hotkeys:
next-tab:
- 'Ctrl-Shift-ArrowRight'
- ['Ctrl-A', 'N']
- 'Ctrl-Tab'
previous-tab:
- 'Ctrl-Shift-ArrowLeft'
- ['Ctrl-A', 'P']
- 'Ctrl-Shift-Tab'
tab-1:
- 'Alt-1'
- ['Ctrl-A', '1']

View File

@@ -1,46 +1,33 @@
hotkeys:
toggle-window:
- 'Ctrl+Space'
toggle-fullscreen:
- 'Ctrl+⌘+F'
close-tab:
- '⌘-W'
- ['Ctrl-A', 'K']
toggle-last-tab:
- ['Ctrl-A', 'A']
- ['Ctrl-A', 'Ctrl-A']
toggle-last-tab: []
next-tab:
- '⌘-ArrowRight'
- ['Ctrl-A', 'N']
- 'Ctrl-Tab'
previous-tab:
- '⌘-ArrowLeft'
- ['Ctrl-A', 'P']
- 'Ctrl-Shift-Tab'
tab-1:
- '⌘-1'
- ['Ctrl-A', '1']
tab-2:
- '⌘-2'
- ['Ctrl-A', '2']
tab-3:
- '⌘-3'
- ['Ctrl-A', '3']
tab-4:
- '⌘-4'
- ['Ctrl-A', '4']
tab-5:
- '⌘-5'
- ['Ctrl-A', '5']
tab-6:
- '⌘-6'
- ['Ctrl-A', '6']
tab-7:
- '⌘-7'
- ['Ctrl-A', '7']
tab-8:
- '⌘-8'
- ['Ctrl-A', '8']
tab-9:
- '⌘-9'
- ['Ctrl-A', '9']
tab-10:
- '⌘-0'
- ['Ctrl-A', '0']
pluginBlacklist: ['ssh']

View File

@@ -1,6 +1,8 @@
hotkeys:
toggle-window:
- 'Ctrl+Space'
toggle-fullscreen:
- 'F11'
close-tab:
- 'Ctrl-Shift-W'
- ['Ctrl-A', 'K']
@@ -10,9 +12,11 @@ hotkeys:
next-tab:
- 'Ctrl-Shift-ArrowRight'
- ['Ctrl-A', 'N']
- 'Ctrl-Tab'
previous-tab:
- 'Ctrl-Shift-ArrowLeft'
- ['Ctrl-A', 'P']
- 'Ctrl-Shift-Tab'
tab-1:
- 'Alt-1'
- ['Ctrl-A', '1']

View File

@@ -3,6 +3,7 @@ appearance:
dockScreen: current
dockFill: 50
tabsLocation: top
cycleTabs: true
theme: Standard
frame: thin
css: '/* * { color: blue !important; } */'

View File

@@ -3,6 +3,7 @@ import { Injectable, ComponentFactoryResolver, Injector, Optional } from '@angul
import { DefaultTabProvider } from '../api/defaultTabProvider'
import { BaseTabComponent } from '../components/baseTab.component'
import { Logger, LogService } from '../services/log.service'
import { ConfigService } from '../services/config.service'
export declare type TabComponentType = new (...args: any[]) => BaseTabComponent
@@ -18,6 +19,7 @@ export class AppService {
constructor (
private componentFactoryResolver: ComponentFactoryResolver,
@Optional() private defaultTabProvider: DefaultTabProvider,
private config: ConfigService,
private injector: Injector,
log: LogService,
) {
@@ -70,16 +72,24 @@ export class AppService {
}
nextTab () {
let tabIndex = this.tabs.indexOf(this.activeTab)
if (tabIndex < this.tabs.length - 1) {
this.selectTab(this.tabs[tabIndex + 1])
if (this.tabs.length > 1) {
let tabIndex = this.tabs.indexOf(this.activeTab)
if (tabIndex < this.tabs.length - 1) {
this.selectTab(this.tabs[tabIndex + 1])
} else if (this.config.store.appearance.cycleTabs) {
this.selectTab(this.tabs[0])
}
}
}
previousTab () {
let tabIndex = this.tabs.indexOf(this.activeTab)
if (tabIndex > 0) {
this.selectTab(this.tabs[tabIndex - 1])
if (this.tabs.length > 1) {
let tabIndex = this.tabs.indexOf(this.activeTab)
if (tabIndex > 0) {
this.selectTab(this.tabs[tabIndex - 1])
} else if (this.config.store.appearance.cycleTabs) {
this.selectTab(this.tabs[this.tabs.length - 1])
}
}
}

View File

@@ -73,8 +73,13 @@ export class HostAppService {
return this.electron.app.getPath(type)
}
toggleFullscreen () {
let window = this.getWindow()
window.setFullScreen(!window.isFullScreen())
}
openDevTools () {
this.getWindow().webContents.openDevTools()
this.getWindow().webContents.openDevTools({ mode: 'undocked' })
}
focusWindow () {

View File

@@ -178,6 +178,10 @@ export class AppHotkeyProvider extends HotkeyProvider {
id: 'toggle-window',
name: 'Toggle terminal window',
},
{
id: 'toggle-fullscreen',
name: 'Toggle fullscreen mode',
},
{
id: 'close-tab',
name: 'Close tab',

View File

@@ -5,7 +5,7 @@ export const metaKeyName = {
}[process.platform]
export const altKeyName = {
darwin: 'Option',
darwin: '',
win32: 'Alt',
linux: 'Alt',
}[process.platform]

View File

@@ -22,6 +22,7 @@
"apply-loader": "^2.0.0",
"awesome-typescript-loader": "^3.1.2",
"electron": "^1.6.11",
"ngx-toastr": "^8.0.0",
"pug": "^2.0.0-rc.3",
"pug-loader": "^2.3.0",
"rxjs": "^5.4.0",

View File

@@ -3,6 +3,7 @@ import { BaseSession } from 'terminus-terminal'
export interface SSHConnection {
name?: string
host: string
port: number
user: string
password?: string
privateKey?: string

View File

@@ -13,6 +13,14 @@
[(ngModel)]='connection.host',
)
.form-group
label Port
input.form-control(
type='number',
placeholder='22',
[(ngModel)]='connection.port',
)
.form-group
label Username
input.form-control(

View File

@@ -20,7 +20,6 @@ export class EditConnectionModalComponent {
this.hostApp.getWindow(),
{
title: 'Select private key',
properties: ['openDirectory']
}
)
if (path) {

View File

@@ -3,7 +3,7 @@
type='text',
[(ngModel)]='quickTarget',
autofocus,
placeholder='Quick connect: [user@]host',
placeholder='Quick connect: [user@]host[:port]',
(keyup.enter)='quickConnect()'
)

View File

@@ -1,5 +1,6 @@
import { Component } from '@angular/core'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { ToastrService } from 'ngx-toastr'
import { ConfigService, AppService } from 'terminus-core'
import { SettingsTabComponent } from 'terminus-settings'
import { SSHService } from '../services/ssh.service'
@@ -19,6 +20,7 @@ export class SSHModalComponent {
private config: ConfigService,
private ssh: SSHService,
private app: AppService,
private toastr: ToastrService,
) { }
ngOnInit () {
@@ -31,12 +33,18 @@ export class SSHModalComponent {
quickConnect () {
let user = 'root'
let host = this.quickTarget
let port = 22
if (host.includes('@')) {
[user, host] = host.split('@')
}
if (host.includes(':')) {
port = parseInt(host.split(':')[1])
host = host.split(':')[0]
}
let connection: SSHConnection = {
name: this.quickTarget,
host, user,
host, user, port
}
window.localStorage.lastConnection = JSON.stringify(connection)
this.connect(connection)
@@ -45,7 +53,7 @@ export class SSHModalComponent {
connect (connection: SSHConnection) {
this.close()
this.ssh.connect(connection).catch(error => {
alert(`Could not connect: ${error}`)
this.toastr.error(`Could not connect: ${error}`)
})
}

View File

@@ -21,6 +21,7 @@ export class SSHSettingsTabComponent {
let connection: SSHConnection = {
name: '',
host: '',
port: 22,
user: 'root',
}
let modal = this.ngbModal.open(EditConnectionModalComponent)

View File

@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'
import { FormsModule } from '@angular/forms'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { ToastrModule } from 'ngx-toastr'
import { ToolbarButtonProvider, ConfigProvider } from 'terminus-core'
import { SettingsTabProvider } from 'terminus-settings'
@@ -10,6 +11,7 @@ import { SSHModalComponent } from './components/sshModal.component'
import { PromptModalComponent } from './components/promptModal.component'
import { SSHSettingsTabComponent } from './components/sshSettingsTab.component'
import { SSHService } from './services/ssh.service'
import { PasswordStorageService } from './services/passwordStorage.service'
import { ButtonProvider } from './buttonProvider'
import { SSHConfigProvider } from './config'
@@ -20,8 +22,10 @@ import { SSHSettingsTabProvider } from './settings'
NgbModule,
CommonModule,
FormsModule,
ToastrModule,
],
providers: [
PasswordStorageService,
SSHService,
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
{ provide: ConfigProvider, useClass: SSHConfigProvider, multi: true },

View File

@@ -0,0 +1,73 @@
import { Injectable, NgZone } from '@angular/core'
import { SSHConnection } from '../api'
let xkeychain
let wincredmgr
try {
xkeychain = require('xkeychain')
} catch (error) {
try {
wincredmgr = require('wincredmgr')
} catch (error2) {
console.warn('No keychain manager available')
}
}
@Injectable()
export class PasswordStorageService {
constructor (
private zone: NgZone,
) { }
savePassword (connection: SSHConnection, password: string) {
if (xkeychain) {
xkeychain.setPassword({
account: connection.user,
service: `ssh@${connection.host}`,
password
}, () => null)
} else {
wincredmgr.WriteCredentials(
'user',
password,
`ssh:${connection.user}@${connection.host}`,
)
}
}
deletePassword (connection: SSHConnection) {
if (xkeychain) {
xkeychain.deletePassword({
account: connection.user,
service: `ssh@${connection.host}`,
}, () => null)
} else {
wincredmgr.DeleteCredentials(
`ssh:${connection.user}@${connection.host}`,
)
}
}
loadPassword (connection: SSHConnection): Promise<string> {
return new Promise(resolve => {
if (!wincredmgr && !xkeychain.isSupported()) {
return resolve(null)
}
if (xkeychain) {
xkeychain.getPassword(
{
account: connection.user,
service: `ssh@${connection.host}`,
},
(_, result) => this.zone.run(() => resolve(result))
)
} else {
try {
resolve(wincredmgr.ReadCredentials(`ssh:${connection.user}@${connection.host}`).password)
} catch (error) {
resolve(null)
}
}
})
}
}

View File

@@ -2,87 +2,62 @@ import { Injectable, NgZone } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { Client } from 'ssh2'
import * as fs from 'mz/fs'
import { AppService } from 'terminus-core'
import * as path from 'path'
import { ToastrService } from 'ngx-toastr'
import { AppService, HostAppService, Platform, Logger, LogService } from 'terminus-core'
import { TerminalTabComponent } from 'terminus-terminal'
import { SSHConnection, SSHSession } from '../api'
import { PromptModalComponent } from '../components/promptModal.component'
import { PasswordStorageService } from './passwordStorage.service'
const { SSH2Stream } = require('ssh2-streams')
let xkeychain
let wincredmgr
try {
console.log(1)
xkeychain = require('xkeychain')
} catch (error) {
try {
wincredmgr = require('wincredmgr')
} catch (error2) {
console.warn('No keychain manager available')
}
}
@Injectable()
export class SSHService {
private logger: Logger
constructor (
log: LogService,
private app: AppService,
private zone: NgZone,
private ngbModal: NgbModal,
private hostApp: HostAppService,
private passwordStorage: PasswordStorageService,
private toastr: ToastrService,
) {
}
savePassword (connection: SSHConnection, password: string) {
if (xkeychain) {
xkeychain.setPassword({
account: connection.user,
service: `ssh@${connection.host}`,
password
}, () => null)
} else {
wincredmgr.WriteCredentials(
'user',
password,
`ssh:${connection.user}@${connection.host}`,
)
}
}
deletePassword (connection: SSHConnection) {
if (xkeychain) {
xkeychain.deletePassword({
account: connection.user,
service: `ssh@${connection.host}`,
}, () => null)
} else {
wincredmgr.DeleteCredentials(
`ssh:${connection.user}@${connection.host}`,
)
}
}
loadPassword (connection: SSHConnection): Promise<string> {
return new Promise(resolve => {
if (xkeychain) {
xkeychain.getPassword({
account: connection.user,
service: `ssh@${connection.host}`,
}, (_, result) => resolve(result))
} else {
try {
resolve(wincredmgr.ReadCredentials(`ssh:${connection.user}@${connection.host}`).password)
} catch (error) {
resolve(null)
}
}
})
this.logger = log.create('ssh')
}
async connect (connection: SSHConnection): Promise<TerminalTabComponent> {
let privateKey: string = null
if (connection.privateKey) {
let privateKeyPassphrase: string = null
let privateKeyPath = connection.privateKey
if (!privateKeyPath) {
let userKeyPath = path.join(process.env.HOME, '.ssh', 'id_rsa')
if (await fs.exists(userKeyPath)) {
this.logger.info('Using user\'s default private key:', userKeyPath)
privateKeyPath = userKeyPath
}
}
if (privateKeyPath) {
try {
privateKey = (await fs.readFile(connection.privateKey)).toString()
} catch (error) { }
privateKey = (await fs.readFile(privateKeyPath)).toString()
} catch (error) {
this.toastr.warning('Could not read the private key file')
}
if (privateKey) {
this.logger.info('Loaded private key from', privateKeyPath)
if (privateKey.includes('ENCRYPTED')) {
let modal = this.ngbModal.open(PromptModalComponent)
modal.componentInstance.prompt = 'Private key passphrase'
modal.componentInstance.password = true
try {
privateKeyPassphrase = await modal.result
} catch (_err) { }
}
}
}
let ssh = new Client()
@@ -91,14 +66,16 @@ export class SSHService {
await new Promise((resolve, reject) => {
ssh.on('ready', () => {
connected = true
this.savePassword(connection, savedPassword)
if (savedPassword) {
this.passwordStorage.savePassword(connection, savedPassword)
}
this.zone.run(resolve)
})
ssh.on('error', error => {
this.deletePassword(connection)
this.passwordStorage.deletePassword(connection)
this.zone.run(() => {
if (connected) {
alert(`SSH error: ${error}`)
this.toastr.error(error.toString())
} else {
reject(error)
}
@@ -115,24 +92,38 @@ export class SSHService {
}
finish(results)
}))
let agent: string = null
if (this.hostApp.platform === Platform.Windows) {
agent = 'pageant'
} else {
agent = process.env.SSH_AUTH_SOCK
}
ssh.connect({
host: connection.host,
port: connection.port || 22,
username: connection.user,
password: privateKey ? undefined : '',
password: connection.privateKey ? undefined : '',
privateKey,
passphrase: privateKeyPassphrase,
tryKeyboard: true,
agent,
agentForward: !!agent,
})
let keychainPasswordUsed = false
;(ssh as any).config.password = () => this.zone.run(async () => {
if (connection.password) {
this.logger.info('Using preset password')
return connection.password
}
if (!keychainPasswordUsed && (wincredmgr || xkeychain.isSupported())) {
let password = await this.loadPassword(connection)
if (!keychainPasswordUsed) {
let password = await this.passwordStorage.loadPassword(connection)
if (password) {
this.logger.info('Using saved password')
keychainPasswordUsed = true
return password
}

View File

@@ -39,6 +39,8 @@ module.exports = {
'node-ssh',
'xkeychain',
'wincredmgr',
'path',
'ngx-toastr',
/^rxjs/,
/^@angular/,
/^@ng-bootstrap/,

View File

@@ -2,9 +2,13 @@
# yarn lockfile v1
"@types/node@*", "@types/node@^8.0.24":
version "8.0.53"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8"
"@types/node@*":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.3.0.tgz#3a129cda7c4e5df2409702626892cb4b96546dd5"
"@types/node@^7.0.18":
version "7.0.52"
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.52.tgz#8990d3350375542b0c21a83cd0331e6a8fc86716"
"@types/ssh2-streams@*":
version "0.1.2"
@@ -20,8 +24,8 @@
"@types/ssh2-streams" "*"
"@types/webpack-env@^1.13.0":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.2.tgz#c290b99dbef74df21b06671aea36e355bf3b27e1"
version "1.13.3"
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.3.tgz#0ecbe70f87341767793774d3683b51aa3246434c"
abbrev@1:
version "1.1.1"
@@ -48,8 +52,8 @@ acorn@^4.0.3, acorn@^4.0.4, acorn@~4.0.2:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
acorn@^5.0.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7"
version "5.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822"
ajv-keywords@^1.1.1:
version "1.5.1"
@@ -63,8 +67,8 @@ ajv@^4.7.0, ajv@^4.9.1:
json-stable-stringify "^1.0.1"
ajv@^5.1.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.0.tgz#eb2840746e9dc48bd5e063a36e3fd400c5eab5a9"
version "5.5.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
dependencies:
co "^4.6.0"
fast-deep-equal "^1.0.0"
@@ -171,6 +175,10 @@ assert@^1.1.1:
dependencies:
util "0.10.3"
assign-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@@ -190,8 +198,8 @@ atob@^2.0.0:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d"
awesome-typescript-loader@^3.1.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/awesome-typescript-loader/-/awesome-typescript-loader-3.4.0.tgz#aed2c83af614d617d11e3ec368ac3befb55d002f"
version "3.4.1"
resolved "https://registry.yarnpkg.com/awesome-typescript-loader/-/awesome-typescript-loader-3.4.1.tgz#22fa49800f0619ec18ab15383aef93b95378dea9"
dependencies:
colors "^1.1.2"
enhanced-resolve "3.3.0"
@@ -456,13 +464,12 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
safe-buffer "^5.0.1"
class-utils@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.5.tgz#17e793103750f9627b2176ea34cfd1b565903c80"
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
dependencies:
arr-union "^3.1.0"
define-property "^0.2.5"
isobject "^3.0.0"
lazy-cache "^2.0.2"
static-extend "^0.1.1"
clean-css@^3.3.0:
@@ -721,10 +728,10 @@ electron-download@^3.0.1:
sumchecker "^1.2.0"
electron@^1.6.11:
version "1.8.1"
resolved "https://registry.yarnpkg.com/electron/-/electron-1.8.1.tgz#19b6f39f2013e204a91a60bc3086dc7a4a07ed88"
version "1.7.10"
resolved "https://registry.yarnpkg.com/electron/-/electron-1.7.10.tgz#3a3e83d965fd7fafe473be8ddf8f472561b6253d"
dependencies:
"@types/node" "^8.0.24"
"@types/node" "^7.0.18"
electron-download "^3.0.1"
extract-zip "^1.0.3"
@@ -744,7 +751,7 @@ emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
enhanced-resolve@3.3.0, enhanced-resolve@^3.3.0:
enhanced-resolve@3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.3.0.tgz#950964ecc7f0332a42321b673b38dc8ff15535b3"
dependencies:
@@ -753,11 +760,20 @@ enhanced-resolve@3.3.0, enhanced-resolve@^3.3.0:
object-assign "^4.0.1"
tapable "^0.2.5"
errno@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
enhanced-resolve@^3.3.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
dependencies:
prr "~0.0.0"
graceful-fs "^4.1.2"
memory-fs "^0.4.0"
object-assign "^4.0.1"
tapable "^0.2.7"
errno@^0.1.3:
version "0.1.6"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.6.tgz#c386ce8a6283f14fc09563b71560908c9bf53026"
dependencies:
prr "~1.0.1"
error-ex@^1.2.0:
version "1.3.1"
@@ -766,8 +782,8 @@ error-ex@^1.2.0:
is-arrayish "^0.2.1"
es6-promise@^4.0.5:
version "4.1.1"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a"
version "4.2.2"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.2.tgz#f722d7769af88bd33bc13ec6605e1f92966b82d9"
events@^1.0.0:
version "1.1.1"
@@ -811,9 +827,10 @@ extend-shallow@^2.0.1:
is-extendable "^0.1.0"
extend-shallow@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.1.tgz#4b6d8c49b147fee029dc9eb9484adb770f689844"
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
dependencies:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
extend@~3.0.0, extend@~3.0.1:
@@ -827,8 +844,8 @@ extglob@^0.3.1:
is-extglob "^1.0.0"
extglob@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.2.tgz#3290f46208db1b2e8eb8be0c94ed9e6ad80edbe2"
version "2.0.4"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
dependencies:
array-unique "^0.3.2"
define-property "^1.0.0"
@@ -848,10 +865,14 @@ extract-zip@^1.0.3:
mkdirp "0.5.0"
yauzl "2.4.1"
extsprintf@1.3.0, extsprintf@^1.2.0:
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
fast-deep-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
@@ -1216,8 +1237,8 @@ ini@~1.3.0:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
interpret@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0"
version "1.1.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
invert-kv@^1.0.0:
version "1.0.0"
@@ -1229,6 +1250,12 @@ is-accessor-descriptor@^0.1.6:
dependencies:
kind-of "^3.0.2"
is-accessor-descriptor@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
dependencies:
kind-of "^6.0.0"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -1255,6 +1282,12 @@ is-data-descriptor@^0.1.4:
dependencies:
kind-of "^3.0.2"
is-data-descriptor@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
dependencies:
kind-of "^6.0.0"
is-descriptor@^0.1.0:
version "0.1.6"
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
@@ -1264,12 +1297,12 @@ is-descriptor@^0.1.0:
kind-of "^5.0.0"
is-descriptor@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.1.tgz#2c6023599bde2de9d5d2c8b9a9d94082036b6ef2"
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
dependencies:
is-accessor-descriptor "^0.1.6"
is-data-descriptor "^0.1.4"
kind-of "^5.0.0"
is-accessor-descriptor "^1.0.0"
is-data-descriptor "^1.0.0"
kind-of "^6.0.2"
is-dotfile@^1.0.0:
version "1.0.3"
@@ -1475,9 +1508,9 @@ kind-of@^5.0.0, kind-of@^5.0.2:
version "5.1.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
kind-of@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.1.tgz#4948e6263553ac3712fc44d305b77851d9e40ea4"
kind-of@^6.0.0, kind-of@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
klaw@^1.0.0:
version "1.3.1"
@@ -1609,8 +1642,8 @@ micromatch@^2.1.5:
regex-cache "^0.4.2"
micromatch@^3.0.3:
version "3.1.4"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.4.tgz#bb812e741a41f982c854e42b421a7eac458796f4"
version "3.1.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.5.tgz#d05e168c206472dfbca985bfef4f57797b4cd4ba"
dependencies:
arr-diff "^4.0.0"
array-unique "^0.3.2"
@@ -1666,11 +1699,11 @@ minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
mixin-deep@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.2.0.tgz#d02b8c6f8b6d4b8f5982d3fd009c4919851c3fe2"
version "1.3.0"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.0.tgz#47a8732ba97799457c8c1eca28f95132d7e8150a"
dependencies:
for-in "^1.0.2"
is-extendable "^0.1.1"
is-extendable "^1.0.1"
mkdirp@0.5.0:
version "0.5.0"
@@ -1693,8 +1726,8 @@ nan@^2.3.0:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a"
nanomatch@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.5.tgz#5c9ab02475c76676275731b0bf0a7395c624a9c4"
version "1.2.7"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.7.tgz#53cd4aa109ff68b7f869591fdc9d10daeeea3e79"
dependencies:
arr-diff "^4.0.0"
array-unique "^0.3.2"
@@ -1708,6 +1741,10 @@ nanomatch@^1.2.5:
snapdragon "^0.8.1"
to-regex "^3.0.1"
ngx-toastr@^8.0.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/ngx-toastr/-/ngx-toastr-8.1.0.tgz#3a0742e62895f88e232607843d61373d6f0d44d3"
node-libs-browser@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
@@ -2000,9 +2037,9 @@ promise@^7.0.1:
dependencies:
asap "~2.0.3"
prr@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
public-encrypt@^4.0.0:
version "4.0.0"
@@ -2147,8 +2184,8 @@ randomatic@^1.1.3:
kind-of "^4.0.0"
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
version "2.0.6"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80"
dependencies:
safe-buffer "^5.1.0"
@@ -2160,8 +2197,8 @@ randomfill@^1.0.3:
safe-buffer "^5.1.0"
rc@^1.1.2, rc@^1.1.7:
version "1.2.2"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077"
version "1.2.4"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.4.tgz#a0f606caae2a3b862bbd0ef85482c0125b315fa3"
dependencies:
deep-extend "~0.4.0"
ini "~1.3.0"
@@ -2183,7 +2220,7 @@ read-pkg@^1.0.0:
normalize-package-data "^2.3.2"
path-type "^1.0.0"
readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6, readable-stream@^2.3.3:
readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
dependencies:
@@ -2342,18 +2379,18 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
inherits "^2.0.1"
rxjs@^5.4.0:
version "5.5.2"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.2.tgz#28d403f0071121967f18ad665563255d54236ac3"
version "5.5.6"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.6.tgz#e31fb96d6fd2ff1fd84bcea8ae9c02d007179c02"
dependencies:
symbol-observable "^1.0.1"
symbol-observable "1.0.1"
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
@@ -2552,12 +2589,12 @@ stream-browserify@^2.0.1:
readable-stream "^2.0.2"
stream-http@^2.7.2:
version "2.7.2"
resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
version "2.8.0"
resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10"
dependencies:
builtin-status-codes "^3.0.0"
inherits "^2.0.1"
readable-stream "^2.2.6"
readable-stream "^2.3.3"
to-arraybuffer "^1.0.0"
xtend "^4.0.0"
@@ -2622,11 +2659,11 @@ supports-color@^3.1.0:
dependencies:
has-flag "^1.0.0"
symbol-observable@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
symbol-observable@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
tapable@^0.2.5, tapable@~0.2.5:
tapable@^0.2.5, tapable@^0.2.7, tapable@~0.2.5:
version "0.2.8"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
@@ -2726,8 +2763,8 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
typescript@^2.2.2:
version "2.6.1"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.1.tgz#ef39cdea27abac0b500242d6726ab90e0c846631"
version "2.6.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
uglify-js@^2.6.1, uglify-js@^2.8.27:
version "2.8.29"
@@ -2792,8 +2829,8 @@ util@0.10.3, util@^0.10.3:
inherits "2.0.1"
uuid@^3.0.0, uuid@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
version "3.2.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
validate-npm-package-license@^3.0.1:
version "3.0.1"

View File

@@ -16,7 +16,13 @@ export class HyperColorSchemes extends TerminalColorSchemeProvider {
try {
let module = (global as any).require(path.join(pluginsPath, plugin))
if (module.decorateConfig) {
let config = module.decorateConfig({})
let config: any
try {
config = module.decorateConfig({})
} catch (error) {
console.warn('Could not load Hyper theme:', plugin)
return
}
if (config.colors) {
themes.push({
name: plugin,

View File

@@ -88,20 +88,40 @@ export class TerminalTabComponent extends BaseTabComponent {
if (!this.hasFocus) {
return
}
if (hotkey === 'copy') {
this.hterm.copySelectionToClipboard()
}
if (hotkey === 'clear') {
this.clear()
}
if (hotkey === 'zoom-in') {
this.zoomIn()
}
if (hotkey === 'zoom-out') {
this.zoomOut()
}
if (hotkey === 'reset-zoom') {
this.resetZoom()
switch (hotkey) {
case 'copy':
this.hterm.copySelectionToClipboard()
break
case 'clear':
this.clear()
break
case 'zoom-in':
this.zoomIn()
break
case 'zoom-out':
this.zoomOut()
break
case 'reset-zoom':
this.resetZoom()
break
case 'home':
this.sendInput('\x1bOH')
break
case 'end':
this.sendInput('\x1bOF')
break
case 'previous-word':
this.sendInput('\x1bb')
break
case 'next-word':
this.sendInput('\x1bf')
break
case 'delete-previous-word':
this.sendInput('\x1b\x7f')
break
case 'delete-next-word':
this.sendInput('\x1bd')
break
}
})
this.bellPlayer = document.createElement('audio')
@@ -321,7 +341,7 @@ export class TerminalTabComponent extends BaseTabComponent {
this.hterm.onVTKeystroke('\f')
}
async configure (): Promise<void> {
configure (): void {
let config = this.config.store
preferenceManager.set('font-family', `"${config.terminal.font}", "monospace-fallback", monospace`)
this.setFontSize()

View File

@@ -75,7 +75,13 @@ export class TerminalConfigProvider extends ConfigProvider {
['Ctrl-A', 'Ctrl-C'],
'⌘-T',
'⌘-N',
]
],
'home': ['⌘-ArrowLeft', 'Home'],
'end': ['⌘-ArrowRight', 'End'],
'previous-word': ['⌥-ArrowLeft'],
'next-word': ['⌥-ArrowRight'],
'delete-previous-word': ['⌥-Backspace'],
'delete-next-word': ['⌥-Delete'],
},
},
[Platform.Windows]: {
@@ -108,7 +114,13 @@ export class TerminalConfigProvider extends ConfigProvider {
['Ctrl-A', 'C'],
['Ctrl-A', 'Ctrl-C'],
'Ctrl-Shift-T',
]
],
'home': ['Home'],
'end': ['End'],
'previous-word': ['Ctrl-ArrowLeft'],
'next-word': ['Ctrl-ArrowRight'],
'delete-previous-word': ['Ctrl-Backspace'],
'delete-next-word': ['Ctrl-Delete'],
},
},
[Platform.Linux]: {
@@ -139,7 +151,13 @@ export class TerminalConfigProvider extends ConfigProvider {
['Ctrl-A', 'C'],
['Ctrl-A', 'Ctrl-C'],
'Ctrl-Shift-T',
]
],
'home': ['Home'],
'end': ['End'],
'previous-word': ['Ctrl-ArrowLeft'],
'next-word': ['Ctrl-ArrowRight'],
'delete-previous-word': ['Ctrl-Backspace'],
'delete-next-word': ['Ctrl-Delete'],
},
},
}

View File

@@ -8,6 +8,30 @@ export class TerminalHotkeyProvider extends HotkeyProvider {
id: 'copy',
name: 'Copy to clipboard',
},
{
id: 'home',
name: 'Beginning of the line',
},
{
id: 'end',
name: 'End of the line',
},
{
id: 'previous-word',
name: 'Jump to previous word',
},
{
id: 'next-word',
name: 'Jump to next word',
},
{
id: 'delete-previous-word',
name: 'Delete previous word',
},
{
id: 'delete-next-word',
name: 'Delete next word',
},
{
id: 'clear',
name: 'Clear terminal',

View File

@@ -8,6 +8,15 @@ a:hover {
x-screen {
transition: 0.125s ease background;
&::-webkit-scrollbar {
width: 3px;
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
}
}
x-row > span {

View File

@@ -153,8 +153,8 @@ export class TMux {
async create (id: string, options: SessionOptions): Promise<void> {
await this.ready
let args = [options.command].concat(options.args)
let cmd = args.map(x => `"${x.replace('"', '\\"')}"`)
let args = [options.command].concat(options.args.slice(1))
let cmd = args.map(x => `"${x.replace('"', '\\"')}"`).join(' ')
await this.process.command(
`new-session -s "${id}" -d`
+ (options.cwd ? ` -c '${options.cwd.replace("'", "\\'")}'` : '')

View File

@@ -34,7 +34,7 @@ export class TerminalService {
async openTab (shell?: IShell, cwd?: string): Promise<TerminalTabComponent> {
if (!cwd) {
if (this.app.activeTab instanceof TerminalTabComponent) {
if (this.app.activeTab instanceof TerminalTabComponent && this.app.activeTab.session) {
cwd = await this.app.activeTab.session.getWorkingDirectory()
} else {
cwd = this.config.store.terminal.workingDirectory || null

2297
yarn.lock

File diff suppressed because it is too large Load Diff