mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-24 10:11:51 +00:00
Compare commits
1 Commits
tmp
...
localizati
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4d6866ac75 |
@@ -1,9 +1,6 @@
|
||||
{
|
||||
"files": [
|
||||
"README.md",
|
||||
"README.zh-CN.md",
|
||||
"README.ru-RU.md",
|
||||
"README.ko-KR.md"
|
||||
"README.md"
|
||||
],
|
||||
"imageSize": 100,
|
||||
"commit": false,
|
||||
@@ -517,88 +514,6 @@
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "gkor",
|
||||
"name": "George Korsnick",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/780052?v=4",
|
||||
"profile": "https://usual.io/",
|
||||
"contributions": [
|
||||
"financial"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "uluhonolulu",
|
||||
"name": "Artem Smirnov",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/872764?v=4",
|
||||
"profile": "https://about.me/ulu",
|
||||
"contributions": [
|
||||
"financial"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nevotheless",
|
||||
"name": "Tim Kopplow",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/779797?v=4",
|
||||
"profile": "https://github.com/nevotheless",
|
||||
"contributions": [
|
||||
"financial"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "mrthock",
|
||||
"name": "mrthock",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/88901709?v=4",
|
||||
"profile": "https://github.com/mrthock",
|
||||
"contributions": [
|
||||
"financial"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lrottach",
|
||||
"name": "Lukas Rottach",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/50323692?v=4",
|
||||
"profile": "https://github.com/lrottach",
|
||||
"contributions": [
|
||||
"financial"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "boonkerz",
|
||||
"name": "boonkerz",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/277321?v=4",
|
||||
"profile": "https://github.com/boonkerz",
|
||||
"contributions": [
|
||||
"code",
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "milotype",
|
||||
"name": "Milo Ivir",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/43657314?v=4",
|
||||
"profile": "https://github.com/milotype",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "JasonCubic",
|
||||
"name": "JasonCubic",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8921015?v=4",
|
||||
"profile": "https://github.com/JasonCubic",
|
||||
"contributions": [
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "MaxWaldorf",
|
||||
"name": "MaxWaldorf",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/15877853?v=4",
|
||||
"profile": "https://github.com/MaxWaldorf",
|
||||
"contributions": [
|
||||
"infra"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
7
.github/ISSUE_TEMPLATE/feature_request.md
vendored
7
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -7,13 +7,6 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
# RULES:
|
||||
|
||||
* **ENGLISH ONLY** - this issue tracker is English-only. Please respect the people who take time to help you with your problems.
|
||||
* Search existing issues first: https://github.com/Eugeny/tabby/issues
|
||||
-->
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
|
10
.github/ISSUE_TEMPLATE/issue-report.md
vendored
10
.github/ISSUE_TEMPLATE/issue-report.md
vendored
@@ -8,12 +8,12 @@ assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
# READ CAREFULLY:
|
||||
Before submitting an issue, make sure that:
|
||||
* You're running the latest Tabby version: https://github.com/Eugeny/tabby/releases
|
||||
* You've searched the existing issues: https://github.com/Eugeny/tabby/issues
|
||||
* Your problem is not caused by third-party plugins (disable _third-party_ plugins, restart and try to reproduce the problem).
|
||||
|
||||
* **ENGLISH ONLY** - this issue tracker is English-only. Please respect the people who take time to help you with your problems.
|
||||
* Search existing issues first: https://github.com/Eugeny/tabby/issues
|
||||
* Test with the latest Tabby version: https://github.com/Eugeny/tabby/releases
|
||||
* Disable third-party plugins.
|
||||
*Reports are accepted in English ONLY.*
|
||||
-->
|
||||
|
||||
**Describe the problem**:
|
||||
|
15
.github/workflows/issue-translator.yml
vendored
15
.github/workflows/issue-translator.yml
vendored
@@ -1,15 +0,0 @@
|
||||
name: 'issue-translator'
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: tomsun28/issues-translate-action@v2.6
|
||||
with:
|
||||
IS_MODIFY_TITLE: true
|
||||
CUSTOM_BOT_NOTE: The translator bot has detected that this issue body's language is not English, and has translated it automatically.
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -34,5 +34,3 @@ sentry-symbols.js
|
||||
|
||||
tabby-ssh/util/pagent.exe
|
||||
*.psd
|
||||
|
||||
crowdin.yml
|
||||
|
@@ -204,29 +204,6 @@ Pull requests and plugins are welcome!
|
||||
<td align="center"><a href="https://github.com/cypherbits"><img src="https://avatars.githubusercontent.com/u/10424900?v=4?s=100" width="100px;" alt=""/><br /><sub><b>cypherbits</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cypherbits" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://modulolotus.net"><img src="https://avatars.githubusercontent.com/u/946421?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matthew Davidson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=KingMob" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/al-wi"><img src="https://avatars.githubusercontent.com/u/11092199?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexander Wiedemann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=al-wi" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.notion.so/3d45c6bd2cbd4f938873a4bd12e23375"><img src="https://avatars.githubusercontent.com/u/59506394?v=4?s=100" width="100px;" alt=""/><br /><sub><b>장보연</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BoYeonJang" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Me1onRind"><img src="https://avatars.githubusercontent.com/u/19531270?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zZ</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Me1onRind" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/tainoNZ"><img src="https://avatars.githubusercontent.com/u/49261322?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aaron Davison</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=tainoNZ" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/composer404"><img src="https://avatars.githubusercontent.com/u/58251560?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Przemyslaw Kozik</b></sub></a><br /><a href="#design-composer404" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/highfredo"><img src="https://avatars.githubusercontent.com/u/5951524?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alfredo Arellano de la Fuente</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=highfredo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/NessunKim"><img src="https://avatars.githubusercontent.com/u/12974079?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MH Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=NessunKim" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://discord.gg/4c5EVTBhtp"><img src="https://avatars.githubusercontent.com/u/40345645?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marmota</b></sub></a><br /><a href="#design-jaimeadf" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://ares.zone"><img src="https://avatars.githubusercontent.com/u/40336192?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ares Andrew</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TENX-S" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://usual.io/"><img src="https://avatars.githubusercontent.com/u/780052?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Korsnick</b></sub></a><br /><a href="#financial-gkor" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://about.me/ulu"><img src="https://avatars.githubusercontent.com/u/872764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Artem Smirnov</b></sub></a><br /><a href="#financial-uluhonolulu" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/nevotheless"><img src="https://avatars.githubusercontent.com/u/779797?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim Kopplow</b></sub></a><br /><a href="#financial-nevotheless" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/mrthock"><img src="https://avatars.githubusercontent.com/u/88901709?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mrthock</b></sub></a><br /><a href="#financial-mrthock" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/lrottach"><img src="https://avatars.githubusercontent.com/u/50323692?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lukas Rottach</b></sub></a><br /><a href="#financial-lrottach" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/boonkerz"><img src="https://avatars.githubusercontent.com/u/277321?v=4?s=100" width="100px;" alt=""/><br /><sub><b>boonkerz</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=boonkerz" title="Code">💻</a> <a href="#translation-boonkerz" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/milotype"><img src="https://avatars.githubusercontent.com/u/43657314?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Milo Ivir</b></sub></a><br /><a href="#translation-milotype" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/JasonCubic"><img src="https://avatars.githubusercontent.com/u/8921015?v=4?s=100" width="100px;" alt=""/><br /><sub><b>JasonCubic</b></sub></a><br /><a href="#design-JasonCubic" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/MaxWaldorf"><img src="https://avatars.githubusercontent.com/u/15877853?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MaxWaldorf</b></sub></a><br /><a href="#infra-MaxWaldorf" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
20
README.md
20
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=DOWNLOADS&logo=github&style=for-the-badge"></a> <a href="https://nightly.link/Eugeny/tabby/workflows/build/master"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=for-the-badge"/></a> <a href="https://matrix.to/#/#tabby-general:matrix.org"><img alt="Matrix" src="https://img.shields.io/matrix/tabby-general:matrix.org?logo=matrix&style=for-the-badge&color=magenta"></a>   <a href="https://translate.tabby.sh/"><img alt="Translate" src="https://shields.io/badge/Translate-UI-white?logo=googletranslate&style=for-the-badge&color=white&logoColor=fff"></a> <a href="https://twitter.com/eugeeeeny"><img alt="Twitter" src="https://shields.io/badge/Subscribe-News-blue?logo=twitter&style=for-the-badge&color=blue"></a>
|
||||
<a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=DOWNLOADS&logo=github&style=for-the-badge"></a> <a href="https://nightly.link/Eugeny/tabby/workflows/build/master"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=for-the-badge"/></a> <a href="https://matrix.to/#/#tabby-general:matrix.org"><img alt="Matrix" src="https://img.shields.io/matrix/tabby-general:matrix.org?logo=matrix&style=for-the-badge&color=magenta"></a> <a href="https://twitter.com/eugeeeeny"><img alt="Twitter" src="https://shields.io/badge/Subscribe-News-blue?logo=twitter&style=for-the-badge&color=blue"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
This README is also available in: <a href="./README.ru-RU.md">Русский</a> <a href="./README.ko-KR.md">한국어</a> <a href="./README.zh-CN.md">简体中文</a>
|
||||
This README is also available in: <a href="./README.ko-KR.md">Korean</a> <a href="./README.zh-CN.md">简体中文</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -108,6 +108,7 @@ Tabby will run as a portable app on Windows, if you create a `data` folder in th
|
||||
|
||||
Plugins and themes can be installed directly from the Settings view inside Tabby.
|
||||
|
||||
* [clickable-links](https://github.com/Eugeny/tabby-clickable-links) - makes paths and URLs in the terminal clickable
|
||||
* [docker](https://github.com/Eugeny/tabby-docker) - connect to Docker containers
|
||||
* [title-control](https://github.com/kbjr/terminus-title-control) - allows modifying the title of the terminal tabs by providing a prefix, suffix, and/or strings to be removed
|
||||
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - quickly send commands to one or all terminal tabs
|
||||
@@ -220,19 +221,6 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center"><a href="https://discord.gg/4c5EVTBhtp"><img src="https://avatars.githubusercontent.com/u/40345645?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marmota</b></sub></a><br /><a href="#design-jaimeadf" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://ares.zone"><img src="https://avatars.githubusercontent.com/u/40336192?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ares Andrew</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TENX-S" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://usual.io/"><img src="https://avatars.githubusercontent.com/u/780052?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Korsnick</b></sub></a><br /><a href="#financial-gkor" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://about.me/ulu"><img src="https://avatars.githubusercontent.com/u/872764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Artem Smirnov</b></sub></a><br /><a href="#financial-uluhonolulu" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/nevotheless"><img src="https://avatars.githubusercontent.com/u/779797?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim Kopplow</b></sub></a><br /><a href="#financial-nevotheless" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/mrthock"><img src="https://avatars.githubusercontent.com/u/88901709?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mrthock</b></sub></a><br /><a href="#financial-mrthock" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/lrottach"><img src="https://avatars.githubusercontent.com/u/50323692?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lukas Rottach</b></sub></a><br /><a href="#financial-lrottach" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/boonkerz"><img src="https://avatars.githubusercontent.com/u/277321?v=4?s=100" width="100px;" alt=""/><br /><sub><b>boonkerz</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=boonkerz" title="Code">💻</a> <a href="#translation-boonkerz" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/milotype"><img src="https://avatars.githubusercontent.com/u/43657314?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Milo Ivir</b></sub></a><br /><a href="#translation-milotype" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/JasonCubic"><img src="https://avatars.githubusercontent.com/u/8921015?v=4?s=100" width="100px;" alt=""/><br /><sub><b>JasonCubic</b></sub></a><br /><a href="#design-JasonCubic" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/MaxWaldorf"><img src="https://avatars.githubusercontent.com/u/15877853?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MaxWaldorf</b></sub></a><br /><a href="#infra-MaxWaldorf" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
@@ -241,3 +229,5 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
<img src="https://ga-beacon.appspot.com/UA-3278102-18/github/readme" width="1"/>
|
||||
|
246
README.ru-RU.md
246
README.ru-RU.md
@@ -1,246 +0,0 @@
|
||||
[](https://tabby.sh)
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=DOWNLOADS&logo=github&style=for-the-badge"></a> <a href="https://nightly.link/Eugeny/tabby/workflows/build/master"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=for-the-badge"/></a> <a href="https://matrix.to/#/#tabby-general:matrix.org"><img alt="Matrix" src="https://img.shields.io/matrix/tabby-general:matrix.org?logo=matrix&style=for-the-badge&color=magenta"></a>   <a href="https://translate.tabby.sh/"><img alt="Translate" src="https://shields.io/badge/Translate-UI-white?logo=googletranslate&style=for-the-badge&color=white&logoColor=fff"></a> <a href="https://twitter.com/eugeeeeny"><img alt="Twitter" src="https://shields.io/badge/Subscribe-News-blue?logo=twitter&style=for-the-badge&color=blue"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://ko-fi.com/J3J8KWTF">
|
||||
<img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=2" width="150">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
### Загрузки:
|
||||
|
||||
* [Последняя версия](https://github.com/Eugeny/tabby/releases/latest)
|
||||
* [Репозитории](https://packagecloud.io/eugeny/tabby): [Debian/Ubuntu](https://packagecloud.io/eugeny/tabby/install#bash-deb), [RPM](https://packagecloud.io/eugeny/tabby/install#bash-rpm)
|
||||
* [Последний nightly-билд](https://nightly.link/Eugeny/tabby/workflows/build/master)
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Этот README также доступен на: <a href="./README.md">Английском</a> <a href="./README.ko-KR.md">Корейском</a> <a href="./README.zh-CN.md">Китайском</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
[**Tabby**](https://tabby.sh) (ранее **Terminus**) — широко конфигурируемый эмулятор терминала, SSH- и COM-клиент для Windows, macOS и Linux:
|
||||
|
||||
* Встроенный SSH- и Telnet-клиент и менеджер подключений;
|
||||
* Встроенный последовтаельный терминал;
|
||||
* Темы и цветовые схемы;
|
||||
* Полностью настраеваемые сочетания клавиш;
|
||||
* Панели;
|
||||
* Запоминание вкладок;
|
||||
* Поддержка PowerShell (and PS Core), WSL, Git-Bash, Cygwin, MSYS2, Cmder и CMD;
|
||||
* Прямая передача файлов из и в SSH-сессии через Zmodem;
|
||||
* Полная поддержка Unicode, включая символы двойной ширины;
|
||||
* Не задыхается при быстром выводе;
|
||||
* Полноценный опыт работы с shell на Windows, включая дополнение слов и команд по Tab (при помощи Clink);
|
||||
* Втроенное защищённое хранилище для SSH-ключей и настроек;
|
||||
* SSH-, SFTP- и Telnet-клиент доступен как [веб-приложение](https://tabby.sh/app) (также для [самостоятелньного хостинга](https://github.com/Eugeny/tabby-web)).
|
||||
|
||||
# Содержание <!-- omit in toc -->
|
||||
|
||||
- [Правда и ложь про Tabby](#правда-и-ложь-про-tabby)
|
||||
- [Функции терминала](#функции-терминала)
|
||||
- [SSH-клиент](#ssh-клиент)
|
||||
- [Терминал последовательного порта](#терминал-последовательного-порта)
|
||||
- [Портативность](#портативность)
|
||||
- [Плагины](#плагины)
|
||||
- [Темы](#темы)
|
||||
- [Внести свой вклад](#внести-свой-вклад)
|
||||
|
||||
<a name="about"></a>
|
||||
|
||||
# Правда и ложь про Tabby
|
||||
|
||||
* **Правда:** Tabby — это альтернатива стандартному терминалу Windows (conhost), PowerShell ISE, PuTTY, macOS Terminal.app и iTerm.
|
||||
|
||||
* **Ложь:** Tabby — это не новая оболочка или замена MinGW или Cygwin. Также он нелёгок — если потребление ОЗУ крайне важно для вас, лучше взгляните на [Conemu](https://conemu.github.io) или [Alacritty](https://github.com/jwilm/alacritty).
|
||||
|
||||
<a name="terminal"></a>
|
||||
|
||||
# Функции терминала
|
||||
|
||||

|
||||
|
||||
* Терминал V220 + различные дополнения;
|
||||
* Деление окна на несколько панелей;
|
||||
* Вкладки на любой стороне окна;
|
||||
* Опционально закрепляемое окно с глобальной горячей клавишей для вызова («Quake console»);
|
||||
* Определение прогресса процесса;
|
||||
* Уведомления о завершении процессов;
|
||||
* Защита от выполнения команд при вставке, предупреждения о вставке нескольких строк;
|
||||
* Лигатуры шрифтов;
|
||||
* Пользовательские профили оболочки;
|
||||
* Опциональная ПКМ-вставка и копирование при выделении (в стиле PuTTY).
|
||||
|
||||
<a name="ssh"></a>
|
||||
# SSH-клиент
|
||||
|
||||

|
||||
|
||||
* SSH2-клиент с менеджером соединений;
|
||||
* Проброс портов и X11;
|
||||
* Управление автоматическими джамп-хостами;
|
||||
* Проброс агента (включая Pageant и встроеный в Windows OpenSSH Agent);
|
||||
* Скрипты для входа.
|
||||
|
||||
<a name="serial"></a>
|
||||
# Терминал последовательного порта
|
||||
|
||||
* Сохранение соединений;
|
||||
* Поддержка ввода readline;
|
||||
* Опциональый побатный ввод HEX и вывод hexdump;
|
||||
* Преобразование newline;
|
||||
* Автоматическое восстановление соединения.
|
||||
|
||||
<a name="portable"></a>
|
||||
# Портативность
|
||||
|
||||
На Windows Tabby будет работать в портативном режиме, если создать папку `data` там же, где расположен файл `Tabby.exe`.
|
||||
|
||||
<a name="plugins"></a>
|
||||
# Плагины
|
||||
|
||||
Плагины и темы можно установить напрямую из Настроек Tabby.
|
||||
|
||||
* [clickable-links](https://github.com/Eugeny/tabby-clickable-links) — делает пути и URL в терминале гиперссылками;
|
||||
* [docker](https://github.com/Eugeny/tabby-docker) — подключения к Docker-контейнерам;
|
||||
* [title-control](https://github.com/kbjr/terminus-title-control) — позволяет изменять названия вкладок, добавляя префиксы, суффиксы и позволяя удалять строки;
|
||||
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) — быстро передаёт команды в одну или все вкладки терминала;
|
||||
* [save-output](https://github.com/Eugeny/tabby-save-output) — запись вывода терминала в файл;
|
||||
* [sync-config](https://github.com/starxg/terminus-sync-config) — синхронизация конфига в Gist или Gitee;
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) — плагин-пример, который постоянно будет вас бесить;
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) — позволяет создавать пользовательские провили рабочего окружеиня на основе конфига;
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) — открывает браузер по умолчанию с текстом, выделенном во вкладке Tabby.
|
||||
|
||||
<a name="themes"></a>
|
||||
# Темы
|
||||
|
||||
* [hype](https://github.com/Eugeny/tabby-theme-hype) — тема, вдохновлённая Hyper;
|
||||
* [relaxed](https://github.com/Relaxed-Theme/relaxed-terminal-themes#terminus) — тема Relaxed для Tabby;
|
||||
* [gruvbox](https://github.com/porkloin/terminus-theme-gruvbox);
|
||||
* [windows10](https://www.npmjs.com/package/terminus-theme-windows10);
|
||||
* [altair](https://github.com/yxuko/terminus-altair).
|
||||
|
||||
# Спонсоры <!-- omit in toc -->
|
||||
|
||||
[](https://packagecloud.io)
|
||||
|
||||
[**packagecloud**](https://packagecloud.io) предоставил бесплатный хостинг для Debian/RPM репозитория.
|
||||
|
||||
<a name="contributing"></a>
|
||||
# Внести свой вклад
|
||||
|
||||
Pull-запросы и плагины приветствуются!
|
||||
|
||||
Взгляните на [HACKING.md](https://github.com/Eugeny/tabby/blob/master/HACKING.md) и [API docs](https://docs.tabby.sh/), чтобы понять, как устроен проект, и ради очень краткого туториала по созданию плагинов.
|
||||
|
||||
---
|
||||
<a name="contributors"></a>
|
||||
|
||||
Огромное спасибо этим прекрасным людям ([описание эмодзи](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Russell Myers</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mezner" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Austin Warren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ehwarren" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Felicia Hummel</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Drachenkaetzchen" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike MacCana</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mikemaccana" title="Tests">⚠️</a> <a href="#design-mikemaccana" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yacine Kanzari</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=yxuko" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4?s=100" width="100px;" alt=""/><br /><sub><b>BBJip</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BBJip" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Levin Rickert</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=levrik" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4?s=100" width="100px;" alt=""/><br /><sub><b>OJ Kwon</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kwonoj" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4?s=100" width="100px;" alt=""/><br /><sub><b>domain</b></sub></a><br /><a href="#plugin-Domain" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/tabby/commits?author=Domain" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Imms</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Tyriar" title="Code">💻</a> <a href="#plugin-Tyriar" title="Plugin/utility libraries">🔌</a> <a href="https://github.com/Eugeny/tabby/commits?author=Tyriar" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Florian Bachmann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=baflo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Kühnel</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mischah" title="Code">💻</a> <a href="#design-mischah" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tilmann Meyer</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=NieLeben" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>PM Extra</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/issues?q=author%3APMExtra" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jonathan</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=IgnusG" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hans Koch</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hammster" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dak Smyth</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ThePuzzlemaker" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wang Zhi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=yfwz100" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jack1142</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=jack1142" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Howie Douglas</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hdougie" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Kaczor</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ckaczor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Johannes Kadak</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=boxmein" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>LeSeulArtichaut</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=LeSeulArtichaut" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cyril Taylor</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=CyrilTaylor" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nstefanou</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nstefanou" title="Code">💻</a> <a href="#plugin-nstefanou" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4?s=100" width="100px;" alt=""/><br /><sub><b>orin220444</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=orin220444" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gobius Dolhain</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Goobles" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/3l0w"><img src="https://avatars2.githubusercontent.com/u/37798980?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gwilherm Folliot</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=3l0w" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Dimitory"><img src="https://avatars0.githubusercontent.com/u/475955?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dmitry Pronin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=dimitory" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JonathanBeverley"><img src="https://avatars1.githubusercontent.com/u/20328966?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jonathan Beverley</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=JonathanBeverley" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/zend"><img src="https://avatars1.githubusercontent.com/u/25160?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zenghai Liang</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zend" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://about.me/matishadow"><img src="https://avatars0.githubusercontent.com/u/9083085?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mateusz Tracz</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=matishadow" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://zergpool.com"><img src="https://avatars3.githubusercontent.com/u/36234677?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pinpin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=pinpins" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/TakuroOnoda"><img src="https://avatars0.githubusercontent.com/u/1407926?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Takuro Onoda</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TakuroOnoda" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/frauhottelmann"><img src="https://avatars2.githubusercontent.com/u/902705?v=4?s=100" width="100px;" alt=""/><br /><sub><b>frauhottelmann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=frauhottelmann" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://patalong.pl"><img src="https://avatars.githubusercontent.com/u/29167842?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piotr Patalong</b></sub></a><br /><a href="#design-VectorKappa" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/clarkwang"><img src="https://avatars.githubusercontent.com/u/157076?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Clark Wang</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=clarkwang" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/iamchating"><img src="https://avatars.githubusercontent.com/u/7088153?v=4?s=100" width="100px;" alt=""/><br /><sub><b>iamchating</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=iamchating" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/starxg"><img src="https://avatars.githubusercontent.com/u/34997494?v=4?s=100" width="100px;" alt=""/><br /><sub><b>starxg</b></sub></a><br /><a href="#plugin-starxg" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center"><a href="http://hashnote.net/"><img src="https://avatars.githubusercontent.com/u/546312?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alisue</b></sub></a><br /><a href="#design-lambdalisue" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/ydcool"><img src="https://avatars.githubusercontent.com/u/5668295?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dominic Yin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ydcool" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/bdr99"><img src="https://avatars.githubusercontent.com/u/2292715?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brandon Rothweiler</b></sub></a><br /><a href="#design-bdr99" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://git.io/JnP49"><img src="https://avatars.githubusercontent.com/u/63876444?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Logic Machine</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=logicmachine123" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/cypherbits"><img src="https://avatars.githubusercontent.com/u/10424900?v=4?s=100" width="100px;" alt=""/><br /><sub><b>cypherbits</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cypherbits" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://modulolotus.net"><img src="https://avatars.githubusercontent.com/u/946421?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matthew Davidson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=KingMob" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/al-wi"><img src="https://avatars.githubusercontent.com/u/11092199?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alexander Wiedemann</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=al-wi" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.notion.so/3d45c6bd2cbd4f938873a4bd12e23375"><img src="https://avatars.githubusercontent.com/u/59506394?v=4?s=100" width="100px;" alt=""/><br /><sub><b>장보연</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BoYeonJang" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Me1onRind"><img src="https://avatars.githubusercontent.com/u/19531270?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zZ</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Me1onRind" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/tainoNZ"><img src="https://avatars.githubusercontent.com/u/49261322?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aaron Davison</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=tainoNZ" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/composer404"><img src="https://avatars.githubusercontent.com/u/58251560?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Przemyslaw Kozik</b></sub></a><br /><a href="#design-composer404" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/highfredo"><img src="https://avatars.githubusercontent.com/u/5951524?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alfredo Arellano de la Fuente</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=highfredo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/NessunKim"><img src="https://avatars.githubusercontent.com/u/12974079?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MH Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=NessunKim" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://discord.gg/4c5EVTBhtp"><img src="https://avatars.githubusercontent.com/u/40345645?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marmota</b></sub></a><br /><a href="#design-jaimeadf" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://ares.zone"><img src="https://avatars.githubusercontent.com/u/40336192?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ares Andrew</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TENX-S" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://usual.io/"><img src="https://avatars.githubusercontent.com/u/780052?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Korsnick</b></sub></a><br /><a href="#financial-gkor" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://about.me/ulu"><img src="https://avatars.githubusercontent.com/u/872764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Artem Smirnov</b></sub></a><br /><a href="#financial-uluhonolulu" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/nevotheless"><img src="https://avatars.githubusercontent.com/u/779797?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim Kopplow</b></sub></a><br /><a href="#financial-nevotheless" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/mrthock"><img src="https://avatars.githubusercontent.com/u/88901709?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mrthock</b></sub></a><br /><a href="#financial-mrthock" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/lrottach"><img src="https://avatars.githubusercontent.com/u/50323692?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lukas Rottach</b></sub></a><br /><a href="#financial-lrottach" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/boonkerz"><img src="https://avatars.githubusercontent.com/u/277321?v=4?s=100" width="100px;" alt=""/><br /><sub><b>boonkerz</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=boonkerz" title="Code">💻</a> <a href="#translation-boonkerz" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/milotype"><img src="https://avatars.githubusercontent.com/u/43657314?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Milo Ivir</b></sub></a><br /><a href="#translation-milotype" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/JasonCubic"><img src="https://avatars.githubusercontent.com/u/8921015?v=4?s=100" width="100px;" alt=""/><br /><sub><b>JasonCubic</b></sub></a><br /><a href="#design-JasonCubic" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/MaxWaldorf"><img src="https://avatars.githubusercontent.com/u/15877853?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MaxWaldorf</b></sub></a><br /><a href="#infra-MaxWaldorf" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
Данный проект следует заветам [all-contributors](https://github.com/all-contributors/all-contributors). Любые созидатели приветствуются!
|
||||
|
||||
<img src="https://ga-beacon.appspot.com/UA-3278102-18/github/readme" width="1"/>
|
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=DOWNLOADS&logo=github&style=for-the-badge"></a> <a href="https://nightly.link/Eugeny/tabby/workflows/build/master"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=for-the-badge"/></a> <a href="https://matrix.to/#/#tabby-general:matrix.org"><img alt="Matrix" src="https://img.shields.io/matrix/tabby-general:matrix.org?logo=matrix&style=for-the-badge&color=magenta"></a>   <a href="https://translate.tabby.sh/"><img alt="Translate" src="https://shields.io/badge/Translate-UI-white?logo=googletranslate&style=for-the-badge&color=white&logoColor=fff"></a> <a href="https://twitter.com/eugeeeeny"><img alt="Twitter" src="https://shields.io/badge/Subscribe-News-blue?logo=twitter&style=for-the-badge&color=blue"></a>
|
||||
<a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="GitHub All Releases" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=DOWNLOADS&logo=github&style=for-the-badge"></a> <a href="https://nightly.link/Eugeny/tabby/workflows/build/master"><img src="https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=for-the-badge"/></a> <a href="https://matrix.to/#/#tabby-general:matrix.org"><img alt="Matrix" src="https://img.shields.io/matrix/tabby-general:matrix.org?logo=matrix&style=for-the-badge&color=magenta"></a> <a href="https://twitter.com/eugeeeeny"><img alt="Twitter" src="https://shields.io/badge/Subscribe-News-blue?logo=twitter&style=for-the-badge&color=blue"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -19,11 +19,6 @@
|
||||
* [Repositories](https://packagecloud.io/eugeny/tabby): [Debian/Ubuntu-based](https://packagecloud.io/eugeny/tabby/install#bash-deb), [RPM-based](https://packagecloud.io/eugeny/tabby/install#bash-rpm)
|
||||
* [Latest nightly build](https://nightly.link/Eugeny/tabby/workflows/build/master)
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
本 README 还适用于以下语言: <a href="./README.ru-RU.md">Русский</a> <a href="./README.ko-KR.md">한국어</a> <a href="./README.zh-CN.md">简体中文</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
[**Tabby**](https://tabby.sh) (前身是 **Terminus**) 是一个可高度配置的终端模拟器和 SSH 或串口客户端,支持 Windows,macOS 和 Linux
|
||||
@@ -32,15 +27,15 @@
|
||||
* 集成串行终端
|
||||
* 定制主题和配色方案
|
||||
* 完全可配置的快捷键和多键快捷键
|
||||
* 分体式窗格
|
||||
* 自动保存标签页
|
||||
* 拆分窗格
|
||||
* 记住你的标签
|
||||
* 支持 PowerShell(和 PS Core)、WSL、Git-Bash、Cygwin、MSYS2、Cmder 和 CMD
|
||||
* 在 SSH 会话中通过 Zmodem 进行直接文件传输
|
||||
* 完整的 Unicode 支持,包括双角字符
|
||||
* 不会因快速的输出而卡住
|
||||
* Windows 上舒适的 shell 体验,包括 tab 自动补全(通过 Clink)
|
||||
* 为 SSH secrets 和设置集成了加密容器
|
||||
* SSH、SFTP 和 Telnet 客户端可用作 [Web 应用](https://tabby.sh/app)(也可[托管](https://github.com/Eugeny/tabby-web))
|
||||
* Windows 上的正确 shell 体验,包括 tab 自动补全(通过 Clink)
|
||||
* Integrated encrypted container for SSH secrets and configuration
|
||||
* SSH、SFTP 和 Telnet 客户端可用作 [Web 应用程序](https://tabby.sh/app)(也可[托管](https://github.com/Eugeny/tabby-web))
|
||||
|
||||
# 目录 <!-- omit in toc -->
|
||||
|
||||
@@ -48,7 +43,7 @@
|
||||
- [终端特性](#终端特性)
|
||||
- [SSH 客户端](#ssh-客户端)
|
||||
- [串行终端](#串行终端)
|
||||
- [便携式应用](#便携式应用)
|
||||
- [可移植的](#可移植的)
|
||||
- [插件](#插件)
|
||||
- [主题](#主题)
|
||||
- [贡献](#贡献)
|
||||
@@ -59,7 +54,7 @@
|
||||
|
||||
* **Tabby 是** Windows 标准终端 (conhost)、PowerShell ISE、PuTTY、macOS Terminal.app 和 iTerm 的替代品
|
||||
|
||||
* **Tabby 不是**一个全新的 shell,也不是 MinGW 或 Cygwin 的替代品。它也不是轻量级的 - 如果你对内存的占用很敏感,请考虑 [Conemu](https://conemu.github.io) 或 [Alacritty](https://github.com/jwilm/alacritty)
|
||||
* **Tabby 不是** Tabby 不是新的 shell,也不是 MinGW 或 Cygwin 的替代品。它也不是轻量级的 - 如果,请考虑 [Conemu](https://conemu.github.io) 或 [Alacritty](https://github.com/jwilm/alacritty)
|
||||
<a name="terminal"></a>
|
||||
|
||||
# 终端特性
|
||||
@@ -68,11 +63,11 @@
|
||||
|
||||
* 一个 V220 终端 + 各种插件
|
||||
* 多个嵌套的拆分窗格
|
||||
* 可以将标签页设置在窗口的任意一侧
|
||||
* Tabs on any side of the window
|
||||
* 带有全局生成热键的可选可停靠窗口(“Quake console”)
|
||||
* 进度检测
|
||||
* 流程完成通知
|
||||
* 带括号的粘贴,多行粘贴提示
|
||||
* 括号粘贴,多行粘贴警告
|
||||
* 连体字
|
||||
* 自定义 shell 配置文件
|
||||
* 可选的 RMB 粘贴和复制选择(PuTTY 风格)
|
||||
@@ -91,31 +86,31 @@
|
||||
<a name="serial"></a>
|
||||
# 串行终端
|
||||
|
||||
* 保存连接
|
||||
* 逐行读取的输入支持
|
||||
* 保存链接
|
||||
* Readline 输入支持
|
||||
* 可选的十六进制逐字节输入和十六进制转储输出
|
||||
* 换行转换
|
||||
* 自动重连
|
||||
|
||||
<a name="portable"></a>
|
||||
# 便携式应用
|
||||
# 可移植的
|
||||
|
||||
如果在 Tabby.exe 所在的目录创建一个名为`data`文件夹,Tabby 将可以在 Windows 上作为便携式的应用程序运行。
|
||||
如果在 Tabby.exe 所在的同一位置创建数据文件夹,Tabby 将在 Windows 上作为便携式的应用程序运行。
|
||||
|
||||
<a name="plugins"></a>
|
||||
# 插件
|
||||
|
||||
插件和主题可以直接在 Tabby 设置中安装。
|
||||
插件和主题可以直接从 Tabby 中的设置视图安装。
|
||||
|
||||
* [clickable-links](https://github.com/Eugeny/tabby-clickable-links) - 使终端中的路径和 URL 可点击
|
||||
* [docker](https://github.com/Eugeny/tabby-docker) - 连接 Docker 容器
|
||||
* [title-control](https://github.com/kbjr/terminus-title-control) - 允许通过提供要删除的前缀、后缀和/或字符串来修改标签页的标题
|
||||
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - 快速向一个或所有标签页发送命令
|
||||
* [docker](https://github.com/Eugeny/tabby-docker) - 连接到 Docker 容器
|
||||
* [title-control](https://github.com/kbjr/terminus-title-control) - 允许通过提供要删除的前缀、后缀和/或字符串来修改终端选项卡的标题
|
||||
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - 快速向一个或所有终端选项卡发送命令
|
||||
* [save-output](https://github.com/Eugeny/tabby-save-output) - 将终端输出记录到文件中
|
||||
* [sync-config](https://github.com/starxg/terminus-sync-config) - 将配置同步到 Gist 或 Gitee
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - 一个可以一直烦你的示例插件
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - 一个一直打扰你的示例插件
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 允许根据给定的配置创建自定义工作区配置文件
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - 从 Tabby 标签页带有选中的文本来打开系统默认浏览器
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - 使用从 Tabby 选项卡中选择的文本打开默认系统浏览器
|
||||
|
||||
<a name="themes"></a>
|
||||
# 主题
|
||||
@@ -218,20 +213,6 @@
|
||||
<td align="center"><a href="https://github.com/highfredo"><img src="https://avatars.githubusercontent.com/u/5951524?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alfredo Arellano de la Fuente</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=highfredo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/NessunKim"><img src="https://avatars.githubusercontent.com/u/12974079?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MH Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=NessunKim" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://discord.gg/4c5EVTBhtp"><img src="https://avatars.githubusercontent.com/u/40345645?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marmota</b></sub></a><br /><a href="#design-jaimeadf" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://ares.zone"><img src="https://avatars.githubusercontent.com/u/40336192?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ares Andrew</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TENX-S" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://usual.io/"><img src="https://avatars.githubusercontent.com/u/780052?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George Korsnick</b></sub></a><br /><a href="#financial-gkor" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://about.me/ulu"><img src="https://avatars.githubusercontent.com/u/872764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Artem Smirnov</b></sub></a><br /><a href="#financial-uluhonolulu" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/nevotheless"><img src="https://avatars.githubusercontent.com/u/779797?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim Kopplow</b></sub></a><br /><a href="#financial-nevotheless" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/mrthock"><img src="https://avatars.githubusercontent.com/u/88901709?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mrthock</b></sub></a><br /><a href="#financial-mrthock" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/lrottach"><img src="https://avatars.githubusercontent.com/u/50323692?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lukas Rottach</b></sub></a><br /><a href="#financial-lrottach" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/boonkerz"><img src="https://avatars.githubusercontent.com/u/277321?v=4?s=100" width="100px;" alt=""/><br /><sub><b>boonkerz</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=boonkerz" title="Code">💻</a> <a href="#translation-boonkerz" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/milotype"><img src="https://avatars.githubusercontent.com/u/43657314?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Milo Ivir</b></sub></a><br /><a href="#translation-milotype" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/JasonCubic"><img src="https://avatars.githubusercontent.com/u/8921015?v=4?s=100" width="100px;" alt=""/><br /><sub><b>JasonCubic</b></sub></a><br /><a href="#design-JasonCubic" title="Design">🎨</a></td>
|
||||
<td align="center"><a href="https://github.com/MaxWaldorf"><img src="https://avatars.githubusercontent.com/u/15877853?v=4?s=100" width="100px;" alt=""/><br /><sub><b>MaxWaldorf</b></sub></a><br /><a href="#infra-MaxWaldorf" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -240,4 +221,6 @@
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
本项目遵循 [all-contributors](https://github.com/all-contributors/all-contributors) 规范。 欢迎任何形式的贡献!
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
<img src="https://ga-beacon.appspot.com/UA-3278102-18/github/readme" width="1"/>
|
||||
|
@@ -70,11 +70,11 @@ export class Application {
|
||||
app.commandLine.appendSwitch('enable-transparent-visuals')
|
||||
app.disableHardwareAcceleration()
|
||||
}
|
||||
}
|
||||
if (this.configStore.hacks?.disableGPU) {
|
||||
app.commandLine.appendSwitch('disable-gpu')
|
||||
app.disableHardwareAcceleration()
|
||||
}
|
||||
}
|
||||
|
||||
this.userPluginsPath = path.join(
|
||||
app.getPath('userData'),
|
||||
@@ -130,6 +130,7 @@ export class Application {
|
||||
this.setupMenu()
|
||||
}
|
||||
await window.ready
|
||||
window.present()
|
||||
return window
|
||||
}
|
||||
|
||||
|
@@ -27,7 +27,7 @@ abstract class GlasstronWindow extends BrowserWindow {
|
||||
abstract setBlur (_: boolean)
|
||||
}
|
||||
|
||||
const macOSVibrancyType = process.platform === 'darwin' ? compareVersions(macOSRelease().version, '10.14', '>=') ? 'under-window' : 'dark' : null
|
||||
const macOSVibrancyType = process.platform === 'darwin' ? compareVersions(macOSRelease().version, '10.14', '>=') ? 'fullscreen-ui' : 'dark' : null
|
||||
|
||||
const activityIcon = nativeImage.createFromPath(`${app.getAppPath()}/assets/activity.png`)
|
||||
|
||||
@@ -303,9 +303,6 @@ export class Window {
|
||||
this.window.on('enter-full-screen', () => this.send('host:window-enter-full-screen'))
|
||||
this.window.on('leave-full-screen', () => this.send('host:window-leave-full-screen'))
|
||||
|
||||
this.window.on('maximize', () => this.send('host:window-maximized'))
|
||||
this.window.on('unmaximize', () => this.send('host:window-unmaximized'))
|
||||
|
||||
this.window.on('close', event => {
|
||||
if (!this.closing) {
|
||||
event.preventDefault()
|
||||
|
@@ -38,7 +38,7 @@
|
||||
"optionalDependencies": {
|
||||
"@tabby-gang/windows-blurbehind": "^3.0.0",
|
||||
"macos-native-processlist": "^2.0.0",
|
||||
"serialport": "^10.0.2",
|
||||
"serialport": "^10.0.1",
|
||||
"windows-native-registry": "^3.1.0",
|
||||
"windows-process-tree": "^0.3.2"
|
||||
},
|
||||
|
@@ -1,7 +1,7 @@
|
||||
body {
|
||||
min-height: 100vh;
|
||||
overflow: hidden;
|
||||
background: transparent !important;
|
||||
background: #1D272D;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
|
@@ -3,5 +3,4 @@ export const PLUGIN_BLACKLIST = [
|
||||
'terminus-scrollbar', // now useless
|
||||
'terminus-clickable-links', // now bundled with Tabby
|
||||
'tabby-clickable-links', // now bundled with Tabby
|
||||
'terminus-clickable-ips', // broken, functionality now bundled with Tabby
|
||||
]
|
||||
|
@@ -1,7 +1,3 @@
|
||||
app-root {
|
||||
background: #1D272D;
|
||||
}
|
||||
|
||||
.preload-logo {
|
||||
-webkit-app-region: drag;
|
||||
position: fixed;
|
||||
|
@@ -40,16 +40,17 @@
|
||||
"@serialport/binding-abstract" "10.0.1"
|
||||
debug "^4.3.2"
|
||||
|
||||
"@serialport/bindings-cpp@^10.2.1":
|
||||
version "10.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/bindings-cpp/-/bindings-cpp-10.2.1.tgz#e44a246142c11c83f0e4fd0cd16491702e6c3202"
|
||||
integrity sha512-PCnMBdy53/DLYx8dJg4e8Na1hMVGxE0d60IU6i03+k5SEmtPblixvIyytcllFhMRGQmH2zHHjP/2Big2Rjddwg==
|
||||
"@serialport/bindings@10.0.1":
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/bindings/-/bindings-10.0.1.tgz#b8f1d81dae370b954329ec9fdbabb23df74e6a35"
|
||||
integrity sha512-CcSE0OQQwpEup0LebG8bMFhVv+MB2wOm2yHWrdY6UiP3AEh7bB8F6sU1B/iq78BogyoIQ3ZDZBEi4I4F1hYVvA==
|
||||
dependencies:
|
||||
"@serialport/binding-abstract" "10.0.1"
|
||||
"@serialport/parser-readline" "10.0.1"
|
||||
bindings "^1.5.0"
|
||||
debug "^4.3.2"
|
||||
node-addon-api "4.2.0"
|
||||
node-gyp-build "^4.3.0"
|
||||
prebuild-install "^7.0.0"
|
||||
|
||||
"@serialport/parser-byte-length@10.0.1":
|
||||
version "10.0.1"
|
||||
@@ -88,10 +89,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@serialport/parser-regex/-/parser-regex-10.0.1.tgz#bcb302dda0a9d07ce9b3e554e3d2a41abf3fb5c5"
|
||||
integrity sha512-l8ECuUsan33x5pirQZodlmw0q70Jcxy+oHnXJaqchBTRCbtXlE7+PMFJnmNoIHGqDwt0XALbwpvKcnNBrgvT1g==
|
||||
|
||||
"@serialport/stream@10.0.2":
|
||||
version "10.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/stream/-/stream-10.0.2.tgz#3a242ea8a42356af9e4fb0924ca4a4a0efd36e37"
|
||||
integrity sha512-ZlC1M8/+hIO4JYI+cwJMAL2gkdf6Ahcen5gHJhM1Ibj40fRPOtxIWR1vgGFY1a/TKADDUZorE4RVYxmbheeZYw==
|
||||
"@serialport/stream@10.0.1":
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@serialport/stream/-/stream-10.0.1.tgz#f38c0e076e9e9ba3255e20e161576879f7d9ae18"
|
||||
integrity sha512-WQ5baxC56Jxo9mXgHq3BPxCXKnfOo3PZxpm6CDaKsZbdsdPYChogRsJCzKjAn6QaKIIFv3/5UdAXKmMCxkeVDA==
|
||||
dependencies:
|
||||
debug "^4.3.2"
|
||||
|
||||
@@ -330,6 +331,13 @@ bin-links@^1.1.2, bin-links@^1.1.8:
|
||||
npm-normalize-package-bin "^1.0.0"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
bindings@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz"
|
||||
integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
|
||||
dependencies:
|
||||
file-uri-to-path "1.0.0"
|
||||
|
||||
bl@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz"
|
||||
@@ -760,6 +768,13 @@ decompress-response@^4.2.0:
|
||||
dependencies:
|
||||
mimic-response "^2.0.0"
|
||||
|
||||
decompress-response@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
|
||||
integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
|
||||
dependencies:
|
||||
mimic-response "^3.1.0"
|
||||
|
||||
deep-extend@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz"
|
||||
@@ -1056,6 +1071,11 @@ figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
|
||||
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
|
||||
integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==
|
||||
|
||||
file-uri-to-path@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz"
|
||||
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
|
||||
|
||||
"filesize@>= 4.0.0":
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.3.0.tgz#dff53cfb3f104c9e422f346d53be8dbcc971bf11"
|
||||
@@ -2106,6 +2126,11 @@ mimic-response@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz"
|
||||
integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
|
||||
|
||||
mimic-response@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
|
||||
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz"
|
||||
@@ -2239,6 +2264,13 @@ node-abi@^2.20.0, node-abi@^2.7.0:
|
||||
dependencies:
|
||||
semver "^5.4.1"
|
||||
|
||||
node-abi@^3.3.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.5.0.tgz#26e8b7b251c3260a5ac5ba5aef3b4345a0229248"
|
||||
integrity sha512-LtHvNIBgOy5mO8mPEUtkCW/YCRWYEKshIvqhe1GHHyXEHEB5mgICyYnAcl4qan3uFeRROErKGzatFHPf6kDxWw==
|
||||
dependencies:
|
||||
semver "^7.3.5"
|
||||
|
||||
node-addon-api@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz"
|
||||
@@ -2263,11 +2295,6 @@ node-fetch-npm@^2.0.2:
|
||||
json-parse-better-errors "^1.0.0"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
node-gyp-build@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
|
||||
integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==
|
||||
|
||||
node-gyp@^5.0.2, node-gyp@^5.1.0:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e"
|
||||
@@ -2862,6 +2889,25 @@ prebuild-install@^6.0.0:
|
||||
tunnel-agent "^0.6.0"
|
||||
which-pm-runs "^1.0.0"
|
||||
|
||||
prebuild-install@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.0.0.tgz#3c5ce3902f1cb9d6de5ae94ca53575e4af0c1574"
|
||||
integrity sha512-IvSenf33K7JcgddNz2D5w521EgO+4aMMjFt73Uk9FRzQ7P+QZPKrp7qPsDydsSwjGt3T5xRNnM1bj1zMTD5fTA==
|
||||
dependencies:
|
||||
detect-libc "^1.0.3"
|
||||
expand-template "^2.0.3"
|
||||
github-from-package "0.0.0"
|
||||
minimist "^1.2.3"
|
||||
mkdirp-classic "^0.5.3"
|
||||
napi-build-utils "^1.0.1"
|
||||
node-abi "^3.3.0"
|
||||
npmlog "^4.0.1"
|
||||
pump "^3.0.0"
|
||||
rc "^1.2.7"
|
||||
simple-get "^4.0.0"
|
||||
tar-fs "^2.0.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
|
||||
prepend-http@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
@@ -3235,13 +3281,13 @@ serialize-error@^5.0.0:
|
||||
dependencies:
|
||||
type-fest "^0.8.0"
|
||||
|
||||
serialport@^10.0.2:
|
||||
version "10.0.2"
|
||||
resolved "https://registry.yarnpkg.com/serialport/-/serialport-10.0.2.tgz#64150fd2cd4cec35a88e0b8af66614a42b06e577"
|
||||
integrity sha512-hFQ6V/LFh0G4FmQsPjQCLqofalpHRWznXVA3lKlA19kUkdQrOmsz3CHQ72mPglbY+1PGGHZwXHPdTROtWP4qsA==
|
||||
serialport@^10.0.1:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/serialport/-/serialport-10.0.1.tgz#2df0ddcedf507180229973fc46e175f123e7c46f"
|
||||
integrity sha512-RNEUs8mtf6m8593b2qRfkDakxbhPR4VQT0iNKEpJu/JfuWVrSYMqAAWnJOQXOWdJV6ib7rcxCHgHFyarGqJVWw==
|
||||
dependencies:
|
||||
"@serialport/binding-mock" "10.0.1"
|
||||
"@serialport/bindings-cpp" "^10.2.1"
|
||||
"@serialport/bindings" "10.0.1"
|
||||
"@serialport/parser-byte-length" "10.0.1"
|
||||
"@serialport/parser-cctalk" "10.0.1"
|
||||
"@serialport/parser-delimiter" "10.0.1"
|
||||
@@ -3249,7 +3295,7 @@ serialport@^10.0.2:
|
||||
"@serialport/parser-readline" "10.0.1"
|
||||
"@serialport/parser-ready" "10.0.1"
|
||||
"@serialport/parser-regex" "10.0.1"
|
||||
"@serialport/stream" "10.0.2"
|
||||
"@serialport/stream" "10.0.1"
|
||||
debug "^4.3.2"
|
||||
|
||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||
@@ -3295,6 +3341,15 @@ simple-get@^3.0.3:
|
||||
once "^1.3.1"
|
||||
simple-concat "^1.0.0"
|
||||
|
||||
simple-get@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.0.tgz#73fa628278d21de83dadd5512d2cc1f4872bd675"
|
||||
integrity sha512-ZalZGexYr3TA0SwySsr5HlgOOinS4Jsa8YB2GJ6lUNAazyAu4KG/VmzMTwAt2YVXzzVj8QmefmAonZIK2BSGcQ==
|
||||
dependencies:
|
||||
decompress-response "^6.0.0"
|
||||
once "^1.3.1"
|
||||
simple-concat "^1.0.0"
|
||||
|
||||
slash@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
|
||||
|
@@ -40,7 +40,7 @@ publish:
|
||||
win:
|
||||
icon: "./build/windows/icon.ico"
|
||||
artifactName: tabby-${version}-portable.${ext}
|
||||
rfc3161TimeStampServer: http://timestamp.sectigo.com
|
||||
rfc3161TimeStampServer: http://sha256timestamp.ws.symantec.com/sha256/timestamp
|
||||
nsis:
|
||||
oneClick: false
|
||||
artifactName: tabby-${version}-setup.${ext}
|
||||
@@ -66,7 +66,7 @@ mac:
|
||||
NSRemovableVolumesUsageDescription: 'A subprocess requests access to files on a removable volume.'
|
||||
|
||||
linux:
|
||||
category: "Utility;TerminalEmulator;System"
|
||||
category: Utility
|
||||
icon: "./build/icons"
|
||||
artifactName: tabby-${version}-linux.${ext}
|
||||
executableArgs:
|
||||
|
@@ -1,3 +0,0 @@
|
||||
Do not submit pull requests for translations.
|
||||
|
||||
Translations are managed at https://crowdin.com/project/tabby
|
1490
locale/app.pot
1490
locale/app.pot
File diff suppressed because it is too large
Load Diff
1462
locale/de-DE.po
1462
locale/de-DE.po
File diff suppressed because it is too large
Load Diff
1489
locale/es-ES.po
1489
locale/es-ES.po
File diff suppressed because it is too large
Load Diff
1489
locale/fr-FR.po
1489
locale/fr-FR.po
File diff suppressed because it is too large
Load Diff
1462
locale/hr-HR.po
1462
locale/hr-HR.po
File diff suppressed because it is too large
Load Diff
1462
locale/pl-PL.po
1462
locale/pl-PL.po
File diff suppressed because it is too large
Load Diff
1462
locale/ru-RU.po
1462
locale/ru-RU.po
File diff suppressed because it is too large
Load Diff
1489
locale/zh-CN.po
1489
locale/zh-CN.po
File diff suppressed because it is too large
Load Diff
1489
locale/zh-TW.po
1489
locale/zh-TW.po
File diff suppressed because it is too large
Load Diff
31
package.json
31
package.json
@@ -7,8 +7,6 @@
|
||||
"@angular/forms": "^12.0.0",
|
||||
"@angular/platform-browser": "^12.0.0",
|
||||
"@angular/platform-browser-dynamic": "^12.0.0",
|
||||
"@biesbjerg/ngx-translate-extract": "^7.0.4",
|
||||
"@biesbjerg/ngx-translate-extract-marker": "^1.0.0",
|
||||
"@fortawesome/fontawesome-free": "^6.0.0-beta3",
|
||||
"@ng-bootstrap/ng-bootstrap": "^10.0.0",
|
||||
"@sentry/cli": "^1.71.0",
|
||||
@@ -26,24 +24,23 @@
|
||||
"@typescript-eslint/parser": "^4.33.0",
|
||||
"apply-loader": "2.0.0",
|
||||
"axios": "^0.21.2",
|
||||
"browserify-sign": "^4.2.1",
|
||||
"clone-deep": "^4.0.1",
|
||||
"compare-versions": "^4",
|
||||
"core-js": "^3.18.2",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "^6.5.1",
|
||||
"deep-equal": "2.0.5",
|
||||
"electron": "16.0.8",
|
||||
"electron": "16.0.6",
|
||||
"electron-builder": "^22.14.5",
|
||||
"electron-download": "^4.1.1",
|
||||
"electron-installer-snap": "^5.1.0",
|
||||
"electron-notarize": "^1.1.1",
|
||||
"electron-rebuild": "^3.2.7",
|
||||
"electron-rebuild": "^3.2.5",
|
||||
"eslint": "^7.32.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"graceful-fs": "^4.2.8",
|
||||
"html-loader": "2.1.2",
|
||||
"json-loader": "^0.5.7",
|
||||
"json-loader": "0.5.7",
|
||||
"lru-cache": "^6.0.0",
|
||||
"macos-release": "^3.0.1",
|
||||
"ngx-sortablejs": "^11.1.0",
|
||||
@@ -53,9 +50,7 @@
|
||||
"npmlog": "6.0.0",
|
||||
"npx": "^10.2.2",
|
||||
"patch-package": "^6.4.7",
|
||||
"po-gettext-loader": "^1.0.0",
|
||||
"pug": "3",
|
||||
"pug-cli": "^1.0.0-alpha6",
|
||||
"pug": "^3.0.2",
|
||||
"pug-html-loader": "1.1.5",
|
||||
"pug-lint": "^2.6.0",
|
||||
"pug-loader": "^2.4.0",
|
||||
@@ -63,11 +58,11 @@
|
||||
"raw-loader": "4.0.2",
|
||||
"sass-loader": "^12.4.0",
|
||||
"shell-quote": "^1.7.3",
|
||||
"shelljs": "0.8.5",
|
||||
"slugify": "^1.6.5",
|
||||
"shelljs": "0.8.4",
|
||||
"slugify": "^1.6.4",
|
||||
"sortablejs": "^1.14.0",
|
||||
"source-code-pro": "^2.38.0",
|
||||
"source-map-loader": "^3.0.1",
|
||||
"source-map-loader": "^3.0.0",
|
||||
"source-sans-pro": "3.6.0",
|
||||
"ssh2": "^1.5.0",
|
||||
"style-loader": "^3.2.1",
|
||||
@@ -78,14 +73,13 @@
|
||||
"typescript": "^4.3.5",
|
||||
"utils-decorators": "^1.10.4",
|
||||
"val-loader": "4.0.0",
|
||||
"webpack": "^5.67.0",
|
||||
"webpack": "^5.65.0",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"yaml-loader": "0.6.0",
|
||||
"zone.js": "^0.11.4"
|
||||
},
|
||||
"resolutions": {
|
||||
"*/pug": "^3",
|
||||
"lzma-native": "^8.0.0",
|
||||
"*/node-abi": "^3.5.0",
|
||||
"**/graceful-fs": "^4.2.4"
|
||||
@@ -99,10 +93,7 @@
|
||||
"prod": "cross-env TABBY_DEV=1 electron app",
|
||||
"docs": "node scripts/build-docs.js",
|
||||
"lint": "eslint --ext ts */src */lib",
|
||||
"postinstall": "patch-package && node ./scripts/install-deps.js",
|
||||
"i18n:pull": "crowdin pull --skip-untranslated-strings",
|
||||
"i18n:extract": "node scripts/i18n-extract.js",
|
||||
"i18n:push": "crowdin push"
|
||||
"postinstall": "patch-package && node ./scripts/install-deps.js"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
@@ -1,39 +0,0 @@
|
||||
diff --git a/node_modules/ssh2/lib/protocol/keyParser.js b/node_modules/ssh2/lib/protocol/keyParser.js
|
||||
index 9860e3f..ee82e51 100644
|
||||
--- a/node_modules/ssh2/lib/protocol/keyParser.js
|
||||
+++ b/node_modules/ssh2/lib/protocol/keyParser.js
|
||||
@@ -15,6 +15,7 @@ const {
|
||||
sign: sign_,
|
||||
verify: verify_,
|
||||
} = require('crypto');
|
||||
+const { createVerify: createVerifyDSS } = require('browserify-sign')
|
||||
const supportedOpenSSLCiphers = getCiphers();
|
||||
|
||||
const { Ber } = require('asn1');
|
||||
@@ -404,6 +405,17 @@ const BaseKey = {
|
||||
return new Error('No public key available');
|
||||
if (!algo || typeof algo !== 'string')
|
||||
algo = this[SYM_HASH_ALGO];
|
||||
+
|
||||
+ if (algo === 'dss1') {
|
||||
+ const verifier = createVerifyDSS('DSA-SHA1');
|
||||
+ verifier.update(data);
|
||||
+ try {
|
||||
+ return verifier.verify(pem, signature);
|
||||
+ } catch (ex) {
|
||||
+ return ex;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
try {
|
||||
return verify_(algo, data, pem, signature);
|
||||
} catch (ex) {
|
||||
@@ -1343,7 +1355,7 @@ function parseDER(data, baseType, comment, fullType) {
|
||||
return new Error('Malformed OpenSSH public key');
|
||||
pubPEM = genOpenSSLDSAPub(p, q, g, y);
|
||||
pubSSH = genOpenSSHDSAPub(p, q, g, y);
|
||||
- algo = 'sha1';
|
||||
+ algo = 'dss1';
|
||||
break;
|
||||
}
|
||||
case 'ssh-ed25519': {
|
@@ -5,5 +5,5 @@ const log = require('npmlog')
|
||||
|
||||
vars.packagesWithDocs.forEach(([dest, src]) => {
|
||||
log.info('docs', src)
|
||||
sh.exec(`yarn typedoc --out docs/api/${dest} --tsconfig ${src}/tsconfig.typings.json ${src}/src/index.ts`, { fatal: true })
|
||||
sh.exec(`yarn typedoc --out docs/api/${dest} --tsconfig ${src}/tsconfig.typings.json ${src}/src/index.ts`)
|
||||
})
|
||||
|
@@ -5,5 +5,5 @@ const log = require('npmlog')
|
||||
|
||||
vars.builtinPlugins.forEach(plugin => {
|
||||
log.info('typings', plugin)
|
||||
sh.exec(`yarn tsc --project ${plugin}/tsconfig.typings.json`, { fatal: true })
|
||||
sh.exec(`npx tsc --project ${plugin}/tsconfig.typings.json`)
|
||||
})
|
||||
|
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
const sh = require('shelljs')
|
||||
const fs = require('fs/promises')
|
||||
const vars = require('./vars')
|
||||
const log = require('npmlog')
|
||||
|
||||
const tempOutput = 'locale/app.new.pot'
|
||||
const pot = 'locale/app.pot'
|
||||
const tempHtml = 'locale/tmp-html'
|
||||
|
||||
;(async () => {
|
||||
sh.mkdir('-p', tempHtml)
|
||||
for (const plugin of vars.builtinPlugins) {
|
||||
log.info('extract-pug', plugin)
|
||||
|
||||
sh.exec(`yarn pug --doctype html -s --pretty -O '{require: function(){}}' -o ${tempHtml}/${plugin} ${plugin}`, { fatal: true })
|
||||
|
||||
log.info('extract-ts', plugin)
|
||||
sh.exec(`node node_modules/.bin/ngx-translate-extract -i ${plugin}/src -m -s -f pot -o ${tempOutput}`, { fatal: true })
|
||||
}
|
||||
|
||||
log.info('extract-pug')
|
||||
sh.exec(`node node_modules/.bin/ngx-translate-extract -i ${tempHtml} -f pot -s -o ${tempOutput}`, { fatal: true })
|
||||
|
||||
sh.rm('-r', tempHtml)
|
||||
await fs.rename(tempOutput, pot)
|
||||
})()
|
@@ -1,26 +1,30 @@
|
||||
#!/usr/bin/env node
|
||||
const sh = require('shelljs')
|
||||
const path = require('path')
|
||||
const vars = require('./vars')
|
||||
const log = require('npmlog')
|
||||
|
||||
const localBinPath = path.resolve(__dirname, '../node_modules/.bin')
|
||||
const npx = `${localBinPath}/npx`
|
||||
|
||||
log.info('patch')
|
||||
sh.exec(`yarn patch-package`, { fatal: true })
|
||||
sh.exec(`${npx} patch-package`)
|
||||
|
||||
log.info('deps', 'app')
|
||||
|
||||
sh.cd('app')
|
||||
sh.exec(`yarn install --force`, { fatal: true })
|
||||
sh.exec(`${npx} yarn install --force`)
|
||||
sh.cd('..')
|
||||
|
||||
sh.cd('web')
|
||||
sh.exec(`yarn install --force`, { fatal: true })
|
||||
sh.exec(`yarn patch-package`, { fatal: true })
|
||||
sh.exec(`${npx} yarn install --force`)
|
||||
sh.exec(`${npx} patch-package`)
|
||||
sh.cd('..')
|
||||
|
||||
vars.allPackages.forEach(plugin => {
|
||||
log.info('deps', plugin)
|
||||
sh.cd(plugin)
|
||||
sh.exec(`yarn install --force`, { fatal: true })
|
||||
sh.exec(`${npx} yarn install --force`)
|
||||
sh.cd('..')
|
||||
})
|
||||
|
||||
|
@@ -18,7 +18,7 @@ vars.builtinPlugins.forEach(plugin => {
|
||||
sh.cp('-r', path.join('..', plugin), '.')
|
||||
sh.rm('-rf', path.join(plugin, 'node_modules'))
|
||||
sh.cd(plugin)
|
||||
sh.exec(`yarn install --force --production`, { fatal: true })
|
||||
sh.exec(`yarn install --force --production`)
|
||||
|
||||
|
||||
log.info('rebuild', 'native')
|
||||
|
@@ -7,7 +7,7 @@ const { execSync } = require('child_process')
|
||||
vars.allPackages.forEach(plugin => {
|
||||
log.info('bump', plugin)
|
||||
sh.cd(plugin)
|
||||
sh.exec('npm --no-git-tag-version version ' + vars.version, { fatal: true })
|
||||
sh.exec('npm --no-git-tag-version version ' + vars.version)
|
||||
execSync('npm publish', { stdio: 'inherit' })
|
||||
sh.cd('..')
|
||||
})
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tabby-community-color-schemes",
|
||||
"version": "1.0.170-nightly.0",
|
||||
"version": "1.0.165-nightly.0",
|
||||
"description": "Community color schemes for Tabby",
|
||||
"keywords": [
|
||||
"tabby-builtin-plugin"
|
||||
|
@@ -1,44 +0,0 @@
|
||||
!
|
||||
! Light Owl
|
||||
! https://github.com/sdras/night-owl-vscode-theme
|
||||
!
|
||||
*.foreground: #403f53
|
||||
*.background: #fbfbfb
|
||||
*.cursorColor: #90a7b2
|
||||
!
|
||||
! Black
|
||||
*.color0: #403f53
|
||||
*.color8: #403f53
|
||||
!
|
||||
! Red
|
||||
*.color1: #de3d3b
|
||||
*.color9: #de3d3b
|
||||
!
|
||||
! Green
|
||||
*.color2: #08916a
|
||||
*.color10: #08916a
|
||||
!
|
||||
! Yellow
|
||||
*.color3: #e0af02
|
||||
*.color11: #daaa01
|
||||
!
|
||||
! Blue
|
||||
*.color4: #288ed7
|
||||
*.color12: #288ed7
|
||||
!
|
||||
! Magenta
|
||||
*.color5: #d6438a
|
||||
*.color13: #d6438a
|
||||
!
|
||||
! Cyan
|
||||
*.color6: #2aa298
|
||||
*.color14: #2aa298
|
||||
!
|
||||
! White
|
||||
*.color7: #f0f0f0
|
||||
*.color15: #979797
|
||||
!
|
||||
! Bold, Italic, Underline
|
||||
!*.colorBD:
|
||||
!*.colorIT:
|
||||
!*.colorUL:
|
@@ -1,44 +0,0 @@
|
||||
!
|
||||
! Night Owl
|
||||
! https://github.com/sdras/night-owl-vscode-theme
|
||||
!
|
||||
*.foreground: #d6deeb
|
||||
*.background: #011627
|
||||
*.cursorColor: #80a4c2
|
||||
!
|
||||
! Black
|
||||
*.color0: #011627
|
||||
*.color8: #969696
|
||||
!
|
||||
! Red
|
||||
*.color1: #ef5350
|
||||
*.color9: #ef5350
|
||||
!
|
||||
! Green
|
||||
*.color2: #22da6e
|
||||
*.color10: #22da6e
|
||||
!
|
||||
! Yellow
|
||||
*.color3: #addb67
|
||||
*.color11: #ffeb95
|
||||
!
|
||||
! Blue
|
||||
*.color4: #82aaff
|
||||
*.color12: #82aaff
|
||||
!
|
||||
! Magenta
|
||||
*.color5: #c792ea
|
||||
*.color13: #c792ea
|
||||
!
|
||||
! Cyan
|
||||
*.color6: #21c7a8
|
||||
*.color14: #7fdbca
|
||||
!
|
||||
! White
|
||||
*.color7: #ffffff
|
||||
*.color15: #ffffff
|
||||
!
|
||||
! Bold, Italic, Underline
|
||||
!*.colorBD:
|
||||
!*.colorIT:
|
||||
!*.colorUL:
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tabby-core",
|
||||
"version": "1.0.170-nightly.0",
|
||||
"version": "1.0.165-nightly.0",
|
||||
"description": "Tabby core",
|
||||
"keywords": [
|
||||
"tabby-builtin-plugin"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
export { BaseComponent, SubscriptionContainer } from '../components/base.component'
|
||||
export { BaseTabComponent, BaseTabProcess, GetRecoveryTokenOptions } from '../components/baseTab.component'
|
||||
export { BaseTabComponent, BaseTabProcess } from '../components/baseTab.component'
|
||||
export { TabHeaderComponent } from '../components/tabHeader.component'
|
||||
export { SplitTabComponent, SplitContainer, SplitDirection, SplitOrientation } from '../components/splitTab.component'
|
||||
export { TabRecoveryProvider, RecoveryToken } from './tabRecovery'
|
||||
@@ -35,5 +35,5 @@ export { TabsService, NewTabParameters, TabComponentType } from '../services/tab
|
||||
export { UpdaterService } from '../services/updater.service'
|
||||
export { VaultService, Vault, VaultSecret, VaultFileSecret, VAULT_SECRET_TYPE_FILE, StoredVault, VaultSecretKey } from '../services/vault.service'
|
||||
export { FileProvidersService } from '../services/fileProviders.service'
|
||||
export { LocaleService, TranslateServiceWrapper as TranslateService } from '../services/locale.service'
|
||||
export { LocaleService } from '../services/locale.service'
|
||||
export * from '../utils'
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import deepClone from 'clone-deep'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { NewTabParameters } from '../services/tabs.service'
|
||||
|
||||
@@ -37,4 +38,14 @@ export abstract class TabRecoveryProvider <T extends BaseTabComponent> {
|
||||
* or `null` if this token is from a different tab type or is not supported
|
||||
*/
|
||||
abstract recover (recoveryToken: RecoveryToken): Promise<NewTabParameters<T>>
|
||||
|
||||
/**
|
||||
* @param recoveryToken a recovery token found in the saved tabs list
|
||||
* @returns [[RecoveryToken]] a new recovery token to create the duplicate tab from
|
||||
*
|
||||
* The default implementation just returns a deep copy of the original token
|
||||
*/
|
||||
duplicate (recoveryToken: RecoveryToken): RecoveryToken {
|
||||
return deepClone(recoveryToken)
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
|
||||
import { ToolbarButton, ToolbarButtonProvider } from './api/toolbarButtonProvider'
|
||||
import { HostAppService, Platform } from './api/hostApp'
|
||||
@@ -13,7 +12,6 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
private profilesService: ProfilesService,
|
||||
private translate: TranslateService,
|
||||
hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
@@ -37,7 +35,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
icon: this.hostApp.platform === Platform.Web
|
||||
? require('./icons/plus.svg')
|
||||
: require('./icons/profiles.svg'),
|
||||
title: this.translate.instant('Profiles & connections'),
|
||||
title: 'Profiles and connections',
|
||||
click: () => this.activate(),
|
||||
},
|
||||
...this.profilesService.getRecentProfiles().map(profile => ({
|
||||
|
@@ -88,7 +88,7 @@ $side-tab-width: 200px;
|
||||
padding: 0 12px;
|
||||
flex: 0 0 auto;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: 0.125s all ease-out;
|
||||
transition: 0.25s all;
|
||||
font-size: 12px;
|
||||
|
||||
text-transform: uppercase;
|
||||
|
@@ -14,7 +14,6 @@ import { UpdaterService } from '../services/updater.service'
|
||||
import { BaseTabComponent } from './baseTab.component'
|
||||
import { SafeModeModalComponent } from './safeModeModal.component'
|
||||
import { TabBodyComponent } from './tabBody.component'
|
||||
import { SplitTabComponent } from './splitTab.component'
|
||||
import { AppService, FileTransfer, HostWindowService, PlatformService, ToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@@ -197,13 +196,6 @@ export class AppRootComponent {
|
||||
}
|
||||
|
||||
onTabsReordered (event: CdkDragDrop<BaseTabComponent[]>) {
|
||||
const tab: BaseTabComponent = event.item.data
|
||||
if (!this.app.tabs.includes(tab)) {
|
||||
if (tab.parent instanceof SplitTabComponent) {
|
||||
tab.parent.removeTab(tab)
|
||||
this.app.wrapAndAddTab(tab)
|
||||
}
|
||||
}
|
||||
moveItemInArray(this.app.tabs, event.previousIndex, event.currentIndex)
|
||||
this.app.emitTabsChanged()
|
||||
}
|
||||
@@ -214,10 +206,6 @@ export class AppRootComponent {
|
||||
}
|
||||
}
|
||||
|
||||
@HostBinding('class.vibrant') get isVibrant () {
|
||||
return this.config.store.appearance.vibrancy
|
||||
}
|
||||
|
||||
private getToolbarButtons (aboveZero: boolean): ToolbarButton[] {
|
||||
let buttons: ToolbarButton[] = []
|
||||
this.config.enabledServices(this.toolbarButtonProviders).forEach(provider => {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Observable, Subject, distinctUntilChanged, filter, debounceTime } from 'rxjs'
|
||||
import { Observable, Subject, distinctUntilChanged } from 'rxjs'
|
||||
import { EmbeddedViewRef, ViewContainerRef, ViewRef } from '@angular/core'
|
||||
import { RecoveryToken } from '../api/tabRecovery'
|
||||
import { BaseComponent } from './base.component'
|
||||
@@ -11,10 +11,6 @@ export interface BaseTabProcess {
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface GetRecoveryTokenOptions {
|
||||
includeState: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base class for custom tab components
|
||||
*/
|
||||
@@ -47,9 +43,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
/**
|
||||
* CSS color override for the tab's header
|
||||
*/
|
||||
get color (): string|null { return this._color }
|
||||
set color (value: string|null) { this._color = value }
|
||||
private _color: string|null = null
|
||||
color: string|null = null
|
||||
|
||||
hasFocus = false
|
||||
|
||||
@@ -63,6 +57,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
/* @hidden */
|
||||
viewContainerEmbeddedRef?: EmbeddedViewRef<any>
|
||||
|
||||
private progressClearTimeout: number
|
||||
private titleChange = new Subject<string>()
|
||||
private focused = new Subject<void>()
|
||||
private blurred = new Subject<void>()
|
||||
@@ -88,12 +83,6 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
this.blurred$.subscribe(() => {
|
||||
this.hasFocus = false
|
||||
})
|
||||
this.subscribeUntilDestroyed(this.progress.pipe(
|
||||
filter(x => x !== null),
|
||||
debounceTime(5000),
|
||||
), () => {
|
||||
this.setProgress(null)
|
||||
})
|
||||
}
|
||||
|
||||
setTitle (title: string): void {
|
||||
@@ -110,6 +99,14 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
*/
|
||||
setProgress (progress: number|null): void {
|
||||
this.progress.next(progress)
|
||||
if (progress) {
|
||||
if (this.progressClearTimeout) {
|
||||
clearTimeout(this.progressClearTimeout)
|
||||
}
|
||||
this.progressClearTimeout = setTimeout(() => {
|
||||
this.setProgress(null)
|
||||
}, 5000) as any
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +136,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
* @return JSON serializable tab state representation
|
||||
* for your [[TabRecoveryProvider]] to parse
|
||||
*/
|
||||
async getRecoveryToken (options?: GetRecoveryTokenOptions): Promise<RecoveryToken|null> { // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
async getRecoveryToken (): Promise<RecoveryToken|null> {
|
||||
return null
|
||||
}
|
||||
|
||||
|
@@ -2,5 +2,5 @@
|
||||
input.form-control(type='text', #input, [(ngModel)]='value', (keyup.enter)='save()', autofocus)
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-primary((click)='save()', translate) Save
|
||||
button.btn.btn-secondary((click)='close()', translate) Cancel
|
||||
button.btn.btn-primary((click)='save()') Save
|
||||
button.btn.btn-secondary((click)='close()') Cancel
|
||||
|
@@ -1,7 +1,7 @@
|
||||
.modal-body
|
||||
.alert.alert-danger(translate) Tabby could not start with your plugins, so all third party plugins have been disabled in this session. The error was:
|
||||
.alert.alert-danger Tabby could not start with your plugins, so all third party plugins have been disabled in this session. The error was:
|
||||
|
||||
pre {{error}}
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-primary((click)='close()', translate) Close
|
||||
button.btn.btn-primary((click)='close()') Close
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { Component, Injectable, ViewChild, ViewContainerRef, EmbeddedViewRef, AfterViewInit, OnDestroy } from '@angular/core'
|
||||
import { BaseTabComponent, BaseTabProcess, GetRecoveryTokenOptions } from './baseTab.component'
|
||||
import { BaseTabComponent, BaseTabProcess } from './baseTab.component'
|
||||
import { TabRecoveryProvider, RecoveryToken } from '../api/tabRecovery'
|
||||
import { TabsService, NewTabParameters } from '../services/tabs.service'
|
||||
import { HotkeysService } from '../services/hotkeys.service'
|
||||
@@ -93,13 +93,13 @@ export class SplitContainer {
|
||||
return s
|
||||
}
|
||||
|
||||
async serialize (tabsRecovery: TabRecoveryService, options?: GetRecoveryTokenOptions): Promise<RecoveryToken> {
|
||||
async serialize (tabsRecovery: TabRecoveryService): Promise<RecoveryToken> {
|
||||
const children: any[] = []
|
||||
for (const child of this.children) {
|
||||
if (child instanceof SplitContainer) {
|
||||
children.push(await child.serialize(tabsRecovery, options))
|
||||
children.push(await child.serialize(tabsRecovery))
|
||||
} else {
|
||||
children.push(await tabsRecovery.getFullRecoveryToken(child, options))
|
||||
children.push(await tabsRecovery.getFullRecoveryToken(child))
|
||||
}
|
||||
}
|
||||
return {
|
||||
@@ -158,7 +158,6 @@ export type SplitDropZoneInfo = {
|
||||
></split-tab-spanner>
|
||||
<split-tab-drop-zone
|
||||
*ngFor='let dropZone of _dropZones'
|
||||
[enabled]='dropZonesEnabled'
|
||||
[parent]='this'
|
||||
[dropZone]='dropZone'
|
||||
(tabDropped)='onTabDropped($event, dropZone)'
|
||||
@@ -254,9 +253,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
})
|
||||
this.blurred$.subscribe(() => this.getAllTabs().forEach(x => x.emitBlurred()))
|
||||
|
||||
this.tabAdded$.subscribe(() => this.updateTitle())
|
||||
this.tabRemoved$.subscribe(() => this.updateTitle())
|
||||
|
||||
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, hotkey => {
|
||||
if (!this.hasFocus || !this.focusedTab) {
|
||||
return
|
||||
@@ -309,7 +305,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
/** @hidden */
|
||||
async ngAfterViewInit (): Promise<void> {
|
||||
if (this._recoveredState) {
|
||||
await this.recoverContainer(this.root, this._recoveredState)
|
||||
await this.recoverContainer(this.root, this._recoveredState, this._recoveredState.duplicate)
|
||||
this.updateTitle()
|
||||
this.layout()
|
||||
setTimeout(() => {
|
||||
@@ -575,8 +571,8 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
async getRecoveryToken (options?: GetRecoveryTokenOptions): Promise<any> {
|
||||
return this.root.serialize(this.tabRecovery, options)
|
||||
async getRecoveryToken (): Promise<any> {
|
||||
return this.root.serialize(this.tabRecovery)
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@@ -604,10 +600,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
this.tabAdopted.next(tab)
|
||||
}
|
||||
|
||||
get dropZonesEnabled (): boolean {
|
||||
return this.getAllTabs().length > 1
|
||||
}
|
||||
|
||||
destroy (): void {
|
||||
super.destroy()
|
||||
for (const x of this.getAllTabs()) {
|
||||
@@ -629,16 +621,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
super.clearActivity()
|
||||
}
|
||||
|
||||
get color (): string|null {
|
||||
return this.getFocusedTab()?.color ?? null
|
||||
}
|
||||
|
||||
set color (color: string|null) {
|
||||
for (const t of this.getAllTabs()) {
|
||||
t.color = color
|
||||
}
|
||||
}
|
||||
|
||||
private updateTitle (): void {
|
||||
this.setTitle(this.getAllTabs().map(x => x.title).join(' | '))
|
||||
}
|
||||
@@ -810,7 +792,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
})
|
||||
}
|
||||
|
||||
private async recoverContainer (root: SplitContainer, state: any) {
|
||||
private async recoverContainer (root: SplitContainer, state: any, duplicate = false) {
|
||||
const children: (SplitContainer | BaseTabComponent)[] = []
|
||||
root.orientation = state.orientation
|
||||
root.ratios = state.ratios
|
||||
@@ -821,10 +803,10 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
}
|
||||
if (childState.type === 'app:split-tab') {
|
||||
const child = new SplitContainer()
|
||||
await this.recoverContainer(child, childState)
|
||||
await this.recoverContainer(child, childState, duplicate)
|
||||
children.push(child)
|
||||
} else {
|
||||
const recovered = await this.tabRecovery.recoverTab(childState)
|
||||
const recovered = await this.tabRecovery.recoverTab(childState, duplicate)
|
||||
if (recovered) {
|
||||
const tab = this.tabsService.create(recovered)
|
||||
children.push(tab)
|
||||
@@ -855,4 +837,11 @@ export class SplitTabRecoveryProvider extends TabRecoveryProvider<SplitTabCompon
|
||||
inputs: { _recoveredState: recoveryToken },
|
||||
}
|
||||
}
|
||||
|
||||
duplicate (recoveryToken: RecoveryToken): RecoveryToken {
|
||||
return {
|
||||
...recoveryToken,
|
||||
duplicate: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,32 +23,22 @@ import { SplitDropZoneInfo } from './splitTab.component'
|
||||
export class SplitTabDropZoneComponent extends SelfPositioningComponent {
|
||||
@Input() dropZone: SplitDropZoneInfo
|
||||
@Input() parent: BaseTabComponent
|
||||
@Input() enabled = false
|
||||
@Output() tabDropped = new EventEmitter<BaseTabComponent>()
|
||||
@HostBinding('class.active') isActive = false
|
||||
@HostBinding('class.highlighted') isHighlighted = false
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
constructor (
|
||||
element: ElementRef,
|
||||
app: AppService,
|
||||
) {
|
||||
super(element)
|
||||
this.subscribeUntilDestroyed(app.tabDragActive$, tab => {
|
||||
this.isActive = !!(tab && this.canActivateFor(tab))
|
||||
this.isActive = !!tab && tab !== this.parent && (this.dropZone.type === 'relative' || tab !== this.dropZone.container.children[this.dropZone.position])
|
||||
this.layout()
|
||||
})
|
||||
}
|
||||
|
||||
canActivateFor (tab: BaseTabComponent) {
|
||||
if (tab === this.parent || !this.enabled) {
|
||||
return false
|
||||
}
|
||||
if (this.dropZone.type === 'absolute' && tab === this.dropZone.container.children[this.dropZone.position]) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
ngOnChanges () {
|
||||
this.layout()
|
||||
}
|
||||
|
@@ -18,6 +18,6 @@ footer.d-flex.align-items-center
|
||||
span GitHub
|
||||
button.btn.btn-dark((click)='homeBase.reportBug()')
|
||||
i.fas.fa-bug
|
||||
span(translate) Report a problem
|
||||
span Report a problem
|
||||
|
||||
.form-control-static.selectable.no-drag {{ 'Version: {version}'|translate:{ version: this.homeBase.appVersion } }}
|
||||
.form-control-static.selectable.no-drag Version: {{homeBase.appVersion}}
|
||||
|
@@ -37,7 +37,6 @@ $tabs-height: 38px;
|
||||
text-align: center;
|
||||
transition: 0.25s all;
|
||||
align-self: center;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.name {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component, Input, Optional, Inject, HostBinding, HostListener, NgZone } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { auditTime } from 'rxjs'
|
||||
import { TabContextMenuItemProvider } from '../api/tabContextMenuProvider'
|
||||
import { BaseTabComponent } from './baseTab.component'
|
||||
import { RenameTabModalComponent } from './renameTabModal.component'
|
||||
@@ -48,9 +47,7 @@ export class TabHeaderComponent extends BaseComponent {
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.subscribeUntilDestroyed(this.tab.progress$.pipe(
|
||||
auditTime(300),
|
||||
), progress => {
|
||||
this.subscribeUntilDestroyed(this.tab.progress$, progress => {
|
||||
this.zone.run(() => {
|
||||
this.progress = progress
|
||||
})
|
||||
|
@@ -1,5 +1,5 @@
|
||||
.d-flex.align-items-center
|
||||
.dropdown-header(translate) File transfers
|
||||
.dropdown-header File transfers
|
||||
button.btn.btn-link.ml-auto((click)='removeAll(); $event.stopPropagation()') !{require('../icons/times.svg')}
|
||||
.transfer(*ngFor='let transfer of transfers', (click)='showTransfer(transfer)')
|
||||
.icon(*ngIf='isDownload(transfer)') !{require('../icons/download.svg')}
|
||||
@@ -16,11 +16,4 @@
|
||||
.size {{transfer.getSize()|filesize}}
|
||||
.speed(*ngIf='transfer.getSpeed()') {{transfer.getSpeed()|filesize}}/s
|
||||
|
||||
button.btn.btn-link(
|
||||
*ngIf='!transfer.isComplete()',
|
||||
(click)='removeTransfer(transfer); $event.stopPropagation()'
|
||||
) !{require('../icons/times.svg')}
|
||||
button.btn.btn-link(
|
||||
*ngIf='transfer.isComplete()',
|
||||
(click)='removeTransfer(transfer); $event.stopPropagation()'
|
||||
) !{require('../icons/check.svg')}
|
||||
button.btn.btn-link((click)='removeTransfer(transfer); $event.stopPropagation()') !{require('../icons/times.svg')}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { FileDownload, FileTransfer, PlatformService } from '../api/platform'
|
||||
|
||||
/** @hidden */
|
||||
@@ -12,10 +11,7 @@ export class TransfersMenuComponent {
|
||||
@Input() transfers: FileTransfer[]
|
||||
@Output() transfersChange = new EventEmitter<FileTransfer[]>()
|
||||
|
||||
constructor (
|
||||
private platform: PlatformService,
|
||||
private translate: TranslateService,
|
||||
) { }
|
||||
constructor (private platform: PlatformService) { }
|
||||
|
||||
isDownload (transfer: FileTransfer): boolean {
|
||||
return transfer instanceof FileDownload
|
||||
@@ -44,11 +40,8 @@ export class TransfersMenuComponent {
|
||||
if (this.transfers.some(x => !x.isComplete())) {
|
||||
if ((await this.platform.showMessageBox({
|
||||
type: 'warning',
|
||||
message: this.translate.instant('There are active file transfers'),
|
||||
buttons: [
|
||||
this.translate.instant('Abort all'),
|
||||
this.translate.instant('Do not abort'),
|
||||
],
|
||||
message: 'There are active file transfers',
|
||||
buttons: ['Abort all', 'Do not abort'],
|
||||
defaultId: 1,
|
||||
cancelId: 1,
|
||||
})).response === 1) {
|
||||
|
@@ -1,16 +1,13 @@
|
||||
.modal-body
|
||||
.d-flex.align-items-center.mb-3
|
||||
h3.m-0(translate) Vault is locked
|
||||
h3.m-0 Vault is locked
|
||||
.ml-auto(ngbDropdown, placement='bottom-right')
|
||||
button.btn.btn-link(ngbDropdownToggle, (click)='$event.stopPropagation()')
|
||||
span(
|
||||
*ngIf='rememberFor'
|
||||
) {{ 'Remember for {time}'|translate:{time: getRememberForDisplay(rememberFor)} }}
|
||||
span(*ngIf='!rememberFor', translate) Do not remember
|
||||
span(*ngIf='rememberFor') Remember for {{getRememberForDisplay(rememberFor)}}
|
||||
span(*ngIf='!rememberFor') Do not remember
|
||||
div(ngbDropdownMenu)
|
||||
button.dropdown-item(
|
||||
(click)='rememberFor = 0',
|
||||
translate
|
||||
) Do not remember
|
||||
button.dropdown-item(
|
||||
*ngFor='let x of rememberOptions',
|
||||
|
@@ -4,31 +4,21 @@
|
||||
h1.tabby-title Tabby
|
||||
sup α
|
||||
|
||||
.text-center.mb-5(translate) Thank you for downloading Tabby!
|
||||
.text-center.mb-5 Thank you for downloading Tabby!
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title(translate) Language
|
||||
select.form-control([(ngModel)]='config.store.language', (ngModelChange)='config.save()')
|
||||
option([ngValue]='null', translate) Automatic
|
||||
option(
|
||||
[value]='lang.code',
|
||||
*ngFor='let lang of locale.allLanguages'
|
||||
) {{lang.name|translate}}
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title(translate) Enable analytics
|
||||
.description(translate) Help track the number of Tabby installs across the world!
|
||||
.title Enable analytics
|
||||
.description Help track the number of Tabby installs across the world!
|
||||
toggle([(ngModel)]='config.store.enableAnalytics')
|
||||
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title(translate) Enable global hotkey (Ctrl-Space)
|
||||
.description(translate) Toggles the Tabby window visibility
|
||||
.title Enable global hotkey (#[strong Ctrl-Space])
|
||||
.description Toggles the Tabby window visibility
|
||||
toggle([(ngModel)]='enableGlobalHotkey')
|
||||
|
||||
|
||||
.text-center.mt-5
|
||||
button.btn.btn-primary((click)='closeAndDisable()', translate) Close and never show again
|
||||
button.btn.btn-primary((click)='closeAndDisable()') Close and never show again
|
||||
|
@@ -1,9 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { BaseTabComponent } from './baseTab.component'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { LocaleService } from '../services/locale.service'
|
||||
import { HostWindowService } from '../api/hostWindow'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
@@ -15,12 +14,11 @@ export class WelcomeTabComponent extends BaseTabComponent {
|
||||
enableGlobalHotkey = true
|
||||
|
||||
constructor (
|
||||
private hostWindow: HostWindowService,
|
||||
public config: ConfigService,
|
||||
public locale: LocaleService,
|
||||
translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
this.setTitle(translate.instant('Welcome'))
|
||||
this.setTitle('Welcome')
|
||||
}
|
||||
|
||||
async closeAndDisable () {
|
||||
@@ -30,6 +28,6 @@ export class WelcomeTabComponent extends BaseTabComponent {
|
||||
this.config.store.hotkeys['toggle-window'] = []
|
||||
}
|
||||
await this.config.save()
|
||||
this.destroy()
|
||||
this.hostWindow.reload()
|
||||
}
|
||||
}
|
||||
|
@@ -75,5 +75,3 @@ hotkeys:
|
||||
- '⌘-E'
|
||||
switch-profile:
|
||||
- '⌘-Shift-E'
|
||||
appearance:
|
||||
vibrancy: true
|
||||
|
@@ -38,4 +38,4 @@ enableExperimentalFeatures: false
|
||||
pluginBlacklist: []
|
||||
hacks:
|
||||
disableGPU: false
|
||||
language: null
|
||||
language: en
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { ProfilesService } from './services/profiles.service'
|
||||
import { HotkeyDescription, HotkeyProvider } from './api/hotkeyProvider'
|
||||
import { PartialProfile, Profile } from './api'
|
||||
@@ -10,189 +9,188 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
||||
hotkeys: HotkeyDescription[] = [
|
||||
{
|
||||
id: 'profile-selector',
|
||||
name: this.translate.instant('Show profile selector'),
|
||||
name: 'Show profile selector',
|
||||
},
|
||||
{
|
||||
id: 'toggle-fullscreen',
|
||||
name: this.translate.instant('Toggle fullscreen mode'),
|
||||
name: 'Toggle fullscreen mode',
|
||||
},
|
||||
{
|
||||
id: 'rename-tab',
|
||||
name: this.translate.instant('Rename Tab'),
|
||||
name: 'Rename Tab',
|
||||
},
|
||||
{
|
||||
id: 'close-tab',
|
||||
name: this.translate.instant('Close tab'),
|
||||
name: 'Close tab',
|
||||
},
|
||||
{
|
||||
id: 'reopen-tab',
|
||||
name: this.translate.instant('Reopen last tab'),
|
||||
name: 'Reopen last tab',
|
||||
},
|
||||
{
|
||||
id: 'toggle-last-tab',
|
||||
name: this.translate.instant('Toggle last tab'),
|
||||
name: 'Toggle last tab',
|
||||
},
|
||||
{
|
||||
id: 'next-tab',
|
||||
name: this.translate.instant('Next tab'),
|
||||
name: 'Next tab',
|
||||
},
|
||||
{
|
||||
id: 'previous-tab',
|
||||
name: this.translate.instant('Previous tab'),
|
||||
name: 'Previous tab',
|
||||
},
|
||||
{
|
||||
id: 'move-tab-left',
|
||||
name: this.translate.instant('Move tab to the left'),
|
||||
name: 'Move tab to the left',
|
||||
},
|
||||
{
|
||||
id: 'move-tab-right',
|
||||
name: this.translate.instant('Move tab to the right'),
|
||||
name: 'Move tab to the right',
|
||||
},
|
||||
{
|
||||
id: 'rearrange-panes',
|
||||
name: this.translate.instant('Show pane labels (for rearranging)'),
|
||||
name: 'Show pane labels (for rearranging)',
|
||||
},
|
||||
{
|
||||
id: 'duplicate-tab',
|
||||
name: this.translate.instant('Duplicate tab'),
|
||||
name: 'Duplicate tab',
|
||||
},
|
||||
{
|
||||
id: 'tab-1',
|
||||
name: this.translate.instant('Tab {number}', { number: 1 }),
|
||||
name: 'Tab 1',
|
||||
},
|
||||
{
|
||||
id: 'tab-2',
|
||||
name: this.translate.instant('Tab {number}', { number: 2 }),
|
||||
name: 'Tab 2',
|
||||
},
|
||||
{
|
||||
id: 'tab-3',
|
||||
name: this.translate.instant('Tab {number}', { number: 3 }),
|
||||
name: 'Tab 3',
|
||||
},
|
||||
{
|
||||
id: 'tab-4',
|
||||
name: this.translate.instant('Tab {number}', { number: 4 }),
|
||||
name: 'Tab 4',
|
||||
},
|
||||
{
|
||||
id: 'tab-5',
|
||||
name: this.translate.instant('Tab {number}', { number: 5 }),
|
||||
name: 'Tab 5',
|
||||
},
|
||||
{
|
||||
id: 'tab-6',
|
||||
name: this.translate.instant('Tab {number}', { number: 6 }),
|
||||
name: 'Tab 6',
|
||||
},
|
||||
{
|
||||
id: 'tab-7',
|
||||
name: this.translate.instant('Tab {number}', { number: 7 }),
|
||||
name: 'Tab 7',
|
||||
},
|
||||
{
|
||||
id: 'tab-8',
|
||||
name: this.translate.instant('Tab {number}', { number: 8 }),
|
||||
name: 'Tab 8',
|
||||
},
|
||||
{
|
||||
id: 'tab-9',
|
||||
name: this.translate.instant('Tab {number}', { number: 9 }),
|
||||
name: 'Tab 9',
|
||||
},
|
||||
{
|
||||
id: 'tab-10',
|
||||
name: this.translate.instant('Tab {number}', { number: 10 }),
|
||||
name: 'Tab 10',
|
||||
},
|
||||
{
|
||||
id: 'tab-11',
|
||||
name: this.translate.instant('Tab {number}', { number: 11 }),
|
||||
name: 'Tab 11',
|
||||
},
|
||||
{
|
||||
id: 'tab-12',
|
||||
name: this.translate.instant('Tab {number}', { number: 12 }),
|
||||
name: 'Tab 12',
|
||||
},
|
||||
{
|
||||
id: 'tab-13',
|
||||
name: this.translate.instant('Tab {number}', { number: 13 }),
|
||||
name: 'Tab 13',
|
||||
},
|
||||
{
|
||||
id: 'tab-14',
|
||||
name: this.translate.instant('Tab {number}', { number: 14 }),
|
||||
name: 'Tab 14',
|
||||
},
|
||||
{
|
||||
id: 'tab-15',
|
||||
name: this.translate.instant('Tab {number}', { number: 15 }),
|
||||
name: 'Tab 15',
|
||||
},
|
||||
{
|
||||
id: 'tab-16',
|
||||
name: this.translate.instant('Tab {number}', { number: 16 }),
|
||||
name: 'Tab 16',
|
||||
},
|
||||
{
|
||||
id: 'tab-17',
|
||||
name: this.translate.instant('Tab {number}', { number: 17 }),
|
||||
name: 'Tab 17',
|
||||
},
|
||||
{
|
||||
id: 'tab-18',
|
||||
name: this.translate.instant('Tab {number}', { number: 18 }),
|
||||
name: 'Tab 18',
|
||||
},
|
||||
{
|
||||
id: 'tab-19',
|
||||
name: this.translate.instant('Tab {number}', { number: 19 }),
|
||||
name: 'Tab 19',
|
||||
},
|
||||
{
|
||||
id: 'tab-20',
|
||||
name: this.translate.instant('Tab {number}', { number: 20 }),
|
||||
name: 'Tab 20',
|
||||
},
|
||||
{
|
||||
id: 'split-right',
|
||||
name: this.translate.instant('Split to the right'),
|
||||
name: 'Split to the right',
|
||||
},
|
||||
{
|
||||
id: 'split-bottom',
|
||||
name: this.translate.instant('Split to the bottom'),
|
||||
name: 'Split to the bottom',
|
||||
},
|
||||
{
|
||||
id: 'split-left',
|
||||
name: this.translate.instant('Split to the left'),
|
||||
name: 'Split to the left',
|
||||
},
|
||||
{
|
||||
id: 'split-top',
|
||||
name: this.translate.instant('Split to the top'),
|
||||
name: 'Split to the top',
|
||||
},
|
||||
{
|
||||
id: 'pane-maximize',
|
||||
name: this.translate.instant('Maximize the active pane'),
|
||||
name: 'Maximize the active pane',
|
||||
},
|
||||
{
|
||||
id: 'pane-nav-up',
|
||||
name: this.translate.instant('Focus the pane above'),
|
||||
name: 'Focus the pane above',
|
||||
},
|
||||
{
|
||||
id: 'pane-nav-down',
|
||||
name: this.translate.instant('Focus the pane below'),
|
||||
name: 'Focus the pane below',
|
||||
},
|
||||
{
|
||||
id: 'pane-nav-left',
|
||||
name: this.translate.instant('Focus the pane on the left'),
|
||||
name: 'Focus the pane on the left',
|
||||
},
|
||||
{
|
||||
id: 'pane-nav-right',
|
||||
name: this.translate.instant('Focus the pane on the right'),
|
||||
name: 'Focus the pane on the right',
|
||||
},
|
||||
{
|
||||
id: 'pane-nav-previous',
|
||||
name: this.translate.instant('Focus previous pane'),
|
||||
name: 'Focus previous pane',
|
||||
},
|
||||
{
|
||||
id: 'pane-nav-next',
|
||||
name: this.translate.instant('Focus next pane'),
|
||||
name: 'Focus next pane',
|
||||
},
|
||||
{
|
||||
id: 'switch-profile',
|
||||
name: this.translate.instant('Switch profile in the active pane'),
|
||||
name: 'Switch profile in the active pane',
|
||||
},
|
||||
{
|
||||
id: 'close-pane',
|
||||
name: this.translate.instant('Close focused pane'),
|
||||
name: 'Close focused pane',
|
||||
},
|
||||
]
|
||||
|
||||
constructor (
|
||||
private profilesService: ProfilesService,
|
||||
private translate: TranslateService,
|
||||
) { super() }
|
||||
|
||||
async provide (): Promise<HotkeyDescription[]> {
|
||||
@@ -201,11 +199,11 @@ export class AppHotkeyProvider extends HotkeyProvider {
|
||||
...this.hotkeys,
|
||||
...profiles.map(profile => ({
|
||||
id: `profile.${AppHotkeyProvider.getProfileHotkeyName(profile)}`,
|
||||
name: this.translate.instant('New tab: {profile}', { profile: profile.name }),
|
||||
name: `New tab: ${profile.name}`,
|
||||
})),
|
||||
...this.profilesService.getProviders().map(provider => ({
|
||||
id: `profile-selectors.${provider.id}`,
|
||||
name: this.translate.instant('Show {type} profile selector', { type: provider.name }),
|
||||
name: `Show ${provider.name} profile selector`,
|
||||
})),
|
||||
]
|
||||
}
|
||||
|
@@ -1 +0,0 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="check" class="svg-inline--fa fa-check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M480.1 128.1l-272 272C204.3 405.7 198.2 408 192 408s-12.28-2.344-16.97-7.031l-144-144c-9.375-9.375-9.375-24.56 0-33.94s24.56-9.375 33.94 0L192 350.1l255-255c9.375-9.375 24.56-9.375 33.94 0S490.3 119.6 480.1 128.1z"></path></svg>
|
Before Width: | Height: | Size: 436 B |
@@ -149,7 +149,6 @@ const PROVIDERS = [
|
||||
SortablejsModule,
|
||||
DragDropModule,
|
||||
TranslateModule,
|
||||
CdkAutoDropGroup,
|
||||
],
|
||||
})
|
||||
export default class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class
|
||||
@@ -158,8 +157,6 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
config: ConfigService,
|
||||
platform: PlatformService,
|
||||
hotkeys: HotkeysService,
|
||||
public locale: LocaleService,
|
||||
private translate: TranslateService,
|
||||
private profilesService: ProfilesService,
|
||||
private selector: SelectorService,
|
||||
) {
|
||||
@@ -207,8 +204,8 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
|
||||
if (provider.supportsQuickConnect) {
|
||||
options.push({
|
||||
name: this.translate.instant('Quick connect'),
|
||||
freeInputPattern: this.translate.instant('Connect to "%s"...'),
|
||||
name: 'Quick connect',
|
||||
freeInputPattern: 'Connect to "%s"...',
|
||||
icon: 'fas fa-arrow-right',
|
||||
callback: query => {
|
||||
const p = provider.quickConnect(query)
|
||||
@@ -219,7 +216,7 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
|
||||
})
|
||||
}
|
||||
|
||||
await this.selector.show(this.translate.instant('Select profile'), options)
|
||||
await this.selector.show('Select profile', options)
|
||||
}
|
||||
|
||||
static forRoot (): ModuleWithProviders<AppModule> {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import slugify from 'slugify'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { ConfigService, NewTabParameters, PartialProfile, Profile, ProfileProvider } from './api'
|
||||
import { SplitTabComponent, SplitTabRecoveryProvider } from './components/splitTab.component'
|
||||
|
||||
@@ -16,7 +15,7 @@ export interface SplitLayoutProfile extends Profile {
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SplitLayoutProfilesService extends ProfileProvider<SplitLayoutProfile> {
|
||||
id = 'split-layout'
|
||||
name = this.translate.instant('Saved layout')
|
||||
name = 'Saved layout'
|
||||
configDefaults = {
|
||||
options: {
|
||||
recoveryToken: null,
|
||||
@@ -26,7 +25,6 @@ export class SplitLayoutProfilesService extends ProfileProvider<SplitLayoutProfi
|
||||
constructor (
|
||||
private splitTabRecoveryProvider: SplitTabRecoveryProvider,
|
||||
private config: ConfigService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
@@ -44,7 +42,7 @@ export class SplitLayoutProfilesService extends ProfileProvider<SplitLayoutProfi
|
||||
}
|
||||
|
||||
async createProfile (tab: SplitTabComponent, name: string): Promise<void> {
|
||||
const token = await tab.getRecoveryToken({ includeState: false })
|
||||
const token = await tab.getRecoveryToken()
|
||||
const profile: PartialProfile<SplitLayoutProfile> = {
|
||||
id: `${this.id}:custom:${slugify(name)}:${uuidv4()}`,
|
||||
type: this.id,
|
||||
|
@@ -170,19 +170,11 @@ export class AppService {
|
||||
if (params.type as any === SplitTabComponent) {
|
||||
return this.openNewTabRaw(params)
|
||||
}
|
||||
const tab = this.tabsService.create(params)
|
||||
this.wrapAndAddTab(tab)
|
||||
return tab
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an existing tab while wrapping it in a SplitTabComponent
|
||||
*/
|
||||
wrapAndAddTab (tab: BaseTabComponent): SplitTabComponent {
|
||||
const splitTab = this.tabsService.create({ type: SplitTabComponent })
|
||||
const tab = this.tabsService.create(params)
|
||||
splitTab.addTab(tab, null, 'r')
|
||||
this.addTabRaw(splitTab)
|
||||
return splitTab
|
||||
return tab
|
||||
}
|
||||
|
||||
async reopenLastTab (): Promise<BaseTabComponent|null> {
|
||||
@@ -318,10 +310,9 @@ export class AppService {
|
||||
if (checkCanClose && !await tab.canClose()) {
|
||||
return
|
||||
}
|
||||
const token = await this.tabRecovery.getFullRecoveryToken(tab, { includeState: true })
|
||||
const token = await this.tabRecovery.getFullRecoveryToken(tab)
|
||||
if (token) {
|
||||
this.closedTabsStack.push(token)
|
||||
this.closedTabsStack = this.closedTabsStack.slice(-5)
|
||||
}
|
||||
tab.destroy()
|
||||
}
|
||||
|
@@ -2,9 +2,8 @@ import deepClone from 'clone-deep'
|
||||
import deepEqual from 'deep-equal'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { Observable, Subject, AsyncSubject, lastValueFrom } from 'rxjs'
|
||||
import { Observable, Subject, AsyncSubject } from 'rxjs'
|
||||
import { Injectable, Inject } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { ConfigProvider } from '../api/configProvider'
|
||||
import { PlatformService } from '../api/platform'
|
||||
import { HostAppService } from '../api/hostApp'
|
||||
@@ -137,7 +136,6 @@ export class ConfigService {
|
||||
private hostApp: HostAppService,
|
||||
private platform: PlatformService,
|
||||
private vault: VaultService,
|
||||
private translate: TranslateService,
|
||||
@Inject(ConfigProvider) private configProviders: ConfigProvider[],
|
||||
) {
|
||||
this.defaults = this.mergeDefaults()
|
||||
@@ -196,7 +194,7 @@ export class ConfigService {
|
||||
}
|
||||
|
||||
async save (): Promise<void> {
|
||||
await lastValueFrom(this.ready$)
|
||||
await this.ready$
|
||||
if (!this._store) {
|
||||
throw new Error('Cannot save an empty store')
|
||||
}
|
||||
@@ -270,8 +268,8 @@ export class ConfigService {
|
||||
}
|
||||
|
||||
private emitChange (): void {
|
||||
this.vault.setStore(this.store.vault)
|
||||
this.changed.next()
|
||||
this.vault.setStore(this.store.vault)
|
||||
}
|
||||
|
||||
private migrate (config) {
|
||||
@@ -362,13 +360,9 @@ export class ConfigService {
|
||||
} catch (e) {
|
||||
let result = await this.platform.showMessageBox({
|
||||
type: 'error',
|
||||
message: this.translate.instant('Could not decrypt config'),
|
||||
message: 'Could not decrypt config',
|
||||
detail: e.toString(),
|
||||
buttons: [
|
||||
this.translate.instant('Try again'),
|
||||
this.translate.instant('Erase config'),
|
||||
this.translate.instant('Quit'),
|
||||
],
|
||||
buttons: ['Try again', 'Erase config', 'Quit'],
|
||||
defaultId: 0,
|
||||
})
|
||||
if (result.response === 2) {
|
||||
@@ -377,12 +371,9 @@ export class ConfigService {
|
||||
if (result.response === 1) {
|
||||
result = await this.platform.showMessageBox({
|
||||
type: 'warning',
|
||||
message: this.translate.instant('Are you sure?'),
|
||||
message: 'Are you sure?',
|
||||
detail: e.toString(),
|
||||
buttons: [
|
||||
this.translate.instant('Erase config'),
|
||||
this.translate.instant('Quit'),
|
||||
],
|
||||
buttons: ['Erase config', 'Quit'],
|
||||
defaultId: 1,
|
||||
cancelId: 1,
|
||||
})
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Inject, Injectable } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { FileProvider, NotificationsService, SelectorService } from '../api'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@@ -8,7 +7,6 @@ export class FileProvidersService {
|
||||
private constructor (
|
||||
private selector: SelectorService,
|
||||
private notifications: NotificationsService,
|
||||
private translate: TranslateService,
|
||||
@Inject(FileProvider) private fileProviders: FileProvider[],
|
||||
) { }
|
||||
|
||||
@@ -36,18 +34,15 @@ export class FileProvidersService {
|
||||
}
|
||||
}))
|
||||
if (!providers.length) {
|
||||
this.notifications.error(this.translate.instant('Vault master passphrase needs to be set to allow storing secrets'))
|
||||
this.notifications.error('Vault master passphrase needs to be set to allow storing secrets')
|
||||
throw new Error('No available file providers')
|
||||
}
|
||||
if (providers.length === 1) {
|
||||
return providers[0]
|
||||
}
|
||||
return this.selector.show(
|
||||
this.translate.instant('Select file storage'),
|
||||
providers.map(p => ({
|
||||
return this.selector.show('Select file storage', providers.map(p => ({
|
||||
name: p.name,
|
||||
result: p,
|
||||
}))
|
||||
)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
@@ -130,7 +130,9 @@ export class HotkeysService {
|
||||
const keyName = getKeyName(eventData)
|
||||
if (eventName === 'keydown') {
|
||||
this.addPressedKey(keyName, eventData)
|
||||
if (!nativeEvent.repeat) {
|
||||
this.recognitionPhase = true
|
||||
}
|
||||
this.updateModifiers(eventData)
|
||||
}
|
||||
if (eventName === 'keyup') {
|
||||
@@ -156,10 +158,8 @@ export class HotkeysService {
|
||||
|
||||
const matched = this.matchActiveHotkey()
|
||||
this.zone.run(() => {
|
||||
if (matched) {
|
||||
if (this.recognitionPhase) {
|
||||
if (matched && this.recognitionPhase) {
|
||||
this.emitHotkeyOn(matched)
|
||||
}
|
||||
} else if (this.pressedHotkey) {
|
||||
this.emitHotkeyOff(this.pressedHotkey)
|
||||
}
|
||||
@@ -288,9 +288,10 @@ export class HotkeysService {
|
||||
|
||||
private emitHotkeyOn (hotkey: string) {
|
||||
if (this.pressedHotkey) {
|
||||
if (this.pressedHotkey !== hotkey) {
|
||||
this.emitHotkeyOff(this.pressedHotkey)
|
||||
if (this.pressedHotkey === hotkey) {
|
||||
return
|
||||
}
|
||||
this.emitHotkeyOff(this.pressedHotkey)
|
||||
}
|
||||
if (document.querySelectorAll('input:focus').length === 0) {
|
||||
console.debug('Matched hotkey', hotkey)
|
||||
|
@@ -2,27 +2,15 @@ import { Injectable } from '@angular/core'
|
||||
import { registerLocaleData } from '@angular/common'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
|
||||
import localeEN from '@angular/common/locales/en'
|
||||
import localeDE from '@angular/common/locales/de'
|
||||
import localeES from '@angular/common/locales/es'
|
||||
import localeFR from '@angular/common/locales/fr'
|
||||
import localeHR from '@angular/common/locales/hr'
|
||||
import localePL from '@angular/common/locales/pl'
|
||||
import localeEN from '@angular/common/locales/en-GB'
|
||||
import localeRU from '@angular/common/locales/ru'
|
||||
import localeZH from '@angular/common/locales/zh'
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { distinctUntilChanged } from 'rxjs/operators'
|
||||
import { ConfigService } from './config.service'
|
||||
import { LogService, Logger } from './log.service'
|
||||
|
||||
registerLocaleData(localeEN)
|
||||
registerLocaleData(localeDE)
|
||||
registerLocaleData(localeES)
|
||||
registerLocaleData(localeFR)
|
||||
registerLocaleData(localeHR)
|
||||
registerLocaleData(localePL)
|
||||
registerLocaleData(localeRU)
|
||||
registerLocaleData(localeZH)
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TranslateServiceWrapper extends TranslateService {
|
||||
@@ -37,26 +25,28 @@ export class TranslateServiceWrapper extends TranslateService {
|
||||
export class LocaleService {
|
||||
private logger: Logger
|
||||
|
||||
static readonly allLocales = [
|
||||
'en-US',
|
||||
'de-DE',
|
||||
'es-ES',
|
||||
'fr-FR',
|
||||
'hr-HR',
|
||||
'pl-PL',
|
||||
'ru-RU',
|
||||
'zh-CN',
|
||||
'zh-TW',
|
||||
]
|
||||
|
||||
readonly allLanguages: { code: string, name: string }[]
|
||||
static readonly allLocales = ['en', 'de', 'fr', 'ru']
|
||||
|
||||
get localeChanged$ (): Observable<string> {
|
||||
return this.localeChanged.pipe(distinctUntilChanged())
|
||||
}
|
||||
|
||||
private locale = 'en-US'
|
||||
get catalogChanged$ (): Observable<Record<string, string | undefined>> {
|
||||
return this.catalogChanged.pipe(distinctUntilChanged())
|
||||
}
|
||||
|
||||
readonly allLanguages: { code: string, name: string }[]
|
||||
private translations = {
|
||||
en: {
|
||||
Close: 'Close',
|
||||
},
|
||||
ru: {
|
||||
Close: 'Закрыть',
|
||||
},
|
||||
}
|
||||
private locale = 'en'
|
||||
private localeChanged = new Subject<string>()
|
||||
private catalogChanged = new Subject<Record<string, string | undefined>>()
|
||||
|
||||
constructor (
|
||||
private config: ConfigService,
|
||||
@@ -67,76 +57,55 @@ export class LocaleService {
|
||||
config.changed$.subscribe(() => {
|
||||
this.refresh()
|
||||
})
|
||||
config.ready$.subscribe(() => {
|
||||
this.refresh()
|
||||
})
|
||||
|
||||
this.allLanguages = [
|
||||
{
|
||||
code: 'en-US',
|
||||
code: 'en',
|
||||
name: translate.instant('English'),
|
||||
},
|
||||
{
|
||||
code: 'zh-CN',
|
||||
name: translate.instant('Chinese (simplified)'),
|
||||
},
|
||||
{
|
||||
code: 'zh-TW',
|
||||
name: translate.instant('Chinese (traditional)'),
|
||||
},
|
||||
{
|
||||
code: 'hr-HR',
|
||||
name: translate.instant('Croatian'),
|
||||
},
|
||||
{
|
||||
code: 'de-DE',
|
||||
code: 'de',
|
||||
name: translate.instant('German'),
|
||||
},
|
||||
{
|
||||
code: 'fr-FR',
|
||||
code: 'fr',
|
||||
name: translate.instant('French'),
|
||||
},
|
||||
{
|
||||
code: 'pl-PL',
|
||||
name: translate.instant('Polish'),
|
||||
/* {
|
||||
code: 'it',
|
||||
name: translate.instant('Italian'),
|
||||
},
|
||||
{
|
||||
code: 'ru-RU',
|
||||
code: 'es',
|
||||
name: translate.instant('Spanish'),
|
||||
}, */
|
||||
{
|
||||
code: 'ru',
|
||||
name: translate.instant('Russian'),
|
||||
},
|
||||
{
|
||||
code: 'es-ES',
|
||||
name: translate.instant('Spanish'),
|
||||
},
|
||||
/* {
|
||||
code: 'ar',
|
||||
name: translate.instant('Arabic'),
|
||||
}, */
|
||||
]
|
||||
|
||||
this.translate.setTranslation('en-US', {})
|
||||
}
|
||||
|
||||
refresh (): void {
|
||||
let lang = this.config.store.language
|
||||
if (!lang) {
|
||||
for (const systemLanguage of navigator.languages) {
|
||||
if (!lang && this.allLanguages.some(x => x.code === systemLanguage)) {
|
||||
lang = systemLanguage
|
||||
}
|
||||
}
|
||||
}
|
||||
lang ??= 'en-US'
|
||||
this.setLocale(lang)
|
||||
this.setLocale(this.config.store.language)
|
||||
}
|
||||
|
||||
async setLocale (lang: string): Promise<void> {
|
||||
if (!this.translate.langs.includes(lang) && lang !== 'en-US') {
|
||||
const strings = this.translations[lang]
|
||||
|
||||
if (!this.translate.langs.includes(lang)) {
|
||||
this.translate.addLangs([lang])
|
||||
|
||||
const po = require(`../../../locale/${lang}.po`).translations['']
|
||||
const translation = {}
|
||||
for (const k of Object.keys(po)) {
|
||||
translation[k] = po[k].msgstr[0] || k
|
||||
}
|
||||
|
||||
this.translate.setTranslation(lang, translation)
|
||||
// Filter out legacy interpolated strings
|
||||
const filteredStrings = Object.fromEntries(
|
||||
Object.entries(strings).filter(e => !e[0].includes('{{')),
|
||||
)
|
||||
this.translate.setTranslation(lang, filteredStrings)
|
||||
}
|
||||
|
||||
this.translate.setDefaultLang(lang)
|
||||
@@ -144,6 +113,7 @@ export class LocaleService {
|
||||
this.locale = lang
|
||||
this.localeChanged.next(lang)
|
||||
this.logger.debug('Setting language to', lang)
|
||||
this.catalogChanged.next(strings)
|
||||
}
|
||||
|
||||
getLocale (): string {
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Injectable, Inject } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { NewTabParameters } from './tabs.service'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { PartialProfile, Profile, ProfileProvider } from '../api/profileProvider'
|
||||
@@ -30,14 +29,15 @@ export class ProfilesService {
|
||||
private config: ConfigService,
|
||||
private notifications: NotificationsService,
|
||||
private selector: SelectorService,
|
||||
private translate: TranslateService,
|
||||
@Inject(ProfileProvider) private profileProviders: ProfileProvider<Profile>[],
|
||||
) { }
|
||||
|
||||
async openNewTabForProfile <P extends Profile> (profile: PartialProfile<P>): Promise<BaseTabComponent|null> {
|
||||
const params = await this.newTabParametersForProfile(profile)
|
||||
if (params) {
|
||||
return this.app.openNewTab(params)
|
||||
const tab = this.app.openNewTab(params)
|
||||
;(this.app.getParentTab(tab) ?? tab).color = profile.color ?? null
|
||||
return tab
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -48,12 +48,9 @@ export class ProfilesService {
|
||||
if (params) {
|
||||
params.inputs ??= {}
|
||||
params.inputs['title'] = profile.name
|
||||
if (fullProfile.disableDynamicTitle) {
|
||||
if (profile.disableDynamicTitle) {
|
||||
params.inputs['disableDynamicTitle'] = true
|
||||
}
|
||||
if (fullProfile.color) {
|
||||
params.inputs['color'] = fullProfile.color
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
@@ -106,7 +103,7 @@ export class ProfilesService {
|
||||
|
||||
let options: SelectorOption<void>[] = recentProfiles.map(p => ({
|
||||
...this.selectorOptionForProfile(p),
|
||||
group: this.translate.instant('Recent'),
|
||||
group: 'Recent',
|
||||
icon: 'fas fa-history',
|
||||
color: p.color,
|
||||
callback: async () => {
|
||||
@@ -118,8 +115,8 @@ export class ProfilesService {
|
||||
}))
|
||||
if (recentProfiles.length) {
|
||||
options.push({
|
||||
name: this.translate.instant('Clear recent profiles'),
|
||||
group: this.translate.instant('Recent'),
|
||||
name: 'Clear recent profiles',
|
||||
group: 'Recent',
|
||||
icon: 'fas fa-eraser',
|
||||
callback: async () => {
|
||||
window.localStorage.removeItem('recentProfiles')
|
||||
@@ -145,7 +142,7 @@ export class ProfilesService {
|
||||
try {
|
||||
const { SettingsTabComponent } = window['nodeRequire']('tabby-settings')
|
||||
options.push({
|
||||
name: this.translate.instant('Manage profiles'),
|
||||
name: 'Manage profiles',
|
||||
icon: 'fas fa-window-restore',
|
||||
callback: () => {
|
||||
this.app.openNewTabRaw({
|
||||
@@ -159,8 +156,8 @@ export class ProfilesService {
|
||||
|
||||
if (this.getProviders().some(x => x.supportsQuickConnect)) {
|
||||
options.push({
|
||||
name: this.translate.instant('Quick connect'),
|
||||
freeInputPattern: this.translate.instant('Connect to "%s"...'),
|
||||
name: 'Quick connect',
|
||||
freeInputPattern: 'Connect to "%s"...',
|
||||
icon: 'fas fa-arrow-right',
|
||||
callback: query => {
|
||||
const profile = this.quickConnect(query)
|
||||
@@ -168,7 +165,7 @@ export class ProfilesService {
|
||||
},
|
||||
})
|
||||
}
|
||||
await this.selector.show(this.translate.instant('Select profile or enter an address'), options)
|
||||
await this.selector.show('Select profile or enter an address', options)
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Injectable, Inject } from '@angular/core'
|
||||
import { TabRecoveryProvider, RecoveryToken } from '../api/tabRecovery'
|
||||
import { BaseTabComponent, GetRecoveryTokenOptions } from '../components/baseTab.component'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { Logger, LogService } from './log.service'
|
||||
import { ConfigService } from './config.service'
|
||||
import { NewTabParameters } from './tabs.service'
|
||||
@@ -25,13 +25,13 @@ export class TabRecoveryService {
|
||||
}
|
||||
window.localStorage.tabsRecovery = JSON.stringify(
|
||||
(await Promise.all(
|
||||
tabs.map(async tab => this.getFullRecoveryToken(tab, { includeState: true }))
|
||||
tabs.map(async tab => this.getFullRecoveryToken(tab))
|
||||
)).filter(token => !!token)
|
||||
)
|
||||
}
|
||||
|
||||
async getFullRecoveryToken (tab: BaseTabComponent, options?: GetRecoveryTokenOptions): Promise<RecoveryToken|null> {
|
||||
const token = await tab.getRecoveryToken(options)
|
||||
async getFullRecoveryToken (tab: BaseTabComponent): Promise<RecoveryToken|null> {
|
||||
const token = await tab.getRecoveryToken()
|
||||
if (token) {
|
||||
token.tabTitle = tab.title
|
||||
token.tabCustomTitle = tab.customTitle
|
||||
@@ -43,12 +43,15 @@ export class TabRecoveryService {
|
||||
return token
|
||||
}
|
||||
|
||||
async recoverTab (token: RecoveryToken): Promise<NewTabParameters<BaseTabComponent>|null> {
|
||||
async recoverTab (token: RecoveryToken, duplicate = false): Promise<NewTabParameters<BaseTabComponent>|null> {
|
||||
for (const provider of this.config.enabledServices(this.tabRecoveryProviders ?? [])) {
|
||||
try {
|
||||
if (!await provider.applicableTo(token)) {
|
||||
continue
|
||||
}
|
||||
if (duplicate) {
|
||||
token = provider.duplicate(token)
|
||||
}
|
||||
const tab = await provider.recover(token)
|
||||
tab.inputs = tab.inputs ?? {}
|
||||
tab.inputs.color = token.tabColor ?? null
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import deepClone from 'clone-deep'
|
||||
import { Injectable, ComponentFactoryResolver, Injector } from '@angular/core'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { TabRecoveryService } from './tabRecovery.service'
|
||||
@@ -49,7 +48,7 @@ export class TabsService {
|
||||
if (!token) {
|
||||
return null
|
||||
}
|
||||
const dup = await this.tabRecovery.recoverTab(deepClone(token))
|
||||
const dup = await this.tabRecovery.recoverTab(token, true)
|
||||
if (dup) {
|
||||
return this.create(dup)
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Injectable } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { AppService } from './services/app.service'
|
||||
import { BaseTabComponent } from './components/baseTab.component'
|
||||
@@ -15,6 +14,7 @@ import { HotkeysService } from './services/hotkeys.service'
|
||||
import { PromptModalComponent } from './components/promptModal.component'
|
||||
import { SplitLayoutProfilesService } from './profiles'
|
||||
import { TAB_COLORS } from './utils'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
@@ -109,7 +109,6 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: TabHeaderComponent): Promise<MenuItemOptions[]> {
|
||||
let items: MenuItemOptions[] = []
|
||||
if (tabHeader) {
|
||||
const currentColor = TAB_COLORS.find(x => x.value === tab.color)?.name
|
||||
items = [
|
||||
...items,
|
||||
{
|
||||
@@ -122,9 +121,9 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Color'),
|
||||
sublabel: currentColor ? this.translate.instant(currentColor) : undefined,
|
||||
sublabel: TAB_COLORS.find(x => x.value === tab.color)?.name,
|
||||
submenu: TAB_COLORS.map(color => ({
|
||||
label: this.translate.instant(color.name) ?? color.name,
|
||||
label: this.translate.instant(color.name),
|
||||
type: 'radio',
|
||||
checked: tab.color === color.value,
|
||||
click: () => {
|
||||
@@ -172,7 +171,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
||||
if (process) {
|
||||
items.push({
|
||||
enabled: false,
|
||||
label: this.translate.instant('Current process: {name}', process),
|
||||
label: this.translate.instant('Current process: ' + process.name),
|
||||
})
|
||||
items.push({
|
||||
label: this.translate.instant('Notify when done'),
|
||||
@@ -233,7 +232,6 @@ export class ProfilesContextMenu extends TabContextMenuItemProvider {
|
||||
private profilesService: ProfilesService,
|
||||
private tabsService: TabsService,
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
@@ -276,7 +274,7 @@ export class ProfilesContextMenu extends TabContextMenuItemProvider {
|
||||
if (!tabHeader && tab.parent instanceof SplitTabComponent && tab.parent.getAllTabs().length > 1) {
|
||||
return [
|
||||
{
|
||||
label: this.translate.instant('Switch profile'),
|
||||
label: 'Switch profile',
|
||||
click: () => this.switchTabProfile(tab),
|
||||
},
|
||||
]
|
||||
|
@@ -117,13 +117,15 @@ window-controls {
|
||||
|
||||
$border-color: $base1;
|
||||
|
||||
app-root {
|
||||
body {
|
||||
background: $body-bg;
|
||||
|
||||
&.vibrant {
|
||||
background: rgba(255, 255, 255,.4) !important;
|
||||
}
|
||||
}
|
||||
|
||||
app-root {
|
||||
&> .content {
|
||||
.tab-bar {
|
||||
.btn-tab-bar {
|
||||
@@ -380,7 +382,7 @@ start-page footer {
|
||||
background: $white !important;
|
||||
}
|
||||
|
||||
terminal-toolbar {
|
||||
.terminal-toolbar {
|
||||
background: #ffffff4a !important;
|
||||
border-bottom: 1px solid #00000026 !important;
|
||||
}
|
||||
|
@@ -25,13 +25,15 @@ window-controls {
|
||||
|
||||
$border-color: #111;
|
||||
|
||||
app-root {
|
||||
body {
|
||||
background: $body-bg;
|
||||
|
||||
&.vibrant {
|
||||
background: rgba(0,0,0,.65);
|
||||
}
|
||||
}
|
||||
|
||||
app-root {
|
||||
&.no-tabs {
|
||||
background: rgba(0,0,0,.5);
|
||||
}
|
||||
@@ -122,21 +124,16 @@ app-root {
|
||||
|
||||
&.platform-win32, &.platform-linux {
|
||||
border: 1px solid #111;
|
||||
|
||||
&>.content {
|
||||
margin: -1px; // expand the content into the border
|
||||
|
||||
.tab-bar .tabs tab-header:first-child {
|
||||
&>.content .tab-bar .tabs tab-header:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tab-body {
|
||||
background: $content-bg;
|
||||
|
||||
terminal-toolbar .btn, .toolbar-pin-button {
|
||||
.terminal-toolbar .btn, .toolbar-pin-button {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
@@ -1,31 +1,22 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { Theme } from './api'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class StandardTheme extends Theme {
|
||||
name = this.translate.instant('Standard')
|
||||
name = 'Standard'
|
||||
css = require('./theme.scss')
|
||||
terminalBackground = '#222a33'
|
||||
|
||||
constructor (private translate: TranslateService) {
|
||||
super()
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class StandardCompactTheme extends Theme {
|
||||
name = this.translate.instant('Compact')
|
||||
name = 'Compact'
|
||||
css = require('./theme.compact.scss')
|
||||
terminalBackground = '#222a33'
|
||||
macOSWindowButtonsInsetX = 8
|
||||
macOSWindowButtonsInsetY = 6
|
||||
|
||||
constructor (private translate: TranslateService) {
|
||||
super()
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import * as os from 'os'
|
||||
import { NgZone } from '@angular/core'
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'
|
||||
|
||||
export const WIN_BUILD_CONPTY_SUPPORTED = 17692
|
||||
export const WIN_BUILD_CONPTY_STABLE = 18309
|
||||
@@ -57,13 +56,13 @@ export class ResettableTimeout {
|
||||
}
|
||||
|
||||
export const TAB_COLORS = [
|
||||
{ name: _('No color'), value: null },
|
||||
{ name: _('Blue'), value: '#0275d8' },
|
||||
{ name: _('Green'), value: '#5cb85c' },
|
||||
{ name: _('Orange'), value: '#f0ad4e' },
|
||||
{ name: _('Purple'), value: '#613d7c' },
|
||||
{ name: _('Red'), value: '#d9534f' },
|
||||
{ name: _('Yellow'), value: '#ffd500' },
|
||||
{ name: 'No color', value: null },
|
||||
{ name: 'Blue', value: '#0275d8' },
|
||||
{ name: 'Green', value: '#5cb85c' },
|
||||
{ name: 'Orange', value: '#f0ad4e' },
|
||||
{ name: 'Purple', value: '#613d7c' },
|
||||
{ name: 'Red', value: '#d9534f' },
|
||||
{ name: 'Yellow', value: '#ffd500' },
|
||||
]
|
||||
|
||||
export function serializeFunction <T extends () => Promise<any>> (fn: T): T {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tabby-electron",
|
||||
"version": "1.0.170-nightly.0",
|
||||
"version": "1.0.165-nightly.0",
|
||||
"description": "Electron-specific bindings",
|
||||
"keywords": [
|
||||
"tabby-builtin-plugin"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HotkeyDescription, HotkeyProvider, TranslateService } from 'tabby-core'
|
||||
import { HotkeyDescription, HotkeyProvider } from 'tabby-core'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
@@ -7,16 +7,14 @@ export class ElectronHotkeyProvider extends HotkeyProvider {
|
||||
hotkeys: HotkeyDescription[] = [
|
||||
{
|
||||
id: 'new-window',
|
||||
name: this.translate.instant('New window'),
|
||||
name: 'New window',
|
||||
},
|
||||
{
|
||||
id: 'toggle-window',
|
||||
name: this.translate.instant('Toggle terminal window'),
|
||||
name: 'Toggle terminal window',
|
||||
},
|
||||
]
|
||||
|
||||
constructor (private translate: TranslateService) { super() }
|
||||
|
||||
async provide (): Promise<HotkeyDescription[]> {
|
||||
return this.hotkeys
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import { NgModule } from '@angular/core'
|
||||
import { PlatformService, LogService, UpdaterService, DockingService, HostAppService, ThemesService, Platform, AppService, ConfigService, WIN_BUILD_FLUENT_BG_SUPPORTED, isWindowsBuild, HostWindowService, HotkeyProvider, ConfigProvider, FileProvider } from 'tabby-core'
|
||||
import { TerminalColorSchemeProvider } from 'tabby-terminal'
|
||||
import { SFTPContextMenuItemProvider, SSHProfileImporter } from 'tabby-ssh'
|
||||
import { auditTime } from 'rxjs'
|
||||
import { SFTPContextMenuItemProvider } from 'tabby-ssh'
|
||||
|
||||
import { HyperColorSchemes } from './colorSchemes'
|
||||
import { ElectronPlatformService } from './services/platform.service'
|
||||
@@ -17,7 +16,6 @@ import { ElectronService } from './services/electron.service'
|
||||
import { ElectronHotkeyProvider } from './hotkeys'
|
||||
import { ElectronConfigProvider } from './config'
|
||||
import { EditSFTPContextMenu } from './sftpContextMenu'
|
||||
import { OpenSSHImporter } from './openSSHImport'
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
@@ -32,7 +30,6 @@ import { OpenSSHImporter } from './openSSHImport'
|
||||
{ provide: ConfigProvider, useClass: ElectronConfigProvider, multi: true },
|
||||
{ provide: FileProvider, useClass: ElectronFileProvider, multi: true },
|
||||
{ provide: SFTPContextMenuItemProvider, useClass: EditSFTPContextMenu, multi: true },
|
||||
{ provide: SSHProfileImporter, useClass: OpenSSHImporter, multi: true },
|
||||
],
|
||||
})
|
||||
export default class ElectronModule {
|
||||
@@ -71,7 +68,7 @@ export default class ElectronModule {
|
||||
|
||||
let lastProgress: number|null = null
|
||||
app.tabOpened$.subscribe(tab => {
|
||||
tab.progress$.pipe(auditTime(250)).subscribe(progress => {
|
||||
tab.progress$.subscribe(progress => {
|
||||
if (lastProgress === progress) {
|
||||
return
|
||||
}
|
||||
@@ -116,6 +113,7 @@ export default class ElectronModule {
|
||||
if (this.hostApp.platform === Platform.Windows && !isWindowsBuild(WIN_BUILD_FLUENT_BG_SUPPORTED)) {
|
||||
vibrancyType = null
|
||||
}
|
||||
document.body.classList.toggle('vibrant', this.config.store.appearance.vibrancy)
|
||||
this.electron.ipcRenderer.send('window-set-vibrancy', this.config.store.appearance.vibrancy, vibrancyType)
|
||||
|
||||
this.hostWindow.setOpacity(this.config.store.appearance.opacity)
|
||||
|
@@ -1,129 +0,0 @@
|
||||
import * as fs from 'fs/promises'
|
||||
import * as path from 'path'
|
||||
import slugify from 'slugify'
|
||||
import { PartialProfile } from 'tabby-core'
|
||||
import { SSHProfileImporter, PortForwardType, SSHProfile, SSHProfileOptions } from 'tabby-ssh'
|
||||
|
||||
function deriveID (name: string): string {
|
||||
return 'openssh-config:' + slugify(name)
|
||||
}
|
||||
|
||||
export class OpenSSHImporter extends SSHProfileImporter {
|
||||
async getProfiles (): Promise<PartialProfile<SSHProfile>[]> {
|
||||
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.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.split(':')[0] ?? '127.0.0.1',
|
||||
port: parseInt(bind.split(':')[1] ?? bind),
|
||||
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.split(':')[0] ?? '127.0.0.1',
|
||||
port: parseInt(bind.split(':')[1] ?? bind),
|
||||
targetAddress: '',
|
||||
targetPort: 22,
|
||||
})
|
||||
} else {
|
||||
const mappedKey = {
|
||||
hostname: 'host',
|
||||
host: 'host',
|
||||
port: 'port',
|
||||
user: 'user',
|
||||
forwardx11: 'x11',
|
||||
serveraliveinterval: 'keepaliveInterval',
|
||||
serveralivecountmax: 'keepaliveCountMax',
|
||||
proxycommand: 'proxyCommand',
|
||||
proxyjump: 'jumpHost',
|
||||
}[key.toLowerCase()]
|
||||
if (mappedKey) {
|
||||
target[mappedKey] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentProfile) {
|
||||
results.push(currentProfile)
|
||||
}
|
||||
for (const p of results) {
|
||||
if (p.options?.proxyCommand) {
|
||||
p.options.proxyCommand = p.options.proxyCommand
|
||||
.replace('%h', p.options.host ?? '')
|
||||
.replace('%p', (p.options.port ?? 22).toString())
|
||||
}
|
||||
if (p.options?.jumpHost) {
|
||||
p.options.jumpHost = deriveID(p.options.jumpHost)
|
||||
}
|
||||
}
|
||||
return results
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
return []
|
||||
}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,7 +15,6 @@ export class ElectronHostWindow extends HostWindowService {
|
||||
get isFullscreen (): boolean { return this._isFullscreen }
|
||||
|
||||
private _isFullscreen = false
|
||||
private _isMaximized = false
|
||||
|
||||
constructor (
|
||||
zone: NgZone,
|
||||
@@ -48,16 +47,6 @@ export class ElectronHostWindow extends HostWindowService {
|
||||
electron.ipcRenderer.on('host:became-main-window', () => zone.run(() => {
|
||||
this.bootstrapData.isMainWindow = true
|
||||
}))
|
||||
|
||||
electron.ipcRenderer.on('host:window-maximized', () => zone.run(() => {
|
||||
this._isMaximized = true
|
||||
}))
|
||||
|
||||
electron.ipcRenderer.on('host:window-unmaximized', () => zone.run(() => {
|
||||
this._isMaximized = false
|
||||
}))
|
||||
|
||||
this._isMaximized = this.getWindow().isMaximized()
|
||||
}
|
||||
|
||||
getWindow (): BrowserWindow {
|
||||
@@ -85,7 +74,7 @@ export class ElectronHostWindow extends HostWindowService {
|
||||
}
|
||||
|
||||
isMaximized (): boolean {
|
||||
return this._isMaximized
|
||||
return this.getWindow().isMaximized()
|
||||
}
|
||||
|
||||
toggleMaximize (): void {
|
||||
|
@@ -7,7 +7,7 @@ import { promisify } from 'util'
|
||||
import promiseIpc, { RendererProcessType } from 'electron-promise-ipc'
|
||||
import { execFile } from 'mz/child_process'
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { PlatformService, ClipboardContent, HostAppService, Platform, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileDownload, FileUploadOptions, wrapPromise, TranslateService } from 'tabby-core'
|
||||
import { PlatformService, ClipboardContent, HostAppService, Platform, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileDownload, FileUploadOptions, wrapPromise } from 'tabby-core'
|
||||
import { ElectronService } from '../services/electron.service'
|
||||
import { ElectronHostWindow } from './hostWindow.service'
|
||||
import { ShellIntegrationService } from './shellIntegration.service'
|
||||
@@ -34,7 +34,6 @@ export class ElectronPlatformService extends PlatformService {
|
||||
private electron: ElectronService,
|
||||
private zone: NgZone,
|
||||
private shellIntegration: ShellIntegrationService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
this.configPath = path.join(electron.app.getPath('userData'), 'config.yaml')
|
||||
@@ -205,7 +204,7 @@ export class ElectronPlatformService extends PlatformService {
|
||||
const result = await this.electron.dialog.showOpenDialog(
|
||||
this.hostWindow.getWindow(),
|
||||
{
|
||||
buttonLabel: this.translate.instant('Select'),
|
||||
buttonLabel: 'Select',
|
||||
properties,
|
||||
},
|
||||
)
|
||||
|
@@ -2,7 +2,7 @@ import type { AppUpdater } from 'electron-updater'
|
||||
import { Injectable } from '@angular/core'
|
||||
import axios from 'axios'
|
||||
|
||||
import { Logger, LogService, ConfigService, UpdaterService, PlatformService, TranslateService } from 'tabby-core'
|
||||
import { Logger, LogService, ConfigService, UpdaterService, PlatformService } from 'tabby-core'
|
||||
import { ElectronService } from '../services/electron.service'
|
||||
|
||||
const UPDATES_URL = 'https://api.github.com/repos/eugeny/tabby/releases/latest'
|
||||
@@ -18,7 +18,6 @@ export class ElectronUpdaterService extends UpdaterService {
|
||||
constructor (
|
||||
log: LogService,
|
||||
config: ConfigService,
|
||||
private translate: TranslateService,
|
||||
private platform: PlatformService,
|
||||
private electron: ElectronService,
|
||||
) {
|
||||
@@ -133,11 +132,8 @@ export class ElectronUpdaterService extends UpdaterService {
|
||||
if ((await this.platform.showMessageBox(
|
||||
{
|
||||
type: 'warning',
|
||||
message: this.translate.instant('Installing the update will close all tabs and restart Tabby.'),
|
||||
buttons: [
|
||||
this.translate.instant('Update'),
|
||||
this.translate.instant('Cancel'),
|
||||
],
|
||||
message: 'Installing the update will close all tabs and restart Tabby.',
|
||||
buttons: ['Update', 'Cancel'],
|
||||
defaultId: 0,
|
||||
cancelId: 1,
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tabby-linkifier",
|
||||
"version": "1.0.170-nightly.0",
|
||||
"version": "1.0.165-nightly.0",
|
||||
"description": "Makes URLs, IPs and file paths clickable in Tabby",
|
||||
"keywords": [
|
||||
"tabby-builtin-plugin"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Inject, Injectable } from '@angular/core'
|
||||
import { ConfigService, PlatformService, TranslateService } from 'tabby-core'
|
||||
import { ConfigService, PlatformService } from 'tabby-core'
|
||||
import { TerminalDecorator, BaseTerminalTabComponent } from 'tabby-terminal'
|
||||
|
||||
import { LinkHandler } from './api'
|
||||
@@ -9,7 +9,6 @@ export class LinkHighlighterDecorator extends TerminalDecorator {
|
||||
constructor (
|
||||
private config: ConfigService,
|
||||
private platform: PlatformService,
|
||||
private translate: TranslateService,
|
||||
@Inject(LinkHandler) private handlers: LinkHandler[],
|
||||
) {
|
||||
super()
|
||||
@@ -43,13 +42,13 @@ export class LinkHighlighterDecorator extends TerminalDecorator {
|
||||
this.platform.popupContextMenu([
|
||||
{
|
||||
click: () => openLink(uri),
|
||||
label: this.translate.instant('Open'),
|
||||
label: 'Open',
|
||||
},
|
||||
{
|
||||
click: async () => {
|
||||
this.platform.setClipboard({ text: await getLink(uri) })
|
||||
},
|
||||
label: this.translate.instant('Copy'),
|
||||
label: 'Copy',
|
||||
},
|
||||
])
|
||||
return false
|
||||
|
@@ -11,8 +11,7 @@ import { LinkHandler } from './api'
|
||||
@Injectable()
|
||||
export class URLHandler extends LinkHandler {
|
||||
// From https://urlregex.com/
|
||||
// with "-" added to last group (https://github.com/Eugeny/tabby/issues/5611)
|
||||
regex = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((:((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{1,5})|([0-9]{1,4})))?(?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w-]*))?)/
|
||||
regex = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((:((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{1,5})|([0-9]{1,4})))?(?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/
|
||||
|
||||
priority = 5
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tabby-local",
|
||||
"version": "1.0.170-nightly.0",
|
||||
"version": "1.0.165-nightly.0",
|
||||
"description": "Tabby's local shell plugin",
|
||||
"keywords": [
|
||||
"tabby-builtin-plugin"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ToolbarButtonProvider, ToolbarButton, TranslateService } from 'tabby-core'
|
||||
import { ToolbarButtonProvider, ToolbarButton } from 'tabby-core'
|
||||
import { TerminalService } from './services/terminal.service'
|
||||
|
||||
/** @hidden */
|
||||
@@ -8,7 +8,6 @@ import { TerminalService } from './services/terminal.service'
|
||||
export class ButtonProvider extends ToolbarButtonProvider {
|
||||
constructor (
|
||||
private terminal: TerminalService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
@@ -17,7 +16,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
return [
|
||||
{
|
||||
icon: require('./icons/plus.svg'),
|
||||
title: this.translate.instant('New terminal'),
|
||||
title: 'New terminal',
|
||||
touchBarNSImage: 'NSTouchBarAddDetailTemplate',
|
||||
click: () => {
|
||||
this.terminal.openTab()
|
||||
|
@@ -1,6 +1,6 @@
|
||||
ng-container(*ngIf='!argvMode')
|
||||
.form-group
|
||||
label(translate) Command line
|
||||
label Command line
|
||||
.input-group
|
||||
.input-group-prepend
|
||||
a.input-group-text(
|
||||
@@ -16,7 +16,7 @@ ng-container(*ngIf='!argvMode')
|
||||
|
||||
ng-container(*ngIf='argvMode')
|
||||
.form-group
|
||||
label(translate) Program
|
||||
label Program
|
||||
.input-group
|
||||
.input-group-prepend
|
||||
a.input-group-text(
|
||||
@@ -31,7 +31,7 @@ ng-container(*ngIf='argvMode')
|
||||
)
|
||||
|
||||
.form-group
|
||||
label(translate) Arguments
|
||||
label Arguments
|
||||
.input-group(
|
||||
*ngFor='let arg of _model.args; index as i; trackBy: trackByIndex',
|
||||
)
|
||||
@@ -46,4 +46,4 @@ ng-container(*ngIf='argvMode')
|
||||
.mt-2
|
||||
button.btn.btn-secondary((click)='_model.args.push("")')
|
||||
i.fas.fa-plus.mr-2
|
||||
span(translate) Add
|
||||
| Add
|
||||
|
@@ -11,10 +11,10 @@
|
||||
.d-flex
|
||||
button.btn.btn-secondary((click)='addEnvironmentVar()')
|
||||
i.fas.fa-plus.mr-2
|
||||
span(translate) Add
|
||||
span Add
|
||||
|
||||
.ml-auto
|
||||
.text-muted(translate) Substitutions allowed.
|
||||
.text-muted Substitutions allowed.
|
||||
.d-flex.ml-1(*ngIf='shouldShowExample()')
|
||||
.text-muted(translate) Example:
|
||||
.text-muted Example:
|
||||
a.ml-1((click)='addExample()', href='#') extend PATH
|
||||
|
@@ -2,13 +2,13 @@ command-line-editor([model]='profile.options')
|
||||
|
||||
.form-line(*ngIf='uac.isAvailable')
|
||||
.header
|
||||
.title(translate) Run as administrator
|
||||
.title Run as administrator
|
||||
toggle(
|
||||
[(ngModel)]='profile.options.runAsAdministrator',
|
||||
)
|
||||
|
||||
.form-group
|
||||
label(translate) Working directory
|
||||
label Working directory
|
||||
|
||||
.input-group
|
||||
input.form-control(
|
||||
@@ -21,7 +21,7 @@ command-line-editor([model]='profile.options')
|
||||
i.fas.fa-folder-open
|
||||
|
||||
.form-group
|
||||
label(translate) Environment
|
||||
label Environment
|
||||
environment-editor(
|
||||
type='text',
|
||||
[(model)]='profile.options.env',
|
||||
|
@@ -1,9 +1,9 @@
|
||||
h3.mb-3(translate) Shell
|
||||
h3.mb-3 Shell
|
||||
|
||||
.form-line(*ngIf='isConPTYAvailable')
|
||||
.header
|
||||
.title(translate) Use ConPTY
|
||||
.description(translate) Enables the experimental Windows ConPTY API
|
||||
.title Use ConPTY
|
||||
.description Enables the experimental Windows ConPTY API
|
||||
|
||||
toggle(
|
||||
[(ngModel)]='config.store.terminal.useConPTY',
|
||||
@@ -11,7 +11,7 @@ h3.mb-3(translate) Shell
|
||||
)
|
||||
|
||||
.alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.useConPTY && isConPTYAvailable && !isConPTYStable')
|
||||
.mr-auto(translate) Windows 10 build 18309 or above is recommended for ConPTY
|
||||
.mr-auto Windows 10 build 18309 or above is recommended for ConPTY
|
||||
|
||||
.alert.alert-info.d-flex.align-items-center(*ngIf='config.store.terminal.profile.startsWith("WSL") && (!config.store.terminal.useConPTY)')
|
||||
.mr-auto(translate) WSL terminal only supports TrueColor with ConPTY
|
||||
.mr-auto WSL terminal only supports TrueColor with ConPTY
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Component, Input, Injector } from '@angular/core'
|
||||
import { BaseTabProcess, WIN_BUILD_CONPTY_SUPPORTED, isWindowsBuild, GetRecoveryTokenOptions } from 'tabby-core'
|
||||
import { BaseTabProcess, WIN_BUILD_CONPTY_SUPPORTED, isWindowsBuild } from 'tabby-core'
|
||||
import { BaseTerminalTabComponent } from 'tabby-terminal'
|
||||
import { LocalProfile, SessionOptions } from '../api'
|
||||
import { Session } from '../session'
|
||||
@@ -74,7 +74,7 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
|
||||
this.recoveryStateChangedHint.next()
|
||||
}
|
||||
|
||||
async getRecoveryToken (options?: GetRecoveryTokenOptions): Promise<any> {
|
||||
async getRecoveryToken (): Promise<any> {
|
||||
const cwd = this.session ? await this.session.getWorkingDirectory() : null
|
||||
return {
|
||||
type: 'app:local-tab',
|
||||
@@ -83,10 +83,10 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
|
||||
options: {
|
||||
...this.profile.options,
|
||||
cwd: cwd ?? this.profile.options.cwd,
|
||||
restoreFromPTYID: options?.includeState && this.session?.getPTYID(),
|
||||
restoreFromPTYID: this.session?.getPTYID(),
|
||||
},
|
||||
},
|
||||
savedState: options?.includeState && this.frontend?.saveState(),
|
||||
savedState: this.frontend?.saveState(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,14 +108,8 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
|
||||
return (await this.platform.showMessageBox(
|
||||
{
|
||||
type: 'warning',
|
||||
message: this.translate.instant(
|
||||
'"{command}" is still running. Close?',
|
||||
children[0],
|
||||
),
|
||||
buttons: [
|
||||
this.translate.instant('Kill'),
|
||||
this.translate.instant('Cancel'),
|
||||
],
|
||||
message: `"${children[0].command}" is still running. Close?`,
|
||||
buttons: ['Kill', 'Cancel'],
|
||||
defaultId: 0,
|
||||
cancelId: 1,
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HotkeyDescription, HotkeyProvider, TranslateService } from 'tabby-core'
|
||||
import { HotkeyDescription, HotkeyProvider } from 'tabby-core'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
@@ -7,12 +7,10 @@ export class LocalTerminalHotkeyProvider extends HotkeyProvider {
|
||||
hotkeys: HotkeyDescription[] = [
|
||||
{
|
||||
id: 'new-tab',
|
||||
name: this.translate.instant('New tab'),
|
||||
name: 'New tab',
|
||||
},
|
||||
]
|
||||
|
||||
constructor (private translate: TranslateService) { super() }
|
||||
|
||||
async provide (): Promise<HotkeyDescription[]> {
|
||||
return this.hotkeys
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import deepClone from 'clone-deep'
|
||||
import { Injectable, Inject } from '@angular/core'
|
||||
import { ProfileProvider, NewTabParameters, ConfigService, SplitTabComponent, AppService, PartialProfile, TranslateService } from 'tabby-core'
|
||||
import { ProfileProvider, NewTabParameters, ConfigService, SplitTabComponent, AppService, PartialProfile } from 'tabby-core'
|
||||
import { TerminalTabComponent } from './components/terminalTab.component'
|
||||
import { LocalProfileSettingsComponent } from './components/localProfileSettings.component'
|
||||
import { ShellProvider, Shell, SessionOptions, LocalProfile } from './api'
|
||||
@@ -8,7 +8,7 @@ import { ShellProvider, Shell, SessionOptions, LocalProfile } from './api'
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class LocalProfilesService extends ProfileProvider<LocalProfile> {
|
||||
id = 'local'
|
||||
name = this.translate.instant('Local terminal')
|
||||
name = 'Local'
|
||||
settingsComponent = LocalProfileSettingsComponent
|
||||
configDefaults = {
|
||||
options: {
|
||||
@@ -29,7 +29,6 @@ export class LocalProfilesService extends ProfileProvider<LocalProfile> {
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private config: ConfigService,
|
||||
private translate: TranslateService,
|
||||
@Inject(ShellProvider) private shellProviders: ShellProvider[],
|
||||
) {
|
||||
super()
|
||||
|
@@ -19,4 +19,18 @@ export class RecoveryProvider extends TabRecoveryProvider<TerminalTabComponent>
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
duplicate (recoveryToken: RecoveryToken): RecoveryToken {
|
||||
return {
|
||||
...recoveryToken,
|
||||
profile: {
|
||||
...recoveryToken.profile,
|
||||
options: {
|
||||
...recoveryToken.profile.options,
|
||||
restoreFromPTYID: null,
|
||||
},
|
||||
},
|
||||
savedState: null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { NgZone, Injectable } from '@angular/core'
|
||||
import { ConfigService, HostAppService, Platform, ProfilesService, TranslateService } from 'tabby-core'
|
||||
import { ConfigService, HostAppService, Platform, ProfilesService } from 'tabby-core'
|
||||
import { ElectronService } from 'tabby-electron'
|
||||
|
||||
/** @hidden */
|
||||
@@ -13,7 +13,6 @@ export class DockMenuService {
|
||||
private hostApp: HostAppService,
|
||||
private zone: NgZone,
|
||||
private profilesService: ProfilesService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
config.changed$.subscribe(() => this.update())
|
||||
}
|
||||
@@ -22,7 +21,7 @@ export class DockMenuService {
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
this.electron.app.setJumpList(this.config.store.profiles.length ? [{
|
||||
type: 'custom',
|
||||
name: this.translate.instant('Profiles'),
|
||||
name: 'Profiles',
|
||||
items: this.config.store.profiles.map(profile => ({
|
||||
type: 'task',
|
||||
program: process.execPath,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import * as fs from 'mz/fs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform, LogService, Logger, TranslateService } from 'tabby-core'
|
||||
import { HostAppService, Platform, LogService, Logger } from 'tabby-core'
|
||||
|
||||
import { ShellProvider, Shell } from '../api'
|
||||
|
||||
@@ -11,7 +11,6 @@ export class LinuxDefaultShellProvider extends ShellProvider {
|
||||
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
private translate: TranslateService,
|
||||
log: LogService,
|
||||
) {
|
||||
super()
|
||||
@@ -28,14 +27,14 @@ export class LinuxDefaultShellProvider extends ShellProvider {
|
||||
this.logger.warn('Could not detect user shell')
|
||||
return [{
|
||||
id: 'default',
|
||||
name: this.translate.instant('User default'),
|
||||
name: 'User default',
|
||||
command: '/bin/sh',
|
||||
env: {},
|
||||
}]
|
||||
} else {
|
||||
return [{
|
||||
id: 'default',
|
||||
name: this.translate.instant('User default'),
|
||||
name: 'User default',
|
||||
command: line.split(':')[6],
|
||||
args: ['--login'],
|
||||
hidden: true,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import promiseIpc, { RendererProcessType } from 'electron-promise-ipc'
|
||||
import { HostAppService, Platform, TranslateService } from 'tabby-core'
|
||||
import { HostAppService, Platform } from 'tabby-core'
|
||||
|
||||
import { ShellProvider, Shell } from '../api'
|
||||
|
||||
@@ -11,7 +11,6 @@ export class MacOSDefaultShellProvider extends ShellProvider {
|
||||
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
@@ -22,7 +21,7 @@ export class MacOSDefaultShellProvider extends ShellProvider {
|
||||
}
|
||||
return [{
|
||||
id: 'default',
|
||||
name: this.translate.instant('OS default'),
|
||||
name: 'OS default',
|
||||
command: await this.getDefaultShellCached(),
|
||||
args: ['--login'],
|
||||
hidden: true,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HostAppService, Platform, TranslateService } from 'tabby-core'
|
||||
import { HostAppService, Platform } from 'tabby-core'
|
||||
|
||||
import { ShellProvider, Shell } from '../api'
|
||||
|
||||
@@ -17,7 +17,6 @@ export class WindowsDefaultShellProvider extends ShellProvider {
|
||||
wsl: WSLShellProvider,
|
||||
stock: WindowsStockShellsProvider,
|
||||
private hostApp: HostAppService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
this.providers = [
|
||||
@@ -40,7 +39,7 @@ export class WindowsDefaultShellProvider extends ShellProvider {
|
||||
return [{
|
||||
...shell,
|
||||
id: 'default',
|
||||
name: this.translate.instant('OS default ({name})', shell),
|
||||
name: `OS default (${shell.name})`,
|
||||
hidden: true,
|
||||
env: {},
|
||||
}]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user