Compare commits

...

100 Commits

Author SHA1 Message Date
allcontributors[bot]
e041ddb8b5 update README.id-ID.md [skip ci] 2025-03-27 22:15:34 +00:00
allcontributors[bot]
82a429089d update README.de-DE.md [skip ci] 2025-03-27 22:15:33 +00:00
allcontributors[bot]
4ae59604a7 update README.it-IT.md [skip ci] 2025-03-27 22:15:32 +00:00
allcontributors[bot]
e596fe71f3 update README.ko-KR.md [skip ci] 2025-03-27 22:15:31 +00:00
allcontributors[bot]
2a884868a3 update README.ru-RU.md [skip ci] 2025-03-27 22:15:30 +00:00
allcontributors[bot]
82dc762779 update README.zh-CN.md [skip ci] 2025-03-27 22:15:29 +00:00
allcontributors[bot]
694b9dd662 update README.md [skip ci] 2025-03-27 22:15:28 +00:00
allcontributors[bot]
a44d2e4a90 update README.de-DE.md [skip ci] 2025-03-11 23:48:54 +00:00
allcontributors[bot]
d0804a5ad1 update README.it-IT.md [skip ci] 2025-03-11 23:48:53 +00:00
allcontributors[bot]
b6ed50bbbb update README.ko-KR.md [skip ci] 2025-03-11 23:48:52 +00:00
allcontributors[bot]
3f9b905bed update README.ru-RU.md [skip ci] 2025-03-11 23:48:51 +00:00
allcontributors[bot]
42b88e4e33 update README.zh-CN.md [skip ci] 2025-03-11 23:48:50 +00:00
allcontributors[bot]
ba24069b8a update README.md [skip ci] 2025-03-11 23:48:49 +00:00
gh-log
424b062d5b scroll_terminal_by_line (#10353)
Co-authored-by: gh-log <>
2025-03-12 00:48:34 +01:00
Eugene
5deb725758 bumped russh again 2025-03-10 07:50:20 +01:00
Eugene
4069c22891 bumped russh for EXT_INFO race condition fix 2025-03-09 19:27:48 +01:00
mannjani
4a515d9432 Add support for %h and %r escape characters in IdentityFile for SSH. (#10343)
* Add support for %h and %r escape characters in IdentityFile for SSH.
See section "IdentityFile" on https://linux.die.net/man/5/ssh_config for
details.

* Fix lint warnings.
2025-03-05 09:28:31 +01:00
Eugene
b83b2e5acc Update README.ru-RU.md 2025-02-28 10:11:30 +01:00
Eugene
e407ee8bf1 fixed #9845, fixed #10302 - allow alternative OSC52 suffix 2025-02-25 00:40:28 +01:00
Eugene
c7b39bdca7 bump russh for 1024 bit rsa key support 2025-02-25 00:37:24 +01:00
ianaflous
934cdff0f8 Using ssh default profile(user/password/port) without host (#10076) 2025-02-25 00:14:27 +01:00
Timo Schnaible
ab87099b8b add debian bullseye, bookworm and trixie deb package upload (#10314) 2025-02-25 00:12:45 +01:00
Eugene
47b4b54557 bump russh for agent RSA auth fixes 2025-02-21 10:48:51 +01:00
OpaqueGlass
15f4182e0e Fix: Unable to launch WinSCP for SSH sessions using private key (#10308) 2025-02-19 10:27:59 +01:00
aminelch
4be1e12559 Add Tokyonight color scheme (#10283) 2025-02-03 10:06:20 +01:00
Eugene
5d2d179677 prefer saved password to keyboard interactive auth 2025-01-29 10:37:28 +01:00
Eugene
4197cefdfd bump russh for events fix 2025-01-28 10:57:56 +01:00
Eugene
7c1421ffcf bump russh for async trait 2025-01-28 09:00:50 +01:00
Eugene
380c306d89 added warning when server disconnects during auth 2025-01-27 14:53:44 +01:00
Eugene
cf0da75224 bump russh for best hash selection in agent auth 2025-01-27 14:53:32 +01:00
Eugene
d1c1b48502 bump russh for rsa hash autoselection 2025-01-25 12:56:54 +01:00
Eugene
a3c5b41bb1 electron builder fixes 2025-01-22 23:44:36 +01:00
Eugene
2fa7678bec Squashed commit of the following:
commit 4efcf1bbd6
Author: Eugene <inbox@null.page>
Date:   Wed Jan 22 23:07:24 2025 +0100

    Update build.yml

commit abea964d94
Author: Eugene <inbox@null.page>
Date:   Wed Jan 22 22:59:28 2025 +0100

    Update build.yml

commit 2e7b66ac60
Author: Eugene <inbox@null.page>
Date:   Wed Jan 22 22:40:11 2025 +0100

    native arm64 build
2025-01-22 23:28:47 +01:00
Eugene
c6939b114d updated locales 2025-01-22 23:07:08 +01:00
Eugene
d3e8e2a6af bump electron-builder 2025-01-22 23:01:57 +01:00
Eugene
d1b161364b bump russh for error handling crash fix - fixes #10184, fixes #10244, fixes #10178, fixes #8481, fixes #10215, fixes #10203, fixes #7659 2025-01-22 22:44:47 +01:00
Eugene
c4a514fc4a fixed agent login regression - fixes #10248, fixes #10174 2025-01-22 22:33:26 +01:00
Eugene
d525374061 fixed missing app theme at the initial vault password prompt 2025-01-22 22:16:17 +01:00
Eugene
6db08b765f lint 2025-01-16 22:30:36 +01:00
Eugene
d8d346c507 bump russh for agent fix 2025-01-16 22:27:11 +01:00
Eugene
6ffeb61c9c fixed dropping files into the terminal not inserting the path - fixes #10221, fixes #10206 2025-01-16 22:24:24 +01:00
Eugene
92c729dada bump russh for keyboard-interactive fixes and lock race fix 2025-01-16 22:14:29 +01:00
PytatoDuck
302f88058c Added Sponsors Logos in README.md (#10200) 2025-01-13 20:46:29 +01:00
fireblue
66c173b1b5 Keep the translucency effect even when the window loses focus on macOS. (#10196) 2025-01-13 19:06:09 +01:00
fireblue
f9dadf0816 Set the application's dark mode to follow the app settings on macOS. (#10186) 2025-01-10 22:07:17 +01:00
Eugene
0a475daa9c fixed #10180 - encrypted PPK keys 2025-01-09 21:06:01 +01:00
Eugene
ba7c31d940 fixed #10146 - agent auth 2025-01-09 21:05:30 +01:00
Eugene
52a85e4f36 lint 2025-01-08 18:44:00 +01:00
Eugene
ddbb2feb9c bump russh for jump host fix - fixes #10166 2025-01-08 18:37:56 +01:00
Eugene
c43ee28a0c Update install-deps.mjs 2025-01-08 16:44:06 +01:00
Eugene
9f3c7a95cf Update install-deps.mjs 2025-01-08 16:08:51 +01:00
Eugene
02205410b6 Update build.yml 2025-01-08 14:31:57 +01:00
Eugene
9bcbde265d Update build-macos.mjs 2025-01-08 12:10:06 +01:00
Eugene
fee857a0f6 ci: bump node 2025-01-08 11:57:04 +01:00
Eugene
73f978781c bump electron builder 2025-01-08 11:53:20 +01:00
Eugene
87e99654f6 bump russh for EC key support 2025-01-08 11:20:33 +01:00
Eugene
93513541f7 tweak electron fuses 2025-01-08 09:59:56 +01:00
Eugene
60a6c148d8 bump russh for freeze fix 2025-01-07 22:11:34 +01:00
Eugene
070343aebe bump russh for ppk2 and remainingMethods support 2025-01-06 22:19:29 +01:00
Eugeny
fe376a48d8 Update node-pty+1.0.0.patch 2025-01-06 15:31:30 +01:00
Eugeny
2008f30cf5 downgrade node-pty - fixes #10134 2025-01-06 14:13:39 +01:00
Eugene
53ca484ca6 Update webpack.config.mjs 2025-01-06 12:13:58 +01:00
Eugene
fe46ed7847 Update default_settings 2025-01-06 11:47:52 +01:00
Eugene
e90731f427 bumpe node-pty 2025-01-06 11:22:17 +01:00
Eugene
025cc68ad8 bump windows-process-tree 2025-01-06 10:51:23 +01:00
Eugene
6edb1e9cd4 bump blurbehind 2025-01-06 10:03:17 +01:00
Eugene
c6981a8216 bumped russh 2025-01-06 02:52:23 +01:00
Eugene
5d318478ec updated contributors 2025-01-02 16:58:20 +01:00
Hiroaki Ogasawara
39e3ba35c4 Update sshImporters.ts to parse Include directive (#10105) 2025-01-01 01:13:02 +01:00
Hiroaki Ogasawara
d0dd09ad88 fix: case-insensitive hostname check (#10130) 2025-01-01 01:08:20 +01:00
geodic
1e44d8c525 Bump Electron to 32 as 29 is EOL (#10118)
Co-authored-by: Eugene <inbox@null.page>
2024-12-31 17:26:02 +01:00
Eugene
a10e9c05b6 bumped russh for ppk support 2024-12-30 23:53:31 +01:00
Eugene
6b0b1563c5 bump russh 2024-12-28 14:12:55 +01:00
Eugene
04b34b0edd bumped russh to 0.0.4 - ref #10117 2024-12-26 18:42:36 +01:00
Eugene
2346e10b70 fixed #10109 - not starting on x64 macOS 2024-12-25 11:54:54 +01:00
Eugene
55c13edace only publish on tag 2024-12-25 10:42:13 +01:00
Eugene
6a91565da1 Update prepackage-plugins.mjs 2024-12-25 02:44:08 +01:00
Eugene
90d0bbce23 Update build-windows.mjs 2024-12-25 02:37:18 +01:00
Eugene
daa5687cfc Update build.yml 2024-12-25 02:37:18 +01:00
Eugene
9590ab8bf6 updated locales 2024-12-25 02:37:18 +01:00
Eugeny
d7971294aa fixed native mod build 2024-12-25 02:34:31 +01:00
Eugene
67230c1601 Update docs.yml 2024-12-24 23:54:28 +01:00
Eugene
09556ae6a1 Merge branch 'master' of github.com:Eugeny/tabby 2024-12-24 23:53:24 +01:00
Eugene
eae946d0f0 Update docs.yml 2024-12-24 23:53:20 +01:00
Eugene
33eb5bd800 Windows signing (#10100) 2024-12-24 23:52:14 +01:00
Davide
6196f3b85d Update clink to 1.7.6 (#10097)
Thank you!
2024-12-16 16:28:41 +01:00
Eugene
e1e6e1cdab Update entitlements.plist 2024-12-15 15:00:05 +01:00
Snuupy
ac6f60f1ae add ubuntu 24.10 to build.yml (#10047) 2024-11-07 16:58:06 +01:00
Andy Law
aa67130e37 Fix Issue #10012 - better ssh config parsing (#10043) 2024-11-06 12:41:04 +01:00
Eugene
21aedb6045 fixed #9323 - "Save as profile" profile editability 2024-10-20 23:42:02 +02:00
Eugene
2bc95bb0e0 removed legacy themes 2024-10-20 23:20:14 +02:00
Eugene
b4d3667b9a lint 2024-10-20 23:15:51 +02:00
Eugene
e84cbd82d8 added support for custom color schemes for local shell profiles 2024-10-20 22:19:06 +02:00
Clem
2ecccad2db Feat#10008: add hotkeys to open profile selectors for a specific group (#10015) 2024-10-20 21:31:09 +02:00
Eugene
aab7e285a9 replace ssh2 with russh 2024-10-18 20:24:53 +02:00
Eugene
3eaa600544 Create funding-manifest-urls 2024-10-17 11:22:02 +02:00
AuroraTea
9beab8994b Docs: fix terminal type in readme (#9985) 2024-10-08 09:02:41 +02:00
Eugene
d9363b5de1 Update README.md 2024-10-01 16:00:58 +02:00
Eugene
ed22309e93 Update homeBase.service.ts 2024-10-01 15:59:45 +02:00
Eugene
5932b8664b updated contributors 2024-09-29 09:38:57 +02:00
120 changed files with 3086 additions and 3579 deletions

View File

@@ -1328,6 +1328,33 @@
"contributions": [ "contributions": [
"code" "code"
] ]
},
{
"login": "SelfHosted-Club",
"name": "SelfHosted",
"avatar_url": "https://avatars.githubusercontent.com/u/128927132?v=4",
"profile": "https://www.selfhosted.sg/",
"contributions": [
"financial"
]
},
{
"login": "xhiroga",
"name": "Hiroaki Ogasawara",
"avatar_url": "https://avatars.githubusercontent.com/u/13391129?v=4",
"profile": "http://hiroga.hatenablog.com/",
"contributions": [
"code"
]
},
{
"login": "geodic",
"name": "geodic",
"avatar_url": "https://avatars.githubusercontent.com/u/64704703?v=4",
"profile": "https://github.com/geodic",
"contributions": [
"code"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

View File

@@ -2,7 +2,7 @@ name: Package-Build
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
Lint: Lint:
runs-on: ubuntu-20.04 runs-on: ubuntu-24.04
steps: steps:
- name: Checkout - name: Checkout
@@ -13,10 +13,11 @@ jobs:
- name: Installing Node - name: Installing Node
uses: actions/setup-node@v3.7.0 uses: actions/setup-node@v3.7.0
with: with:
node-version: 18 node-version: 22
- name: Install deps - name: Install deps
run: | run: |
sudo apt-get update && sudo apt-get install -y libfontconfig1-dev
npm i -g yarn npm i -g yarn
cd app cd app
yarn yarn
@@ -31,15 +32,21 @@ jobs:
run: yarn run lint run: yarn run lint
macOS-Build: macOS-Build:
runs-on: macos-12 runs-on: macos-15
needs: Lint needs: Lint
strategy: strategy:
matrix: matrix:
include: include:
- arch: x86_64 - arch: x86_64
rust_triple: x86_64-apple-darwin
- arch: arm64 - arch: arm64
rust_triple: aarch64-apple-darwin
fail-fast: false fail-fast: false
env:
ARCH: ${{matrix.arch}}
RUST_TARGET_TRIPLE: ${{matrix.rust_triple}}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@@ -49,22 +56,16 @@ jobs:
- name: Installing Node - name: Installing Node
uses: actions/setup-node@v3.7.0 uses: actions/setup-node@v3.7.0
with: with:
node-version: 18 node-version: 22
- run: rustup target add ${{matrix.rust_triple}}
- name: Install deps - name: Install deps
run: | run: |
sudo -H pip3 install setuptools
sudo npm i -g yarn
yarn --network-timeout 1000000 yarn --network-timeout 1000000
env: env:
ARCH: ${{matrix.arch}} ARCH: ${{matrix.arch}}
- name: Fix cross build
run: |
rm -rf app/node_modules/cpu-features
rm -rf app/node_modules/ssh2/crypto/build
if: matrix.arch == 'arm64'
- name: Webpack - name: Webpack
run: yarn run build run: yarn run build
@@ -80,7 +81,7 @@ jobs:
- name: Build and sign packages - name: Build and sign packages
run: scripts/build-macos.mjs run: scripts/build-macos.mjs
if: github.repository == 'Eugeny/tabby' && github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags')) if: github.event_name == 'push' && (github.ref_protected || startsWith(github.ref, 'refs/tags'))
env: env:
ARCH: ${{matrix.arch}} ARCH: ${{matrix.arch}}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -95,7 +96,7 @@ jobs:
- name: Build packages without signing - name: Build packages without signing
run: scripts/build-macos.mjs run: scripts/build-macos.mjs
if: "! (github.repository == 'Eugeny/tabby' && github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags')))" if: "! (github.event_name == 'push' && (github.ref_protected || startsWith(github.ref, 'refs/tags')))"
env: env:
ARCH: ${{matrix.arch}} ARCH: ${{matrix.arch}}
# DEBUG: electron-builder,electron-builder:* # DEBUG: electron-builder,electron-builder:*
@@ -129,25 +130,34 @@ jobs:
path: artifact-zip path: artifact-zip
Linux-Build: Linux-Build:
runs-on: ubuntu-20.04 runs-on: ${{matrix.os}}
needs: Lint needs: Lint
strategy: strategy:
matrix: matrix:
include: include:
- build-arch: x64 - build-arch: x64
arch: amd64 arch: amd64
rust_triple: x86_64-unknown-linux-gnu
os: ubuntu-24.04
- build-arch: arm64 - build-arch: arm64
arch: arm64 arch: arm64
rust_triple: aarch64-unknown-linux-gnu
triplet: aarch64-linux-gnu- triplet: aarch64-linux-gnu-
os: ubuntu-24.04-arm
- build-arch: arm - build-arch: arm
arch: armhf arch: armhf
rust_triple: arm-unknown-linux-gnueabihf
triplet: arm-linux-gnueabihf- triplet: arm-linux-gnueabihf-
os: ubuntu-24.04
fail-fast: false
env: env:
CC: ${{matrix.triplet}}gcc CC: ${{matrix.triplet}}gcc
CXX: ${{matrix.triplet}}g++ CXX: ${{matrix.triplet}}g++
ARCH: ${{matrix.build-arch}} ARCH: ${{matrix.build-arch}}
npm_config_arch: ${{matrix.build-arch}} npm_config_arch: ${{matrix.build-arch}}
npm_config_target_arch: ${{matrix.build-arch}} npm_config_target_arch: ${{matrix.build-arch}}
RUST_TARGET_TRIPLE: ${{matrix.rust_triple}}
steps: steps:
- name: Checkout - name: Checkout
@@ -158,21 +168,27 @@ jobs:
- name: Install Node - name: Install Node
uses: actions/setup-node@v3.7.0 uses: actions/setup-node@v3.7.0
with: with:
node-version: 18 node-version: 22
- name: Install FPM
run: |
sudo gem install fpm
- run: rustup target add ${{matrix.rust_triple}}
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install libarchive-tools zsh crossbuild-essential-${{matrix.arch}} sudo apt-get install libfontconfig1-dev libarchive-tools zsh crossbuild-essential-${{matrix.arch}}
- name: Setup tar to run as root - name: Setup tar to run as root
run: sudo chmod u+s "$(command -v tar)" run: sudo chmod u+s "$(command -v tar)"
if: matrix.build-arch != 'x64' if: matrix.build-arch == 'arm'
- name: Download cached sysroot - name: Download cached sysroot
uses: actions/cache@v3 uses: actions/cache@v3
id: dl-cached-sysroot id: dl-cached-sysroot
if: matrix.build-arch !='x64' if: matrix.build-arch == 'arm'
with: with:
key: sysroot-${{matrix.build-arch}} key: sysroot-${{matrix.build-arch}}
path: /${{matrix.build-arch}}-sysroot path: /${{matrix.build-arch}}-sysroot
@@ -182,7 +198,7 @@ jobs:
sudo apt-get update -y && sudo apt-get install debootstrap qemu-user-static binfmt-support -y sudo apt-get update -y && sudo apt-get install debootstrap qemu-user-static binfmt-support -y
sudo qemu-debootstrap --include=libfontconfig1-dev,libsecret-1-dev,libnss3,libatk1.0-0,libatk-bridge2.0-0,libgdk-pixbuf2.0-0,libgtk-3-0,libgbm1 --variant=buildd --exclude=snapd --components=main,restricted,universe,multiverse --extractor=dpkg-deb --arch ${{matrix.arch}} bionic /${{matrix.build-arch}}-sysroot/ http://ports.ubuntu.com/ubuntu-ports/ sudo qemu-debootstrap --include=libfontconfig1-dev,libsecret-1-dev,libnss3,libatk1.0-0,libatk-bridge2.0-0,libgdk-pixbuf2.0-0,libgtk-3-0,libgbm1 --variant=buildd --exclude=snapd --components=main,restricted,universe,multiverse --extractor=dpkg-deb --arch ${{matrix.arch}} bionic /${{matrix.build-arch}}-sysroot/ http://ports.ubuntu.com/ubuntu-ports/
sudo find /${{matrix.build-arch}}-sysroot -type l -lname '/*' -exec sh -c 'file="$0"; dir=$(dirname "$file"); target=$(readlink "$0"); prefix=$(dirname "$dir" | sed 's@[^/]*@\.\.@g'); newtarget="$prefix$target"; ln -snf $newtarget $file' {} \; ; sudo find /${{matrix.build-arch}}-sysroot -type l -lname '/*' -exec sh -c 'file="$0"; dir=$(dirname "$file"); target=$(readlink "$0"); prefix=$(dirname "$dir" | sed 's@[^/]*@\.\.@g'); newtarget="$prefix$target"; ln -snf $newtarget $file' {} \; ;
if: matrix.build-arch != 'x64' && steps.dl-cached-sysroot.outputs.cache-hit != 'true' if: matrix.build-arch == 'arm' && steps.dl-cached-sysroot.outputs.cache-hit != 'true'
- name: Setup env to use ${{matrix.build-arch}} sysroot - name: Setup env to use ${{matrix.build-arch}} sysroot
run: | run: |
@@ -197,9 +213,9 @@ jobs:
elif [[ ${{matrix.arch}} == 'arm64' ]]; then elif [[ ${{matrix.arch}} == 'arm64' ]]; then
echo "PKG_CONFIG_PATH=/${{matrix.build-arch}}-sysroot/usr/lib/pkgconfig/:/${{matrix.build-arch}}-sysroot/usr/lib/aarch64-linux-gnu/pkgconfig/" >> $GITHUB_ENV echo "PKG_CONFIG_PATH=/${{matrix.build-arch}}-sysroot/usr/lib/pkgconfig/:/${{matrix.build-arch}}-sysroot/usr/lib/aarch64-linux-gnu/pkgconfig/" >> $GITHUB_ENV
fi fi
if: matrix.build-arch != 'x64' if: matrix.build-arch == 'arm'
- name: Install npm_modules (amd64) - name: Install npm_modules (native)
run: | run: |
npm i -g yarn node-gyp npm i -g yarn node-gyp
yarn --network-timeout 1000000 --arch=${{matrix.build-arch}} --target-arch=${{matrix.build-arch}} yarn --network-timeout 1000000 --arch=${{matrix.build-arch}} --target-arch=${{matrix.build-arch}}
@@ -216,6 +232,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }} KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }}
USE_HARD_LINKS: false USE_HARD_LINKS: false
USE_SYSTEM_FPM: true
# DEBUG: electron-builder,electron-builder:* # DEBUG: electron-builder,electron-builder:*
- name: Build web resources (amd64 only) - name: Build web resources (amd64 only)
@@ -234,14 +251,14 @@ jobs:
- name: Upload packages to packagecloud.io - name: Upload packages to packagecloud.io
uses: TykTechnologies/packagecloud-action@main uses: TykTechnologies/packagecloud-action@main
if: github.repository == 'Eugeny/tabby' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
env: env:
PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }} PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }}
with: with:
repo: 'eugeny/tabby' repo: 'eugeny/tabby'
dir: 'dist' dir: 'dist'
rpmvers: 'el/9 el/8 ol/6 ol/7' rpmvers: 'el/9 el/8 ol/6 ol/7'
debvers: 'ubuntu/bionic ubuntu/focal ubuntu/hirsute ubuntu/impish ubuntu/jammy ubuntu/kinetic ubuntu/noble debian/jessie debian/stretch debian/buster' debvers: 'ubuntu/bionic ubuntu/focal ubuntu/hirsute ubuntu/impish ubuntu/jammy ubuntu/kinetic ubuntu/noble ubuntu/oracular debian/jessie debian/stretch debian/buster debian/bullseye debian/bookworm debian/trixie'
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
name: Upload AppImage (${{matrix.arch}}) name: Upload AppImage (${{matrix.arch}})
@@ -280,27 +297,44 @@ jobs:
path: tabby-web.tar.gz path: tabby-web.tar.gz
if: matrix.build-arch == 'x64' if: matrix.build-arch == 'x64'
Windows-Build: Windows-Build:
runs-on: windows-2022 runs-on: windows-latest
needs: Lint needs: Lint
strategy: strategy:
matrix: matrix:
include: include:
- arch: x64 - arch: x64
rust_triple: x86_64-pc-windows-msvc
- arch: arm64 - arch: arm64
rust_triple: aarch64-pc-windows-msvc
fail-fast: false fail-fast: false
env:
RUST_TARGET_TRIPLE: ${{matrix.rust_triple}}
ARCH: ${{matrix.arch}}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Code signing with Software Trust Manager
uses: digicert/ssm-code-signing@v1.0.0
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags'))
- name: Installing Node - name: Installing Node
uses: actions/setup-node@v3.7.0 uses: actions/setup-node@v3.7.0
with: with:
node-version: 18 node-version: 22
- run: npm i -g npx
- run: rustup target add ${{matrix.rust_triple}}
- name: Update node-gyp
run: |
npm install --global node-gyp@10.2.0
npm prefix -g | % {npm config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js"}
- name: Build - name: Build
shell: powershell shell: powershell
@@ -312,20 +346,48 @@ jobs:
env: env:
ARCH: ${{matrix.arch}} ARCH: ${{matrix.arch}}
- name: Decode certificate
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags'))
env:
SM_CLIENT_CERT_FILE_B64: ${{ secrets.SM_CLIENT_CERT_FILE_B64 }}
run: |
SM_CLIENT_CERT_FILE=$RUNNER_TEMP/certificate.p12
echo "$SM_CLIENT_CERT_FILE_B64" | base64 --decode > $SM_CLIENT_CERT_FILE
echo "SM_CLIENT_CERT_FILE=$SM_CLIENT_CERT_FILE" >> "$GITHUB_ENV"
shell: bash
- name: Build and sign packages - name: Build and sign packages
run: node scripts/build-windows.mjs if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags'))
if: github.repository == 'Eugeny/tabby' && github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags')) shell: powershell
run: |
Get-FileHash $env:SM_CLIENT_CERT_FILE -Algorithm MD5
smksp_registrar.exe list
smctl.exe healthcheck
smctl.exe keypair ls
smctl windows certsync --keypair-alias $env:SM_KEYPAIR_ALIAS
smctl.exe certificate ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe
# not used but necessary for electron-builder to run
$env:WIN_CSC_LINK=$env:SM_CLIENT_CERT_FILE
$env:WIN_CSC_KEY_PASSWORD=$env:SM_CLIENT_CERT_PASSWORD
node scripts/build-windows.mjs
env: env:
ARCH: ${{matrix.arch}} ARCH: ${{matrix.arch}}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }} KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }}
WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }} SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }} SM_PUBLISHER_NAME: ${{ secrets.SM_PUBLISHER_NAME }}
DEBUG: electron-builder,electron-builder:* SM_API_KEY: ${{ secrets.SM_API_KEY }}
SM_HOST: ${{ vars.SM_HOST }}
SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ vars.SM_CODE_SIGNING_CERT_SHA1_HASH }}
SM_KEYPAIR_ALIAS: ${{ vars.SM_KEYPAIR_ALIAS }}
# DEBUG: electron-builder,electron-builder:*
- name: Build packages without signing - name: Build packages without signing
run: node scripts/build-windows.mjs run: node scripts/build-windows.mjs
if: "! (github.repository == 'Eugeny/tabby' && github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags')))" if: "! (github.event_name == 'push' && (startsWith(github.ref, 'refs/tags')))"
env: env:
ARCH: ${{matrix.arch}} ARCH: ${{matrix.arch}}

