mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-19 15:51:53 +00:00
Compare commits
267 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8afad944b7 | ||
![]() |
707d077eb2 | ||
![]() |
92eabab509 | ||
![]() |
888cfc6548 | ||
![]() |
9cb10c3e21 | ||
![]() |
661d5af9ba | ||
![]() |
26429bf209 | ||
![]() |
4779c41f48 | ||
![]() |
b11eda8653 | ||
![]() |
23bff8750c | ||
![]() |
aab1ae3ceb | ||
![]() |
9b5b5a9d00 | ||
![]() |
9c87cf3f3a | ||
![]() |
a8c7134218 | ||
![]() |
9734830a74 | ||
![]() |
5fa056751d | ||
![]() |
6fdccd0a02 | ||
![]() |
1149d68d1c | ||
![]() |
1d92a3f89d | ||
![]() |
3557345d70 | ||
![]() |
86ebdd92b4 | ||
![]() |
4764ec8249 | ||
![]() |
b1752bd0b4 | ||
![]() |
1e697a952a | ||
![]() |
6bad2a2167 | ||
![]() |
61a46e3b4a | ||
![]() |
cba90cec0a | ||
![]() |
7583d92747 | ||
![]() |
e2b99d71ad | ||
![]() |
c829daac41 | ||
![]() |
aac38fa190 | ||
![]() |
7098622c8f | ||
![]() |
8695003c74 | ||
![]() |
43a27a7b7c | ||
![]() |
dd2d2ce20d | ||
![]() |
73574374f0 | ||
![]() |
5bd1bfd565 | ||
![]() |
0611afa8b5 | ||
![]() |
91c9e8affd | ||
![]() |
322ffc5847 | ||
![]() |
21084b5d24 | ||
![]() |
4c840a0db1 | ||
![]() |
e0efb4073a | ||
![]() |
c42b62afe6 | ||
![]() |
e2b11c83d5 | ||
![]() |
891fa5770a | ||
![]() |
6b395cc2b3 | ||
![]() |
448a1a094f | ||
![]() |
788dd61a13 | ||
![]() |
467684d9ab | ||
![]() |
5069070040 | ||
![]() |
ecf5297bc3 | ||
![]() |
78bd90ac55 | ||
![]() |
712589eb93 | ||
![]() |
f103e71285 | ||
![]() |
0cf883cc4a | ||
![]() |
2b0ad0d558 | ||
![]() |
67bacb9dd3 | ||
![]() |
d0a597634d | ||
![]() |
322014c409 | ||
![]() |
c751a8725b | ||
![]() |
5417efe558 | ||
![]() |
bf356fcd19 | ||
![]() |
10ee66b9dd | ||
![]() |
763da0d80c | ||
![]() |
8d46bb2181 | ||
![]() |
fe936c7726 | ||
![]() |
2f3e32990a | ||
![]() |
22344f8d54 | ||
![]() |
f6d37a39f4 | ||
![]() |
0e4c60ad4b | ||
![]() |
e8c2171d8f | ||
![]() |
f7a5be2c67 | ||
![]() |
39fa0424a6 | ||
![]() |
bcb1b6a13b | ||
![]() |
a19f35ac44 | ||
![]() |
ea92f1a700 | ||
![]() |
b5701cf9f9 | ||
![]() |
4742530cf3 | ||
![]() |
a8d78ce185 | ||
![]() |
bba1eaccbe | ||
![]() |
cd6d05aa69 | ||
![]() |
412403c72a | ||
![]() |
93ae907dd1 | ||
![]() |
ce24b9cc52 | ||
![]() |
dc68372d76 | ||
![]() |
e0fe125cf2 | ||
![]() |
e594fcd0e7 | ||
![]() |
0219da4d85 | ||
![]() |
5e06b2248b | ||
![]() |
cdc3623986 | ||
![]() |
6d016002c0 | ||
![]() |
f3569f5d2d | ||
![]() |
4125582ef2 | ||
![]() |
c6331c9b1c | ||
![]() |
aaab475e5f | ||
![]() |
e6bf76c616 | ||
![]() |
e36bad2553 | ||
![]() |
154cc29333 | ||
![]() |
1b0402c2cf | ||
![]() |
15073cbc81 | ||
![]() |
3365b143d8 | ||
![]() |
4d9cc91e91 | ||
![]() |
946f4292ef | ||
![]() |
eb12b1ae60 | ||
![]() |
4765c97d31 | ||
![]() |
3fb32e1a97 | ||
![]() |
9ec1a0d253 | ||
![]() |
fef19615bb | ||
![]() |
4d237baf33 | ||
![]() |
03e654b5a0 | ||
![]() |
ef815eaa40 | ||
![]() |
4771a38747 | ||
![]() |
ce016793d4 | ||
![]() |
3a854f04e1 | ||
![]() |
b5658d61d9 | ||
![]() |
02750d8581 | ||
![]() |
077a3e6bba | ||
![]() |
5454be032a | ||
![]() |
ceb638e08d | ||
![]() |
040098050d | ||
![]() |
00de7c148f | ||
![]() |
8a0b4f82db | ||
![]() |
74fd1aeea5 | ||
![]() |
aac230e362 | ||
![]() |
ae82ed4a47 | ||
![]() |
9d1b0e9861 | ||
![]() |
8cb4e9f27d | ||
![]() |
c8c00a2c9b | ||
![]() |
bacb475896 | ||
![]() |
c8faa67083 | ||
![]() |
b6c0e3cdfb | ||
![]() |
323581d513 | ||
![]() |
bc7a537c4c | ||
![]() |
10ae6ffd99 | ||
![]() |
847628fbff | ||
![]() |
b502c3e84d | ||
![]() |
85e99ff0a8 | ||
![]() |
21b81f476c | ||
![]() |
02de15a6d2 | ||
![]() |
38a6e7fe67 | ||
![]() |
2283a5dad9 | ||
![]() |
e98c12d409 | ||
![]() |
aacc603309 | ||
![]() |
2ef3a81dd8 | ||
![]() |
22ef1bbb87 | ||
![]() |
7ff9f268c9 | ||
![]() |
7866bcd9a4 | ||
![]() |
5a20ac19d9 | ||
![]() |
915f6acf22 | ||
![]() |
59b73fcdc1 | ||
![]() |
8699634492 | ||
![]() |
d625e90464 | ||
![]() |
bc31c775e9 | ||
![]() |
49424e8da5 | ||
![]() |
2526c4e458 | ||
![]() |
24de3ba77c | ||
![]() |
157ed82000 | ||
![]() |
8275a9449a | ||
![]() |
6ed6b90840 | ||
![]() |
d7565e497d | ||
![]() |
de827ef61a | ||
![]() |
7b4e99fc5f | ||
![]() |
035a6f8da8 | ||
![]() |
bcdbab43de | ||
![]() |
a24f52c58a | ||
![]() |
0e745ea607 | ||
![]() |
8fe9232d9b | ||
![]() |
e6004fa980 | ||
![]() |
987b89b914 | ||
![]() |
9fddfa6fc2 | ||
![]() |
6d765bb1b8 | ||
![]() |
0ca971a289 | ||
![]() |
e87f6e7af0 | ||
![]() |
56be0a1085 | ||
![]() |
41f464d21d | ||
![]() |
c8dde73158 | ||
![]() |
0971a85db4 | ||
![]() |
51d54a8477 | ||
![]() |
b75775283f | ||
![]() |
66558290a0 | ||
![]() |
a1980afd9d | ||
![]() |
2b28802ce7 | ||
![]() |
0514a7c229 | ||
![]() |
326901b7e8 | ||
![]() |
bbe6b61d63 | ||
![]() |
204c1057db | ||
![]() |
dff6a2470c | ||
![]() |
cbebc09504 | ||
![]() |
f56dd71f43 | ||
![]() |
17f52a257e | ||
![]() |
8d09ddb686 | ||
![]() |
e6fd31e0b0 | ||
![]() |
c6188a49f5 | ||
![]() |
9a60b4d102 | ||
![]() |
7977c1d644 | ||
![]() |
ac85a1d7d3 | ||
![]() |
86b503093c | ||
![]() |
dd3e7a0f89 | ||
![]() |
8905106b48 | ||
![]() |
225760a9a5 | ||
![]() |
4aa79a76ea | ||
![]() |
1e2d6c7e75 | ||
![]() |
f1e79e9ada | ||
![]() |
37cc37650e | ||
![]() |
d607b7423a | ||
![]() |
a2e843ec84 | ||
![]() |
17cafbfa52 | ||
![]() |
91333abc4f | ||
![]() |
05b2b11af5 | ||
![]() |
3931e8088e | ||
![]() |
299ede2eb1 | ||
![]() |
4fed323a2a | ||
![]() |
b4bf8ec250 | ||
![]() |
780657ce1d | ||
![]() |
2d558563e4 | ||
![]() |
bc5e6e9535 | ||
![]() |
0c15fc2657 | ||
![]() |
5e115c63f1 | ||
![]() |
2bcf23cff1 | ||
![]() |
2c59022b78 | ||
![]() |
358d9f30d2 | ||
![]() |
afd6ce4346 | ||
![]() |
5c7256ffe5 | ||
![]() |
a15e79ad5a | ||
![]() |
f1ecbd1a93 | ||
![]() |
7da941d038 | ||
![]() |
3efc142630 | ||
![]() |
d592469237 | ||
![]() |
b3e63620b3 | ||
![]() |
22b79510ea | ||
![]() |
70cf63f8fa | ||
![]() |
c9067cf8b8 | ||
![]() |
4ccc406768 | ||
![]() |
1c25747de0 | ||
![]() |
8e4c36ec24 | ||
![]() |
444d92d393 | ||
![]() |
2597702676 | ||
![]() |
c9d75d81e4 | ||
![]() |
98eb68c845 | ||
![]() |
5185e1fe1d | ||
![]() |
5bde116a4e | ||
![]() |
179acc1382 | ||
![]() |
c6d918e401 | ||
![]() |
62b53575ac | ||
![]() |
32b29a91e9 | ||
![]() |
4346030459 | ||
![]() |
9e8c0ccb14 | ||
![]() |
6c8d00eb16 | ||
![]() |
b3fcfd0c8b | ||
![]() |
4eefab5655 | ||
![]() |
2745896ec3 | ||
![]() |
cdfaaabb70 | ||
![]() |
60ab6ece62 | ||
![]() |
436318b534 | ||
![]() |
248f431437 | ||
![]() |
7794280115 | ||
![]() |
c2cc4c977f | ||
![]() |
f9b7f97863 | ||
![]() |
59ce7eeee6 | ||
![]() |
0e012a90ea | ||
![]() |
6773d260cf | ||
![]() |
7379f6cd59 | ||
![]() |
3aee24bdbd | ||
![]() |
84dbfa5d6c | ||
![]() |
7030f562e8 | ||
![]() |
a5a662c05d |
@@ -298,6 +298,51 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "zend",
|
||||
"name": "Zenghai Liang",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/25160?v=4",
|
||||
"profile": "https://github.com/zend",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "matishadow",
|
||||
"name": "Mateusz Tracz",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/9083085?v=4",
|
||||
"profile": "https://about.me/matishadow",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "pinpins",
|
||||
"name": "pinpin",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/36234677?v=4",
|
||||
"profile": "https://zergpool.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "TakuroOnoda",
|
||||
"name": "Takuro Onoda",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/1407926?v=4",
|
||||
"profile": "https://github.com/TakuroOnoda",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "frauhottelmann",
|
||||
"name": "frauhottelmann",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/902705?v=4",
|
||||
"profile": "https://github.com/frauhottelmann",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
@@ -1,6 +1,8 @@
|
||||
parser: '@typescript-eslint/parser'
|
||||
parserOptions:
|
||||
project: tsconfig.json
|
||||
project:
|
||||
- tsconfig.json
|
||||
- '*/tsconfig.typings.json'
|
||||
extends:
|
||||
- 'plugin:@typescript-eslint/all'
|
||||
plugins:
|
||||
@@ -29,7 +31,6 @@ rules:
|
||||
'@typescript-eslint/no-magic-numbers': off
|
||||
'@typescript-eslint/member-delimiter-style': off
|
||||
'@typescript-eslint/promise-function-async': off
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': off
|
||||
'@typescript-eslint/require-array-sort-compare': off
|
||||
'@typescript-eslint/no-floating-promises': off
|
||||
'@typescript-eslint/prefer-readonly': off
|
||||
@@ -37,6 +38,8 @@ rules:
|
||||
'@typescript-eslint/strict-boolean-expressions': off
|
||||
'@typescript-eslint/no-misused-promises': off
|
||||
'@typescript-eslint/typedef': off
|
||||
'@typescript-eslint/consistent-type-imports': off
|
||||
'@typescript-eslint/sort-type-union-intersection-members': off
|
||||
'@typescript-eslint/no-use-before-define':
|
||||
- error
|
||||
- classes: false
|
||||
@@ -53,7 +56,8 @@ rules:
|
||||
computed-property-spacing:
|
||||
- error
|
||||
- never
|
||||
comma-dangle:
|
||||
comma-dangle: off
|
||||
'@typescript-eslint/comma-dangle':
|
||||
- error
|
||||
- always-multiline
|
||||
curly: error
|
||||
@@ -80,7 +84,8 @@ rules:
|
||||
argsIgnorePattern: ^_
|
||||
no-undef: error
|
||||
no-var: error
|
||||
object-curly-spacing:
|
||||
object-curly-spacing: off
|
||||
'@typescript-eslint/object-curly-spacing':
|
||||
- error
|
||||
- always
|
||||
quote-props:
|
||||
@@ -93,14 +98,22 @@ rules:
|
||||
- error
|
||||
- single
|
||||
- allowTemplateLiterals: true
|
||||
'@typescript-eslint/no-confusing-void-expression': off
|
||||
'@typescript-eslint/no-non-null-assertion': off
|
||||
'@typescript-eslint/no-unnecessary-condition': off
|
||||
'@typescript-eslint/no-untyped-public-signature': off # bugs out on constructors
|
||||
'@typescript-eslint/no-unnecessary-condition':
|
||||
- error
|
||||
- allowConstantLoopConditions: true
|
||||
'@typescript-eslint/restrict-template-expressions': off
|
||||
'@typescript-eslint/no-dynamic-delete': off
|
||||
'@typescript-eslint/prefer-nullish-coalescing': off
|
||||
'@typescript-eslint/prefer-readonly-parameter-types': off
|
||||
'@typescript-eslint/no-unsafe-member-access': off
|
||||
'@typescript-eslint/no-unsafe-call': off
|
||||
'@typescript-eslint/no-unsafe-return': off
|
||||
'@typescript-eslint/no-base-to-string': off # broken in typescript-eslint
|
||||
'@typescript-eslint/no-unsafe-assignment': off
|
||||
'@typescript-eslint/naming-convention': off
|
||||
'@typescript-eslint/lines-between-class-members':
|
||||
- error
|
||||
- exceptAfterSingleLine: true
|
||||
'@typescript-eslint/dot-notation': off
|
||||
'@typescript-eslint/no-implicit-any-catch': off
|
||||
'@typescript-eslint/member-ordering': off
|
||||
'@typescript-eslint/no-var-requires': off
|
||||
|
5
.github/workflows/lint.yml
vendored
5
.github/workflows/lint.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
- name: Installing Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
node-version: 15
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
@@ -22,5 +22,8 @@ jobs:
|
||||
rm app/node_modules/.yarn-integrity
|
||||
yarn
|
||||
|
||||
- name: Build typings
|
||||
run: yarn run build:typings
|
||||
|
||||
- name: Lint
|
||||
run: yarn run lint
|
||||
|
12
.github/workflows/linux.yml
vendored
12
.github/workflows/linux.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
node-version: 15
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
@@ -36,6 +36,16 @@ jobs:
|
||||
env:
|
||||
DEBUG: electron-builder,electron-builder:*
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
USE_HARD_LINKS: false
|
||||
|
||||
- name: Upload symbols
|
||||
run: |
|
||||
sudo npm install -g @sentry/cli --unsafe-perm
|
||||
./scripts/sentry-upload.js
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
|
39
.github/workflows/macos.yml
vendored
39
.github/workflows/macos.yml
vendored
@@ -2,7 +2,12 @@ name: macOS Build
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macOS-latest
|
||||
runs-on: macos-11.0
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: x86_64
|
||||
- arch: arm64
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -11,25 +16,33 @@ jobs:
|
||||
- name: Installing Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
node-version: 15
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
sudo npm i -g yarn@1.19.1
|
||||
sudo npm i -g yarn@1.22.1
|
||||
cd app
|
||||
yarn
|
||||
cd ..
|
||||
rm app/node_modules/.yarn-integrity
|
||||
yarn
|
||||
./node_modules/.bin/patch-package
|
||||
cd app
|
||||
../node_modules/.bin/patch-package
|
||||
cd ..
|
||||
|
||||
- name: Build native deps
|
||||
run: scripts/build-native.js
|
||||
env:
|
||||
ARCH: ${{matrix.arch}}
|
||||
|
||||
- name: Webpack
|
||||
run: yarn run build
|
||||
|
||||
- name: Prepackage plugins
|
||||
run: scripts/prepackage-plugins.js
|
||||
env:
|
||||
ARCH: ${{matrix.arch}}
|
||||
|
||||
- run: sed -i '' 's/updateInfo = await/\/\/updateInfo = await/g' node_modules/app-builder-lib/out/targets/ArchiveTarget.js
|
||||
|
||||
@@ -37,18 +50,30 @@ jobs:
|
||||
run: scripts/build-macos.js
|
||||
if: github.repository == 'Eugeny/terminus' && github.event_name == 'push'
|
||||
env:
|
||||
#DEBUG: electron-builder,electron-builder:*
|
||||
ARCH: ${{matrix.arch}}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
CSC_LINK: ${{ secrets.CSC_LINK }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||
APPSTORE_USERNAME: ${{ secrets.APPSTORE_USERNAME }}
|
||||
APPSTORE_PASSWORD: ${{ secrets.APPSTORE_PASSWORD }}
|
||||
USE_HARD_LINKS: false
|
||||
# DEBUG: electron-builder,electron-builder:*
|
||||
|
||||
- name: Build packages without signing
|
||||
run: scripts/build-macos.js
|
||||
if: github.repository != 'Eugeny/terminus' || github.event_name != 'push'
|
||||
env:
|
||||
DEBUG: electron-builder,electron-builder:*
|
||||
ARCH: ${{matrix.arch}}
|
||||
# DEBUG: electron-builder,electron-builder:*
|
||||
|
||||
- name: Upload symbols
|
||||
run: |
|
||||
sudo npm install -g @sentry/cli --unsafe-perm
|
||||
./scripts/sentry-upload.js
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
@@ -60,11 +85,11 @@ jobs:
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload PKG
|
||||
with:
|
||||
name: macOS .pkg
|
||||
name: macOS .pkg (${{matrix.arch}})
|
||||
path: artifact-pkg
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload ZIP
|
||||
with:
|
||||
name: macOS .zip
|
||||
name: macOS .zip (${{matrix.arch}})
|
||||
path: artifact-zip
|
||||
|
11
.github/workflows/windows.yml
vendored
11
.github/workflows/windows.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
- name: Installing Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
node-version: 14
|
||||
|
||||
- name: Build
|
||||
shell: powershell
|
||||
@@ -34,6 +34,15 @@ jobs:
|
||||
run: node scripts/build-windows.js
|
||||
if: github.repository != 'Eugeny/terminus' || github.event_name != 'push'
|
||||
|
||||
- name: Upload symbols
|
||||
run: |
|
||||
npm install @sentry/cli
|
||||
node scripts/sentry-upload.js
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
mkdir artifact-setup
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -13,6 +13,9 @@ dist
|
||||
*.xcuserstate
|
||||
*.wixpdb
|
||||
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
|
||||
coverage
|
||||
.nyc_output
|
||||
npm-debug.log
|
||||
|
@@ -1,5 +1,5 @@
|
||||
language: node_js
|
||||
node_js: 11
|
||||
node_js: 15
|
||||
|
||||
stages:
|
||||
- Build
|
||||
|
78
README.md
78
README.md
@@ -2,11 +2,11 @@
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://raw.githubusercontent.com/Eugeny/terminus/master/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/eugeny/terminus.svg?label=License&style=flat-square"></a> <a href="https://ci.appveyor.com/project/Eugeny/terminus"><img alt="AppVeyor" src="https://img.shields.io/appveyor/ci/eugeny/terminus.svg?label=CI&logo=appveyor&logoColor=white&style=flat-square"></a>
|
||||
<a href="https://raw.githubusercontent.com/Eugeny/terminus/master/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/eugeny/terminus.svg?label=License&style=flat-square"></a> <a href="https://ci.appveyor.com/project/Eugeny/terminus"><img alt="AppVeyor" src="https://img.shields.io/appveyor/ci/eugeny/****terminus****.svg?label=CI&logo=appveyor&logoColor=white&style=flat-square"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Eugeny/terminus/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/terminus/total.svg?label=DOWNLOAD&logo=github&style=for-the-badge"></a> <a href="https://ci.appveyor.com/project/Eugeny/terminus/build/artifacts"><img src="https://img.shields.io/badge/download-nightly%20build-magenta.svg?logo=appveyor&style=for-the-badge"/></a> <a href="https://gitter.im/terminus-terminal/community"><img alt="Gitter" src="https://img.shields.io/gitter/room/terminus/community.svg?color=blue&logo=gitter&style=for-the-badge"></a>
|
||||
<a href="https://github.com/Eugeny/terminus/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/terminus/total.svg?label=RELEASE&logo=github&style=for-the-badge"></a> <a href="https://nightly.link/Eugeny/terminus/workflows/windows/master"><img src="https://shields.io/badge/-Nightly-blue?logo=windows&style=for-the-badge"/></a> <a href="https://nightly.link/Eugeny/terminus/workflows/macos/master"><img src="https://shields.io/badge/-Nightly-black?logo=apple&style=for-the-badge"/></a> <a href="https://nightly.link/Eugeny/terminus/workflows/linux/master"><img src="https://shields.io/badge/-Nightly-orange?logo=linux&style=for-the-badge"/></a> <a href="https://gitter.im/terminus-terminal/community"><img alt="Gitter" src="https://img.shields.io/gitter/room/terminus/community.svg?color=magenta&logo=gitter&style=for-the-badge"></a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -74,51 +74,59 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4" width="100px;" alt=""/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mezner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4" width="100px;" alt=""/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ehwarren" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4" width="100px;" alt=""/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4" width="100px;" alt=""/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4" width="100px;" alt=""/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yxuko" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4" width="100px;" alt=""/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=BBJip" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4" width="100px;" alt=""/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mezner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ehwarren" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yxuko" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4?s=100" width="100px;" alt=""/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=BBJip" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4" width="100px;" alt=""/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=levrik" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4" width="100px;" alt=""/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=kwonoj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4" width="100px;" alt=""/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Domain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4" width="100px;" alt=""/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4" width="100px;" alt=""/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4" width="100px;" alt=""/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=baflo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4" width="100px;" alt=""/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=levrik" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4?s=100" width="100px;" alt=""/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=kwonoj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4?s=100" width="100px;" alt=""/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Domain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/terminus/commits?author=Tyriar" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=baflo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4" width="100px;" alt=""/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=NieLeben" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4" width="100px;" alt=""/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4" width="100px;" alt=""/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=IgnusG" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4" width="100px;" alt=""/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hammster" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4" width="100px;" alt=""/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4" width="100px;" alt=""/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yfwz100" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4" width="100px;" alt=""/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=jack1142" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=NieLeben" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=IgnusG" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hammster" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=yfwz100" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=jack1142" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4" width="100px;" alt=""/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hdougie" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4" width="100px;" alt=""/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ckaczor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4" width="100px;" alt=""/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=boxmein" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4" width="100px;" alt=""/><br /><sub><b>LeSeulArtichaut</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=LeSeulArtichaut" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4" width="100px;" alt=""/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=CyrilTaylor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4" width="100px;" alt=""/><br /><sub><b>nstefanou</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=nstefanou" title="Code">💻</a> <a href="#plugin-nstefanou" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4" width="100px;" alt=""/><br /><sub><b>orin220444</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=orin220444" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=hdougie" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=ckaczor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=boxmein" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>LeSeulArtichaut</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=LeSeulArtichaut" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=CyrilTaylor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nstefanou</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=nstefanou" title="Code">💻</a> <a href="#plugin-nstefanou" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4?s=100" width="100px;" alt=""/><br /><sub><b>orin220444</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=orin220444" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4" width="100px;" alt=""/><br /><sub><b>Gobius Dolhain</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Goobles" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/3l0w"><img src="https://avatars2.githubusercontent.com/u/37798980?v=4" width="100px;" alt=""/><br /><sub><b>Gwilherm Folliot</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=3l0w" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Dimitory"><img src="https://avatars0.githubusercontent.com/u/475955?v=4" width="100px;" alt=""/><br /><sub><b>Dmitry Pronin</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=dimitory" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JonathanBeverley"><img src="https://avatars1.githubusercontent.com/u/20328966?v=4" width="100px;" alt=""/><br /><sub><b>Jonathan Beverley</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=JonathanBeverley" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gobius Dolhain</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=Goobles" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/3l0w"><img src="https://avatars2.githubusercontent.com/u/37798980?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gwilherm Folliot</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=3l0w" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Dimitory"><img src="https://avatars0.githubusercontent.com/u/475955?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dmitry Pronin</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=dimitory" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JonathanBeverley"><img src="https://avatars1.githubusercontent.com/u/20328966?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jonathan Beverley</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=JonathanBeverley" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/zend"><img src="https://avatars1.githubusercontent.com/u/25160?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zenghai Liang</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=zend" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://about.me/matishadow"><img src="https://avatars0.githubusercontent.com/u/9083085?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mateusz Tracz</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=matishadow" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://zergpool.com"><img src="https://avatars3.githubusercontent.com/u/36234677?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pinpin</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=pinpins" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/TakuroOnoda"><img src="https://avatars0.githubusercontent.com/u/1407926?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Takuro Onoda</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=TakuroOnoda" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/frauhottelmann"><img src="https://avatars2.githubusercontent.com/u/902705?v=4?s=100" width="100px;" alt=""/><br /><sub><b>frauhottelmann</b></sub></a><br /><a href="https://github.com/Eugeny/terminus/commits?author=frauhottelmann" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { app, ipcMain, Menu, Tray, shell, globalShortcut } from 'electron'
|
||||
// eslint-disable-next-line no-duplicate-imports
|
||||
import * as electron from 'electron'
|
||||
import { app, ipcMain, Menu, Tray, shell, screen, globalShortcut, MenuItemConstructorOptions } from 'electron'
|
||||
import * as promiseIpc from 'electron-promise-ipc'
|
||||
import { loadConfig } from './config'
|
||||
import { Window, WindowOptions } from './window'
|
||||
import { pluginManager } from './pluginManager'
|
||||
|
||||
export class Application {
|
||||
private tray: Tray
|
||||
private tray?: Tray
|
||||
private windows: Window[] = []
|
||||
|
||||
constructor () {
|
||||
@@ -15,13 +15,21 @@ export class Application {
|
||||
|
||||
ipcMain.on('app:register-global-hotkey', (_event, specs) => {
|
||||
globalShortcut.unregisterAll()
|
||||
for (let spec of specs) {
|
||||
for (const spec of specs) {
|
||||
globalShortcut.register(spec, () => {
|
||||
this.onGlobalHotkey()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
;(promiseIpc as any).on('plugin-manager:install', (path, name, version) => {
|
||||
return pluginManager.install(path, name, version)
|
||||
})
|
||||
|
||||
;(promiseIpc as any).on('plugin-manager:uninstall', (path, name) => {
|
||||
return pluginManager.uninstall(path, name)
|
||||
})
|
||||
|
||||
const configData = loadConfig()
|
||||
if (process.platform === 'linux') {
|
||||
app.commandLine.appendSwitch('no-sandbox')
|
||||
@@ -41,11 +49,13 @@ export class Application {
|
||||
}
|
||||
|
||||
init (): void {
|
||||
electron.screen.on('display-metrics-changed', () => this.broadcast('host:display-metrics-changed'))
|
||||
screen.on('display-metrics-changed', () => this.broadcast('host:display-metrics-changed'))
|
||||
screen.on('display-added', () => this.broadcast('host:displays-changed'))
|
||||
screen.on('display-removed', () => this.broadcast('host:displays-changed'))
|
||||
}
|
||||
|
||||
async newWindow (options?: WindowOptions): Promise<Window> {
|
||||
let window = new Window(options)
|
||||
const window = new Window(options)
|
||||
this.windows.push(window)
|
||||
window.visible$.subscribe(visible => {
|
||||
if (visible) {
|
||||
@@ -65,30 +75,30 @@ export class Application {
|
||||
}
|
||||
|
||||
onGlobalHotkey (): void {
|
||||
if (this.windows.some(x => x.isFocused())) {
|
||||
for (let window of this.windows) {
|
||||
if (this.windows.some(x => x.isFocused() && x.isVisible())) {
|
||||
for (const window of this.windows) {
|
||||
window.hide()
|
||||
}
|
||||
} else {
|
||||
for (let window of this.windows) {
|
||||
for (const window of this.windows) {
|
||||
window.present()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
presentAllWindows (): void {
|
||||
for (let window of this.windows) {
|
||||
for (const window of this.windows) {
|
||||
window.present()
|
||||
}
|
||||
}
|
||||
|
||||
broadcast (event: string, ...args): void {
|
||||
broadcast (event: string, ...args: any[]): void {
|
||||
for (const window of this.windows) {
|
||||
window.send(event, ...args)
|
||||
}
|
||||
}
|
||||
|
||||
async send (event: string, ...args): Promise<void> {
|
||||
async send (event: string, ...args: any[]): Promise<void> {
|
||||
if (!this.hasWindows()) {
|
||||
await this.newWindow()
|
||||
}
|
||||
@@ -121,10 +131,8 @@ export class Application {
|
||||
}
|
||||
|
||||
disableTray (): void {
|
||||
if (this.tray) {
|
||||
this.tray.destroy()
|
||||
this.tray = null
|
||||
}
|
||||
this.tray?.destroy()
|
||||
this.tray = null
|
||||
}
|
||||
|
||||
hasWindows (): boolean {
|
||||
@@ -132,20 +140,18 @@ export class Application {
|
||||
}
|
||||
|
||||
focus (): void {
|
||||
for (let window of this.windows) {
|
||||
for (const window of this.windows) {
|
||||
window.show()
|
||||
}
|
||||
}
|
||||
|
||||
handleSecondInstance (argv: string[], cwd: string): void {
|
||||
this.presentAllWindows()
|
||||
for (let window of this.windows) {
|
||||
window.handleSecondInstance(argv, cwd)
|
||||
}
|
||||
this.windows[this.windows.length - 1].passCliArguments(argv, cwd, true)
|
||||
}
|
||||
|
||||
private setupMenu () {
|
||||
let template: Electron.MenuItemConstructorOptions[] = [
|
||||
const template: MenuItemConstructorOptions[] = [
|
||||
{
|
||||
label: 'Application',
|
||||
submenu: [
|
||||
|
@@ -5,7 +5,7 @@ export function parseArgs (argv: string[], cwd: string): any {
|
||||
argv = argv.slice(1)
|
||||
}
|
||||
|
||||
return require('yargs')
|
||||
return require('yargs/yargs')(argv.slice(1))
|
||||
.usage('terminus [command] [arguments]')
|
||||
.command('open [directory]', 'open a shell in a directory', {
|
||||
directory: { type: 'string', 'default': cwd },
|
||||
@@ -41,5 +41,5 @@ export function parseArgs (argv: string[], cwd: string): any {
|
||||
type: 'boolean',
|
||||
})
|
||||
.help('help')
|
||||
.parse(argv.slice(1))
|
||||
.parse()
|
||||
}
|
||||
|
@@ -4,9 +4,9 @@ import * as yaml from 'js-yaml'
|
||||
import { app } from 'electron'
|
||||
|
||||
export function loadConfig (): any {
|
||||
let configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||
const configPath = path.join(app.getPath('userData'), 'config.yaml')
|
||||
if (fs.existsSync(configPath)) {
|
||||
return yaml.safeLoad(fs.readFileSync(configPath, 'utf8'))
|
||||
return yaml.load(fs.readFileSync(configPath, 'utf8'))
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import './portable'
|
||||
import 'source-map-support/register'
|
||||
import './sentry'
|
||||
import './lru'
|
||||
import { app, ipcMain, Menu } from 'electron'
|
||||
@@ -52,7 +53,7 @@ if (argv.d) {
|
||||
})
|
||||
}
|
||||
|
||||
app.on('ready', () => {
|
||||
app.on('ready', async () => {
|
||||
if (process.platform === 'darwin') {
|
||||
app.dock.setMenu(Menu.buildFromTemplate([
|
||||
{
|
||||
@@ -64,5 +65,8 @@ app.on('ready', () => {
|
||||
]))
|
||||
}
|
||||
application.init()
|
||||
application.newWindow({ hidden: argv.hidden })
|
||||
|
||||
const window = await application.newWindow({ hidden: argv.hidden })
|
||||
await window.ready
|
||||
window.passCliArguments(process.argv, process.cwd(), false)
|
||||
})
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import * as createLRU from 'lru-cache'
|
||||
import * as LRU from 'lru-cache'
|
||||
import * as fs from 'fs'
|
||||
const lru = createLRU({ max: 256, maxAge: 250 })
|
||||
const lru = new LRU({ max: 256, maxAge: 250 })
|
||||
const origLstat = fs.realpathSync.bind(fs)
|
||||
|
||||
// NB: The biggest offender of thrashing realpathSync is the node module system
|
||||
|
40
app/lib/pluginManager.ts
Normal file
40
app/lib/pluginManager.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { promisify } from 'util'
|
||||
|
||||
|
||||
export class PluginManager {
|
||||
npm: any
|
||||
npmReady?: Promise<void>
|
||||
|
||||
async ensureLoaded (): Promise<void> {
|
||||
if (!this.npmReady) {
|
||||
this.npmReady = new Promise(resolve => {
|
||||
const npm = require('npm')
|
||||
npm.load(err => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
return
|
||||
}
|
||||
npm.config.set('global', false)
|
||||
this.npm = npm
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
return this.npmReady
|
||||
}
|
||||
|
||||
async install (path: string, name: string, version: string): Promise<void> {
|
||||
await this.ensureLoaded()
|
||||
this.npm.prefix = path
|
||||
return promisify(this.npm.commands.install)([`${name}@${version}`])
|
||||
}
|
||||
|
||||
async uninstall (path: string, name: string): Promise<void> {
|
||||
await this.ensureLoaded()
|
||||
this.npm.prefix = path
|
||||
return promisify(this.npm.commands.remove)([name])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const pluginManager = new PluginManager()
|
@@ -8,17 +8,15 @@ try {
|
||||
appPath = path.dirname(require('electron').remote.app.getPath('exe'))
|
||||
}
|
||||
|
||||
if (null != appPath) {
|
||||
if(fs.existsSync(path.join(appPath, 'terminus-data'))) {
|
||||
fs.renameSync(path.join(appPath, 'terminus-data'), path.join(appPath, 'data'))
|
||||
}
|
||||
const portableData = path.join(appPath, 'data')
|
||||
if (fs.existsSync(portableData)) {
|
||||
console.log('reset user data to ' + portableData)
|
||||
try {
|
||||
require('electron').app.setPath('userData', portableData)
|
||||
} catch {
|
||||
require('electron').remote.app.setPath('userData', portableData)
|
||||
}
|
||||
if (fs.existsSync(path.join(appPath, 'terminus-data'))) {
|
||||
fs.renameSync(path.join(appPath, 'terminus-data'), path.join(appPath, 'data'))
|
||||
}
|
||||
const portableData = path.join(appPath, 'data')
|
||||
if (fs.existsSync(portableData)) {
|
||||
console.log('reset user data to ' + portableData)
|
||||
try {
|
||||
require('electron').app.setPath('userData', portableData)
|
||||
} catch {
|
||||
require('electron').remote.app.setPath('userData', portableData)
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
const { init } = process.type === 'main' ? require('@sentry/electron/dist/main') : require('@sentry/electron/dist/renderer')
|
||||
const { init } = String(process.type) === 'main' ? require('@sentry/electron/dist/main') : require('@sentry/electron/dist/renderer')
|
||||
import * as isDev from 'electron-is-dev'
|
||||
|
||||
|
||||
const SENTRY_DSN = 'https://4717a0a7ee0b4429bd3a0f06c3d7eec3@sentry.io/181876'
|
||||
let release
|
||||
let release = null
|
||||
try {
|
||||
release = require('electron').app.getVersion()
|
||||
} catch {
|
||||
|
@@ -1,19 +1,18 @@
|
||||
import * as glasstron from 'glasstron'
|
||||
if (process.platform === 'win32' || process.platform === 'linux') {
|
||||
glasstron.init()
|
||||
}
|
||||
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
import { debounceTime } from 'rxjs/operators'
|
||||
import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen } from 'electron'
|
||||
import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen, BrowserWindowConstructorOptions } from 'electron'
|
||||
import ElectronConfig = require('electron-config')
|
||||
import * as os from 'os'
|
||||
import * as path from 'path'
|
||||
import macOSRelease from 'macos-release'
|
||||
import * as compareVersions from 'compare-versions'
|
||||
|
||||
import { parseArgs } from './cli'
|
||||
import { loadConfig } from './config'
|
||||
|
||||
let DwmEnableBlurBehindWindow: any
|
||||
let DwmEnableBlurBehindWindow: any = null
|
||||
if (process.platform === 'win32') {
|
||||
DwmEnableBlurBehindWindow = require('windows-blurbehind').DwmEnableBlurBehindWindow
|
||||
}
|
||||
@@ -22,15 +21,22 @@ export interface WindowOptions {
|
||||
hidden?: boolean
|
||||
}
|
||||
|
||||
abstract class GlasstronWindow extends BrowserWindow {
|
||||
blurType: string
|
||||
abstract setBlur (_: boolean)
|
||||
}
|
||||
|
||||
const macOSVibrancyType = process.platform === 'darwin' ? compareVersions.compare(macOSRelease().version, '10.14', '>=') ? 'fullscreen-ui' : 'dark' : null
|
||||
|
||||
export class Window {
|
||||
ready: Promise<void>
|
||||
private visible = new Subject<boolean>()
|
||||
private closed = new Subject<void>()
|
||||
private window: BrowserWindow
|
||||
private window?: GlasstronWindow
|
||||
private windowConfig: ElectronConfig
|
||||
private windowBounds: Rectangle
|
||||
private windowBounds?: Rectangle
|
||||
private closing = false
|
||||
private lastVibrancy: {enabled: boolean, type?: string} | null = null
|
||||
private lastVibrancy: { enabled: boolean, type?: string } | null = null
|
||||
private disableVibrancyWhileDragging = false
|
||||
private configStore: any
|
||||
|
||||
@@ -40,13 +46,13 @@ export class Window {
|
||||
constructor (options?: WindowOptions) {
|
||||
this.configStore = loadConfig()
|
||||
|
||||
options = options || {}
|
||||
options = options ?? {}
|
||||
|
||||
this.windowConfig = new ElectronConfig({ name: 'window' })
|
||||
this.windowBounds = this.windowConfig.get('windowBoundaries')
|
||||
|
||||
let maximized = this.windowConfig.get('maximized')
|
||||
let bwOptions: Electron.BrowserWindowConstructorOptions = {
|
||||
const maximized = this.windowConfig.get('maximized')
|
||||
const bwOptions: BrowserWindowConstructorOptions = {
|
||||
width: 800,
|
||||
height: 600,
|
||||
title: 'Terminus',
|
||||
@@ -56,7 +62,10 @@ export class Window {
|
||||
nodeIntegration: true,
|
||||
preload: path.join(__dirname, 'sentry.js'),
|
||||
backgroundThrottling: false,
|
||||
enableRemoteModule: true,
|
||||
contextIsolation: false,
|
||||
},
|
||||
maximizable: true,
|
||||
frame: false,
|
||||
show: false,
|
||||
backgroundColor: '#00000000',
|
||||
@@ -83,11 +92,15 @@ export class Window {
|
||||
}
|
||||
}
|
||||
|
||||
this.window = new BrowserWindow(bwOptions)
|
||||
if (process.platform === 'darwin') {
|
||||
this.window = new BrowserWindow(bwOptions) as GlasstronWindow
|
||||
} else {
|
||||
this.window = new glasstron.BrowserWindow(bwOptions)
|
||||
}
|
||||
|
||||
this.window.once('ready-to-show', () => {
|
||||
if (process.platform === 'darwin') {
|
||||
this.window.setVibrancy('window')
|
||||
this.window.setVibrancy(macOSVibrancyType)
|
||||
} else if (process.platform === 'win32' && (this.configStore.appearance || {}).vibrancy) {
|
||||
this.setVibrancy(true)
|
||||
}
|
||||
@@ -128,23 +141,26 @@ export class Window {
|
||||
})
|
||||
}
|
||||
|
||||
setVibrancy (enabled: boolean, type?: string): void {
|
||||
this.lastVibrancy = { enabled, type }
|
||||
setVibrancy (enabled: boolean, type?: string, userRequested?: boolean): void {
|
||||
if (userRequested ?? true) {
|
||||
this.lastVibrancy = { enabled, type }
|
||||
}
|
||||
if (process.platform === 'win32') {
|
||||
if (parseFloat(os.release()) >= 10) {
|
||||
glasstron.update(this.window, {
|
||||
windows: { blurType: enabled ? type === 'fluent' ? 'acrylic' : 'blurbehind' : null },
|
||||
})
|
||||
this.window.blurType = enabled ? type === 'fluent' ? 'acrylic' : 'blurbehind' : null
|
||||
try {
|
||||
this.window.setBlur(enabled)
|
||||
} catch (error) {
|
||||
console.error('Failed to set window blur', error)
|
||||
}
|
||||
} else {
|
||||
DwmEnableBlurBehindWindow(this.window, enabled)
|
||||
}
|
||||
} else if (process.platform ==='linux') {
|
||||
glasstron.update(this.window, {
|
||||
linux: { requestBlur: enabled },
|
||||
})
|
||||
} else if (process.platform === 'linux') {
|
||||
this.window.setBackgroundColor(enabled ? '#00000000' : '#131d27')
|
||||
this.window.setBlur(enabled)
|
||||
} else {
|
||||
this.window.setVibrancy(enabled ? 'dark' : null as any) // electron issue 20269
|
||||
this.window.setVibrancy(enabled ? macOSVibrancyType : null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +173,7 @@ export class Window {
|
||||
this.window.focus()
|
||||
}
|
||||
|
||||
send (event: string, ...args): void {
|
||||
send (event: string, ...args: any[]): void {
|
||||
if (!this.window) {
|
||||
return
|
||||
}
|
||||
@@ -175,6 +191,10 @@ export class Window {
|
||||
return this.window.isFocused()
|
||||
}
|
||||
|
||||
isVisible (): boolean {
|
||||
return this.window.isVisible()
|
||||
}
|
||||
|
||||
hide (): void {
|
||||
if (process.platform === 'darwin') {
|
||||
// Lose focus
|
||||
@@ -210,10 +230,8 @@ export class Window {
|
||||
}
|
||||
}
|
||||
|
||||
handleSecondInstance (argv: string[], cwd: string): void {
|
||||
if (!this.configStore.appearance?.dock) {
|
||||
this.send('host:second-instance', parseArgs(argv, cwd), cwd)
|
||||
}
|
||||
passCliArguments (argv: string[], cwd: string, secondInstance: boolean): void {
|
||||
this.send('cli', parseArgs(argv, cwd), cwd, secondInstance)
|
||||
}
|
||||
|
||||
private setupWindowManagement () {
|
||||
@@ -226,7 +244,7 @@ export class Window {
|
||||
this.visible.next(false)
|
||||
})
|
||||
|
||||
let moveSubscription = new Observable<void>(observer => {
|
||||
const moveSubscription = new Observable<void>(observer => {
|
||||
this.window.on('move', () => observer.next())
|
||||
}).pipe(debounceTime(250)).subscribe(() => {
|
||||
this.send('host:window-moved')
|
||||
@@ -361,24 +379,21 @@ export class Window {
|
||||
this.disableVibrancyWhileDragging = value
|
||||
})
|
||||
|
||||
this.window.on('will-move', () => {
|
||||
let moveEndedTimeout: number|null = null
|
||||
const onBoundsChange = () => {
|
||||
if (!this.lastVibrancy?.enabled || !this.disableVibrancyWhileDragging) {
|
||||
return
|
||||
}
|
||||
let timeout: number|null = null
|
||||
const oldVibrancy = this.lastVibrancy
|
||||
this.setVibrancy(false)
|
||||
const onMove = () => {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
timeout = setTimeout(() => {
|
||||
this.window.off('move', onMove)
|
||||
this.setVibrancy(oldVibrancy.enabled, oldVibrancy.type)
|
||||
}, 500)
|
||||
this.setVibrancy(false, undefined, false)
|
||||
if (moveEndedTimeout) {
|
||||
clearTimeout(moveEndedTimeout)
|
||||
}
|
||||
this.window.on('move', onMove)
|
||||
})
|
||||
moveEndedTimeout = setTimeout(() => {
|
||||
this.setVibrancy(this.lastVibrancy.enabled, this.lastVibrancy.type)
|
||||
}, 50)
|
||||
}
|
||||
this.window.on('move', onBoundsChange)
|
||||
this.window.on('resize', onBoundsChange)
|
||||
}
|
||||
|
||||
private destroy () {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "terminus",
|
||||
"description": "A terminal for a modern age",
|
||||
"private": true,
|
||||
"repository": "https://github.com/eugeny/terminus",
|
||||
"author": {
|
||||
"name": "Eugene Pankov",
|
||||
@@ -13,42 +14,52 @@
|
||||
"watch": "webpack --progress --color --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "9.1.9",
|
||||
"@angular/common": "9.1.11",
|
||||
"@angular/compiler": "9.1.9",
|
||||
"@angular/core": "9.1.9",
|
||||
"@angular/forms": "9.1.11",
|
||||
"@angular/platform-browser": "9.1.9",
|
||||
"@angular/platform-browser-dynamic": "9.1.9",
|
||||
"@angular/animations": "^11.1.1",
|
||||
"@angular/common": "^11.1.1",
|
||||
"@angular/compiler": "^11.1.1",
|
||||
"@angular/core": "^11.1.1",
|
||||
"@angular/forms": "^11.1.1",
|
||||
"@angular/platform-browser": "^11.1.1",
|
||||
"@angular/platform-browser-dynamic": "^11.1.1",
|
||||
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
|
||||
"devtron": "1.4.0",
|
||||
"@terminus-term/node-pty": "0.10.0-terminus.3",
|
||||
"electron-config": "2.0.0",
|
||||
"electron-debug": "^3.0.1",
|
||||
"electron-is-dev": "1.1.0",
|
||||
"fontmanager-redux": "0.4.0",
|
||||
"glasstron": "sentialx/Glasstron#n-api",
|
||||
"js-yaml": "3.14.0",
|
||||
"keytar": "^6.0.1",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-is-dev": "1.2.0",
|
||||
"electron-promise-ipc": "^2.2.4",
|
||||
"fontmanager-redux": "1.0.0",
|
||||
"glasstron": "0.0.6",
|
||||
"js-yaml": "4.0.0",
|
||||
"keytar": "^7.2.0",
|
||||
"mz": "^2.7.0",
|
||||
"native-process-working-directory": "^1.0.2",
|
||||
"ngx-toastr": "^12.0.1",
|
||||
"node-pty": "^0.10.0-beta9",
|
||||
"npm": "6.9.0",
|
||||
"npm": "6",
|
||||
"path": "0.12.7",
|
||||
"rxjs": "^6.5.5",
|
||||
"rxjs-compat": "^6.6.0",
|
||||
"yargs": "^15.4.1",
|
||||
"zone.js": "^0.10.3"
|
||||
"zone.js": "^0.11.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"macos-native-processlist": "^1.0.2",
|
||||
"serialport": "^9.0.0",
|
||||
"macos-native-processlist": "^2.0.0",
|
||||
"serialport": "^9.0.4",
|
||||
"windows-blurbehind": "^1.0.1",
|
||||
"windows-native-registry": "^1.0.17",
|
||||
"windows-native-registry": "^3.0.0",
|
||||
"windows-process-tree": "^0.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mz": "0.0.32",
|
||||
"@types/node": "12.7.12",
|
||||
"node-abi": "^2.18.0"
|
||||
"@types/node": "14.14.14",
|
||||
"node-abi": "2.19.3",
|
||||
"source-map-support": "^0.5.19"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"terminus-community-color-schemes": "*",
|
||||
"terminus-core": "*",
|
||||
"terminus-plugin-manager": "*",
|
||||
"terminus-serial": "*",
|
||||
"terminus-settings": "*",
|
||||
"terminus-ssh": "*",
|
||||
"terminus-terminal": "*"
|
||||
}
|
||||
}
|
||||
|
12
app/patches/node-abi+2.19.3.patch
Normal file
12
app/patches/node-abi+2.19.3.patch
Normal file
@@ -0,0 +1,12 @@
|
||||
diff --git a/node_modules/node-abi/abi_registry.json b/node_modules/node-abi/abi_registry.json
|
||||
index bc1436d..630c1b7 100644
|
||||
--- a/node_modules/node-abi/abi_registry.json
|
||||
+++ b/node_modules/node-abi/abi_registry.json
|
||||
@@ -94,6 +94,6 @@
|
||||
"future": true,
|
||||
"lts": false,
|
||||
"runtime": "electron",
|
||||
- "target": "12.0.0-nightly.20201013"
|
||||
+ "target": "12.0.0-beta.16"
|
||||
}
|
||||
]
|
@@ -58,8 +58,8 @@ findPlugins().then(async plugins => {
|
||||
window['safeModeReason'] = error
|
||||
try {
|
||||
await bootstrap(plugins, true)
|
||||
} catch (error) {
|
||||
console.error('Bootstrap failed:', error)
|
||||
} catch (error2) {
|
||||
console.error('Bootstrap failed:', error2)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@@ -95,3 +95,7 @@ input[type=range] {
|
||||
&::-moz-range-track { @include track(); }
|
||||
&::-ms-track { @include track(); }
|
||||
}
|
||||
|
||||
a[ngbdropdownitem] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@@ -3,13 +3,13 @@ import * as path from 'path'
|
||||
const nodeModule = require('module') // eslint-disable-line @typescript-eslint/no-var-requires
|
||||
const nodeRequire = (global as any).require
|
||||
|
||||
function normalizePath (path: string): string {
|
||||
function normalizePath (p: string): string {
|
||||
const cygwinPrefix = '/cygdrive/'
|
||||
if (path.startsWith(cygwinPrefix)) {
|
||||
path = path.substring(cygwinPrefix.length).replace('/', '\\')
|
||||
path = path[0] + ':' + path.substring(1)
|
||||
if (p.startsWith(cygwinPrefix)) {
|
||||
p = p.substring(cygwinPrefix.length).replace('/', '\\')
|
||||
p = p[0] + ':' + p.substring(1)
|
||||
}
|
||||
return path
|
||||
return p
|
||||
}
|
||||
|
||||
global['module'].paths.map((x: string) => nodeModule.globalPaths.push(normalizePath(x)))
|
||||
@@ -63,7 +63,6 @@ const builtinModules = [
|
||||
'ngx-toastr',
|
||||
'rxjs',
|
||||
'rxjs/operators',
|
||||
'rxjs-compat/Subject',
|
||||
'terminus-core',
|
||||
'terminus-settings',
|
||||
'terminus-terminal',
|
||||
@@ -83,7 +82,7 @@ const originalRequire = (global as any).require
|
||||
if (cachedBuiltinModules[query]) {
|
||||
return cachedBuiltinModules[query]
|
||||
}
|
||||
return originalRequire.apply(this, arguments)
|
||||
return originalRequire.apply(this, [query])
|
||||
}
|
||||
|
||||
const originalModuleRequire = nodeModule.prototype.require
|
||||
@@ -173,8 +172,8 @@ export async function loadPlugins (foundPlugins: PluginInfo[], progress: Progres
|
||||
console.time(label)
|
||||
const packageModule = nodeRequire(foundPlugin.path)
|
||||
const pluginModule = packageModule.default.forRoot ? packageModule.default.forRoot() : packageModule.default
|
||||
pluginModule['pluginName'] = foundPlugin.name
|
||||
pluginModule['bootstrap'] = packageModule.bootstrap
|
||||
pluginModule.pluginName = foundPlugin.name
|
||||
pluginModule.bootstrap = packageModule.bootstrap
|
||||
plugins.push(pluginModule)
|
||||
console.timeEnd(label)
|
||||
await new Promise(x => setTimeout(x, 50))
|
||||
|
@@ -9,6 +9,7 @@
|
||||
padding: 10px;
|
||||
background-image: none;
|
||||
width: auto;
|
||||
flex-basis: auto;
|
||||
|
||||
&.toast-error {
|
||||
background-color: #BD362F;
|
||||
|
@@ -12,7 +12,6 @@
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUnusedParameters": true,
|
||||
"noUnusedLocals": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
|
@@ -35,12 +35,15 @@ module.exports = {
|
||||
externals: {
|
||||
electron: 'commonjs electron',
|
||||
'electron-config': 'commonjs electron-config',
|
||||
'electron-promise-ipc': 'commonjs electron-promise-ipc',
|
||||
'electron-vibrancy': 'commonjs electron-vibrancy',
|
||||
fs: 'commonjs fs',
|
||||
glasstron: 'commonjs glasstron',
|
||||
mz: 'commonjs mz',
|
||||
npm: 'commonjs npm',
|
||||
path: 'commonjs path',
|
||||
yargs: 'commonjs yargs',
|
||||
util: 'commonjs util',
|
||||
'source-map-support': 'commonjs source-map-support',
|
||||
'windows-swca': 'commonjs windows-swca',
|
||||
'windows-blurbehind': 'commonjs windows-blurbehind',
|
||||
},
|
||||
@@ -50,4 +53,6 @@ module.exports = {
|
||||
'process.type': '"main"',
|
||||
}),
|
||||
],
|
||||
// Ignore warnings due to yarg's dynamic module loading
|
||||
ignoreWarnings: [/node_modules\/yargs/],
|
||||
}
|
||||
|
2412
app/yarn.lock
2412
app/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ platform:
|
||||
- x64
|
||||
|
||||
environment:
|
||||
nodejs_version: "10"
|
||||
nodejs_version: "15"
|
||||
|
||||
version: "{build}"
|
||||
|
||||
|
@@ -2,11 +2,32 @@
|
||||
appId: org.terminus
|
||||
productName: Terminus
|
||||
compression: normal
|
||||
npmRebuild: false
|
||||
afterSign: "./build/mac/afterSignHook.js"
|
||||
afterAllArtifactBuild: "./build/mac/afterBuildHook.js"
|
||||
files:
|
||||
- "**/*"
|
||||
- '**/*'
|
||||
- dist
|
||||
- '!lib'
|
||||
- '!src'
|
||||
- '!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme,node.lib}'
|
||||
- '!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples,docs}'
|
||||
- '!**/node_modules/@angular/common/locales'
|
||||
- '!**/node_modules/@angular/compiler/src'
|
||||
- '!**/node_modules/node-gyp'
|
||||
- '!**/node_modules/**/*.d.ts'
|
||||
- '!**/node_modules/**/*.map'
|
||||
- '!**/node_modules/**/include/node'
|
||||
- '!**/node_modules/.bin'
|
||||
- '!**/node_modules/*/*/{esm5,fesm5,esm2015,fesm2015,_esm2015,_fesm2015}'
|
||||
- '!**/*.{woff,ttf,otf,eot}'
|
||||
- '!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}'
|
||||
- '!.editorconfig'
|
||||
- '!**/._*'
|
||||
- '!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}'
|
||||
- '!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}'
|
||||
- '!**/{appveyor.yml,.travis.yml,circle.yml}'
|
||||
- '!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json'
|
||||
extraResources:
|
||||
- builtin-plugins
|
||||
- extras
|
||||
@@ -21,11 +42,12 @@ nsis:
|
||||
oneClick: false
|
||||
artifactName: terminus-${version}-setup.${ext}
|
||||
installerIcon: "./build/windows/icon.ico"
|
||||
allowToChangeInstallationDirectory: true
|
||||
|
||||
mac:
|
||||
category: public.app-category.video
|
||||
icon: "./build/mac/icon.icns"
|
||||
artifactName: terminus-${version}-macos.${ext}
|
||||
artifactName: terminus-${version}-macos-${env.ARCH}.${ext}
|
||||
hardenedRuntime: true
|
||||
entitlements: "./build/mac/entitlements.plist"
|
||||
entitlementsInherit: "./build/mac/entitlements.plist"
|
||||
@@ -40,9 +62,6 @@ mac:
|
||||
NSNetworkVolumesUsageDescription: 'A subprocess requests access to files on a network volume.'
|
||||
NSRemovableVolumesUsageDescription: 'A subprocess requests access to files on a removable volume.'
|
||||
|
||||
pkg:
|
||||
artifactName: terminus-${version}-macos.pkg
|
||||
|
||||
linux:
|
||||
category: Utilities
|
||||
icon: "./build/icons"
|
||||
|
83
package.json
83
package.json
@@ -1,61 +1,68 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.13.0",
|
||||
"@sentry/cli": "^1.52.3",
|
||||
"@sentry/electron": "^1.5.1",
|
||||
"@sentry/cli": "^1.61.0",
|
||||
"@sentry/electron": "^2.2.0",
|
||||
"@terminus-term/to-string-loader": "1.1.7-beta.1",
|
||||
"@types/electron-config": "^3.2.2",
|
||||
"@types/electron-debug": "^2.1.0",
|
||||
"@types/js-yaml": "^3.12.4",
|
||||
"@types/node": "12.7.12",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
"@typescript-eslint/eslint-plugin": "^2.26.0",
|
||||
"@typescript-eslint/parser": "^3.8.0",
|
||||
"@types/fs-extra": "^8.1.1",
|
||||
"@types/js-yaml": "^3.12.5",
|
||||
"@types/node": "14.14.14",
|
||||
"@types/webpack-env": "^1.16.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.14.1",
|
||||
"@typescript-eslint/parser": "^4.14.1",
|
||||
"apply-loader": "2.0.0",
|
||||
"awesome-typescript-loader": "^5.0.0",
|
||||
"core-js": "^3.6.5",
|
||||
"cross-env": "7.0.2",
|
||||
"css-loader": "3.4.2",
|
||||
"electron": "^8.2.5",
|
||||
"electron-builder": "22.6.1",
|
||||
"awesome-typescript-loader": "^5.2.1",
|
||||
"compare-versions": "^3.6.0",
|
||||
"core-js": "^3.8.3",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "5.0.1",
|
||||
"electron": "12.0.0-beta.25",
|
||||
"electron-builder": "22.10.4",
|
||||
"electron-download": "^4.1.1",
|
||||
"electron-installer-snap": "^5.0.0",
|
||||
"electron-installer-snap": "^5.1.0",
|
||||
"electron-notarize": "^1.0.0",
|
||||
"electron-rebuild": "^1.10.1",
|
||||
"eslint": "^7.6.0",
|
||||
"electron-rebuild": "^2.3.4",
|
||||
"eslint": "^7.18.0",
|
||||
"eslint-plugin-import": "^2.21.1",
|
||||
"file-loader": "^5.0.2",
|
||||
"file-loader": "^6.2.0",
|
||||
"graceful-fs": "^4.2.4",
|
||||
"html-loader": "0.5.5",
|
||||
"html-loader": "1.3.2",
|
||||
"json-loader": "0.5.7",
|
||||
"node-abi": "^2.16.0",
|
||||
"node-gyp": "^7.0.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"lru-cache": "^6.0.0",
|
||||
"macos-release": "^2.4.1",
|
||||
"node-abi": "^2.19.3",
|
||||
"node-gyp": "^7.1.2",
|
||||
"node-sass": "^5.0.0",
|
||||
"npmlog": "4.1.2",
|
||||
"npx": "^10.2.0",
|
||||
"pug": "^2.0.4",
|
||||
"npx": "^10.2.2",
|
||||
"patch-package": "^6.2.2",
|
||||
"pug": "^3.0.0",
|
||||
"pug-html-loader": "1.1.5",
|
||||
"pug-lint": "^2.6.0",
|
||||
"pug-loader": "^2.4.0",
|
||||
"pug-static-loader": "2.0.0",
|
||||
"raw-loader": "4.0.1",
|
||||
"sass-loader": "^8.0.0",
|
||||
"raw-loader": "4.0.2",
|
||||
"sass-loader": "^10.1.1",
|
||||
"shelljs": "0.8.4",
|
||||
"source-code-pro": "^2.30.2",
|
||||
"source-sans-pro": "3.6.0",
|
||||
"style-loader": "^1.1.4",
|
||||
"svg-inline-loader": "^0.8.0",
|
||||
"to-string-loader": "1.1.6",
|
||||
"tslib": "^2.0.0",
|
||||
"typedoc": "^0.17.7",
|
||||
"typescript": "^3.9.3",
|
||||
"url-loader": "^3.0.0",
|
||||
"val-loader": "2.1.1",
|
||||
"webpack": "^5.0.0-beta.18",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"ssh2-streams": "^0.4.10",
|
||||
"style-loader": "^2.0.0",
|
||||
"svg-inline-loader": "^0.8.2",
|
||||
"tslib": "^2.0.3",
|
||||
"typedoc": "^0.18.0",
|
||||
"typescript": "^3.9.7",
|
||||
"url-loader": "^4.1.1",
|
||||
"val-loader": "3.0.0",
|
||||
"webpack": "^5.18.0",
|
||||
"webpack-cli": "^4.4.0",
|
||||
"yaml-loader": "0.6.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"*/node-abi": "^2.14.0"
|
||||
"*/node-abi": "^2.19.3",
|
||||
"**/graceful-fs": "^4.2.4"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run build:typings && webpack --color --config app/webpack.main.config.js && webpack --color --config app/webpack.config.js && webpack --color --config terminus-core/webpack.config.js && webpack --color --config terminus-settings/webpack.config.js && webpack --color --config terminus-terminal/webpack.config.js && webpack --color --config terminus-plugin-manager/webpack.config.js && webpack --color --config terminus-community-color-schemes/webpack.config.js && webpack --color --config terminus-ssh/webpack.config.js && webpack --color --config terminus-serial/webpack.config.js",
|
||||
@@ -68,7 +75,5 @@
|
||||
"lint": "eslint --ext ts */src */lib",
|
||||
"postinstall": "node ./scripts/install-deps.js"
|
||||
},
|
||||
"repository": "eugeny/terminus",
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT"
|
||||
"private": true
|
||||
}
|
||||
|
12
patches/node-abi+2.19.3.patch
Normal file
12
patches/node-abi+2.19.3.patch
Normal file
@@ -0,0 +1,12 @@
|
||||
diff --git a/node_modules/node-abi/abi_registry.json b/node_modules/node-abi/abi_registry.json
|
||||
index bc1436d..630c1b7 100644
|
||||
--- a/node_modules/node-abi/abi_registry.json
|
||||
+++ b/node_modules/node-abi/abi_registry.json
|
||||
@@ -94,6 +94,6 @@
|
||||
"future": true,
|
||||
"lts": false,
|
||||
"runtime": "electron",
|
||||
- "target": "12.0.0-nightly.20201013"
|
||||
+ "target": "12.0.0-beta.16"
|
||||
}
|
||||
]
|
@@ -1,18 +1,20 @@
|
||||
#!/usr/bin/env node
|
||||
const builder = require('electron-builder').build
|
||||
const vars = require('./vars')
|
||||
const fs = require('fs')
|
||||
const signHook = require('../build/mac/afterSignHook')
|
||||
|
||||
const isTag = (process.env.GITHUB_REF || '').startsWith('refs/tags/')
|
||||
|
||||
process.env.ARCH = process.env.ARCH || process.arch
|
||||
|
||||
builder({
|
||||
dir: true,
|
||||
mac: ['pkg', 'zip'],
|
||||
arm64: process.env.ARCH === 'arm64',
|
||||
config: {
|
||||
extraMetadata: {
|
||||
version: vars.version,
|
||||
},
|
||||
npmRebuild: process.env.ARCH !== 'arm64',
|
||||
},
|
||||
publish: isTag ? 'always' : 'onTag',
|
||||
}).catch(e => {
|
||||
|
@@ -8,6 +8,7 @@ for (let dir of ['app', 'terminus-core', 'terminus-ssh', 'terminus-terminal']) {
|
||||
const build = rebuild({
|
||||
buildPath: path.resolve(__dirname, '../' + dir),
|
||||
electronVersion: vars.electronVersion,
|
||||
arch: process.env.ARCH ?? process.arch,
|
||||
force: true,
|
||||
})
|
||||
build.catch(e => {
|
||||
|
@@ -10,13 +10,13 @@ const npx = `${localBinPath}/npx`;
|
||||
log.info('deps', 'app')
|
||||
|
||||
sh.cd('app')
|
||||
sh.exec(`${npx} yarn install`)
|
||||
sh.exec(`${npx} yarn install --force`)
|
||||
sh.cd('..')
|
||||
|
||||
vars.builtinPlugins.forEach(plugin => {
|
||||
log.info('deps', plugin)
|
||||
sh.cd(plugin)
|
||||
sh.exec(`${npx} yarn install`)
|
||||
sh.exec(`${npx} yarn install --force`)
|
||||
sh.cd('..')
|
||||
})
|
||||
|
||||
|
@@ -15,10 +15,17 @@ vars.builtinPlugins.forEach(plugin => {
|
||||
sh.cp('-r', path.join('..', plugin), '.')
|
||||
sh.rm('-rf', path.join(plugin, 'node_modules'))
|
||||
sh.cd(plugin)
|
||||
sh.exec(`npm install --only=prod`)
|
||||
sh.exec(`yarn install --force --production`)
|
||||
|
||||
|
||||
log.info('rebuild', 'native')
|
||||
if (fs.existsSync('node_modules')) {
|
||||
rebuild(path.resolve('.'), vars.electronVersion, process.arch, [], true)
|
||||
rebuild({
|
||||
buildPath: path.resolve('.'),
|
||||
electronVersion: vars.electronVersion,
|
||||
arch: process.env.ARCH ?? process.arch,
|
||||
force: true,
|
||||
})
|
||||
}
|
||||
sh.cd('..')
|
||||
})
|
||||
|
24
scripts/sentry-upload.js
Executable file
24
scripts/sentry-upload.js
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env node
|
||||
const sh = require('shelljs')
|
||||
const vars = require('./vars')
|
||||
|
||||
const sentryCli = process.platform === 'win32' ? 'node_modules\\.bin\\sentry-cli.cmd' : 'sentry-cli'
|
||||
|
||||
sh.exec(`${sentryCli} releases new ${vars.version}`)
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
for (const path of [
|
||||
'app/node_modules/@serialport/bindings/build/Release/bindings.node',
|
||||
'app/node_modules/@terminus-term/node-pty/build/Release/pty.node',
|
||||
'app/node_modules/fontmanager-redux/build/Release/fontmanager.node',
|
||||
'app/node_modules/macos-native-processlist/build/Release/native.node',
|
||||
]) {
|
||||
sh.exec('dsymutil ' + path)
|
||||
}
|
||||
}
|
||||
|
||||
sh.exec(`${sentryCli} upload-dif app/node_modules`)
|
||||
sh.exec(`${sentryCli} releases set-commits --auto ${vars.version}`)
|
||||
for (const p of vars.builtinPlugins) {
|
||||
sh.exec(`${sentryCli} releases files ${vars.version} upload-sourcemaps ${p}/dist -u ${p}/dist/ -d ${process.platform}-${p}`)
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-community-color-schemes",
|
||||
"version": "1.0.104-nightly.0",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"description": "Community color schemes for Terminus",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -17,7 +17,7 @@
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@angular/core": "^7",
|
||||
"@angular/core": "^9.1.9",
|
||||
"terminus-core": "*",
|
||||
"terminus-terminal": "*"
|
||||
}
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TerminalColorSchemeProvider, TerminalColorScheme } from 'terminus-terminal'
|
||||
|
||||
const schemeContents = require.context('../schemes/', true, /.*/)
|
||||
const schemeContents = require.context('../schemes/', false, /.*/)
|
||||
|
||||
@Injectable()
|
||||
export class ColorSchemes extends TerminalColorSchemeProvider {
|
||||
async getSchemes (): Promise<TerminalColorScheme[]> {
|
||||
const schemes: TerminalColorScheme[] = []
|
||||
|
||||
schemeContents.keys().forEach(schemeFile => {
|
||||
schemeContents.keys().filter(x => !x.startsWith('./')).forEach(schemeFile => {
|
||||
const lines = (schemeContents(schemeFile).default as string).split('\n')
|
||||
|
||||
// process #define variables
|
||||
|
@@ -1,51 +1,6 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-community-color-schemes:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: {
|
||||
loader: 'awesome-typescript-loader',
|
||||
options: {
|
||||
configFileName: path.resolve(__dirname, 'tsconfig.json'),
|
||||
typeRoots: [
|
||||
path.resolve(__dirname, 'node_modules/@types'),
|
||||
path.resolve(__dirname, '../node_modules/@types'),
|
||||
],
|
||||
paths: {
|
||||
"terminus-*": [path.resolve(__dirname, '../terminus-*')],
|
||||
"*": [path.resolve(__dirname, '../app/node_modules/*')],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ test: /[\\\/]schemes[\\\/]/, use: "raw-loader" },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
/^terminus-/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'community-color-schemes',
|
||||
dirname: __dirname,
|
||||
})
|
||||
module.exports.module.rules.push({ test: /[\\\/]schemes[\\\/]/, use: 'raw-loader' })
|
||||
|
1
terminus-core/.gitignore
vendored
1
terminus-core/.gitignore
vendored
@@ -1,2 +1 @@
|
||||
dist
|
||||
node_modules
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-core",
|
||||
"version": "1.0.104-nightly.0",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"description": "Terminus core",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -20,7 +20,7 @@
|
||||
"@types/js-yaml": "^3.9.0",
|
||||
"@types/shell-escape": "^0.2.0",
|
||||
"@types/winston": "^2.3.6",
|
||||
"axios": "^0.19.0",
|
||||
"axios": "^0.21.1",
|
||||
"bootstrap": "^4.1.3",
|
||||
"core-js": "^3.1.2",
|
||||
"deepmerge": "^4.1.1",
|
||||
@@ -29,17 +29,18 @@
|
||||
"mixpanel": "^0.10.2",
|
||||
"ng2-dnd": "^5.0.2",
|
||||
"ngx-perfect-scrollbar": "^8.0.0",
|
||||
"readable-stream": "2.3.7",
|
||||
"shell-escape": "^0.2.0",
|
||||
"uuid": "^8.0.0",
|
||||
"winston": "^3.2.1"
|
||||
"winston": "^3.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/animations": "^7",
|
||||
"@angular/common": "^7",
|
||||
"@angular/core": "^7",
|
||||
"@angular/forms": "^7",
|
||||
"@angular/platform-browser": "^7",
|
||||
"@angular/platform-browser-dynamic": "^7",
|
||||
"rxjs": "^5"
|
||||
"@angular/animations": "^9.1.9",
|
||||
"@angular/common": "^9.1.11",
|
||||
"@angular/core": "^9.1.9",
|
||||
"@angular/forms": "^9.1.11",
|
||||
"@angular/platform-browser": "^9.1.11",
|
||||
"@angular/platform-browser-dynamic": "^9.1.11",
|
||||
"rxjs": "^6.6.3"
|
||||
}
|
||||
}
|
||||
|
@@ -33,5 +33,5 @@ export abstract class ConfigProvider {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
platformDefaults: {[platform: string]: any} = {}
|
||||
platformDefaults: Record<string, any> = {}
|
||||
}
|
||||
|
@@ -8,7 +8,5 @@ export interface HotkeyDescription {
|
||||
* must also provide the `hotkeys.foo` config options with the default values
|
||||
*/
|
||||
export abstract class HotkeyProvider {
|
||||
hotkeys: HotkeyDescription[] = []
|
||||
|
||||
abstract provide (): Promise<HotkeyDescription[]>
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import type { MenuItemConstructorOptions } from 'electron'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { TabHeaderComponent } from '../components/tabHeader.component'
|
||||
|
||||
@@ -7,5 +8,5 @@ import { TabHeaderComponent } from '../components/tabHeader.component'
|
||||
export abstract class TabContextMenuItemProvider {
|
||||
weight = 0
|
||||
|
||||
abstract async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]>
|
||||
abstract async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]>
|
||||
}
|
||||
|
@@ -4,10 +4,13 @@ title-bar(
|
||||
)
|
||||
|
||||
.content(
|
||||
[class.tabs-on-top]='config.store.appearance.tabsLocation == "top"'
|
||||
[class.tabs-on-top]='config.store.appearance.tabsLocation == "top" || config.store.appearance.tabsLocation == "left"',
|
||||
[class.tabs-on-side]='hasVerticalTabs()',
|
||||
)
|
||||
.tab-bar
|
||||
.inset.background(*ngIf='hostApp.platform == Platform.macOS && config.store.appearance.frame == "thin" && config.store.appearance.tabsLocation == "top"')
|
||||
.inset.background(*ngIf='hostApp.platform == Platform.macOS \
|
||||
&& config.store.appearance.frame == "thin" \
|
||||
&& (config.store.appearance.tabsLocation == "top" || config.store.appearance.tabsLocation == "left")')
|
||||
.tabs(
|
||||
dnd-sortable-container,
|
||||
[sortableData]='app.tabs',
|
||||
@@ -18,12 +21,12 @@ title-bar(
|
||||
[sortableIndex]='idx',
|
||||
(onDragStart)='onTabDragStart()',
|
||||
(onDragEnd)='onTabDragEnd()',
|
||||
|
||||
[index]='idx',
|
||||
[tab]='tab',
|
||||
[active]='tab == app.activeTab',
|
||||
[hasActivity]='tab.activity$|async',
|
||||
@animateTab,
|
||||
[@.disabled]='hasVerticalTabs()',
|
||||
(click)='app.selectTab(tab)',
|
||||
[class.fully-draggable]='hostApp.platform != Platform.macOS',
|
||||
[class.drag-region]='hostApp.platform == Platform.macOS && !tabsDragging',
|
||||
@@ -87,7 +90,8 @@ title-bar(
|
||||
)
|
||||
|
||||
window-controls.background(
|
||||
*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)',
|
||||
)
|
||||
|
||||
start-page(*ngIf='ready && app.tabs.length == 0')
|
||||
|
@@ -15,29 +15,77 @@
|
||||
|
||||
$tabs-height: 38px;
|
||||
$tab-border-radius: 4px;
|
||||
$side-tab-width: 200px;
|
||||
|
||||
.wrap {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: 100%;
|
||||
flex: auto;
|
||||
width: 100vw;
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
|
||||
&.tabs-on-top {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.tabs-on-side {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
&.tabs-on-top {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.content.tabs-on-side > .tab-bar {
|
||||
height: 100%;
|
||||
width: $side-tab-width;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
flex-direction: column;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
|
||||
.tabs {
|
||||
width: $side-tab-width;
|
||||
flex: none;
|
||||
flex-direction: column;
|
||||
|
||||
tab-header {
|
||||
flex: 0 0 $tabs-height;
|
||||
}
|
||||
}
|
||||
|
||||
.drag-space {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
&>.inset {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tab-bar {
|
||||
flex: none;
|
||||
height: $tabs-height;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
.btn-tab-bar {
|
||||
line-height: $tabs-height + 2px;
|
||||
height: $tabs-height;
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 15px;
|
||||
flex: 0 0 auto;
|
||||
border-bottom: 2px solid transparent;
|
||||
@@ -50,6 +98,8 @@ $tab-border-radius: 4px;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
|
||||
align-items: center;
|
||||
|
||||
&.dropdown-toggle::after {
|
||||
display: none;
|
||||
}
|
||||
@@ -74,7 +124,9 @@ $tab-border-radius: 4px;
|
||||
|
||||
& > .inset {
|
||||
width: 85px;
|
||||
height: $tabs-height;
|
||||
flex: none;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
window-controls {
|
||||
|
@@ -142,6 +142,8 @@ export class AppRootComponent {
|
||||
|
||||
this.touchbar.update()
|
||||
|
||||
this.hostApp.useBuiltinGraphics()
|
||||
|
||||
config.changed$.subscribe(() => this.updateVibrancy())
|
||||
this.updateVibrancy()
|
||||
|
||||
@@ -184,6 +186,10 @@ export class AppRootComponent {
|
||||
return false
|
||||
}
|
||||
|
||||
hasVerticalTabs () {
|
||||
return this.config.store.appearance.tabsLocation === 'left' || this.config.store.appearance.tabsLocation === 'right'
|
||||
}
|
||||
|
||||
async updateApp () {
|
||||
if ((await this.electron.showMessageBox(
|
||||
this.hostApp.getWindow(),
|
||||
@@ -225,8 +231,8 @@ export class AppRootComponent {
|
||||
buttons = buttons.concat(provider.provide())
|
||||
})
|
||||
return buttons
|
||||
.filter(button => (button.weight || 0) > 0 === aboveZero)
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight || 0) - (b.weight || 0))
|
||||
.filter(button => (button.weight ?? 0) > 0 === aboveZero)
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
}
|
||||
|
||||
private updateVibrancy () {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, HostListener, ViewChildren, QueryList, ElementRef } from '@angular/core'
|
||||
import { Component, Input, HostListener, ViewChildren, QueryList, ElementRef } from '@angular/core' // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { SelectorOption } from '../api/selector'
|
||||
|
||||
@@ -50,7 +50,7 @@ export class SelectorModalComponent<T> {
|
||||
this.filteredOptions = this.options.filter(x => !x.freeInputPattern)
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||
this.filteredOptions = this.options.filter(x => x.freeInputPattern || (x.name + (x.description || '')).toLowerCase().includes(f))
|
||||
this.filteredOptions = this.options.filter(x => x.freeInputPattern ?? (x.name + (x.description ?? '')).toLowerCase().includes(f))
|
||||
}
|
||||
this.selectedIndex = Math.max(0, this.selectedIndex)
|
||||
this.selectedIndex = Math.min(this.filteredOptions.length - 1, this.selectedIndex)
|
||||
@@ -72,7 +72,7 @@ export class SelectorModalComponent<T> {
|
||||
this.modalInstance.dismiss()
|
||||
}
|
||||
|
||||
iconIsSVG (icon: string): boolean {
|
||||
return icon?.startsWith('<')
|
||||
iconIsSVG (icon?: string): boolean {
|
||||
return icon?.startsWith('<') ?? false
|
||||
}
|
||||
}
|
||||
|
@@ -157,7 +157,11 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
/** @hidden */
|
||||
_spanners: SplitSpannerInfo[] = []
|
||||
|
||||
private focusedTab: BaseTabComponent
|
||||
/** @hidden */
|
||||
_allFocusMode = false
|
||||
|
||||
/** @hidden */
|
||||
private focusedTab: BaseTabComponent|null = null
|
||||
private maximizedTab: BaseTabComponent|null = null
|
||||
private hotkeysSubscription: Subscription
|
||||
private viewRefs: Map<BaseTabComponent, EmbeddedViewRef<any>> = new Map()
|
||||
@@ -207,7 +211,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
this.blurred$.subscribe(() => this.getAllTabs().forEach(x => x.emitBlurred()))
|
||||
|
||||
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
|
||||
if (!this.hasFocus) {
|
||||
if (!this.hasFocus || !this.focusedTab) {
|
||||
return
|
||||
}
|
||||
switch (hotkey) {
|
||||
@@ -254,12 +258,13 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
if (this._recoveredState) {
|
||||
await this.recoverContainer(this.root, this._recoveredState)
|
||||
this.layout()
|
||||
setImmediate(() => {
|
||||
setTimeout(() => {
|
||||
if (this.hasFocus) {
|
||||
this.getAllTabs().forEach(x => x.emitFocused())
|
||||
this.focusAnyIn(this.root)
|
||||
for (const tab of this.getAllTabs()) {
|
||||
this.focus(tab)
|
||||
}
|
||||
}
|
||||
})
|
||||
}, 100)
|
||||
}
|
||||
this.initialized.next()
|
||||
this.initialized.complete()
|
||||
@@ -275,7 +280,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
return this.root.getAllTabs()
|
||||
}
|
||||
|
||||
getFocusedTab (): BaseTabComponent {
|
||||
getFocusedTab (): BaseTabComponent|null {
|
||||
return this.focusedTab
|
||||
}
|
||||
|
||||
@@ -290,10 +295,8 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
x.emitBlurred()
|
||||
}
|
||||
}
|
||||
if (tab) {
|
||||
tab.emitFocused()
|
||||
this.focusChanged.next(tab)
|
||||
}
|
||||
tab.emitFocused()
|
||||
this.focusChanged.next(tab)
|
||||
|
||||
if (this.maximizedTab !== tab) {
|
||||
this.maximizedTab = null
|
||||
@@ -309,7 +312,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
/**
|
||||
* Focuses the first available tab inside the given [[SplitContainer]]
|
||||
*/
|
||||
focusAnyIn (parent: BaseTabComponent | SplitContainer): void {
|
||||
focusAnyIn (parent?: BaseTabComponent | SplitContainer): void {
|
||||
if (!parent) {
|
||||
return
|
||||
}
|
||||
@@ -326,7 +329,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
async addTab (tab: BaseTabComponent, relative: BaseTabComponent|null, side: SplitDirection): Promise<void> {
|
||||
tab.parent = this
|
||||
|
||||
let target = (relative ? this.getParentOf(relative) : null) || this.root
|
||||
let target = (relative ? this.getParentOf(relative) : null) ?? this.root
|
||||
let insertIndex = relative ? target.children.indexOf(relative) : -1
|
||||
|
||||
if (
|
||||
@@ -393,6 +396,10 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
* Moves focus in the given direction
|
||||
*/
|
||||
navigate (dir: SplitDirection): void {
|
||||
if (!this.focusedTab) {
|
||||
return
|
||||
}
|
||||
|
||||
let rel: BaseTabComponent | SplitContainer = this.focusedTab
|
||||
let parent = this.getParentOf(rel)
|
||||
if (!parent) {
|
||||
@@ -437,7 +444,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
* @returns the immediate parent of `tab`
|
||||
*/
|
||||
getParentOf (tab: BaseTabComponent | SplitContainer, root?: SplitContainer): SplitContainer|null {
|
||||
root = root || this.root
|
||||
root = root ?? this.root
|
||||
for (const child of root.children) {
|
||||
if (child instanceof SplitContainer) {
|
||||
const r = this.getParentOf(tab, child)
|
||||
@@ -464,7 +471,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
|
||||
/** @hidden */
|
||||
async getCurrentProcess (): Promise<BaseTabProcess|null> {
|
||||
return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x) || null
|
||||
return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x) ?? null
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@@ -480,6 +487,12 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
}
|
||||
}
|
||||
|
||||
layout (): void {
|
||||
this.root.normalize()
|
||||
this._spanners = []
|
||||
this.layoutInternal(this.root, 0, 0, 100, 100)
|
||||
}
|
||||
|
||||
private attachTabView (tab: BaseTabComponent) {
|
||||
const ref = this.viewContainer.insert(tab.hostView) as EmbeddedViewRef<any> // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
this.viewRefs.set(tab, ref)
|
||||
@@ -505,15 +518,9 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
}
|
||||
}
|
||||
|
||||
private layout () {
|
||||
this.root.normalize()
|
||||
this._spanners = []
|
||||
this.layoutInternal(this.root, 0, 0, 100, 100)
|
||||
}
|
||||
|
||||
private layoutInternal (root: SplitContainer, x: number, y: number, w: number, h: number) {
|
||||
const size = root.orientation === 'v' ? h : w
|
||||
const sizes = root.ratios.map(x => x * size)
|
||||
const sizes = root.ratios.map(ratio => ratio * size)
|
||||
|
||||
root.x = x
|
||||
root.y = y
|
||||
@@ -535,7 +542,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
element.classList.toggle('child', true)
|
||||
element.classList.toggle('maximized', child === this.maximizedTab)
|
||||
element.classList.toggle('minimized', this.maximizedTab && child !== this.maximizedTab)
|
||||
element.classList.toggle('focused', child === this.focusedTab)
|
||||
element.classList.toggle('focused', this._allFocusMode || child === this.focusedTab)
|
||||
element.style.left = `${childX}%`
|
||||
element.style.top = `${childY}%`
|
||||
element.style.width = `${childW}%`
|
||||
@@ -593,7 +600,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
@Injectable()
|
||||
export class SplitTabRecoveryProvider extends TabRecoveryProvider {
|
||||
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
|
||||
if (recoveryToken && recoveryToken.type === 'app:split-tab') {
|
||||
if (recoveryToken.type === 'app:split-tab') {
|
||||
return {
|
||||
type: SplitTabComponent,
|
||||
options: { _recoveredState: recoveryToken },
|
||||
|
@@ -34,8 +34,8 @@ export class SplitTabSpannerComponent {
|
||||
let current = start
|
||||
const oldPosition: number = this.isVertical ? this.element.nativeElement.offsetTop : this.element.nativeElement.offsetLeft
|
||||
|
||||
const dragHandler = (e: MouseEvent) => {
|
||||
current = this.isVertical ? e.pageY : e.pageX
|
||||
const dragHandler = (dragEvent: MouseEvent) => {
|
||||
current = this.isVertical ? dragEvent.pageY : dragEvent.pageX
|
||||
const newPosition = oldPosition + (current - start)
|
||||
if (this.isVertical) {
|
||||
this.element.nativeElement.style.top = `${newPosition - this.marginOffset}px`
|
||||
|
@@ -26,10 +26,10 @@ export class StartPageComponent {
|
||||
.map(provider => provider.provide())
|
||||
.reduce((a, b) => a.concat(b))
|
||||
.filter(x => !!x.click)
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight || 0) - (b.weight || 0))
|
||||
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
}
|
||||
|
||||
sanitizeIcon (icon: string): any {
|
||||
return this.domSanitizer.bypassSecurityTrustHtml(icon || '')
|
||||
sanitizeIcon (icon?: string): any {
|
||||
return this.domSanitizer.bypassSecurityTrustHtml(icon ?? '')
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
.progressbar([style.width]='progress + "%"', *ngIf='progress != null')
|
||||
.index(
|
||||
.index(*ngIf='!config.store.terminal.hideTabIndex',
|
||||
#handle,
|
||||
[style.background-color]='tab.color',
|
||||
) {{index + 1}}
|
||||
.name([title]='tab.customTitle || tab.title') {{tab.customTitle || tab.title}}
|
||||
button((click)='app.closeTab(tab, true)') ×
|
||||
button(*ngIf='!config.store.terminal.hideCloseButton',(click)='app.closeTab(tab, true)') ×
|
||||
|
@@ -7,12 +7,22 @@ $tabs-height: 38px;
|
||||
flex: 1000 1 200px;
|
||||
width: 200px;
|
||||
|
||||
&.flex-width {
|
||||
flex: 1000 1 auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
min-width: 0;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
&.vertical {
|
||||
flex: none;
|
||||
height: $tabs-height;
|
||||
}
|
||||
|
||||
.index {
|
||||
flex: none;
|
||||
font-weight: bold;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import type { MenuItemConstructorOptions } from 'electron'
|
||||
import { Component, Input, Optional, Inject, HostBinding, HostListener, ViewChild, ElementRef } from '@angular/core'
|
||||
import { SortableComponent } from 'ng2-dnd'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
@@ -9,10 +10,11 @@ import { HotkeysService } from '../services/hotkeys.service'
|
||||
import { ElectronService } from '../services/electron.service'
|
||||
import { AppService } from '../services/app.service'
|
||||
import { HostAppService, Platform } from '../services/hostApp.service'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
|
||||
/** @hidden */
|
||||
export interface SortableComponentProxy {
|
||||
setDragHandle (_: HTMLElement)
|
||||
setDragHandle: (_: HTMLElement) => void
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@@ -31,6 +33,7 @@ export class TabHeaderComponent {
|
||||
|
||||
private constructor (
|
||||
public app: AppService,
|
||||
public config: ConfigService,
|
||||
private electron: ElectronService,
|
||||
private hostApp: HostAppService,
|
||||
private ngbModal: NgbModal,
|
||||
@@ -69,8 +72,8 @@ export class TabHeaderComponent {
|
||||
}).catch(() => null)
|
||||
}
|
||||
|
||||
async buildContextMenu (): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
let items: Electron.MenuItemConstructorOptions[] = []
|
||||
async buildContextMenu (): Promise<MenuItemConstructorOptions[]> {
|
||||
let items: MenuItemConstructorOptions[] = []
|
||||
for (const section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(this.tab, this)))) {
|
||||
items.push({ type: 'separator' })
|
||||
items = items.concat(section)
|
||||
@@ -78,6 +81,10 @@ export class TabHeaderComponent {
|
||||
return items.slice(1)
|
||||
}
|
||||
|
||||
@HostBinding('class.flex-width') get isFlexWidthEnabled (): boolean {
|
||||
return this.config.store.appearance.flexTabs
|
||||
}
|
||||
|
||||
@HostListener('dblclick') onDoubleClick (): void {
|
||||
this.showRenameTabModal()
|
||||
}
|
||||
|
@@ -12,7 +12,8 @@ button {
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
text-align: center;
|
||||
|
||||
align-items: center;
|
||||
|
||||
&:not(:hover):not(:active) {
|
||||
background: transparent;
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ appearance:
|
||||
dockFill: 0.5
|
||||
dockHideOnBlur: false
|
||||
dockAlwaysOnTop: true
|
||||
flexTabs: false
|
||||
tabsLocation: top
|
||||
cycleTabs: true
|
||||
theme: Standard
|
||||
|
@@ -44,8 +44,11 @@ import 'ng2-dnd/bundles/style.css'
|
||||
// PerfectScrollbar fix
|
||||
import { fromEvent } from 'rxjs/internal/observable/fromEvent'
|
||||
import { merge } from 'rxjs/internal/observable/merge'
|
||||
require('rxjs').fromEvent = fromEvent
|
||||
require('rxjs').merge = merge
|
||||
|
||||
try {
|
||||
require('rxjs').fromEvent = fromEvent
|
||||
require('rxjs').merge = merge
|
||||
} catch {}
|
||||
|
||||
const PROVIDERS = [
|
||||
{ provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true },
|
||||
@@ -110,7 +113,7 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
})
|
||||
}
|
||||
|
||||
static forRoot (): ModuleWithProviders {
|
||||
static forRoot (): ModuleWithProviders<AppModule> {
|
||||
return {
|
||||
ngModule: AppModule,
|
||||
providers: PROVIDERS,
|
||||
|
@@ -46,13 +46,13 @@ class CompletionObserver {
|
||||
export class AppService {
|
||||
tabs: BaseTabComponent[] = []
|
||||
|
||||
get activeTab (): BaseTabComponent { return this._activeTab }
|
||||
get activeTab (): BaseTabComponent|null { return this._activeTab ?? null }
|
||||
|
||||
private lastTabIndex = 0
|
||||
private _activeTab: BaseTabComponent
|
||||
private _activeTab: BaseTabComponent | null = null
|
||||
private closedTabsStack: RecoveryToken[] = []
|
||||
|
||||
private activeTabChange = new Subject<BaseTabComponent>()
|
||||
private activeTabChange = new Subject<BaseTabComponent|null>()
|
||||
private tabsChanged = new Subject<void>()
|
||||
private tabOpened = new Subject<BaseTabComponent>()
|
||||
private tabClosed = new Subject<BaseTabComponent>()
|
||||
@@ -60,7 +60,7 @@ export class AppService {
|
||||
|
||||
private completionObservers = new Map<BaseTabComponent, CompletionObserver>()
|
||||
|
||||
get activeTabChange$ (): Observable<BaseTabComponent> { return this.activeTabChange }
|
||||
get activeTabChange$ (): Observable<BaseTabComponent|null> { return this.activeTabChange }
|
||||
get tabOpened$ (): Observable<BaseTabComponent> { return this.tabOpened }
|
||||
get tabsChanged$ (): Observable<void> { return this.tabsChanged }
|
||||
get tabClosed$ (): Observable<BaseTabComponent> { return this.tabClosed }
|
||||
@@ -97,9 +97,7 @@ export class AppService {
|
||||
}
|
||||
}
|
||||
|
||||
hostApp.windowFocused$.subscribe(() => {
|
||||
this._activeTab?.emitFocused()
|
||||
})
|
||||
hostApp.windowFocused$.subscribe(() => this._activeTab?.emitFocused())
|
||||
|
||||
this.tabClosed$.subscribe(async tab => {
|
||||
const token = await tab.getRecoveryToken()
|
||||
@@ -187,12 +185,12 @@ export class AppService {
|
||||
return null
|
||||
}
|
||||
|
||||
selectTab (tab: BaseTabComponent): void {
|
||||
if (this._activeTab === tab) {
|
||||
selectTab (tab: BaseTabComponent|null): void {
|
||||
if (tab && this._activeTab === tab) {
|
||||
this._activeTab.emitFocused()
|
||||
return
|
||||
}
|
||||
if (this.tabs.includes(this._activeTab)) {
|
||||
if (this._activeTab && this.tabs.includes(this._activeTab)) {
|
||||
this.lastTabIndex = this.tabs.indexOf(this._activeTab)
|
||||
} else {
|
||||
this.lastTabIndex = 0
|
||||
@@ -203,12 +201,10 @@ export class AppService {
|
||||
}
|
||||
this._activeTab = tab
|
||||
this.activeTabChange.next(tab)
|
||||
if (this._activeTab) {
|
||||
setImmediate(() => {
|
||||
this._activeTab.emitFocused()
|
||||
})
|
||||
this.hostApp.setTitle(this._activeTab.title)
|
||||
}
|
||||
setImmediate(() => {
|
||||
this._activeTab?.emitFocused()
|
||||
})
|
||||
this.hostApp.setTitle(this._activeTab?.title)
|
||||
}
|
||||
|
||||
getParentTab (tab: BaseTabComponent): SplitTabComponent|null {
|
||||
@@ -231,6 +227,9 @@ export class AppService {
|
||||
}
|
||||
|
||||
nextTab (): void {
|
||||
if (!this._activeTab) {
|
||||
return
|
||||
}
|
||||
if (this.tabs.length > 1) {
|
||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex < this.tabs.length - 1) {
|
||||
@@ -242,6 +241,9 @@ export class AppService {
|
||||
}
|
||||
|
||||
previousTab (): void {
|
||||
if (!this._activeTab) {
|
||||
return
|
||||
}
|
||||
if (this.tabs.length > 1) {
|
||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex > 0) {
|
||||
@@ -253,6 +255,9 @@ export class AppService {
|
||||
}
|
||||
|
||||
moveSelectedTabLeft (): void {
|
||||
if (!this._activeTab) {
|
||||
return
|
||||
}
|
||||
if (this.tabs.length > 1) {
|
||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex > 0) {
|
||||
@@ -264,6 +269,9 @@ export class AppService {
|
||||
}
|
||||
|
||||
moveSelectedTabRight (): void {
|
||||
if (!this._activeTab) {
|
||||
return
|
||||
}
|
||||
if (this.tabs.length > 1) {
|
||||
const tabIndex = this.tabs.indexOf(this._activeTab)
|
||||
if (tabIndex < this.tabs.length - 1) {
|
||||
|
@@ -97,7 +97,7 @@ export class ConfigService {
|
||||
private changed = new Subject<void>()
|
||||
private _store: any
|
||||
private defaults: any
|
||||
private servicesCache: { [id: string]: Function[] }|null = null
|
||||
private servicesCache: Record<string, Function[]>|null = null // eslint-disable-line @typescript-eslint/ban-types
|
||||
|
||||
get changed$ (): Observable<void> { return this.changed }
|
||||
|
||||
@@ -109,10 +109,7 @@ export class ConfigService {
|
||||
) {
|
||||
this.path = path.join(electron.app.getPath('userData'), 'config.yaml')
|
||||
this.defaults = configProviders.map(provider => {
|
||||
let defaults = {}
|
||||
if (provider.platformDefaults) {
|
||||
defaults = configMerge(defaults, provider.platformDefaults[hostApp.platform] || {})
|
||||
}
|
||||
let defaults = provider.platformDefaults[hostApp.platform] || {}
|
||||
if (provider.defaults) {
|
||||
defaults = configMerge(defaults, provider.defaults)
|
||||
}
|
||||
@@ -147,7 +144,7 @@ export class ConfigService {
|
||||
|
||||
load (): void {
|
||||
if (fs.existsSync(this.path)) {
|
||||
this._store = yaml.safeLoad(fs.readFileSync(this.path, 'utf8'))
|
||||
this._store = yaml.load(fs.readFileSync(this.path, 'utf8'))
|
||||
} else {
|
||||
this._store = {}
|
||||
}
|
||||
@@ -157,23 +154,23 @@ export class ConfigService {
|
||||
save (): void {
|
||||
// Scrub undefined values
|
||||
this._store = JSON.parse(JSON.stringify(this._store))
|
||||
fs.writeFileSync(this.path, yaml.safeDump(this._store), 'utf8')
|
||||
fs.writeFileSync(this.path, yaml.dump(this._store), 'utf8')
|
||||
this.emitChange()
|
||||
this.hostApp.broadcastConfigChange(this.store)
|
||||
this.hostApp.broadcastConfigChange(JSON.parse(JSON.stringify(this.store)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads config YAML as string
|
||||
*/
|
||||
readRaw (): string {
|
||||
return yaml.safeDump(this._store)
|
||||
return yaml.dump(this._store)
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes config YAML as string
|
||||
*/
|
||||
writeRaw (data: string): void {
|
||||
this._store = yaml.safeLoad(data)
|
||||
this._store = yaml.load(data)
|
||||
this.save()
|
||||
this.load()
|
||||
this.emitChange()
|
||||
@@ -189,15 +186,15 @@ export class ConfigService {
|
||||
*
|
||||
* @typeparam T Base provider type
|
||||
*/
|
||||
enabledServices<T extends object> (services: T[]): T[] {
|
||||
enabledServices<T extends object> (services: T[]): T[] { // eslint-disable-line @typescript-eslint/ban-types
|
||||
if (!this.servicesCache) {
|
||||
this.servicesCache = {}
|
||||
const ngModule = window['rootModule'].ɵinj
|
||||
for (const imp of ngModule.imports) {
|
||||
const module = imp['ngModule'] || imp
|
||||
const module = imp.ngModule || imp
|
||||
if (module.ɵinj?.providers) {
|
||||
this.servicesCache[module['pluginName']] = module.ɵinj.providers.map(provider => {
|
||||
return provider['useClass'] || provider
|
||||
this.servicesCache[module.pluginName] = module.ɵinj.providers.map(provider => {
|
||||
return provider.useClass || provider
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import type { Display } from 'electron'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { ElectronService } from '../services/electron.service'
|
||||
@@ -11,8 +12,8 @@ export class DockingService {
|
||||
private config: ConfigService,
|
||||
private hostApp: HostAppService,
|
||||
) {
|
||||
electron.screen.on('display-removed', () => this.repositionWindow())
|
||||
electron.screen.on('display-metrics-changed', () => this.repositionWindow())
|
||||
hostApp.displaysChanged$.subscribe(() => this.repositionWindow())
|
||||
hostApp.displayMetricsChanged$.subscribe(() => this.repositionWindow())
|
||||
}
|
||||
|
||||
dock (): void {
|
||||
@@ -25,6 +26,7 @@ export class DockingService {
|
||||
|
||||
let display = this.electron.screen.getAllDisplays()
|
||||
.filter(x => x.id === this.config.store.appearance.dockScreen)[0]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!display) {
|
||||
display = this.getCurrentScreen()
|
||||
}
|
||||
@@ -61,11 +63,11 @@ export class DockingService {
|
||||
})
|
||||
}
|
||||
|
||||
getCurrentScreen (): Electron.Display {
|
||||
getCurrentScreen (): Display {
|
||||
return this.electron.screen.getDisplayNearestPoint(this.electron.screen.getCursorScreenPoint())
|
||||
}
|
||||
|
||||
getScreens (): Electron.Display[] {
|
||||
getScreens (): Display[] {
|
||||
const primaryDisplayID = this.electron.screen.getPrimaryDisplay().id
|
||||
return this.electron.screen.getAllDisplays().sort((a, b) =>
|
||||
a.bounds.x === b.bounds.x ? a.bounds.y - b.bounds.y : a.bounds.x - b.bounds.x
|
||||
@@ -73,7 +75,7 @@ export class DockingService {
|
||||
return {
|
||||
...display,
|
||||
id: display.id,
|
||||
name: display.id === primaryDisplayID ? 'Primary Display' : `Display ${index +1}`,
|
||||
name: display.id === primaryDisplayID ? 'Primary Display' : `Display ${index + 1}`,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TouchBar, BrowserWindow, Menu, MenuItem, NativeImage } from 'electron'
|
||||
import { App, IpcRenderer, Shell, Dialog, Clipboard, GlobalShortcut, Screen, Remote, AutoUpdater, TouchBar, BrowserWindow, Menu, MenuItem, NativeImage, MessageBoxOptions } from 'electron'
|
||||
|
||||
export interface MessageBoxResponse {
|
||||
response: number
|
||||
@@ -8,16 +8,16 @@ export interface MessageBoxResponse {
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ElectronService {
|
||||
app: Electron.App
|
||||
ipcRenderer: Electron.IpcRenderer
|
||||
shell: Electron.Shell
|
||||
dialog: Electron.Dialog
|
||||
clipboard: Electron.Clipboard
|
||||
globalShortcut: Electron.GlobalShortcut
|
||||
app: App
|
||||
ipcRenderer: IpcRenderer
|
||||
shell: Shell
|
||||
dialog: Dialog
|
||||
clipboard: Clipboard
|
||||
globalShortcut: GlobalShortcut
|
||||
nativeImage: typeof NativeImage
|
||||
screen: Electron.Screen
|
||||
remote: Electron.Remote
|
||||
autoUpdater: Electron.AutoUpdater
|
||||
screen: Screen
|
||||
remote: Remote
|
||||
autoUpdater: AutoUpdater
|
||||
TouchBar: typeof TouchBar
|
||||
BrowserWindow: typeof BrowserWindow
|
||||
Menu: typeof Menu
|
||||
@@ -44,8 +44,8 @@ export class ElectronService {
|
||||
}
|
||||
|
||||
async showMessageBox (
|
||||
browserWindow: Electron.BrowserWindow,
|
||||
options: Electron.MessageBoxOptions
|
||||
browserWindow: BrowserWindow,
|
||||
options: MessageBoxOptions
|
||||
): Promise<MessageBoxResponse> {
|
||||
return this.dialog.showMessageBox(browserWindow, options)
|
||||
}
|
||||
|
@@ -58,7 +58,7 @@ export class HomeBaseService {
|
||||
|
||||
getAnalyticsProperties (): Record<string, string> {
|
||||
return {
|
||||
distinct_id: window.localStorage.analyticsUserID, // eslint-disable-line @typescript-eslint/camelcase
|
||||
distinct_id: window.localStorage.analyticsUserID,
|
||||
platform: process.platform,
|
||||
os: os.release(),
|
||||
version: this.appVersion,
|
||||
|
@@ -1,13 +1,23 @@
|
||||
import type { BrowserWindow, TouchBar, MenuItemConstructorOptions } from 'electron'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'mz/fs'
|
||||
import shellEscape from 'shell-escape'
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { Injectable, NgZone, EventEmitter } from '@angular/core'
|
||||
import { ElectronService } from './electron.service'
|
||||
import { Logger, LogService } from './log.service'
|
||||
import { isWindowsBuild, WIN_BUILD_FLUENT_BG_MOVE_BUG_FIXED, WIN_BUILD_FLUENT_BG_SUPPORTED } from '../utils'
|
||||
import { isWindowsBuild, WIN_BUILD_FLUENT_BG_SUPPORTED } from '../utils'
|
||||
|
||||
/* eslint-disable block-scoped-var */
|
||||
|
||||
try {
|
||||
var wnr = require('windows-native-registry') // eslint-disable-line @typescript-eslint/no-var-requires, no-var
|
||||
} catch (_) { }
|
||||
|
||||
export enum Platform {
|
||||
Linux, macOS, Windows,
|
||||
Linux = 'Linux',
|
||||
macOS = 'macOS',
|
||||
Windows = 'Windows',
|
||||
}
|
||||
|
||||
export interface Bounds {
|
||||
@@ -42,6 +52,7 @@ export class HostAppService {
|
||||
private windowMoved = new Subject<void>()
|
||||
private windowFocused = new Subject<void>()
|
||||
private displayMetricsChanged = new Subject<void>()
|
||||
private displaysChanged = new Subject<void>()
|
||||
private logger: Logger
|
||||
private windowId: number
|
||||
|
||||
@@ -91,6 +102,8 @@ export class HostAppService {
|
||||
|
||||
get displayMetricsChanged$ (): Observable<void> { return this.displayMetricsChanged }
|
||||
|
||||
get displaysChanged$ (): Observable<void> { return this.displaysChanged }
|
||||
|
||||
private constructor (
|
||||
private zone: NgZone,
|
||||
private electron: ElectronService,
|
||||
@@ -140,9 +153,14 @@ export class HostAppService {
|
||||
this.zone.run(() => this.displayMetricsChanged.next())
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('host:second-instance', (_$event, argv: any, cwd: string) => this.zone.run(() => {
|
||||
electron.ipcRenderer.on('host:displays-changed', () => {
|
||||
this.zone.run(() => this.displaysChanged.next())
|
||||
})
|
||||
|
||||
electron.ipcRenderer.on('cli', (_$event, argv: any, cwd: string, secondInstance: boolean) => this.zone.run(async () => {
|
||||
this.logger.info('Second instance', argv)
|
||||
const op = argv._[0]
|
||||
const opAsPath = op ? path.resolve(cwd, op) : null
|
||||
if (op === 'open') {
|
||||
this.cliOpenDirectory.next(path.resolve(cwd, argv.directory))
|
||||
} else if (op === 'run') {
|
||||
@@ -155,9 +173,13 @@ export class HostAppService {
|
||||
this.cliPaste.next(text)
|
||||
} else if (op === 'profile') {
|
||||
this.cliOpenProfile.next(argv.profileName)
|
||||
} else if (op === undefined) {
|
||||
} else if (secondInstance && op === undefined) {
|
||||
this.newWindow()
|
||||
} else {
|
||||
} else if (opAsPath && (await fs.lstat(opAsPath)).isDirectory()) {
|
||||
this.cliOpenDirectory.next(opAsPath)
|
||||
}
|
||||
|
||||
if (secondInstance) {
|
||||
this.secondInstance.next()
|
||||
}
|
||||
}))
|
||||
@@ -166,10 +188,7 @@ export class HostAppService {
|
||||
this.configChangeBroadcast.next()
|
||||
}))
|
||||
|
||||
if (
|
||||
isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED) &&
|
||||
!isWindowsBuild(WIN_BUILD_FLUENT_BG_MOVE_BUG_FIXED)
|
||||
) {
|
||||
if (isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED)) {
|
||||
electron.ipcRenderer.send('window-set-disable-vibrancy-while-dragging', true)
|
||||
}
|
||||
}
|
||||
@@ -177,8 +196,8 @@ export class HostAppService {
|
||||
/**
|
||||
* Returns the current remote [[BrowserWindow]]
|
||||
*/
|
||||
getWindow (): Electron.BrowserWindow {
|
||||
return this.electron.BrowserWindow.fromId(this.windowId)
|
||||
getWindow (): BrowserWindow {
|
||||
return this.electron.BrowserWindow.fromId(this.windowId)!
|
||||
}
|
||||
|
||||
newWindow (): void {
|
||||
@@ -228,29 +247,29 @@ export class HostAppService {
|
||||
* @param type `null`, or `fluent` when supported (Windowd only)
|
||||
*/
|
||||
setVibrancy (enable: boolean, type: string|null): void {
|
||||
if (!isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED)) {
|
||||
if (this.platform === Platform.Windows && !isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED)) {
|
||||
type = null
|
||||
}
|
||||
document.body.classList.toggle('vibrant', enable)
|
||||
this.electron.ipcRenderer.send('window-set-vibrancy', enable, type)
|
||||
}
|
||||
|
||||
setTitle (title: string): void {
|
||||
this.electron.ipcRenderer.send('window-set-title', title)
|
||||
setTitle (title?: string): void {
|
||||
this.electron.ipcRenderer.send('window-set-title', title ?? 'Terminus')
|
||||
}
|
||||
|
||||
setTouchBar (touchBar: Electron.TouchBar): void {
|
||||
setTouchBar (touchBar: TouchBar): void {
|
||||
this.getWindow().setTouchBar(touchBar)
|
||||
}
|
||||
|
||||
popupContextMenu (menuDefinition: Electron.MenuItemConstructorOptions[]): void {
|
||||
popupContextMenu (menuDefinition: MenuItemConstructorOptions[]): void {
|
||||
this.electron.Menu.buildFromTemplate(menuDefinition).popup({})
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies other windows of config file changes
|
||||
*/
|
||||
broadcastConfigChange (configStore: {[k: string]: any}): void {
|
||||
broadcastConfigChange (configStore: Record<string, any>): void {
|
||||
this.electron.ipcRenderer.send('app:config-change', configStore)
|
||||
}
|
||||
|
||||
@@ -270,6 +289,16 @@ export class HostAppService {
|
||||
this.electron.ipcRenderer.send('app:register-global-hotkey', specs)
|
||||
}
|
||||
|
||||
useBuiltinGraphics (): void {
|
||||
const keyPath = 'SOFTWARE\\Microsoft\\DirectX\\UserGpuPreferences'
|
||||
const valueName = this.electron.app.getPath('exe')
|
||||
if (this.platform === Platform.Windows) {
|
||||
if (!wnr.getRegistryValue(wnr.HK.CU, keyPath, valueName)) {
|
||||
wnr.setRegistryValue(wnr.HK.CU, keyPath, valueName, wnr.REG.SZ, 'GpuPreference=1;')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
relaunch (): void {
|
||||
if (this.isPortable) {
|
||||
this.electron.app.relaunch({ execPath: process.env.PORTABLE_EXECUTABLE_FILE })
|
||||
|
@@ -172,7 +172,7 @@ export class HotkeysService {
|
||||
return (
|
||||
await Promise.all(
|
||||
this.config.enabledServices(this.hotkeyProviders)
|
||||
.map(async x => x.provide ? x.provide() : x.hotkeys)
|
||||
.map(async x => x.provide())
|
||||
)
|
||||
).reduce((a, b) => a.concat(b))
|
||||
}
|
||||
@@ -222,7 +222,7 @@ export class HotkeysService {
|
||||
if (!(value instanceof Array)) {
|
||||
continue
|
||||
}
|
||||
if (value) {
|
||||
if (value.length > 0) {
|
||||
value = value.map((item: string | string[]) => typeof item === 'string' ? [item] : item)
|
||||
keys[key] = value
|
||||
}
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ElectronService } from './electron.service'
|
||||
import * as winston from 'winston'
|
||||
import type * as winston from 'winston'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
const initializeWinston = (electron: ElectronService) => {
|
||||
const logDirectory = electron.app.getPath('userData')
|
||||
// eslint-disable-next-line
|
||||
const winston = require('winston')
|
||||
|
||||
if (!fs.existsSync(logDirectory)) {
|
||||
fs.mkdirSync(logDirectory)
|
||||
@@ -28,7 +30,7 @@ const initializeWinston = (electron: ElectronService) => {
|
||||
|
||||
export class Logger {
|
||||
constructor (
|
||||
private winstonLogger: any,
|
||||
private winstonLogger: winston.Logger,
|
||||
private name: string,
|
||||
) {}
|
||||
|
||||
@@ -54,19 +56,21 @@ export class Logger {
|
||||
|
||||
private doLog (level: string, ...args: any[]): void {
|
||||
console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
|
||||
if (this.winstonLogger) {
|
||||
this.winstonLogger[level](...args)
|
||||
}
|
||||
this.winstonLogger[level](...args)
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class LogService {
|
||||
private log: any
|
||||
private log: winston.Logger
|
||||
|
||||
/** @hidden */
|
||||
private constructor (electron: ElectronService) {
|
||||
this.log = initializeWinston(electron)
|
||||
if (!process.env.XWEB) {
|
||||
this.log = initializeWinston(electron)
|
||||
} else {
|
||||
this.log = console as any
|
||||
}
|
||||
}
|
||||
|
||||
create (name: string): Logger {
|
||||
|
@@ -44,7 +44,7 @@ export class ShellIntegrationService {
|
||||
'extras',
|
||||
'automator-workflows',
|
||||
)
|
||||
this.automatorWorkflowsDestination = path.join(process.env.HOME as string, 'Library', 'Services')
|
||||
this.automatorWorkflowsDestination = path.join(process.env.HOME!, 'Library', 'Services')
|
||||
}
|
||||
this.updatePaths()
|
||||
}
|
||||
@@ -59,7 +59,7 @@ export class ShellIntegrationService {
|
||||
}
|
||||
|
||||
async install (): Promise<void> {
|
||||
const exe: string = process.env.PORTABLE_EXECUTABLE_FILE || this.electron.app.getPath('exe')
|
||||
const exe: string = process.env.PORTABLE_EXECUTABLE_FILE ?? this.electron.app.getPath('exe')
|
||||
if (this.hostApp.platform === Platform.macOS) {
|
||||
for (const wf of this.automatorWorkflows) {
|
||||
await exec(`cp -r "${this.automatorWorkflowsLocation}/${wf}" "${this.automatorWorkflowsDestination}"`)
|
||||
@@ -73,10 +73,10 @@ export class ShellIntegrationService {
|
||||
wnr.setRegistryValue(wnr.HK.CU, registryKey.path + '\\command', '', wnr.REG.SZ, exe + ' ' + registryKey.command)
|
||||
}
|
||||
|
||||
if(wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')) {
|
||||
if (wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')) {
|
||||
wnr.deleteRegistryKey(wnr.HK.CU, 'Software\\Classes\\Directory\\Background\\shell\\Open Terminus here')
|
||||
}
|
||||
if(wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')) {
|
||||
if (wnr.getRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')) {
|
||||
wnr.deleteRegistryKey(wnr.HK.CU, 'Software\\Classes\\*\\shell\\Paste path into Terminus')
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ export class TabRecoveryService {
|
||||
enabled = false
|
||||
|
||||
private constructor (
|
||||
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[],
|
||||
@Inject(TabRecoveryProvider) private tabRecoveryProviders: TabRecoveryProvider[]|null,
|
||||
private config: ConfigService,
|
||||
log: LogService
|
||||
) {
|
||||
@@ -23,35 +23,28 @@ export class TabRecoveryService {
|
||||
return
|
||||
}
|
||||
window.localStorage.tabsRecovery = JSON.stringify(
|
||||
await Promise.all(
|
||||
(await Promise.all(
|
||||
tabs
|
||||
.map(tab => {
|
||||
let token = tab.getRecoveryToken()
|
||||
if (token) {
|
||||
token = token.then(r => {
|
||||
if (r) {
|
||||
r.tabTitle = tab.title
|
||||
if (tab.color) {
|
||||
r.tabColor = tab.color
|
||||
}
|
||||
}
|
||||
return r
|
||||
})
|
||||
.map(async tab => tab.getRecoveryToken().then(r => {
|
||||
if (r) {
|
||||
r.tabTitle = tab.title
|
||||
if (tab.color) {
|
||||
r.tabColor = tab.color
|
||||
}
|
||||
}
|
||||
return token
|
||||
})
|
||||
.filter(token => !!token)
|
||||
)
|
||||
return r
|
||||
}))
|
||||
)).filter(token => !!token)
|
||||
)
|
||||
}
|
||||
|
||||
async recoverTab (token: RecoveryToken): Promise<RecoveredTab|null> {
|
||||
for (const provider of this.config.enabledServices(this.tabRecoveryProviders)) {
|
||||
for (const provider of this.config.enabledServices(this.tabRecoveryProviders ?? [])) {
|
||||
try {
|
||||
const tab = await provider.recover(token)
|
||||
if (tab !== null) {
|
||||
tab.options = tab.options || {}
|
||||
tab.options.color = token.tabColor || null
|
||||
tab.options.color = token.tabColor ?? null
|
||||
tab.options.title = token.tabTitle || ''
|
||||
return tab
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ export class TabsService {
|
||||
const componentRef = componentFactory.create(this.injector)
|
||||
const tab = componentRef.instance
|
||||
tab.hostView = componentRef.hostView
|
||||
Object.assign(tab, inputs || {})
|
||||
Object.assign(tab, inputs ?? {})
|
||||
return tab
|
||||
}
|
||||
|
||||
|
@@ -18,11 +18,11 @@ export class ThemesService {
|
||||
}
|
||||
|
||||
findTheme (name: string): Theme|null {
|
||||
return this.config.enabledServices(this.themes).find(x => x.name === name) || null
|
||||
return this.config.enabledServices(this.themes).find(x => x.name === name) ?? null
|
||||
}
|
||||
|
||||
findCurrentTheme (): Theme {
|
||||
return this.findTheme(this.config.store.appearance.theme) || this.findTheme('Standard')!
|
||||
return this.findTheme(this.config.store.appearance.theme) ?? this.findTheme('Standard')!
|
||||
}
|
||||
|
||||
applyTheme (theme: Theme): void {
|
||||
|
@@ -1,24 +1,18 @@
|
||||
import { Injectable, Inject, NgZone } from '@angular/core'
|
||||
import { TouchBarSegmentedControl, SegmentedControlSegment } from 'electron'
|
||||
import { SegmentedControlSegment, TouchBarSegmentedControl } from 'electron'
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { AppService } from './app.service'
|
||||
import { ConfigService } from './config.service'
|
||||
import { ElectronService } from './electron.service'
|
||||
import { HostAppService, Platform } from './hostApp.service'
|
||||
import { ToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TouchbarService {
|
||||
private tabsSegmentedControl: TouchBarSegmentedControl
|
||||
private buttonsSegmentedControl: TouchBarSegmentedControl
|
||||
private tabSegments: SegmentedControlSegment[] = []
|
||||
private nsImageCache: {[id: string]: Electron.NativeImage} = {}
|
||||
|
||||
private constructor (
|
||||
private app: AppService,
|
||||
private hostApp: HostAppService,
|
||||
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
private config: ConfigService,
|
||||
private electron: ElectronService,
|
||||
private zone: NgZone,
|
||||
) {
|
||||
@@ -33,6 +27,7 @@ export class TouchbarService {
|
||||
app.tabOpened$.subscribe(tab => {
|
||||
tab.titleChange$.subscribe(title => {
|
||||
const segment = this.tabSegments[app.tabs.indexOf(tab)]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (segment) {
|
||||
segment.label = this.shortenTitle(title)
|
||||
this.tabsSegmentedControl.segments = this.tabSegments
|
||||
@@ -41,6 +36,7 @@ export class TouchbarService {
|
||||
tab.activity$.subscribe(hasActivity => {
|
||||
const showIcon = this.app.activeTab !== tab && hasActivity
|
||||
const segment = this.tabSegments[app.tabs.indexOf(tab)]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (segment) {
|
||||
segment.icon = showIcon ? activityIcon : undefined
|
||||
}
|
||||
@@ -53,7 +49,7 @@ export class TouchbarService {
|
||||
label: this.shortenTitle(tab.title),
|
||||
}))
|
||||
this.tabsSegmentedControl.segments = this.tabSegments
|
||||
this.tabsSegmentedControl.selectedIndex = this.app.tabs.indexOf(this.app.activeTab)
|
||||
this.tabsSegmentedControl.selectedIndex = this.app.activeTab ? this.app.tabs.indexOf(this.app.activeTab) : 0
|
||||
}
|
||||
|
||||
update (): void {
|
||||
@@ -61,60 +57,22 @@ export class TouchbarService {
|
||||
return
|
||||
}
|
||||
|
||||
let buttons: ToolbarButton[] = []
|
||||
this.config.enabledServices(this.toolbarButtonProviders).forEach(provider => {
|
||||
buttons = buttons.concat(provider.provide())
|
||||
})
|
||||
buttons = buttons.filter(x => !!x.touchBarNSImage)
|
||||
buttons.sort((a, b) => (a.weight || 0) - (b.weight || 0))
|
||||
this.tabSegments = this.app.tabs.map(tab => ({
|
||||
label: this.shortenTitle(tab.title),
|
||||
}))
|
||||
|
||||
this.tabsSegmentedControl = new this.electron.TouchBar.TouchBarSegmentedControl({
|
||||
segments: this.tabSegments,
|
||||
selectedIndex: this.app.tabs.indexOf(this.app.activeTab),
|
||||
selectedIndex: this.app.activeTab ? this.app.tabs.indexOf(this.app.activeTab) : undefined,
|
||||
change: (selectedIndex) => this.zone.run(() => {
|
||||
this.app.selectTab(this.app.tabs[selectedIndex])
|
||||
}),
|
||||
})
|
||||
|
||||
this.buttonsSegmentedControl = new this.electron.TouchBar.TouchBarSegmentedControl({
|
||||
segments: buttons.map(button => this.getButton(button)),
|
||||
mode: 'buttons',
|
||||
change: (selectedIndex) => this.zone.run(() => {
|
||||
if (buttons[selectedIndex].click) {
|
||||
buttons[selectedIndex].click!()
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
const touchBar = new this.electron.TouchBar({
|
||||
items: [
|
||||
this.tabsSegmentedControl,
|
||||
new this.electron.TouchBar.TouchBarSpacer({ size: 'flexible' }),
|
||||
new this.electron.TouchBar.TouchBarSpacer({ size: 'small' }),
|
||||
this.buttonsSegmentedControl,
|
||||
],
|
||||
})
|
||||
this.hostApp.setTouchBar(touchBar)
|
||||
}
|
||||
|
||||
private getButton (button: ToolbarButton): Electron.SegmentedControlSegment {
|
||||
return {
|
||||
label: button.touchBarNSImage ? undefined : this.shortenTitle(button.touchBarTitle || button.title),
|
||||
icon: button.touchBarNSImage ? this.getCachedNSImage(button.touchBarNSImage) : undefined,
|
||||
// click: () => this.zone.run(() => button.click()),
|
||||
}
|
||||
}
|
||||
|
||||
private getCachedNSImage (name: string) {
|
||||
if (!this.nsImageCache[name]) {
|
||||
this.nsImageCache[name] = this.electron.nativeImage.createFromNamedImage(name, [0, 0, 1])
|
||||
}
|
||||
return this.nsImageCache[name]
|
||||
}
|
||||
|
||||
private shortenTitle (title: string): string {
|
||||
if (title.length > 15) {
|
||||
title = title.substring(0, 15) + '...'
|
||||
|
@@ -35,6 +35,10 @@ export class UpdaterService {
|
||||
this.logger.info('No updates')
|
||||
})
|
||||
|
||||
electron.autoUpdater.once('error', err => {
|
||||
this.logger.error(err)
|
||||
})
|
||||
|
||||
this.downloaded = new Promise<boolean>(resolve => {
|
||||
electron.autoUpdater.once('update-downloaded', () => resolve(true))
|
||||
})
|
||||
|
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import type { MenuItemConstructorOptions } from 'electron'
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { AppService } from './services/app.service'
|
||||
@@ -19,8 +20,8 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
let items: Electron.MenuItemConstructorOptions[] = [
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]> {
|
||||
let items: MenuItemConstructorOptions[] = [
|
||||
{
|
||||
label: 'Close',
|
||||
click: () => this.zone.run(() => {
|
||||
@@ -75,7 +76,7 @@ export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
||||
click: () => this.zone.run(() => {
|
||||
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
||||
}),
|
||||
})) as Electron.MenuItemConstructorOptions[],
|
||||
})) as MenuItemConstructorOptions[],
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -105,14 +106,14 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
let items: Electron.MenuItemConstructorOptions[] = []
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemConstructorOptions[]> {
|
||||
let items: MenuItemConstructorOptions[] = []
|
||||
if (tabHeader) {
|
||||
items = [
|
||||
...items,
|
||||
{
|
||||
label: 'Rename',
|
||||
click: () => this.zone.run(() => tabHeader?.showRenameTabModal()),
|
||||
click: () => this.zone.run(() => tabHeader.showRenameTabModal()),
|
||||
},
|
||||
{
|
||||
label: 'Duplicate',
|
||||
@@ -120,7 +121,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
},
|
||||
{
|
||||
label: 'Color',
|
||||
sublabel: COLORS.find(x => x.value === tab.color)!.name,
|
||||
sublabel: COLORS.find(x => x.value === tab.color)?.name,
|
||||
submenu: COLORS.map(color => ({
|
||||
label: color.name,
|
||||
type: 'radio',
|
||||
@@ -128,7 +129,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
click: () => this.zone.run(() => {
|
||||
tab.color = color.value
|
||||
}),
|
||||
})) as Electron.MenuItemConstructorOptions[],
|
||||
})) as MenuItemConstructorOptions[],
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -146,9 +147,9 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<Electron.MenuItemConstructorOptions[]> {
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemConstructorOptions[]> {
|
||||
const process = await tab.getCurrentProcess()
|
||||
let items: Electron.MenuItemConstructorOptions[] = []
|
||||
const items: MenuItemConstructorOptions[] = []
|
||||
|
||||
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = tab
|
||||
|
||||
|
@@ -1,12 +1,17 @@
|
||||
@import './theme.scss';
|
||||
|
||||
app-root {
|
||||
.tabs-on-side .tab-bar {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
height: 27px !important;
|
||||
|
||||
.btn-tab-bar {
|
||||
line-height: 29px !important;
|
||||
|
||||
height: 27px !important;
|
||||
align-items: center;
|
||||
svg {
|
||||
height: 14px;
|
||||
}
|
||||
|
@@ -137,7 +137,7 @@ app-root {
|
||||
.btn-tab-bar {
|
||||
background: transparent;
|
||||
line-height: 42px;
|
||||
|
||||
align-items: center;
|
||||
svg, path {
|
||||
fill: $black;
|
||||
fill-opacity: 0.75;
|
||||
|
@@ -358,6 +358,7 @@ search-panel {
|
||||
.btn-secondary:not(:disabled):not(.disabled) {
|
||||
&.active, &:active {
|
||||
background: #191e23;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,7 +4,6 @@ export const WIN_BUILD_CONPTY_SUPPORTED = 17692
|
||||
export const WIN_BUILD_CONPTY_STABLE = 18309
|
||||
export const WIN_BUILD_WSL_EXE_DISTRO_FLAG = 17763
|
||||
export const WIN_BUILD_FLUENT_BG_SUPPORTED = 17063
|
||||
export const WIN_BUILD_FLUENT_BG_MOVE_BUG_FIXED = 18917
|
||||
|
||||
export function isWindowsBuild (build: number): boolean {
|
||||
return process.platform === 'win32' && parseFloat(os.release()) >= 10 && parseInt(os.release().split('.')[2]) >= build
|
||||
|
@@ -1,60 +1,5 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-core:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: {
|
||||
loader: 'awesome-typescript-loader',
|
||||
options: {
|
||||
configFileName: path.resolve(__dirname, 'tsconfig.json'),
|
||||
typeRoots: [
|
||||
path.resolve(__dirname, 'node_modules/@types'),
|
||||
path.resolve(__dirname, '../node_modules/@types'),
|
||||
],
|
||||
paths: {
|
||||
"terminus-*": [path.resolve(__dirname, '../terminus-*')],
|
||||
"*": [path.resolve(__dirname, '../app/node_modules/*')],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ test: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
|
||||
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||
{ test: /\.css$/, use: ['to-string-loader', 'css-loader'], include: /component\.css/ },
|
||||
{ test: /\.css$/, use: ['style-loader', 'css-loader'], exclude: /component\.css/ },
|
||||
{ test: /\.yaml$/, use: ['json-loader', 'yaml-loader'] },
|
||||
{ test: /\.svg/, use: ['svg-inline-loader'] },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
'electron',
|
||||
'fs',
|
||||
'os',
|
||||
'path',
|
||||
'windows-native-registry',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'core',
|
||||
dirname: __dirname,
|
||||
})
|
||||
|
@@ -12,21 +12,14 @@
|
||||
kuler "^2.0.0"
|
||||
|
||||
"@types/js-yaml@^3.9.0":
|
||||
version "3.12.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.4.tgz#7d3b534ec35a0585128e2d332db1403ebe057e25"
|
||||
integrity sha512-fYMgzN+9e28R81weVN49inn/u798ruU91En1ZnGvSZzCRc5jXx9B2EDhlRaWmcO1RIxFHL8AajRXzxDuJu93+A==
|
||||
version "3.12.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.5.tgz#136d5e6a57a931e1cce6f9d8126aa98a9c92a6bb"
|
||||
integrity sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww==
|
||||
|
||||
"@types/node@*":
|
||||
version "13.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.1.tgz#238eb34a66431b71d2aaddeaa7db166f25971a0d"
|
||||
integrity sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==
|
||||
|
||||
"@types/semver@^7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.1.0.tgz#c8c630d4c18cd326beff77404887596f96408408"
|
||||
integrity sha512-pOKLaubrAEMUItGNpgwl0HMFPrSAFic8oSVIvfu1UwcgGNmNyK9gyhBHKmBnUTwwVvpZfkzUC0GaMgnL6P86uA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
"@types/semver@^7.3.1":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb"
|
||||
integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==
|
||||
|
||||
"@types/shell-escape@^0.2.0":
|
||||
version "0.2.0"
|
||||
@@ -64,22 +57,22 @@ at-least-node@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
|
||||
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
|
||||
|
||||
axios@^0.19.0:
|
||||
version "0.19.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
||||
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
bootstrap@^4.1.3:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01"
|
||||
integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==
|
||||
version "4.5.3"
|
||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.5.3.tgz#c6a72b355aaf323920be800246a6e4ef30997fe6"
|
||||
integrity sha512-o9ppKQioXGqhw8Z7mah6KdTYpNQY//tipnkxppWhPbiSWdD+1raYsnhwEZjkTHYbGee4cVQ0Rx65EhOY/HNLcQ==
|
||||
|
||||
builder-util-runtime@8.7.0:
|
||||
version "8.7.0"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.0.tgz#e48ad004835c8284662e8eaf47a53468c66e8e8d"
|
||||
integrity sha512-G1AqqVM2vYTrSFR982c1NNzwXKrGLQjVjaZaWQdn4O6Z3YKjdMDofw88aD9jpyK9ZXkrCxR0tI3Qe9wNbyTlXg==
|
||||
builder-util-runtime@8.7.2:
|
||||
version "8.7.2"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.2.tgz#d93afc71428a12789b437e13850e1fa7da956d72"
|
||||
integrity sha512-xBqv+8bg6cfnzAQK1k3OGpfaHg+QkPgIgpEkXNhouZ0WiUkyZCftuRc2LYzQrLucFywpa14Xbc6+hTbpq83yRA==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
sax "^1.2.4"
|
||||
@@ -102,9 +95,9 @@ color-name@^1.0.0:
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-string@^1.5.2:
|
||||
version "1.5.3"
|
||||
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc"
|
||||
integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==
|
||||
version "1.5.4"
|
||||
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6"
|
||||
integrity sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==
|
||||
dependencies:
|
||||
color-name "^1.0.0"
|
||||
simple-swizzle "^0.2.2"
|
||||
@@ -118,9 +111,9 @@ color@3.0.x:
|
||||
color-string "^1.5.2"
|
||||
|
||||
colors@^1.2.1:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d"
|
||||
integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
|
||||
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
|
||||
|
||||
colorspace@1.1.x:
|
||||
version "1.1.2"
|
||||
@@ -131,22 +124,15 @@ colorspace@1.1.x:
|
||||
text-hex "1.0.x"
|
||||
|
||||
core-js@^3.1.2:
|
||||
version "3.6.5"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
|
||||
integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==
|
||||
version "3.8.2"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.2.tgz#0a1fd6709246da9ca8eff5bb0cbd15fba9ac7044"
|
||||
integrity sha512-FfApuSRgrR6G5s58casCBd9M2k+4ikuu4wbW6pJyYU7bd9zvFc9qf7vr5xmrZOhT9nn+8uwlH1oRR9jTnFoA3A==
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
debug@=3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.1.0:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
@@ -155,11 +141,11 @@ debug@^3.1.0:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
||||
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1"
|
||||
integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
ms "2.1.2"
|
||||
|
||||
deepmerge@^4.1.1:
|
||||
version "4.2.2"
|
||||
@@ -167,17 +153,17 @@ deepmerge@^4.1.1:
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
|
||||
electron-updater@^4.0.6:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.1.tgz#9d485b6262bc56fcf7ee62b1dc1b3b105a3e96a7"
|
||||
integrity sha512-UDC5AHCgeiHJYDYWZG/rsl1vdAFKqI/Lm7whN57LKAk8EfhTewhcEHzheRcncLgikMcQL8gFo1KeX51tf5a5Wg==
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.5.tgz#4fb36f593a031c87ea07ee141c9f064d5deffb15"
|
||||
integrity sha512-5jjN7ebvfj1cLI0VZMdCnJk6aC4bP+dy7ryBf21vArR0JzpRVk0OZHA2QBD+H5rm6ZSeDYHOY6+8PrMEqJ4wlQ==
|
||||
dependencies:
|
||||
"@types/semver" "^7.1.0"
|
||||
builder-util-runtime "8.7.0"
|
||||
fs-extra "^9.0.0"
|
||||
js-yaml "^3.13.1"
|
||||
"@types/semver" "^7.3.1"
|
||||
builder-util-runtime "8.7.2"
|
||||
fs-extra "^9.0.1"
|
||||
js-yaml "^3.14.0"
|
||||
lazy-val "^1.0.4"
|
||||
lodash.isequal "^4.5.0"
|
||||
semver "^7.1.3"
|
||||
semver "^7.3.2"
|
||||
|
||||
enabled@2.0.x:
|
||||
version "2.0.0"
|
||||
@@ -185,9 +171,9 @@ enabled@2.0.x:
|
||||
integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
|
||||
|
||||
es6-promise@^4.0.3:
|
||||
version "4.2.6"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f"
|
||||
integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==
|
||||
version "4.2.8"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
|
||||
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
|
||||
|
||||
es6-promisify@^5.0.0:
|
||||
version "5.0.0"
|
||||
@@ -202,9 +188,9 @@ esprima@^4.0.0:
|
||||
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
|
||||
|
||||
fast-safe-stringify@^2.0.4:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2"
|
||||
integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
|
||||
integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==
|
||||
|
||||
fecha@^4.2.0:
|
||||
version "4.2.0"
|
||||
@@ -216,17 +202,15 @@ fn.name@1.x.x:
|
||||
resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
|
||||
integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
|
||||
|
||||
follow-redirects@1.5.10:
|
||||
version "1.5.10"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
||||
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
|
||||
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
|
||||
|
||||
fs-extra@^9.0.0:
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3"
|
||||
integrity sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==
|
||||
fs-extra@^9.0.1:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc"
|
||||
integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==
|
||||
dependencies:
|
||||
at-least-node "^1.0.0"
|
||||
graceful-fs "^4.2.0"
|
||||
@@ -234,9 +218,9 @@ fs-extra@^9.0.0:
|
||||
universalify "^1.0.0"
|
||||
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02"
|
||||
integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
|
||||
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
|
||||
|
||||
https-proxy-agent@3.0.0:
|
||||
version "3.0.0"
|
||||
@@ -247,9 +231,9 @@ https-proxy-agent@3.0.0:
|
||||
debug "^3.1.0"
|
||||
|
||||
inherits@^2.0.3, inherits@~2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
is-arrayish@^0.3.1:
|
||||
version "0.3.2"
|
||||
@@ -266,7 +250,7 @@ isarray@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
js-yaml@^3.13.1, js-yaml@^3.9.0:
|
||||
js-yaml@^3.14.0, js-yaml@^3.9.0:
|
||||
version "3.14.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
|
||||
integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
|
||||
@@ -275,11 +259,11 @@ js-yaml@^3.13.1, js-yaml@^3.9.0:
|
||||
esprima "^4.0.0"
|
||||
|
||||
jsonfile@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179"
|
||||
integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
|
||||
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
|
||||
dependencies:
|
||||
universalify "^1.0.0"
|
||||
universalify "^2.0.0"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
@@ -316,12 +300,7 @@ mixpanel@^0.10.2:
|
||||
dependencies:
|
||||
https-proxy-agent "3.0.0"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
ms@^2.1.1:
|
||||
ms@2.1.2, ms@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
@@ -347,16 +326,16 @@ one-time@^1.0.0:
|
||||
fn.name "1.x.x"
|
||||
|
||||
perfect-scrollbar@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.4.0.tgz#5d014ef9775e1f43058a1dbae9ed1daf0e7091f1"
|
||||
integrity sha512-/2Sk/khljhdrsamjJYS5NjrH+GKEHEwh7zFSiYyxROyYKagkE4kSn2zDQDRTOMo8mpT2jikxx6yI1dG7lNP/hw==
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/perfect-scrollbar/-/perfect-scrollbar-1.5.0.tgz#821d224ed8ff61990c23f26db63048cdc75b6b83"
|
||||
integrity sha512-NrNHJn5mUGupSiheBTy6x+6SXCFbLlm8fVZh9moIzw/LgqElN5q4ncR4pbCBCYuCJ8Kcl9mYM0NgDxvW+b4LxA==
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
|
||||
integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
readable-stream@^2.3.7:
|
||||
readable-stream@2.3.7, readable-stream@^2.3.7:
|
||||
version "2.3.7"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
|
||||
@@ -388,15 +367,20 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
sax@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
semver@^7.1.3:
|
||||
version "7.1.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6"
|
||||
integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==
|
||||
semver@^7.3.2:
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
|
||||
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
|
||||
|
||||
shell-escape@^0.2.0:
|
||||
version "0.2.0"
|
||||
@@ -421,11 +405,11 @@ stack-trace@0.0.x:
|
||||
integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
|
||||
|
||||
string_decoder@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
|
||||
integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
|
||||
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
safe-buffer "~5.2.0"
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
@@ -449,15 +433,20 @@ universalify@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"
|
||||
integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
|
||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||
|
||||
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
uuid@^8.0.0:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.2.0.tgz#cb10dd6b118e2dada7d0cd9730ba7417c93d920e"
|
||||
integrity sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==
|
||||
version "8.3.1"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31"
|
||||
integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==
|
||||
|
||||
winston-transport@^4.4.0:
|
||||
version "4.4.0"
|
||||
@@ -467,7 +456,7 @@ winston-transport@^4.4.0:
|
||||
readable-stream "^2.3.7"
|
||||
triple-beam "^1.2.0"
|
||||
|
||||
winston@*, winston@^3.2.1:
|
||||
winston@*, winston@^3.3.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170"
|
||||
integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-plugin-manager",
|
||||
"version": "1.0.104-nightly.0",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"description": "Terminus' plugin manager",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -18,17 +18,18 @@
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/semver": "^7.1.0",
|
||||
"axios": "^0.19.0",
|
||||
"axios": "^0.21.1",
|
||||
"electron-promise-ipc": "^2.2.4",
|
||||
"mz": "^2.6.0",
|
||||
"semver": "^7.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^7",
|
||||
"@angular/core": "^7",
|
||||
"@angular/forms": "^7",
|
||||
"@angular/platform-browser": "^7",
|
||||
"@ng-bootstrap/ng-bootstrap": "^1",
|
||||
"rxjs": "^5",
|
||||
"@angular/common": "^9.1.11",
|
||||
"@angular/core": "^9.1.9",
|
||||
"@angular/forms": "^9.1.11",
|
||||
"@angular/platform-browser": "^9.1.11",
|
||||
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
|
||||
"rxjs": "^6.5.5",
|
||||
"terminus-core": "*",
|
||||
"terminus-settings": "*"
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@
|
||||
strong Error in {{erroredPlugin}}:
|
||||
pre {{errorMessage}}
|
||||
|
||||
|
||||
.d-flex
|
||||
h3.mb-1 Installed
|
||||
button.btn.btn-outline-secondary.btn-sm.ml-auto((click)='openPluginsFolder()')
|
||||
@@ -11,42 +10,35 @@
|
||||
|
||||
.list-group.list-group-flush.mt-2
|
||||
.list-group-item.d-flex.align-items-center(*ngFor='let plugin of pluginManager.installedPlugins')
|
||||
toggle(
|
||||
[ngModel]='isPluginEnabled(plugin)',
|
||||
(ngModelChange)='togglePlugin(plugin)'
|
||||
)
|
||||
|
||||
.mr-auto.d-flex.flex-column
|
||||
div
|
||||
strong {{plugin.name}}
|
||||
small.text-muted.ml-1(*ngIf='!plugin.isBuiltin') {{plugin.version}} / {{plugin.author}}
|
||||
small.text-warning.ml-1(*ngIf='config.store.pluginBlacklist.includes(plugin.name)') Disabled
|
||||
small.text-warning.ml-1(*ngIf='!isPluginEnabled(plugin)') Disabled
|
||||
a.text-muted.mb-0((click)='showPluginInfo(plugin)')
|
||||
small {{plugin.description}}
|
||||
|
||||
button.btn.btn-primary.ml-2(
|
||||
*ngIf='knownUpgrades[plugin.name]',
|
||||
(click)='upgradePlugin(plugin)',
|
||||
[disabled]='busy[plugin.name] != undefined'
|
||||
[disabled]='busy.has(plugin.name)'
|
||||
)
|
||||
i.fas.fa-fw.fa-arrow-up(*ngIf='busy[plugin.name] != BusyState.Installing')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Installing')
|
||||
i.fas.fa-fw.fa-arrow-up(*ngIf='busy.get(plugin.name) != BusyState.Installing')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy.get(plugin.name) == BusyState.Installing')
|
||||
span Upgrade ({{knownUpgrades[plugin.name].version}})
|
||||
|
||||
button.btn.btn-link.text-primary.ml-2(
|
||||
*ngIf='config.store.pluginBlacklist.includes(plugin.name)',
|
||||
(click)='enablePlugin(plugin)'
|
||||
)
|
||||
i.fas.fa-fw.fa-play
|
||||
|
||||
button.btn.btn-link.ml-2(
|
||||
*ngIf='!config.store.pluginBlacklist.includes(plugin.name)',
|
||||
(click)='disablePlugin(plugin)'
|
||||
)
|
||||
i.fas.fa-fw.fa-pause
|
||||
|
||||
button.btn.btn-link.text-danger.ml-2(
|
||||
(click)='uninstallPlugin(plugin)',
|
||||
*ngIf='!plugin.isBuiltin',
|
||||
[disabled]='busy[plugin.name] != undefined'
|
||||
[disabled]='busy.has(plugin.name)'
|
||||
)
|
||||
i.fas.fa-fw.fa-trash(*ngIf='busy[plugin.name] != BusyState.Uninstalling')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Uninstalling')
|
||||
i.fas.fa-fw.fa-trash(*ngIf='busy.get(plugin.name) != BusyState.Uninstalling')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy.get(plugin.name) == BusyState.Uninstalling')
|
||||
|
||||
div
|
||||
h3.mt-4 Available
|
||||
@@ -69,10 +61,10 @@ div
|
||||
.list-group-item.d-flex.align-items-center(*ngIf='!isAlreadyInstalled(plugin)')
|
||||
button.btn.btn-primary.mr-3(
|
||||
(click)='installPlugin(plugin)',
|
||||
[disabled]='busy[plugin.name] != undefined'
|
||||
[disabled]='busy.has(plugin.name)'
|
||||
)
|
||||
i.fas.fa-fw.fa-download(*ngIf='busy[plugin.name] != BusyState.Installing')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Installing')
|
||||
i.fas.fa-fw.fa-download(*ngIf='busy.get(plugin.name) != BusyState.Installing')
|
||||
i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy.get(plugin.name) == BusyState.Installing')
|
||||
|
||||
div((click)='showPluginInfo(plugin)')
|
||||
div
|
||||
|
@@ -7,7 +7,7 @@ import { Component, Input } from '@angular/core'
|
||||
import { ConfigService, ElectronService } from 'terminus-core'
|
||||
import { PluginInfo, PluginManagerService } from '../services/pluginManager.service'
|
||||
|
||||
enum BusyState { Installing, Uninstalling }
|
||||
enum BusyState { Installing = 'Installing', Uninstalling = 'Uninstalling' }
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
@@ -19,8 +19,8 @@ export class PluginsSettingsTabComponent {
|
||||
@Input() availablePlugins$: Observable<PluginInfo[]>
|
||||
@Input() availablePluginsQuery$ = new BehaviorSubject<string>('')
|
||||
@Input() availablePluginsReady = false
|
||||
@Input() knownUpgrades: {[id: string]: PluginInfo|null} = {}
|
||||
@Input() busy: {[id: string]: BusyState} = {}
|
||||
@Input() knownUpgrades: Record<string, PluginInfo|null> = {}
|
||||
@Input() busy = new Map<string, BusyState>()
|
||||
@Input() erroredPlugin: string
|
||||
@Input() errorMessage: string
|
||||
|
||||
@@ -55,7 +55,7 @@ export class PluginsSettingsTabComponent {
|
||||
}
|
||||
|
||||
openPluginsFolder (): void {
|
||||
this.electron.shell.openItem(this.pluginManager.userPluginsPath)
|
||||
this.electron.shell.openPath(this.pluginManager.userPluginsPath)
|
||||
}
|
||||
|
||||
searchAvailable (query: string) {
|
||||
@@ -67,29 +67,29 @@ export class PluginsSettingsTabComponent {
|
||||
}
|
||||
|
||||
async installPlugin (plugin: PluginInfo): Promise<void> {
|
||||
this.busy[plugin.name] = BusyState.Installing
|
||||
this.busy.set(plugin.name, BusyState.Installing)
|
||||
try {
|
||||
await this.pluginManager.installPlugin(plugin)
|
||||
delete this.busy[plugin.name]
|
||||
this.busy.delete(plugin.name)
|
||||
this.config.requestRestart()
|
||||
} catch (err) {
|
||||
this.erroredPlugin = plugin.name
|
||||
this.errorMessage = err
|
||||
delete this.busy[plugin.name]
|
||||
this.busy.delete(plugin.name)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async uninstallPlugin (plugin: PluginInfo): Promise<void> {
|
||||
this.busy[plugin.name] = BusyState.Uninstalling
|
||||
this.busy.set(plugin.name, BusyState.Uninstalling)
|
||||
try {
|
||||
await this.pluginManager.uninstallPlugin(plugin)
|
||||
delete this.busy[plugin.name]
|
||||
this.busy.delete(plugin.name)
|
||||
this.config.requestRestart()
|
||||
} catch (err) {
|
||||
this.erroredPlugin = plugin.name
|
||||
this.errorMessage = err
|
||||
delete this.busy[plugin.name]
|
||||
this.busy.delete(plugin.name)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,18 @@ export class PluginsSettingsTabComponent {
|
||||
this.electron.shell.openExternal('https://www.npmjs.com/package/' + plugin.packageName)
|
||||
}
|
||||
|
||||
isPluginEnabled (plugin: PluginInfo) {
|
||||
return !this.config.store.pluginBlacklist.includes(plugin.name)
|
||||
}
|
||||
|
||||
togglePlugin (plugin: PluginInfo) {
|
||||
if (this.isPluginEnabled(plugin)) {
|
||||
this.disablePlugin(plugin)
|
||||
} else {
|
||||
this.enablePlugin(plugin)
|
||||
}
|
||||
}
|
||||
|
||||
enablePlugin (plugin: PluginInfo) {
|
||||
this.config.store.pluginBlacklist = this.config.store.pluginBlacklist.filter(x => x !== plugin.name)
|
||||
this.config.save()
|
||||
|
@@ -3,6 +3,7 @@ import { BrowserModule } from '@angular/platform-browser'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
import TerminusCorePlugin from 'terminus-core'
|
||||
import { SettingsTabProvider } from 'terminus-settings'
|
||||
|
||||
import { PluginsSettingsTabComponent } from './components/pluginsSettingsTab.component'
|
||||
@@ -14,6 +15,7 @@ import { PluginsSettingsTabProvider } from './settings'
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
NgbModule,
|
||||
TerminusCorePlugin,
|
||||
],
|
||||
providers: [
|
||||
{ provide: SettingsTabProvider, useClass: PluginsSettingsTabProvider, multi: true },
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import axios from 'axios'
|
||||
import promiseIpc from 'electron-promise-ipc'
|
||||
import { Observable, from } from 'rxjs'
|
||||
import { map } from 'rxjs/operators'
|
||||
import { Injectable } from '@angular/core'
|
||||
@@ -31,39 +32,15 @@ export class PluginManagerService {
|
||||
userPluginsPath: string = (window as any).userPluginsPath
|
||||
installedPlugins: PluginInfo[] = (window as any).installedPlugins
|
||||
|
||||
private npmReady: Promise<void>
|
||||
private npm: any
|
||||
|
||||
private constructor (
|
||||
log: LogService,
|
||||
) {
|
||||
this.logger = log.create('pluginManager')
|
||||
}
|
||||
|
||||
async getNPM (): Promise<any> {
|
||||
if (!this.npm) {
|
||||
if (!this.npmReady) {
|
||||
this.npmReady = new Promise(resolve => {
|
||||
const npm = (global as any).require('npm')
|
||||
npm.load({
|
||||
prefix: this.userPluginsPath,
|
||||
}, err => {
|
||||
if (err) {
|
||||
this.logger.error(err)
|
||||
}
|
||||
this.npm = npm
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
await this.npmReady
|
||||
}
|
||||
return this.npm
|
||||
}
|
||||
|
||||
listAvailable (query?: string): Observable<PluginInfo[]> {
|
||||
return from(
|
||||
axios.get(`https://www.npmjs.com/search?q=keywords%3A${KEYWORD}+${encodeURIComponent(query || '')}&from=0&size=1000`, {
|
||||
axios.get(`https://www.npmjs.com/search?q=keywords%3A${KEYWORD}+${encodeURIComponent(query ?? '')}&from=0&size=1000`, {
|
||||
headers: {
|
||||
'x-spiferack': '1',
|
||||
},
|
||||
@@ -84,21 +61,23 @@ export class PluginManagerService {
|
||||
}
|
||||
|
||||
async installPlugin (plugin: PluginInfo): Promise<void> {
|
||||
(await this.getNPM()).commands.install([`${plugin.packageName}@${plugin.version}`], err => {
|
||||
if (err) {
|
||||
this.logger.error(err)
|
||||
}
|
||||
try {
|
||||
await (promiseIpc as any).send('plugin-manager:install', this.userPluginsPath, plugin.packageName, plugin.version)
|
||||
this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
|
||||
this.installedPlugins.push(plugin)
|
||||
})
|
||||
} catch (err) {
|
||||
this.logger.error(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async uninstallPlugin (plugin: PluginInfo): Promise<void> {
|
||||
(await this.getNPM()).commands.remove([plugin.packageName], err => {
|
||||
if (err) {
|
||||
this.logger.error(err)
|
||||
}
|
||||
try {
|
||||
await (promiseIpc as any).send('plugin-manager:uninstall', this.userPluginsPath, plugin.packageName)
|
||||
this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
|
||||
})
|
||||
} catch (err) {
|
||||
this.logger.error(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,56 +1,5 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'cheap-module-source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-plugin-manager:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: {
|
||||
loader: 'awesome-typescript-loader',
|
||||
options: {
|
||||
configFileName: path.resolve(__dirname, 'tsconfig.json'),
|
||||
typeRoots: [
|
||||
path.resolve(__dirname, 'node_modules/@types'),
|
||||
path.resolve(__dirname, '../node_modules/@types'),
|
||||
],
|
||||
paths: {
|
||||
"terminus-*": [path.resolve(__dirname, '../terminus-*')],
|
||||
"*": [path.resolve(__dirname, '../app/node_modules/*')],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ test: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
|
||||
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
'fs',
|
||||
'net',
|
||||
'npm',
|
||||
'path',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
/^terminus-/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'plugin-manager',
|
||||
dirname: __dirname,
|
||||
})
|
||||
|
@@ -2,48 +2,139 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/node@*":
|
||||
version "13.7.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.6.tgz#cb734a7c191472ae6a2b3a502b4dfffcea974113"
|
||||
integrity sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA==
|
||||
|
||||
"@types/semver@^7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.1.0.tgz#c8c630d4c18cd326beff77404887596f96408408"
|
||||
integrity sha512-pOKLaubrAEMUItGNpgwl0HMFPrSAFic8oSVIvfu1UwcgGNmNyK9gyhBHKmBnUTwwVvpZfkzUC0GaMgnL6P86uA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb"
|
||||
integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==
|
||||
|
||||
any-promise@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
|
||||
|
||||
axios@^0.19.0:
|
||||
version "0.19.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
||||
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
debug@=3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||
call-bind@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce"
|
||||
integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
function-bind "^1.1.1"
|
||||
get-intrinsic "^1.0.0"
|
||||
|
||||
follow-redirects@1.5.10:
|
||||
version "1.5.10"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
||||
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
|
||||
define-properties@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
||||
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
object-keys "^1.0.12"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
electron-promise-ipc@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/electron-promise-ipc/-/electron-promise-ipc-2.2.4.tgz#b82daf86ca6d0f0b8655937fdbe9a554590deeea"
|
||||
integrity sha512-xCkFEeuru9l7H/+m1gpK4F1utexvTT7+n1PTquP2MVTpmBmpgFBlLqSXC7TqwpROkHRm9wGpaCJEx0djonnSEg==
|
||||
dependencies:
|
||||
is-electron-renderer "^2.0.1"
|
||||
object.entries "^1.1.3"
|
||||
serialize-error "^5.0.0"
|
||||
uuid "^3.0.1"
|
||||
|
||||
es-abstract@^1.18.0-next.1:
|
||||
version "1.18.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68"
|
||||
integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==
|
||||
dependencies:
|
||||
es-to-primitive "^1.2.1"
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
is-callable "^1.2.2"
|
||||
is-negative-zero "^2.0.0"
|
||||
is-regex "^1.1.1"
|
||||
object-inspect "^1.8.0"
|
||||
object-keys "^1.1.1"
|
||||
object.assign "^4.1.1"
|
||||
string.prototype.trimend "^1.0.1"
|
||||
string.prototype.trimstart "^1.0.1"
|
||||
|
||||
es-to-primitive@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
|
||||
integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
|
||||
dependencies:
|
||||
is-callable "^1.1.4"
|
||||
is-date-object "^1.0.1"
|
||||
is-symbol "^1.0.2"
|
||||
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
|
||||
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
get-intrinsic@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49"
|
||||
integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
has-symbols@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
|
||||
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
|
||||
|
||||
has@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
is-callable@^1.1.4, is-callable@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
|
||||
integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==
|
||||
|
||||
is-date-object@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
|
||||
integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
|
||||
|
||||
is-electron-renderer@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-electron-renderer/-/is-electron-renderer-2.0.1.tgz#a469d056f975697c58c98c6023eb0aa79af895a2"
|
||||
integrity sha1-pGnQVvl1aXxYyYxgI+sKp5r4laI=
|
||||
|
||||
is-negative-zero@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
|
||||
integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
|
||||
|
||||
is-regex@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
|
||||
integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
|
||||
dependencies:
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
is-symbol@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
|
||||
integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
|
||||
dependencies:
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
mz@^2.6.0:
|
||||
version "2.7.0"
|
||||
@@ -59,10 +150,63 @@ object-assign@^4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-inspect@^1.8.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a"
|
||||
integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==
|
||||
|
||||
object-keys@^1.0.12, object-keys@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
|
||||
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
|
||||
|
||||
object.assign@^4.1.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
|
||||
integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
define-properties "^1.1.3"
|
||||
has-symbols "^1.0.1"
|
||||
object-keys "^1.1.1"
|
||||
|
||||
object.entries@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.3.tgz#c601c7f168b62374541a07ddbd3e2d5e4f7711a6"
|
||||
integrity sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
define-properties "^1.1.3"
|
||||
es-abstract "^1.18.0-next.1"
|
||||
has "^1.0.3"
|
||||
|
||||
semver@^7.1.1:
|
||||
version "7.2.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.2.2.tgz#d01432d74ed3010a20ffaf909d63a691520521cd"
|
||||
integrity sha512-Zo84u6o2PebMSK3zjJ6Zp5wi8VnQZnEaCP13Ul/lt1ANsLACxnJxq4EEm1PY94/por1Hm9+7xpIswdS5AkieMA==
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
|
||||
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
|
||||
|
||||
serialize-error@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-5.0.0.tgz#a7ebbcdb03a5d71a6ed8461ffe0fc1a1afed62ac"
|
||||
integrity sha512-/VtpuyzYf82mHYTtI4QKtwHa79vAdU5OQpNPAmE/0UDdlGT0ZxHwC+J6gXkw29wwoVI8fMPsfcVHOwXtUQYYQA==
|
||||
dependencies:
|
||||
type-fest "^0.8.0"
|
||||
|
||||
string.prototype.trimend@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b"
|
||||
integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
define-properties "^1.1.3"
|
||||
|
||||
string.prototype.trimstart@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa"
|
||||
integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
define-properties "^1.1.3"
|
||||
|
||||
thenify-all@^1.0.0:
|
||||
version "1.6.0"
|
||||
@@ -72,8 +216,18 @@ thenify-all@^1.0.0:
|
||||
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"
|
||||
integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
|
||||
integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
|
||||
dependencies:
|
||||
any-promise "^1.0.0"
|
||||
|
||||
type-fest@^0.8.0:
|
||||
version "0.8.1"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
|
||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
|
||||
|
||||
uuid@^3.0.1:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
0
terminus-serial/.gitignore
vendored
Normal file
0
terminus-serial/.gitignore
vendored
Normal file
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "terminus-serial",
|
||||
"version": "1.0.104-nightly.0",
|
||||
"version": "1.0.123-nightly.0",
|
||||
"description": "Serial connection manager for Terminus",
|
||||
"keywords": [
|
||||
"terminus-builtin-plugin"
|
||||
@@ -17,19 +17,21 @@
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "12.7.3",
|
||||
"@types/node": "14.14.14",
|
||||
"@types/ssh2": "^0.5.35",
|
||||
"ansi-colors": "^4.1.1",
|
||||
"cli-spinner": "^0.2.10",
|
||||
"electron-rebuild": "^1.10.0",
|
||||
"terminus-terminal": "^1.0.98-nightly.0"
|
||||
"buffer-replace": "^1.0.0",
|
||||
"cli-spinner": "^0.2.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^7",
|
||||
"@angular/core": "^7",
|
||||
"@angular/forms": "^7",
|
||||
"@ng-bootstrap/ng-bootstrap": "^1",
|
||||
"rxjs": "^5",
|
||||
"@angular/animations": "^9.1.9",
|
||||
"@angular/common": "^9.1.11",
|
||||
"@angular/core": "^9.1.9",
|
||||
"@angular/forms": "^9.1.11",
|
||||
"@angular/platform-browser": "^9.1.11",
|
||||
"@angular/platform-browser-dynamic": "^9.1.11",
|
||||
"@ng-bootstrap/ng-bootstrap": "^6.2.0",
|
||||
"rxjs": "^6.6.3",
|
||||
"terminus-core": "*",
|
||||
"terminus-settings": "*",
|
||||
"terminus-terminal": "*"
|
||||
|
@@ -1,7 +1,12 @@
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import bufferReplace from 'buffer-replace'
|
||||
import { BaseSession } from 'terminus-terminal'
|
||||
import { SerialPort } from 'serialport'
|
||||
import { Logger } from 'terminus-core'
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
import { Subject, Observable, interval } from 'rxjs'
|
||||
import { debounce } from 'rxjs/operators'
|
||||
import { ReadLine, createInterface as createReadline, clearLine } from 'readline'
|
||||
import { PassThrough, Readable, Writable } from 'stream'
|
||||
|
||||
export interface LoginScript {
|
||||
expect: string
|
||||
@@ -23,10 +28,13 @@ export interface SerialConnection {
|
||||
xany: boolean
|
||||
scripts?: LoginScript[]
|
||||
color?: string
|
||||
inputMode?: InputMode
|
||||
inputNewlines?: NewlineMode
|
||||
outputNewlines?: NewlineMode
|
||||
}
|
||||
|
||||
export const BAUD_RATES = [
|
||||
110, 150, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600,
|
||||
110, 150, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 1500000,
|
||||
]
|
||||
|
||||
export interface SerialPortInfo {
|
||||
@@ -34,6 +42,9 @@ export interface SerialPortInfo {
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type InputMode = null | 'readline' // eslint-disable-line @typescript-eslint/no-type-alias
|
||||
export type NewlineMode = null | 'cr' | 'lf' | 'crlf' // eslint-disable-line @typescript-eslint/no-type-alias
|
||||
|
||||
export class SerialSession extends BaseSession {
|
||||
scripts?: LoginScript[]
|
||||
serial: SerialPort
|
||||
@@ -41,58 +52,38 @@ export class SerialSession extends BaseSession {
|
||||
|
||||
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
|
||||
private serviceMessage = new Subject<string>()
|
||||
private inputReadline: ReadLine
|
||||
private inputPromptVisible = true
|
||||
private inputReadlineInStream: Readable & Writable
|
||||
private inputReadlineOutStream: Readable & Writable
|
||||
|
||||
constructor (public connection: SerialConnection) {
|
||||
super()
|
||||
this.scripts = connection.scripts || []
|
||||
this.scripts = connection.scripts ?? []
|
||||
|
||||
this.inputReadlineInStream = new PassThrough()
|
||||
this.inputReadlineOutStream = new PassThrough()
|
||||
this.inputReadline = createReadline({
|
||||
input: this.inputReadlineInStream,
|
||||
output: this.inputReadlineOutStream,
|
||||
terminal: true,
|
||||
} as any)
|
||||
this.inputReadlineOutStream.on('data', data => {
|
||||
if (this.connection.inputMode === 'readline') {
|
||||
this.emitOutput(data)
|
||||
}
|
||||
})
|
||||
this.inputReadline.on('line', line => {
|
||||
this.onInput(new Buffer(line + '\n'))
|
||||
})
|
||||
this.output$.pipe(debounce(() => interval(500))).subscribe(() => this.onOutputSettled())
|
||||
}
|
||||
|
||||
async start (): Promise<void> {
|
||||
this.open = true
|
||||
|
||||
this.serial.on('data', data => {
|
||||
const dataString = data.toString()
|
||||
this.emitOutput(data)
|
||||
|
||||
if (this.scripts) {
|
||||
let found = false
|
||||
for (const script of this.scripts) {
|
||||
let match = false
|
||||
let cmd = ''
|
||||
if (script.isRegex) {
|
||||
const re = new RegExp(script.expect, 'g')
|
||||
if (dataString.match(re)) {
|
||||
cmd = dataString.replace(re, script.send)
|
||||
match = true
|
||||
found = true
|
||||
}
|
||||
} else {
|
||||
if (dataString.includes(script.expect)) {
|
||||
cmd = script.send
|
||||
match = true
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
this.logger.info('Executing script: "' + cmd + '"')
|
||||
this.serial.write(cmd + '\n')
|
||||
this.scripts = this.scripts.filter(x => x !== script)
|
||||
} else {
|
||||
if (script.optional) {
|
||||
this.logger.debug('Skip optional script: ' + script.expect)
|
||||
found = true
|
||||
this.scripts = this.scripts.filter(x => x !== script)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
this.executeUnconditionalScripts()
|
||||
}
|
||||
}
|
||||
this.serial.on('readable', () => {
|
||||
this.onOutput(this.serial.read())
|
||||
})
|
||||
|
||||
this.serial.on('end', () => {
|
||||
@@ -106,23 +97,33 @@ export class SerialSession extends BaseSession {
|
||||
}
|
||||
|
||||
write (data: Buffer): void {
|
||||
if (this.serial) {
|
||||
this.serial.write(data.toString())
|
||||
if (this.connection.inputMode === 'readline') {
|
||||
this.inputReadlineInStream.write(data)
|
||||
} else {
|
||||
this.onInput(data)
|
||||
}
|
||||
}
|
||||
|
||||
async destroy (): Promise<void> {
|
||||
this.serviceMessage.complete()
|
||||
this.inputReadline.close()
|
||||
await super.destroy()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-empty-function
|
||||
resize (_, __) { }
|
||||
resize (_, __) {
|
||||
this.inputReadlineOutStream.emit('resize')
|
||||
}
|
||||
|
||||
kill (_?: string): void {
|
||||
this.serial.close()
|
||||
}
|
||||
|
||||
emitServiceMessage (msg: string): void {
|
||||
this.serviceMessage.next(msg)
|
||||
this.logger.info(stripAnsi(msg))
|
||||
}
|
||||
|
||||
async getChildProcesses (): Promise<any[]> {
|
||||
return []
|
||||
}
|
||||
@@ -131,10 +132,102 @@ export class SerialSession extends BaseSession {
|
||||
this.kill('TERM')
|
||||
}
|
||||
|
||||
supportsWorkingDirectory (): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
async getWorkingDirectory (): Promise<string|null> {
|
||||
return null
|
||||
}
|
||||
|
||||
private replaceNewlines (data: Buffer, mode?: NewlineMode): Buffer {
|
||||
if (!mode) {
|
||||
return data
|
||||
}
|
||||
data = bufferReplace(data, '\r\n', '\n')
|
||||
data = bufferReplace(data, '\r', '\n')
|
||||
const replacement = {
|
||||
strip: '',
|
||||
cr: '\r',
|
||||
lf: '\n',
|
||||
crlf: '\r\n',
|
||||
}[mode]
|
||||
return bufferReplace(data, '\n', replacement)
|
||||
}
|
||||
|
||||
private onInput (data: Buffer) {
|
||||
data = this.replaceNewlines(data, this.connection.inputNewlines)
|
||||
if (this.serial) {
|
||||
this.serial.write(data.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private onOutputSettled () {
|
||||
if (this.connection.inputMode === 'readline' && !this.inputPromptVisible) {
|
||||
this.resetInputPrompt()
|
||||
}
|
||||
}
|
||||
|
||||
private resetInputPrompt () {
|
||||
this.emitOutput(new Buffer('\r\n'))
|
||||
this.inputReadline.prompt(true)
|
||||
this.inputPromptVisible = true
|
||||
}
|
||||
|
||||
private onOutput (data: Buffer) {
|
||||
const dataString = data.toString()
|
||||
|
||||
if (this.connection.inputMode === 'readline') {
|
||||
if (this.inputPromptVisible) {
|
||||
clearLine(this.inputReadlineOutStream, 0)
|
||||
this.inputPromptVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
data = this.replaceNewlines(data, this.connection.outputNewlines)
|
||||
this.emitOutput(data)
|
||||
|
||||
if (this.scripts) {
|
||||
let found = false
|
||||
for (const script of this.scripts) {
|
||||
let match = false
|
||||
let cmd = ''
|
||||
if (script.isRegex) {
|
||||
const re = new RegExp(script.expect, 'g')
|
||||
if (re.test(dataString)) {
|
||||
cmd = dataString.replace(re, script.send)
|
||||
match = true
|
||||
found = true
|
||||
}
|
||||
} else {
|
||||
if (dataString.includes(script.expect)) {
|
||||
cmd = script.send
|
||||
match = true
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
this.logger.info('Executing script: "' + cmd + '"')
|
||||
this.serial.write(cmd + '\n')
|
||||
this.scripts = this.scripts.filter(x => x !== script)
|
||||
} else {
|
||||
if (script.optional) {
|
||||
this.logger.debug('Skip optional script: ' + script.expect)
|
||||
found = true
|
||||
this.scripts = this.scripts.filter(x => x !== script)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
this.executeUnconditionalScripts()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private executeUnconditionalScripts () {
|
||||
if (this.scripts) {
|
||||
for (const script of this.scripts) {
|
||||
|
@@ -28,7 +28,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
weight: 5,
|
||||
title: 'Serial connections',
|
||||
touchBarNSImage: 'NSTouchBarOpenInBrowserTemplate',
|
||||
click: async () => {
|
||||
click: () => {
|
||||
this.activate()
|
||||
},
|
||||
}]
|
||||
|
@@ -11,23 +11,86 @@
|
||||
[(ngModel)]='connection.name',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Path
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='connection.port',
|
||||
[ngbTypeahead]='portsAutocomplete',
|
||||
[resultFormatter]='portsFormatter',
|
||||
)
|
||||
.row
|
||||
.col-6
|
||||
.form-group
|
||||
label Path
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='connection.port',
|
||||
[ngbTypeahead]='portsAutocomplete',
|
||||
[resultFormatter]='portsFormatter',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label Baud Rate
|
||||
select.form-control(
|
||||
[(ngModel)]='connection.baudrate',
|
||||
)
|
||||
option([value]='x', *ngFor='let x of baudRates') {{x}}
|
||||
.col-6
|
||||
.form-group
|
||||
label Baud Rate
|
||||
select.form-control(
|
||||
[(ngModel)]='connection.baudrate',
|
||||
)
|
||||
option([value]='x', *ngFor='let x of baudRates') {{x}}
|
||||
|
||||
ngb-tab(id='advanced')
|
||||
.row
|
||||
.col-6
|
||||
.form-line
|
||||
.header
|
||||
.title Input mode
|
||||
|
||||
.d-flex(ngbDropdown)
|
||||
button.btn.btn-secondary.btn-tab-bar(
|
||||
ngbDropdownToggle,
|
||||
) {{getInputModeName(connection.inputMode)}}
|
||||
|
||||
div(ngbDropdownMenu)
|
||||
a.d-flex.flex-column(
|
||||
*ngFor='let mode of inputModes',
|
||||
(click)='connection.inputMode = mode.key',
|
||||
ngbDropdownItem
|
||||
)
|
||||
div {{mode.name}}
|
||||
.text-muted {{mode.description}}
|
||||
|
||||
.col-6
|
||||
.form-line
|
||||
.header
|
||||
.title Input newlines
|
||||
|
||||
select.form-control(
|
||||
[(ngModel)]='connection.inputNewlines',
|
||||
)
|
||||
option([ngValue]='mode.key', *ngFor='let mode of newlineModes') {{mode.name}}
|
||||
|
||||
.row
|
||||
.col-6
|
||||
//- .form-line
|
||||
.header
|
||||
.title Output mode
|
||||
|
||||
.d-flex(ngbDropdown)
|
||||
button.btn.btn-secondary.btn-tab-bar(
|
||||
ngbDropdownToggle,
|
||||
) {{getInputModeName(connection.inputMode)}}
|
||||
|
||||
div(ngbDropdownMenu)
|
||||
a.d-flex.flex-column(
|
||||
*ngFor='let mode of inputModes',
|
||||
(click)='connection.inputMode = mode.key',
|
||||
ngbDropdownItem
|
||||
)
|
||||
div {{mode.name}}
|
||||
.text-muted {{mode.description}}
|
||||
|
||||
.col-6
|
||||
.form-line
|
||||
.header
|
||||
.title Output newlines
|
||||
|
||||
select.form-control(
|
||||
[(ngModel)]='connection.outputNewlines',
|
||||
)
|
||||
option([ngValue]='mode.key', *ngFor='let mode of newlineModes') {{mode.name}}
|
||||
|
||||
ngb-tab(id='advanced')
|
||||
ng-template(ngbTabTitle) Advanced
|
||||
ng-template(ngbTabContent)
|
||||
.form-line
|
||||
|
@@ -15,6 +15,17 @@ export class EditConnectionModalComponent {
|
||||
connection: SerialConnection
|
||||
foundPorts: SerialPortInfo[]
|
||||
baudRates = BAUD_RATES
|
||||
inputModes = [
|
||||
{ key: null, name: 'Normal', description: 'Input is sent as you type' },
|
||||
{ key: 'readline', name: 'Line by line', description: 'Line editor, input is sent after you press Enter' },
|
||||
]
|
||||
newlineModes = [
|
||||
{ key: null, name: 'Keep' },
|
||||
{ key: 'strip', name: 'Strip' },
|
||||
{ key: 'cr', name: 'Force CR' },
|
||||
{ key: 'lf', name: 'Force LF' },
|
||||
{ key: 'crlf', name: 'Force CRLF' },
|
||||
]
|
||||
|
||||
constructor (
|
||||
private modalInstance: NgbActiveModal,
|
||||
@@ -24,6 +35,10 @@ export class EditConnectionModalComponent {
|
||||
) {
|
||||
}
|
||||
|
||||
getInputModeName (key) {
|
||||
return this.inputModes.find(x => x.key === key)?.name
|
||||
}
|
||||
|
||||
portsAutocomplete = text$ => text$.pipe(map(() => {
|
||||
return this.foundPorts.map(x => x.name)
|
||||
}))
|
||||
@@ -37,7 +52,7 @@ export class EditConnectionModalComponent {
|
||||
}
|
||||
|
||||
async ngOnInit () {
|
||||
this.connection.scripts = this.connection.scripts || []
|
||||
this.connection.scripts = this.connection.scripts ?? []
|
||||
this.foundPorts = await this.serial.listPorts()
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,9 @@ export class SerialSettingsTabComponent {
|
||||
xany: false,
|
||||
xoff: false,
|
||||
xon: false,
|
||||
inputMode: null,
|
||||
inputNewlines: null,
|
||||
outputNewlines: null,
|
||||
}
|
||||
|
||||
const modal = this.ngbModal.open(EditConnectionModalComponent)
|
||||
|
@@ -1,16 +1,16 @@
|
||||
.tab-toolbar
|
||||
.tab-toolbar([class.show]='!session || !session.open')
|
||||
.btn.btn-outline-secondary.reveal-button
|
||||
i.fas.fa-ellipsis-h
|
||||
.toolbar(*ngIf='session', [class.show]='!session.open')
|
||||
i.fas.fa-circle.text-success.mr-2(*ngIf='session.open')
|
||||
i.fas.fa-circle.text-danger.mr-2(*ngIf='!session.open')
|
||||
strong(*ngIf='session') {{session.connection.port}} ({{session.connection.baudrate}})
|
||||
.toolbar
|
||||
i.fas.fa-circle.text-success.mr-2(*ngIf='session && session.open')
|
||||
i.fas.fa-circle.text-danger.mr-2(*ngIf='!session || !session.open')
|
||||
strong {{connection.port}} ({{connection.baudrate}})
|
||||
|
||||
.mr-auto
|
||||
|
||||
button.btn.btn-secondary.mr-3((click)='changeBaudRate()', *ngIf='session.open')
|
||||
button.btn.btn-secondary.mr-3((click)='changeBaudRate()', *ngIf='session && session.open')
|
||||
span Change baud rate
|
||||
|
||||
button.btn.btn-info((click)='reconnect()', *ngIf='!session.open')
|
||||
button.btn.btn-info((click)='reconnect()', *ngIf='!session || !session.open')
|
||||
i.fas.fa-reload
|
||||
span Reconnect
|
||||
|
@@ -11,14 +11,15 @@ import { Subscription } from 'rxjs'
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'serial-tab',
|
||||
template: BaseTerminalTabComponent.template + require<string>('./serialTab.component.pug'),
|
||||
template: `${BaseTerminalTabComponent.template} ${require('./serialTab.component.pug')}`,
|
||||
styles: [require('./serialTab.component.scss'), ...BaseTerminalTabComponent.styles],
|
||||
animations: BaseTerminalTabComponent.animations,
|
||||
})
|
||||
export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
connection: SerialConnection
|
||||
session: SerialSession
|
||||
connection?: SerialConnection
|
||||
session: SerialSession|null = null
|
||||
serialPort: any
|
||||
private serialService: SerialService
|
||||
private homeEndSubscription: Subscription
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
@@ -26,6 +27,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
injector: Injector,
|
||||
) {
|
||||
super(injector)
|
||||
this.serialService = injector.get(SerialService)
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
@@ -42,6 +44,9 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
case 'end':
|
||||
this.sendInput('\x1b[F' )
|
||||
break
|
||||
case 'restart-serial-session':
|
||||
this.reconnect()
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
@@ -52,7 +57,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
super.ngOnInit()
|
||||
|
||||
setImmediate(() => {
|
||||
this.setTitle(this.connection.name)
|
||||
this.setTitle(this.connection!.name)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -62,12 +67,8 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
return
|
||||
}
|
||||
|
||||
this.session = this.injector.get(SerialService).createSession(this.connection)
|
||||
this.session.serviceMessage$.subscribe(msg => {
|
||||
this.write('\r\n' + colors.black.bgWhite(' serial ') + ' ' + msg + '\r\n')
|
||||
this.session.resize(this.size.columns, this.size.rows)
|
||||
})
|
||||
this.attachSessionHandlers()
|
||||
const session = this.serialService.createSession(this.connection)
|
||||
this.setSession(session)
|
||||
this.write(`Connecting to `)
|
||||
|
||||
const spinner = new Spinner({
|
||||
@@ -80,15 +81,32 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
spinner.start()
|
||||
|
||||
try {
|
||||
this.serialPort = await this.injector.get(SerialService).connectSession(this.session)
|
||||
this.serialPort = await this.serialService.connectSession(this.session!)
|
||||
spinner.stop(true)
|
||||
session.emitServiceMessage('Port opened')
|
||||
} catch (e) {
|
||||
spinner.stop(true)
|
||||
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
|
||||
return
|
||||
}
|
||||
await this.session.start()
|
||||
this.session.resize(this.size.columns, this.size.rows)
|
||||
await this.session!.start()
|
||||
this.session!.resize(this.size.columns, this.size.rows)
|
||||
}
|
||||
|
||||
protected attachSessionHandlers () {
|
||||
this.attachSessionHandler(this.session!.serviceMessage$.subscribe(msg => {
|
||||
this.write(`\r\n${colors.black.bgWhite(' Serial ')} ${msg}\r\n`)
|
||||
this.session?.resize(this.size.columns, this.size.rows)
|
||||
}))
|
||||
this.attachSessionHandler(this.session!.destroyed$.subscribe(() => {
|
||||
this.write('Press any key to reconnect\r\n')
|
||||
this.input$.pipe(first()).subscribe(() => {
|
||||
if (!this.session?.open) {
|
||||
this.reconnect()
|
||||
}
|
||||
})
|
||||
}))
|
||||
super.attachSessionHandlers()
|
||||
}
|
||||
|
||||
async getRecoveryToken (): Promise<any> {
|
||||
@@ -99,8 +117,10 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
}
|
||||
}
|
||||
|
||||
reconnect () {
|
||||
this.initializeSession()
|
||||
async reconnect (): Promise<void> {
|
||||
this.session?.destroy()
|
||||
await this.initializeSession()
|
||||
this.session?.releaseInitialDataBuffer()
|
||||
}
|
||||
|
||||
async changeBaudRate () {
|
||||
@@ -108,7 +128,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
name: x.toString(), result: x,
|
||||
})))
|
||||
this.serialPort.update({ baudRate: rate })
|
||||
this.connection.baudrate = rate
|
||||
this.connection!.baudrate = rate
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
|
@@ -12,6 +12,7 @@ export class SerialConfigProvider extends ConfigProvider {
|
||||
serial: [
|
||||
'Alt-K',
|
||||
],
|
||||
'restart-serial-session': [],
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -9,6 +9,10 @@ export class SerialHotkeyProvider extends HotkeyProvider {
|
||||
id: 'serial',
|
||||
name: 'Show Serial connections',
|
||||
},
|
||||
{
|
||||
id: 'restart-serial-session',
|
||||
name: 'Restart current serial session',
|
||||
},
|
||||
]
|
||||
|
||||
async provide (): Promise<HotkeyDescription[]> {
|
||||
|
@@ -7,12 +7,12 @@ import { SerialTabComponent } from './components/serialTab.component'
|
||||
@Injectable()
|
||||
export class RecoveryProvider extends TabRecoveryProvider {
|
||||
async recover (recoveryToken: RecoveryToken): Promise<RecoveredTab|null> {
|
||||
if (recoveryToken?.type === 'app:serial-tab') {
|
||||
if (recoveryToken.type === 'app:serial-tab') {
|
||||
return {
|
||||
type: SerialTabComponent,
|
||||
options: {
|
||||
connection: recoveryToken['connection'],
|
||||
savedState: recoveryToken['savedState'],
|
||||
connection: recoveryToken.connection,
|
||||
savedState: recoveryToken.savedState,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@@ -30,10 +30,17 @@ export class SerialService {
|
||||
}
|
||||
|
||||
async connectSession (session: SerialSession): Promise<SerialPort> {
|
||||
const serial = new SerialPort(session.connection.port, { autoOpen: false, baudRate: session.connection.baudrate,
|
||||
dataBits: session.connection.databits, stopBits: session.connection.stopbits, parity: session.connection.parity,
|
||||
rtscts: session.connection.rtscts, xon: session.connection.xon, xoff: session.connection.xoff,
|
||||
xany: session.connection.xany })
|
||||
const serial = new SerialPort(session.connection.port, {
|
||||
autoOpen: false,
|
||||
baudRate: session.connection.baudrate,
|
||||
dataBits: session.connection.databits,
|
||||
stopBits: session.connection.stopbits,
|
||||
parity: session.connection.parity,
|
||||
rtscts: session.connection.rtscts,
|
||||
xon: session.connection.xon,
|
||||
xoff: session.connection.xoff,
|
||||
xany: session.connection.xany,
|
||||
})
|
||||
session.serial = serial
|
||||
let connected = false
|
||||
await new Promise(async (resolve, reject) => {
|
||||
@@ -50,6 +57,10 @@ export class SerialService {
|
||||
}
|
||||
})
|
||||
})
|
||||
serial.on('close', () => {
|
||||
session.emitServiceMessage('Port closed')
|
||||
session.destroy()
|
||||
})
|
||||
|
||||
try {
|
||||
serial.open()
|
||||
@@ -57,7 +68,6 @@ export class SerialService {
|
||||
this.toastr.error(e.message)
|
||||
reject(e)
|
||||
}
|
||||
|
||||
})
|
||||
return serial
|
||||
}
|
||||
@@ -104,7 +114,7 @@ export class SerialService {
|
||||
options.push({
|
||||
name: 'Manage connections',
|
||||
icon: 'cog',
|
||||
callback: () => this.app.openNewTab(SettingsTabComponent, { activeTab: 'serial' }),
|
||||
callback: () => this.app.openNewTabRaw(SettingsTabComponent, { activeTab: 'serial' }),
|
||||
})
|
||||
|
||||
options.push({
|
||||
@@ -125,10 +135,10 @@ export class SerialService {
|
||||
{ connection }
|
||||
) as SerialTabComponent
|
||||
if (connection.color) {
|
||||
(this.app.getParentTab(tab) || tab).color = connection.color
|
||||
(this.app.getParentTab(tab) ?? tab).color = connection.color
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.app.activeTab.emitFocused()
|
||||
this.app.activeTab?.emitFocused()
|
||||
})
|
||||
return tab
|
||||
} catch (error) {
|
||||
|
@@ -1,59 +1,5 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
context: __dirname,
|
||||
devtool: 'source-map',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
pathinfo: true,
|
||||
libraryTarget: 'umd',
|
||||
devtoolModuleFilenameTemplate: 'webpack-terminus-serial:///[resource-path]',
|
||||
},
|
||||
mode: process.env.TERMINUS_DEV ? 'development' : 'production',
|
||||
optimization:{
|
||||
minimize: false,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['.', 'src', 'node_modules', '../app/node_modules'].map(x => path.join(__dirname, x)),
|
||||
extensions: ['.ts', '.js', '.node'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: {
|
||||
loader: 'awesome-typescript-loader',
|
||||
options: {
|
||||
configFileName: path.resolve(__dirname, 'tsconfig.json'),
|
||||
typeRoots: [
|
||||
path.resolve(__dirname, 'node_modules/@types'),
|
||||
path.resolve(__dirname, '../node_modules/@types'),
|
||||
],
|
||||
paths: {
|
||||
"terminus-*": [path.resolve(__dirname, '../terminus-*')],
|
||||
"*": [path.resolve(__dirname, '../app/node_modules/*')],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ test: /\.pug$/, use: ['apply-loader', 'pug-loader'] },
|
||||
{ test: /\.scss$/, use: ['to-string-loader', 'css-loader', 'sass-loader'] },
|
||||
{ test: /\.svg/, use: ['svg-inline-loader'] },
|
||||
],
|
||||
},
|
||||
externals: [
|
||||
'fs',
|
||||
'keytar',
|
||||
'path',
|
||||
'ngx-toastr',
|
||||
'serialport',
|
||||
'windows-process-tree/build/Release/windows_process_tree.node',
|
||||
/^rxjs/,
|
||||
/^@angular/,
|
||||
/^@ng-bootstrap/,
|
||||
/^terminus-/,
|
||||
],
|
||||
}
|
||||
const config = require('../webpack.plugin.config')
|
||||
module.exports = config({
|
||||
name: 'serial',
|
||||
dirname: __dirname,
|
||||
})
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user