mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-01 15:06:59 +00:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2346e10b70 | ||
![]() |
55c13edace | ||
![]() |
6a91565da1 | ||
![]() |
90d0bbce23 | ||
![]() |
daa5687cfc | ||
![]() |
9590ab8bf6 | ||
![]() |
d7971294aa | ||
![]() |
67230c1601 | ||
![]() |
09556ae6a1 | ||
![]() |
eae946d0f0 | ||
![]() |
33eb5bd800 | ||
![]() |
6196f3b85d | ||
![]() |
e1e6e1cdab | ||
![]() |
ac6f60f1ae | ||
![]() |
aa67130e37 | ||
![]() |
21aedb6045 | ||
![]() |
2bc95bb0e0 | ||
![]() |
b4d3667b9a | ||
![]() |
e84cbd82d8 | ||
![]() |
2ecccad2db | ||
![]() |
aab7e285a9 | ||
![]() |
3eaa600544 | ||
![]() |
9beab8994b | ||
![]() |
d9363b5de1 | ||
![]() |
ed22309e93 | ||
![]() |
5932b8664b | ||
![]() |
0ca097fa23 | ||
![]() |
e8fdb8b8f9 | ||
![]() |
1c077147ac |
@@ -1328,6 +1328,15 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "SelfHosted-Club",
|
||||
"name": "SelfHosted",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/128927132?v=4",
|
||||
"profile": "https://www.selfhosted.sg/",
|
||||
"contributions": [
|
||||
"financial"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
56
.github/workflows/build.yml
vendored
56
.github/workflows/build.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
run: yarn run lint
|
||||
|
||||
macOS-Build:
|
||||
runs-on: macos-12
|
||||
runs-on: macos-15
|
||||
needs: Lint
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -61,8 +61,6 @@ jobs:
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
sudo -H pip3 install setuptools
|
||||
sudo npm i -g yarn
|
||||
yarn --network-timeout 1000000
|
||||
env:
|
||||
ARCH: ${{matrix.arch}}
|
||||
@@ -82,7 +80,7 @@ jobs:
|
||||
|
||||
- name: Build and sign packages
|
||||
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:
|
||||
ARCH: ${{matrix.arch}}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -97,7 +95,7 @@ jobs:
|
||||
|
||||
- name: Build packages without signing
|
||||
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:
|
||||
ARCH: ${{matrix.arch}}
|
||||
# DEBUG: electron-builder,electron-builder:*
|
||||
@@ -244,14 +242,14 @@ jobs:
|
||||
|
||||
- name: Upload packages to packagecloud.io
|
||||
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:
|
||||
PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }}
|
||||
with:
|
||||
repo: 'eugeny/tabby'
|
||||
dir: 'dist'
|
||||
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'
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload AppImage (${{matrix.arch}})
|
||||
@@ -312,6 +310,10 @@ jobs:
|
||||
with:
|
||||
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
|
||||
uses: actions/setup-node@v3.7.0
|
||||
with:
|
||||
@@ -335,20 +337,48 @@ jobs:
|
||||
env:
|
||||
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
|
||||
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'))
|
||||
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:
|
||||
ARCH: ${{matrix.arch}}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
KEYGEN_TOKEN: ${{ secrets.KEYGEN_TOKEN }}
|
||||
WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
|
||||
WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
|
||||
DEBUG: electron-builder,electron-builder:*
|
||||
SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }}
|
||||
SM_PUBLISHER_NAME: ${{ secrets.SM_PUBLISHER_NAME }}
|
||||
SM_API_KEY: ${{ vars.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
|
||||
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:
|
||||
ARCH: ${{matrix.arch}}
|
||||
|
||||
|
1
.github/workflows/docs.yml
vendored
1
.github/workflows/docs.yml
vendored
@@ -18,6 +18,7 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt update && sudo apt install libfontconfig1-dev
|
||||
yarn cache clean
|
||||
cd app
|
||||
yarn
|
||||
|
1
.well-known/funding-manifest-urls
Normal file
1
.well-known/funding-manifest-urls
Normal file
@@ -0,0 +1 @@
|
||||
https://null.page/funding.json
|
@@ -66,7 +66,7 @@ Diese README ist auch verfügbar in: <a href="./README.md">:gb: English</a> ·
|
||||
|
||||

|
||||
|
||||
* Ein V220-Terminal + verschiedene Erweiterungen
|
||||
* Ein VT220-Terminal + verschiedene Erweiterungen
|
||||
* Mehrere verschachtelte, geteilte Fenster
|
||||
* Tabs auf jeder Seite des Fensters
|
||||
* Optional andockbares Fenster mit einem globalen Spawn-Hotkey ("Quake-Konsole")
|
||||
@@ -342,6 +342,7 @@ 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/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://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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -67,7 +67,7 @@ Este fichero README está disponible en: <a href="./README.md">:gb: English</a>
|
||||
|
||||

|
||||
|
||||
* Un terminal V220 + varias extensiones
|
||||
* Un terminal VT220 + varias extensiones
|
||||
* Múltiples paneles divididos anidados
|
||||
* Pestañas en cualquier lado de la ventana
|
||||
* Ventana acoplable opcional con una tecla de acceso directo global ("consola de Quake")
|
||||
@@ -344,6 +344,7 @@ 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/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://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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -67,7 +67,7 @@ This README is also available in: <a href="./README.md">:gb: English</a> · <a
|
||||
|
||||

|
||||
|
||||
* Terminal V220 + berbagai macam ekstensi
|
||||
* Terminal VT220 + berbagai macam ekstensi
|
||||
* Beberapa pembagian panel
|
||||
* Tab di sisi mana pun dari jendela
|
||||
* Jendela dockable opsional dengan hotkey spawn global ("Quake console")
|
||||
@@ -341,6 +341,7 @@ 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/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://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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -68,7 +68,7 @@ Questo README è disponibile anche in: <a href="./README.md">:gb: English</a>
|
||||
|
||||

|
||||
|
||||
* Un terminale V220 + vari estensioni
|
||||
* Un terminale VT220 + vari estensioni
|
||||
* Suddivisione in pannelli
|
||||
* Schede su qualsiasi lato della finestra
|
||||
* Finestra agganciabile opzionale con un tasto di scelta rapida ("Quake console")
|
||||
@@ -337,6 +337,7 @@ 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/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://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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -74,7 +74,7 @@
|
||||
|
||||

|
||||
|
||||
* V220ターミナル+各種拡張機能
|
||||
* VT220ターミナル+各種拡張機能
|
||||
* 複数ネストされたペイン分割に対応
|
||||
* ウィンドウ内に自由に配置可能なタブ
|
||||
* グローバルホットキーで呼び出せるドックウィンドウ機能("Quakeコンソール")
|
||||
@@ -352,6 +352,7 @@ 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/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://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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -66,7 +66,7 @@ This README is also available in: <a href="./README.md">:gb: English</a> · <a
|
||||
|
||||

|
||||
|
||||
* A V220 터미널 + 다양한 확장
|
||||
* A VT220 터미널 + 다양한 확장
|
||||
* 여러 개의 분할 창 중첩
|
||||
* 모든 측면에 탭이 위치함
|
||||
* 전역 스폰 단축키가 있는 도킹 가능한 윈도우 ("Quake console")
|
||||
@@ -336,6 +336,7 @@ 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/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://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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -72,7 +72,7 @@ This README is also available in: <a href="./README.es-ES.md">:es: Spanish</a>
|
||||
|
||||

|
||||
|
||||
* A V220 terminal + various extensions
|
||||
* A VT220 terminal + various extensions
|
||||
* Multiple nested split panes
|
||||
* Tabs on any side of the window
|
||||
* Optional dockable window with a global spawn hotkey ("Quake console")
|
||||
@@ -360,6 +360,7 @@ 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/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://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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -75,7 +75,7 @@ Ten plik README jest również dostępny w językach: <a href="./README.md">:gb
|
||||
|
||||

|
||||
|
||||
* Konsola V220 + wiele rozszerzeń
|
||||
* Konsola VT220 + wiele rozszerzeń
|
||||
* Wiele nakładających się podzielonych okien
|
||||
* Okna na każdej stronie ekranu
|
||||
* Opcjonalne dokowanie okna za pomocą skrótu ("Quake console")
|
||||
|
@@ -67,7 +67,7 @@ Esse README também está disponível em: <a href="./README.md">:gb: English</a
|
||||
|
||||

|
||||
|
||||
* Um terminal V220 + várias extensões
|
||||
* Um terminal VT220 + várias extensões
|
||||
* Múltiplos painéis divididos aninhados
|
||||
* Guias em qualquer lado da janela
|
||||
* Opção de minimizar para a barra de tarefas com uma tecla de atalho global ("Quake console")
|
||||
@@ -345,6 +345,7 @@ 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/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://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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -67,7 +67,7 @@
|
||||
|
||||

|
||||
|
||||
* Терминал V220 + различные дополнения;
|
||||
* Терминал VT220 + различные дополнения;
|
||||
* Деление окна на несколько панелей;
|
||||
* Вкладки на любой стороне окна;
|
||||
* Опционально закрепляемое окно с глобальной горячей клавишей для вызова («Quake console»);
|
||||
@@ -337,6 +337,7 @@ 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/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://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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -66,7 +66,7 @@
|
||||
|
||||

|
||||
|
||||
* 一个 V220 终端 + 各种插件
|
||||
* 一个 VT220 终端 + 各种插件
|
||||
* 多个嵌套的拆分窗格
|
||||
* 可以将标签页设置在窗口的任意一侧
|
||||
* 带有全局生成热键的可选可停靠窗口(“Quake console”)
|
||||
@@ -336,6 +336,7 @@
|
||||
<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/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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -108,7 +108,7 @@ export class Window {
|
||||
|
||||
this.webContents = this.window.webContents
|
||||
|
||||
this.window.once('ready-to-show', () => {
|
||||
this.window.webContents.once('did-finish-load', () => {
|
||||
if (process.platform === 'darwin') {
|
||||
this.window.setVibrancy(macOSVibrancyType)
|
||||
} else if (process.platform === 'win32' && this.configStore.appearance?.vibrancy) {
|
||||
@@ -139,7 +139,7 @@ export class Window {
|
||||
|
||||
enableRemote(this.window.webContents)
|
||||
|
||||
this.window.loadURL(`file://${app.getAppPath()}/dist/index.html`, { extraHeaders: 'pragma: no-cache\n' })
|
||||
this.window.loadFile(path.join(app.getAppPath(), 'dist', 'index.html'))
|
||||
|
||||
this.window.webContents.setVisualZoomLevelLimits(1, 1)
|
||||
this.window.webContents.setZoomFactor(1)
|
||||
|
@@ -3949,8 +3949,7 @@ strict-uri-encode@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
name string-width-cjs
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@@ -3985,6 +3984,15 @@ string-width@^3.0.0, string-width@^3.1.0:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^5.1.0"
|
||||
|
||||
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^5.0.1, string-width@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
|
||||
@@ -4027,8 +4035,7 @@ stringify-package@^1.0.0, stringify-package@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85"
|
||||
integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1:
|
||||
name strip-ansi-cjs
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
@@ -4063,6 +4070,13 @@ strip-ansi@^6.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^5.0.0"
|
||||
|
||||
strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^7.0.1:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
|
||||
@@ -4474,8 +4488,7 @@ worker-farm@^1.6.0, worker-farm@^1.7.0:
|
||||
dependencies:
|
||||
errno "~0.1.7"
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||
name wrap-ansi-cjs
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
@@ -4501,6 +4514,15 @@ wrap-ansi@^5.1.0:
|
||||
string-width "^3.0.0"
|
||||
strip-ansi "^5.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||
|
@@ -8,10 +8,6 @@
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<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>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
|
@@ -32,7 +32,8 @@ extraResources:
|
||||
- extras
|
||||
asarUnpack:
|
||||
- 'dist/*.map'
|
||||
|
||||
- node_modules/keytar/build/Release/*.node
|
||||
- node_modules/**/*.node
|
||||
win:
|
||||
icon: "./build/windows/icon.ico"
|
||||
artifactName: tabby-${version}-portable-${env.ARCH}.${ext}
|
||||
|
1371
extras/clink/CHANGES
1371
extras/clink/CHANGES
File diff suppressed because it is too large
Load Diff
@@ -1,63 +1,64 @@
|
||||
:: Copyright (c) 2012 Martin Ridgers
|
||||
:: License: http://opensource.org/licenses/MIT
|
||||
|
||||
@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
|
||||
set clink_profile_arg=
|
||||
set clink_quiet_arg=
|
||||
|
||||
:: Mimic cmd.exe's behaviour when starting from the start menu.
|
||||
if /i "%1"=="startmenu" (
|
||||
rem -- Mimic cmd.exe's behaviour when starting from the start menu.
|
||||
if /i "%~1"=="startmenu" (
|
||||
cd /d "%userprofile%"
|
||||
shift
|
||||
)
|
||||
|
||||
:: Check for the --profile option.
|
||||
if /i "%1"=="--profile" (
|
||||
rem -- Check for the --profile option.
|
||||
if /i "%~1"=="--profile" (
|
||||
set clink_profile_arg=--profile "%~2"
|
||||
shift
|
||||
shift
|
||||
)
|
||||
|
||||
:: Check for the --quiet option.
|
||||
if /i "%1"=="--quiet" (
|
||||
rem -- Check for the --quiet option.
|
||||
if /i "%~1"=="--quiet" (
|
||||
set clink_quiet_arg= --quiet
|
||||
shift
|
||||
)
|
||||
|
||||
:: If the .bat is run without any arguments, then start a cmd.exe instance.
|
||||
if "%1"=="" (
|
||||
rem -- If the .bat is run without any arguments, then start a cmd.exe instance.
|
||||
if _%1==_ (
|
||||
call :launch
|
||||
goto :end
|
||||
)
|
||||
|
||||
:: Test for autorun.
|
||||
if defined CLINK_NOAUTORUN if /i "%1"=="inject" if /i "%2"=="--autorun" goto :end
|
||||
rem -- Test for autorun.
|
||||
if defined CLINK_NOAUTORUN if /i "%~1"=="inject" if /i "%~2"=="--autorun" goto :end
|
||||
|
||||
:: Endlocal before inject tags the prompt.
|
||||
endlocal
|
||||
|
||||
:: Pass through to appropriate loader.
|
||||
rem -- Forward to appropriate loader, and endlocal before inject tags the prompt.
|
||||
if /i "%processor_architecture%"=="x86" (
|
||||
endlocal
|
||||
"%~dp0\clink_x86.exe" %*
|
||||
) else if /i "%processor_architecture%"=="arm64" (
|
||||
endlocal
|
||||
"%~dp0\clink_arm64.exe" %*
|
||||
) else if /i "%processor_architecture%"=="amd64" (
|
||||
if defined processor_architew6432 (
|
||||
endlocal
|
||||
"%~dp0\clink_x86.exe" %*
|
||||
) else (
|
||||
endlocal
|
||||
"%~dp0\clink_x64.exe" %*
|
||||
)
|
||||
)
|
||||
|
||||
:end
|
||||
goto :eof
|
||||
goto :end
|
||||
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
:launch
|
||||
setlocal
|
||||
setlocal enableextensions
|
||||
set WT_PROFILE_ID=
|
||||
set WT_SESSION=
|
||||
start "Clink" cmd.exe /s /k ""%~dpnx0" inject %clink_profile_arg%%clink_quiet_arg%"
|
||||
endlocal
|
||||
exit /b 0
|
||||
|
||||
:end
|
||||
|
BIN
extras/clink/clink_arm64.exe
Normal file
BIN
extras/clink/clink_arm64.exe
Normal file
Binary file not shown.
BIN
extras/clink/clink_dll_arm64.dll
Normal file
BIN
extras/clink/clink_dll_arm64.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,10 +4,10 @@
|
||||
# Override the built-in Readline defaults with ones that provide a more
|
||||
# enhanced Clink experience.
|
||||
|
||||
colored-completion-prefix on
|
||||
colored-stats on
|
||||
mark-symlinked-directories on
|
||||
completion-auto-query-items on
|
||||
history-point-at-end-of-anchored-search on
|
||||
search-ignore-case on
|
||||
set colored-completion-prefix on
|
||||
set colored-stats on
|
||||
set mark-symlinked-directories on
|
||||
set completion-auto-query-items on
|
||||
set history-point-at-end-of-anchored-search on
|
||||
set search-ignore-case on
|
||||
|
||||
|
@@ -4,28 +4,26 @@
|
||||
# Override built-in default settings with ones that provide a more
|
||||
# enhanced Clink experience.
|
||||
|
||||
autosuggest.enable = True
|
||||
clink.default_bindings = windows
|
||||
cmd.ctrld_exits = False
|
||||
color.arginfo = sgr 38;5;172
|
||||
color.argmatcher = sgr 1;38;5;40
|
||||
color.cmd = sgr 1;38;5;231
|
||||
color.cmd = bold
|
||||
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.description = sgr 38;5;39
|
||||
color.doskey = sgr 1;38;5;75
|
||||
color.executable = sgr 1;38;5;33
|
||||
color.filtered = sgr 38;5;231
|
||||
color.filtered = bold
|
||||
color.flag = sgr 38;5;117
|
||||
color.hidden = sgr 38;5;160
|
||||
color.histexpand = sgr 97;48;5;55
|
||||
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.selected_completion = sgr 38;5;16;48;5;254
|
||||
color.selected_completion = sgr 7
|
||||
color.selection = sgr 38;5;16;48;5;179
|
||||
color.suggestion = sgr 38;5;239
|
||||
color.unrecognized = sgr 38;5;203
|
||||
history.max_lines = 25000
|
||||
history.time_stamp = show
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Afrikaans\n"
|
||||
"Language: af_ZA\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Bulgarian\n"
|
||||
"Language: bg_BG\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Czech\n"
|
||||
"Language: cs_CZ\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Danish\n"
|
||||
"Language: da_DK\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
@@ -211,7 +211,7 @@ msgstr "Sløring"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:28
|
||||
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:80
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de_DE\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: English, United Kingdom\n"
|
||||
"Language: en_GB\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Language: es_ES\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: French\n"
|
||||
"Language: fr_FR\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Croatian\n"
|
||||
"Language: hr_HR\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Indonesian\n"
|
||||
"Language: id_ID\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Italian\n"
|
||||
"Language: it_IT\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
@@ -23,7 +23,7 @@ msgstr "{name} copia"
|
||||
|
||||
#: 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"
|
||||
msgstr "Una famiglia di font secondaria usata per visualizzare quelle mancanti nella font principale"
|
||||
msgstr "Un set di caratteri secondario usato per mostrare quelli mancanti del font principale"
|
||||
|
||||
#: tabby-core/src/components/transfersMenu.component.ts:49
|
||||
msgid "Abort all"
|
||||
@@ -192,7 +192,7 @@ msgstr "Modalità tasto backspace"
|
||||
#: tabby-serial/src/components/serialTab.component.ts:93
|
||||
#: tabby-serial/src/profiles.ts:88
|
||||
msgid "Baud rate"
|
||||
msgstr "Velocità di trasmissione"
|
||||
msgstr "Velocità trasmissione"
|
||||
|
||||
#: tabby-terminal/src/hotkeys.ts:22
|
||||
msgid "Beginning of the line"
|
||||
@@ -479,7 +479,7 @@ msgstr "Crea cartella"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:90
|
||||
msgid "Current"
|
||||
msgstr "Corrente"
|
||||
msgstr "Attuale"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsForMode.component.html:3
|
||||
msgid "Current color scheme"
|
||||
@@ -487,7 +487,7 @@ msgstr "Tema in uso"
|
||||
|
||||
#: locale/tmp-html/tabby-ssh/src/components/hostKeyPromptModal.component.html:17
|
||||
msgid "Current host key fingerprint"
|
||||
msgstr "Firma della chiave host attuale"
|
||||
msgstr "Firma chiave host attuale"
|
||||
|
||||
#: tabby-core/src/tabContextMenu.ts:184
|
||||
msgid "Current process: {name}"
|
||||
@@ -495,7 +495,7 @@ msgstr "Processo attuale: {name}"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:51
|
||||
msgid "Cursor shape"
|
||||
msgstr "Forma del cursore"
|
||||
msgstr "Forma cursore"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsForMode.component.html:46
|
||||
msgid "Custom"
|
||||
@@ -531,7 +531,7 @@ msgstr "\"Connetti a\" predefinito"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:93
|
||||
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
|
||||
msgid "Default profile for new tabs"
|
||||
@@ -791,7 +791,7 @@ msgstr "Cancella configurazione"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/vaultSettingsTab.component.html:12
|
||||
msgid "Erase the Vault"
|
||||
msgstr "Cancella la cassaforte"
|
||||
msgstr "Cancella cassaforte"
|
||||
|
||||
#: locale/tmp-html/tabby-plugin-manager/src/components/pluginsSettingsTab.component.html:6
|
||||
msgid "Error in {plugin}:"
|
||||
@@ -1189,7 +1189,7 @@ msgstr "Lingua"
|
||||
|
||||
#: locale/tmp-html/tabby-ssh/src/components/hostKeyPromptModal.component.html:11
|
||||
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
|
||||
msgid "Launch WinSCP"
|
||||
@@ -1439,7 +1439,7 @@ msgstr "Nelle discussioni di GitHub"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/editProfileModal.component.html:47
|
||||
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
|
||||
msgid "Opacity"
|
||||
@@ -1476,11 +1476,11 @@ msgstr "Arancione"
|
||||
|
||||
#: tabby-electron/src/shells/macDefault.ts:25
|
||||
msgid "OS default"
|
||||
msgstr "Predefinito del OS"
|
||||
msgstr "Predefinito S.O."
|
||||
|
||||
#: tabby-electron/src/shells/winDefault.ts:43
|
||||
msgid "OS default ({name})"
|
||||
msgstr "Predefinito del OS ({name})"
|
||||
msgstr "Predefinito S.O. ({name})"
|
||||
|
||||
#: tabby-terminal/src/components/streamProcessingSettings.component.ts:46
|
||||
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
|
||||
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:249
|
||||
@@ -1694,7 +1694,7 @@ msgstr "Recente"
|
||||
#: tabby-terminal/src/tabContextMenu.ts:115
|
||||
#: tabby-terminal/src/tabContextMenu.ts:119
|
||||
msgid "Reconnect"
|
||||
msgstr "Riconetti"
|
||||
msgstr "Riconnetti"
|
||||
|
||||
#: tabby-terminal/src/hotkeys.ts:102
|
||||
msgid "Reconnect current tab (Serial/Telnet/SSH)"
|
||||
@@ -1723,7 +1723,7 @@ msgstr "Remoto"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:124
|
||||
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
|
||||
#: tabby-core/src/tabContextMenu.ts:120
|
||||
@@ -2011,7 +2011,7 @@ msgstr "Visualizza predefiniti"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:146
|
||||
msgid "Show Mixer"
|
||||
msgstr "Visualizza Mixer"
|
||||
msgstr "Visualizza mixer"
|
||||
|
||||
#: tabby-core/src/hotkeys.ts:56
|
||||
msgid "Show pane labels (for rearranging)"
|
||||
@@ -2382,7 +2382,7 @@ msgstr "Carica come nuova configurazione"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:39
|
||||
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
|
||||
msgid "Use ConPTY"
|
||||
@@ -2554,7 +2554,7 @@ msgstr "Giallo"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/setVaultPassphraseModal.component.html:4
|
||||
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
|
||||
msgid "You could be under a man-in-the-middle attack right now, or the host key could have just been changed."
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Japanese\n"
|
||||
"Language: ja_JP\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
@@ -185,7 +185,7 @@ msgstr "透過の種類"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/inputProcessingSettings.component.html:4
|
||||
msgid "Backspace key mode"
|
||||
msgstr "BackSpaceキー"
|
||||
msgstr "Backspaceキー"
|
||||
|
||||
#: locale/tmp-html/tabby-serial/src/components/serialProfileSettings.component.html:14
|
||||
#: tabby-serial/src/components/serialTab.component.ts:93
|
||||
@@ -526,7 +526,7 @@ msgstr "垂直方向の分割サイズを縮小"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:92
|
||||
msgid "Default \"Connect to\" type"
|
||||
msgstr "既定の接続"
|
||||
msgstr "既定の接続方式"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:93
|
||||
msgid "Default connection type used by quick connect feature (ex. SSH, Telnet)"
|
||||
@@ -630,7 +630,7 @@ msgstr "動的なタブ名を無効にする"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:218
|
||||
msgid "Disable fluent background while dragging"
|
||||
msgstr "ドラッグ中はFluentを無効にする"
|
||||
msgstr "ドラッグ中はFluent背景を無効化する"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:204
|
||||
msgid "Disable GPU acceleration"
|
||||
@@ -757,7 +757,7 @@ msgstr "アップデートが利用可能になったら自動的にインスト
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:211
|
||||
msgid "Enable fluent background option"
|
||||
msgstr "Fluent背景設定を有効にする"
|
||||
msgstr "Fluent背景オプションを有効にする"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:16
|
||||
msgid "Enable font ligatures"
|
||||
@@ -806,7 +806,7 @@ msgstr "例:"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:212
|
||||
msgid "Experimental Windows 10 background style known to cause issues"
|
||||
msgstr "Windows10では問題が発生する場合があります。"
|
||||
msgstr "不具合が報告されているWindows10風の実験的な背景"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/vaultSettingsTab.component.html:28
|
||||
msgid "Export"
|
||||
@@ -834,7 +834,7 @@ msgstr "固定"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:219
|
||||
msgid "Fluent background sometimes causes drag lag"
|
||||
msgstr "Fluentはドラッグ中にラグを発生させる場合があります"
|
||||
msgstr "Fluent背景はドラッグ中にラグを発生させることがあります"
|
||||
|
||||
#: tabby-terminal/src/tabContextMenu.ts:82
|
||||
msgid "Focus all panes"
|
||||
@@ -1052,7 +1052,7 @@ msgstr "ホットキー"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:83
|
||||
msgid "How Tabby presents itself through environment vars"
|
||||
msgstr "環境変数を利用してTabbyを他の端末のように扱わせます"
|
||||
msgstr "環境変数を利用して、Tabbyを他の端末として認識させます"
|
||||
|
||||
#: locale/tmp-html/tabby-ssh/src/components/sshProfileSettings.component.html:24
|
||||
msgid "HTTP proxy"
|
||||
@@ -1299,7 +1299,7 @@ msgstr "\"未分類\" に移動"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:197
|
||||
msgid "Moving the mouse over an inactive pane will cause it to activate"
|
||||
msgstr "マウスの移動でアクティブなペインを切り替えることができます。"
|
||||
msgstr "マウスの移動に合わせてアクティブなペインを切り替えます。"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/editProfileGroupModal.component.html:9
|
||||
#: locale/tmp-html/tabby-settings/src/components/editProfileModal.component.html:12
|
||||
@@ -1366,7 +1366,7 @@ msgstr "新しいタブ: {profile}"
|
||||
#: tabby-local/src/buttonProvider.ts:20
|
||||
#: tabby-local/src/tabContextMenu.ts:27
|
||||
msgid "New terminal"
|
||||
msgstr "新しいターミナル"
|
||||
msgstr "新しい端末"
|
||||
|
||||
#: tabby-electron/src/hotkeys.ts:10
|
||||
msgid "New window"
|
||||
@@ -1956,7 +1956,7 @@ msgstr "Tabbyを %COMSPEC% に設定"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:69
|
||||
msgid "Set to 0 to disable recent profiles"
|
||||
msgstr "最近使用したプロファイルをセレクターに表示しない場合は0に設定してください"
|
||||
msgstr "セレクターに最近使用したプロファイルを表示したくない場合は、0に設定してください"
|
||||
|
||||
#: locale/tmp-html/tabby-ssh/src/components/sshSettingsTab.component.html:36
|
||||
msgid "Sets the SSH agent's named pipe path."
|
||||
@@ -1994,7 +1994,7 @@ msgstr "複数行の貼り付けをする際に確認画面を表示します"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/profilesSettingsTab.component.html:75
|
||||
msgid "Show built-in profiles in selector"
|
||||
msgstr "セレクターに標準プロファイルを表示する"
|
||||
msgstr "標準プロファイルをセレクターに表示"
|
||||
|
||||
#: tabby-core/src/hotkeys.ts:12
|
||||
msgid "Show command selector"
|
||||
@@ -2089,7 +2089,7 @@ msgstr "ソースコード"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:13
|
||||
msgid "Spaciness"
|
||||
msgstr "UIの間隔"
|
||||
msgstr "UI間隔"
|
||||
|
||||
#: tabby-core/src/tabContextMenu.ts:75
|
||||
msgid "Split"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Korean\n"
|
||||
"Language: ko_KR\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Polish\n"
|
||||
"Language: pl_PL\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Portuguese, Brazilian\n"
|
||||
"Language: pt_BR\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Portuguese\n"
|
||||
"Language: pt_PT\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Russian\n"
|
||||
"Language: ru_RU\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
@@ -660,7 +660,7 @@ msgstr "Отключиться от {host}?"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:30
|
||||
msgid "Display images via Sixel escape sequences"
|
||||
msgstr "Отображать изображения при помощи сиксельной управляющей последовательности"
|
||||
msgstr "Отображать изображения при помощи управляющей последовательности Sixel"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:85
|
||||
msgid "Display on"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Serbian (Cyrillic)\n"
|
||||
"Language: sr_SP\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
@@ -342,7 +342,7 @@ msgstr ""
|
||||
#: locale/tmp-html/tabby-serial/src/components/serialProfileSettings.component.html:81
|
||||
#: locale/tmp-html/tabby-ssh/src/components/sshProfileSettings.component.html:216
|
||||
msgid "Colors"
|
||||
msgstr ""
|
||||
msgstr "Боје"
|
||||
|
||||
#: tabby-core/src/hotkeys.ts:72
|
||||
msgid "Combine all tabs into the current tab"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Swedish\n"
|
||||
"Language: sv_SE\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Turkish\n"
|
||||
"Language: tr_TR\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Ukrainian\n"
|
||||
"Language: uk_UA\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
@@ -100,12 +100,12 @@ msgstr "Дозволяє швидко відкрити термінал у ви
|
||||
#: locale/tmp-html/tabby-core/src/components/welcomeTab.component.html:25
|
||||
#: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsTab.component.html:11
|
||||
msgid "Always dark"
|
||||
msgstr "Завжди темно"
|
||||
msgstr "Завжди темна"
|
||||
|
||||
#: locale/tmp-html/tabby-core/src/components/welcomeTab.component.html:27
|
||||
#: locale/tmp-html/tabby-terminal/src/components/colorSchemeSettingsTab.component.html:13
|
||||
msgid "Always light"
|
||||
msgstr "Завжди світити"
|
||||
msgstr "Завжди світла"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/appearanceSettingsTab.component.html:2
|
||||
#: tabby-terminal/src/settings.ts:14
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Chinese Simplified\n"
|
||||
"Language: zh_CN\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
@@ -43,7 +43,7 @@ msgstr "辅助功能"
|
||||
|
||||
#: locale/tmp-html/tabby-settings/src/components/windowSettingsTab.component.html:27
|
||||
msgid "Acrylic background"
|
||||
msgstr "亚克力背景"
|
||||
msgstr "毛玻璃背景"
|
||||
|
||||
#: locale/tmp-html/tabby-local/src/components/commandLineEditor.component.html:24
|
||||
#: locale/tmp-html/tabby-local/src/components/environmentEditor.component.html:11
|
||||
|
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: tabby\n"
|
||||
"Language-Team: Chinese Traditional\n"
|
||||
"Language: zh_TW\n"
|
||||
"PO-Revision-Date: 2024-07-10 09:04\n"
|
||||
"PO-Revision-Date: 2024-12-24 22:58\n"
|
||||
|
||||
#: tabby-local/src/components/terminalTab.component.ts:113
|
||||
msgid "\"{command}\" is still running. Close?"
|
||||
@@ -1390,7 +1390,7 @@ msgstr "無色彩"
|
||||
|
||||
#: locale/tmp-html/tabby-terminal/src/components/terminalSettingsTab.component.html:85
|
||||
msgid "No modifier"
|
||||
msgstr "不可修改"
|
||||
msgstr "無修飾鍵"
|
||||
|
||||
#: locale/tmp-html/tabby-serial/src/components/serialProfileSettings.component.html:41
|
||||
msgid "None"
|
||||
|
@@ -43,7 +43,7 @@
|
||||
"electron-builder": "^24.6.4",
|
||||
"electron-download": "^4.1.1",
|
||||
"electron-installer-snap": "^5.1.0",
|
||||
"electron-rebuild": "^3.2.9",
|
||||
"@electron/rebuild": "^3.7.1",
|
||||
"eslint": "^8.48.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.0",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
@@ -96,7 +96,8 @@
|
||||
"*/pug": "^3",
|
||||
"lzma-native": "^8.0.6",
|
||||
"**/graceful-fs": "^4.2.4",
|
||||
"nan": "2.17.0"
|
||||
"nan": "2.17.0",
|
||||
"node-gyp": "^10.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run build:typings && node scripts/build-modules.mjs",
|
||||
|
@@ -25,7 +25,7 @@ builder({
|
||||
},
|
||||
] : undefined,
|
||||
},
|
||||
publish: process.env.KEYGEN_TOKEN ? isTag ? 'always' : 'onTagOrDraft' : 'never',
|
||||
publish: (process.env.KEYGEN_TOKEN && isTag) ? 'always' : 'never',
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
|
@@ -42,7 +42,7 @@ builder({
|
||||
},
|
||||
] : undefined,
|
||||
},
|
||||
publish: process.env.KEYGEN_TOKEN ? isTag ? 'always' : 'onTagOrDraft' : 'never',
|
||||
publish: (process.env.KEYGEN_TOKEN && isTag) ? 'always' : 'never',
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
import { rebuild } from 'electron-rebuild'
|
||||
import { rebuild } from '@electron/rebuild'
|
||||
import * as path from 'path'
|
||||
import * as vars from './vars.mjs'
|
||||
|
||||
|
@@ -2,11 +2,15 @@
|
||||
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
|
||||
import { build as builder } from 'electron-builder'
|
||||
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 keypair = process.env.SM_KEYPAIR_ALIAS
|
||||
|
||||
process.env.ARCH = process.env.ARCH || process.arch
|
||||
|
||||
console.log('Signing enabled:', !!keypair)
|
||||
|
||||
builder({
|
||||
dir: true,
|
||||
win: ['nsis', 'zip'],
|
||||
@@ -22,8 +26,33 @@ builder({
|
||||
channel: `latest-${process.env.ARCH}`,
|
||||
},
|
||||
] : undefined,
|
||||
forceCodeSigning: !!keypair,
|
||||
win: {
|
||||
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 => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
import { rebuild } from 'electron-rebuild'
|
||||
import { rebuild } from '@electron/rebuild'
|
||||
import sh from 'shelljs'
|
||||
import path from 'node:path'
|
||||
import fs from 'node:fs'
|
||||
|
@@ -31,6 +31,8 @@ hotkeys:
|
||||
__nonStructural: true
|
||||
profile-selectors:
|
||||
__nonStructural: true
|
||||
group-selectors:
|
||||
__nonStructural: true
|
||||
profiles: []
|
||||
groups: []
|
||||
profileDefaults:
|
||||
|
@@ -264,6 +264,7 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
||||
|
||||
async provide (): Promise<HotkeyDescription[]> {
|
||||
const profiles = await this.profilesService.getProfiles()
|
||||
const groups = await this.profilesService.getProfileGroups()
|
||||
return [
|
||||
...this.hotkeys,
|
||||
...profiles.map(profile => ({
|
||||
@@ -274,6 +275,10 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
||||
id: `profile-selectors.${provider.id}`,
|
||||
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 }),
|
||||
})),
|
||||
]
|
||||
}
|
||||
|
||||
|
@@ -37,7 +37,7 @@ import { FastHtmlBindDirective } from './directives/fastHtmlBind.directive'
|
||||
import { DropZoneDirective } from './directives/dropZone.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 { ConfigService } from './services/config.service'
|
||||
@@ -46,7 +46,7 @@ import { HotkeysService } from './services/hotkeys.service'
|
||||
import { CustomMissingTranslationHandler, LocaleService } from './services/locale.service'
|
||||
import { CommandService } from './services/commands.service'
|
||||
|
||||
import { StandardTheme, StandardCompactTheme, PaperTheme, NewTheme } from './theme'
|
||||
import { NewTheme } from './theme'
|
||||
import { CoreConfigProvider } from './config'
|
||||
import { AppHotkeyProvider } from './hotkeys'
|
||||
import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu, ProfilesContextMenu } from './tabContextMenu'
|
||||
@@ -60,9 +60,6 @@ export function TranslateMessageFormatCompilerFactory (): TranslateMessageFormat
|
||||
|
||||
const PROVIDERS = [
|
||||
{ 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: ConfigProvider, useClass: CoreConfigProvider, 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) {
|
||||
profilesService.openNewTabForProfile(profile)
|
||||
}
|
||||
}
|
||||
if (hotkey.startsWith('profile-selectors.')) {
|
||||
} else if (hotkey.startsWith('profile-selectors.')) {
|
||||
const id = hotkey.substring(hotkey.indexOf('.') + 1)
|
||||
const provider = profilesService.getProviders().find(x => x.id === id)
|
||||
if (!provider) {
|
||||
return
|
||||
}
|
||||
this.showSelector(provider).catch(() => null)
|
||||
}
|
||||
if (hotkey === 'command-selector') {
|
||||
} else if (hotkey.startsWith('group-selectors.')) {
|
||||
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)
|
||||
}
|
||||
|
||||
if (hotkey === 'profile-selector') {
|
||||
} else if (hotkey === '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)
|
||||
}
|
||||
|
||||
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> {
|
||||
return {
|
||||
ngModule: AppModule,
|
||||
|
@@ -28,7 +28,7 @@ export class HomeBaseService {
|
||||
}
|
||||
|
||||
openDiscord (): void {
|
||||
this.platform.openExternal('https://discord.gg/4c5EVTBhtp')
|
||||
this.platform.openExternal('https://discord.gg/Vn7BjmzhtF')
|
||||
}
|
||||
|
||||
openTranslations (): void {
|
||||
|
@@ -487,6 +487,12 @@ export class ProfilesService {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -2,32 +2,6 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
||||
import { Injectable } from '@angular/core'
|
||||
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 */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class NewTheme extends Theme {
|
||||
|
@@ -24,6 +24,7 @@
|
||||
"devDependencies": {
|
||||
"electron-promise-ipc": "^2.2.4",
|
||||
"ps-node": "^0.1.6",
|
||||
"ssh-config": "^5.0.0",
|
||||
"tmp-promise": "^3.0.2",
|
||||
"which": "^3.0.0",
|
||||
"winston": "^3.3.3"
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import at from 'core-js-pure/actual/array/at'
|
||||
import * as fs from 'fs/promises'
|
||||
import * as fsSync from 'fs'
|
||||
import * as path from 'path'
|
||||
@@ -6,125 +5,297 @@ import slugify from 'slugify'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { Injectable } from '@angular/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 SSHConfig, { 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 and return it as a string
|
||||
async function readSSHConfigFile (filePath: string): Promise<string> {
|
||||
try {
|
||||
return await fs.readFile(filePath, 'utf8')
|
||||
} catch (err) {
|
||||
console.error('Error reading SSH config file:', err)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
// 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 (configuration['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' })
|
||||
export class OpenSSHImporter extends SSHProfileImporter {
|
||||
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')
|
||||
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') {
|
||||
target.privateKeys = value.split(',').map(s => s.trim()).map(s => {
|
||||
if (s.startsWith('~')) {
|
||||
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
|
||||
try {
|
||||
const sshConfigContent = await readSSHConfigFile(configPath)
|
||||
const config: SSHConfig = SSHConfig.parse(sshConfigContent)
|
||||
return convertToSSHProfiles(config)
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
return []
|
||||
|
@@ -413,6 +413,11 @@ simple-swizzle@^0.2.2:
|
||||
dependencies:
|
||||
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:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
|
||||
|
@@ -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')
|
||||
.header
|
||||
.title(translate) Run as administrator
|
||||
toggle(
|
||||
[(ngModel)]='profile.options.runAsAdministrator',
|
||||
)
|
||||
.form-line(*ngIf='uac?.isAvailable')
|
||||
.header
|
||||
.title(translate) Run as administrator
|
||||
toggle(
|
||||
[(ngModel)]='profile.options.runAsAdministrator',
|
||||
)
|
||||
|
||||
.mb-3
|
||||
label(translate) Working directory
|
||||
.mb-3
|
||||
label(translate) Working directory
|
||||
|
||||
.input-group
|
||||
input.form-control(
|
||||
type='text',
|
||||
placeholder='Home directory',
|
||||
[(ngModel)]='profile.options.cwd'
|
||||
)
|
||||
button.btn.btn-secondary((click)='pickWorkingDirectory()')
|
||||
i.fas.fa-folder-open
|
||||
.input-group
|
||||
input.form-control(
|
||||
type='text',
|
||||
placeholder='Home directory',
|
||||
[(ngModel)]='profile.options.cwd'
|
||||
)
|
||||
button.btn.btn-secondary((click)='pickWorkingDirectory()')
|
||||
i.fas.fa-folder-open
|
||||
|
||||
.mb-3
|
||||
label(translate) Environment
|
||||
environment-editor(
|
||||
type='text',
|
||||
[(model)]='profile.options.env',
|
||||
)
|
||||
.mb-3
|
||||
label(translate) Environment
|
||||
environment-editor(
|
||||
type='text',
|
||||
[(model)]='profile.options.env',
|
||||
)
|
||||
|
||||
li(ngbNavItem)
|
||||
a(ngbNavLink, translate) Colors
|
||||
ng-template(ngbNavContent)
|
||||
color-scheme-selector([(model)]='profile.terminalColorScheme')
|
||||
|
||||
div([ngbNavOutlet]='nav')
|
||||
|
@@ -1,6 +1,6 @@
|
||||
h3.mb-3(translate) Window
|
||||
|
||||
.form-line
|
||||
.form-line(*ngIf='themes.length > 1')
|
||||
.header
|
||||
.title(translate) Theme
|
||||
select.form-control(
|
||||
|
@@ -180,9 +180,7 @@ export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
|
||||
return
|
||||
}
|
||||
|
||||
const options = {
|
||||
...tab.profile.options,
|
||||
}
|
||||
const options = JSON.parse(JSON.stringify(tab.profile.options))
|
||||
|
||||
const cwd = await tab.session?.getWorkingDirectory() ?? tab.profile.options.cwd
|
||||
if (cwd) {
|
||||
|
Reference in New Issue
Block a user