View File

@@ -18,6 +18,7 @@ jobs:
- name: Build - name: Build
run: | run: |
sudo apt update && sudo apt install libfontconfig1-dev
yarn cache clean yarn cache clean
cd app cd app
yarn yarn

1
.gitignore vendored
View File

@@ -33,7 +33,6 @@ docs/api
sentry.properties sentry.properties
sentry-symbols.js sentry-symbols.js
tabby-ssh/util/pagent.exe
*.psd *.psd
crowdin.yml crowdin.yml

View File

@@ -0,0 +1 @@
https://null.page/funding.json

View File

@@ -66,7 +66,7 @@ Diese README ist auch verfügbar in: <a href="./README.md">:gb: English</a> ·
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* Ein V220-Terminal + verschiedene Erweiterungen * Ein VT220-Terminal + verschiedene Erweiterungen
* Mehrere verschachtelte, geteilte Fenster * Mehrere verschachtelte, geteilte Fenster
* Tabs auf jeder Seite des Fensters * Tabs auf jeder Seite des Fensters
* Optional andockbares Fenster mit einem globalen Spawn-Hotkey ("Quake-Konsole") * Optional andockbares Fenster mit einem globalen Spawn-Hotkey ("Quake-Konsole")
@@ -342,6 +342,12 @@ Dank geht an diese wunderbaren Menschen ([emoji key](https://allcontributors.org
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gh-log"><img src="https://avatars.githubusercontent.com/u/16019542?v=4?s=100" width="100px;" alt="gh-log"/><br /><sub><b>gh-log</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=gh-log" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -67,7 +67,7 @@ Este fichero README está disponible en: <a href="./README.md">:gb: English</a>
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* Un terminal V220 + varias extensiones * Un terminal VT220 + varias extensiones
* Múltiples paneles divididos anidados * Múltiples paneles divididos anidados
* Pestañas en cualquier lado de la ventana * Pestañas en cualquier lado de la ventana
* Ventana acoplable opcional con una tecla de acceso directo global ("consola de Quake") * Ventana acoplable opcional con una tecla de acceso directo global ("consola de Quake")
@@ -344,6 +344,11 @@ Gracias a estas maravillosas personas ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -67,7 +67,7 @@ This README is also available in: <a href="./README.md">:gb: English</a> · <a
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* Terminal V220 + berbagai macam ekstensi * Terminal VT220 + berbagai macam ekstensi
* Beberapa pembagian panel * Beberapa pembagian panel
* Tab di sisi mana pun dari jendela * Tab di sisi mana pun dari jendela
* Jendela dockable opsional dengan hotkey spawn global ("Quake console") * Jendela dockable opsional dengan hotkey spawn global ("Quake console")
@@ -341,6 +341,12 @@ Terima kasih kepada mereka yang telah membantu ([emoji key](https://allcontribut
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gh-log"><img src="https://avatars.githubusercontent.com/u/16019542?v=4?s=100" width="100px;" alt="gh-log"/><br /><sub><b>gh-log</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=gh-log" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -68,7 +68,7 @@ Questo README è disponibile anche in: <a href="./README.md">:gb: English</a>
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* Un terminale V220 + vari estensioni * Un terminale VT220 + vari estensioni
* Suddivisione in pannelli * Suddivisione in pannelli
* Schede su qualsiasi lato della finestra * Schede su qualsiasi lato della finestra
* Finestra agganciabile opzionale con un tasto di scelta rapida ("Quake console") * Finestra agganciabile opzionale con un tasto di scelta rapida ("Quake console")
@@ -337,6 +337,12 @@ Grazie a queste persone meravigliose ([emoji key](https://allcontributors.org/do
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gh-log"><img src="https://avatars.githubusercontent.com/u/16019542?v=4?s=100" width="100px;" alt="gh-log"/><br /><sub><b>gh-log</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=gh-log" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -74,7 +74,7 @@
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* V220ターミナル各種拡張機能 * VT220ターミナル各種拡張機能
* 複数ネストされたペイン分割に対応 * 複数ネストされたペイン分割に対応
* ウィンドウ内に自由に配置可能なタブ * ウィンドウ内に自由に配置可能なタブ
* グローバルホットキーで呼び出せるドックウィンドウ機能("Quakeコンソール" * グローバルホットキーで呼び出せるドックウィンドウ機能("Quakeコンソール"
@@ -352,6 +352,11 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -66,7 +66,7 @@ This README is also available in: <a href="./README.md">:gb: English</a> · <a
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* A V220 터미널 + 다양한 확장 * A VT220 터미널 + 다양한 확장
* 여러 개의 분할 창 중첩 * 여러 개의 분할 창 중첩
* 모든 측면에 탭이 위치함 * 모든 측면에 탭이 위치함
* 전역 스폰 단축키가 있는 도킹 가능한 윈도우 ("Quake console") * 전역 스폰 단축키가 있는 도킹 가능한 윈도우 ("Quake console")
@@ -336,6 +336,12 @@ Pull requests and plugins are welcome!
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gh-log"><img src="https://avatars.githubusercontent.com/u/16019542?v=4?s=100" width="100px;" alt="gh-log"/><br /><sub><b>gh-log</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=gh-log" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -2,7 +2,7 @@
<p align="center"> <p align="center">
<a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=DOWNLOADS&logo=github&style=for-the-badge"></a> &nbsp; <a href="https://nightly.link/Eugeny/tabby/workflows/build/master"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=for-the-badge"/></a> &nbsp; <a href="https://matrix.to/#/#tabby-general:matrix.org"><img alt="Matrix" src="https://img.shields.io/matrix/tabby-general:matrix.org?logo=matrix&style=for-the-badge&color=magenta"></a> &nbsp <a href="https://translate.tabby.sh/"><img alt="Translate" src="https://shields.io/badge/Translate-UI-white?logo=googletranslate&style=for-the-badge&color=white&logoColor=fff"></a> &nbsp; <a href="https://twitter.com/eugeeeeny"><img alt="Twitter" src="https://shields.io/badge/Subscribe-News-blue?logo=twitter&style=for-the-badge&color=blue"></a> <a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=DOWNLOADS&logo=github&style=for-the-badge"></a> &nbsp; <a href="https://nightly.link/Eugeny/tabby/workflows/build/master"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=for-the-badge"/></a> &nbsp; <a href="https://discord.gg/Vn7BjmzhtF"><img alt="Discord" src="https://img.shields.io/discord/1280890060195233934?style=for-the-badge&color=blue&logo=discord&logoColor=white&label=Discord"></a> &nbsp <a href="https://translate.tabby.sh/"><img alt="Translate" src="https://shields.io/badge/Translate-UI-white?logo=googletranslate&style=for-the-badge&color=white&logoColor=fff"></a>
</p> </p>
<p align="center"> <p align="center">
@@ -72,7 +72,7 @@ This README is also available in: <a href="./README.es-ES.md">:es: Spanish</a>
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* A V220 terminal + various extensions * A VT220 terminal + various extensions
* Multiple nested split panes * Multiple nested split panes
* Tabs on any side of the window * Tabs on any side of the window
* Optional dockable window with a global spawn hotkey ("Quake console") * Optional dockable window with a global spawn hotkey ("Quake console")
@@ -144,7 +144,7 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
# Sponsors <!-- omit in toc --> # Sponsors <!-- omit in toc -->
[![](https://assets-production.packagecloud.io/assets/packagecloud-logo-light-scaled-26ce8e96060fddf74afbd4445e63ba35590d4aaa56edc98495bb390ef3cae0ae.png)](https://packagecloud.io) <a href="https://packagecloud.io"><img src="https://assets-production.packagecloud.io/assets/logo_v1-d5895e7b89b2dee19030e85515fd0f91d8f3b37c82d218a6531fc89c2b1b613c.png" width="200"></a>
[**packagecloud**](https://packagecloud.io) has provided free Debian/RPM repository hosting [**packagecloud**](https://packagecloud.io) has provided free Debian/RPM repository hosting
@@ -152,7 +152,7 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
[**keygen**](https://keygen.sh/?via=eugene) has provided free release & auto-update hosting [**keygen**](https://keygen.sh/?via=eugene) has provided free release & auto-update hosting
<a href="https://iqhive.com/"><img src="https://private-user-images.githubusercontent.com/161476/361584584-ed292436-1d50-46bc-b479-78222c83ed22.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQ3MDg3NjgsIm5iZiI6MTcyNDcwODQ2OCwicGF0aCI6Ii8xNjE0NzYvMzYxNTg0NTg0LWVkMjkyNDM2LTFkNTAtNDZiYy1iNDc5LTc4MjIyYzgzZWQyMi5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjQwODI2JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI0MDgyNlQyMTQxMDhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1iYzNlZjIxN2JiYzBkYTU5NGE4YmZlZDJiNmIxZWE1ZTAyOTNhYjJlZTRhOGZjYTk4N2E4MzMzZjg0ZTNkZWQ0JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZhY3Rvcl9pZD0wJmtleV9pZD0wJnJlcG9faWQ9MCJ9.pQzR2d71YV4TIxOH3Lg20HpNKrm_r2D-xfkEM_F2DTs" width="100"></a> <a href="https://iqhive.com/"><img src="https://iqhive.com/img/icons/logo.svg" width="200"></a>
[**IQ Hive**](https://iqhive.com) is providing financial support for the project development [**IQ Hive**](https://iqhive.com) is providing financial support for the project development
@@ -360,6 +360,12 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gh-log"><img src="https://avatars.githubusercontent.com/u/16019542?v=4?s=100" width="100px;" alt="gh-log"/><br /><sub><b>gh-log</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=gh-log" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -75,7 +75,7 @@ Ten plik README jest również dostępny w językach: <a href="./README.md">:gb
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* Konsola V220 + wiele rozszerzeń * Konsola VT220 + wiele rozszerzeń
* Wiele nakładających się podzielonych okien * Wiele nakładających się podzielonych okien
* Okna na każdej stronie ekranu * Okna na każdej stronie ekranu
* Opcjonalne dokowanie okna za pomocą skrótu ("Quake console") * Opcjonalne dokowanie okna za pomocą skrótu ("Quake console")

View File

@@ -67,7 +67,7 @@ Esse README também está disponível em: <a href="./README.md">:gb: English</a
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* Um terminal V220 + várias extensões * Um terminal VT220 + várias extensões
* Múltiplos painéis divididos aninhados * Múltiplos painéis divididos aninhados
* Guias em qualquer lado da janela * Guias em qualquer lado da janela
* Opção de minimizar para a barra de tarefas com uma tecla de atalho global ("Quake console") * Opção de minimizar para a barra de tarefas com uma tecla de atalho global ("Quake console")
@@ -345,6 +345,11 @@ Obrigado vai para essas pessoas maravilhosas ([emoji key](https://allcontributor
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -31,7 +31,7 @@
* Встроенный SSH- и Telnet-клиент и менеджер подключений; * Встроенный SSH- и Telnet-клиент и менеджер подключений;
* Встроенный последовательный терминал; * Встроенный последовательный терминал;
* Темы и цветовые схемы; * Темы и цветовые схемы;
* Полностью настраеваемые сочетания клавиш; * Полностью настраиваемые сочетания клавиш;
* Панели; * Панели;
* Запоминание вкладок; * Запоминание вкладок;
* Поддержка PowerShell (and PS Core), WSL, Git-Bash, Cygwin, MSYS2, Cmder и CMD; * Поддержка PowerShell (and PS Core), WSL, Git-Bash, Cygwin, MSYS2, Cmder и CMD;
@@ -67,7 +67,7 @@
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* Терминал V220 + различные дополнения; * Терминал VT220 + различные дополнения;
* Деление окна на несколько панелей; * Деление окна на несколько панелей;
* Вкладки на любой стороне окна; * Вкладки на любой стороне окна;
* Опционально закрепляемое окно с глобальной горячей клавишей для вызова («Quake console»); * Опционально закрепляемое окно с глобальной горячей клавишей для вызова («Quake console»);
@@ -337,6 +337,12 @@ Pull-запросы и плагины приветствуются!
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gh-log"><img src="https://avatars.githubusercontent.com/u/16019542?v=4?s=100" width="100px;" alt="gh-log"/><br /><sub><b>gh-log</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=gh-log" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -66,7 +66,7 @@
![](docs/readme-terminal.png) ![](docs/readme-terminal.png)
* 一个 V220 终端 + 各种插件 * 一个 VT220 终端 + 各种插件
* 多个嵌套的拆分窗格 * 多个嵌套的拆分窗格
* 可以将标签页设置在窗口的任意一侧 * 可以将标签页设置在窗口的任意一侧
* 带有全局生成热键的可选可停靠窗口“Quake console” * 带有全局生成热键的可选可停靠窗口“Quake console”
@@ -336,6 +336,12 @@
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/GeminiLn"><img src="https://avatars.githubusercontent.com/u/12425057?v=4?s=100" width="100px;" alt="Yu Qin"/><br /><sub><b>Yu Qin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=GeminiLn" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fireblue"><img src="https://avatars.githubusercontent.com/u/1034929?v=4?s=100" width="100px;" alt="fireblue"/><br /><sub><b>fireblue</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=fireblue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/marko1616"><img src="https://avatars.githubusercontent.com/u/45327989?v=4?s=100" width="100px;" alt="marko1616"/><br /><sub><b>marko1616</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=marko1616" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.selfhosted.sg/"><img src="https://avatars.githubusercontent.com/u/128927132?v=4?s=100" width="100px;" alt="SelfHosted"/><br /><sub><b>SelfHosted</b></sub></a><br /><a href="#financial-SelfHosted-Club" title="Financial">💵</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://hiroga.hatenablog.com/"><img src="https://avatars.githubusercontent.com/u/13391129?v=4?s=100" width="100px;" alt="Hiroaki Ogasawara"/><br /><sub><b>Hiroaki Ogasawara</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=xhiroga" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gh-log"><img src="https://avatars.githubusercontent.com/u/16019542?v=4?s=100" width="100px;" alt="gh-log"/><br /><sub><b>gh-log</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=gh-log" title="Code">💻</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -1,7 +1,7 @@
import * as glasstron from 'glasstron' import * as glasstron from 'glasstron'
import { autoUpdater } from 'electron-updater' import { autoUpdater } from 'electron-updater'
import { Subject, Observable, debounceTime } from 'rxjs' import { Subject, Observable, debounceTime } from 'rxjs'
import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen, BrowserWindowConstructorOptions, TouchBar, nativeImage, WebContents } from 'electron' import { BrowserWindow, app, ipcMain, Rectangle, Menu, screen, BrowserWindowConstructorOptions, TouchBar, nativeImage, WebContents, nativeTheme } from 'electron'
import ElectronConfig = require('electron-config') import ElectronConfig = require('electron-config')
import { enable as enableRemote } from '@electron/remote/main' import { enable as enableRemote } from '@electron/remote/main'
import * as os from 'os' import * as os from 'os'
@@ -100,6 +100,10 @@ export class Window {
} }
} }
if (process.platform === 'darwin') {
bwOptions.visualEffectState = 'active'
}
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
this.window = new BrowserWindow(bwOptions) as GlasstronWindow this.window = new BrowserWindow(bwOptions) as GlasstronWindow
} else { } else {
@@ -115,6 +119,8 @@ export class Window {
this.setVibrancy(true) this.setVibrancy(true)
} }
this.setDarkMode(this.configStore.appearance?.colorSchemeMode ?? 'dark')
if (!options.hidden) { if (!options.hidden) {
if (maximized) { if (maximized) {
this.window.maximize() this.window.maximize()
@@ -201,6 +207,18 @@ export class Window {
} }
} }
setDarkMode (mode: string): void {
if (process.platform === 'darwin') {
if ('light' === mode ) {
nativeTheme.themeSource = 'light'
} else if ('auto' === mode) {
nativeTheme.themeSource = 'system'
} else {
nativeTheme.themeSource = 'dark'
}
}
}
focus (): void { focus (): void {
this.window.focus() this.window.focus()
} }
@@ -373,6 +391,10 @@ export class Window {
this.setVibrancy(enabled, type) this.setVibrancy(enabled, type)
}) })
this.on('window-set-dark-mode', (_, mode) => {
this.setDarkMode(mode)
})
this.on('window-set-window-controls-color', (_, theme) => { this.on('window-set-window-controls-color', (_, theme) => {
if (process.platform === 'win32') { if (process.platform === 'win32') {
const symbolColor: string = theme.foreground const symbolColor: string = theme.foreground

View File

@@ -16,7 +16,7 @@
}, },
"dependencies": { "dependencies": {
"@electron/remote": "^2", "@electron/remote": "^2",
"node-pty": "^1.0", "node-pty": "^1.0.0",
"any-promise": "^1.3.0", "any-promise": "^1.3.0",
"electron-config": "2.0.0", "electron-config": "2.0.0",
"electron-debug": "^3.2.0", "electron-debug": "^3.2.0",
@@ -30,18 +30,19 @@
"native-process-working-directory": "^1.0.2", "native-process-working-directory": "^1.0.2",
"npm": "6", "npm": "6",
"rxjs": "^7.5.7", "rxjs": "^7.5.7",
"russh": "0.1.24",
"source-map-support": "^0.5.20", "source-map-support": "^0.5.20",
"v8-compile-cache": "^2.3.0", "v8-compile-cache": "^2.3.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"optionalDependencies": { "optionalDependencies": {
"@tabby-gang/windows-blurbehind": "^3.0.0", "@tabby-gang/windows-blurbehind": "^3.1.0",
"macos-native-processlist": "^2.1.0", "macos-native-processlist": "^2.1.0",
"patch-package": "^6.5.0", "patch-package": "^6.5.0",
"serialport": "11.0.1", "serialport": "11.0.1",
"serialport-binding-webserialapi": "^1.0.3", "serialport-binding-webserialapi": "^1.0.3",
"windows-native-registry": "^3.2.1", "windows-native-registry": "^3.2.1",
"windows-process-tree": "^0.4.0" "@tabby-gang/windows-process-tree": "^0.6.1"
}, },
"devDependencies": { "devDependencies": {
"@ngx-translate/core": "^14.0.0", "@ngx-translate/core": "^14.0.0",
@@ -64,6 +65,8 @@
}, },
"resolutions": { "resolutions": {
"*/node-abi": "^3", "*/node-abi": "^3",
"node-gyp": "^10.0.0" "node-gyp": "^10.0.0",
"nan": "2.22.0",
"node-addon-api": "^8.3.0"
} }
} }

View File

@@ -0,0 +1,53 @@
diff --git a/node_modules/node-pty/binding.gyp b/node_modules/node-pty/binding.gyp
index 79a93e7..efb0a3f 100644
--- a/node_modules/node-pty/binding.gyp
+++ b/node_modules/node-pty/binding.gyp
@@ -18,6 +18,9 @@
]
}
},
+ 'defines': [
+ 'NOMINMAX'
+ ]
}],
],
},
diff --git a/node_modules/node-pty/src/win/winpty.cc b/node_modules/node-pty/src/win/winpty.cc
index b054dee..a094b1c 100644
--- a/node_modules/node-pty/src/win/winpty.cc
+++ b/node_modules/node-pty/src/win/winpty.cc
@@ -164,7 +164,7 @@ static NAN_METHOD(PtyStartProcess) {
Nan::ThrowError(why.str().c_str());
goto cleanup;
}
-
+ {
int cols = info[4]->Int32Value(Nan::GetCurrentContext()).FromJust();
int rows = info[5]->Int32Value(Nan::GetCurrentContext()).FromJust();
bool debug = Nan::To<bool>(info[6]).FromJust();
@@ -179,6 +179,7 @@ static NAN_METHOD(PtyStartProcess) {
throw_winpty_error("Error creating WinPTY config", error_ptr);
goto cleanup;
}
+ {
winpty_error_free(error_ptr);
// Set pty size on config
@@ -215,7 +216,7 @@ static NAN_METHOD(PtyStartProcess) {
winpty_error_free(error_ptr);
// Set return values
- v8::Local<v8::Object> marshal = Nan::New<v8::Object>();
+ {v8::Local<v8::Object> marshal = Nan::New<v8::Object>();
Nan::Set(marshal, Nan::New<v8::String>("innerPid").ToLocalChecked(), Nan::New<v8::Number>((int)GetProcessId(handle)));
Nan::Set(marshal, Nan::New<v8::String>("innerPidHandle").ToLocalChecked(), Nan::New<v8::Number>((int)handle));
Nan::Set(marshal, Nan::New<v8::String>("pid").ToLocalChecked(), Nan::New<v8::Number>((int)winpty_agent_process(pc)));
@@ -232,7 +233,7 @@ static NAN_METHOD(PtyStartProcess) {
Nan::Set(marshal, Nan::New<v8::String>("conout").ToLocalChecked(), Nan::New<v8::String>(conoutPipeNameStr).ToLocalChecked());
}
info.GetReturnValue().Set(marshal);
-
+ }}}
goto cleanup;
cleanup:

View File

@@ -28,6 +28,11 @@
wrap-ansi "^8.1.0" wrap-ansi "^8.1.0"
wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
"@napi-rs/cli@^2.18.3":
version "2.18.4"
resolved "https://registry.yarnpkg.com/@napi-rs/cli/-/cli-2.18.4.tgz#12bebfb7995902fa7ab43cc0b155a7f5a2caa873"
integrity sha512-SgJeA4df9DE2iAEpr3M2H0OKl/yjtg1BnRI5/JyowS71tUWhrfSu2LT0V3vlHET+g1hBVlrO60PmEXwUEKp8Mg==
"@ngx-translate/core@^14.0.0": "@ngx-translate/core@^14.0.0":
version "14.0.0" version "14.0.0"
resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-14.0.0.tgz#af421d0e1a28376843f0fed375cd2fae7630a5ff" resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-14.0.0.tgz#af421d0e1a28376843f0fed375cd2fae7630a5ff"
@@ -173,13 +178,20 @@
dependencies: dependencies:
debug "^4.3.2" debug "^4.3.2"
"@tabby-gang/windows-blurbehind@^3.0.0": "@tabby-gang/windows-blurbehind@^3.1.0":
version "3.0.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/@tabby-gang/windows-blurbehind/-/windows-blurbehind-3.0.0.tgz#48d409c2eb14a12c867b70de5ee4d6769ef45e8f" resolved "https://registry.yarnpkg.com/@tabby-gang/windows-blurbehind/-/windows-blurbehind-3.1.0.tgz#bd1462f2a970d195e277d48cceb8b2c0a20f09bd"
integrity sha512-ah6eJcoQZWOZfu9sd2pWlOJmfl1v+2EZQMeIp7MWvg+/16WS16UFNdnOtlV6AUiABHfZo2QKfCNUEuorCM+Q2A== integrity sha512-wTvyNrBDNxD4yq1bXv7lvXRQujJYRQ2Ke3LJyE9yzY9e/L9/fHVIuprIgAMiLsnW+BKPERq0k27iC38WnxUBZQ==
dependencies: dependencies:
"@types/node" "^10.12.18" "@types/node" "^10.12.18"
"@tabby-gang/windows-process-tree@^0.6.1":
version "0.6.1"
resolved "https://registry.yarnpkg.com/@tabby-gang/windows-process-tree/-/windows-process-tree-0.6.1.tgz#2a5a5cbbee16f611fc61d53cbadf930c8d3d20a8"
integrity sha512-I7AwncTXTmo1+WPfV+O+jYRJzjCMJznIjC/ycl4dP/n2HAocuXCIjTZfoMmL+rgjN2nRFpTyn6P+EhuIPMACbQ==
dependencies:
node-addon-api "7.1.0"
"@types/mz@2.7.4": "@types/mz@2.7.4":
version "2.7.4" version "2.7.4"
resolved "https://registry.yarnpkg.com/@types/mz/-/mz-2.7.4.tgz#f9d1535cb5171199b28ae6abd6ec29e856551401" resolved "https://registry.yarnpkg.com/@types/mz/-/mz-2.7.4.tgz#f9d1535cb5171199b28ae6abd6ec29e856551401"
@@ -1490,25 +1502,26 @@ glasstron@0.1.1:
x11 "^2.3.0" x11 "^2.3.0"
glob@^10.2.2, glob@^10.3.10: glob@^10.2.2, glob@^10.3.10:
version "10.3.10" version "10.4.5"
resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956"
integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==
dependencies: dependencies:
foreground-child "^3.1.0" foreground-child "^3.1.0"
jackspeak "^2.3.5" jackspeak "^3.1.2"
minimatch "^9.0.1" minimatch "^9.0.4"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0" minipass "^7.1.2"
path-scurry "^1.10.1" package-json-from-dist "^1.0.0"
path-scurry "^1.11.1"
glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
version "7.1.6" version "7.2.3"
resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies: dependencies:
fs.realpath "^1.0.0" fs.realpath "^1.0.0"
inflight "^1.0.4" inflight "^1.0.4"
inherits "2" inherits "2"
minimatch "^3.0.4" minimatch "^3.1.1"
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
@@ -1931,10 +1944,10 @@ isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
jackspeak@^2.3.5: jackspeak@^3.1.2:
version "2.3.6" version "3.4.3"
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a"
integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==
dependencies: dependencies:
"@isaacs/cliui" "^8.0.2" "@isaacs/cliui" "^8.0.2"
optionalDependencies: optionalDependencies:
@@ -2286,13 +2299,18 @@ lowercase-keys@^1.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
lru-cache@^10.0.1, "lru-cache@^9.1.1 || ^10.0.0": lru-cache@^10.0.1:
version "10.0.2" version "10.0.2"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.2.tgz#34504678cc3266b09b8dfd6fab4e1515258271b7" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.2.tgz#34504678cc3266b09b8dfd6fab4e1515258271b7"
integrity sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg== integrity sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg==
dependencies: dependencies:
semver "^7.3.5" semver "^7.3.5"
lru-cache@^10.2.0:
version "10.4.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
lru-cache@^4.0.1: lru-cache@^4.0.1:
version "4.1.5" version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@@ -2412,10 +2430,17 @@ minimatch@^3.0.4:
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
minimatch@^9.0.1: minimatch@^3.1.1:
version "9.0.3" version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimatch@^9.0.4:
version "9.0.5"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
dependencies: dependencies:
brace-expansion "^2.0.1" brace-expansion "^2.0.1"
@@ -2488,6 +2513,11 @@ minipass@^5.0.0:
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
minipass@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
minizlib@^1.3.3: minizlib@^1.3.3:
version "1.3.3" version "1.3.3"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
@@ -2577,10 +2607,10 @@ mz@^2.7.0:
object-assign "^4.0.1" object-assign "^4.0.1"
thenify-all "^1.0.0" thenify-all "^1.0.0"
nan@^2.17.0: nan@2.22.0, nan@^2.17.0:
version "2.20.0" version "2.22.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3"
integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==
napi-build-utils@^1.0.1: napi-build-utils@^1.0.1:
version "1.0.2" version "1.0.2"
@@ -2625,20 +2655,10 @@ node-abi@^3.3.0:
dependencies: dependencies:
semver "^7.3.5" semver "^7.3.5"
node-addon-api@3.1.0, node-addon-api@^3.0.2, node-addon-api@^3.1.0: node-addon-api@3.1.0, node-addon-api@6.1.0, node-addon-api@7.1.0, node-addon-api@^3.0.2, node-addon-api@^3.1.0, node-addon-api@^4.0.0, node-addon-api@^4.3.0, node-addon-api@^8.3.0:
version "3.1.0" version "8.3.0"
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.3.0.tgz#ec3763f18befc1cdf66d11e157ce44d5eddc0603"
integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw== integrity sha512-8VOpLHFrOQlAH+qA0ZzuGRlALRA6/LVh8QJldbrC4DY0hXoMP0l4Acq8TzFC018HztWiRqyCEj2aTWY2UvnJUg==
node-addon-api@6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76"
integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==
node-addon-api@^4.0.0, node-addon-api@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
node-fetch-npm@^2.0.2: node-fetch-npm@^2.0.2:
version "2.0.4" version "2.0.4"
@@ -2670,7 +2690,7 @@ node-gyp@^10.0.0, node-gyp@^5.0.2, node-gyp@^5.1.0:
tar "^6.1.2" tar "^6.1.2"
which "^4.0.0" which "^4.0.0"
node-pty@^1.0: node-pty@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.0.0.tgz#7daafc0aca1c4ca3de15c61330373af4af5861fd" resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.0.0.tgz#7daafc0aca1c4ca3de15c61330373af4af5861fd"
integrity sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA== integrity sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==
@@ -3097,6 +3117,11 @@ p-try@^2.0.0:
resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
package-json-from-dist@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00"
integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==
package-json@^4.0.0: package-json@^4.0.0:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
@@ -3209,12 +3234,12 @@ path-parse@^1.0.6:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-scurry@^1.10.1: path-scurry@^1.11.1:
version "1.10.1" version "1.11.1"
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
dependencies: dependencies:
lru-cache "^9.1.1 || ^10.0.0" lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-type@^2.0.0: path-type@^2.0.0:
@@ -3603,6 +3628,13 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies: dependencies:
aproba "^1.1.1" aproba "^1.1.1"
russh@0.1.24:
version "0.1.24"
resolved "https://registry.yarnpkg.com/russh/-/russh-0.1.24.tgz#dce27a3bc63eb78024db60e6767bc80cbf523b9a"
integrity sha512-lLMtXHJKL5uwRxwoFNDx71T7+qCXiL80qyGCRgQjYMV10gaW2AlI6mqcz3FVH8dXvdgK2ZE8DuSwlhCBK7schA==
dependencies:
"@napi-rs/cli" "^2.18.3"
rxjs@^7.5.2, rxjs@^7.5.7: rxjs@^7.5.2, rxjs@^7.5.7:
version "7.5.7" version "7.5.7"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.7.tgz#2ec0d57fdc89ece220d2e702730ae8f1e49def39" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.7.tgz#2ec0d57fdc89ece220d2e702730ae8f1e49def39"
@@ -4420,13 +4452,6 @@ windows-native-registry@^3.2.1:
dependencies: dependencies:
node-addon-api "^3.1.0" node-addon-api "^3.1.0"
windows-process-tree@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.4.0.tgz#31ac49c5da557e628ce7e37a5800972173d3349a"
integrity sha512-9LunDnc1WwuhyLeTAXMFX8wbActGJtDCBaiapQXFYk/nO4W4X9YxOKV5g/lQL3XX69QYxveDbjVVrdnTt1qqCQ==
dependencies:
nan "^2.17.0"
worker-farm@^1.6.0, worker-farm@^1.7.0: worker-farm@^1.6.0, worker-farm@^1.7.0:
version "1.7.0" version "1.7.0"
resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"

View File

@@ -8,10 +8,6 @@
<true/> <true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key> <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/> <true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.device.microphone</key> <key>com.apple.security.device.microphone</key>
<true/> <true/>
<key>com.apple.security.device.camera</key> <key>com.apple.security.device.camera</key>

View File

@@ -32,11 +32,13 @@ extraResources:
- extras - extras
asarUnpack: asarUnpack:
- 'dist/*.map' - 'dist/*.map'
- node_modules/keytar/build/Release/*.node
- node_modules/**/*.node
win: win:
icon: "./build/windows/icon.ico" icon: "./build/windows/icon.ico"
artifactName: tabby-${version}-portable-${env.ARCH}.${ext} artifactName: tabby-${version}-portable-${env.ARCH}.${ext}
rfc3161TimeStampServer: http://timestamp.sectigo.com signtoolOptions:
rfc3161TimeStampServer: http://timestamp.sectigo.com
nsis: nsis:
oneClick: false oneClick: false
artifactName: tabby-${version}-setup-${env.ARCH}.${ext} artifactName: tabby-${version}-setup-${env.ARCH}.${ext}
@@ -70,7 +72,8 @@ linux:
executableArgs: executableArgs:
- "--no-sandbox" - "--no-sandbox"
desktop: desktop:
StartupWMClass: tabby entry:
StartupWMClass: tabby
snap: snap:
plugs: plugs:
- default - default
@@ -99,3 +102,7 @@ rpm:
- '_build_id_links none' - '_build_id_links none'
- '--replaces' - '--replaces'
- 'terminus-terminal' - 'terminus-terminal'
electronFuses:
runAsNode: false
enableNodeOptionsEnvironmentVariable: false
enableNodeCliInspectArguments: false

File diff suppressed because it is too large Load Diff

View File

@@ -1,63 +1,64 @@
:: Copyright (c) 2012 Martin Ridgers
:: License: http://opensource.org/licenses/MIT
@echo off @echo off
rem -- Copyright (c) 2012 Martin Ridgers
rem -- Portions Copyright (c) 2020-2024 Christopher Antos
rem -- License: http://opensource.org/licenses/MIT
setlocal enableextensions setlocal enableextensions
set clink_profile_arg= set clink_profile_arg=
set clink_quiet_arg= set clink_quiet_arg=
:: Mimic cmd.exe's behaviour when starting from the start menu. rem -- Mimic cmd.exe's behaviour when starting from the start menu.
if /i "%1"=="startmenu" ( if /i "%~1"=="startmenu" (
cd /d "%userprofile%" cd /d "%userprofile%"
shift shift
) )
:: Check for the --profile option. rem -- Check for the --profile option.
if /i "%1"=="--profile" ( if /i "%~1"=="--profile" (
set clink_profile_arg=--profile "%~2" set clink_profile_arg=--profile "%~2"
shift shift
shift shift
) )
:: Check for the --quiet option. rem -- Check for the --quiet option.
if /i "%1"=="--quiet" ( if /i "%~1"=="--quiet" (
set clink_quiet_arg= --quiet set clink_quiet_arg= --quiet
shift shift
) )
:: If the .bat is run without any arguments, then start a cmd.exe instance. rem -- If the .bat is run without any arguments, then start a cmd.exe instance.
if "%1"=="" ( if _%1==_ (
call :launch call :launch
goto :end goto :end
) )
:: Test for autorun. rem -- Test for autorun.
if defined CLINK_NOAUTORUN if /i "%1"=="inject" if /i "%2"=="--autorun" goto :end if defined CLINK_NOAUTORUN if /i "%~1"=="inject" if /i "%~2"=="--autorun" goto :end
:: Endlocal before inject tags the prompt. rem -- Forward to appropriate loader, and endlocal before inject tags the prompt.
endlocal
:: Pass through to appropriate loader.
if /i "%processor_architecture%"=="x86" ( if /i "%processor_architecture%"=="x86" (
endlocal
"%~dp0\clink_x86.exe" %* "%~dp0\clink_x86.exe" %*
) else if /i "%processor_architecture%"=="arm64" ( ) else if /i "%processor_architecture%"=="arm64" (
endlocal
"%~dp0\clink_arm64.exe" %* "%~dp0\clink_arm64.exe" %*
) else if /i "%processor_architecture%"=="amd64" ( ) else if /i "%processor_architecture%"=="amd64" (
if defined processor_architew6432 ( if defined processor_architew6432 (
endlocal
"%~dp0\clink_x86.exe" %* "%~dp0\clink_x86.exe" %*
) else ( ) else (
endlocal
"%~dp0\clink_x64.exe" %* "%~dp0\clink_x64.exe" %*
) )
) )
:end goto :end
goto :eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:launch :launch
setlocal setlocal enableextensions
set WT_PROFILE_ID= set WT_PROFILE_ID=
set WT_SESSION= set WT_SESSION=
start "Clink" cmd.exe /s /k ""%~dpnx0" inject %clink_profile_arg%%clink_quiet_arg%" start "Clink" cmd.exe /s /k ""%~dpnx0" inject %clink_profile_arg%%clink_quiet_arg%"
endlocal endlocal
exit /b 0
:end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -4,10 +4,10 @@
# Override the built-in Readline defaults with ones that provide a more # Override the built-in Readline defaults with ones that provide a more
# enhanced Clink experience. # enhanced Clink experience.
colored-completion-prefix on set colored-completion-prefix on
colored-stats on set colored-stats on
mark-symlinked-directories on set mark-symlinked-directories on
completion-auto-query-items on set completion-auto-query-items on
history-point-at-end-of-anchored-search on set history-point-at-end-of-anchored-search on
search-ignore-case on set search-ignore-case on

View File

@@ -1,34 +1,32 @@
# When this file is named "default_settings" and is in the binaries # When this file is named "default_settings" and is in the binaries
# directory or profile directory, it provides enhanced default settings. # directory or profile directory, it provides enhanced default settings.
# Override built-in default settings with ones that provide a more # Override built-in default settings with ones that provide a more
# enhanced Clink experience. # enhanced Clink experience.
autosuggest.enable = True clink.default_bindings = windows
clink.default_bindings = windows clink.autoupdate = off
cmd.ctrld_exits = False cmd.ctrld_exits = False
color.arginfo = sgr 38;5;172 color.arginfo = sgr 38;5;172
color.argmatcher = sgr 1;38;5;40 color.argmatcher = sgr 1;38;5;40
color.cmd = sgr 1;38;5;231 color.cmd = bold
color.cmdredir = sgr 38;5;172 color.cmdredir = sgr 38;5;172
color.cmdsep = sgr 38;5;214 color.cmdsep = sgr 38;5;135
color.comment_row = sgr 38;5;87;48;5;18 color.comment_row = sgr 38;5;87;48;5;18
color.description = sgr 38;5;39 color.description = sgr 38;5;39
color.doskey = sgr 1;38;5;75 color.doskey = sgr 1;38;5;75
color.executable = sgr 1;38;5;33 color.executable = sgr 1;38;5;33
color.filtered = sgr 38;5;231 color.filtered = bold
color.flag = sgr 38;5;117 color.flag = sgr 38;5;117
color.hidden = sgr 38;5;160 color.hidden = sgr 38;5;160
color.histexpand = sgr 97;48;5;55 color.histexpand = sgr 97;48;5;55
color.horizscroll = sgr 38;5;16;48;5;30 color.horizscroll = sgr 38;5;16;48;5;30
color.input = sgr 38;5;222 color.input = sgr 38;5;214
color.readonly = sgr 38;5;28 color.readonly = sgr 38;5;28
color.selected_completion = sgr 38;5;16;48;5;254 color.selected_completion = sgr 7
color.selection = sgr 38;5;16;48;5;179 color.selection = sgr 38;5;16;48;5;179
color.suggestion = sgr 38;5;239 color.unrecognized = sgr 38;5;203
color.unrecognized = sgr 38;5;203 history.max_lines = 25000
history.max_lines = 25000 history.time_stamp = show
history.time_stamp = show match.expand_envvars = True
match.expand_envvars = True match.substring = True
match.substring = True

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Afrikaans\n" "Language-Team: Afrikaans\n"
"Language: af_ZA\n" "Language: af_ZA\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Bulgarian\n" "Language-Team: Bulgarian\n"
"Language: bg_BG\n" "Language: bg_BG\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Czech\n" "Language-Team: Czech\n"
"Language: cs_CZ\n" "Language: cs_CZ\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Danish\n" "Language-Team: Danish\n"
"Language: da_DK\n" "Language: da_DK\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"
@@ -211,7 +211,7 @@ msgstr "Sløring"
#: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:28 #: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:28
msgid "Bold font weight" msgid "Bold font weight"
msgstr "" msgstr "Fed skriftvægt"
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:132 #: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:132
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:80 #: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:80

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: German\n" "Language-Team: German\n"
"Language: de_DE\n" "Language: de_DE\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: English, United Kingdom\n" "Language-Team: English, United Kingdom\n"
"Language: en_GB\n" "Language: en_GB\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Spanish\n" "Language-Team: Spanish\n"
"Language: es_ES\n" "Language: es_ES\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: French\n" "Language-Team: French\n"
"Language: fr_FR\n" "Language: fr_FR\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Croatian\n" "Language-Team: Croatian\n"
"Language: hr_HR\n" "Language: hr_HR\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Indonesian\n" "Language-Team: Indonesian\n"
"Language: id_ID\n" "Language: id_ID\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2025-01-22 22:02\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"
@@ -23,7 +23,7 @@ msgstr "{name} salin"
#: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:77 #: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:77
msgid "A second font family used to display characters missing in the main font" msgid "A second font family used to display characters missing in the main font"
msgstr "Keluarga font kedua digunakan untuk menampilkan karakter yang hilang di font utama" msgstr "Keluarga huruf kedua digunakan untuk menampilkan karakter yang hilang di huruf utama"
#: tabby-core/src/components/transfersMenu.component.ts:49 #: tabby-core/src/components/transfersMenu.component.ts:49
msgid "Abort all" msgid "Abort all"
@@ -100,12 +100,12 @@ msgstr "Izinkan buka dengan cepat terminal di direktori terpilih"
#: locale/tmp-html/tabby-core/src/components/welcomeTab.component.html:25 #: locale/tmp-html/tabby-core/src/components/welcomeTab.component.html:25
#: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsTab.component.html:11 #: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsTab.component.html:11
msgid "Always dark" msgid "Always dark"
msgstr "" msgstr "Selalu gelap"
#: locale/tmp-html/tabby-core/src/components/welcomeTab.component.html:27 #: locale/tmp-html/tabby-core/src/components/welcomeTab.component.html:27
#: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsTab.component.html:13 #: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsTab.component.html:13
msgid "Always light" msgid "Always light"
msgstr "" msgstr "Selalu terang"
#: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:2 #: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:2
#: tabby-terminal/src/settings.ts:14 #: tabby-terminal/src/settings.ts:14
@@ -255,7 +255,7 @@ msgstr "Ubah baud rate"
#: tabby-core/src/tabContextMenu.ts:133 #: tabby-core/src/tabContextMenu.ts:133
msgid "Change tab color" msgid "Change tab color"
msgstr "" msgstr "Rubah warna label"
#: locale/tmp-html/tabby-settings/src/components/vaultSettingsTab.component.html:12 #: locale/tmp-html/tabby-settings/src/components/vaultSettingsTab.component.html:12
msgid "Change the master passphrase" msgid "Change the master passphrase"
@@ -337,7 +337,7 @@ msgstr "Skema warna"
#: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsTab.component.html:2 #: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsTab.component.html:2
msgid "Color schemes" msgid "Color schemes"
msgstr "" msgstr "Warna Skema"
#: locale/tmp-html/tabby-serial/src/components/serialProfileSettings.component.html:81 #: locale/tmp-html/tabby-serial/src/components/serialProfileSettings.component.html:81
#: locale/tmp-html/tabby-ssh/src/components/sshProfileSettings.component.html:216 #: locale/tmp-html/tabby-ssh/src/components/sshProfileSettings.component.html:216
@@ -362,7 +362,7 @@ msgstr "Perintah-perintah"
#: tabby-core/src/theme.ts:16 #: tabby-core/src/theme.ts:16
msgid "Compact (legacy)" msgid "Compact (legacy)"
msgstr "" msgstr "Padat (tua)"
#: tabby-settings/src/components/configSyncSettingsTab.component.ts:126 #: tabby-settings/src/components/configSyncSettingsTab.component.ts:126
msgid "Config deleted" msgid "Config deleted"
@@ -449,7 +449,7 @@ msgstr "Salin jalur saat ini"
#: tabby-electron/src/sftpContextMenu.ts:29 #: tabby-electron/src/sftpContextMenu.ts:29
msgid "Copy full path" msgid "Copy full path"
msgstr "" msgstr "Salin alamat lengkap"
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:97 #: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:97
msgid "Copy on select" msgid "Copy on select"
@@ -1732,7 +1732,7 @@ msgstr "Ganti Nama"
#: tabby-core/src/hotkeys.ts:24 #: tabby-core/src/hotkeys.ts:24
#: tabby-core/src/tabContextMenu.ts:121 #: tabby-core/src/tabContextMenu.ts:121
msgid "Rename tab" msgid "Rename tab"
msgstr "" msgstr "Ganti nama label"
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:3 #: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:3
msgid "Rendering" msgid "Rendering"
@@ -1770,7 +1770,7 @@ msgstr "Mulai ulang sesi SSH saat ini"
#: tabby-telnet/src/hotkeys.ts:10 #: tabby-telnet/src/hotkeys.ts:10
msgid "Restart current Telnet session" msgid "Restart current Telnet session"
msgstr "" msgstr "Mulai ulang sesi Telnet saat ini"
#: tabby-core/src/hotkeys.ts:64 #: tabby-core/src/hotkeys.ts:64
msgid "Restart tab" msgid "Restart tab"
@@ -1782,7 +1782,7 @@ msgstr "Mulai ulang aplikasi untuk menerapkan perubahan"
#: tabby-settings/src/components/profilesSettingsTab.component.ts:316 #: tabby-settings/src/components/profilesSettingsTab.component.ts:316
msgid "Restore settings to defaults ?" msgid "Restore settings to defaults ?"
msgstr "" msgstr "Kembali ke settingan sebelumnya ?"
#: tabby-settings/src/components/editProfileGroupModal.component.ts:36 #: tabby-settings/src/components/editProfileGroupModal.component.ts:36
msgid "Restore settings to inherited defaults ?" msgid "Restore settings to inherited defaults ?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Italian\n" "Language-Team: Italian\n"
"Language: it_IT\n" "Language: it_IT\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2025-01-22 22:02\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"
@@ -192,7 +192,7 @@ msgstr "Modalità tasto backspace"
#: tabby-serial/src/components/serialTab.component.ts:93 #: tabby-serial/src/components/serialTab.component.ts:93
#: tabby-serial/src/profiles.ts:88 #: tabby-serial/src/profiles.ts:88
msgid "Baud rate" msgid "Baud rate"
msgstr "Velocità di trasmissione" msgstr "Velocità trasmissione"
#: tabby-terminal/src/hotkeys.ts:22 #: tabby-terminal/src/hotkeys.ts:22
msgid "Beginning of the line" msgid "Beginning of the line"
@@ -479,7 +479,7 @@ msgstr "Crea cartella"
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:90 #: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:90
msgid "Current" msgid "Current"
msgstr "Corrente" msgstr "Attuale"
#: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsForMode.component.html:3 #: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsForMode.component.html:3
msgid "Current color scheme" msgid "Current color scheme"
@@ -487,7 +487,7 @@ msgstr "Tema in uso"
#: locale/tmp-html/tabby-ssh/src/components/hostKeyPromptModal.component.html:17 #: locale/tmp-html/tabby-ssh/src/components/hostKeyPromptModal.component.html:17
msgid "Current host key fingerprint" msgid "Current host key fingerprint"
msgstr "Firma della chiave host attuale" msgstr "Firma chiave host attuale"
#: tabby-core/src/tabContextMenu.ts:184 #: tabby-core/src/tabContextMenu.ts:184
msgid "Current process: {name}" msgid "Current process: {name}"
@@ -495,7 +495,7 @@ msgstr "Processo attuale: {name}"
#: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:51 #: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:51
msgid "Cursor shape" msgid "Cursor shape"
msgstr "Forma del cursore" msgstr "Forma cursore"
#: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsForMode.component.html:46 #: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsForMode.component.html:46
msgid "Custom" msgid "Custom"
@@ -531,7 +531,7 @@ msgstr "\"Connetti a\" predefinito"
#: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:93 #: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:93
msgid "Default connection type used by quick connect feature (ex. SSH, Telnet)" msgid "Default connection type used by quick connect feature (ex. SSH, Telnet)"
msgstr "Tipo di connessione predefinito usato dalla funzione di connessione rapida (es. SSH, Telnet)" msgstr "Tipo di connessione predefinita usato dalla funzione di connessione rapida (es. SSH, Telnet)"
#: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:8 #: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:8
msgid "Default profile for new tabs" msgid "Default profile for new tabs"
@@ -791,7 +791,7 @@ msgstr "Cancella configurazione"
#: locale/tmp-html/tabby-settings/src/components/vaultSettingsTab.component.html:12 #: locale/tmp-html/tabby-settings/src/components/vaultSettingsTab.component.html:12
msgid "Erase the Vault" msgid "Erase the Vault"
msgstr "Cancella la cassaforte" msgstr "Cancella cassaforte"
#: locale/tmp-html/tabby-plugin-manager/src/components/pluginsSettingsTab.component.html:6 #: locale/tmp-html/tabby-plugin-manager/src/components/pluginsSettingsTab.component.html:6
msgid "Error in {plugin}:" msgid "Error in {plugin}:"
@@ -1189,7 +1189,7 @@ msgstr "Lingua"
#: locale/tmp-html/tabby-ssh/src/components/hostKeyPromptModal.component.html:11 #: locale/tmp-html/tabby-ssh/src/components/hostKeyPromptModal.component.html:11
msgid "Last known host key fingerprint" msgid "Last known host key fingerprint"
msgstr "Ultima firma nota della chiave host" msgstr "Ultima firma nota chiave host"
#: tabby-ssh/src/tabContextMenu.ts:32 #: tabby-ssh/src/tabContextMenu.ts:32
msgid "Launch WinSCP" msgid "Launch WinSCP"
@@ -1439,7 +1439,7 @@ msgstr "Nelle discussioni di GitHub"
#: locale/tmp-html/tabby-settings/src/components/editProfileModal.component.html:47 #: locale/tmp-html/tabby-settings/src/components/editProfileModal.component.html:47
msgid "Only close the tab when session is explicitly terminated" msgid "Only close the tab when session is explicitly terminated"
msgstr "Chiude la scheda solo quando la sessione è esplicitamente terminata" msgstr "Chiudi la scheda solo quando la sessione è esplicitamente terminata"
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:46 #: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:46
msgid "Opacity" msgid "Opacity"
@@ -1476,11 +1476,11 @@ msgstr "Arancione"
#: tabby-electron/src/shells/macDefault.ts:25 #: tabby-electron/src/shells/macDefault.ts:25
msgid "OS default" msgid "OS default"
msgstr "Predefinito del OS" msgstr "Predefinito S.O."
#: tabby-electron/src/shells/winDefault.ts:43 #: tabby-electron/src/shells/winDefault.ts:43
msgid "OS default ({name})" msgid "OS default ({name})"
msgstr "Predefinito del OS ({name})" msgstr "Predefinito S.O. ({name})"
#: tabby-terminal/src/components/streamProcessingSettings.component.ts:46 #: tabby-terminal/src/components/streamProcessingSettings.component.ts:46
msgid "Output is shown as a hexdump" msgid "Output is shown as a hexdump"
@@ -1678,7 +1678,7 @@ msgstr "Connessione raw socket"
#: locale/tmp-html/tabby-ssh/src/components/sshProfileSettings.component.html:166 #: locale/tmp-html/tabby-ssh/src/components/sshProfileSettings.component.html:166
msgid "Ready Timeout (Milliseconds)" msgid "Ready Timeout (Milliseconds)"
msgstr "Tempo di preparazione (in millisecondi)" msgstr "Tempo stato pronto (millisecondi)"
#: tabby-core/src/services/profiles.service.ts:235 #: tabby-core/src/services/profiles.service.ts:235
#: tabby-core/src/services/profiles.service.ts:249 #: tabby-core/src/services/profiles.service.ts:249
@@ -1694,7 +1694,7 @@ msgstr "Recente"
#: tabby-terminal/src/tabContextMenu.ts:115 #: tabby-terminal/src/tabContextMenu.ts:115
#: tabby-terminal/src/tabContextMenu.ts:119 #: tabby-terminal/src/tabContextMenu.ts:119
msgid "Reconnect" msgid "Reconnect"
msgstr "Riconetti" msgstr "Riconnetti"
#: tabby-terminal/src/hotkeys.ts:102 #: tabby-terminal/src/hotkeys.ts:102
msgid "Reconnect current tab (Serial/Telnet/SSH)" msgid "Reconnect current tab (Serial/Telnet/SSH)"
@@ -1723,7 +1723,7 @@ msgstr "Remoto"
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:124 #: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:124
msgid "Remove whitespace and newlines around the copied text" msgid "Remove whitespace and newlines around the copied text"
msgstr "Rimuovi spazi bianchi e a riorni a capo dal testo copiato" msgstr "Rimuovi spazi bianchi e a ritorni a capo dal testo copiato"
#: locale/tmp-html/tabby-settings/src/components/vaultSettingsTab.component.html:26 #: locale/tmp-html/tabby-settings/src/components/vaultSettingsTab.component.html:26
#: tabby-core/src/tabContextMenu.ts:120 #: tabby-core/src/tabContextMenu.ts:120
@@ -2011,7 +2011,7 @@ msgstr "Visualizza predefiniti"
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:146 #: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:146
msgid "Show Mixer" msgid "Show Mixer"
msgstr "Visualizza Mixer" msgstr "Visualizza mixer"
#: tabby-core/src/hotkeys.ts:56 #: tabby-core/src/hotkeys.ts:56
msgid "Show pane labels (for rearranging)" msgid "Show pane labels (for rearranging)"
@@ -2177,7 +2177,7 @@ msgstr "Cambia l'implementazione del frontend del terminale (sperimentale)"
#: locale/tmp-html/tabby-settings/src/components/configSyncSettingsTab.component.html:4 #: locale/tmp-html/tabby-settings/src/components/configSyncSettingsTab.component.html:4
msgid "Sync" msgid "Sync"
msgstr "Sincronizazione" msgstr "Sincronizzazione"
#: locale/tmp-html/tabby-settings/src/components/configSyncSettingsTab.component.html:53 #: locale/tmp-html/tabby-settings/src/components/configSyncSettingsTab.component.html:53
msgid "Sync automatically" msgid "Sync automatically"
@@ -2382,7 +2382,7 @@ msgstr "Carica come nuova configurazione"
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:39 #: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:39
msgid "Use {altKeyName} as the Meta key" msgid "Use {altKeyName} as the Meta key"
msgstr "Usa {altKeyName} come chiave Meta" msgstr "Come chiave meta usa {altKeyName} "
#: locale/tmp-html/tabby-local/src/components/shellSettingsTab.component.html:5 #: locale/tmp-html/tabby-local/src/components/shellSettingsTab.component.html:5
msgid "Use ConPTY" msgid "Use ConPTY"
@@ -2554,7 +2554,7 @@ msgstr "Giallo"
#: locale/tmp-html/tabby-settings/src/components/setVaultPassphraseModal.component.html:4 #: locale/tmp-html/tabby-settings/src/components/setVaultPassphraseModal.component.html:4
msgid "You can change it later, but it's unrecoverable if forgotten." msgid "You can change it later, but it's unrecoverable if forgotten."
msgstr "Si può cambiare più tardi, ma è irrecuperabile se dimenticata." msgstr "Si può modificare più tardi, ma è irrecuperabile se dimenticata."
#: locale/tmp-html/tabby-ssh/src/components/hostKeyPromptModal.component.html:7 #: locale/tmp-html/tabby-ssh/src/components/hostKeyPromptModal.component.html:7
msgid "You could be under a man-in-the-middle attack right now, or the host key could have just been changed." msgid "You could be under a man-in-the-middle attack right now, or the host key could have just been changed."

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Japanese\n" "Language-Team: Japanese\n"
"Language: ja_JP\n" "Language: ja_JP\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Korean\n" "Language-Team: Korean\n"
"Language: ko_KR\n" "Language: ko_KR\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Polish\n" "Language-Team: Polish\n"
"Language: pl_PL\n" "Language: pl_PL\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Portuguese, Brazilian\n" "Language-Team: Portuguese, Brazilian\n"
"Language: pt_BR\n" "Language: pt_BR\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Portuguese\n" "Language-Team: Portuguese\n"
"Language: pt_PT\n" "Language: pt_PT\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Russian\n" "Language-Team: Russian\n"
"Language: ru_RU\n" "Language: ru_RU\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"
@@ -660,7 +660,7 @@ msgstr "Отключиться от {host}?"
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:30 #: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:30
msgid "Display images via Sixel escape sequences" msgid "Display images via Sixel escape sequences"
msgstr "Отображать изображения при помощи сиксельной управляющей последовательности" msgstr "Отображать изображения при помощи управляющей последовательности Sixel"
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:85 #: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:85
msgid "Display on" msgid "Display on"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Serbian (Cyrillic)\n" "Language-Team: Serbian (Cyrillic)\n"
"Language: sr_SP\n" "Language: sr_SP\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Swedish\n" "Language-Team: Swedish\n"
"Language: sv_SE\n" "Language: sv_SE\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Turkish\n" "Language-Team: Turkish\n"
"Language: tr_TR\n" "Language: tr_TR\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2025-01-22 22:02\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"
@@ -966,7 +966,7 @@ msgstr "Hazır bir GitHub sorunu oluşturun"
#: locale/tmp-html/tabby-plugin-manager/src/components/pluginsSettingsTab.component.html:25 #: locale/tmp-html/tabby-plugin-manager/src/components/pluginsSettingsTab.component.html:25
msgid "Get" msgid "Get"
msgstr "Getir" msgstr "Yükle"
#: locale/tmp-html/tabby-settings/src/components/configSyncSettingsTab.component.html:18 #: locale/tmp-html/tabby-settings/src/components/configSyncSettingsTab.component.html:18
msgid "Get it from the Tabby Web settings window" msgid "Get it from the Tabby Web settings window"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Ukrainian\n" "Language-Team: Ukrainian\n"
"Language: uk_UA\n" "Language: uk_UA\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2024-12-24 22:58\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Chinese Simplified\n" "Language-Team: Chinese Simplified\n"
"Language: zh_CN\n" "Language: zh_CN\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2025-01-22 22:02\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"
@@ -43,7 +43,7 @@ msgstr "辅助功能"
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:27 #: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:27
msgid "Acrylic background" msgid "Acrylic background"
msgstr "亚克力背景" msgstr "毛玻璃背景"
#: locale/tmp-html/tabby-local/src/components/commandLineEditor.component.html:24 #: locale/tmp-html/tabby-local/src/components/commandLineEditor.component.html:24
#: locale/tmp-html/tabby-local/src/components/environmentEditor.component.html:11 #: locale/tmp-html/tabby-local/src/components/environmentEditor.component.html:11

View File

@@ -10,7 +10,7 @@ msgstr ""
"Project-Id-Version: tabby\n" "Project-Id-Version: tabby\n"
"Language-Team: Chinese Traditional\n" "Language-Team: Chinese Traditional\n"
"Language: zh_TW\n" "Language: zh_TW\n"
"PO-Revision-Date: 2024-09-26 08:04\n" "PO-Revision-Date: 2025-01-22 22:02\n"
#: tabby-local/src/components/terminalTab.component.ts:113 #: tabby-local/src/components/terminalTab.component.ts:113
msgid "\"{command}\" is still running. Close?" msgid "\"{command}\" is still running. Close?"

View File

@@ -39,11 +39,11 @@
"cross-env": "7.0.3", "cross-env": "7.0.3",
"css-loader": "^6.7.3", "css-loader": "^6.7.3",
"deep-equal": "2.0.5", "deep-equal": "2.0.5",
"electron": "^29", "electron": "^32.2.7",
"electron-builder": "^24.6.4", "electron-builder": "^26.0.0-alpha.10",
"electron-download": "^4.1.1", "electron-download": "^4.1.1",
"electron-installer-snap": "^5.1.0", "electron-installer-snap": "^5.1.0",
"electron-rebuild": "^3.2.9", "@electron/rebuild": "^3.7.1",
"eslint": "^8.48.0", "eslint": "^8.48.0",
"eslint-import-resolver-typescript": "^3.6.0", "eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-import": "^2.28.1", "eslint-plugin-import": "^2.28.1",
@@ -55,7 +55,7 @@
"lru-cache": "^6.0.0", "lru-cache": "^6.0.0",
"macos-release": "^3.3.0", "macos-release": "^3.3.0",
"ngx-toastr": "^16.0.2", "ngx-toastr": "^16.0.2",
"node-abi": "^3.65.0", "node-abi": "^3.71.0",
"npmlog": "6.0.2", "npmlog": "6.0.2",
"npx": "^10.2.2", "npx": "^10.2.2",
"patch-package": "^6.4.7", "patch-package": "^6.4.7",
@@ -76,7 +76,6 @@
"source-code-pro": "^2.38.0", "source-code-pro": "^2.38.0",
"source-map-loader": "^4.0.1", "source-map-loader": "^4.0.1",
"source-sans-pro": "3.6.0", "source-sans-pro": "3.6.0",
"ssh2": "^1.14.0",
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
"svg-inline-loader": "^0.8.2", "svg-inline-loader": "^0.8.2",
"thenby": "^1.3.4", "thenby": "^1.3.4",
@@ -97,7 +96,8 @@
"*/pug": "^3", "*/pug": "^3",
"lzma-native": "^8.0.6", "lzma-native": "^8.0.6",
"**/graceful-fs": "^4.2.4", "**/graceful-fs": "^4.2.4",
"nan": "2.17.0" "nan": "2.22.0",
"node-gyp": "^10.0.0"
}, },
"scripts": { "scripts": {
"build": "npm run build:typings && node scripts/build-modules.mjs", "build": "npm run build:typings && node scripts/build-modules.mjs",

View File

@@ -1,8 +1,8 @@
diff --git a/node_modules/app-builder-lib/out/appInfo.js b/node_modules/app-builder-lib/out/appInfo.js diff --git a/node_modules/app-builder-lib/out/appInfo.js b/node_modules/app-builder-lib/out/appInfo.js
index 49f6dca..0ea11f2 100644 index 7fbbef7..0821807 100644
--- a/node_modules/app-builder-lib/out/appInfo.js --- a/node_modules/app-builder-lib/out/appInfo.js
+++ b/node_modules/app-builder-lib/out/appInfo.js +++ b/node_modules/app-builder-lib/out/appInfo.js
@@ -112,9 +112,7 @@ class AppInfo { @@ -116,9 +116,7 @@ class AppInfo {
return this.info.metadata.name; return this.info.metadata.name;
} }
get linuxPackageName() { get linuxPackageName() {

View File

@@ -1,39 +0,0 @@
diff --git a/node_modules/ssh2/lib/protocol/keyParser.js b/node_modules/ssh2/lib/protocol/keyParser.js
index 9860e3f..ee82e51 100644
--- a/node_modules/ssh2/lib/protocol/keyParser.js
+++ b/node_modules/ssh2/lib/protocol/keyParser.js
@@ -15,6 +15,7 @@ const {
sign: sign_,
verify: verify_,
} = require('crypto');
+const { createVerify: createVerifyDSS } = require('browserify-sign')
const supportedOpenSSLCiphers = getCiphers();
const { Ber } = require('asn1');
@@ -404,6 +405,17 @@ const BaseKey = {
return new Error('No public key available');
if (!algo || typeof algo !== 'string')
algo = this[SYM_HASH_ALGO];
+
+ if (algo === 'dss1') {
+ const verifier = createVerifyDSS('DSA-SHA1');
+ verifier.update(data);
+ try {
+ return verifier.verify(pem, signature);
+ } catch (ex) {
+ return ex;
+ }
+ }
+
try {
return verify_(algo, data, pem, signature);
} catch (ex) {
@@ -1343,7 +1355,7 @@ function parseDER(data, baseType, comment, fullType) {
return new Error('Malformed OpenSSH public key');
pubPEM = genOpenSSLDSAPub(p, q, g, y);
pubSSH = genOpenSSHDSAPub(p, q, g, y);
- algo = 'sha1';
+ algo = 'dss1';
break;
}
case 'ssh-ed25519': {

View File

@@ -25,7 +25,7 @@ builder({
}, },
] : undefined, ] : undefined,
}, },
publish: process.env.KEYGEN_TOKEN ? isTag ? 'always' : 'onTagOrDraft' : 'never', publish: (process.env.KEYGEN_TOKEN && isTag) ? 'always' : 'never',
}).catch(e => { }).catch(e => {
console.error(e) console.error(e)
process.exit(1) process.exit(1)

View File

@@ -28,10 +28,7 @@ builder({
}, },
mac: { mac: {
identity: !process.env.CI || process.env.CSC_LINK ? undefined : null, identity: !process.env.CI || process.env.CSC_LINK ? undefined : null,
notarize: process.env.APPLE_TEAM_ID ? { notarize: !!process.env.APPLE_TEAM_ID,
appBundleId: 'org.tabby',
teamId: process.env.APPLE_TEAM_ID,
} : false,
}, },
npmRebuild: process.env.ARCH !== 'arm64', npmRebuild: process.env.ARCH !== 'arm64',
publish: process.env.KEYGEN_TOKEN ? [ publish: process.env.KEYGEN_TOKEN ? [
@@ -42,7 +39,7 @@ builder({
}, },
] : undefined, ] : undefined,
}, },
publish: process.env.KEYGEN_TOKEN ? isTag ? 'always' : 'onTagOrDraft' : 'never', publish: (process.env.KEYGEN_TOKEN && isTag) ? 'always' : 'never',
}).catch(e => { }).catch(e => {
console.error(e) console.error(e)
process.exit(1) process.exit(1)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env node #!/usr/bin/env node
import { rebuild } from 'electron-rebuild' import { rebuild } from '@electron/rebuild'
import * as path from 'path' import * as path from 'path'
import * as vars from './vars.mjs' import * as vars from './vars.mjs'

View File

@@ -2,11 +2,15 @@
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
import { build as builder } from 'electron-builder' import { build as builder } from 'electron-builder'
import * as vars from './vars.mjs' import * as vars from './vars.mjs'
import { execSync } from 'child_process'
const isTag = (process.env.GITHUB_REF || process.env.BUILD_SOURCEBRANCH || '').startsWith('refs/tags/') const isTag = (process.env.GITHUB_REF || process.env.BUILD_SOURCEBRANCH || '').startsWith('refs/tags/')
const keypair = process.env.SM_KEYPAIR_ALIAS
process.env.ARCH = process.env.ARCH || process.arch process.env.ARCH = process.env.ARCH || process.arch
console.log('Signing enabled:', !!keypair)
builder({ builder({
dir: true, dir: true,
win: ['nsis', 'zip'], win: ['nsis', 'zip'],
@@ -22,8 +26,35 @@ builder({
channel: `latest-${process.env.ARCH}`, channel: `latest-${process.env.ARCH}`,
}, },
] : undefined, ] : undefined,
forceCodeSigning: !!keypair,
win: {
signtoolOptions: {
certificateSha1: process.env.SM_CODE_SIGNING_CERT_SHA1_HASH,
publisherName: process.env.SM_PUBLISHER_NAME,
signingHashAlgorithms: ['sha256'],
sign: keypair ? async function (configuration) {
console.log('Signing', configuration)
if (configuration.path) {
try {
const out = execSync(
`smctl sign --keypair-alias=${keypair} --input "${String(configuration.path)}"`
)
if (out.toString().includes('FAILED')) {
throw new Error(out.toString())
}
console.log(out.toString())
} catch (e) {
console.error(`Failed to sign ${configuration.path}`)
console.error(e)
process.exit(1)
}
}
} : undefined,
},
},
}, },
publish: process.env.KEYGEN_TOKEN ? isTag ? 'always' : 'onTagOrDraft' : 'never',
publish: (process.env.KEYGEN_TOKEN && isTag) ? 'always' : 'never',
}).catch(e => { }).catch(e => {
console.error(e) console.error(e)
process.exit(1) process.exit(1)

View File

@@ -10,6 +10,8 @@ log.info('deps', 'app')
sh.cd('app') sh.cd('app')
sh.exec(`yarn install --force --network-timeout 1000000`, { fatal: true }) sh.exec(`yarn install --force --network-timeout 1000000`, { fatal: true })
// Some native packages might fail to build before patch-package gets a chance to run via postinstall
sh.exec(`yarn postinstall`, { fatal: false })
sh.cd('..') sh.cd('..')
sh.cd('web') sh.cd('web')

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env node #!/usr/bin/env node
import { rebuild } from 'electron-rebuild' import { rebuild } from '@electron/rebuild'
import sh from 'shelljs' import sh from 'shelljs'
import path from 'node:path' import path from 'node:path'
import fs from 'node:fs' import fs from 'node:fs'

View File

@@ -0,0 +1,44 @@
!
! Generated with :
! XRDB2Xreources.py
!
*.foreground: #c0caf5
*.background: #1a1b26
*.cursorColor: #c0caf5
!
! Black
*.color0: #15161e
*.color8: #414868
!
! Red
*.color1: #f7768e
*.color9: #f7768e
!
! Green
*.color2: #9ece6a
*.color10: #9ece6a
!
! Yellow
*.color3: #e0af68
*.color11: #e0af68
!
! Blue
*.color4: #7aa2f7
*.color12: #7aa2f7
!
! Magenta
*.color5: #bb9af7
*.color13: #bb9af7
!
! Cyan
*.color6: #7dcfff
*.color14: #7dcfff
!
! White
*.color7: #a9b1d6
*.color15: #c0caf5
!
! Bold, Italic, Underline
*.colorBD: #eeeeee
!*.colorIT:
!*.colorUL:

View File

@@ -0,0 +1,44 @@
!
! Generated with :
! XRDB2Xreources.py
!
*.foreground: #3760bf
*.background: #e1e2e7
*.cursorColor: #3760bf
!
! Black
*.color0: #e9e9ed
*.color8: #a1a6c5
!
! Red
*.color1: #f52a65
*.color9: #f52a65
!
! Green
*.color2: #587539
*.color10: #587539
!
! Yellow
*.color3: #8c6c3e
*.color11: #8c6c3e
!
! Blue
*.color4: #2e7de9
*.color12: #2e7de9
!
! Magenta
*.color5: #9854f1
*.color13: #9854f1
!
! Cyan
*.color6: #007197
*.color14: #007197
!
! White
*.color7: #6172b0
*.color15: #3760bf
!
! Bold, Italic, Underline
*.colorBD: #eeeeee
!*.colorIT:
!*.colorUL:

View File

@@ -0,0 +1,44 @@
!
! Generated with :
! XRDB2Xreources.py
!
*.foreground: #c0caf5
*.background: #24283b
*.cursorColor: #c0caf5
!
! Black
*.color0: #1d202f
*.color8: #414868
!
! Red
*.color1: #f7768e
*.color9: #f7768e
!
! Green
*.color2: #9ece6a
*.color10: #9ece6a
!
! Yellow
*.color3: #e0af68
*.color11: #e0af68
!
! Blue
*.color4: #7aa2f7
*.color12: #7aa2f7
!
! Magenta
*.color5: #bb9af7
*.color13: #bb9af7
!
! Cyan
*.color6: #7dcfff
*.color14: #7dcfff
!
! White
*.color7: #a9b1d6
*.color15: #c0caf5
!
! Bold, Italic, Underline
*.colorBD: #eeeeee
!*.colorIT:
!*.colorUL:

View File

@@ -63,22 +63,24 @@ export abstract class FileTransfer {
} }
export abstract class FileDownload extends FileTransfer { export abstract class FileDownload extends FileTransfer {
abstract write (buffer: Buffer): Promise<void> abstract write (buffer: Uint8Array): Promise<void>
} }
export abstract class FileUpload extends FileTransfer { export abstract class FileUpload extends FileTransfer {
abstract read (): Promise<Buffer> abstract read (): Promise<Uint8Array>
async readAll (): Promise<Buffer> { async readAll (): Promise<Uint8Array> {
const buffers: Buffer[] = [] const result = new Uint8Array(this.getSize())
let pos = 0
while (true) { while (true) {
const buf = await this.read() const buf = await this.read()
if (!buf.length) { if (!buf.length) {
break break
} }
buffers.push(Buffer.from(buf)) result.set(buf, pos)
pos += buf.length
} }
return Buffer.concat(buffers) return result
} }
} }
@@ -261,12 +263,12 @@ export class HTMLFileUpload extends FileUpload {
return this.file.size return this.file.size
} }
async read (): Promise<Buffer> { async read (): Promise<Uint8Array> {
const result: any = await this.reader.read() const result: any = await this.reader.read()
if (result.done || !result.value) { if (result.done || !result.value) {
return Buffer.from('') return new Uint8Array(0)
} }
const chunk = Buffer.from(result.value) const chunk = new Uint8Array(result.value)
this.increaseProgress(chunk.length) this.increaseProgress(chunk.length)
return chunk return chunk
} }

View File

@@ -31,6 +31,8 @@ hotkeys:
__nonStructural: true __nonStructural: true
profile-selectors: profile-selectors:
__nonStructural: true __nonStructural: true
group-selectors:
__nonStructural: true
profiles: [] profiles: []
groups: [] groups: []
profileDefaults: profileDefaults:

View File

@@ -264,6 +264,7 @@ export class AppHotkeyProvider extends HotkeyProvider {
async provide (): Promise<HotkeyDescription[]> { async provide (): Promise<HotkeyDescription[]> {
const profiles = await this.profilesService.getProfiles() const profiles = await this.profilesService.getProfiles()
const groups = await this.profilesService.getProfileGroups()
return [ return [
...this.hotkeys, ...this.hotkeys,
...profiles.map(profile => ({ ...profiles.map(profile => ({
@@ -274,6 +275,10 @@ export class AppHotkeyProvider extends HotkeyProvider {
id: `profile-selectors.${provider.id}`, id: `profile-selectors.${provider.id}`,
name: this.translate.instant('Show {type} profile selector', { type: provider.name }), name: this.translate.instant('Show {type} profile selector', { type: provider.name }),
})), })),
...groups.map(group => ({
id: `group-selectors.${group.id}`,
name: this.translate.instant('Show profile selector for group {name}', { name: group.name }),
})),
] ]
} }

View File

@@ -37,7 +37,7 @@ import { FastHtmlBindDirective } from './directives/fastHtmlBind.directive'
import { DropZoneDirective } from './directives/dropZone.directive' import { DropZoneDirective } from './directives/dropZone.directive'
import { CdkAutoDropGroup } from './directives/cdkAutoDropGroup.directive' import { CdkAutoDropGroup } from './directives/cdkAutoDropGroup.directive'
import { Theme, CLIHandler, TabContextMenuItemProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, QuickConnectProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api' import { Theme, CLIHandler, TabContextMenuItemProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, QuickConnectProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider, PartialProfileGroup, ProfileGroup } from './api'
import { AppService } from './services/app.service' import { AppService } from './services/app.service'
import { ConfigService } from './services/config.service' import { ConfigService } from './services/config.service'
@@ -46,7 +46,7 @@ import { HotkeysService } from './services/hotkeys.service'
import { CustomMissingTranslationHandler, LocaleService } from './services/locale.service' import { CustomMissingTranslationHandler, LocaleService } from './services/locale.service'
import { CommandService } from './services/commands.service' import { CommandService } from './services/commands.service'
import { StandardTheme, StandardCompactTheme, PaperTheme, NewTheme } from './theme' import { NewTheme } from './theme'
import { CoreConfigProvider } from './config' import { CoreConfigProvider } from './config'
import { AppHotkeyProvider } from './hotkeys' import { AppHotkeyProvider } from './hotkeys'
import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu, ProfilesContextMenu } from './tabContextMenu' import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu, ProfilesContextMenu } from './tabContextMenu'
@@ -60,9 +60,6 @@ export function TranslateMessageFormatCompilerFactory (): TranslateMessageFormat
const PROVIDERS = [ const PROVIDERS = [
{ provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true }, { provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true },
{ provide: Theme, useClass: StandardTheme, multi: true },
{ provide: Theme, useClass: StandardCompactTheme, multi: true },
{ provide: Theme, useClass: PaperTheme, multi: true },
{ provide: Theme, useClass: NewTheme, multi: true }, { provide: Theme, useClass: NewTheme, multi: true },
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true }, { provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
{ provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true }, { provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true },
@@ -181,20 +178,24 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
if (profile) { if (profile) {
profilesService.openNewTabForProfile(profile) profilesService.openNewTabForProfile(profile)
} }
} } else if (hotkey.startsWith('profile-selectors.')) {
if (hotkey.startsWith('profile-selectors.')) {
const id = hotkey.substring(hotkey.indexOf('.') + 1) const id = hotkey.substring(hotkey.indexOf('.') + 1)
const provider = profilesService.getProviders().find(x => x.id === id) const provider = profilesService.getProviders().find(x => x.id === id)
if (!provider) { if (!provider) {
return return
} }
this.showSelector(provider).catch(() => null) this.showSelector(provider).catch(() => null)
} } else if (hotkey.startsWith('group-selectors.')) {
if (hotkey === 'command-selector') { const id = hotkey.substring(hotkey.indexOf('.') + 1)
const groups = await this.profilesService.getProfileGroups({ includeProfiles: true })
const group = groups.find(x => x.id === id)
if (!group) {
return
}
this.showGroupSelector(group).catch(() => null)
} else if (hotkey === 'command-selector') {
commands.showSelector().catch(() => null) commands.showSelector().catch(() => null)
} } else if (hotkey === 'profile-selector') {
if (hotkey === 'profile-selector') {
commands.run('core:profile-selector', {}) commands.run('core:profile-selector', {})
} }
}) })
@@ -232,6 +233,21 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
await this.selector.show(this.translate.instant('Select profile'), options) await this.selector.show(this.translate.instant('Select profile'), options)
} }
async showGroupSelector (group: PartialProfileGroup<ProfileGroup>): Promise<void> {
if (this.selector.active) {
return
}
const profiles = group.profiles ?? []
const options: SelectorOption<void>[] = profiles.map(p => ({
...this.profilesService.selectorOptionForProfile(p),
callback: () => this.profilesService.openNewTabForProfile(p),
}))
await this.selector.show(this.translate.instant('Select profile'), options)
}
static forRoot (): ModuleWithProviders<AppModule> { static forRoot (): ModuleWithProviders<AppModule> {
return { return {
ngModule: AppModule, ngModule: AppModule,

View File

@@ -28,7 +28,7 @@ export class HomeBaseService {
} }
openDiscord (): void { openDiscord (): void {
this.platform.openExternal('https://discord.gg/4c5EVTBhtp') this.platform.openExternal('https://discord.gg/Vn7BjmzhtF')
} }
openTranslations (): void { openTranslations (): void {

View File

@@ -487,6 +487,12 @@ export class ProfilesService {
delete profile.group delete profile.group
} }
} }
if (this.config.store.hotkeys['group-selectors'].hasOwnProperty(group.id)) {
const groupSelectorsHotkeys = { ...this.config.store.hotkeys['group-selectors'] }
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete groupSelectorsHotkeys[group.id]
this.config.store.hotkeys['group-selectors'] = groupSelectorsHotkeys
}
} }
/** /**

View File

@@ -23,6 +23,7 @@ export class ThemesService {
) { ) {
this.rootElementStyleBackup = document.documentElement.style.cssText this.rootElementStyleBackup = document.documentElement.style.cssText
this.applyTheme(standardTheme) this.applyTheme(standardTheme)
this.applyThemeVariables()
config.ready$.toPromise().then(() => { config.ready$.toPromise().then(() => {
this.applyCurrentTheme() this.applyCurrentTheme()
this.applyThemeVariables() this.applyThemeVariables()
@@ -37,6 +38,11 @@ export class ThemesService {
}) })
} }
private getConfigStoreOrDefaults (): any {
/// Theme service is active before the vault is unlocked and config is available
return this.config.store ?? this.config.getDefaults()
}
private applyThemeVariables () { private applyThemeVariables () {
if (!this.findCurrentTheme().followsColorScheme) { if (!this.findCurrentTheme().followsColorScheme) {
document.documentElement.style.cssText = this.rootElementStyleBackup document.documentElement.style.cssText = this.rootElementStyleBackup
@@ -60,7 +66,7 @@ export class ThemesService {
} }
let background = Color(theme.background) let background = Color(theme.background)
if (this.config.store?.appearance.vibrancy) { if (this.getConfigStoreOrDefaults().appearance.vibrancy) {
background = background.fade(0.6) background = background.fade(0.6)
} }
// const background = theme.background // const background = theme.background
@@ -148,13 +154,13 @@ export class ThemesService {
vars['--bs-form-switch-bg'] = `url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%27-4 -4 8 8%27%3e%3ccircle r=%273%27 fill=%27${switchBackground}%27/%3e%3c/svg%3e")` vars['--bs-form-switch-bg'] = `url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%27-4 -4 8 8%27%3e%3ccircle r=%273%27 fill=%27${switchBackground}%27/%3e%3c/svg%3e")`
} }
vars['--spaciness'] = this.config.store.appearance.spaciness vars['--spaciness'] = this.getConfigStoreOrDefaults().appearance.spaciness
for (const [bg, fg] of contrastPairs) { for (const [bg, fg] of contrastPairs) {
const colorBg = Color(vars[bg]).hsl() const colorBg = Color(vars[bg]).hsl()
const colorFg = Color(vars[fg]).hsl() const colorFg = Color(vars[fg]).hsl()
const bgContrast = colorBg.contrast(colorFg) const bgContrast = colorBg.contrast(colorFg)
if (bgContrast < this.config.store.terminal.minimumContrastRatio) { if (bgContrast < this.getConfigStoreOrDefaults().terminal.minimumContrastRatio) {
vars[fg] = this.ensureContrast(colorFg, colorBg).string() vars[fg] = this.ensureContrast(colorFg, colorBg).string()
} }
} }
@@ -163,7 +169,7 @@ export class ThemesService {
document.documentElement.style.setProperty(key, value) document.documentElement.style.setProperty(key, value)
} }
document.body.classList.toggle('no-animations', !this.config.store.accessibility.animations) document.body.classList.toggle('no-animations', !this.getConfigStoreOrDefaults().accessibility.animations)
} }
private ensureContrast (color: Color, against: Color): Color { private ensureContrast (color: Color, against: Color): Color {
@@ -178,7 +184,7 @@ export class ThemesService {
while ( while (
(step < 1 && color.color[2] > 1 || (step < 1 && color.color[2] > 1 ||
step > 1 && color.color[2] < 99) && step > 1 && color.color[2] < 99) &&
color.contrast(against) < this.config.store.terminal.minimumContrastRatio) { color.contrast(against) < this.getConfigStoreOrDefaults().terminal.minimumContrastRatio) {
color.color[2] *= step color.color[2] *= step
} }
return color return color
@@ -189,22 +195,22 @@ export class ThemesService {
} }
findCurrentTheme (): Theme { findCurrentTheme (): Theme {
return this.findTheme(this.config.store.appearance.theme) ?? this.standardTheme return this.findTheme(this.getConfigStoreOrDefaults().appearance.theme) ?? this.standardTheme
} }
/// @hidden /// @hidden
_getActiveColorScheme (): any { _getActiveColorScheme (): any {
let theme: PlatformTheme = 'dark' let theme: PlatformTheme = 'dark'
if (this.config.store.appearance.colorSchemeMode === 'light') { if (this.getConfigStoreOrDefaults().appearance.colorSchemeMode === 'light') {
theme = 'light' theme = 'light'
} else if (this.config.store.appearance.colorSchemeMode === 'auto') { } else if (this.getConfigStoreOrDefaults().appearance.colorSchemeMode === 'auto') {
theme = this.platform.getTheme() theme = this.platform.getTheme()
} }
if (theme === 'light') { if (theme === 'light') {
return this.config.store.terminal.lightColorScheme return this.getConfigStoreOrDefaults().terminal.lightColorScheme
} else { } else {
return this.config.store.terminal.colorScheme return this.getConfigStoreOrDefaults().terminal.colorScheme
} }
} }
@@ -215,7 +221,7 @@ export class ThemesService {
document.querySelector('head')!.appendChild(this.styleElement) document.querySelector('head')!.appendChild(this.styleElement)
} }
this.styleElement.textContent = theme.css this.styleElement.textContent = theme.css
document.querySelector('style#custom-css')!.innerHTML = this.config.store?.appearance?.css document.querySelector('style#custom-css')!.innerHTML = this.getConfigStoreOrDefaults().appearance.css
this.themeChanged.next(theme) this.themeChanged.next(theme)
} }

View File

@@ -195,7 +195,13 @@ export class VaultService {
if (!vault) { if (!vault) {
return null return null
} }
return vault.secrets.find(s => s.type === type && this.keyMatches(key, s)) ?? null let vaultSecret = vault.secrets.find(s => s.type === type && this.keyMatches(key, s))
if (!vaultSecret) {
// search for secret without host in vault (like a default user/password used in multiple servers)
key['host'] = null
vaultSecret = vault.secrets.find(s => s.type === type && this.keyMatches(key, s))
}
return vaultSecret ?? null
} }
async addSecret (secret: VaultSecret): Promise<void> { async addSecret (secret: VaultSecret): Promise<void> {
@@ -306,7 +312,7 @@ export class VaultFileProvider extends FileProvider {
id, id,
description: `${description} (${transfer.getName()})`, description: `${description} (${transfer.getName()})`,
}, },
value: (await transfer.readAll()).toString('base64'), value: Buffer.from(await transfer.readAll()).toString('base64'),
}) })
return `${this.prefix}${id}` return `${this.prefix}${id}`
} }

View File

@@ -1,36 +0,0 @@
@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;
}
}
.inset {
width: 70 !important;
}
}
terminaltab .content {
margin: 5px !important;
}
ssh-tab .content {
margin: 5px !important;
}
serial-tab .content {
margin: 5px !important;
}
}

View File

@@ -1,407 +0,0 @@
$black: #002b36;
$base02: #073642;
$base01: #586e75;
$base00: #657b83;
$base0: #839496;
$base1: #93a1a1;
$base2: #eee8d5;
$white: #fdf6e3;
$yellow: #b58900;
$orange: #cb4b16;
$red: #dc322f;
$pink: #d33682;
$purple: #6c71c4;
$blue: #268bd2;
$teal: #2aa198;
$green: #859900;
$tab-border-radius: 5px;
$button-hover-bg: rgba(0, 0, 0, .125);
$button-active-bg: rgba(0, 0, 0, .25);
$primary: #fd7e14;
$secondary: #495057;
$content-bg: rgba($white, 0.65);
$content-bg-solid: $white;
$body-bg: $base2;
$body-bg2: $base1;
$body-color: $black;
$font-family-sans-serif: "Source Sans Pro";
$font-size-base: 14rem / 16;
$btn-border-radius: 0;
$nav-tabs-border-width: 0;
$nav-tabs-border-radius: 0;
$nav-tabs-link-hover-border-color: $body-bg;
$nav-tabs-active-link-hover-color: $white;
$nav-tabs-active-link-hover-bg: $blue;
$nav-tabs-active-link-hover-border-color: darken($blue, 30%);
$nav-pills-border-radius: 0;
$input-bg: $base2;
$input-disabled-bg: $base1;
$input-color: $body-color;
$input-color-placeholder: $base1;
$input-border-color: $base1;
//$input-box-shadow: inset 0 1px 1px rgba($black,.075);
$input-border-radius: 0;
$custom-select-border-radius: 0;
$input-bg-focus: $input-bg;
//$input-border-focus: lighten($brand-primary, 25%);
//$input-box-shadow-focus: $input-box-shadow, rgba($input-border-focus, .6);
$input-color-focus: $input-color;
$input-group-addon-bg: $body-bg;
$input-group-addon-border-color: $input-border-color;
$modal-content-bg: $content-bg-solid;
$modal-content-border-color: $body-bg;
$modal-header-border-color: transparent;
$modal-footer-border-color: transparent;
$popover-bg: $body-bg;
$dropdown-bg: $body-bg;
$dropdown-link-color: $body-color;
$dropdown-link-hover-color: #333;
$dropdown-link-hover-bg: $body-bg2;
//$dropdown-link-active-color: $component-active-color;
//$dropdown-link-active-bg: $component-active-bg;
$dropdown-link-disabled-color: #333;
$dropdown-header-color: #333;
$list-group-color: $body-color;
$list-group-bg: rgba($black,.05);
$list-group-border-color: rgba($black,.1);
$list-group-hover-bg: rgba($black,.1);
$list-group-link-active-bg: rgba($black,.2);
$list-group-action-color: $body-color;
$list-group-action-bg: rgba($black,.05);
$list-group-action-active-bg: $list-group-link-active-bg;
$list-group-border-radius: 0;
$pre-bg: $dropdown-bg;
$pre-color: $dropdown-link-color;
$headings-font-weight: lighter;
$headings-color: $base0;
@import '~bootstrap/scss/bootstrap.scss';
window-controls {
svg {
transition: 0.25s fill;
fill: $base01;
}
button:hover {
background: rgba($black, 0.125);
svg {
fill: $black;
}
}
.btn-close:hover {
background: #8a2828;
}
}
$border-color: $base1;
app-root {
background: $body-bg;
&.vibrant {
background: rgba(255, 255, 255,.4) !important;
}
&> .content {
.tab-bar {
.btn-tab-bar {
background: transparent;
line-height: 42px;
align-items: center;
svg, path {
fill: $black;
fill-opacity: 0.75;
}
&:hover { background: rgba(0, 0, 0, .125) !important; }
&:active { background: rgba(0, 0, 0, .25) !important; }
}
&>.tabs {
tab-header {
border-left: 1px solid transparent;
border-right: 1px solid transparent;
color: $base01;
transition: 0.125s ease-out width;
.index {
color: rgba($black, 0.4);
}
button {
color: $body-color;
border: none;
transition: 0.25s all;
&:hover { background: $button-hover-bg !important; }
&:active { background: $button-active-bg !important; }
}
.progressbar {
background: $blue;
}
.activity-indicator {
background:rgba(0, 0, 0, 0.2);
}
&.active {
color: $black;
background: $content-bg;
border-left: 1px solid $border-color;
border-right: 1px solid $border-color;
}
}
}
}
&.tabs-on-top .tab-bar {
&>.background {
border-bottom: 1px solid $border-color;
}
tab-header {
border-bottom: 1px solid $border-color;
&.active {
border-bottom-color: transparent;
}
}
}
&:not(.tabs-on-top) .tab-bar {
&>.background {
border-top: 1px solid $border-color;
}
tab-header {
border-top: 1px solid $border-color;
&.active {
margin-top: -1px;
}
}
}
}
&.platform-win32, &.platform-linux {
border: 1px solid #111;
&>.content .tab-bar .tabs tab-header:first-child {
border-left: none;
}
}
}
tab-body {
background: $content-bg;
}
settings-tab > .content {
& > .nav {
background: rgba(0, 0, 0, 0.25);
border-right: 1px solid $body-bg;
& > .nav-item > .nav-link {
border: none;
padding: 10px 50px 10px 20px;
font-size: 14px;
&:not(.active) {
color: $body-color;
}
}
}
}
multi-hotkey-input {
.item {
background: $body-bg2;
border: 1px solid $blue;
border-radius: 3px;
margin-right: 5px;
.body {
padding: 3px 0 2px;
.stroke {
padding: 0 6px;
border-right: 1px solid $content-bg;
}
}
.remove {
padding: 3px 8px 2px;
}
}
.item:has(.duplicate) {
background-color: map-get($theme-colors, 'danger');
border: 1px solid map-get($theme-colors, 'danger');
}
.add {
color: #777;
padding: 4px 10px 0;
}
.add, .item .body, .item .remove {
&:hover { background: darken($body-bg2, 5%); }
&:active { background: darken($body-bg2, 15%); }
}
.add:has(.duplicate), .item:has(.duplicate) .body, .item:has(.duplicate) .remove {
&:hover { background: darken(map-get($theme-colors, 'danger'), 5%); }
&:active { background: darken(map-get($theme-colors, 'danger'), 15%); }
}
}
hotkey-input-modal {
.input {
background: $input-bg;
padding: 10px;
font-size: 24px;
line-height: 27px;
height: 55px;
.stroke {
background: $body-bg2;
border: 1px solid $blue;
border-radius: 3px;
margin-right: 10px;
padding: 3px 10px;
}
}
.timeout {
background: $input-bg;
div {
background: $blue;
}
}
}
.mb-3 label {
margin-bottom: 2px;
}
.nav-tabs {
.nav-link {
transition: 0.25s all;
border-bottom-color: $nav-tabs-border-color;
}
}
.btn-check:checked + label {
background: $blue;
}
.btn {
i + * {
margin-left: 5px;
}
&.btn-lg i + * {
margin-left: 10px;
}
}
.input-group-addon + .form-control {
border-left: none;
}
.input-group > select.form-control {
flex-direction: row;
}
.list-group-item {
transition: 0.25s background;
&:not(:first-child) {
border-top: none;
}
i + * {
margin-left: 10px;
}
}
select.form-control {
-webkit-appearance: none;
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='24' height='24' viewBox='0 0 24 24'><path fill='#444' d='M7.406 7.828l4.594 4.594 4.594-4.594 1.406 1.406-6 6-6-6z'></path></svg>");
background-position: 100% 50%;
background-repeat: no-repeat;
padding-right: 30px;
}
checkbox i.on {
color: $blue;
}
toggle {
.body {
border-color: $base0 !important;
.toggle {
background: $base0 !important;
}
}
&.active .body .toggle {
background: map-get($theme-colors, primary) !important;
}
}
.list-group-item svg {
fill: $black;
}
.tabby-title {
color: $base01;
}
.tabby-logo {
filter: saturate(0);
}
start-page footer {
background: $white !important;
}
terminal-toolbar {
background: #ffffff4a !important;
border-bottom: 1px solid #00000026 !important;
}
.bg-dark{
background-color: $base2 !important;
}
split-tab-spanner {
background: rgba(0, 0, 0, .2);
&:hover, &.active {
background: rgba(255, 255, 255, .125);
}
}

View File

@@ -1,428 +0,0 @@
@import "./theme.vars";
// ---------
$button-hover-bg: rgba(0, 0, 0, .25);
$button-active-bg: rgba(0, 0, 0, .5);
@import '~bootstrap/scss/bootstrap.scss';
@import "./theme.vendor.scss";
window-controls {
svg {
transition: 0.25s fill;
fill: #aaa;
}
button:hover svg {
fill: white;
}
.btn-close:hover {
background: #8a2828;
}
}
$border-color: #111;
app-root {
background: $body-bg;
&.vibrant {
background: rgba(0,0,0,.65);
}
&> .content {
.tab-bar {
.btn-tab-bar {
background: transparent;
&:hover { background: rgba(0, 0, 0, .25) !important; }
&:active, &[aria-expanded-true] { background: rgba(0, 0, 0, .5) !important; }
&:focus {
box-shadow: none;
}
&::after {
display: none;
}
}
&>.tabs {
tab-header {
border-left: 1px solid transparent;
border-right: 1px solid transparent;
transition: 0.125s ease-out width;
.index {
color: rgba(255, 255, 255, 0.4);
}
.icon {
opacity: .75;
}
button {
color: $body-color;
border: none;
transition: 0.25s all;
right: 5px;
&:hover { background: $button-active-bg !important; }
&:active { background: $button-active-bg !important; }
}
.progressbar {
background: $green;
}
.activity-indicator {
background:rgba(255, 255, 255, 0.2);
}
&.active {
color: white;
background: $content-bg;
border-left: 1px solid $border-color;
border-right: 1px solid $border-color;
}
}
}
}
&.tabs-on-top .tab-bar {
&>.background {
border-bottom: 1px solid $border-color;
}
tab-header {
border-bottom: 1px solid $border-color;
&.active {
border-bottom-color: transparent;
}
}
}
&:not(.tabs-on-top) .tab-bar {
&>.background {
border-top: 1px solid $border-color;
}
tab-header {
border-top: 1px solid $border-color;
&.active {
margin-top: -1px;
}
}
}
}
&.platform-win32, &.platform-linux {
border: 1px solid #111;
&>.content {
margin: -1px; // expand the content into the border
.tab-bar .tabs tab-header:first-child {
border-left: none;
}
}
}
}
tab-body {
background: $content-bg;
terminal-toolbar .btn, .toolbar-pin-button {
font-weight: bold;
}
}
multi-hotkey-input {
.item {
background: $body-bg2;
border: 1px solid $blue;
border-radius: 3px;
margin-right: 5px;
.body {
padding: 3px 0 2px;
.stroke {
padding: 0 6px;
border-right: 1px solid $content-bg;
}
}
.remove {
padding: 3px 8px 2px;
}
}
.item:has(.duplicate) {
background-color: map-get($theme-colors, 'danger');
border: 1px solid map-get($theme-colors, 'danger');
}
.add {
color: #777;
padding: 4px 10px 0;
}
.add, .item .body, .item .remove {
&:hover { background: darken($body-bg2, 5%); }
&:active { background: darken($body-bg2, 15%); }
}
.add:has(.duplicate), .item:has(.duplicate) .body, .item:has(.duplicate) .remove {
&:hover { background: darken(map-get($theme-colors, 'danger'), 5%); }
&:active { background: darken(map-get($theme-colors, 'danger'), 15%); }
}
}
hotkey-input-modal {
.input {
background: $input-bg;
padding: 10px;
font-size: 24px;
line-height: 27px;
height: 55px;
.stroke {
background: $body-bg2;
border: 1px solid $blue;
border-radius: 3px;
margin-right: 10px;
padding: 3px 10px;
}
}
.timeout {
background: $input-bg;
div {
background: $blue;
}
}
}
.mb-3 label {
margin-bottom: 2px;
}
.btn-check:checked + label {
background: $blue;
}
.btn {
i + * {
margin-left: 5px;
}
&.btn-lg i + * {
margin-left: 10px;
}
}
.input-group-addon + .form-control {
border-left: none;
}
.input-group > select.form-control {
flex-direction: row;
}
.list-group-item {
// transition: 0.0625s background ease;
i + * {
margin-left: 10px;
}
}
.list-group.list-group-flush .list-group-item {
background: transparent;
border: none;
&:not(:last-child) {
border-bottom: none;
}
&.list-group-item-action {
&:hover, &.active {
background: $list-group-hover-bg;
}
}
}
.list-group-light {
.list-group-item {
border: none !important;
outline: none !important;
background: transparent;
border-radius: $border-radius;
margin: 0 !important;
&.list-group-item-action {
&:hover, &.active {
background: $component-active-bg;
color: $component-active-color;
}
}
}
}
checkbox i.on {
color: $blue;
}
.modal .modal-footer {
background: rgba(0, 0, 0, .25);
.btn {
font-weight: bold;
padding: 0.375rem 1.5rem;
}
}
.list-group-item svg {
fill: white;
fill-opacity: 0.75;
}
*::-webkit-scrollbar {
background: rgba(0, 0, 0, .125);
width: 10px;
margin: 5px;
}
*::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, .25);
}
*::-webkit-scrollbar-corner,
*::-webkit-resizer {
opacity: 0;
}
search-panel {
background: #131d27 !important;
input {
border-radius: 0 !important;
}
}
.btn {
cursor: pointer;
justify-content: flex-start;
overflow: hidden;
&.disabled,
&:disabled {
cursor: not-allowed;
}
}
.btn-warning:not(:disabled):not(.disabled) {
&.active, &:active {
color: $gray-900;
}
}
.btn-secondary:not(:disabled):not(.disabled) {
&.active, &:active {
background: #191e23;
align-items: center;
}
}
.btn-link {
text-decoration: none;
&:hover, &[aria-expanded=true], &:active, &.active {
color: $link-hover-color;
border-radius: $btn-border-radius;
}
&[aria-expanded=true], &:active, &.active {
background: rgba(255, 255, 255, 0.1);
}
}
.btn-group .btn.active {
border-color: transparent !important;
}
.nav-tabs {
margin-bottom: 10px;
&.nav-justified .nav-link {
margin-right: 5px;
}
.nav-link {
border: none;
border-bottom: $nav-tabs-border-width solid transparent;
text-transform: uppercase;
font-weight: bold;
padding: 5px 0;
margin-right: 20px;
uib-tab-heading > i {
font-size: 18px;
}
// @include hover-focus {
// color: $nav-tabs-link-active-color;
// }
&.disabled {
color: $nav-link-disabled-color;
border-color: transparent;
}
}
.nav-item:last-child .nav-link {
margin-right: 0;
}
.nav-link.active,
.nav-item.show .nav-link {
color: $nav-tabs-link-active-color;
border-color: $nav-tabs-link-active-border-color;
}
}
hr {
border-color: $list-group-border-color;
}
.dropdown-menu {
box-shadow: $dropdown-box-shadow;
}
ngx-colors-panel .opened {
background: $body-bg !important;
button {
color: $body-color !important;
}
.button svg {
fill: white;
}
}
split-tab-spanner {
background: rgba(0, 0, 0, .2);
&:hover, &.active {
background: rgba(255, 255, 255, .125);
}
}

View File

@@ -2,32 +2,6 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Theme } from './api' import { Theme } from './api'
/** @hidden */
@Injectable()
export class StandardTheme extends Theme {
name = _('Standard (legacy)')
css = require('./theme.scss')
terminalBackground = '#222a33'
}
/** @hidden */
@Injectable()
export class StandardCompactTheme extends Theme {
name = _('Compact (legacy)')
css = require('./theme.compact.scss')
terminalBackground = '#222a33'
macOSWindowButtonsInsetX = 8
macOSWindowButtonsInsetY = 6
}
/** @hidden */
@Injectable()
export class PaperTheme extends Theme {
name = _('Paper (legacy)')
css = require('./theme.paper.scss')
terminalBackground = '#f7f1e0'
}
/** @hidden */ /** @hidden */
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class NewTheme extends Theme { export class NewTheme extends Theme {

View File

@@ -24,6 +24,7 @@
"devDependencies": { "devDependencies": {
"electron-promise-ipc": "^2.2.4", "electron-promise-ipc": "^2.2.4",
"ps-node": "^0.1.6", "ps-node": "^0.1.6",
"ssh-config": "^5.0.0",
"tmp-promise": "^3.0.2", "tmp-promise": "^3.0.2",
"which": "^3.0.0", "which": "^3.0.0",
"winston": "^3.3.3" "winston": "^3.3.3"

View File

@@ -1,6 +1,6 @@
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { PlatformService, LogService, UpdaterService, DockingService, HostAppService, ThemesService, Platform, AppService, ConfigService, WIN_BUILD_FLUENT_BG_SUPPORTED, isWindowsBuild, HostWindowService, HotkeyProvider, ConfigProvider, FileProvider } from 'tabby-core' import { PlatformService, LogService, UpdaterService, DockingService, HostAppService, ThemesService, Platform, AppService, ConfigService, WIN_BUILD_FLUENT_BG_SUPPORTED, isWindowsBuild, HostWindowService, HotkeyProvider, ConfigProvider, FileProvider } from 'tabby-core'
import { TerminalColorSchemeProvider } from 'tabby-terminal' import { TerminalColorSchemeProvider, TerminalDecorator } from 'tabby-terminal'
import { SFTPContextMenuItemProvider, SSHProfileImporter, AutoPrivateKeyLocator } from 'tabby-ssh' import { SFTPContextMenuItemProvider, SSHProfileImporter, AutoPrivateKeyLocator } from 'tabby-ssh'
import { PTYInterface, ShellProvider, UACService } from 'tabby-local' import { PTYInterface, ShellProvider, UACService } from 'tabby-local'
import { auditTime } from 'rxjs' import { auditTime } from 'rxjs'
@@ -23,6 +23,7 @@ import { ElectronConfigProvider } from './config'
import { EditSFTPContextMenu } from './sftpContextMenu' import { EditSFTPContextMenu } from './sftpContextMenu'
import { OpenSSHImporter, PrivateKeyLocator, StaticFileImporter } from './sshImporters' import { OpenSSHImporter, PrivateKeyLocator, StaticFileImporter } from './sshImporters'
import { ElectronPTYInterface } from './pty' import { ElectronPTYInterface } from './pty'
import { PathDropDecorator } from './pathDrop'
import { CmderShellProvider } from './shells/cmder' import { CmderShellProvider } from './shells/cmder'
import { Cygwin32ShellProvider } from './shells/cygwin32' import { Cygwin32ShellProvider } from './shells/cygwin32'
@@ -73,6 +74,8 @@ import { VSDevToolsProvider } from './shells/vs'
{ provide: PTYInterface, useClass: ElectronPTYInterface }, { provide: PTYInterface, useClass: ElectronPTYInterface },
{ provide: TerminalDecorator, useClass: PathDropDecorator, multi: true },
// For WindowsDefaultShellProvider // For WindowsDefaultShellProvider
PowerShellCoreShellProvider, PowerShellCoreShellProvider,
WSLShellProvider, WSLShellProvider,
@@ -130,7 +133,10 @@ export default class ElectronModule {
}) })
}) })
config.changed$.subscribe(() => this.updateVibrancy()) config.changed$.subscribe(() => {
this.updateVibrancy()
this.updateDarkMode()
})
config.changed$.subscribe(() => this.updateWindowControlsColor()) config.changed$.subscribe(() => this.updateWindowControlsColor())
@@ -173,6 +179,11 @@ export default class ElectronModule {
this.hostWindow.setOpacity(this.config.store.appearance.opacity) this.hostWindow.setOpacity(this.config.store.appearance.opacity)
} }
private updateDarkMode () {
const colorSchemeMode = this.config.store.appearance.colorSchemeMode
this.electron.ipcRenderer.send('window-set-dark-mode', colorSchemeMode)
}
private updateWindowControlsColor () { private updateWindowControlsColor () {
// if windows and not using native frame, WCO does not exist, return. // if windows and not using native frame, WCO does not exist, return.
if (this.hostApp.platform === Platform.Windows && this.config.store.appearance.frame === 'native') { if (this.hostApp.platform === Platform.Windows && this.config.store.appearance.frame === 'native') {

View File

@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { TerminalDecorator } from '../api/decorator' import { TerminalDecorator, BaseTerminalTabComponent } from 'tabby-terminal'
import { BaseTerminalTabComponent } from '../api/baseTerminalTab.component' import { webUtils } from 'electron'
/** @hidden */ /** @hidden */
@Injectable() @Injectable()
@@ -11,8 +11,8 @@ export class PathDropDecorator extends TerminalDecorator {
event.preventDefault() event.preventDefault()
})) }))
this.subscribeUntilDetached(terminal, terminal.frontend?.drop$.subscribe((event: DragEvent) => { this.subscribeUntilDetached(terminal, terminal.frontend?.drop$.subscribe((event: DragEvent) => {
for (const file of event.dataTransfer!.files as any) { for (const file of event.dataTransfer!.files as unknown as Iterable<File>) {
this.injectPath(terminal, file.path) this.injectPath(terminal, webUtils.getPathForFile(file))
} }
event.preventDefault() event.preventDefault()
})) }))

