diff --git a/README.md b/README.md index 1015c34..2a57f8d 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ # Why another terminal? -Tess was mainly built in order to offer you a new, intuitive, fully customizable and blazing fast terminal app, by using the power of web technologies. +Tess was mainly built in order to offer you a new, intuitive, fully customizable, and blazing fast terminal app by using the power of web technologies. -Why should you not test it? We work for more than 2 years on this, and we've been relied on by thousands of users. +Why should you not test it? We've worked on this for more than 2 years, and we've been relied on by thousands of users. -Tess is currently officially tested on Windows & Linux, but it should work also on other platform. -If you cannot have access to Tess yet, fill an issue, we'll try to provide you the best cross-platform experience by making new packages or helping you manually installing Tess. +Tess is currently officially tested on Windows and Linux, but it should also work on other platforms. +If you do not have access to Tess yet, fill out an issue, and we'll try to provide you with the best cross-platform experience by making new packages or helping you manually install Tess.

@@ -21,13 +21,15 @@ If you cannot have access to Tess yet, fill an issue, we'll try to provide you t
-## Installation from archive +## Installation from the archive -We provide package for most major distribution, simply select the one that match your distro and install it. +We provide packages for most major distributions; simply select the one that matches your distro and install it. + +
## Installation with PPA -If you prefer using apt over downloading and installing the `deb` archive. You could set up the PPA and download Tess with these +If you prefer using apt over downloading and installing the `deb` archive, you could set up the PPA and download Tess with these ```bash apt install curl apt-transport-https gnupg2 @@ -38,14 +40,20 @@ echo 'deb [signed-by=/usr/share/keyrings/tess.gpg] https://apt.tessapp.dev stabl apt update && apt install tess ``` +
+ ## Installation with AUR -On Arch Linux, the recommended way to install Tess is using an AUR package manager like [yay](https://github.com/Jguer/yay) -`yay -S tess-git` +On Arch Linux, the recommended way to install Tess is to use an AUR package manager like [yay](https://github.com/Jguer/yay) +```sh +yay -S tess-git +``` + +
## Installation with RPM repository -If you are on RHEL derivate distros, you could also want to add our RPM repository to install Tess and receive update automatically with your package manager +If you are on RHEL-derived distros, you may also want to add our RPM repository to install Tess and receive updates automatically with your package manager. ```bash yum install curl @@ -66,27 +74,33 @@ yum check-update && yum install tess ## Installation from Installer -Simply download and execute the installer, available in the [releases](https://github.com/SquitchYT/Tess/releases) page. +Simply download and execute the installer, available on the [releases](https://github.com/SquitchYT/Tess/releases) page. + +
## Installation using Winget -If you are running on `Windows 10 1709 (build 16299)` or superior, you could download [Winget](https://github.com/microsoft/winget-cli). It may also be already installed on your system.
-Next, execute the following command +
+ +If you are running on `Windows 10 1709 (build 16299)` or superior, you could download [Winget](https://github.com/microsoft/winget-cli). It may also already be installed on your system.
+Next, execute the following command. ```sh winget install Squitch.Tess ``` +
+ ## Installation using Chocolatey Firstly, download [Chocolatey](https://chocolatey.org/install).
-Next, you will be allowed to run this +Next, you will be allowed to run this. ```sh choco install tess ``` -You can also find the package [here](https://community.chocolatey.org/packages/tess) +You can also find the package [here](https://community.chocolatey.org/packages/tess).

@@ -95,11 +109,11 @@ You can also find the package [here](https://community.chocolatey.org/packages/t ## Getting started -You want to contribute in Tess, find a simple task to help us with this project. +If you want to contribute to Tess, find a simple task to help us with this project. -* You've found a mistake in documentations, code or in the wiki, let us know by opening an [issue](https://github.com/SquitchYT/Tess/issues). -* You've an amazing feature idea, simply post your suggestion by creating an issue too. -* You want to help us close an issue, implementing a feature or something else related to code, follow the guide below. +* If you've found a mistake in documentation, sources, or the wiki, let us know by opening an [issue](https://github.com/SquitchYT/Tess/issues). +* You've got an amazing feature idea; simply post your suggestion by creating an issue too. +* You want to help us close an issue, implement a feature, or do something else related to code, follow the guide below. *Please, search for a similar issue before creating a new one.* @@ -107,20 +121,47 @@ You want to contribute in Tess, find a simple task to help us with this project. ## Developing with Tess -You want to contribute to Tess, it's simply, fork the repository and start developing on it. +First and foremost, you need to ensure that you have installed the necessary tools: + +* [Rust & Cargo](https://rustup.rs/) +* [Node.js](https://nodejs.org/en) +* Tauri CLI `cargo install tauri-cli` + +
+ +Next, start by downloading the source code. +```sh +git clone -b dev https://github.com/SquitchYT/Tess +``` + +Next, set up the project. +```sh +npm i +``` + +To ensure that everything is set up properly, run Tess with this command; it should launch Tess. +```sh +cargo tauri dev +``` + +You are now ready! + +
+ +Important notice: -* As Tess is cross-platform, when you implement a new feature, try to make it available everywhere. If despite all your efforts, you are unable to make it cross-platform, let us know the supported platforms when submitting your changes. -* If you update code, explain why you think this change is important and what you've done. +* As Tess is cross-platform, when you implement a new feature, try to make it available everywhere. If, despite all your efforts, you are unable to make it cross-platform, let us know the supported platforms when submitting your changes. +* If you update the code, explain why you think this change is important and what you've done. -After making your changes, simply open a [pull request](https://github.com/SquitchYT/Tess/pulls). +Simply open a [pull request](https://github.com/SquitchYT/Tess/pulls) to submit your changes.

# Roadmap -As long as Tess is in beta, many bugs may occur and some of them have not yet been fixed.
-More, many features are not yet available, here's a quick recap of major features that will want to integrate in Tess. +As long as Tess is in beta, many bugs may occur, and some of them have not yet been fixed.
+Many features are not yet available; here's a quick recap of the major features that we'll integrate in Tess. |Features |Electron|Tauri| @@ -131,15 +172,15 @@ More, many features are not yet available, here's a quick recap of major feature |Administrator tabs |❌ |⌛ | |Tabs split |❌ |⌛ | |Command line interface |✔️ |⌛ | -|Notifications |❌ |⌛ | +|Notifications |❌ |🟠 | |Macros |❌ |⌛ | |Plugins |🟠 |⌛ | -|Themes |🟠 |⌛ | +|Themes |🟠 |🟠 | |Config page |✔️ |⌛ | |Config watching |🟠 |⌛ | |Image display |❌ |⌛ | |Font ligature |🟠 |⌛ | -|Animated background |❌ |⌛ | +|Animated background |❌ |✔️ | |URI scheme API |❌ |⌛ | |Search in a shell |❌ |⌛ | |Marketplace |❌ |⌛ | diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 2dee7c2..88b6fa9 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2,6 +2,20 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "cpp_demangle", + "fallible-iterator", + "gimli", + "object", + "rustc-demangle", + "smallvec", +] + [[package]] name = "adler" version = "1.0.2" @@ -87,6 +101,17 @@ dependencies = [ "url", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -99,6 +124,48 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "bindgen" +version = "0.59.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", +] + +[[package]] +name = "bindgen" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -220,6 +287,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfb" version = "0.6.1" @@ -265,6 +341,41 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags", + "clap_lex", + "indexmap", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "cocoa" version = "0.24.1" @@ -359,6 +470,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpp_demangle" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c76f98bdfc7f66172e6c7065f981ebb576ffc903fe4c0561d9f0c2509226dc6" +dependencies = [ + "cfg-if", +] + [[package]] name = "cpufeatures" version = "0.2.5" @@ -545,6 +665,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + [[package]] name = "dtoa" version = "0.4.8" @@ -566,6 +692,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + [[package]] name = "embed_plist" version = "1.2.2" @@ -581,6 +713,46 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fastrand" version = "1.8.0" @@ -871,6 +1043,16 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + [[package]] name = "gio" version = "0.15.12" @@ -976,6 +1158,17 @@ dependencies = [ "system-deps 6.0.3", ] +[[package]] +name = "goblin" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "gtk" version = "0.15.5" @@ -1092,6 +1285,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "ico" version = "0.2.0" @@ -1328,11 +1527,17 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" -version = "0.2.138" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libdbus-sys" @@ -1343,6 +1548,27 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libproc" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b799ad155d75ce914c467ee5627b62247c20d4aedbd446f821484cebf3cded7" +dependencies = [ + "bindgen 0.59.2", + "errno", + "libc", +] + [[package]] name = "line-wrap" version = "0.1.1" @@ -1405,6 +1631,30 @@ dependencies = [ "time", ] +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "mach2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +dependencies = [ + "libc", +] + +[[package]] +name = "mach_o_sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e854583a83f20cf329bb9283366335387f7db59d640d1412167e05fedb98826" + [[package]] name = "malloc_buf" version = "0.0.6" @@ -1449,6 +1699,16 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "memoffset" version = "0.6.5" @@ -1458,6 +1718,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.6.2" @@ -1531,12 +1797,36 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if", + "libc", + "memoffset", + "pin-utils", +] + [[package]] name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "notify" version = "5.1.0" @@ -1676,6 +1966,16 @@ dependencies = [ "objc", ] +[[package]] +name = "object" +version = "0.30.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +dependencies = [ + "flate2", + "memchr", +] + [[package]] name = "once_cell" version = "1.16.0" @@ -1758,6 +2058,12 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "os_str_bytes" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" + [[package]] name = "overload" version = "0.1.1" @@ -1824,6 +2130,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "percent-encoding" version = "2.2.0" @@ -1956,6 +2268,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "plist" version = "1.3.1" @@ -1984,20 +2302,23 @@ dependencies = [ [[package]] name = "portable-pty" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4d17ec050a6b7ea4b15c430183772bce8384072d3f328e0967e72b7eec46b5" +checksum = "806ee80c2a03dbe1a9fb9534f8d19e4c0546b790cde8fd1fea9d6390644cb0be" dependencies = [ "anyhow", "bitflags", + "downcast-rs", "filedescriptor", "lazy_static", "libc", "log", + "nix", "serial", "shared_library", "shell-words", "winapi", + "winreg", ] [[package]] @@ -2062,6 +2383,20 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-maps" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d17946c951c8e8c4233375fdbfc212b215bd14ea1b18388eae8c95bb03a0174" +dependencies = [ + "anyhow", + "bindgen 0.60.1", + "libc", + "libproc", + "mach2", + "winapi", +] + [[package]] name = "quick-xml" version = "0.23.1" @@ -2170,6 +2505,18 @@ dependencies = [ "cty", ] +[[package]] +name = "read-process-memory" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8497683b2f0b6887786f1928c118f26ecc6bb3d78bbb6ed23e8e7ba110af3bb0" +dependencies = [ + "libc", + "log", + "mach", + "winapi", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -2222,6 +2569,29 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +[[package]] +name = "remoteprocess" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3ed67d3fade907d519c2edd07329a8f16296a64f91b6f3c35570769cf6b25d" +dependencies = [ + "addr2line", + "goblin", + "lazy_static", + "libc", + "libproc", + "log", + "mach", + "mach_o_sys", + "memmap", + "nix", + "object", + "proc-maps", + "read-process-memory", + "regex", + "winapi", +] + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -2255,6 +2625,18 @@ dependencies = [ "windows 0.37.0", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.3.3" @@ -2322,6 +2704,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "security-framework" version = "2.7.0" @@ -2588,6 +2990,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + [[package]] name = "siphasher" version = "0.3.10" @@ -3012,6 +3420,15 @@ dependencies = [ "utf-8", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "termios" version = "0.2.2" @@ -3023,7 +3440,7 @@ dependencies = [ [[package]] name = "tess" -version = "0.7.0-alpha.4" +version = "0.7.0-alpha.5" dependencies = [ "dirs-next", "infer 0.12.0", @@ -3031,14 +3448,22 @@ dependencies = [ "notify", "portable-pty", "regex", + "remoteprocess", "serde", "serde_json", "tauri", "tauri-build", "tokio", "uuid 1.3.0", + "window-vibrancy", ] +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + [[package]] name = "thin-slice" version = "0.1.1" @@ -3496,6 +3921,17 @@ dependencies = [ "windows-metadata", ] +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3527,6 +3963,18 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "window-vibrancy" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f762d9cc392fb85e6b1b5eed1ef13d73fed5149a5cbb017a7137497d14ef612" +dependencies = [ + "cocoa", + "objc", + "raw-window-handle", + "windows-sys 0.42.0", +] + [[package]] name = "windows" version = "0.37.0" @@ -3746,6 +4194,15 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + [[package]] name = "winres" version = "0.1.12" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 95bb881..63cb31a 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tess" -version = "0.7.0-alpha.4" +version = "0.7.0-alpha.5" description = "Fast. Lightweight. Famous. Terminal for the new era." authors = ["Squitch"] repository = "https://github.com/SquitchYT/Tess" @@ -17,16 +17,18 @@ tauri-build = { version = "1.1.1", features = [] } serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.1.1", features = ["api-all"] } -portable-pty = "0.7.0" +portable-pty = "0.8.1" infer = "0.12.0" notify = "5.1.0" tokio = "1.25.0" dirs-next = "2.0.0" uuid = "1.3.0" +remoteprocess = "0.4.11" [target.'cfg(windows)'.dependencies] lazy_static = "1.4.0" regex = "1.8.4" +window-vibrancy = "0.3.2" [features] default = ["custom-protocol"] diff --git a/src-tauri/src/command/option.rs b/src-tauri/src/command/option.rs index 2870b96..0704e1a 100644 --- a/src-tauri/src/command/option.rs +++ b/src-tauri/src/command/option.rs @@ -1,7 +1,6 @@ use crate::configuration::deserialized::Option; use std::sync::{Arc, Mutex}; - #[tauri::command] pub async fn get_configuration(option: tauri::State<'_, Arc>>) -> Result { Ok(option.lock().unwrap().clone()) diff --git a/src-tauri/src/command/term.rs b/src-tauri/src/command/term.rs index 73b23f2..9959ee9 100644 --- a/src-tauri/src/command/term.rs +++ b/src-tauri/src/command/term.rs @@ -1,3 +1,4 @@ +use crate::configuration::deserialized::Option; use crate::state::pty_manager::PtyManager; use std::sync::{Arc, Mutex}; @@ -10,7 +11,7 @@ pub async fn terminal_input( content: String, ) -> Result<(), PtyError> { if let Ok(mut pty_manager) = pty_manager.lock() { - pty_manager.write(id, content)?; + pty_manager.write(&id, content)?; Ok(()) } else { Err(PtyError::ManagerUnresponding) @@ -24,17 +25,28 @@ pub async fn create_terminal( cols: u16, rows: u16, id: String, - command: String, + profile_uuid: String, + option: tauri::State<'_, Arc>>, ) -> Result<(), PtyError> { - if let Ok(mut pty_manager) = pty_manager.lock() { - if let None = pty_manager.app { - pty_manager.app = Some(Arc::new(app)); - } + if let Some(profile) = option + .lock() + .unwrap() + .profiles + .iter() + .find(|profile| profile.uuid == profile_uuid) + { + if let Ok(mut pty_manager) = pty_manager.lock() { + if pty_manager.app.is_none() { + pty_manager.app = Some(Arc::new(app)); + } - pty_manager.create_pty(cols, rows, id, &command)?; - Ok(()) + pty_manager.create_pty(cols, rows, id, profile.clone())?; + Ok(()) + } else { + Err(PtyError::ManagerUnresponding) + } } else { - Err(PtyError::ManagerUnresponding) + todo!() } } @@ -46,7 +58,7 @@ pub async fn resize_terminal( rows: u16, ) -> Result<(), PtyError> { if let Ok(mut pty_manager) = pty_manager.lock() { - pty_manager.resize(id, cols, rows)?; + pty_manager.resize(&id, cols, rows)?; Ok(()) } else { Err(PtyError::ManagerUnresponding) @@ -59,7 +71,7 @@ pub async fn close_terminal( id: String, ) -> Result<(), PtyError> { if let Ok(mut pty_manager) = pty_manager.lock() { - pty_manager.close(id)?; + pty_manager.close(&id)?; Ok(()) } else { Err(PtyError::ManagerUnresponding) diff --git a/src-tauri/src/common/payloads.rs b/src-tauri/src/common/payloads.rs index 1db6a1c..f451f11 100644 --- a/src-tauri/src/common/payloads.rs +++ b/src-tauri/src/common/payloads.rs @@ -3,3 +3,9 @@ pub struct PtySendData { pub id: String, pub data: String, } + +#[derive(serde::Serialize, Clone)] +pub struct PtyTitleChanged { + pub id: String, + pub title: String, +} diff --git a/src-tauri/src/common/utils.rs b/src-tauri/src/common/utils.rs index 8782f2a..befbec4 100644 --- a/src-tauri/src/common/utils.rs +++ b/src-tauri/src/common/utils.rs @@ -1,5 +1,8 @@ use crate::configuration::deserialized::TerminalTheme; +#[cfg(target_os = "windows")] +use std::ffi::OsString; + pub fn parse_theme(location: String) -> (Option, Option) { let theme_path = if std::path::Path::new(&format!( "{}/tess/themes/{}", @@ -20,11 +23,65 @@ pub fn parse_theme(location: String) -> (Option, Option) }; if let Some(theme_path) = theme_path { - let app_theme = if std::path::Path::new(&format!("{}/style.css", theme_path)).exists() { Some(format!("{}/style.css", theme_path)) } else { None }; - let terminal_theme = if std::path::Path::new(&format!("{}/terminal.json", theme_path)).exists() { Some(serde_json::from_str(&std::fs::read_to_string(std::path::Path::new(&format!("{}/terminal.json", theme_path))).unwrap_or_default()).unwrap_or_default()) } else { None }; + let app_theme = if std::path::Path::new(&format!("{}/style.css", theme_path)).exists() { + Some(format!("{}/style.css", theme_path)) + } else { + None + }; + let terminal_theme = + if std::path::Path::new(&format!("{}/terminal.json", theme_path)).exists() { + Some( + serde_json::from_str( + &std::fs::read_to_string(std::path::Path::new(&format!( + "{}/terminal.json", + theme_path + ))) + .unwrap_or_default(), + ) + .unwrap_or_default(), + ) + } else { + None + }; (app_theme, terminal_theme) } else { (None, None) } -} \ No newline at end of file +} + +#[cfg(target_os = "windows")] +pub fn get_leader_process_name(process: remoteprocess::Process) -> Option { + if let Ok(childs) = process.child_processes() { + let mut childs = childs + .iter() + .filter(|tmp| { + tmp.1 == process.pid + && remoteprocess::Process::new(tmp.0) + .is_ok_and(|sub_process| sub_process.exe().is_ok()) + }) + .collect::>(); + + if childs.is_empty() { + std::path::Path::new(&process.exe().ok().unwrap_or_default()) + .file_name() + .map(|x| x.to_owned()) + } else { + childs.sort(); + + if let Ok(child_process) = + remoteprocess::Process::new(childs.as_slice().last().unwrap().0) + { + get_leader_process_name(child_process) + } else { + std::path::Path::new(&process.exe().ok().unwrap_or_default()) + .file_name() + .map(|x| x.to_owned()) + } + } + } else { + std::path::Path::new(&process.exe().ok().unwrap_or_default()) + .file_name() + .map(|x| x.to_owned()) + } +} diff --git a/src-tauri/src/configuration/deserialized.rs b/src-tauri/src/configuration/deserialized.rs index 9c8fa05..3549720 100644 --- a/src-tauri/src/configuration/deserialized.rs +++ b/src-tauri/src/configuration/deserialized.rs @@ -1,14 +1,12 @@ -use serde::{Serialize, Serializer, ser::SerializeSeq}; -use serde::Deserialize; -use crate::configuration::types::RangedInt; -use crate::configuration::types::CursorType; -use crate::configuration::types::BackgroundType; use crate::configuration::partial::PartialOption; +use crate::configuration::types::CursorType; +use crate::configuration::types::RangedInt; +use crate::configuration::types::{BackgroundMedia, BackgroundType}; +use serde::Deserialize; +use serde::{ser::SerializeSeq, Serialize, Serializer}; use crate::common::utils::parse_theme; - - #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] pub struct Option { @@ -25,7 +23,7 @@ pub struct Option { pub default_profile: Profile, #[serde(skip_serializing)] - theme: String + theme: String, } impl Default for Option { @@ -45,7 +43,7 @@ impl Default for Option { macros: Vec::default(), default_profile: default_profile(uuid), - theme: String::default() + theme: String::default(), } } } @@ -58,23 +56,23 @@ impl<'de> serde::Deserialize<'de> for Option { let app_theme = app_theme.unwrap_or_default(); let terminal_theme = terminal_theme.unwrap_or_default(); - let mut profiles = vec![]; if partial_option.profiles.is_empty() { - profiles.push( - Profile { - name: String::from("Default profile"), - terminal_options: partial_option.terminal.clone(), - theme: terminal_theme.clone(), - background_transparency: RangedInt::default(), - uuid: uuid::Uuid::new_v4().to_string(), - #[cfg(target_family = "unix")] - command: String::from("sh -c $SHELL"), - #[cfg(target_os = "windows")] - command: String::from("%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"), - } - ) + profiles.push(Profile { + name: String::from("Default profile"), + terminal_options: partial_option.terminal.clone(), + theme: terminal_theme.clone(), + background_transparency: RangedInt::default(), + uuid: uuid::Uuid::new_v4().to_string(), + #[cfg(target_family = "unix")] + command: String::from("sh -c $SHELL"), + #[cfg(target_os = "windows")] + command: String::from( + "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", + ), + background: None, + }) } else { for partial_profile in partial_option.profiles { let profile_option = TerminalOption { @@ -120,24 +118,30 @@ impl<'de> serde::Deserialize<'de> for Option { .unwrap_or(partial_option.terminal.title_is_running_process), }; - let profile_theme = if let Some(partial_profile_theme) = partial_profile.theme { parse_theme(partial_profile_theme).1.unwrap_or(terminal_theme.clone()) } else { terminal_theme.clone() }; - + let profile_theme = if let Some(partial_profile_theme) = partial_profile.theme { + parse_theme(partial_profile_theme) + .1 + .unwrap_or(terminal_theme.clone()) + } else { + terminal_theme.clone() + }; + profiles.push(Profile { name: partial_profile.name, terminal_options: profile_option, theme: profile_theme, background_transparency: partial_profile .background_transparency - .unwrap_or(RangedInt::default()), + .unwrap_or(partial_option.background_transparency), uuid: uuid::Uuid::parse_str(partial_profile.uuid.unwrap_or_default().as_str()) .unwrap_or(uuid::Uuid::new_v4()) .to_string(), - command: partial_profile.command + command: partial_profile.command, + background: partial_profile.background, }) } } - let mut macros = vec![]; if let Some(partial_macros) = partial_option.macros { @@ -151,7 +155,6 @@ impl<'de> serde::Deserialize<'de> for Option { } } - let shortcuts = if let Some(partial_option_shortcuts) = partial_option.shortcuts { let mut shortcuts = vec![]; @@ -177,12 +180,13 @@ impl<'de> serde::Deserialize<'de> for Option { action: ShortcutAction::ExecuteMacro(macro_command.uuid.clone()), }) } - }, - _ => { - shortcuts.push(Shortcut { shortcut: partial_shortcut.shortcut, action: partial_shortcut.action }) } + _ => shortcuts.push(Shortcut { + shortcut: partial_shortcut.shortcut, + action: partial_shortcut.action, + }), }; - }; + } shortcuts } else { @@ -192,23 +196,25 @@ impl<'de> serde::Deserialize<'de> for Option { Ok(Option { theme: partial_option.theme.clone(), - terminal_theme: terminal_theme, - app_theme: app_theme, + terminal_theme, + app_theme, background: partial_option.background, custom_titlebar: partial_option.custom_titlebar, terminal: partial_option.terminal, profiles: profiles.clone(), close_confirmation: partial_option.close_confirmation, background_transparency: partial_option.background_transparency, - shortcuts: shortcuts, - macros: macros, - default_profile: profiles.iter().find(|&profile| {profile.uuid == partial_option.default_profile}).unwrap_or(&profiles[0]).clone() + shortcuts, + macros, + default_profile: profiles + .iter() + .find(|&profile| profile.uuid == partial_option.default_profile) + .unwrap_or(&profiles[0]) + .clone(), }) } } - - #[derive(Deserialize, Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] pub struct TerminalOption { @@ -239,7 +245,7 @@ pub struct TerminalOption { #[serde(default)] font_weight_bold: RangedInt<1, 9, 6>, #[serde(default = "default_to_true")] - title_is_running_process: bool, + pub title_is_running_process: bool, } impl Default for TerminalOption { @@ -263,24 +269,18 @@ impl Default for TerminalOption { } } - - #[derive(Deserialize, Debug, Serialize, Clone)] pub struct Macro { pub content: String, pub uuid: String, } - - #[derive(Debug, Serialize, Clone)] pub struct Shortcut { pub shortcut: String, pub action: ShortcutAction, } - - #[derive(Debug, Clone, Deserialize)] pub enum ShortcutAction { CloseFocusedTab, @@ -334,23 +334,20 @@ impl Serialize for ShortcutAction { } } - - #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] pub struct Profile { // TODO: Add Icon - // TODO: Add background_media name: String, - terminal_options: TerminalOption, + pub terminal_options: TerminalOption, theme: TerminalTheme, - background_transparency: RangedInt<0, 100, 0>, - uuid: String, - command: String + background_transparency: RangedInt<0, 100, 100>, + background: std::option::Option, + pub uuid: String, + pub command: String, } - #[derive(Debug, Clone, Serialize)] pub struct TerminalTheme { foreground: String, @@ -372,10 +369,9 @@ pub struct TerminalTheme { bright_cyan: String, bright_white: String, cursor: String, - cursor_accent: String + cursor_accent: String, } - impl Default for TerminalTheme { fn default() -> Self { Self { @@ -398,7 +394,7 @@ impl Default for TerminalTheme { bright_cyan: String::from("#4DE8FE"), bright_white: String::from("#ABB4D6"), cursor: String::from("#DEEAF8"), - cursor_accent: String::from("#141A29") + cursor_accent: String::from("#141A29"), } } } @@ -446,54 +442,94 @@ impl<'de> Deserialize<'de> for TerminalTheme { #[serde(default)] pub cursor: std::option::Option, #[serde(default)] - pub cursor_accent: std::option::Option + pub cursor_accent: std::option::Option, } - let partial_terminal_theme = PartialTerminalTheme::deserialize(deserializer).unwrap_or_default(); + let partial_terminal_theme = + PartialTerminalTheme::deserialize(deserializer).unwrap_or_default(); let default_terminal_theme = TerminalTheme::default(); - + Ok(TerminalTheme { - foreground: partial_terminal_theme.foreground.unwrap_or(default_terminal_theme.foreground), - background: partial_terminal_theme.background.unwrap_or(default_terminal_theme.background), - black: partial_terminal_theme.black.unwrap_or(default_terminal_theme.black), - red: partial_terminal_theme.red.unwrap_or(default_terminal_theme.red), - green: partial_terminal_theme.green.unwrap_or(default_terminal_theme.green), - yellow: partial_terminal_theme.yellow.unwrap_or(default_terminal_theme.yellow), - blue: partial_terminal_theme.blue.unwrap_or(default_terminal_theme.blue), - magenta: partial_terminal_theme.magenta.unwrap_or(default_terminal_theme.magenta), - cyan: partial_terminal_theme.cyan.unwrap_or(default_terminal_theme.cyan), - white: partial_terminal_theme.white.unwrap_or(default_terminal_theme.white), - bright_black: partial_terminal_theme.bright_black.unwrap_or(default_terminal_theme.bright_black), - bright_red: partial_terminal_theme.bright_red.unwrap_or(default_terminal_theme.bright_red), - bright_green: partial_terminal_theme.bright_green.unwrap_or(default_terminal_theme.bright_green), - bright_yellow: partial_terminal_theme.bright_yellow.unwrap_or(default_terminal_theme.bright_yellow), - bright_blue: partial_terminal_theme.bright_blue.unwrap_or(default_terminal_theme.bright_blue), - bright_magenta: partial_terminal_theme.bright_magenta.unwrap_or(default_terminal_theme.bright_magenta), - bright_cyan: partial_terminal_theme.bright_cyan.unwrap_or(default_terminal_theme.bright_cyan), - bright_white: partial_terminal_theme.bright_white.unwrap_or(default_terminal_theme.bright_white), - cursor: partial_terminal_theme.cursor.unwrap_or(default_terminal_theme.cursor), - cursor_accent: partial_terminal_theme.cursor_accent.unwrap_or(default_terminal_theme.cursor_accent), + foreground: partial_terminal_theme + .foreground + .unwrap_or(default_terminal_theme.foreground), + background: partial_terminal_theme + .background + .unwrap_or(default_terminal_theme.background), + black: partial_terminal_theme + .black + .unwrap_or(default_terminal_theme.black), + red: partial_terminal_theme + .red + .unwrap_or(default_terminal_theme.red), + green: partial_terminal_theme + .green + .unwrap_or(default_terminal_theme.green), + yellow: partial_terminal_theme + .yellow + .unwrap_or(default_terminal_theme.yellow), + blue: partial_terminal_theme + .blue + .unwrap_or(default_terminal_theme.blue), + magenta: partial_terminal_theme + .magenta + .unwrap_or(default_terminal_theme.magenta), + cyan: partial_terminal_theme + .cyan + .unwrap_or(default_terminal_theme.cyan), + white: partial_terminal_theme + .white + .unwrap_or(default_terminal_theme.white), + bright_black: partial_terminal_theme + .bright_black + .unwrap_or(default_terminal_theme.bright_black), + bright_red: partial_terminal_theme + .bright_red + .unwrap_or(default_terminal_theme.bright_red), + bright_green: partial_terminal_theme + .bright_green + .unwrap_or(default_terminal_theme.bright_green), + bright_yellow: partial_terminal_theme + .bright_yellow + .unwrap_or(default_terminal_theme.bright_yellow), + bright_blue: partial_terminal_theme + .bright_blue + .unwrap_or(default_terminal_theme.bright_blue), + bright_magenta: partial_terminal_theme + .bright_magenta + .unwrap_or(default_terminal_theme.bright_magenta), + bright_cyan: partial_terminal_theme + .bright_cyan + .unwrap_or(default_terminal_theme.bright_cyan), + bright_white: partial_terminal_theme + .bright_white + .unwrap_or(default_terminal_theme.bright_white), + cursor: partial_terminal_theme + .cursor + .unwrap_or(default_terminal_theme.cursor), + cursor_accent: partial_terminal_theme + .cursor_accent + .unwrap_or(default_terminal_theme.cursor_accent), }) } } - - fn default_to_true() -> bool { true } fn default_profile(uuid: String) -> Profile { Profile { - name: String::from("Default profile"), - terminal_options: TerminalOption::default(), - theme: TerminalTheme::default(), - background_transparency: RangedInt::default(), - uuid, + name: String::from("Default profile"), + terminal_options: TerminalOption::default(), + theme: TerminalTheme::default(), + background_transparency: RangedInt::default(), + uuid, #[cfg(target_family = "unix")] command: String::from("sh -c $SHELL"), #[cfg(target_os = "windows")] command: String::from("%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"), + background: None, } } @@ -528,4 +564,4 @@ fn default_shortcuts() -> Vec { action: ShortcutAction::FocusPrevTab, }, ] -} \ No newline at end of file +} diff --git a/src-tauri/src/configuration/mod.rs b/src-tauri/src/configuration/mod.rs index b6d6941..fe6466c 100644 --- a/src-tauri/src/configuration/mod.rs +++ b/src-tauri/src/configuration/mod.rs @@ -1,3 +1,3 @@ -pub mod partial; pub mod deserialized; -pub mod types; \ No newline at end of file +pub mod partial; +pub mod types; diff --git a/src-tauri/src/configuration/partial.rs b/src-tauri/src/configuration/partial.rs index 6f55efa..c662026 100644 --- a/src-tauri/src/configuration/partial.rs +++ b/src-tauri/src/configuration/partial.rs @@ -1,10 +1,10 @@ -use crate::configuration::types::RangedInt; use crate::configuration::deserialized::ShortcutAction; use crate::configuration::deserialized::TerminalOption; use crate::configuration::types::CursorType; -use crate::configuration::types::BackgroundType; +use crate::configuration::types::RangedInt; +use crate::configuration::types::{BackgroundMedia, BackgroundType}; use serde::Deserialize; - +use serde::Deserializer; #[derive(Deserialize, Debug)] pub struct PartialOption { @@ -31,7 +31,7 @@ pub struct PartialOption { pub close_confirmation: bool, #[serde(default)] - pub default_profile: String + pub default_profile: String, } impl Default for PartialOption { @@ -46,13 +46,11 @@ impl Default for PartialOption { background_transparency: RangedInt::default(), shortcuts: Some(Vec::default()), macros: Some(Vec::default()), - default_profile: String::new() + default_profile: String::new(), } } } - - #[derive(Deserialize, Debug)] pub struct PartialProfile { pub name: String, @@ -65,7 +63,7 @@ pub struct PartialProfile { pub show_picture: std::option::Option, pub bell: std::option::Option, pub theme: std::option::Option, - pub background_transparency: std::option::Option>, + pub background_transparency: std::option::Option>, pub cursor_blink: std::option::Option, pub draw_bold_in_bright: std::option::Option, pub show_unread_data_indicator: std::option::Option, @@ -74,31 +72,48 @@ pub struct PartialProfile { pub font_weight: std::option::Option>, pub font_weight_bold: std::option::Option>, pub title_is_running_process: std::option::Option, + #[serde(deserialize_with = "deserialize_profile_background")] + #[serde(default)] + pub background: std::option::Option, } - - #[derive(Deserialize, Debug)] pub struct PartialMacro { pub content: String, pub uuid: Option, } - - #[derive(Deserialize, Debug)] pub struct PartialShortcut { pub shortcut: String, pub action: ShortcutAction, } +fn deserialize_profile_background<'de, D>( + data: D, +) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + #[derive(Deserialize, Debug)] + #[serde(untagged)] + enum Representation { + Simple(String), + Complex(BackgroundMedia), + } - - - - - + Ok( + if let Ok(name_to_find) = Representation::deserialize(data) { + match name_to_find { + Representation::Simple(path) => BackgroundMedia::deserialize_from_string(path), + Representation::Complex(background) => Some(background), + } + } else { + None + }, + ) +} fn default_to_true() -> bool { true -} \ No newline at end of file +} diff --git a/src-tauri/src/configuration/types.rs b/src-tauri/src/configuration/types.rs index 5c9b89c..f0e76b6 100644 --- a/src-tauri/src/configuration/types.rs +++ b/src-tauri/src/configuration/types.rs @@ -1,6 +1,6 @@ -use serde::{Serializer, Serialize}; use serde::de::Error; use serde::Deserialize; +use serde::{Serialize, Serializer}; #[derive(Debug, Clone, Copy)] pub struct RangedInt { @@ -46,13 +46,13 @@ impl<'de, const MIN: u32, const MAX: u32, const DEF: u32> serde::Serialize } } - #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] pub enum BackgroundType { Opaque, Media(BackgroundMedia), Transparent, + #[cfg(target_family = "unix")] Blurred, #[cfg(target_os = "windows")] Acrylic, @@ -84,6 +84,7 @@ impl<'de> serde::Deserialize<'de> for BackgroundType { match option_value.to_lowercase().as_str() { "opaque" => BackgroundType::Opaque, "transparent" => BackgroundType::Transparent, + #[cfg(target_family = "unix")] "blurred" => BackgroundType::Blurred, #[cfg(target_os = "windows")] "acrylic" => BackgroundType::Acrylic, @@ -127,13 +128,13 @@ impl Default for CursorType { #[derive(Debug, Serialize, Clone)] pub struct BackgroundMedia { blur: RangedInt<0, 20, 0>, - location: String, + pub location: String, } impl BackgroundMedia { - fn deserialize_from_string(value: String) -> Option { + pub fn deserialize_from_string(value: String) -> Option { if let Ok(file) = std::fs::read(&value) { - if infer::is_image(&file) || infer::is_video(&file) { + if infer::is_image(&file) { Some(Self { location: value, blur: RangedInt::default(), @@ -156,18 +157,15 @@ impl<'de> serde::Deserialize<'de> for BackgroundMedia { } let partial_background_media = PartialBackgroundMedia::deserialize(deserializer)?; - - if let Ok(file) = std::fs::read(&partial_background_media.location) { - if infer::is_image(&file) || infer::is_video(&file) { - Ok(Self { - blur: partial_background_media.blur.unwrap_or_default(), - location: partial_background_media.location, - }) - } else { - Err(D::Error::custom("Format not supported")) - } + if std::fs::read(&partial_background_media.location) + .is_ok_and(|file| infer::is_image(&file)) + { + Ok(Self { + blur: partial_background_media.blur.unwrap_or_default(), + location: partial_background_media.location, + }) } else { - Err(D::Error::custom("Cannot read file")) + Err(D::Error::custom("File not found or format not supported")) } } -} \ No newline at end of file +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 51d4b15..3fae476 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,6 +1,6 @@ pub mod command; -pub mod configuration; pub mod common; +pub mod configuration; pub mod logger; pub mod pty; pub mod state; diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index c974264..2027321 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -7,13 +7,14 @@ use notify::Watcher; use tauri::Manager; use tess::command::{option::*, term::*, window::*}; use tess::configuration::deserialized::Option; +use tess::configuration::types::BackgroundType; use tess::logger::Logger; use std::sync::{Arc, Mutex}; fn main() { let start = std::time::Instant::now(); - let logger = Arc::from(Logger {}); + let logger = Logger{}; #[cfg(target_family = "unix")] let config_file = std::fs::read_to_string(format!( @@ -26,7 +27,6 @@ fn main() { dirs_next::config_dir().unwrap_or_default().display() )); - let option = Arc::from(Mutex::from(if let Ok(config_file) = config_file { // TODO: Log error serde_json::from_str(&config_file).unwrap_or_default() @@ -51,11 +51,40 @@ fn main() { let app_handle = app.as_ref().unwrap().app_handle(); + match &option.lock().unwrap().background { + BackgroundType::Media(media) => { + app_handle.fs_scope().allow_file(&media.location); + } + #[cfg(target_family = "unix")] + BackgroundType::Blurred => { + todo!() + } + #[cfg(target_os = "windows")] + BackgroundType::Mica => { + if let Err(_) = window_vibrancy::apply_mica(app_handle.get_window("main").unwrap()) { + logger.warn("Cannot apply mica background effect. Switching back to transparent background"); + } + } + #[cfg(target_os = "windows")] + BackgroundType::Acrylic => { + if let Err(_) = window_vibrancy::apply_acrylic(app_handle.get_window("main").unwrap(), None) { + logger.warn("Cannot apply acrylic background effect. Switching back to transparent background"); + } + } + #[cfg(target_os = "macos")] + BackgroundType::Vibrancy => { + todo!() + } + _ => {} + } + + app_handle.get_window("main").unwrap().set_decorations(true); + + app_handle .fs_scope() .allow_file(&option.lock().unwrap().app_theme); - let logger_clone = logger.clone(); let mut watcher = notify::recommended_watcher(move |res: Result| { @@ -77,7 +106,7 @@ fn main() { *reff = option; - logger_clone.info("Refreshing config..."); + logger.info("Refreshing config..."); app_handle.emit_all("global_config_updated", format!("{:?}", reff)); } diff --git a/src-tauri/src/pty.rs b/src-tauri/src/pty.rs index 97e7570..aaf4da8 100644 --- a/src-tauri/src/pty.rs +++ b/src-tauri/src/pty.rs @@ -1,23 +1,35 @@ -use portable_pty::{native_pty_system, CommandBuilder, PtySize}; use portable_pty::Child; -use std::sync::{Arc, Mutex}; +use portable_pty::{native_pty_system, CommandBuilder, PtySize}; +use std::sync::{Arc, Mutex, RwLock}; use crate::common::errors::PtyError; -use std::sync::mpsc::{Receiver, Sender, TryRecvError}; +use crate::configuration::deserialized::Profile; use tauri::{AppHandle, Manager}; -use crate::common::payloads::PtySendData; +use crate::common::payloads::{PtySendData, PtyTitleChanged}; +#[cfg(target_os = "windows")] +use crate::common::utils::get_leader_process_name; #[cfg(target_os = "windows")] use lazy_static::lazy_static; #[cfg(target_os = "windows")] -use regex::{Regex, Captures}; +use regex::{Captures, Regex}; +#[cfg(target_os = "windows")] +use remoteprocess::Process; +#[cfg(target_os = "windows")] +use std::ffi::OsString; pub struct Pty { pub app: Arc, - pair: Arc, - close_channel_sender: Sender<()>, + pair: Arc>, child: Option>>>, + #[cfg(target_family = "unix")] + current_leader: Arc>, + #[cfg(target_os = "windows")] + leader_programm_name: Arc>, + writer: Option>, + is_running: Arc>, + title_is_running_process: Arc>, } unsafe impl Send for Pty {} @@ -26,31 +38,35 @@ unsafe impl Sync for Pty {} impl Pty { pub fn new( app: Arc, - cmd: &str, + profile: Profile, cols: u16, rows: u16, id: String, ) -> Result { let pty_system = native_pty_system(); - let pair = pty_system.openpty(PtySize { - rows: rows, - cols: cols, + if let Ok(pair) = pty_system.openpty(PtySize { + rows, + cols, pixel_width: 0, pixel_height: 0, - }); - - let (sender, receiver) = std::sync::mpsc::channel::<()>(); - - if let Ok(pair) = pair { + }) { let mut pty = Pty { - app: app, - pair: Arc::new(pair), + app, + pair: Arc::new(Mutex::from(pair)), child: None, - close_channel_sender: sender, + #[cfg(target_family = "unix")] + current_leader: Arc::new(RwLock::new(0)), + #[cfg(target_os = "windows")] + leader_programm_name: Arc::new(Mutex::from(OsString::new())), + writer: None, + is_running: Arc::new(RwLock::new(true)), + title_is_running_process: Arc::new(RwLock::new( + profile.terminal_options.title_is_running_process, + )), }; - pty.run(cmd, id, receiver)?; + pty.run(profile, id)?; Ok(pty) } else { @@ -60,77 +76,161 @@ impl Pty { } } - pub fn run( - &mut self, - cmd: &str, - id: String, - close_channel_receiver: Receiver<()>, - ) -> Result<(), PtyError> { + pub fn run(&mut self, profile: Profile, id: String) -> Result<(), PtyError> { #[cfg(target_os = "windows")] lazy_static! { static ref PROGRAMM_PARSING_REGEX: Regex = Regex::new("%([[:word:]]*)%").unwrap(); } #[cfg(target_os = "windows")] - let cmd: String = PROGRAMM_PARSING_REGEX.replace_all(&cmd, |env_variable: &Captures| { - std::env::var(&env_variable[1]).unwrap_or_default() - }).into(); + let cmd: String = PROGRAMM_PARSING_REGEX + .replace_all(&profile.command, |env_variable: &Captures| { + std::env::var(&env_variable[1]).unwrap_or_default() + }) + .into(); + #[cfg(target_family = "unix")] + let cmd = profile.command; + + #[allow(unused_mut)] let mut command_builder = CommandBuilder::from_argv(Vec::from_iter( - cmd.split(' ').map(|s| std::ffi::OsString::from(s)), + cmd.split(' ') + .map(std::ffi::OsString::from), )); #[cfg(target_family = "unix")] command_builder.env("TERM", "xterm-256color"); - if let Ok(child) = self.pair.slave.spawn_command(command_builder) { + let locked_pair = self.pair.lock().unwrap(); + + if let Ok(child) = locked_pair.slave.spawn_command(command_builder) { + #[cfg(target_os = "windows")] + let tmp_pty_pid = child.process_id().unwrap(); + let child = Arc::from(Mutex::from(child)); let child_clone = child.clone(); - if let Ok(mut reader) = self.pair.clone().master.try_clone_reader() { + if let Ok(mut reader) = locked_pair.master.try_clone_reader() { let app = self.app.as_ref().clone(); let cloned_app = app.clone(); let id_cloned = id.clone(); - std::thread::spawn(move || loop { - match close_channel_receiver.try_recv() { - Err(TryRecvError::Empty) => { - let mut buffer = [0; 4096]; - - if reader.read(&mut buffer).is_ok() { - app.emit_all( - "terminalData", - PtySendData { - data: String::from_utf8(buffer.to_vec()) - .unwrap_or_default(), - id: id.clone(), - }, - ) - .ok(); - } - } - _ => { - break; + self.child = Some(child); + self.writer = Some(locked_pair.master.take_writer().unwrap()); + + let is_running = self.is_running.clone(); + let is_running_cloned = is_running.clone(); + + let title_is_running_process = self.title_is_running_process.clone(); + + #[cfg(target_os = "windows")] + let leader_programm_name = self.leader_programm_name.clone(); + + #[cfg(target_family = "unix")] + let cloned_pair = self.pair.clone(); + #[cfg(target_family = "unix")] + let current_process_leader_pid = self.current_leader.clone(); + + std::thread::spawn(move || { + while *is_running.read().unwrap() { + let mut buffer = [0; 4096]; + + if reader.read(&mut buffer).is_ok() { + app.emit_all( + "terminalData", + PtySendData { + data: String::from_utf8(buffer.to_vec()).unwrap_or_default(), + id: id.clone(), + }, + ) + .ok(); } } }); - std::thread::spawn(move || loop { - if let Ok(Some(_)) = child_clone.as_ref().lock().unwrap().try_wait() { - cloned_app - .emit_all("terminal_closed", id_cloned.clone()) - .ok(); + std::thread::spawn(move || { + while *is_running_cloned.read().unwrap() { + if let Ok(Some(_)) = child_clone.as_ref().lock().unwrap().try_wait() { + *is_running_cloned.write().unwrap() = false; - break; - } + cloned_app + .emit_all("terminal_closed", id_cloned.clone()) + .ok(); + + break; + } else if *title_is_running_process.read().unwrap() { + #[cfg(target_os = "windows")] + { + let leader_process_name = + get_leader_process_name(Process::new(tmp_pty_pid).unwrap()); + + if let Some(new_leader_process_name) = leader_process_name { + let mut leader_programm_name_locked = + leader_programm_name.lock().unwrap(); + + if new_leader_process_name != *leader_programm_name_locked { + *leader_programm_name_locked = new_leader_process_name; + + cloned_app + .emit_all( + "terminalTitleChanged", + PtyTitleChanged { + id: id_cloned.clone(), + title: leader_programm_name_locked + .clone() + .into_string() + .unwrap(), + }, + ) + .ok(); + } + } + } + + #[cfg(target_family = "unix")] + { + let cloned_locked_pair = cloned_pair.lock().unwrap(); + + if let Some(process_leader_pid) = + cloned_locked_pair.master.process_group_leader() + { + if process_leader_pid + != *current_process_leader_pid.read().unwrap() + { + std::thread::sleep(std::time::Duration::from_millis(5)); + + *current_process_leader_pid.write().unwrap() = + process_leader_pid; + + if let Ok(mut process_leader_title) = + std::fs::read_to_string(format!( + "/proc/{}/comm", + process_leader_pid + )) + { + process_leader_title.pop(); + + cloned_app + .emit_all( + "terminalTitleChanged", + PtyTitleChanged { + id: id_cloned.clone(), + title: process_leader_title, + }, + ) + .ok(); + } + } + } + } + } - std::thread::sleep(std::time::Duration::from_millis(5)); + std::thread::sleep(std::time::Duration::from_millis(10)); + } }); }; - self.child = Some(child); - Ok(()) } else { Err(PtyError::Create(String::from( @@ -140,11 +240,7 @@ impl Pty { } pub fn write(&mut self, content: String) -> Result<(), PtyError> { - if let Ok(()) = write!( - self.pair.clone().master.try_clone_writer().unwrap(), - "{}", - content - ) { + if let Ok(()) = write!(self.writer.as_mut().unwrap(), "{}", content) { Ok(()) } else { Err(PtyError::Write(String::from( @@ -154,12 +250,18 @@ impl Pty { } pub fn resize(&self, cols: u16, rows: u16) -> Result<(), PtyError> { - if let Ok(()) = self.pair.master.resize(portable_pty::PtySize { - cols, - rows, - pixel_height: 0, - pixel_width: 0, - }) { + if let Ok(()) = self + .pair + .lock() + .unwrap() + .master + .resize(portable_pty::PtySize { + cols, + rows, + pixel_height: 0, + pixel_width: 0, + }) + { Ok(()) } else { Err(PtyError::Resize(String::from( @@ -170,37 +272,21 @@ impl Pty { pub fn close(&mut self) -> Result<(), PtyError> { if let Some(child) = self.child.as_deref() { + *self.is_running.write().unwrap() = false; + if let Ok(mut child) = child.lock() { - if let Ok(()) = child.kill() { - if let Ok(()) = self.close_channel_sender.send(()) { - Ok(()) - } else { - Err(PtyError::Kill(String::from( - "process didn't terminate correctly.", - ))) - } - } else if let Ok(_) = child.try_wait() { - if let Ok(()) = self.close_channel_sender.send(()) { - Ok(()) - } else { - Err(PtyError::Kill(String::from( - "process didn't terminate correctly.", - ))) - } + if child.try_wait().is_ok_and(|x| x.is_some()) { + Ok(()) + } else if let Ok(()) = child.kill() { + Ok(()) } else { - Err(PtyError::Kill(String::from( - "process didn't terminate correctly.", - ))) + todo!() } } else { - Err(PtyError::Kill(String::from( - "doesn't have access to the pty.", - ))) + todo!() } } else { - Err(PtyError::Kill(String::from( - "doesn't have access to the pty.", - ))) + todo!() } } } diff --git a/src-tauri/src/state/pty_manager.rs b/src-tauri/src/state/pty_manager.rs index 846ccaf..61139f5 100644 --- a/src-tauri/src/state/pty_manager.rs +++ b/src-tauri/src/state/pty_manager.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::sync::Arc; +use crate::configuration::deserialized::Profile; use crate::pty::Pty; use crate::common::errors::PtyError; @@ -23,10 +24,10 @@ impl PtyManager { cols: u16, rows: u16, id: String, - cmd: &str, + profile: Profile, ) -> Result<(), PtyError> { if let Some(app_ref) = self.app.as_ref() { - let pty = Pty::new(app_ref.clone(), cmd, cols, rows, id.clone())?; + let pty = Pty::new(app_ref.clone(), profile, cols, rows, id.clone())?; self.ptys.insert(id, pty); @@ -38,33 +39,32 @@ impl PtyManager { } } - pub fn write(&mut self, id: String, content: String) -> Result<(), PtyError> { + pub fn write(&mut self, id: &str, content: String) -> Result<(), PtyError> { self.ptys - .get_mut(&id) - .ok_or(PtyError::Write(String::from( + .get_mut(id) + .ok_or_else(|| PtyError::Write(String::from( "Unable to access to the terminal.", )))? .write(content)?; Ok(()) } - pub fn resize(&mut self, id: String, cols: u16, rows: u16) -> Result<(), PtyError> { + pub fn resize(&mut self, id: &str, cols: u16, rows: u16) -> Result<(), PtyError> { self.ptys - .get_mut(&id) - .ok_or(PtyError::Resize(String::from( + .get_mut(id) + .ok_or_else(|| PtyError::Resize(String::from( "Unable to access to the terminal.", )))? .resize(cols, rows)?; Ok(()) } - pub fn close(&mut self, id: String) -> Result<(), PtyError> { + pub fn close(&mut self, id: &str) -> Result<(), PtyError> { self.ptys - .get_mut(&id) - .ok_or(PtyError::Kill(String::from( + .remove(id) + .ok_or_else(|| PtyError::Kill(String::from( "Unable to access to the terminal.", )))? - .close()?; - Ok(()) + .close() } } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index ac7157f..1fc66d4 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -62,7 +62,9 @@ "height": 720, "resizable": true, "title": "Tess", - "width": 1280 + "width": 1280, + "transparent": true, + "decorations": false } ] } diff --git a/src/style/style.scss b/src/style/style.scss index 4c3c7cf..2867b6a 100644 --- a/src/style/style.scss +++ b/src/style/style.scss @@ -46,6 +46,7 @@ body { background: var(--app-background); } + ::-webkit-scrollbar { height: 4px; width: 4px; @@ -54,4 +55,16 @@ body { ::-webkit-scrollbar-thumb { background:rgba(212, 212, 212, 0.14); border-radius: 6px; +} + + +.background-image { + height: 100%; + width: 100%; + z-index: -4; + object-fit: cover; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + position: absolute; } \ No newline at end of file diff --git a/src/style/tab.scss b/src/style/tab.scss index 99f3e67..35a379d 100644 --- a/src/style/tab.scss +++ b/src/style/tab.scss @@ -48,6 +48,7 @@ width: calc(100% - 64px); text-align: center; font-weight: 600; + line-height: 12px; } .close { diff --git a/src/style/target/linux.scss b/src/style/target/linux.scss index 729e375..15481f1 100644 --- a/src/style/target/linux.scss +++ b/src/style/target/linux.scss @@ -1,3 +1,7 @@ .views .view .pane .internal-term canvas { will-change: transform; +} + +.background-image { + will-change: transform; // Require to force GPU acceleration to improve blur performance. } \ No newline at end of file diff --git a/src/style/term.scss b/src/style/term.scss index c5adc2f..56a215b 100644 --- a/src/style/term.scss +++ b/src/style/term.scss @@ -18,10 +18,24 @@ width: 100%; height: 100%; display: flex; + position: relative; + + .background-image { + z-index: -2; + } .internal-term { height: calc(100% - 30px); width: 100%; + + &::before { + position: absolute; + height: 100%; + width: 100%; + content: ""; + background: var(--profile-background); + opacity: var(--profile-background-transparency); + } } } } diff --git a/src/ts/class/panes.ts b/src/ts/class/panes.ts index 7d8bdeb..9a58ade 100644 --- a/src/ts/class/panes.ts +++ b/src/ts/class/panes.ts @@ -1,16 +1,21 @@ -import { invoke } from '@tauri-apps/api/tauri'; +import { invoke, convertFileSrc } from '@tauri-apps/api/tauri'; import { Terminal } from "./terminal"; import { Profile } from 'ts/schema/option'; export class TerminalPane { element: Element; id: string; + profile: Profile; term: Terminal | null = null; - constructor(id: string) { + title: String + + constructor(id: string, profile: Profile) { + this.profile = profile this.element = this.generateComponents(); this.id = id; + this.title = profile.name; } generateComponents() : Element { @@ -18,16 +23,29 @@ export class TerminalPane { element.classList.add("pane"); let internalTerm = document.createElement("div"); - internalTerm.classList.add("internal-term") + internalTerm.classList.add("internal-term"); + + if (this.profile.background) { + let background = document.createElement("img"); + background.src = convertFileSrc(this.profile.background.location); + background.classList.add("background-image"); + element.appendChild(background); + + internalTerm.style.setProperty("-webkit-backdrop-filter", `blur(${this.profile.background.blur}px)`) + } + + internalTerm.style.setProperty("--profile-background", this.profile.theme.background); + internalTerm.style.setProperty("--profile-background-transparency", `${this.profile.backgroundTransparency}%`); + element.appendChild(internalTerm); return element } - async initializeTerm(profile: Profile) { - let terminal = new Terminal(this.id, profile.terminalOptions, profile.theme); + async initializeTerm() { + let terminal = new Terminal(this.id, this.profile.terminalOptions, this.profile.theme); - await terminal.launch(this.element.querySelector(".internal-term")!, profile.command); + await terminal.launch(this.element.querySelector(".internal-term")!, this.profile.uuid); this.term = terminal; } @@ -61,10 +79,13 @@ export class PagePane { id: string element: Element | null = null; + title: String + constructor(id: string) { // TODO: Implement this.id = id; + this.title = ""; } async close() { diff --git a/src/ts/class/tab.ts b/src/ts/class/tab.ts index f65cb11..ee333eb 100644 --- a/src/ts/class/tab.ts +++ b/src/ts/class/tab.ts @@ -48,8 +48,6 @@ export class Tab { } private generateComponents() : HTMLElement { - // TODO: Finish implementing this - let tab = document.createElement("div"); let title = document.createElement("span"); diff --git a/src/ts/class/terminal.ts b/src/ts/class/terminal.ts index b9a86cb..baf1403 100644 --- a/src/ts/class/terminal.ts +++ b/src/ts/class/terminal.ts @@ -8,17 +8,21 @@ import { TerminalOptions, TerminalTheme } from "ts/schema/option"; export class Terminal { id: string; term: Xterm; - fitAddon: FitAddon + fitAddon: FitAddon; + constructor(id: string, options: TerminalOptions, theme: TerminalTheme) { // TODO: Finish // TODO: Load all addons + theme = Object.assign({}, theme); + theme.background = "transparent"; this.id = id; this.term = new Xterm({ allowProposedApi: true, fontFamily: "Fira Code, monospace", + allowTransparency: true, fontSize: options.fontSize, drawBoldTextInBrightColors: options.drawBoldInBright, cursorBlink: options.cursorBlink, @@ -33,16 +37,6 @@ export class Terminal { this.fitAddon = new FitAddon(); - addEventListener("resize", () => { - this.fitAddon.fit(); - invoke("resize_terminal", {cols: this.term.cols, rows: this.term.rows, id: this.id}).catch((error) => { - // TODO: Send notification with error message - - console.error(error); - }); - }) - - this.term.attachCustomKeyEventHandler((e) => { if (e.key == "F10") { invoke("terminal_input", {content: "\x1b[21~", id: id}); @@ -54,8 +48,17 @@ export class Terminal { }) } - async launch(target: HTMLElement, command: string) { - await invoke("create_terminal", {cols: this.term.cols, rows: this.term.rows, id: this.id, command: command}) + async launch(target: HTMLElement, profile_id: string) { + target.addEventListener("resize", () => { + this.fitAddon.fit(); + invoke("resize_terminal", {cols: this.term.cols, rows: this.term.rows, id: this.id}).catch((error) => { + // TODO: Send notification with error message + + console.error(error); + }); + }) + + await invoke("create_terminal", {cols: this.term.cols, rows: this.term.rows, id: this.id, profileUuid: profile_id}) this.term.open(target); diff --git a/src/ts/class/views.ts b/src/ts/class/views.ts index 4508c08..56e2842 100644 --- a/src/ts/class/views.ts +++ b/src/ts/class/views.ts @@ -11,18 +11,17 @@ export class View { panes: (TerminalPane|PagePane)[] = [] closedEvent: ((id: string) => void) | undefined; + focusedPaneTitleChangedEvent: ((title: string) => void) | undefined; - async buildNew(viewId: string, paneId: string, closedEvent: ((id: string) => void), profile: Profile) { + async buildNew(viewId: string, paneId: string, closedEvent: ((id: string) => void), profile: Profile, focusedPaneTitleChangedEvent: ((title: string) => void)) { this.id = viewId; this.element = this.generateComponents(); this.closedEvent = closedEvent; + this.focusedPaneTitleChangedEvent = focusedPaneTitleChangedEvent; - - - let pane = new TerminalPane(paneId); - - await pane.initializeTerm(profile); + let pane = new TerminalPane(paneId, profile); + await pane.initializeTerm(); this.panes.push(pane) this.element.appendChild(pane.element); @@ -59,8 +58,6 @@ export class View { if (this.panes.length == 0) { this.closedEvent!(this.id!); } - - // TODO: Implement } writeToTerm(termId: string, data: string) { @@ -97,6 +94,14 @@ export class View { }) } + updatePaneTitle(id: string, title: string) { + let pane = this.panes.find((pane) => pane.id == id); + if (pane) { + pane.title = title; + this.focusedPaneTitleChangedEvent!(title) + } + } + /*openPane(split: "horizontaly" | "vertically", paneId: string, subviewToSplit: string) { // TODO: Implement }*/ diff --git a/src/ts/main.ts b/src/ts/main.ts index 858da0b..ad0da92 100644 --- a/src/ts/main.ts +++ b/src/ts/main.ts @@ -9,21 +9,32 @@ window.addEventListener("contextmenu", (e) => { }) invoke