mirror of
https://github.com/Eugeny/tabby.git
synced 2025-08-10 11:21:53 +00:00
Compare commits
14 Commits
all-contri
...
commands
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c12b445ccd | ||
![]() |
5d8ff72850 | ||
![]() |
e247ff73b2 | ||
![]() |
ed5ff1113c | ||
![]() |
a5fcb83ad0 | ||
![]() |
da5342b4a7 | ||
![]() |
3c7f1079dd | ||
![]() |
c7e01eab0f | ||
![]() |
ffddc36ee0 | ||
![]() |
b2671826c6 | ||
![]() |
fec5d809b7 | ||
![]() |
cf09d95602 | ||
![]() |
266dfe15a3 | ||
![]() |
868f7ba70e |
@@ -635,10 +635,10 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "X-0x01",
|
||||
"name": "X-0x01",
|
||||
"login": "0x973",
|
||||
"name": "0x973",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19320096?v=4",
|
||||
"profile": "http://pingbase.cn",
|
||||
"profile": "https://github.com/0x973",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
@@ -1274,6 +1274,15 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cfs4819",
|
||||
"name": "Chen Fansong",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/53071761?v=4",
|
||||
"profile": "https://github.com/cfs4819",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
@@ -20,7 +20,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Diese README ist auch verfügbar in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
Diese README ist auch verfügbar in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -243,7 +243,7 @@ Dank geht an diese wunderbaren Menschen ([emoji key](https://allcontributors.org
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -334,6 +334,7 @@ Dank geht an diese wunderbaren Menschen ([emoji key](https://allcontributors.org
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Este fichero README está disponible en: <a href="./README.md">:gb: English</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
Este fichero README está disponible en: <a href="./README.md">:gb: English</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -245,7 +245,7 @@ Gracias a estas maravillosas personas ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -336,6 +336,7 @@ Gracias a estas maravillosas personas ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
This README is also available in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
This README is also available in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -242,7 +242,7 @@ Terima kasih kepada mereka yang telah membantu ([emoji key](https://allcontribut
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -333,6 +333,7 @@ Terima kasih kepada mereka yang telah membantu ([emoji key](https://allcontribut
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Questo README è disponibile anche in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
Questo README è disponibile anche in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
|
||||
----
|
||||
|
||||
@@ -238,7 +238,7 @@ Grazie a queste persone meravigliose ([emoji key](https://allcontributors.org/do
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -329,6 +329,7 @@ Grazie a queste persone meravigliose ([emoji key](https://allcontributors.org/do
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -28,7 +28,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
このREADMEは次の言語でもご覧いただけます: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
このREADMEは次の言語でもご覧いただけます: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -253,7 +253,7 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -344,6 +344,7 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -19,6 +19,11 @@
|
||||
* [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">
|
||||
This README is also available in: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
**Tabby** (구 **Terminus**)는 Windows, macOS 및 Linux용으로 뛰어난 구성의 터미널 에뮬레이터, SSH 및 시리얼 클라이언트입니다.
|
||||
@@ -232,7 +237,7 @@ Pull requests and plugins are welcome!
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -323,6 +328,7 @@ Pull requests and plugins are welcome!
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -29,7 +29,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
This README is also available in: <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">🇧🇷 Português</a>
|
||||
This README is also available in: <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -131,7 +131,7 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
|
||||
* [background](https://github.com/moemoechu/tabby-background) - change Tabby background image and more...
|
||||
* [highlight](https://github.com/moemoechu/tabby-highlight) - Tabby terminal keyword highlight plugin
|
||||
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - In-app web authentication popups (Built primarily for warpgate in-browser auth)
|
||||
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - In-app web authentication popups (Built primarily for warpgate in-browser auth)
|
||||
|
||||
<a name="themes"></a>
|
||||
|
||||
@@ -259,7 +259,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -350,6 +350,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
363
README.pl-PL.md
Normal file
363
README.pl-PL.md
Normal file
@@ -0,0 +1,363 @@
|
||||
[](https://tabby.sh)
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Eugeny/tabby/releases/latest"><img alt="Wszystkie wydania na GitHubie" src="https://img.shields.io/github/downloads/eugeny/tabby/total.svg?label=POBRANIA&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="Przetłumacz" 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>
|
||||
|
||||
---
|
||||
|
||||
|
||||
> 👋 Zarządzasz zdalnymi środowiskami? Rzuć okiem na [WarpGate, inteligentny serwer typu bastion SSH/HTTP/MySQL](https://github.com/warp-tech/warpgate), świetnie współdziała z Tabby, pokochasz go!
|
||||
|
||||
> 👋 [Tabby-Web](https://github.com/Eugeny/tabby-web) poszukuje sponsorów. Nie jestem w stanie pokryć kosztów hostowania całej infrastruktury, jeśli jesteś zainteresowany wsparciem, proszę [skontakuj się ze mną!](https://twitter.com/eugeeeeny)
|
||||
|
||||
|
||||
----
|
||||
|
||||
### Pobieranie:
|
||||
|
||||
* [Ostatnie wydania](https://github.com/Eugeny/tabby/releases/latest)
|
||||
* [Repozytoria](https://packagecloud.io/eugeny/tabby): [Systemy Debian/Ubuntu](https://packagecloud.io/eugeny/tabby/install#bash-deb), [Środowiska RPM](https://packagecloud.io/eugeny/tabby/install#bash-rpm)
|
||||
* [Ostatnie wydania developerskie](https://nightly.link/Eugeny/tabby/workflows/build/master)
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Ten plik README jest również dostępny w językach: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">🇧🇷 Português</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
[**Tabby**](https://tabby.sh) (formalnie **Terminus**) to wysoce konfigurowalny emulator konsoli, SSH oraz klienta konsoli szeregowej na systemy Windows 10, macOS oraz Linux
|
||||
|
||||
* Zintegrowany klient SSH i Telnet oraz menedżer sesji
|
||||
* Zintegrowany klient terminala szeregowego
|
||||
* Motywy and palety kolorów
|
||||
* W pełni konfigurowalne skróty klawiszowe
|
||||
* Dzielenie ekranu
|
||||
* Zapamiętywanie okien z poprzednich sesji
|
||||
* PowerShell (oraz PS Core), WSL, Git-Bash, Cygwin, MSYS2, Cmder i wsparcie dla CMD
|
||||
* Bezpośredni transfer plików sesji SSH przez Zmodem
|
||||
* Pełne wsparcie dla znaków Unicode wraz z podwójnymi znakami
|
||||
* Nie zawieszanie się przy szybko wyświetlanych wynikach
|
||||
* Pełne doświadczenie powłoki na systemie Windows zawierającej podpowiedzi (przez Clink)
|
||||
* Zintegrowany zaszyfrowany kontener na klucze SSH i jego konfigurację
|
||||
* Klient SSH, SFTP oraz Telnet dostępny jako [aplikacja webowa](https://tabby.sh/app) (również jako [własna instacja](https://github.com/Eugeny/tabby-web)).
|
||||
|
||||
# Spis treści <!-- omit in toc -->
|
||||
|
||||
- [Czym jest, a czym nie jest Tabby](#what-tabby-is-and-isnt)
|
||||
- [Funkcje konsoli](#terminal-features)
|
||||
- [Klient SSH](#ssh-client)
|
||||
- [Konsola szeregowa](#serial-terminal)
|
||||
- [Wersja przenośna](#portable)
|
||||
- [Wtyczki](#plugins)
|
||||
- [Motywy i palety kolorów](#themes)
|
||||
- [Współtworzenie](#contributing)
|
||||
|
||||
<a name="about"></a>
|
||||
|
||||
# Czym jest, a czym nie jest Tabby
|
||||
|
||||
* **Tabby jest** alternatywą dla standardowej konsoli Windows (conhost), PowerShell ISE, PuTTY, Terminal.app oraz iTerm z macOS
|
||||
|
||||
* **Tabby nie jest** nową powłoką lub zamiennikiem dla MinGW czy Cygwin. Nie jest również zatrważająco szybki - jeśli ważne jest dla Ciebie użycie pamięci RAM, rozważ użycie [Conemu](https://conemu.github.io) lub [Alacritty](https://github.com/jwilm/alacritty)
|
||||
|
||||
<a name="terminal"></a>
|
||||
|
||||
# Funkcje konsoli
|
||||
|
||||

|
||||
|
||||
* Konsola V220 + wiele rozszerzeń
|
||||
* Wiele nakładających się podzielonych okien
|
||||
* Okna na każdej stronie ekranu
|
||||
* Opcjonalne dokowanie okna za pomocą skrótu ("Quake console")
|
||||
* Wykrywanie postępu (Pasek)
|
||||
* Powiadomienia przy ukończeniu procesu podczas postępu
|
||||
* Wklejanie z nawiasami, ostrzeżenie przy wielu liniach
|
||||
* Wsparcie różnych czcionek
|
||||
* Niestandardowe profile powłoki
|
||||
* Opcjonalne wklejanie PPM oraz kopiowanie na zaznaczeniu (Styl PuTTY)
|
||||
|
||||
<a name="ssh"></a>
|
||||
|
||||
# Klient SSH
|
||||
|
||||

|
||||
|
||||
* Klient SSH2 z zarządzaniem połączeń
|
||||
* X11 oraz przekierowywanie portów
|
||||
* Automatyczne przejście między hostami
|
||||
* Przekierowanie agenta (Pageant oraz Windowsowy natywny "OpenSSH Agent")
|
||||
* Skrypty logowania
|
||||
|
||||
<a name="serial"></a>
|
||||
|
||||
# Konsola Szeregowa
|
||||
|
||||
* Zapisane połączenia
|
||||
* Wczytywanie danych wejścia linii
|
||||
* Opcjonalna konwersja danych wejścia i wyjścia na szesnastkowe "byte-by-byte"
|
||||
* Konwersja na nową linię
|
||||
* Automatyczne połączenie po rozłączeniu
|
||||
|
||||
<a name="portable"></a>
|
||||
|
||||
# Wersja przenośna
|
||||
|
||||
Tabby będzie uruchamiał się jako aplikacja przenośna, tylko wtedy, kiedy utworzysz folder `data` w tej samej lokacji, w której znajduje się `Tabby.exe`.
|
||||
|
||||
<a name="plugins"></a>
|
||||
|
||||
# Wtyczki
|
||||
|
||||
Wtyczki (jak i motywy) mogą być instalowane bezpośrednio z widoku ustawień w środku aplikacji Tabby.
|
||||
|
||||
* [docker](https://github.com/Eugeny/tabby-docker) - połączenie z kontenerami Docker
|
||||
* [title-control](https://github.com/kbjr/terminus-title-control) - pozwala na zmienianie tytułu konsoli jako prefiks, sufiks lub/albo tekst do usunięcia
|
||||
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - szybko wysyłaj komendy z jednej konsoli do wielu
|
||||
* [save-output](https://github.com/Eugeny/tabby-save-output) - zapisuj dane wyjściowe do pliku
|
||||
* [sync-config](https://github.com/starxg/terminus-sync-config) - synchronizuj konfigurację przez Gista lub Gitee
|
||||
* [clippy](https://github.com/Eugeny/tabby-clippy) - przykładowa wtyczka, która zwyczajnie denerwuje
|
||||
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - pozwala na utworzenie niestandardowego profilu pracy w aplikacji odpowiednio do konfiguracji
|
||||
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - otwiera domyślną przeglądarkę z zaznaczonym tekstem w oknie Tabby
|
||||
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - otwiera okno z połączeniem SFTP dla połączeń SSH jak SecureCRT
|
||||
* [background](https://github.com/moemoechu/tabby-background) - zmień tło Tabby oraz wiele więcej
|
||||
* [highlight](https://github.com/moemoechu/tabby-highlight) - Tabby terminal keyword highlight plugin
|
||||
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - okienka autoryzacji wewnątrz konsoli (Zbudowany głównie pod autoryzację projektu Warpgate w przeglądarce)
|
||||
|
||||
<a name="themes"></a>
|
||||
|
||||
# Motywy i palety kolorów
|
||||
|
||||
* [hype](https://github.com/Eugeny/tabby-theme-hype) - Motyw zainspirowany konsolą "Hyper"
|
||||
* [relaxed](https://github.com/Relaxed-Theme/relaxed-terminal-themes#terminus) - Motyw "pełnej relaksacji"
|
||||
* [gruvbox](https://github.com/porkloin/terminus-theme-gruvbox) - Motyw zainspirowany konsolą "Hyper" (kolejny)
|
||||
* [windows10](https://www.npmjs.com/package/terminus-theme-windows10) - Motyw zainspirowany Microsoftem
|
||||
* [altair](https://github.com/yxuko/terminus-altair) - Motwy autorstwa Yacine Kanzari
|
||||
* [catppuccin](https://github.com/catppuccin/tabby) - Paleta pastelowa dla Tabby
|
||||
* [noctis](https://github.com/aaronhuggins/tabby-colors-noctis) - Paleta kolorów zainspirowana motywem Noctis z VS Code
|
||||
|
||||
# Sponsorzy <!-- omit in toc -->
|
||||
|
||||
[](https://packagecloud.io)
|
||||
|
||||
[**packagecloud**](https://packagecloud.io) zapewnia darmowe utrzymanie repozytorium Debian/RPM
|
||||
|
||||
[](https://keygen.sh/?via=eugene)
|
||||
|
||||
[**keygen**](https://keygen.sh/?via=eugene) zapewnia darmowe wydawanie oraz automatycznie utrzymywanie strony
|
||||
|
||||
<a name="contributing"></a>
|
||||
# Współtworzenie
|
||||
|
||||
Pull requesty and dodawanie nowych wtyczek jest mile widziane!
|
||||
|
||||
Zobacz plik [HAKOWANIE.md](https://github.com/Eugeny/tabby/blob/master/HACKING.md) oraz [Dokumentację API](https://docs.tabby.sh/), aby poznać, jak projekt jest prowadzony wraz ze wstępnym poradnikiem jak tworzyć wtyczki.
|
||||
|
||||
---
|
||||
<a name="contributors"></a>
|
||||
|
||||
Dziękujemy wszystkim osobom współtworzącym ten projekt ([emotki są specjalizacją](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.russellmyers.com"><img src="https://avatars2.githubusercontent.com/u/184085?v=4?s=100" width="100px;" alt="Russell Myers"/><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" valign="top" width="14.28%"><a href="http://www.morwire.com"><img src="https://avatars1.githubusercontent.com/u/3991658?v=4?s=100" width="100px;" alt="Austin Warren"/><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" valign="top" width="14.28%"><a href="https://github.com/Drachenkaetzchen"><img src="https://avatars1.githubusercontent.com/u/162974?v=4?s=100" width="100px;" alt="Felicia Hummel"/><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" valign="top" width="14.28%"><a href="https://github.com/mikemaccana"><img src="https://avatars2.githubusercontent.com/u/172594?v=4?s=100" width="100px;" alt="Mike MacCana"/><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" valign="top" width="14.28%"><a href="https://github.com/yxuko"><img src="https://avatars1.githubusercontent.com/u/1786317?v=4?s=100" width="100px;" alt="Yacine Kanzari"/><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" valign="top" width="14.28%"><a href="https://github.com/BBJip"><img src="https://avatars2.githubusercontent.com/u/32908927?v=4?s=100" width="100px;" alt="BBJip"/><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" valign="top" width="14.28%"><a href="https://github.com/Futagirl"><img src="https://avatars2.githubusercontent.com/u/33533958?v=4?s=100" width="100px;" alt="Futagirl"/><br /><sub><b>Futagirl</b></sub></a><br /><a href="#design-Futagirl" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.levrik.io"><img src="https://avatars3.githubusercontent.com/u/9491603?v=4?s=100" width="100px;" alt="Levin Rickert"/><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" valign="top" width="14.28%"><a href="https://kwonoj.github.io"><img src="https://avatars2.githubusercontent.com/u/1210596?v=4?s=100" width="100px;" alt="OJ Kwon"/><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" valign="top" width="14.28%"><a href="https://github.com/Domain"><img src="https://avatars2.githubusercontent.com/u/903197?v=4?s=100" width="100px;" alt="domain"/><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" valign="top" width="14.28%"><a href="http://www.jbrumond.me"><img src="https://avatars1.githubusercontent.com/u/195127?v=4?s=100" width="100px;" alt="James Brumond"/><br /><sub><b>James Brumond</b></sub></a><br /><a href="#plugin-kbjr" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://www.growingwiththeweb.com"><img src="https://avatars0.githubusercontent.com/u/2193314?v=4?s=100" width="100px;" alt="Daniel Imms"/><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" valign="top" width="14.28%"><a href="https://github.com/baflo"><img src="https://avatars2.githubusercontent.com/u/834350?v=4?s=100" width="100px;" alt="Florian Bachmann"/><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" valign="top" width="14.28%"><a href="http://michael-kuehnel.de"><img src="https://avatars2.githubusercontent.com/u/441011?v=4?s=100" width="100px;" alt="Michael Kühnel"/><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" valign="top" width="14.28%"><a href="https://github.com/NieLeben"><img src="https://avatars3.githubusercontent.com/u/47182955?v=4?s=100" width="100px;" alt="Tilmann Meyer"/><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" valign="top" width="14.28%"><a href="http://www.jubeat.net"><img src="https://avatars3.githubusercontent.com/u/11289158?v=4?s=100" width="100px;" alt="PM Extra"/><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" valign="top" width="14.28%"><a href="https://jjuhas.keybase.pub//"><img src="https://avatars1.githubusercontent.com/u/6438760?v=4?s=100" width="100px;" alt="Jonathan"/><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" valign="top" width="14.28%"><a href="https://hans-koch.me"><img src="https://avatars0.githubusercontent.com/u/1093709?v=4?s=100" width="100px;" alt="Hans Koch"/><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" valign="top" width="14.28%"><a href="http://thepuzzlemaker.info"><img src="https://avatars3.githubusercontent.com/u/12666617?v=4?s=100" width="100px;" alt="Dak Smyth"/><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" valign="top" width="14.28%"><a href="http://yfwz100.github.io"><img src="https://avatars2.githubusercontent.com/u/983211?v=4?s=100" width="100px;" alt="Wang Zhi"/><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" valign="top" width="14.28%"><a href="https://github.com/jack1142"><img src="https://avatars0.githubusercontent.com/u/6032823?v=4?s=100" width="100px;" alt="jack1142"/><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" valign="top" width="14.28%"><a href="https://github.com/hdougie"><img src="https://avatars1.githubusercontent.com/u/450799?v=4?s=100" width="100px;" alt="Howie Douglas"/><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" valign="top" width="14.28%"><a href="https://chriskaczor.com"><img src="https://avatars2.githubusercontent.com/u/180906?v=4?s=100" width="100px;" alt="Chris Kaczor"/><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" valign="top" width="14.28%"><a href="https://www.boxmein.net"><img src="https://avatars1.githubusercontent.com/u/358714?v=4?s=100" width="100px;" alt="Johannes Kadak"/><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" valign="top" width="14.28%"><a href="https://github.com/LeSeulArtichaut"><img src="https://avatars1.githubusercontent.com/u/38361244?v=4?s=100" width="100px;" alt="LeSeulArtichaut"/><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" valign="top" width="14.28%"><a href="https://github.com/CyrilTaylor"><img src="https://avatars0.githubusercontent.com/u/12631466?v=4?s=100" width="100px;" alt="Cyril Taylor"/><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" valign="top" width="14.28%"><a href="https://github.com/nstefanou"><img src="https://avatars3.githubusercontent.com/u/51129173?v=4?s=100" width="100px;" alt="nstefanou"/><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" valign="top" width="14.28%"><a href="https://github.com/orin220444"><img src="https://avatars3.githubusercontent.com/u/30747229?v=4?s=100" width="100px;" alt="orin220444"/><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" valign="top" width="14.28%"><a href="https://github.com/Goobles"><img src="https://avatars3.githubusercontent.com/u/8776771?v=4?s=100" width="100px;" alt="Gobius Dolhain"/><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" valign="top" width="14.28%"><a href="https://github.com/3l0w"><img src="https://avatars2.githubusercontent.com/u/37798980?v=4?s=100" width="100px;" alt="Gwilherm Folliot"/><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" valign="top" width="14.28%"><a href="https://github.com/Dimitory"><img src="https://avatars0.githubusercontent.com/u/475955?v=4?s=100" width="100px;" alt="Dmitry Pronin"/><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" valign="top" width="14.28%"><a href="https://github.com/JonathanBeverley"><img src="https://avatars1.githubusercontent.com/u/20328966?v=4?s=100" width="100px;" alt="Jonathan Beverley"/><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" valign="top" width="14.28%"><a href="https://github.com/zend"><img src="https://avatars1.githubusercontent.com/u/25160?v=4?s=100" width="100px;" alt="Zenghai Liang"/><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" valign="top" width="14.28%"><a href="https://about.me/matishadow"><img src="https://avatars0.githubusercontent.com/u/9083085?v=4?s=100" width="100px;" alt="Mateusz Tracz"/><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" valign="top" width="14.28%"><a href="https://zergpool.com"><img src="https://avatars3.githubusercontent.com/u/36234677?v=4?s=100" width="100px;" alt="pinpin"/><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" valign="top" width="14.28%"><a href="https://github.com/TakuroOnoda"><img src="https://avatars0.githubusercontent.com/u/1407926?v=4?s=100" width="100px;" alt="Takuro Onoda"/><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" valign="top" width="14.28%"><a href="https://github.com/frauhottelmann"><img src="https://avatars2.githubusercontent.com/u/902705?v=4?s=100" width="100px;" alt="frauhottelmann"/><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" valign="top" width="14.28%"><a href="http://patalong.pl"><img src="https://avatars.githubusercontent.com/u/29167842?v=4?s=100" width="100px;" alt="Piotr Patalong"/><br /><sub><b>Piotr Patalong</b></sub></a><br /><a href="#design-VectorKappa" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/clarkwang"><img src="https://avatars.githubusercontent.com/u/157076?v=4?s=100" width="100px;" alt="Clark Wang"/><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" valign="top" width="14.28%"><a href="https://github.com/iamchating"><img src="https://avatars.githubusercontent.com/u/7088153?v=4?s=100" width="100px;" alt="iamchating"/><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" valign="top" width="14.28%"><a href="https://github.com/starxg"><img src="https://avatars.githubusercontent.com/u/34997494?v=4?s=100" width="100px;" alt="starxg"/><br /><sub><b>starxg</b></sub></a><br /><a href="#plugin-starxg" title="Plugin/utility libraries">🔌</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://hashnote.net/"><img src="https://avatars.githubusercontent.com/u/546312?v=4?s=100" width="100px;" alt="Alisue"/><br /><sub><b>Alisue</b></sub></a><br /><a href="#design-lambdalisue" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ydcool"><img src="https://avatars.githubusercontent.com/u/5668295?v=4?s=100" width="100px;" alt="Dominic Yin"/><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" valign="top" width="14.28%"><a href="https://github.com/bdr99"><img src="https://avatars.githubusercontent.com/u/2292715?v=4?s=100" width="100px;" alt="Brandon Rothweiler"/><br /><sub><b>Brandon Rothweiler</b></sub></a><br /><a href="#design-bdr99" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://git.io/JnP49"><img src="https://avatars.githubusercontent.com/u/63876444?v=4?s=100" width="100px;" alt="Logic Machine"/><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" valign="top" width="14.28%"><a href="https://github.com/cypherbits"><img src="https://avatars.githubusercontent.com/u/10424900?v=4?s=100" width="100px;" alt="cypherbits"/><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" valign="top" width="14.28%"><a href="https://modulolotus.net"><img src="https://avatars.githubusercontent.com/u/946421?v=4?s=100" width="100px;" alt="Matthew Davidson"/><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" valign="top" width="14.28%"><a href="https://github.com/al-wi"><img src="https://avatars.githubusercontent.com/u/11092199?v=4?s=100" width="100px;" alt="Alexander Wiedemann"/><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" valign="top" width="14.28%"><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" valign="top" width="14.28%"><a href="https://github.com/Me1onRind"><img src="https://avatars.githubusercontent.com/u/19531270?v=4?s=100" width="100px;" alt="zZ"/><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" valign="top" width="14.28%"><a href="https://github.com/tainoNZ"><img src="https://avatars.githubusercontent.com/u/49261322?v=4?s=100" width="100px;" alt="Aaron Davison"/><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" valign="top" width="14.28%"><a href="https://github.com/composer404"><img src="https://avatars.githubusercontent.com/u/58251560?v=4?s=100" width="100px;" alt="Przemyslaw Kozik"/><br /><sub><b>Przemyslaw Kozik</b></sub></a><br /><a href="#design-composer404" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/highfredo"><img src="https://avatars.githubusercontent.com/u/5951524?v=4?s=100" width="100px;" alt="Alfredo Arellano de la Fuente"/><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" valign="top" width="14.28%"><a href="https://github.com/NessunKim"><img src="https://avatars.githubusercontent.com/u/12974079?v=4?s=100" width="100px;" alt="MH Kim"/><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" valign="top" width="14.28%"><a href="https://discord.gg/4c5EVTBhtp"><img src="https://avatars.githubusercontent.com/u/40345645?v=4?s=100" width="100px;" alt="Marmota"/><br /><sub><b>Marmota</b></sub></a><br /><a href="#design-jaimeadf" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://ares.zone"><img src="https://avatars.githubusercontent.com/u/40336192?v=4?s=100" width="100px;" alt="Ares Andrew"/><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" valign="top" width="14.28%"><a href="https://usual.io/"><img src="https://avatars.githubusercontent.com/u/780052?v=4?s=100" width="100px;" alt="George Korsnick"/><br /><sub><b>George Korsnick</b></sub></a><br /><a href="#financial-gkor" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://about.me/ulu"><img src="https://avatars.githubusercontent.com/u/872764?v=4?s=100" width="100px;" alt="Artem Smirnov"/><br /><sub><b>Artem Smirnov</b></sub></a><br /><a href="#financial-uluhonolulu" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nevotheless"><img src="https://avatars.githubusercontent.com/u/779797?v=4?s=100" width="100px;" alt="Tim Kopplow"/><br /><sub><b>Tim Kopplow</b></sub></a><br /><a href="#financial-nevotheless" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mrthock"><img src="https://avatars.githubusercontent.com/u/88901709?v=4?s=100" width="100px;" alt="mrthock"/><br /><sub><b>mrthock</b></sub></a><br /><a href="#financial-mrthock" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lrottach"><img src="https://avatars.githubusercontent.com/u/50323692?v=4?s=100" width="100px;" alt="Lukas Rottach"/><br /><sub><b>Lukas Rottach</b></sub></a><br /><a href="#financial-lrottach" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/boonkerz"><img src="https://avatars.githubusercontent.com/u/277321?v=4?s=100" width="100px;" alt="boonkerz"/><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" valign="top" width="14.28%"><a href="https://github.com/milotype"><img src="https://avatars.githubusercontent.com/u/43657314?v=4?s=100" width="100px;" alt="Milo Ivir"/><br /><sub><b>Milo Ivir</b></sub></a><br /><a href="#translation-milotype" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JasonCubic"><img src="https://avatars.githubusercontent.com/u/8921015?v=4?s=100" width="100px;" alt="JasonCubic"/><br /><sub><b>JasonCubic</b></sub></a><br /><a href="#design-JasonCubic" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MaxWaldorf"><img src="https://avatars.githubusercontent.com/u/15877853?v=4?s=100" width="100px;" alt="MaxWaldorf"/><br /><sub><b>MaxWaldorf</b></sub></a><br /><a href="#infra-MaxWaldorf" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://microhobby.com.br/blog"><img src="https://avatars.githubusercontent.com/u/2633321?v=4?s=100" width="100px;" alt="Matheus Castello"/><br /><sub><b>Matheus Castello</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=microhobby" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jai-JAP"><img src="https://avatars.githubusercontent.com/u/78354625?v=4?s=100" width="100px;" alt="Jai A P"/><br /><sub><b>Jai A P</b></sub></a><br /><a href="#platform-Jai-JAP" title="Packaging/porting to new platform">📦</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://blog.ysc3839.com"><img src="https://avatars.githubusercontent.com/u/12028138?v=4?s=100" width="100px;" alt="Richard Yu"/><br /><sub><b>Richard Yu</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ysc3839" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/artu-ole"><img src="https://avatars.githubusercontent.com/u/15938416?v=4?s=100" width="100px;" alt="artu-ole"/><br /><sub><b>artu-ole</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=artu-ole" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://timagribanov.github.io/"><img src="https://avatars.githubusercontent.com/u/48593815?v=4?s=100" width="100px;" alt="Timofey Gribanov"/><br /><sub><b>Timofey Gribanov</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=TimaGribanov" title="Documentation">📖</a> <a href="#translation-TimaGribanov" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://git.christianbingman.com"><img src="https://avatars.githubusercontent.com/u/42191425?v=4?s=100" width="100px;" alt="Christian Bingman"/><br /><sub><b>Christian Bingman</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ChristianBingman" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://zhangzhipeng2023.cn/"><img src="https://avatars.githubusercontent.com/u/5310853?v=4?s=100" width="100px;" alt="zhipeng"/><br /><sub><b>zhipeng</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Ox0400" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/woodmeal"><img src="https://avatars.githubusercontent.com/u/104011197?v=4?s=100" width="100px;" alt="woodmeal"/><br /><sub><b>woodmeal</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=woodmeal" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://magiclike.codeberg.page/"><img src="https://avatars.githubusercontent.com/u/82117109?v=4?s=100" width="100px;" alt="MagicLike"/><br /><sub><b>MagicLike</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=MagicLike" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hisamafahri"><img src="https://avatars.githubusercontent.com/u/65691613?v=4?s=100" width="100px;" alt="Hisam Fahri"/><br /><sub><b>Hisam Fahri</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hisamafahri" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://liangchengj.com"><img src="https://avatars.githubusercontent.com/u/48881023?v=4?s=100" width="100px;" alt="Liangcheng Juves"/><br /><sub><b>Liangcheng Juves</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=LiangchengJ" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/attet"><img src="https://avatars.githubusercontent.com/u/1911416?v=4?s=100" width="100px;" alt="Atte Timonen"/><br /><sub><b>Atte Timonen</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=attet" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/joaolmpinto/"><img src="https://avatars.githubusercontent.com/u/1143125?v=4?s=100" width="100px;" alt="João Pinto"/><br /><sub><b>João Pinto</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=joaompinto" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Qiming-Liu"><img src="https://avatars.githubusercontent.com/u/68600416?v=4?s=100" width="100px;" alt="Alan"/><br /><sub><b>Alan</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Qiming-Liu" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://74th.tech/"><img src="https://avatars.githubusercontent.com/u/1060011?v=4?s=100" width="100px;" alt="Atsushi Morimoto"/><br /><sub><b>Atsushi Morimoto</b></sub></a><br /><a href="#financial-74th" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://arles.red/"><img src="https://avatars.githubusercontent.com/u/5369096?v=4?s=100" width="100px;" alt="Arles"/><br /><sub><b>Arles</b></sub></a><br /><a href="#financial-aarles" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://pentestbook.six2dez.com/"><img src="https://avatars.githubusercontent.com/u/24670991?v=4?s=100" width="100px;" alt="six2dez"/><br /><sub><b>six2dez</b></sub></a><br /><a href="#financial-six2dez" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CandiceJoy"><img src="https://avatars.githubusercontent.com/u/8854890?v=4?s=100" width="100px;" alt="Candice"/><br /><sub><b>Candice</b></sub></a><br /><a href="#financial-CandiceJoy" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kingrowen"><img src="https://avatars.githubusercontent.com/u/13178700?v=4?s=100" width="100px;" alt="Rowen Willabus"/><br /><sub><b>Rowen Willabus</b></sub></a><br /><a href="#financial-kingrowen" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://hengy1.top/"><img src="https://avatars.githubusercontent.com/u/98681454?v=4?s=100" width="100px;" alt="HengY1Coding✨"/><br /><sub><b>HengY1Coding✨</b></sub></a><br /><a href="#financial-HengY1Sky" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FrancisHG"><img src="https://avatars.githubusercontent.com/u/1611626?v=4?s=100" width="100px;" alt="Francis Gelderloos"/><br /><sub><b>Francis Gelderloos</b></sub></a><br /><a href="#financial-FrancisHG" title="Financial">💵</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/astromasoud"><img src="https://avatars.githubusercontent.com/u/18737721?v=4?s=100" width="100px;" alt="astromasoud"/><br /><sub><b>astromasoud</b></sub></a><br /><a href="#financial-astromasoud" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://spirit55555.dk/"><img src="https://avatars.githubusercontent.com/u/2357565?v=4?s=100" width="100px;" alt="Anders G. Jørgensen"/><br /><sub><b>Anders G. Jørgensen</b></sub></a><br /><a href="#financial-Spirit55555" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/djradon"><img src="https://avatars.githubusercontent.com/u/5224156?v=4?s=100" width="100px;" alt="Dave Richardson"/><br /><sub><b>Dave Richardson</b></sub></a><br /><a href="#financial-djradon" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/tpberntsen"><img src="https://avatars.githubusercontent.com/u/922318?v=4?s=100" width="100px;" alt="Thomas Peter Berntsen"/><br /><sub><b>Thomas Peter Berntsen</b></sub></a><br /><a href="#financial-tpberntsen" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt="Ikko Ashimine"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=eltociear" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/giejqf"><img src="https://avatars.githubusercontent.com/u/9211230?v=4?s=100" width="100px;" alt="giejqf"/><br /><sub><b>giejqf</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=giejqf" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LacazeThomas"><img src="https://avatars.githubusercontent.com/u/19855907?v=4?s=100" width="100px;" alt="Thomas LACAZE"/><br /><sub><b>Thomas LACAZE</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=LacazeThomas" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://pochen.me/"><img src="https://avatars.githubusercontent.com/u/1329716?v=4?s=100" width="100px;" alt="Po Chen"/><br /><sub><b>Po Chen</b></sub></a><br /><a href="#financial-princemaple" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://victorchandra.carrd.co/"><img src="https://avatars.githubusercontent.com/u/41635105?v=4?s=100" width="100px;" alt="Victor Chandra"/><br /><sub><b>Victor Chandra</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mzmznasipadang" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daniel347x"><img src="https://avatars.githubusercontent.com/u/309746?v=4?s=100" width="100px;" alt="Dan Nissenbaum"/><br /><sub><b>Dan Nissenbaum</b></sub></a><br /><a href="#financial-daniel347x" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DunklerPhoenix"><img src="https://avatars.githubusercontent.com/u/1261305?v=4?s=100" width="100px;" alt="RogueThorn"/><br /><sub><b>RogueThorn</b></sub></a><br /><a href="#financial-DunklerPhoenix" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://spenserblack.github.io"><img src="https://avatars.githubusercontent.com/u/8546709?v=4?s=100" width="100px;" alt="Spenser Black"/><br /><sub><b>Spenser Black</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=spenserblack" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zuedev"><img src="https://avatars.githubusercontent.com/u/24614929?v=4?s=100" width="100px;" alt="Alex"/><br /><sub><b>Alex</b></sub></a><br /><a href="#financial-zuedev" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://hengy1.top/"><img src="https://avatars.githubusercontent.com/u/98681454?v=4?s=100" width="100px;" alt="HengY1Coding✨"/><br /><sub><b>HengY1Coding✨</b></sub></a><br /><a href="#financial-HengY1Cola" title="Financial">💵</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.stackscale.com/"><img src="https://avatars.githubusercontent.com/u/195768?v=4?s=100" width="100px;" alt="David Carrero"/><br /><sub><b>David Carrero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=dcarrero" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zhoro"><img src="https://avatars.githubusercontent.com/u/1105687?v=4?s=100" width="100px;" alt="Andrii Zhovtiak"/><br /><sub><b>Andrii Zhovtiak</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zhoro" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JohnMasoner"><img src="https://avatars.githubusercontent.com/u/42313377?v=4?s=100" width="100px;" alt="Mason Ma"/><br /><sub><b>Mason Ma</b></sub></a><br /><a href="#financial-JohnMasoner" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ntimo"><img src="https://avatars.githubusercontent.com/u/6145026?v=4?s=100" width="100px;" alt="Timo"/><br /><sub><b>Timo</b></sub></a><br /><a href="#financial-ntimo" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/evinwatson/"><img src="https://avatars.githubusercontent.com/u/24227251?v=4?s=100" width="100px;" alt="Evin Watson"/><br /><sub><b>Evin Watson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=EvinRWatson" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://t.me/hendrjl"><img src="https://avatars.githubusercontent.com/u/15981200?v=4?s=100" width="100px;" alt="Hendra Juli"/><br /><sub><b>Hendra Juli</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=deulizealand" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wkricowski"><img src="https://avatars.githubusercontent.com/u/36803521?v=4?s=100" width="100px;" alt="Wellinton Kricowski"/><br /><sub><b>Wellinton Kricowski</b></sub></a><br /><a href="#financial-wkricowski" title="Financial">💵</a> <a href="https://github.com/Eugeny/tabby/commits?author=wkricowski" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/almzau"><img src="https://avatars.githubusercontent.com/u/29115846?v=4?s=100" width="100px;" alt="Allan"/><br /><sub><b>Allan</b></sub></a><br /><a href="#design-almzau" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://oidamo.de"><img src="https://avatars.githubusercontent.com/u/17959794?v=4?s=100" width="100px;" alt="Benjamin Brandmeier"/><br /><sub><b>Benjamin Brandmeier</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=BenjaminBrandmeier" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/patric1025"><img src="https://avatars.githubusercontent.com/u/65654040?v=4?s=100" width="100px;" alt="patric1025"/><br /><sub><b>patric1025</b></sub></a><br /><a href="#translation-patric1025" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hermitpopcorn"><img src="https://avatars.githubusercontent.com/u/16042129?v=4?s=100" width="100px;" alt="hermitpopcorn"/><br /><sub><b>hermitpopcorn</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=hermitpopcorn" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://joshuatz.com/"><img src="https://avatars.githubusercontent.com/u/17817563?v=4?s=100" width="100px;" alt="Joshua Tzucker"/><br /><sub><b>Joshua Tzucker</b></sub></a><br /><a href="#financial-joshuatz" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/luxifr"><img src="https://avatars.githubusercontent.com/u/665715?v=4?s=100" width="100px;" alt="luxifr"/><br /><sub><b>luxifr</b></sub></a><br /><a href="#financial-luxifr" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ukulanne"><img src="https://avatars.githubusercontent.com/u/28586666?v=4?s=100" width="100px;" alt="Anne Summers"/><br /><sub><b>Anne Summers</b></sub></a><br /><a href="#financial-ukulanne" title="Financial">💵</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Clem-Fern"><img src="https://avatars.githubusercontent.com/u/20025949?v=4?s=100" width="100px;" alt="Clem"/><br /><sub><b>Clem</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Clem-Fern" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/elizabeth-dev"><img src="https://avatars.githubusercontent.com/u/13015727?v=4?s=100" width="100px;" alt="Elizabeth Martín Campos"/><br /><sub><b>Elizabeth Martín Campos</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=elizabeth-dev" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/siccous"><img src="https://avatars.githubusercontent.com/u/7812885?v=4?s=100" width="100px;" alt="Tomáš Hruška"/><br /><sub><b>Tomáš Hruška</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siccous" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/karaketir16"><img src="https://avatars.githubusercontent.com/u/27349806?v=4?s=100" width="100px;" alt="Osman Karaketir"/><br /><sub><b>Osman Karaketir</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=karaketir16" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.gnomegarden.io/"><img src="https://avatars.githubusercontent.com/u/33667144?v=4?s=100" width="100px;" alt="Crypto Gnome"/><br /><sub><b>Crypto Gnome</b></sub></a><br /><a href="#financial-CryptoGnome" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rbukovansky"><img src="https://avatars.githubusercontent.com/u/1004491?v=4?s=100" width="100px;" alt="Richard Bukovansky"/><br /><sub><b>Richard Bukovansky</b></sub></a><br /><a href="#financial-rbukovansky" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pseudocc"><img src="https://avatars.githubusercontent.com/u/85104110?v=4?s=100" width="100px;" alt="catlas"/><br /><sub><b>catlas</b></sub></a><br /><a href="#financial-pseudocc" title="Financial">💵</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://kapocsi.ca"><img src="https://avatars.githubusercontent.com/u/84490604?v=4?s=100" width="100px;" alt="Thomas Kapocsi"/><br /><sub><b>Thomas Kapocsi</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Kapocsi" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://dylhack.dev/"><img src="https://avatars.githubusercontent.com/u/27179786?v=4?s=100" width="100px;" alt="Dylan Hackworth"/><br /><sub><b>Dylan Hackworth</b></sub></a><br /><a href="#financial-dylhack" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/echo304"><img src="https://avatars.githubusercontent.com/u/16456651?v=4?s=100" width="100px;" alt="Sangboak Lee"/><br /><sub><b>Sangboak Lee</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=echo304" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qyecst"><img src="https://avatars.githubusercontent.com/u/13901864?v=4?s=100" width="100px;" alt="qyecst"/><br /><sub><b>qyecst</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=qyecst" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DehanLUO"><img src="https://avatars.githubusercontent.com/u/53093688?v=4?s=100" width="100px;" alt="Han"/><br /><sub><b>Han</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=DehanLUO" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wljince007"><img src="https://avatars.githubusercontent.com/u/88243938?v=4?s=100" width="100px;" alt="wljince007"/><br /><sub><b>wljince007</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=wljince007" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FeroTheFox"><img src="https://avatars.githubusercontent.com/u/52982404?v=4?s=100" width="100px;" alt="fero"/><br /><sub><b>fero</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=FeroTheFox" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://siebsie23.nl/"><img src="https://avatars.githubusercontent.com/u/25083973?v=4?s=100" width="100px;" alt="Sibren"/><br /><sub><b>Sibren</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=siebsie23" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.nathaniel-walser.com"><img src="https://avatars.githubusercontent.com/u/33339996?v=4?s=100" width="100px;" alt="Nathaniel Walser"/><br /><sub><b>Nathaniel Walser</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=nwalser" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aaronhuggins"><img src="https://avatars.githubusercontent.com/u/16567111?v=4?s=100" width="100px;" alt="Aaron Huggins"/><br /><sub><b>Aaron Huggins</b></sub></a><br /><a href="#design-aaronhuggins" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
Ten projekt podlega specyfikacji [dla współautorów](https://github.com/all-contributors/all-contributors). Wszelkiego rodzaju przyczynianie się do rozwoju jest tu mile widziane!
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Esse README também está disponível em: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a>
|
||||
Esse README também está disponível em: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -246,7 +246,7 @@ Obrigado vai para essas pessoas maravilhosas ([emoji key](https://allcontributor
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -337,6 +337,7 @@ Obrigado vai para essas pessoas maravilhosas ([emoji key](https://allcontributor
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
Этот README также доступен на: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
Этот README также доступен на: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.zh-CN.md">:cn: 简体中文</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -238,7 +238,7 @@ Pull-запросы и плагины приветствуются!
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -329,6 +329,7 @@ Pull-запросы и плагины приветствуются!
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
<br/>
|
||||
<p align="center">
|
||||
本 README 还适用于以下语言: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:br: Português</a>
|
||||
本 README 还适用于以下语言: <a href="./README.md">:gb: English</a> · <a href="./README.es-ES.md">:es: Spanish</a> · <a href="./README.ru-RU.md">:ru: Русский</a> · <a href="./README.ko-KR.md">:kr: 한국어</a> · <a href="./README.it-IT.md">:it: Italiano</a> · <a href="./README.de-DE.md">:de: Deutsch</a> · <a href="./README.ja-JP.md">:jp: 日本語</a> · <a href="./README.id-ID.md">:id: Bahasa Indonesia</a> · <a href="./README.pt-BR.md">:brazil: Português</a> · <a href="./README.pl-PL.md">:poland: Polski</a>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -237,7 +237,7 @@
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mwz"><img src="https://avatars.githubusercontent.com/u/1190768?v=4?s=100" width="100px;" alt="Michael Wizner"/><br /><sub><b>Michael Wizner</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mwz" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgrulich"><img src="https://avatars.githubusercontent.com/u/781036?v=4?s=100" width="100px;" alt="Martin"/><br /><sub><b>Martin</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=mgrulich" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersandro"><img src="https://avatars.githubusercontent.com/u/19996309?v=4?s=100" width="100px;" alt="Piersandro Guerrera"/><br /><sub><b>Piersandro Guerrera</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=piersandro" title="Documentation">📖</a> <a href="#translation-piersandro" title="Translation">🌍</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://pingbase.cn"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="X-0x01"/><br /><sub><b>X-0x01</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=X-0x01" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/0x973"><img src="https://avatars.githubusercontent.com/u/19320096?v=4?s=100" width="100px;" alt="0x973"/><br /><sub><b>0x973</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=0x973" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Allenator"><img src="https://avatars.githubusercontent.com/u/11794943?v=4?s=100" width="100px;" alt="Allenator"/><br /><sub><b>Allenator</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=Allenator" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -328,6 +328,7 @@
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://zkxdex.github.io/"><img src="https://avatars.githubusercontent.com/u/66271780?v=4?s=100" width="100px;" alt="KDex"/><br /><sub><b>KDex</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=zKXDEX" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kimbob13"><img src="https://avatars.githubusercontent.com/u/26755098?v=4?s=100" width="100px;" alt="ChangHwan Kim"/><br /><sub><b>ChangHwan Kim</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=kimbob13" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ashneilson"><img src="https://avatars.githubusercontent.com/u/35913512?v=4?s=100" width="100px;" alt="Ash Neilson"/><br /><sub><b>Ash Neilson</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ashneilson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cfs4819"><img src="https://avatars.githubusercontent.com/u/53071761?v=4?s=100" width="100px;" alt="Chen Fansong"/><br /><sub><b>Chen Fansong</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=cfs4819" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import slugify from 'slugify'
|
||||
import { BaseTabComponent } from '../components/baseTab.component'
|
||||
import { MenuItemOptions } from './menu'
|
||||
import { ToolbarButton } from './toolbarButtonProvider'
|
||||
@@ -6,34 +7,33 @@ export enum CommandLocation {
|
||||
LeftToolbar = 'left-toolbar',
|
||||
RightToolbar = 'right-toolbar',
|
||||
StartPage = 'start-page',
|
||||
TabHeaderMenu = 'tab-header-menu',
|
||||
TabBodyMenu = 'tab-body-menu',
|
||||
}
|
||||
|
||||
export class Command {
|
||||
id?: string
|
||||
id: string
|
||||
label: string
|
||||
sublabel?: string
|
||||
locations?: CommandLocation[]
|
||||
run: () => Promise<void>
|
||||
fullLabel?: string
|
||||
locations: CommandLocation[]
|
||||
run?: () => Promise<any>
|
||||
|
||||
/**
|
||||
* Raw SVG icon code
|
||||
*/
|
||||
icon?: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar icon ID
|
||||
*/
|
||||
touchBarNSImage?: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar button label
|
||||
*/
|
||||
touchBarTitle?: string
|
||||
|
||||
weight?: number
|
||||
|
||||
parent?: string
|
||||
|
||||
group?: string
|
||||
|
||||
checked?: boolean
|
||||
|
||||
static fromToolbarButton (button: ToolbarButton): Command {
|
||||
const command = new Command()
|
||||
command.id = `legacy:${slugify(button.title)}`
|
||||
command.label = button.title
|
||||
command.run = async () => button.click?.()
|
||||
command.icon = button.icon
|
||||
@@ -44,18 +44,29 @@ export class Command {
|
||||
if ((button.weight ?? 0) > 0) {
|
||||
command.locations.push(CommandLocation.RightToolbar)
|
||||
}
|
||||
command.touchBarNSImage = button.touchBarNSImage
|
||||
command.touchBarTitle = button.touchBarTitle
|
||||
command.weight = button.weight
|
||||
return command
|
||||
}
|
||||
|
||||
static fromMenuItem (item: MenuItemOptions): Command {
|
||||
const command = new Command()
|
||||
command.label = item.commandLabel ?? item.label ?? ''
|
||||
command.sublabel = item.sublabel
|
||||
command.run = async () => item.click?.()
|
||||
return command
|
||||
static fromMenuItem (item: MenuItemOptions): Command[] {
|
||||
if (item.type === 'separator') {
|
||||
return []
|
||||
}
|
||||
const commands: Command[] = [{
|
||||
id: `legacy:${slugify(item.commandLabel ?? item.label).toLowerCase()}`,
|
||||
label: item.commandLabel ?? item.label,
|
||||
run: async () => item.click?.(),
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
checked: item.checked,
|
||||
}]
|
||||
for (const submenu of item.submenu ?? []) {
|
||||
commands.push(...Command.fromMenuItem(submenu).map(x => ({
|
||||
...x,
|
||||
id: `${commands[0].id}:${slugify(x.label).toLowerCase()}`,
|
||||
parent: commands[0].id,
|
||||
})))
|
||||
}
|
||||
return commands
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -37,6 +37,7 @@ 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 } from '../services/locale.service'
|
||||
export { CommandService } from '../services/commands.service'
|
||||
export { TranslateService } from '@ngx-translate/core'
|
||||
export * from '../utils'
|
||||
export { UTF8Splitter } from '../utfSplitter'
|
||||
|
@@ -1,6 +1,4 @@
|
||||
export interface MenuItemOptions {
|
||||
type?: 'normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'
|
||||
label?: string
|
||||
export type MenuItemOptions = {
|
||||
sublabel?: string
|
||||
enabled?: boolean
|
||||
checked?: boolean
|
||||
@@ -9,4 +7,10 @@ export interface MenuItemOptions {
|
||||
|
||||
/** @hidden */
|
||||
commandLabel?: string
|
||||
}
|
||||
} & ({
|
||||
type: 'separator',
|
||||
label?: string,
|
||||
} | {
|
||||
type?: 'normal' | 'submenu' | 'checkbox' | 'radio',
|
||||
label: string,
|
||||
})
|
||||
|
@@ -9,16 +9,6 @@ export interface ToolbarButton {
|
||||
|
||||
title: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar icon ID
|
||||
*/
|
||||
touchBarNSImage?: string
|
||||
|
||||
/**
|
||||
* Optional Touch Bar button label
|
||||
*/
|
||||
touchBarTitle?: string
|
||||
|
||||
weight?: number
|
||||
|
||||
click?: () => void
|
||||
|
@@ -1,10 +1,20 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Injectable } from '@angular/core'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
|
||||
import { HostAppService, Platform } from './api/hostApp'
|
||||
import { ProfilesService } from './services/profiles.service'
|
||||
import { CommandProvider, Command, CommandLocation } from './api/commands'
|
||||
import { AppService } from './services/app.service'
|
||||
import { CommandProvider, Command, CommandLocation, CommandContext } from './api/commands'
|
||||
import { SplitDirection, SplitTabComponent } from './components/splitTab.component'
|
||||
import { BaseTabComponent } from './components/baseTab.component'
|
||||
import { PromptModalComponent } from './components/promptModal.component'
|
||||
import { HotkeysService } from './services/hotkeys.service'
|
||||
import { TabsService } from './services/tabs.service'
|
||||
import { SplitLayoutProfilesService } from './profiles'
|
||||
import { TAB_COLORS } from './utils'
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@@ -13,38 +23,327 @@ export class CoreCommandProvider extends CommandProvider {
|
||||
private hostApp: HostAppService,
|
||||
private profilesService: ProfilesService,
|
||||
private translate: TranslateService,
|
||||
private app: AppService,
|
||||
private splitLayoutProfilesService: SplitLayoutProfilesService,
|
||||
private ngbModal: NgbModal,
|
||||
private tabsService: TabsService,
|
||||
hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
hotkeys.hotkey$.subscribe(hotkey => {
|
||||
if (hotkey === 'switch-profile') {
|
||||
let tab = this.app.activeTab
|
||||
if (tab instanceof SplitTabComponent) {
|
||||
tab = tab.getFocusedTab()
|
||||
if (tab) {
|
||||
this.switchTabProfile(tab)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async activate () {
|
||||
async switchTabProfile (tab: BaseTabComponent) {
|
||||
const profile = await this.profilesService.showProfileSelector().catch(() => null)
|
||||
if (!profile) {
|
||||
return
|
||||
}
|
||||
|
||||
const params = await this.profilesService.newTabParametersForProfile(profile)
|
||||
if (!params) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!await tab.canClose()) {
|
||||
return
|
||||
}
|
||||
|
||||
const newTab = this.tabsService.create(params)
|
||||
;(tab.parent as SplitTabComponent).replaceTab(tab, newTab)
|
||||
|
||||
tab.destroy()
|
||||
}
|
||||
|
||||
async showProfileSelector () {
|
||||
const profile = await this.profilesService.showProfileSelector().catch(() => null)
|
||||
if (profile) {
|
||||
this.profilesService.launchProfile(profile)
|
||||
}
|
||||
}
|
||||
|
||||
async provide (): Promise<Command[]> {
|
||||
return [
|
||||
async provide (context: CommandContext): Promise<Command[]> {
|
||||
const commands: Command[] = [
|
||||
{
|
||||
id: 'core:profile-selector',
|
||||
locations: [CommandLocation.LeftToolbar, CommandLocation.StartPage],
|
||||
label: this.translate.instant('Profiles & connections'),
|
||||
weight: 12,
|
||||
icon: this.hostApp.platform === Platform.Web
|
||||
? require('./icons/plus.svg')
|
||||
: require('./icons/profiles.svg'),
|
||||
run: async () => this.activate(),
|
||||
run: async () => this.showProfileSelector(),
|
||||
},
|
||||
...this.profilesService.getRecentProfiles().map((profile, index) => ({
|
||||
id: `core:recent-profile-${index}`,
|
||||
label: profile.name,
|
||||
locations: [CommandLocation.StartPage],
|
||||
icon: require('./icons/history.svg'),
|
||||
weight: 20,
|
||||
run: async () => {
|
||||
const p = (await this.profilesService.getProfiles()).find(x => x.id === profile.id) ?? profile
|
||||
this.profilesService.launchProfile(p)
|
||||
},
|
||||
})),
|
||||
]
|
||||
|
||||
if (context.tab) {
|
||||
const tab = context.tab
|
||||
|
||||
commands.push({
|
||||
id: `core:close-tab`,
|
||||
label: this.translate.instant('Close tab'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -35,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
if (this.app.tabs.includes(tab)) {
|
||||
this.app.closeTab(tab, true)
|
||||
} else {
|
||||
tab.destroy()
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
commands.push({
|
||||
id: `core:close`,
|
||||
label: this.translate.instant('Close'),
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
weight: 99,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
tab.destroy()
|
||||
},
|
||||
})
|
||||
|
||||
if (!context.tab.parent) {
|
||||
commands.push(...[{
|
||||
id: 'core:close-other-tabs',
|
||||
label: this.translate.instant('Close other tabs'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -34,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'core:close-tabs-to-the-right',
|
||||
label: this.translate.instant('Close tabs to the right'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -33,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'core:close-tabs-to-the-left',
|
||||
label: this.translate.instant('Close tabs to the left'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -32,
|
||||
group: 'core:close',
|
||||
run: async () => {
|
||||
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
}])
|
||||
}
|
||||
|
||||
commands.push({
|
||||
id: 'core:rename-tab',
|
||||
label: this.translate.instant('Rename tab'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
group: 'core:common',
|
||||
weight: -13,
|
||||
run: async () => this.app.renameTab(tab),
|
||||
})
|
||||
commands.push({
|
||||
id: 'core:duplicate-tab',
|
||||
label: this.translate.instant('Duplicate tab'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
group: 'core:common',
|
||||
weight: -12,
|
||||
run: async () => this.app.duplicateTab(tab),
|
||||
})
|
||||
commands.push({
|
||||
id: 'core:tab-color',
|
||||
label: this.translate.instant('Color'),
|
||||
group: 'core:common',
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: -11,
|
||||
})
|
||||
for (const color of TAB_COLORS) {
|
||||
commands.push({
|
||||
id: `core:tab-color-${color.name.toLowerCase()}`,
|
||||
parent: 'core:tab-color',
|
||||
label: this.translate.instant(color.name) ?? color.name,
|
||||
fullLabel: this.translate.instant('Set tab color to {color}', { color: this.translate.instant(color.name) }),
|
||||
checked: tab.color === color.value,
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
tab.color = color.value
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (tab.parent instanceof SplitTabComponent) {
|
||||
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
|
||||
commands.push({
|
||||
id: 'core:split',
|
||||
label: this.translate.instant('Split'),
|
||||
group: 'core:panes',
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
})
|
||||
for (const dir of directions) {
|
||||
commands.push({
|
||||
id: `core:split-${dir}`,
|
||||
label: {
|
||||
r: this.translate.instant('Right'),
|
||||
b: this.translate.instant('Down'),
|
||||
l: this.translate.instant('Left'),
|
||||
t: this.translate.instant('Up'),
|
||||
}[dir],
|
||||
fullLabel: {
|
||||
r: this.translate.instant('Split to the right'),
|
||||
b: this.translate.instant('Split to the down'),
|
||||
l: this.translate.instant('Split to the left'),
|
||||
t: this.translate.instant('Split to the up'),
|
||||
}[dir],
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
parent: 'core:split',
|
||||
run: async () => {
|
||||
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
commands.push({
|
||||
id: 'core:switch-profile',
|
||||
label: this.translate.instant('Switch profile'),
|
||||
group: 'core:common',
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
run: async () => this.switchTabProfile(tab),
|
||||
})
|
||||
}
|
||||
|
||||
if (tab instanceof SplitTabComponent && tab.getAllTabs().length > 1) {
|
||||
commands.push({
|
||||
id: 'core:save-split-tab-as-profile',
|
||||
label: this.translate.instant('Save layout as profile'),
|
||||
group: 'core:common',
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
modal.componentInstance.prompt = this.translate.instant('Profile name')
|
||||
const name = (await modal.result.catch(() => null))?.value
|
||||
if (!name) {
|
||||
return
|
||||
}
|
||||
this.splitLayoutProfilesService.createProfile(tab, name)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return commands
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TaskCompletionCommandProvider extends CommandProvider {
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (context: CommandContext): Promise<Command[]> {
|
||||
if (!context.tab) {
|
||||
return []
|
||||
}
|
||||
|
||||
const process = await context.tab.getCurrentProcess()
|
||||
const items: Command[] = []
|
||||
|
||||
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = context.tab
|
||||
|
||||
if (process) {
|
||||
items.push({
|
||||
id: 'core:process-name',
|
||||
label: this.translate.instant('Current process: {name}', process),
|
||||
group: 'core:process',
|
||||
weight: -1,
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
})
|
||||
items.push({
|
||||
id: 'core:notify-when-done',
|
||||
label: this.translate.instant('Notify when done'),
|
||||
group: 'core:process',
|
||||
weight: 0,
|
||||
checked: extTab.__completionNotificationEnabled,
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
extTab.__completionNotificationEnabled = !extTab.__completionNotificationEnabled
|
||||
|
||||
if (extTab.__completionNotificationEnabled) {
|
||||
this.app.observeTabCompletion(extTab).subscribe(() => {
|
||||
new Notification(this.translate.instant('Process completed'), {
|
||||
body: process.name,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(extTab)
|
||||
})
|
||||
extTab.__completionNotificationEnabled = false
|
||||
})
|
||||
} else {
|
||||
this.app.stopObservingTabCompletion(extTab)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
items.push({
|
||||
id: 'core:notify-on-activity',
|
||||
label: this.translate.instant('Notify on activity'),
|
||||
group: 'core:process',
|
||||
checked: !!extTab.__outputNotificationSubscription,
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
extTab.clearActivity()
|
||||
|
||||
if (extTab.__outputNotificationSubscription) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
} else {
|
||||
extTab.__outputNotificationSubscription = extTab.activity$.subscribe(active => {
|
||||
if (extTab.__outputNotificationSubscription && active) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
new Notification(this.translate.instant('Tab activity'), {
|
||||
body: extTab.title,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(extTab)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
@@ -238,7 +238,7 @@ export class AppRootComponent {
|
||||
|
||||
private async getToolbarButtons (aboveZero: boolean): Promise<Command[]> {
|
||||
return (await this.commands.getCommands({ tab: this.app.activeTab ?? undefined }))
|
||||
.filter(x => x.locations?.includes(aboveZero ? CommandLocation.RightToolbar : CommandLocation.LeftToolbar))
|
||||
.filter(x => x.locations.includes(aboveZero ? CommandLocation.RightToolbar : CommandLocation.LeftToolbar))
|
||||
}
|
||||
|
||||
toggleMaximize (): void {
|
||||
|
@@ -128,7 +128,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the acticity marker on the tab header
|
||||
* Shows the activity marker on the tab header
|
||||
*/
|
||||
displayActivity (): void {
|
||||
if (!this.hasActivity) {
|
||||
@@ -138,7 +138,7 @@ export abstract class BaseTabComponent extends BaseComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the acticity marker from the tab header
|
||||
* Removes the activity marker from the tab header
|
||||
*/
|
||||
clearActivity (): void {
|
||||
if (this.hasActivity) {
|
||||
|
@@ -350,7 +350,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
}
|
||||
break
|
||||
case 'close-pane':
|
||||
this.removeTab(this.focusedTab)
|
||||
this.focusedTab.destroy()
|
||||
break
|
||||
case 'pane-increase-vertical':
|
||||
this.resizePane('v')
|
||||
@@ -475,7 +475,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
|
||||
let target = relative ? this.getParentOf(relative) : null
|
||||
if (!target) {
|
||||
// Rewrap the root container just in case the orientation isn't compatibile
|
||||
// Rewrap the root container just in case the orientation isn't compatible
|
||||
target = new SplitContainer()
|
||||
target.orientation = ['l', 'r'].includes(side) ? 'h' : 'v'
|
||||
target.children = [this.root]
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { DomSanitizer } from '@angular/platform-browser'
|
||||
import { firstBy } from 'thenby'
|
||||
import { HomeBaseService } from '../services/homeBase.service'
|
||||
import { CommandService } from '../services/commands.service'
|
||||
import { Command, CommandLocation } from '../api/commands'
|
||||
@@ -20,7 +21,8 @@ export class StartPageComponent {
|
||||
commands: CommandService,
|
||||
) {
|
||||
commands.getCommands({}).then(c => {
|
||||
this.commands = c.filter(x => x.locations?.includes(CommandLocation.StartPage))
|
||||
this.commands = c.filter(x => x.locations.includes(CommandLocation.StartPage))
|
||||
this.commands.sort(firstBy(x => x.weight ?? 0))
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -1,16 +1,19 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component, Input, Optional, Inject, HostBinding, HostListener, NgZone } from '@angular/core'
|
||||
import { Component, Input, HostBinding, HostListener, NgZone } from '@angular/core'
|
||||
import { auditTime } from 'rxjs'
|
||||
import { TabContextMenuItemProvider } from '../api/tabContextMenuProvider'
|
||||
|
||||
import { BaseTabComponent } from './baseTab.component'
|
||||
import { SplitTabComponent } from './splitTab.component'
|
||||
import { HotkeysService } from '../services/hotkeys.service'
|
||||
import { AppService } from '../services/app.service'
|
||||
import { HostAppService, Platform } from '../api/hostApp'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { BaseComponent } from './base.component'
|
||||
import { CommandService } from '../services/commands.service'
|
||||
import { MenuItemOptions } from '../api/menu'
|
||||
import { PlatformService } from '../api/platform'
|
||||
import { CommandContext, CommandLocation } from '../api/commands'
|
||||
|
||||
import { BaseComponent } from './base.component'
|
||||
import { SplitTabComponent } from './splitTab.component'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
@@ -31,8 +34,8 @@ export class TabHeaderComponent extends BaseComponent {
|
||||
public hostApp: HostAppService,
|
||||
private hotkeys: HotkeysService,
|
||||
private platform: PlatformService,
|
||||
private commands: CommandService,
|
||||
private zone: NgZone,
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||
) {
|
||||
super()
|
||||
this.subscribeUntilDestroyed(this.hotkeys.hotkey$, (hotkey) => {
|
||||
@@ -42,7 +45,6 @@ export class TabHeaderComponent extends BaseComponent {
|
||||
}
|
||||
}
|
||||
})
|
||||
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
@@ -56,26 +58,17 @@ export class TabHeaderComponent extends BaseComponent {
|
||||
}
|
||||
|
||||
async buildContextMenu (): Promise<MenuItemOptions[]> {
|
||||
let items: MenuItemOptions[] = []
|
||||
const contexts: CommandContext[] = [{ tab: this.tab }]
|
||||
|
||||
// Top-level tab menu
|
||||
for (const section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(this.tab, true)))) {
|
||||
items.push({ type: 'separator' })
|
||||
items = items.concat(section)
|
||||
}
|
||||
if (this.tab instanceof SplitTabComponent) {
|
||||
const tab = this.tab.getFocusedTab()
|
||||
if (tab) {
|
||||
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(tab, true)))) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
||||
if (section.length) {
|
||||
items.push({ type: 'separator' })
|
||||
items = items.concat(section)
|
||||
}
|
||||
}
|
||||
contexts.push({ tab })
|
||||
}
|
||||
}
|
||||
return items.slice(1)
|
||||
|
||||
return this.commands.buildContextMenu(contexts, CommandLocation.TabHeaderMenu)
|
||||
}
|
||||
|
||||
onTabDragStart (tab: BaseTabComponent) {
|
||||
|
@@ -37,7 +37,7 @@ import { FastHtmlBindDirective } from './directives/fastHtmlBind.directive'
|
||||
import { DropZoneDirective } from './directives/dropZone.directive'
|
||||
import { CdkAutoDropGroup } from './directives/cdkAutoDropGroup.directive'
|
||||
|
||||
import { Theme, CLIHandler, TabContextMenuItemProvider, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, QuickConnectProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api'
|
||||
import { Theme, CLIHandler, TabRecoveryProvider, HotkeyProvider, ConfigProvider, PlatformService, FileProvider, ProfilesService, ProfileProvider, QuickConnectProfileProvider, SelectorOption, Profile, SelectorService, CommandProvider } from './api'
|
||||
|
||||
import { AppService } from './services/app.service'
|
||||
import { ConfigService } from './services/config.service'
|
||||
@@ -49,10 +49,9 @@ import { CommandService } from './services/commands.service'
|
||||
import { StandardTheme, StandardCompactTheme, PaperTheme, NewTheme } from './theme'
|
||||
import { CoreConfigProvider } from './config'
|
||||
import { AppHotkeyProvider } from './hotkeys'
|
||||
import { TaskCompletionContextMenu, CommonOptionsContextMenu, TabManagementContextMenu, ProfilesContextMenu } from './tabContextMenu'
|
||||
import { LastCLIHandler, ProfileCLIHandler } from './cli'
|
||||
import { SplitLayoutProfilesService } from './profiles'
|
||||
import { CoreCommandProvider } from './commands'
|
||||
import { CoreCommandProvider, TaskCompletionCommandProvider } from './commands'
|
||||
|
||||
export function TranslateMessageFormatCompilerFactory (): TranslateMessageFormatCompiler {
|
||||
return new TranslateMessageFormatCompiler()
|
||||
@@ -65,16 +64,13 @@ const PROVIDERS = [
|
||||
{ provide: Theme, useClass: PaperTheme, multi: true },
|
||||
{ provide: Theme, useClass: NewTheme, multi: true },
|
||||
{ provide: ConfigProvider, useClass: CoreConfigProvider, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: CommonOptionsContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: TabManagementContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: TaskCompletionContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: ProfilesContextMenu, multi: true },
|
||||
{ provide: TabRecoveryProvider, useExisting: SplitTabRecoveryProvider, multi: true },
|
||||
{ provide: CLIHandler, useClass: ProfileCLIHandler, multi: true },
|
||||
{ provide: CLIHandler, useClass: LastCLIHandler, multi: true },
|
||||
{ provide: FileProvider, useClass: VaultFileProvider, multi: true },
|
||||
{ provide: ProfileProvider, useExisting: SplitLayoutProfilesService, multi: true },
|
||||
{ provide: CommandProvider, useExisting: CoreCommandProvider, multi: true },
|
||||
{ provide: CommandProvider, useExisting: TaskCompletionCommandProvider, multi: true },
|
||||
{
|
||||
provide: LOCALE_ID,
|
||||
deps: [LocaleService],
|
||||
|
@@ -1,6 +1,10 @@
|
||||
import { Inject, Injectable, Optional } from '@angular/core'
|
||||
import { AppService, Command, CommandContext, CommandProvider, ConfigService, MenuItemOptions, SplitTabComponent, TabContextMenuItemProvider, ToolbarButton, ToolbarButtonProvider, TranslateService } from '../api'
|
||||
import { TranslateService } from '@ngx-translate/core'
|
||||
import { Command, CommandContext, CommandLocation, CommandProvider, MenuItemOptions, SplitTabComponent, TabContextMenuItemProvider, ToolbarButton, ToolbarButtonProvider } from '../api'
|
||||
import { AppService } from './app.service'
|
||||
import { ConfigService } from './config.service'
|
||||
import { SelectorService } from './selector.service'
|
||||
import { firstBy } from 'thenby'
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CommandService {
|
||||
@@ -11,11 +15,11 @@ export class CommandService {
|
||||
private config: ConfigService,
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[]|null,
|
||||
@Optional() @Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
||||
@Inject(CommandProvider) private commandProviders: CommandProvider[],
|
||||
) {
|
||||
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
|
||||
this.contextMenuProviders?.sort((a, b) => a.weight - b.weight)
|
||||
}
|
||||
|
||||
async getCommands (context: CommandContext): Promise<Command[]> {
|
||||
@@ -29,8 +33,8 @@ export class CommandService {
|
||||
let items: MenuItemOptions[] = []
|
||||
if (context.tab) {
|
||||
for (const tabHeader of [false, true]) {
|
||||
// Top-level tab menu
|
||||
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(context.tab!, tabHeader)))) {
|
||||
// Top-level tab menu
|
||||
for (let section of await Promise.all(this.contextMenuProviders?.map(x => x.getItems(context.tab!, tabHeader)) ?? [])) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
||||
items = items.concat(section)
|
||||
@@ -38,7 +42,7 @@ export class CommandService {
|
||||
if (context.tab instanceof SplitTabComponent) {
|
||||
const tab = context.tab.getFocusedTab()
|
||||
if (tab) {
|
||||
for (let section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(tab, tabHeader)))) {
|
||||
for (let section of await Promise.all(this.contextMenuProviders?.map(x => x.getItems(tab, tabHeader)) ?? [])) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
section = section.filter(item => !items.some(ex => ex.label === item.label))
|
||||
items = items.concat(section)
|
||||
@@ -50,21 +54,10 @@ export class CommandService {
|
||||
|
||||
items = items.filter(x => (x.enabled ?? true) && x.type !== 'separator')
|
||||
|
||||
const flatItems: MenuItemOptions[] = []
|
||||
function flattenItem (item: MenuItemOptions, prefix?: string): void {
|
||||
if (item.submenu) {
|
||||
item.submenu.forEach(x => flattenItem(x, (prefix ? `${prefix} > ` : '') + (item.commandLabel ?? item.label)))
|
||||
} else {
|
||||
flatItems.push({
|
||||
...item,
|
||||
label: (prefix ? `${prefix} > ` : '') + (item.commandLabel ?? item.label),
|
||||
})
|
||||
}
|
||||
}
|
||||
items.forEach(x => flattenItem(x))
|
||||
|
||||
const commands = buttons.map(x => Command.fromToolbarButton(x))
|
||||
commands.push(...flatItems.map(x => Command.fromMenuItem(x)))
|
||||
const commands = [
|
||||
...buttons.map(x => Command.fromToolbarButton(x)),
|
||||
...items.map(x => Command.fromMenuItem(x)).flat(),
|
||||
]
|
||||
|
||||
for (const provider of this.config.enabledServices(this.commandProviders)) {
|
||||
commands.push(...await provider.provide(context))
|
||||
@@ -74,20 +67,36 @@ export class CommandService {
|
||||
.filter(c => !this.config.store.commandBlacklist.includes(c.id))
|
||||
.sort((a, b) => (a.weight ?? 0) - (b.weight ?? 0))
|
||||
.map(command => {
|
||||
const run = command.run
|
||||
command.run = async () => {
|
||||
// Serialize execution
|
||||
this.lastCommand = this.lastCommand.finally(run)
|
||||
await this.lastCommand
|
||||
if (command.run) {
|
||||
const run = command.run
|
||||
command.run = async () => {
|
||||
// Serialize execution
|
||||
this.lastCommand = this.lastCommand.finally(run)
|
||||
await this.lastCommand
|
||||
}
|
||||
}
|
||||
return command
|
||||
})
|
||||
}
|
||||
|
||||
async getCommandsWithContexts (context: CommandContext[]): Promise<Command[]> {
|
||||
let commands: Command[] = []
|
||||
|
||||
for (const commandSet of await Promise.all(context.map(x => this.getCommands(x)))) {
|
||||
for (const command of commandSet) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
commands = commands.filter(x => x.id !== command.id)
|
||||
commands.push(command)
|
||||
}
|
||||
}
|
||||
|
||||
return commands
|
||||
}
|
||||
|
||||
async run (id: string, context: CommandContext): Promise<void> {
|
||||
const commands = await this.getCommands(context)
|
||||
const command = commands.find(x => x.id === id)
|
||||
await command?.run()
|
||||
await command?.run?.()
|
||||
}
|
||||
|
||||
async showSelector (): Promise<void> {
|
||||
@@ -95,20 +104,80 @@ export class CommandService {
|
||||
return
|
||||
}
|
||||
|
||||
const context: CommandContext = {}
|
||||
const tab = this.app.activeTab
|
||||
if (tab instanceof SplitTabComponent) {
|
||||
context.tab = tab.getFocusedTab() ?? undefined
|
||||
const contexts: CommandContext[] = [{}]
|
||||
if (this.app.activeTab) {
|
||||
contexts.push({ tab: this.app.activeTab })
|
||||
}
|
||||
const commands = await this.getCommands(context)
|
||||
if (this.app.activeTab instanceof SplitTabComponent) {
|
||||
const tab = this.app.activeTab.getFocusedTab()
|
||||
if (tab) {
|
||||
contexts.push({ tab })
|
||||
}
|
||||
}
|
||||
|
||||
const commands = (await this.getCommandsWithContexts(contexts))
|
||||
.filter(x => x.run)
|
||||
.sort(firstBy(x => x.weight ?? 0))
|
||||
|
||||
return this.selector.show(
|
||||
this.translate.instant('Commands'),
|
||||
commands.map(c => ({
|
||||
name: c.label,
|
||||
name: c.fullLabel ?? c.label,
|
||||
callback: c.run,
|
||||
description: c.sublabel,
|
||||
icon: c.icon,
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
async buildContextMenu (contexts: CommandContext[], location: CommandLocation): Promise<MenuItemOptions[]> {
|
||||
let commands = await this.getCommandsWithContexts(contexts)
|
||||
|
||||
commands = commands.filter(x => x.locations.includes(location))
|
||||
commands.sort(firstBy(x => x.weight ?? 0))
|
||||
|
||||
interface Group {
|
||||
id?: string
|
||||
weight: number
|
||||
commands: Command[]
|
||||
}
|
||||
|
||||
const groups: Group[] = []
|
||||
|
||||
for (const command of commands.filter(x => !x.parent)) {
|
||||
let group = groups.find(x => x.id === command.group)
|
||||
if (!group) {
|
||||
group = {
|
||||
id: command.group,
|
||||
weight: 0,
|
||||
commands: [],
|
||||
}
|
||||
groups.push(group)
|
||||
}
|
||||
group.weight += command.weight ?? 0
|
||||
group.commands.push(command)
|
||||
}
|
||||
|
||||
groups.sort(firstBy(x => x.weight / x.commands.length))
|
||||
|
||||
function mapCommand (command: Command): MenuItemOptions {
|
||||
const submenu = command.id ? commands.filter(x => x.parent === command.id).map(mapCommand) : []
|
||||
return {
|
||||
label: command.label,
|
||||
submenu: submenu.length ? submenu : undefined,
|
||||
checked: command.checked,
|
||||
enabled: !!command.run || !!submenu.length,
|
||||
type: command.checked ? 'checkbox' : undefined,
|
||||
click: () => command.run?.(),
|
||||
}
|
||||
}
|
||||
|
||||
const items: MenuItemOptions[] = []
|
||||
for (const group of groups) {
|
||||
items.push({ type: 'separator' })
|
||||
items.push(...group.commands.map(mapCommand))
|
||||
}
|
||||
|
||||
return items.slice(1)
|
||||
}
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ export class ProfilesService {
|
||||
) { }
|
||||
|
||||
/*
|
||||
* Methods used to interract with ProfileProvider
|
||||
* Methods used to interact with ProfileProvider
|
||||
*/
|
||||
|
||||
getProviders (): ProfileProvider<Profile>[] {
|
||||
@@ -58,7 +58,7 @@ export class ProfilesService {
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods used to interract with Profile
|
||||
* Methods used to interact with Profile
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -206,7 +206,7 @@ export class ProfilesService {
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods used to interract with Profile Selector
|
||||
* Methods used to interact with Profile Selector
|
||||
*/
|
||||
|
||||
selectorOptionForProfile <P extends Profile, T> (profile: PartialProfile<P>): SelectorOption<T> {
|
||||
@@ -332,7 +332,7 @@ export class ProfilesService {
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods used to interract with Profile/ProfileGroup/Global defaults
|
||||
* Methods used to interact with Profile/ProfileGroup/Global defaults
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -370,7 +370,7 @@ export class ProfilesService {
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods used to interract with ProfileGroup
|
||||
* Methods used to interact with ProfileGroup
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@@ -1,298 +0,0 @@
|
||||
/* 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'
|
||||
import { SplitTabComponent, SplitDirection } from './components/splitTab.component'
|
||||
import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
|
||||
import { MenuItemOptions } from './api/menu'
|
||||
import { ProfilesService } from './services/profiles.service'
|
||||
import { TabsService } from './services/tabs.service'
|
||||
import { HotkeysService } from './services/hotkeys.service'
|
||||
import { PromptModalComponent } from './components/promptModal.component'
|
||||
import { SplitLayoutProfilesService } from './profiles'
|
||||
import { TAB_COLORS } from './utils'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class TabManagementContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 99
|
||||
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
let items: MenuItemOptions[] = [
|
||||
{
|
||||
label: this.translate.instant('Close'),
|
||||
commandLabel: this.translate.instant('Close tab'),
|
||||
click: () => {
|
||||
if (this.app.tabs.includes(tab)) {
|
||||
this.app.closeTab(tab, true)
|
||||
} else {
|
||||
tab.destroy()
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
if (!tab.parent) {
|
||||
items = [
|
||||
...items,
|
||||
{
|
||||
label: this.translate.instant('Close other tabs'),
|
||||
click: () => {
|
||||
for (const t of this.app.tabs.filter(x => x !== tab)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Close tabs to the right'),
|
||||
click: () => {
|
||||
for (const t of this.app.tabs.slice(this.app.tabs.indexOf(tab) + 1)) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Close tabs to the left'),
|
||||
click: () => {
|
||||
for (const t of this.app.tabs.slice(0, this.app.tabs.indexOf(tab))) {
|
||||
this.app.closeTab(t, true)
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
} else if (tab.parent instanceof SplitTabComponent) {
|
||||
const directions: SplitDirection[] = ['r', 'b', 'l', 't']
|
||||
items.push({
|
||||
label: this.translate.instant('Split'),
|
||||
submenu: directions.map(dir => ({
|
||||
label: {
|
||||
r: this.translate.instant('Right'),
|
||||
b: this.translate.instant('Down'),
|
||||
l: this.translate.instant('Left'),
|
||||
t: this.translate.instant('Up'),
|
||||
}[dir],
|
||||
commandLabel: {
|
||||
r: this.translate.instant('Split to the right'),
|
||||
b: this.translate.instant('Split to the down'),
|
||||
l: this.translate.instant('Split to the left'),
|
||||
t: this.translate.instant('Split to the up'),
|
||||
}[dir],
|
||||
click: () => {
|
||||
(tab.parent as SplitTabComponent).splitTab(tab, dir)
|
||||
},
|
||||
})) as MenuItemOptions[],
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
|
||||
weight = -1
|
||||
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private ngbModal: NgbModal,
|
||||
private splitLayoutProfilesService: SplitLayoutProfilesService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: boolean): Promise<MenuItemOptions[]> {
|
||||
let items: MenuItemOptions[] = []
|
||||
if (tabHeader) {
|
||||
const currentColor = TAB_COLORS.find(x => x.value === tab.color)?.name
|
||||
items = [
|
||||
...items,
|
||||
{
|
||||
label: this.translate.instant('Rename'),
|
||||
commandLabel: this.translate.instant('Rename tab'),
|
||||
click: () => {
|
||||
this.app.renameTab(tab)
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Duplicate'),
|
||||
commandLabel: this.translate.instant('Duplicate tab'),
|
||||
click: () => this.app.duplicateTab(tab),
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Color'),
|
||||
commandLabel: this.translate.instant('Change tab color'),
|
||||
sublabel: currentColor ? this.translate.instant(currentColor) : undefined,
|
||||
submenu: TAB_COLORS.map(color => ({
|
||||
label: this.translate.instant(color.name) ?? color.name,
|
||||
type: 'radio',
|
||||
checked: tab.color === color.value,
|
||||
click: () => {
|
||||
tab.color = color.value
|
||||
},
|
||||
})) as MenuItemOptions[],
|
||||
},
|
||||
]
|
||||
|
||||
if (tab instanceof SplitTabComponent && tab.getAllTabs().length > 1) {
|
||||
items.push({
|
||||
label: this.translate.instant('Save layout as profile'),
|
||||
click: async () => {
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
modal.componentInstance.prompt = this.translate.instant('Profile name')
|
||||
const name = (await modal.result.catch(() => null))?.value
|
||||
if (!name) {
|
||||
return
|
||||
}
|
||||
this.splitLayoutProfilesService.createProfile(tab, name)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
|
||||
constructor (
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
const process = await tab.getCurrentProcess()
|
||||
const items: MenuItemOptions[] = []
|
||||
|
||||
const extTab: (BaseTabComponent & { __completionNotificationEnabled?: boolean, __outputNotificationSubscription?: Subscription|null }) = tab
|
||||
|
||||
if (process) {
|
||||
items.push({
|
||||
enabled: false,
|
||||
label: this.translate.instant('Current process: {name}', process),
|
||||
})
|
||||
items.push({
|
||||
label: this.translate.instant('Notify when done'),
|
||||
type: 'checkbox',
|
||||
checked: extTab.__completionNotificationEnabled,
|
||||
click: () => {
|
||||
extTab.__completionNotificationEnabled = !extTab.__completionNotificationEnabled
|
||||
|
||||
if (extTab.__completionNotificationEnabled) {
|
||||
this.app.observeTabCompletion(tab).subscribe(() => {
|
||||
new Notification(this.translate.instant('Process completed'), {
|
||||
body: process.name,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(tab)
|
||||
})
|
||||
extTab.__completionNotificationEnabled = false
|
||||
})
|
||||
} else {
|
||||
this.app.stopObservingTabCompletion(tab)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
items.push({
|
||||
label: this.translate.instant('Notify on activity'),
|
||||
type: 'checkbox',
|
||||
checked: !!extTab.__outputNotificationSubscription,
|
||||
click: () => {
|
||||
tab.clearActivity()
|
||||
|
||||
if (extTab.__outputNotificationSubscription) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
} else {
|
||||
extTab.__outputNotificationSubscription = tab.activity$.subscribe(active => {
|
||||
if (extTab.__outputNotificationSubscription && active) {
|
||||
extTab.__outputNotificationSubscription.unsubscribe()
|
||||
extTab.__outputNotificationSubscription = null
|
||||
new Notification(this.translate.instant('Tab activity'), {
|
||||
body: tab.title,
|
||||
}).addEventListener('click', () => {
|
||||
this.app.selectTab(tab)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class ProfilesContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 10
|
||||
|
||||
constructor (
|
||||
private profilesService: ProfilesService,
|
||||
private tabsService: TabsService,
|
||||
private app: AppService,
|
||||
private translate: TranslateService,
|
||||
hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
hotkeys.hotkey$.subscribe(hotkey => {
|
||||
if (hotkey === 'switch-profile') {
|
||||
let tab = this.app.activeTab
|
||||
if (tab instanceof SplitTabComponent) {
|
||||
tab = tab.getFocusedTab()
|
||||
if (tab) {
|
||||
this.switchTabProfile(tab)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async switchTabProfile (tab: BaseTabComponent) {
|
||||
const profile = await this.profilesService.showProfileSelector().catch(() => null)
|
||||
if (!profile) {
|
||||
return
|
||||
}
|
||||
|
||||
const params = await this.profilesService.newTabParametersForProfile(profile)
|
||||
if (!params) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!await tab.canClose()) {
|
||||
return
|
||||
}
|
||||
|
||||
const newTab = this.tabsService.create(params)
|
||||
;(tab.parent as SplitTabComponent).replaceTab(tab, newTab)
|
||||
|
||||
tab.destroy()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
|
||||
if (tab.parent instanceof SplitTabComponent && tab.parent.getAllTabs().length > 1) {
|
||||
return [
|
||||
{
|
||||
label: this.translate.instant('Switch profile'),
|
||||
click: () => this.switchTabProfile(tab),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ToolbarButtonProvider, ToolbarButton, TranslateService } from 'tabby-core'
|
||||
import { TerminalService } from './services/terminal.service'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class ButtonProvider extends ToolbarButtonProvider {
|
||||
constructor (
|
||||
private terminal: TerminalService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
provide (): ToolbarButton[] {
|
||||
return [
|
||||
{
|
||||
icon: require('./icons/plus.svg'),
|
||||
title: this.translate.instant('New terminal'),
|
||||
touchBarNSImage: 'NSTouchBarAddDetailTemplate',
|
||||
click: () => {
|
||||
this.terminal.openTab()
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
123
tabby-local/src/commands.ts
Normal file
123
tabby-local/src/commands.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Inject, Injectable, Optional } from '@angular/core'
|
||||
|
||||
import { CommandProvider, Command, CommandLocation, TranslateService, CommandContext, ProfilesService } from 'tabby-core'
|
||||
|
||||
import { TerminalTabComponent } from './components/terminalTab.component'
|
||||
import { TerminalService } from './services/terminal.service'
|
||||
import { LocalProfile, UACService } from './api'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class LocalCommandProvider extends CommandProvider {
|
||||
constructor (
|
||||
private terminal: TerminalService,
|
||||
private profilesService: ProfilesService,
|
||||
private translate: TranslateService,
|
||||
@Optional() @Inject(UACService) private uac: UACService|undefined,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (context: CommandContext): Promise<Command[]> {
|
||||
const profiles = (await this.profilesService.getProfiles()).filter(x => x.type === 'local') as LocalProfile[]
|
||||
|
||||
const commands: Command[] = [
|
||||
{
|
||||
id: 'local:new-tab',
|
||||
group: 'local:new-tab',
|
||||
label: this.translate.instant('New terminal'),
|
||||
locations: [CommandLocation.LeftToolbar, CommandLocation.StartPage, CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
weight: 11,
|
||||
icon: require('./icons/plus.svg'),
|
||||
run: async () => this.runOpenTab(context),
|
||||
},
|
||||
]
|
||||
|
||||
commands.push({
|
||||
id: 'local:new-tab-with-profile',
|
||||
group: 'local:new-tab',
|
||||
label: this.translate.instant('New with profile'),
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
weight: 12,
|
||||
})
|
||||
|
||||
for (const profile of profiles) {
|
||||
commands.push({
|
||||
id: `local:new-tab-with-profile:${profile.id}`,
|
||||
group: 'local:new-tab',
|
||||
parent: 'local:new-tab-with-profile',
|
||||
label: profile.name,
|
||||
fullLabel: this.translate.instant('New terminal with profile: {profile}', { profile: profile.name }),
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
run: async () => {
|
||||
let workingDirectory = profile.options.cwd
|
||||
if (!workingDirectory && context.tab instanceof TerminalTabComponent) {
|
||||
workingDirectory = await context.tab.session?.getWorkingDirectory() ?? undefined
|
||||
}
|
||||
await this.terminal.openTab(profile, workingDirectory)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (this.uac?.isAvailable) {
|
||||
commands.push({
|
||||
id: 'local:new-tab-as-administrator-with-profile',
|
||||
group: 'local:new-tab',
|
||||
label: this.translate.instant('New admin tab'),
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
weight: 13,
|
||||
})
|
||||
|
||||
for (const profile of profiles) {
|
||||
commands.push({
|
||||
id: `local:new-tab-as-administrator-with-profile:${profile.id}`,
|
||||
group: 'local:new-tab',
|
||||
label: profile.name,
|
||||
fullLabel: this.translate.instant('New admin tab with profile: {profile}', { profile: profile.name }),
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
this.profilesService.openNewTabForProfile({
|
||||
...profile,
|
||||
options: {
|
||||
...profile.options,
|
||||
runAsAdministrator: true,
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (context.tab && context.tab instanceof TerminalTabComponent) {
|
||||
const terminalTab = context.tab
|
||||
commands.push({
|
||||
id: 'local:duplicate-tab-as-administrator',
|
||||
group: 'local:new-tab',
|
||||
label: this.translate.instant('Duplicate as administrator'),
|
||||
locations: [CommandLocation.TabHeaderMenu],
|
||||
weight: 14,
|
||||
run: async () => {
|
||||
this.profilesService.openNewTabForProfile({
|
||||
...terminalTab.profile,
|
||||
options: {
|
||||
...terminalTab.profile.options,
|
||||
runAsAdministrator: true,
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return commands
|
||||
}
|
||||
|
||||
runOpenTab (context: CommandContext) {
|
||||
if (context.tab && context.tab instanceof TerminalTabComponent) {
|
||||
this.profilesService.openNewTabForProfile(context.tab.profile)
|
||||
} else {
|
||||
this.terminal.openTab()
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms'
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ToastrModule } from 'ngx-toastr'
|
||||
|
||||
import TabbyCorePlugin, { HostAppService, ToolbarButtonProvider, TabRecoveryProvider, ConfigProvider, HotkeysService, HotkeyProvider, TabContextMenuItemProvider, CLIHandler, ProfileProvider } from 'tabby-core'
|
||||
import TabbyCorePlugin, { HostAppService, TabRecoveryProvider, ConfigProvider, HotkeysService, HotkeyProvider, CLIHandler, ProfileProvider, CommandProvider } from 'tabby-core'
|
||||
import TabbyTerminalModule from 'tabby-terminal'
|
||||
import { SettingsTabProvider } from 'tabby-settings'
|
||||
|
||||
@@ -16,15 +16,14 @@ import { CommandLineEditorComponent } from './components/commandLineEditor.compo
|
||||
|
||||
import { TerminalService } from './services/terminal.service'
|
||||
|
||||
import { ButtonProvider } from './buttonProvider'
|
||||
import { RecoveryProvider } from './recoveryProvider'
|
||||
import { ShellSettingsTabProvider } from './settings'
|
||||
import { TerminalConfigProvider } from './config'
|
||||
import { LocalTerminalHotkeyProvider } from './hotkeys'
|
||||
import { NewTabContextMenu } from './tabContextMenu'
|
||||
|
||||
import { AutoOpenTabCLIHandler, OpenPathCLIHandler, TerminalCLIHandler } from './cli'
|
||||
import { LocalProfilesService } from './profiles'
|
||||
import { LocalCommandProvider } from './commands'
|
||||
|
||||
/** @hidden */
|
||||
@NgModule({
|
||||
@@ -39,15 +38,13 @@ import { LocalProfilesService } from './profiles'
|
||||
providers: [
|
||||
{ provide: SettingsTabProvider, useClass: ShellSettingsTabProvider, multi: true },
|
||||
|
||||
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
||||
{ provide: CommandProvider, useExisting: LocalCommandProvider, multi: true },
|
||||
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
||||
{ provide: ConfigProvider, useClass: TerminalConfigProvider, multi: true },
|
||||
{ provide: HotkeyProvider, useClass: LocalTerminalHotkeyProvider, multi: true },
|
||||
|
||||
{ provide: ProfileProvider, useClass: LocalProfilesService, multi: true },
|
||||
|
||||
{ provide: TabContextMenuItemProvider, useClass: NewTabContextMenu, multi: true },
|
||||
|
||||
{ provide: CLIHandler, useClass: TerminalCLIHandler, multi: true },
|
||||
{ provide: CLIHandler, useClass: OpenPathCLIHandler, multi: true },
|
||||
{ provide: CLIHandler, useClass: AutoOpenTabCLIHandler, multi: true },
|
||||
|
@@ -1,87 +0,0 @@
|
||||
import { Inject, Injectable, Optional } from '@angular/core'
|
||||
import { ConfigService, BaseTabComponent, TabContextMenuItemProvider, MenuItemOptions, ProfilesService, TranslateService } from 'tabby-core'
|
||||
import { TerminalTabComponent } from './components/terminalTab.component'
|
||||
import { TerminalService } from './services/terminal.service'
|
||||
import { LocalProfile, UACService } from './api'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class NewTabContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 10
|
||||
|
||||
constructor (
|
||||
public config: ConfigService,
|
||||
private profilesService: ProfilesService,
|
||||
private terminalService: TerminalService,
|
||||
@Optional() @Inject(UACService) private uac: UACService|undefined,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: boolean): Promise<MenuItemOptions[]> {
|
||||
const profiles = (await this.profilesService.getProfiles()).filter(x => x.type === 'local') as LocalProfile[]
|
||||
|
||||
const items: MenuItemOptions[] = [
|
||||
{
|
||||
label: this.translate.instant('New terminal'),
|
||||
click: () => {
|
||||
if (tab instanceof TerminalTabComponent) {
|
||||
this.profilesService.openNewTabForProfile(tab.profile)
|
||||
} else {
|
||||
this.terminalService.openTab()
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('New with profile'),
|
||||
submenu: profiles.map(profile => ({
|
||||
label: profile.name,
|
||||
click: async () => {
|
||||
let workingDirectory = profile.options.cwd
|
||||
if (!workingDirectory && tab instanceof TerminalTabComponent) {
|
||||
workingDirectory = await tab.session?.getWorkingDirectory() ?? undefined
|
||||
}
|
||||
await this.terminalService.openTab(profile, workingDirectory)
|
||||
},
|
||||
})),
|
||||
},
|
||||
]
|
||||
|
||||
if (this.uac?.isAvailable) {
|
||||
items.push({
|
||||
label: this.translate.instant('New admin tab'),
|
||||
submenu: profiles.map(profile => ({
|
||||
label: profile.name,
|
||||
click: () => {
|
||||
this.profilesService.openNewTabForProfile({
|
||||
...profile,
|
||||
options: {
|
||||
...profile.options,
|
||||
runAsAdministrator: true,
|
||||
},
|
||||
})
|
||||
},
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
if (tab instanceof TerminalTabComponent && tabHeader && this.uac?.isAvailable) {
|
||||
const terminalTab = tab
|
||||
items.push({
|
||||
label: this.translate.instant('Duplicate as administrator'),
|
||||
click: () => {
|
||||
this.profilesService.openNewTabForProfile({
|
||||
...terminalTab.profile,
|
||||
options: {
|
||||
...terminalTab.profile.options,
|
||||
runAsAdministrator: true,
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ToolbarButtonProvider, ToolbarButton, AppService, HostAppService, HotkeysService, TranslateService } from 'tabby-core'
|
||||
import { CommandProvider, AppService, HostAppService, HotkeysService, TranslateService, Command, CommandLocation } from 'tabby-core'
|
||||
|
||||
import { SettingsTabComponent } from './components/settingsTab.component'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class ButtonProvider extends ToolbarButtonProvider {
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SettingsCommandProvider extends CommandProvider {
|
||||
constructor (
|
||||
hostApp: HostAppService,
|
||||
hotkeys: HotkeysService,
|
||||
@@ -22,13 +22,14 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
||||
})
|
||||
}
|
||||
|
||||
provide (): ToolbarButton[] {
|
||||
async provide (): Promise<Command[]> {
|
||||
return [{
|
||||
id: 'settings:open',
|
||||
icon: require('./icons/cog.svg'),
|
||||
title: this.translate.instant('Settings'),
|
||||
touchBarNSImage: 'NSTouchBarComposeTemplate',
|
||||
weight: 10,
|
||||
click: (): void => this.open(),
|
||||
label: this.translate.instant('Settings'),
|
||||
weight: 99,
|
||||
locations: [CommandLocation.RightToolbar, CommandLocation.StartPage],
|
||||
run: async () => this.open(),
|
||||
}]
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms'
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll'
|
||||
|
||||
import TabbyCorePlugin, { ToolbarButtonProvider, HotkeyProvider, ConfigProvider, HotkeysService, AppService } from 'tabby-core'
|
||||
import TabbyCorePlugin, { HotkeyProvider, ConfigProvider, HotkeysService, AppService, CommandProvider } from 'tabby-core'
|
||||
|
||||
import { EditProfileModalComponent } from './components/editProfileModal.component'
|
||||
import { EditProfileGroupModalComponent } from './components/editProfileGroupModal.component'
|
||||
@@ -24,7 +24,7 @@ import { ShowSecretModalComponent } from './components/showSecretModal.component
|
||||
import { ConfigSyncService } from './services/configSync.service'
|
||||
|
||||
import { SettingsTabProvider } from './api'
|
||||
import { ButtonProvider } from './buttonProvider'
|
||||
import { SettingsCommandProvider } from './commands'
|
||||
import { SettingsHotkeyProvider } from './hotkeys'
|
||||
import { SettingsConfigProvider } from './config'
|
||||
import { HotkeySettingsTabProvider, WindowSettingsTabProvider, VaultSettingsTabProvider, ProfilesSettingsTabProvider, ConfigSyncSettingsTabProvider } from './settings'
|
||||
@@ -39,7 +39,7 @@ import { HotkeySettingsTabProvider, WindowSettingsTabProvider, VaultSettingsTabP
|
||||
InfiniteScrollModule,
|
||||
],
|
||||
providers: [
|
||||
{ provide: ToolbarButtonProvider, useClass: ButtonProvider, multi: true },
|
||||
{ provide: CommandProvider, useExisting: SettingsCommandProvider, multi: true },
|
||||
{ provide: ConfigProvider, useClass: SettingsConfigProvider, multi: true },
|
||||
{ provide: HotkeyProvider, useClass: SettingsHotkeyProvider, multi: true },
|
||||
{ provide: SettingsTabProvider, useClass: HotkeySettingsTabProvider, multi: true },
|
||||
|
44
tabby-ssh/src/commands.ts
Normal file
44
tabby-ssh/src/commands.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Injectable } from '@angular/core'
|
||||
|
||||
import { CommandProvider, Command, CommandLocation, TranslateService, CommandContext, Platform, HostAppService } from 'tabby-core'
|
||||
|
||||
import { SSHTabComponent } from './components/sshTab.component'
|
||||
import { SSHService } from './services/ssh.service'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SSHCommandProvider extends CommandProvider {
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
private ssh: SSHService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (context: CommandContext): Promise<Command[]> {
|
||||
const tab = context.tab
|
||||
if (!tab || !(tab instanceof SSHTabComponent)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const commands: Command[] = [{
|
||||
id: 'ssh:open-sftp-panel',
|
||||
group: 'ssh:sftp',
|
||||
label: this.translate.instant('Open SFTP panel'),
|
||||
locations: [CommandLocation.TabHeaderMenu, CommandLocation.TabBodyMenu],
|
||||
run: async () => tab.openSFTP(),
|
||||
}]
|
||||
if (this.hostApp.platform === Platform.Windows && this.ssh.getWinSCPPath()) {
|
||||
commands.push({
|
||||
id: 'ssh:open-winscp',
|
||||
group: 'ssh:sftp',
|
||||
label: this.translate.instant('Launch WinSCP'),
|
||||
locations: [CommandLocation.TabHeaderMenu, CommandLocation.TabBodyMenu],
|
||||
run: async () => this.ssh.launchWinSCP(tab.sshSession!),
|
||||
})
|
||||
}
|
||||
return commands
|
||||
}
|
||||
}
|
@@ -29,6 +29,12 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.list-group-item-action {
|
||||
&:hover {
|
||||
background: rgba(white, .05);
|
||||
}
|
||||
}
|
||||
|
||||
.mode, .size, .date {
|
||||
font-family: monospace;
|
||||
opacity: .5;
|
||||
|
@@ -81,6 +81,45 @@ export class SFTPPanelComponent {
|
||||
a.name.localeCompare(b.name))
|
||||
}
|
||||
|
||||
getFileType (fileExtension: string): string {
|
||||
const codeExtensions = ['js', 'ts', 'py', 'java', 'cpp', 'h', 'cs', 'html', 'css', 'rb', 'php', 'swift', 'go', 'kt', 'sh', 'json', 'cc', 'c', 'xml']
|
||||
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp']
|
||||
const pdfExtensions = ['pdf']
|
||||
const archiveExtensions = ['zip', 'rar', 'tar', 'gz']
|
||||
const wordExtensions = ['doc', 'docx']
|
||||
const videoExtensions = ['mp4', 'avi', 'mkv', 'mov']
|
||||
const powerpointExtensions = ['ppt', 'pptx']
|
||||
const textExtensions = ['txt', 'log']
|
||||
const audioExtensions = ['mp3', 'wav', 'flac']
|
||||
const excelExtensions = ['xls', 'xlsx']
|
||||
|
||||
const lowerCaseExtension = fileExtension.toLowerCase()
|
||||
|
||||
if (codeExtensions.includes(lowerCaseExtension)) {
|
||||
return 'code'
|
||||
} else if (imageExtensions.includes(lowerCaseExtension)) {
|
||||
return 'image'
|
||||
} else if (pdfExtensions.includes(lowerCaseExtension)) {
|
||||
return 'pdf'
|
||||
} else if (archiveExtensions.includes(lowerCaseExtension)) {
|
||||
return 'archive'
|
||||
} else if (wordExtensions.includes(lowerCaseExtension)) {
|
||||
return 'word'
|
||||
} else if (videoExtensions.includes(lowerCaseExtension)) {
|
||||
return 'video'
|
||||
} else if (powerpointExtensions.includes(lowerCaseExtension)) {
|
||||
return 'powerpoint'
|
||||
} else if (textExtensions.includes(lowerCaseExtension)) {
|
||||
return 'text'
|
||||
} else if (audioExtensions.includes(lowerCaseExtension)) {
|
||||
return 'audio'
|
||||
} else if (excelExtensions.includes(lowerCaseExtension)) {
|
||||
return 'excel'
|
||||
} else {
|
||||
return 'unknown'
|
||||
}
|
||||
}
|
||||
|
||||
getIcon (item: SFTPFile): string {
|
||||
if (item.isDirectory) {
|
||||
return 'fas fa-folder text-info'
|
||||
@@ -88,6 +127,18 @@ export class SFTPPanelComponent {
|
||||
if (item.isSymlink) {
|
||||
return 'fas fa-link text-warning'
|
||||
}
|
||||
const fileMatch = /\.([^.]+)$/.exec(item.name)
|
||||
const extension = fileMatch ? fileMatch[1] : null
|
||||
if (extension !== null) {
|
||||
const fileType = this.getFileType(extension)
|
||||
|
||||
switch (fileType) {
|
||||
case 'unknown':
|
||||
return 'fas fa-file'
|
||||
default:
|
||||
return `fa-solid fa-file-${fileType} `
|
||||
}
|
||||
}
|
||||
return 'fas fa-file'
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,7 @@ import { FormsModule } from '@angular/forms'
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ToastrModule } from 'ngx-toastr'
|
||||
import { NgxFilesizeModule } from 'ngx-filesize'
|
||||
import TabbyCoreModule, { ConfigProvider, TabRecoveryProvider, HotkeyProvider, TabContextMenuItemProvider, ProfileProvider } from 'tabby-core'
|
||||
import TabbyCoreModule, { ConfigProvider, TabRecoveryProvider, HotkeyProvider, ProfileProvider, CommandProvider } from 'tabby-core'
|
||||
import { SettingsTabProvider } from 'tabby-settings'
|
||||
import TabbyTerminalModule from 'tabby-terminal'
|
||||
|
||||
@@ -24,11 +24,11 @@ import { SSHConfigProvider } from './config'
|
||||
import { SSHSettingsTabProvider } from './settings'
|
||||
import { RecoveryProvider } from './recoveryProvider'
|
||||
import { SSHHotkeyProvider } from './hotkeys'
|
||||
import { SFTPContextMenu } from './tabContextMenu'
|
||||
import { SSHProfilesService } from './profiles'
|
||||
import { SFTPContextMenuItemProvider } from './api/contextMenu'
|
||||
import { CommonSFTPContextMenu } from './sftpContextMenu'
|
||||
import { SFTPCreateDirectoryModalComponent } from './components/sftpCreateDirectoryModal.component'
|
||||
import { SSHCommandProvider } from './commands'
|
||||
|
||||
/** @hidden */
|
||||
@NgModule({
|
||||
@@ -46,7 +46,7 @@ import { SFTPCreateDirectoryModalComponent } from './components/sftpCreateDirect
|
||||
{ provide: SettingsTabProvider, useClass: SSHSettingsTabProvider, multi: true },
|
||||
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
||||
{ provide: HotkeyProvider, useClass: SSHHotkeyProvider, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: SFTPContextMenu, multi: true },
|
||||
{ provide: CommandProvider, useExisting: SSHCommandProvider, multi: true },
|
||||
{ provide: ProfileProvider, useExisting: SSHProfilesService, multi: true },
|
||||
{ provide: SFTPContextMenuItemProvider, useClass: CommonSFTPContextMenu, multi: true },
|
||||
],
|
||||
|
@@ -1,40 +0,0 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { BaseTabComponent, TabContextMenuItemProvider, HostAppService, Platform, MenuItemOptions, TranslateService } from 'tabby-core'
|
||||
import { SSHTabComponent } from './components/sshTab.component'
|
||||
import { SSHService } from './services/ssh.service'
|
||||
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class SFTPContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 10
|
||||
|
||||
constructor (
|
||||
private hostApp: HostAppService,
|
||||
private ssh: SSHService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
if (!(tab instanceof SSHTabComponent)) {
|
||||
return []
|
||||
}
|
||||
const items = [{
|
||||
label: this.translate.instant('Open SFTP panel'),
|
||||
click: () => {
|
||||
tab.openSFTP()
|
||||
},
|
||||
}]
|
||||
if (this.hostApp.platform === Platform.Windows && this.ssh.getWinSCPPath()) {
|
||||
items.push({
|
||||
label: this.translate.instant('Launch WinSCP'),
|
||||
click: (): void => {
|
||||
this.ssh.launchWinSCP(tab.sshSession!)
|
||||
},
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@ import { Spinner } from 'cli-spinner'
|
||||
import colors from 'ansi-colors'
|
||||
import { NgZone, OnInit, OnDestroy, Injector, ViewChild, HostBinding, Input, ElementRef, InjectFlags, Component } from '@angular/core'
|
||||
import { trigger, transition, style, animate, AnimationTriggerMetadata } from '@angular/animations'
|
||||
import { AppService, ConfigService, BaseTabComponent, HostAppService, HotkeysService, NotificationsService, Platform, LogService, Logger, TabContextMenuItemProvider, SplitTabComponent, SubscriptionContainer, MenuItemOptions, PlatformService, HostWindowService, ResettableTimeout, TranslateService, ThemesService } from 'tabby-core'
|
||||
import { AppService, ConfigService, BaseTabComponent, HostAppService, HotkeysService, NotificationsService, Platform, LogService, Logger, SplitTabComponent, SubscriptionContainer, MenuItemOptions, PlatformService, HostWindowService, ResettableTimeout, TranslateService, ThemesService, CommandContext, CommandLocation, CommandService } from 'tabby-core'
|
||||
|
||||
import { BaseSession } from '../session'
|
||||
|
||||
@@ -97,7 +97,7 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
|
||||
profile: P
|
||||
|
||||
/**
|
||||
* Enables normall passthrough from session output to terminal input
|
||||
* Enables normal passthrough from session output to terminal input
|
||||
*/
|
||||
enablePassthrough = true
|
||||
|
||||
@@ -121,11 +121,11 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
|
||||
protected notifications: NotificationsService
|
||||
protected log: LogService
|
||||
protected decorators: TerminalDecorator[] = []
|
||||
protected contextMenuProviders: TabContextMenuItemProvider[]
|
||||
protected hostWindow: HostWindowService
|
||||
protected translate: TranslateService
|
||||
protected multifocus: MultifocusService
|
||||
protected themes: ThemesService
|
||||
protected commands: CommandService
|
||||
// Deps end
|
||||
|
||||
protected logger: Logger
|
||||
@@ -200,11 +200,11 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
|
||||
this.notifications = injector.get(NotificationsService)
|
||||
this.log = injector.get(LogService)
|
||||
this.decorators = injector.get<any>(TerminalDecorator, null, InjectFlags.Optional) as TerminalDecorator[]
|
||||
this.contextMenuProviders = injector.get<any>(TabContextMenuItemProvider, null, InjectFlags.Optional) as TabContextMenuItemProvider[]
|
||||
this.hostWindow = injector.get(HostWindowService)
|
||||
this.translate = injector.get(TranslateService)
|
||||
this.multifocus = injector.get(MultifocusService)
|
||||
this.themes = injector.get(ThemesService)
|
||||
this.commands = injector.get(CommandService)
|
||||
|
||||
this.logger = this.log.create('baseTerminalTab')
|
||||
this.setTitle(this.translate.instant('Terminal'))
|
||||
@@ -323,8 +323,6 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
|
||||
this.bellPlayer = document.createElement('audio')
|
||||
this.bellPlayer.src = require<string>('../bell.ogg')
|
||||
this.bellPlayer.load()
|
||||
|
||||
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@@ -470,13 +468,14 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
|
||||
}
|
||||
|
||||
async buildContextMenu (): Promise<MenuItemOptions[]> {
|
||||
let items: MenuItemOptions[] = []
|
||||
for (const section of await Promise.all(this.contextMenuProviders.map(x => x.getItems(this)))) {
|
||||
items = items.concat(section)
|
||||
items.push({ type: 'separator' })
|
||||
const contexts: CommandContext[] = [{ tab: this }]
|
||||
|
||||
// Top-level tab menu
|
||||
if (this.parent) {
|
||||
contexts.unshift({ tab: this.parent })
|
||||
}
|
||||
items.splice(items.length - 1, 1)
|
||||
return items
|
||||
|
||||
return this.commands.buildContextMenu(contexts, CommandLocation.TabBodyMenu)
|
||||
}
|
||||
|
||||
/**
|
||||
|
180
tabby-terminal/src/commands.ts
Normal file
180
tabby-terminal/src/commands.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Injectable } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import slugify from 'slugify'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { CommandProvider, Command, CommandLocation, TranslateService, CommandContext, PromptModalComponent, PartialProfile, Profile, ConfigService, NotificationsService, SplitTabComponent } from 'tabby-core'
|
||||
|
||||
import { ConnectableTerminalTabComponent } from './api/connectableTerminalTab.component'
|
||||
import { BaseTerminalTabComponent } from './api/baseTerminalTab.component'
|
||||
import { MultifocusService } from './services/multifocus.service'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class TerminalCommandProvider extends CommandProvider {
|
||||
constructor (
|
||||
private config: ConfigService,
|
||||
private ngbModal: NgbModal,
|
||||
private notifications: NotificationsService,
|
||||
private translate: TranslateService,
|
||||
private multifocus: MultifocusService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async provide (context: CommandContext): Promise<Command[]> {
|
||||
const commands: Command[] = []
|
||||
const tab = context.tab
|
||||
if (!tab) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (tab instanceof BaseTerminalTabComponent && tab.enableToolbar && !tab.pinToolbar) {
|
||||
commands.push({
|
||||
id: 'terminal:show-toolbar',
|
||||
group: 'terminal:misc',
|
||||
label: this.translate.instant('Show toolbar'),
|
||||
locations: [CommandLocation.TabHeaderMenu, CommandLocation.TabBodyMenu],
|
||||
run: async () => {
|
||||
tab.pinToolbar = true
|
||||
},
|
||||
})
|
||||
}
|
||||
if (tab instanceof BaseTerminalTabComponent && tab.session?.supportsWorkingDirectory()) {
|
||||
commands.push({
|
||||
id: 'terminal:copy-current-path',
|
||||
group: 'terminal:misc',
|
||||
label: this.translate.instant('Copy current path'),
|
||||
locations: [CommandLocation.TabHeaderMenu, CommandLocation.TabBodyMenu],
|
||||
run: async () => tab.copyCurrentPath(),
|
||||
})
|
||||
}
|
||||
commands.push({
|
||||
id: 'terminal:focus-all-tabs',
|
||||
group: 'core:panes',
|
||||
label: this.translate.instant('Focus all tabs'),
|
||||
locations: [CommandLocation.TabHeaderMenu, CommandLocation.TabBodyMenu],
|
||||
run: async () => {
|
||||
this.multifocus.focusAllTabs()
|
||||
},
|
||||
})
|
||||
|
||||
let splitTab: SplitTabComponent|null = null
|
||||
if (tab.parent instanceof SplitTabComponent) {
|
||||
splitTab = tab.parent
|
||||
}
|
||||
if (tab instanceof SplitTabComponent) {
|
||||
splitTab = tab
|
||||
}
|
||||
|
||||
if (splitTab && splitTab.getAllTabs().length > 1) {
|
||||
commands.push({
|
||||
id: 'terminal:focus-all-panes',
|
||||
group: 'terminal:misc',
|
||||
label: this.translate.instant('Focus all panes'),
|
||||
locations: [CommandLocation.TabHeaderMenu, CommandLocation.TabBodyMenu],
|
||||
run: async () => {
|
||||
this.multifocus.focusAllPanes()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (tab instanceof BaseTerminalTabComponent) {
|
||||
commands.push({
|
||||
id: 'terminal:save-as-profile',
|
||||
group: 'terminal:misc',
|
||||
label: this.translate.instant('Save as profile'),
|
||||
locations: [CommandLocation.TabBodyMenu, CommandLocation.TabHeaderMenu],
|
||||
run: async () => {
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
modal.componentInstance.prompt = this.translate.instant('New profile name')
|
||||
modal.componentInstance.value = tab.profile.name
|
||||
const name = (await modal.result.catch(() => null))?.value
|
||||
if (!name) {
|
||||
return
|
||||
}
|
||||
|
||||
const options = {
|
||||
...tab.profile.options,
|
||||
}
|
||||
|
||||
const cwd = await tab.session?.getWorkingDirectory() ?? tab.profile.options.cwd
|
||||
if (cwd) {
|
||||
options.cwd = cwd
|
||||
}
|
||||
|
||||
const profile: PartialProfile<Profile> = {
|
||||
type: tab.profile.type,
|
||||
name,
|
||||
options,
|
||||
}
|
||||
|
||||
profile.id = `${profile.type}:custom:${slugify(name)}:${uuidv4()}`
|
||||
profile.group = tab.profile.group
|
||||
profile.icon = tab.profile.icon
|
||||
profile.color = tab.profile.color
|
||||
profile.disableDynamicTitle = tab.profile.disableDynamicTitle
|
||||
profile.behaviorOnSessionEnd = tab.profile.behaviorOnSessionEnd
|
||||
|
||||
this.config.store.profiles = [
|
||||
...this.config.store.profiles,
|
||||
profile,
|
||||
]
|
||||
this.config.save()
|
||||
this.notifications.info(this.translate.instant('Saved'))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (tab instanceof ConnectableTerminalTabComponent) {
|
||||
commands.push({
|
||||
id: 'terminal:disconnect',
|
||||
label: this.translate.instant('Disconnect'),
|
||||
group: 'terminal:connection',
|
||||
locations: [CommandLocation.TabHeaderMenu, CommandLocation.TabBodyMenu],
|
||||
run: async () => {
|
||||
setTimeout(() => {
|
||||
tab.disconnect()
|
||||
this.notifications.notice(this.translate.instant('Disconnect'))
|
||||
})
|
||||
},
|
||||
})
|
||||
commands.push({
|
||||
id: 'terminal:reconnect',
|
||||
label: this.translate.instant('Reconnect'),
|
||||
group: 'terminal:connection',
|
||||
locations: [CommandLocation.TabHeaderMenu, CommandLocation.TabBodyMenu],
|
||||
run: async () => {
|
||||
setTimeout(() => {
|
||||
tab.reconnect()
|
||||
this.notifications.notice(this.translate.instant('Reconnect'))
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (tab instanceof BaseTerminalTabComponent) {
|
||||
commands.push({
|
||||
id: 'terminal:copy',
|
||||
label: this.translate.instant('Copy'),
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
weight: -2,
|
||||
run: async () => {
|
||||
setTimeout(() => {
|
||||
tab.frontend?.copySelection()
|
||||
this.notifications.notice(this.translate.instant('Copied'))
|
||||
})
|
||||
},
|
||||
})
|
||||
commands.push({
|
||||
id: 'terminal:paste',
|
||||
label: this.translate.instant('Paste'),
|
||||
locations: [CommandLocation.TabBodyMenu],
|
||||
weight: -1,
|
||||
run: async () => tab.paste(),
|
||||
})
|
||||
}
|
||||
return commands
|
||||
}
|
||||
}
|
@@ -5,7 +5,7 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ToastrModule } from 'ngx-toastr'
|
||||
import { NgxColorsModule } from 'ngx-colors'
|
||||
|
||||
import TabbyCorePlugin, { ConfigProvider, HotkeyProvider, TabContextMenuItemProvider, CLIHandler } from 'tabby-core'
|
||||
import TabbyCorePlugin, { ConfigProvider, HotkeyProvider, CLIHandler, CommandProvider } from 'tabby-core'
|
||||
import { SettingsTabProvider } from 'tabby-settings'
|
||||
|
||||
import { AppearanceSettingsTabComponent } from './components/appearanceSettingsTab.component'
|
||||
@@ -30,7 +30,7 @@ import { PathDropDecorator } from './features/pathDrop'
|
||||
import { ZModemDecorator } from './features/zmodem'
|
||||
import { TerminalConfigProvider } from './config'
|
||||
import { TerminalHotkeyProvider } from './hotkeys'
|
||||
import { CopyPasteContextMenu, MiscContextMenu, LegacyContextMenu, ReconnectContextMenu, SaveAsProfileContextMenu } from './tabContextMenu'
|
||||
import { TerminalCommandProvider } from './commands'
|
||||
|
||||
import { Frontend } from './frontends/frontend'
|
||||
import { XTermFrontend, XTermWebGLFrontend } from './frontends/xtermFrontend'
|
||||
@@ -58,11 +58,7 @@ import { DefaultColorSchemes } from './colorSchemes'
|
||||
{ provide: TerminalDecorator, useClass: ZModemDecorator, multi: true },
|
||||
{ provide: TerminalDecorator, useClass: DebugDecorator, multi: true },
|
||||
|
||||
{ provide: TabContextMenuItemProvider, useClass: CopyPasteContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: MiscContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: LegacyContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: ReconnectContextMenu, multi: true },
|
||||
{ provide: TabContextMenuItemProvider, useClass: SaveAsProfileContextMenu, multi: true },
|
||||
{ provide: CommandProvider, useExisting: TerminalCommandProvider, multi: true },
|
||||
|
||||
{ provide: CLIHandler, useClass: TerminalCLIHandler, multi: true },
|
||||
{ provide: TerminalColorSchemeProvider, useClass: DefaultColorSchemes, multi: true },
|
||||
|
@@ -1,218 +0,0 @@
|
||||
import { Injectable, Optional, Inject } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { BaseTabComponent, TabContextMenuItemProvider, NotificationsService, MenuItemOptions, TranslateService, SplitTabComponent, PromptModalComponent, ConfigService, PartialProfile, Profile } from 'tabby-core'
|
||||
import { BaseTerminalTabComponent } from './api/baseTerminalTab.component'
|
||||
import { TerminalContextMenuItemProvider } from './api/contextMenuProvider'
|
||||
import { MultifocusService } from './services/multifocus.service'
|
||||
import { ConnectableTerminalTabComponent } from './api/connectableTerminalTab.component'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import slugify from 'slugify'
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class CopyPasteContextMenu extends TabContextMenuItemProvider {
|
||||
weight = -10
|
||||
|
||||
constructor (
|
||||
private notifications: NotificationsService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent, tabHeader?: boolean): Promise<MenuItemOptions[]> {
|
||||
if (tabHeader) {
|
||||
return []
|
||||
}
|
||||
if (tab instanceof BaseTerminalTabComponent) {
|
||||
return [
|
||||
{
|
||||
label: this.translate.instant('Copy'),
|
||||
click: (): void => {
|
||||
setTimeout(() => {
|
||||
tab.frontend?.copySelection()
|
||||
this.notifications.notice(this.translate.instant('Copied'))
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Paste'),
|
||||
click: () => tab.paste(),
|
||||
},
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class MiscContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 1
|
||||
|
||||
constructor (
|
||||
private translate: TranslateService,
|
||||
private multifocus: MultifocusService,
|
||||
) { super() }
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
const items: MenuItemOptions[] = []
|
||||
if (tab instanceof BaseTerminalTabComponent && tab.enableToolbar && !tab.pinToolbar) {
|
||||
items.push({
|
||||
label: this.translate.instant('Show toolbar'),
|
||||
click: () => {
|
||||
tab.pinToolbar = true
|
||||
},
|
||||
})
|
||||
}
|
||||
if (tab instanceof BaseTerminalTabComponent && tab.session?.supportsWorkingDirectory()) {
|
||||
items.push({
|
||||
label: this.translate.instant('Copy current path'),
|
||||
click: () => tab.copyCurrentPath(),
|
||||
})
|
||||
}
|
||||
items.push({
|
||||
label: this.translate.instant('Focus all tabs'),
|
||||
click: () => {
|
||||
this.multifocus.focusAllTabs()
|
||||
},
|
||||
})
|
||||
if (tab.parent instanceof SplitTabComponent && tab.parent.getAllTabs().length > 1) {
|
||||
items.push({
|
||||
label: this.translate.instant('Focus all panes'),
|
||||
click: () => {
|
||||
this.multifocus.focusAllPanes()
|
||||
},
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class ReconnectContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 1
|
||||
|
||||
constructor (
|
||||
private translate: TranslateService,
|
||||
private notifications: NotificationsService,
|
||||
) { super() }
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
if (tab instanceof ConnectableTerminalTabComponent) {
|
||||
return [
|
||||
{
|
||||
label: this.translate.instant('Disconnect'),
|
||||
click: (): void => {
|
||||
setTimeout(() => {
|
||||
tab.disconnect()
|
||||
this.notifications.notice(this.translate.instant('Disconnect'))
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.translate.instant('Reconnect'),
|
||||
click: (): void => {
|
||||
setTimeout(() => {
|
||||
tab.reconnect()
|
||||
this.notifications.notice(this.translate.instant('Reconnect'))
|
||||
})
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class LegacyContextMenu extends TabContextMenuItemProvider {
|
||||
weight = 1
|
||||
|
||||
constructor (
|
||||
@Optional() @Inject(TerminalContextMenuItemProvider) protected contextMenuProviders: TerminalContextMenuItemProvider[]|null,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
if (!this.contextMenuProviders) {
|
||||
return []
|
||||
}
|
||||
if (tab instanceof BaseTerminalTabComponent) {
|
||||
let items: MenuItemOptions[] = []
|
||||
for (const p of this.contextMenuProviders) {
|
||||
items = items.concat(await p.getItems(tab))
|
||||
}
|
||||
return items
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Injectable()
|
||||
export class SaveAsProfileContextMenu extends TabContextMenuItemProvider {
|
||||
constructor (
|
||||
private config: ConfigService,
|
||||
private ngbModal: NgbModal,
|
||||
private notifications: NotificationsService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getItems (tab: BaseTabComponent): Promise<MenuItemOptions[]> {
|
||||
if (tab instanceof BaseTerminalTabComponent) {
|
||||
return [
|
||||
{
|
||||
label: this.translate.instant('Save as profile'),
|
||||
click: async () => {
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
modal.componentInstance.prompt = this.translate.instant('New profile name')
|
||||
modal.componentInstance.value = tab.profile.name
|
||||
const name = (await modal.result.catch(() => null))?.value
|
||||
if (!name) {
|
||||
return
|
||||
}
|
||||
|
||||
const options = {
|
||||
...tab.profile.options,
|
||||
}
|
||||
|
||||
const cwd = await tab.session?.getWorkingDirectory() ?? tab.profile.options.cwd
|
||||
if (cwd) {
|
||||
options.cwd = cwd
|
||||
}
|
||||
|
||||
const profile: PartialProfile<Profile> = {
|
||||
type: tab.profile.type,
|
||||
name,
|
||||
options,
|
||||
}
|
||||
|
||||
profile.id = `${profile.type}:custom:${slugify(name)}:${uuidv4()}`
|
||||
profile.group = tab.profile.group
|
||||
profile.icon = tab.profile.icon
|
||||
profile.color = tab.profile.color
|
||||
profile.disableDynamicTitle = tab.profile.disableDynamicTitle
|
||||
profile.behaviorOnSessionEnd = tab.profile.behaviorOnSessionEnd
|
||||
|
||||
this.config.store.profiles = [
|
||||
...this.config.store.profiles,
|
||||
profile,
|
||||
]
|
||||
this.config.save()
|
||||
this.notifications.info(this.translate.instant('Saved'))
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user