View File

@@ -10,7 +10,7 @@ try {
} catch { } } catch { }
try { try {
var windowsProcessTree = require('windows-process-tree') // eslint-disable-line @typescript-eslint/no-var-requires, no-var var windowsProcessTree = require('@tabby-gang/windows-process-tree') // eslint-disable-line @typescript-eslint/no-var-requires, no-var
} catch { } } catch { }
export class ElectronPTYInterface extends PTYInterface { export class ElectronPTYInterface extends PTYInterface {

View File

@@ -18,7 +18,7 @@ const fontManager = require('fontmanager-redux') // eslint-disable-line
try { try {
// eslint-disable-next-line no-var // eslint-disable-next-line no-var
var windowsProcessTreeNative = require('windows-process-tree/build/Release/windows_process_tree.node') var windowsProcessTreeNative = require('@tabby-gang/windows-process-tree/build/Release/windows_process_tree.node')
// eslint-disable-next-line no-var // eslint-disable-next-line no-var
var wnr = require('windows-native-registry') var wnr = require('windows-native-registry')
} catch { } } catch { }
@@ -300,12 +300,12 @@ class ElectronFileUpload extends FileUpload {
private size: number private size: number
private mode: number private mode: number
private file: fs.FileHandle private file: fs.FileHandle
private buffer: Buffer private buffer: Uint8Array
private powerSaveBlocker = 0 private powerSaveBlocker = 0
constructor (private filePath: string, private electron: ElectronService) { constructor (private filePath: string, private electron: ElectronService) {
super() super()
this.buffer = Buffer.alloc(256 * 1024) this.buffer = new Uint8Array(256 * 1024)
this.powerSaveBlocker = electron.powerSaveBlocker.start('prevent-app-suspension') this.powerSaveBlocker = electron.powerSaveBlocker.start('prevent-app-suspension')
} }
@@ -328,7 +328,7 @@ class ElectronFileUpload extends FileUpload {
return this.size return this.size
} }
async read (): Promise<Buffer> { async read (): Promise<Uint8Array> {
const result = await this.file.read(this.buffer, 0, this.buffer.length, null) const result = await this.file.read(this.buffer, 0, this.buffer.length, null)
this.increaseProgress(result.bytesRead) this.increaseProgress(result.bytesRead)
return this.buffer.slice(0, result.bytesRead) return this.buffer.slice(0, result.bytesRead)
@@ -370,7 +370,7 @@ class ElectronFileDownload extends FileDownload {
return this.size return this.size
} }
async write (buffer: Buffer): Promise<void> { async write (buffer: Uint8Array): Promise<void> {
let pos = 0 let pos = 0
while (pos < buffer.length) { while (pos < buffer.length) {
const result = await this.file.write(buffer, pos, buffer.length - pos, null) const result = await this.file.write(buffer, pos, buffer.length - pos, null)

View File

@@ -49,19 +49,24 @@ export class EditSFTPContextMenu extends SFTPContextMenuItemProvider {
this.platform.openPath(tempPath) this.platform.openPath(tempPath)
const events = new Subject<string>() const events = new Subject<string>()
const watcher = fs.watch(tempPath, event => events.next(event)) fs.chmodSync(tempPath, 0o700)
events.pipe(debounceTime(1000), debounce(async event => {
if (event === 'rename') { // skip the first burst of events
watcher.close() setTimeout(() => {
} const watcher = fs.watch(tempPath, event => events.next(event))
const upload = await this.platform.startUpload({ multiple: false }, [tempPath]) events.pipe(debounceTime(1000), debounce(async event => {
if (!upload.length) { if (event === 'rename') {
return watcher.close()
} }
await sftp.upload(item.fullPath, upload[0]) const upload = await this.platform.startUpload({ multiple: false }, [tempPath])
await sftp.chmod(item.fullPath, item.mode) if (!upload.length) {
})).subscribe() return
watcher.on('close', () => events.complete()) }
sftp.closed$.subscribe(() => watcher.close()) await sftp.upload(item.fullPath, upload[0])
await sftp.chmod(item.fullPath, item.mode)
})).subscribe()
watcher.on('close', () => events.complete())
sftp.closed$.subscribe(() => watcher.close())
}, 1000)
} }
} }

View File

@@ -1,130 +1,346 @@
import at from 'core-js-pure/actual/array/at'
import * as fs from 'fs/promises' import * as fs from 'fs/promises'
import * as fsSync from 'fs' import * as fsSync from 'fs'
import * as path from 'path' import * as path from 'path'
import * as glob from 'glob'
import slugify from 'slugify' import slugify from 'slugify'
import * as yaml from 'js-yaml' import * as yaml from 'js-yaml'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { PartialProfile } from 'tabby-core' import { PartialProfile } from 'tabby-core'
import { SSHProfileImporter, PortForwardType, SSHProfile, SSHProfileOptions, AutoPrivateKeyLocator } from 'tabby-ssh' import {
SSHProfileImporter,
PortForwardType,
SSHProfile,
AutoPrivateKeyLocator,
ForwardedPortConfig,
} from 'tabby-ssh'
import { ElectronService } from './services/electron.service' import { ElectronService } from './services/electron.service'
import SSHConfig, { Directive, LineType } from 'ssh-config'
// Enum to delineate the properties in SSHProfile options
enum SSHProfilePropertyNames {
Host = 'host',
Port = 'port',
User = 'user',
X11 = 'x11',
PrivateKeys = 'privateKeys',
KeepaliveInterval = 'keepaliveInterval',
KeepaliveCountMax = 'keepaliveCountMax',
ReadyTimeout = 'readyTimeout',
JumpHost = 'jumpHost',
AgentForward = 'agentForward',
ProxyCommand = 'proxyCommand',
ForwardedPorts = 'forwardedPorts',
}
// Data structure to map the (lowercase) ssh-config attributes (as keys) to a tuple
// containing the name of the corresponding SSHProfile attribute
const decodeFields: Record<string, SSHProfilePropertyNames> = {
hostname: SSHProfilePropertyNames.Host,
user: SSHProfilePropertyNames.User,
port: SSHProfilePropertyNames.Port,
forwardx11: SSHProfilePropertyNames.X11,
serveraliveinterval: SSHProfilePropertyNames.KeepaliveInterval,
serveralivecountmax: SSHProfilePropertyNames.KeepaliveCountMax,
connecttimeout: SSHProfilePropertyNames.ReadyTimeout,
proxyjump: SSHProfilePropertyNames.JumpHost,
forwardagent: SSHProfilePropertyNames.AgentForward,
identityfile: SSHProfilePropertyNames.PrivateKeys,
proxycommand: SSHProfilePropertyNames.ProxyCommand,
localforward: SSHProfilePropertyNames.ForwardedPorts,
remoteforward: SSHProfilePropertyNames.ForwardedPorts,
dynamicforward: SSHProfilePropertyNames.ForwardedPorts,
}
// Function to use the above to return details corresponding to the supplied SSHProperty name.
// If the name of the supplied SSH Config file Property is valid, and one that we process,
// then we get back the name of the corresponding Property in the SSHProfile object
function decodeTarget (SSHProperty: string): string {
const lower = SSHProperty.toLowerCase()
if (lower in decodeFields) {
return decodeFields[lower]
}
return ''
}
// Function to combine SSHConfig values into a single string. This is used to smash
// together the proxyCommand values which are split on whitespace and presented as
// an array of objects in the SSHConfig object
function convertSSHConfigValuesToString (arg: string | string[] | object[]): string {
if (typeof arg === 'string') { return arg }
let allStrings = true
for (const item of arg) {
if (typeof item !== 'string') {
allStrings = false
break
}
}
if (allStrings) {
return arg.join(' ')
}
// Have to explicitly unwrap the arg into a list of objects to avoid Typescript grumbles
const objList: object[] = []
for (const item of arg) {
if ( typeof item === 'object' && 'val' in item ) {
objList.push(item)
}
}
return objList.filter(obj => 'val' in obj)
.map(obj => 'val' in obj ? obj.val as string: '')
.join(' ')
}
// Function to read in the SSH config file recursively and parse any Include directives
async function parseSSHConfigFile (
filePath: string,
visited = new Set<string>(),
): Promise<SSHConfig> {
// If we've already processed this file, return an empty config to avoid infinite recursion
if (visited.has(filePath)) {
return SSHConfig.parse('')
}
visited.add(filePath)
let raw = ''
try {
raw = await fs.readFile(filePath, 'utf8')
} catch (err) {
console.error(`Error reading SSH config file: ${filePath}`, err)
return SSHConfig.parse('')
}
const parsed = SSHConfig.parse(raw)
const merged = SSHConfig.parse('')
for (const entry of parsed) {
if (entry.type === LineType.DIRECTIVE && entry.param.toLowerCase() === 'include') {
const directive = entry as Directive
if (typeof directive.value !== 'string') {
continue
}
// ssh_config(5) says "Files without absolute paths are assumed to be in ~/.ssh if included in a user configuration file or /etc/ssh if included from the system configuration file."
let incPath = ''
if (path.isAbsolute(directive.value)) {
incPath = directive.value
} else if (directive.value.startsWith('~')) {
incPath = path.join(process.env.HOME ?? '~', directive.value.slice(1))
} else {
incPath = path.join(process.env.HOME ?? '~', '.ssh', directive.value)
}
const matches = glob.sync(incPath)
for (const match of matches) {
const stat = await fs.stat(match)
if (stat.isDirectory()) {
continue
}
const matchedConfig = await parseSSHConfigFile(match, visited)
merged.push(...matchedConfig)
}
} else {
merged.push(entry)
}
}
return merged
}
// Function to take an ssh-config entry and convert it into an SSHProfile
function convertHostToSSHProfile (host: string, settings: Record<string, string | string[] | object[] >): PartialProfile<SSHProfile> {
// inline function to generate an id for this profile
const deriveID = (name: string) => 'openssh-config:' + slugify(name)
// Start point of the profile, with an ID, name, type and group
const thisProfile: PartialProfile<SSHProfile> = {
id: deriveID(host),
name: `${host} (.ssh/config)`,
type: 'ssh',
group: 'Imported from .ssh/config',
}
const options = {}
function convertToForwardedPortDescriptor (forwardType: PortForwardType.Local | PortForwardType.Remote | PortForwardType.Dynamic, details: string): ForwardedPortConfig {
const detailsParts = details.split(/\s/)
const bindParts = detailsParts[0].trim().split(':')
if (bindParts.length === 1) {
bindParts.unshift('127.0.0.1')
}
let tgtParts = ['', '22']
if ( detailsParts.length > 1 ) {
tgtParts = detailsParts[1].trim().split(':')
}
return {
host: bindParts[0],
port: parseInt(bindParts[1]),
targetAddress: tgtParts[0],
targetPort: parseInt(tgtParts[1]),
type: forwardType,
description: details,
}
}
// for each ssh-config key in turn...
for (const key in settings) {
// decode a target attribute and an action
const targetName = decodeTarget(key)
switch (targetName) {
// The following have single string values
case SSHProfilePropertyNames.User:
case SSHProfilePropertyNames.Host:
case SSHProfilePropertyNames.JumpHost:
const basicString = settings[key]
if (typeof basicString === 'string') {
if (targetName === SSHProfilePropertyNames.JumpHost) {
options[targetName] = deriveID(basicString)
} else {
options[targetName] = basicString
}
} else {
console.log('Unexpected value in settings for ' + key)
}
break
// The following have single integer values
case SSHProfilePropertyNames.Port:
case SSHProfilePropertyNames.KeepaliveInterval:
case SSHProfilePropertyNames.KeepaliveCountMax:
case SSHProfilePropertyNames.ReadyTimeout:
const numberString = settings[key]
if (typeof numberString === 'string') {
options[targetName] = parseInt(numberString, 10)
} else {
console.log('Unexpected value in settings for ' + key)
}
break
// The following have single yes/no values
case SSHProfilePropertyNames.X11:
case SSHProfilePropertyNames.AgentForward:
let booleanString = settings[key]
booleanString = typeof booleanString === 'string' ? booleanString.toLowerCase() : ''
if ( booleanString === 'yes' || booleanString === 'no' ) {
options[targetName] = booleanString === 'yes'
} else {
console.log('Unexpected value in settings for ' + key)
}
break
// ProxyCommand will be an array if unquoted and containing multiple words,
// or a simple string otherwise
case SSHProfilePropertyNames.ProxyCommand:
const proxyCommand = convertSSHConfigValuesToString(settings[key])
options[targetName] = proxyCommand
break
// IdentityFile may have multiple values and the need to have '~' converted to the
// path to the HOME directory
case SSHProfilePropertyNames.PrivateKeys:
const processedKeys: string [] = (settings[key] as string[]).map( s => {
let retVal: string = s
if (s.startsWith('~/')) {
retVal = path.join(process.env.HOME ?? '~', s.slice(2))
}
return retVal
})
options[targetName] = processedKeys
break
// The port forwarding directives all end up in the same space, but with a different value
// in the SSHProfileOptions object
case SSHProfilePropertyNames.ForwardedPorts:
const forwardTypeString = key.toLowerCase()
let forwardType: PortForwardType | null = null
switch (forwardTypeString) {
case 'localforward':
forwardType = PortForwardType.Local
break
case 'remoteforward':
forwardType = PortForwardType.Remote
break
case 'dynamicforward':
forwardType = PortForwardType.Dynamic
break
}
if (forwardType) {
options[targetName] ??= []
for (const forwarderDetails of settings[key]) {
if (typeof forwarderDetails === 'string') {
options[targetName].push(convertToForwardedPortDescriptor(forwardType, forwarderDetails))
}
}
}
break
}
}
thisProfile.options = options
return thisProfile
}
function convertToSSHProfiles (config: SSHConfig): PartialProfile<SSHProfile>[] {
const myMap = new Map<string, PartialProfile<SSHProfile>>()
function noWildCardsInName (name: string) {
return !/[?*]/.test(name)
}
for (const entry of config) {
// Each entry represents a line in the SSH Config. If the line is a 'Host' line,
// then it will also contain the configuration for that identifiable Host.
// There may be more than one host per line and some 'Hosts' have wildcards in their
// names
// If this is a genuine entry rather than a Comment...
// ... and there is a 'Host' Parameter
if (entry.type === LineType.DIRECTIVE && entry.param === 'Host') {
// for each Name in this entry
const hostList: string[] = []
// if there is more than one host specified on this line, then the names will be
// in an array
if (typeof entry.value === 'string') {
hostList.push(entry.value)
} else if (Array.isArray(entry.value)) {
for (const item of entry.value) {
hostList.push(item.val)
}
}
// for each Host identified on this line, check that there are no wildcards in the
// name and that we've not seen the name before.
// If that is the case, then get the full configuration for this name.
// If that has a 'Hostname' property (if that's missing, the name is not usable
// for our purposes) then convert the configuration into an SSHProfile and stash it
for (const host of hostList) {
if (noWildCardsInName(host)) {
if (!(host in myMap)) {
// NOTE: SSHConfig.compute() lies about the return types
const configuration: Record<string, string | string[] | object[]> = config.compute(host)
if (Object.keys(configuration).map(key => key.toLowerCase()).includes('hostname')) {
myMap[host] = convertHostToSSHProfile(host, configuration)
}
}
}
}
}
}
// Convert the values from the map into a list of Partial SSHProfiles sorted
// by Hostname
return Object.keys(myMap).sort().map(key => myMap[key])
}
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class OpenSSHImporter extends SSHProfileImporter { export class OpenSSHImporter extends SSHProfileImporter {
async getProfiles (): Promise<PartialProfile<SSHProfile>[]> { async getProfiles (): Promise<PartialProfile<SSHProfile>[]> {
const deriveID = name => 'openssh-config:' + slugify(name)
const results: PartialProfile<SSHProfile>[] = []
const configPath = path.join(process.env.HOME ?? '~', '.ssh', 'config') const configPath = path.join(process.env.HOME ?? '~', '.ssh', 'config')
try {
const lines = (await fs.readFile(configPath, 'utf8')).split('\n')
const globalOptions: Partial<SSHProfileOptions> = {}
let currentProfile: PartialProfile<SSHProfile>|null = null
for (let line of lines) {
if (line.trim().startsWith('#') || !line.trim()) {
continue
}
if (line.toLowerCase().startsWith('host ')) {
if (currentProfile) {
results.push(currentProfile)
}
const name = line.substr(5).trim()
currentProfile = {
id: deriveID(name),
name: `${name} (.ssh/config)`,
type: 'ssh',
group: 'Imported from .ssh/config',
options: {
...globalOptions,
host: name,
},
}
} else {
const target: Partial<SSHProfileOptions> = currentProfile?.options ?? globalOptions
line = line.trim()
const idx = /\s/.exec(line)?.index ?? -1
if (idx === -1) {
continue
}
const key = line.substr(0, idx).trim()
const value = line.substr(idx + 1).trim()
if (key === 'IdentityFile') { try {
target.privateKeys = value.split(',').map(s => s.trim()).map(s => { const config: SSHConfig = await parseSSHConfigFile(configPath)
if (s.startsWith('~')) { return convertToSSHProfiles(config)
s = path.join(process.env.HOME ?? '~', s.slice(2))
}
return s
})
} else if (key === 'RemoteForward') {
const bind = value.split(/\s/)[0].trim()
const tgt = value.split(/\s/)[1].trim()
target.forwardedPorts ??= []
target.forwardedPorts.push({
type: PortForwardType.Remote,
description: value,
host: bind.split(':')[0] ?? '127.0.0.1',
port: parseInt(bind.split(':')[1] ?? bind),
targetAddress: tgt.split(':')[0],
targetPort: parseInt(tgt.split(':')[1]),
})
} else if (key === 'LocalForward') {
const bind = value.split(/\s/)[0].trim()
const tgt = value.split(/\s/)[1].trim()
target.forwardedPorts ??= []
target.forwardedPorts.push({
type: PortForwardType.Local,
description: value,
host: bind.includes(':') ? bind.split(':')[0] : '127.0.0.1',
port: parseInt(at(bind.split(':'), -1)),
targetAddress: tgt.split(':')[0],
targetPort: parseInt(tgt.split(':')[1]),
})
} else if (key === 'DynamicForward') {
const bind = value.trim()
target.forwardedPorts ??= []
target.forwardedPorts.push({
type: PortForwardType.Dynamic,
description: value,
host: bind.includes(':') ? bind.split(':')[0] : '127.0.0.1',
port: parseInt(at(bind.split(':'), -1)),
targetAddress: '',
targetPort: 22,
})
} else {
const mappedKey = {
hostname: 'host',
host: 'host',
port: 'port',
user: 'user',
forwardx11: 'x11',
serveraliveinterval: 'keepaliveInterval',
serveralivecountmax: 'keepaliveCountMax',
proxycommand: 'proxyCommand',
proxyjump: 'jumpHost',
}[key.toLowerCase()]
if (mappedKey) {
target[mappedKey] = value
}
}
}
}
if (currentProfile) {
results.push(currentProfile)
}
for (const p of results) {
if (p.options?.proxyCommand) {
p.options.proxyCommand = p.options.proxyCommand
.replace('%h', p.options.host ?? '')
.replace('%p', (p.options.port ?? 22).toString())
}
if (p.options?.jumpHost) {
p.options.jumpHost = deriveID(p.options.jumpHost)
}
}
return results
} catch (e) { } catch (e) {
if (e.code === 'ENOENT') { if (e.code === 'ENOENT') {
return [] return []

View File

@@ -413,6 +413,11 @@ simple-swizzle@^0.2.2:
dependencies: dependencies:
is-arrayish "^0.3.1" is-arrayish "^0.3.1"
ssh-config@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/ssh-config/-/ssh-config-5.0.1.tgz#44ee7db10d3340c79780afd142af05cf641408b9"
integrity sha512-Bh9CRGFq7pLpWFPmLOyirzYhbpme8FXZe3lZckWvmABdcIEiGB8tNbmEEZdppnr6EiQ0WcGTMoYDp8Tjomq9gw==
stack-trace@0.0.x: stack-trace@0.0.x:
version "0.0.10" version "0.0.10"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"

View File

@@ -1,27 +1,38 @@
command-line-editor([model]='profile.options') ul.nav-tabs(ngbNav, #nav='ngbNav')
li(ngbNavItem)
a(ngbNavLink, translate) General
ng-template(ngbNavContent)
command-line-editor([model]='profile.options')
.form-line(*ngIf='uac?.isAvailable') .form-line(*ngIf='uac?.isAvailable')
.header .header
.title(translate) Run as administrator .title(translate) Run as administrator
toggle( toggle(
[(ngModel)]='profile.options.runAsAdministrator', [(ngModel)]='profile.options.runAsAdministrator',
) )
.mb-3 .mb-3
label(translate) Working directory label(translate) Working directory
.input-group .input-group
input.form-control( input.form-control(
type='text', type='text',
placeholder='Home directory', placeholder='Home directory',
[(ngModel)]='profile.options.cwd' [(ngModel)]='profile.options.cwd'
) )
button.btn.btn-secondary((click)='pickWorkingDirectory()') button.btn.btn-secondary((click)='pickWorkingDirectory()')
i.fas.fa-folder-open i.fas.fa-folder-open
.mb-3 .mb-3
label(translate) Environment label(translate) Environment
environment-editor( environment-editor(
type='text', type='text',
[(model)]='profile.options.env', [(model)]='profile.options.env',
) )
li(ngbNavItem)
a(ngbNavLink, translate) Colors
ng-template(ngbNavContent)
color-scheme-selector([(model)]='profile.terminalColorScheme')
div([ngbNavOutlet]='nav')

View File

@@ -123,7 +123,7 @@ export class VaultSettingsTabComponent extends BaseComponent {
} }
await this.vault.updateSecret(secret, { await this.vault.updateSecret(secret, {
...secret, ...secret,
value: (await transfers[0].readAll()).toString('base64'), value: Buffer.from(await transfers[0].readAll()).toString('base64'),
}) })
this.loadVault() this.loadVault()
} }

View File

@@ -1,6 +1,6 @@
h3.mb-3(translate) Window h3.mb-3(translate) Window
.form-line .form-line(*ngIf='themes.length > 1')
.header .header
.title(translate) Theme .title(translate) Theme
select.form-control( select.form-control(

View File

@@ -11,22 +11,17 @@
"build": "webpack --progress --color", "build": "webpack --progress --color",
"watch": "webpack --progress --color --watch", "watch": "webpack --progress --color --watch",
"postinstall": "run-script-os", "postinstall": "run-script-os",
"postinstall:darwin:linux": "exit", "postinstall:darwin:linux": "exit"
"postinstall:win32": "xcopy /i /y ..\\node_modules\\ssh2\\util\\pagent.exe util\\"
}, },
"files": [ "files": [
"dist", "dist",
"util/pagent.exe",
"typings" "typings"
], ],
"author": "Eugene Pankov", "author": "Eugene Pankov",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/node": "20.3.1", "@types/node": "20.3.1",
"@types/ssh2": "^0.5.46",
"ansi-colors": "^4.1.1", "ansi-colors": "^4.1.1",
"diffie-hellman": "^5.0.3",
"sshpk": "Eugeny/node-sshpk#c2b71d1243714d2daf0988f84c3323d180817136",
"strip-ansi": "^7.0.0" "strip-ansi": "^7.0.0"
}, },
"dependencies": { "dependencies": {
@@ -45,5 +40,8 @@
"tabby-core": "*", "tabby-core": "*",
"tabby-settings": "*", "tabby-settings": "*",
"tabby-terminal": "*" "tabby-terminal": "*"
},
"resolutions": {
"glob": "7.2.3"
} }
} }

View File

@@ -1,20 +1,45 @@
import * as ALGORITHMS from 'ssh2/lib/protocol/constants' import * as russh from 'russh'
import { ALGORITHM_BLACKLIST, SSHAlgorithmType } from './api' import { SSHAlgorithmType } from './api'
// Counteracts https://github.com/mscdex/ssh2/commit/f1b5ac3c81734c194740016eab79a699efae83d8 export const supportedAlgorithms = {
ALGORITHMS.DEFAULT_CIPHER.push('aes128-gcm') [SSHAlgorithmType.KEX]: russh.getSupportedKexAlgorithms().filter(x => x !== 'none'),
ALGORITHMS.DEFAULT_CIPHER.push('aes256-gcm') [SSHAlgorithmType.HOSTKEY]: russh.getSupportedKeyTypes().filter(x => x !== 'none'),
ALGORITHMS.SUPPORTED_CIPHER.push('aes128-gcm') [SSHAlgorithmType.CIPHER]: russh.getSupportedCiphers().filter(x => x !== 'clear'),
ALGORITHMS.SUPPORTED_CIPHER.push('aes256-gcm') [SSHAlgorithmType.HMAC]: russh.getSupportedMACs().filter(x => x !== 'none'),
}
export const supportedAlgorithms: Record<string, string> = {}
export const defaultAlgorithms = {
for (const k of Object.values(SSHAlgorithmType)) { [SSHAlgorithmType.KEX]: [
const supportedAlg = { 'curve25519-sha256',
[SSHAlgorithmType.KEX]: 'SUPPORTED_KEX', 'curve25519-sha256@libssh.org',
[SSHAlgorithmType.HOSTKEY]: 'SUPPORTED_SERVER_HOST_KEY', 'diffie-hellman-group16-sha512',
[SSHAlgorithmType.CIPHER]: 'SUPPORTED_CIPHER', 'diffie-hellman-group14-sha256',
[SSHAlgorithmType.HMAC]: 'SUPPORTED_MAC', 'ext-info-c',
}[k] 'ext-info-s',
supportedAlgorithms[k] = ALGORITHMS[supportedAlg].filter(x => !ALGORITHM_BLACKLIST.includes(x)).sort() 'kex-strict-c-v00@openssh.com',
'kex-strict-s-v00@openssh.com',
],
[SSHAlgorithmType.HOSTKEY]: [
'ssh-ed25519',
'ecdsa-sha2-nistp256',
'ecdsa-sha2-nistp521',
'rsa-sha2-256',
'rsa-sha2-512',
'ssh-rsa',
],
[SSHAlgorithmType.CIPHER]: [
'chacha20-poly1305@openssh.com',
'aes256-gcm@openssh.com',
'aes256-ctr',
'aes192-ctr',
'aes128-ctr',
],
[SSHAlgorithmType.HMAC]: [
'hmac-sha2-512-etm@openssh.com',
'hmac-sha2-256-etm@openssh.com',
'hmac-sha2-512',
'hmac-sha2-256',
'hmac-sha1-etm@openssh.com',
'hmac-sha1',
],
} }

View File

@@ -1,5 +1,4 @@
export * from './contextMenu' export * from './contextMenu'
export * from './interfaces' export * from './interfaces'
export * from './importer' export * from './importer'
export * from './proxyStream'
export { SSHMultiplexerService } from '../services/sshMultiplexer.service' export { SSHMultiplexerService } from '../services/sshMultiplexer.service'

View File

@@ -51,13 +51,3 @@ export interface ForwardedPortConfig {
targetPort: number targetPort: number
description: string description: string
} }
export let ALGORITHM_BLACKLIST = [
// cause native crashes in node crypto, use EC instead
'diffie-hellman-group-exchange-sha256',
'diffie-hellman-group-exchange-sha1',
]
if (!process.env.TABBY_ENABLE_SSH_ALG_BLACKLIST) {
ALGORITHM_BLACKLIST = []
}

View File

@@ -1,61 +0,0 @@
import { Observable, Subject } from 'rxjs'
import { Duplex } from 'stream'
export class SSHProxyStreamSocket extends Duplex {
constructor (private parent: SSHProxyStream) {
super({
allowHalfOpen: false,
})
}
_read (size: number): void {
this.parent.requestData(size)
}
_write (chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void): void {
this.parent.consumeInput(chunk).then(() => callback(null), e => callback(e))
}
_destroy (error: Error|null, callback: (error: Error|null) => void): void {
this.parent.handleStopRequest(error).then(() => callback(null), e => callback(e))
}
}
export abstract class SSHProxyStream {
get message$ (): Observable<string> { return this.message }
get destroyed$ (): Observable<Error|null> { return this.destroyed }
get socket (): SSHProxyStreamSocket|null { return this._socket }
private message = new Subject<string>()
private destroyed = new Subject<Error|null>()
private _socket: SSHProxyStreamSocket|null = null
async start (): Promise<SSHProxyStreamSocket> {
if (!this._socket) {
this._socket = new SSHProxyStreamSocket(this)
}
return this._socket
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
abstract requestData (size: number): void
abstract consumeInput (data: Buffer): Promise<void>
protected emitMessage (message: string): void {
this.message.next(message)
}
protected emitOutput (data: Buffer): void {
this._socket?.push(data)
}
async handleStopRequest (error: Error|null): Promise<void> {
this.destroyed.next(error)
this.destroyed.complete()
this.message.complete()
}
stop (error?: Error): void {
this._socket?.destroy(error)
}
}

View File

@@ -14,11 +14,19 @@ input.form-control.mt-2(
) )
.d-flex.mt-3 .d-flex.mt-3
button.btn.btn-secondary( checkbox(
*ngIf='isPassword()',
[(ngModel)]='remember',
[text]='"Save password"|translate'
)
.ms-auto
button.btn.btn-secondary.me-3(
*ngIf='step > 0', *ngIf='step > 0',
(click)='previous()' (click)='previous()'
) )
.ms-auto
button.btn.btn-primary( button.btn.btn-primary(
(click)='next()' (click)='next()'
) )

View File

@@ -1,6 +1,7 @@
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, ChangeDetectionStrategy } from '@angular/core' import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, ChangeDetectionStrategy } from '@angular/core'
import { KeyboardInteractivePrompt } from '../session/ssh' import { KeyboardInteractivePrompt } from '../session/ssh'
import { SSHProfile } from '../api'
import { PasswordStorageService } from '../services/passwordStorage.service'
@Component({ @Component({
selector: 'keyboard-interactive-auth-panel', selector: 'keyboard-interactive-auth-panel',
@@ -9,13 +10,17 @@ import { KeyboardInteractivePrompt } from '../session/ssh'
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class KeyboardInteractiveAuthComponent { export class KeyboardInteractiveAuthComponent {
@Input() profile: SSHProfile
@Input() prompt: KeyboardInteractivePrompt @Input() prompt: KeyboardInteractivePrompt
@Input() step = 0 @Input() step = 0
@Output() done = new EventEmitter() @Output() done = new EventEmitter()
@ViewChild('input') input: ElementRef @ViewChild('input') input: ElementRef
remember = false
constructor (private passwordStorage: PasswordStorageService) {}
isPassword (): boolean { isPassword (): boolean {
return this.prompt.prompts[this.step].prompt.toLowerCase().includes('password') || !this.prompt.prompts[this.step].echo return this.prompt.isAPasswordPrompt(this.step)
} }
previous (): void { previous (): void {
@@ -26,6 +31,10 @@ export class KeyboardInteractiveAuthComponent {
} }
next (): void { next (): void {
if (this.isPassword() && this.remember) {
this.passwordStorage.savePassword(this.profile, this.prompt.responses[this.step])
}
if (this.step === this.prompt.prompts.length - 1) { if (this.step === this.prompt.prompts.length - 1) {
this.prompt.respond() this.prompt.respond()
this.done.emit() this.done.emit()

View File

@@ -51,6 +51,7 @@ sftp-panel.bg-dark(
keyboard-interactive-auth-panel.bg-dark( keyboard-interactive-auth-panel.bg-dark(
*ngIf='activeKIPrompt', *ngIf='activeKIPrompt',
[prompt]='activeKIPrompt', [prompt]='activeKIPrompt',
[profile]='profile',
(click)='$event.stopPropagation()', (click)='$event.stopPropagation()',
(done)='activeKIPrompt = null; frontend?.focus()' (done)='activeKIPrompt = null; frontend?.focus()'
) )

View File

@@ -1,3 +1,4 @@
import * as russh from 'russh'
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker' import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
import colors from 'ansi-colors' import colors from 'ansi-colors'
import { Component, Injector, HostListener } from '@angular/core' import { Component, Injector, HostListener } from '@angular/core'
@@ -94,17 +95,21 @@ export class SSHTabComponent extends ConnectableTerminalTabComponent<SSHProfile>
} }
}) })
session.jumpStream = await new Promise((resolve, reject) => jumpSession.ssh.forwardOut( if (!(jumpSession.ssh instanceof russh.AuthenticatedSSHClient)) {
'127.0.0.1', 0, profile.options.host, profile.options.port ?? 22, throw new Error('Jump session is not authenticated yet somehow')
(err, stream) => { }
if (err) {
jumpSession.emitServiceMessage(colors.bgRed.black(' X ') + ` Could not set up port forward on ${jumpConnection.name}`) try {
reject(err) session.jumpChannel = await jumpSession.ssh.openTCPForwardChannel({
return addressToConnectTo: profile.options.host,
} portToConnectTo: profile.options.port ?? 22,
resolve(stream) originatorAddress: '127.0.0.1',
}, originatorPort: 0,
)) })
} catch (err) {
jumpSession.emitServiceMessage(colors.bgRed.black(' X ') + ` Could not set up port forward on ${jumpConnection.name}`)
throw err
}
} }
} }
@@ -125,7 +130,7 @@ export class SSHTabComponent extends ConnectableTerminalTabComponent<SSHProfile>
}) })
if (!session.open) { if (!session.open) {
this.write('\r\n' + colors.black.bgWhite(' SSH ') + ` Connecting to ${session.profile.options.host}\r\n`) this.write('\r\n' + colors.black.bgWhite(' SSH ') + ` Connecting to ${session.profile.name}\r\n`)
this.startSpinner(this.translate.instant(_('Connecting'))) this.startSpinner(this.translate.instant(_('Connecting')))

View File

@@ -1,5 +1,3 @@
import './polyfills'
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common' import { CommonModule } from '@angular/common'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'

Some files were not shown because too many files have changed in this diff Show More