diff options
| author | Ellie Huxtable <ellie@atuin.sh> | 2024-07-08 11:17:47 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-08 11:17:47 +0100 |
| commit | 5b384487331eaf08031dfe438bb2affa31aafcbb (patch) | |
| tree | 51904c3df8c54cbc5b7aa5832a5bae49d57f7141 /ui/backend | |
| parent | feat(bash/blesh): hook into BLE_ONLOAD to resolve loading order issue (#2234) (diff) | |
| download | atuin-5b384487331eaf08031dfe438bb2affa31aafcbb.zip | |
feat(gui): runbooks that run (#2233)
* add initial runbooks frontend
* fix buttons, scroll, add shell support to editor
* work
* some tweaks
* wip - run crate
* functioning executable blocks
* handle resizing, killing ptys
* clear properly on stop
* move terminal to its own component, handle lifecycle better
* fix all build issues
* ffs codespelll
* update lockfile
* clippy is needy once more
* only build pty stuff on mac/linux
* vendor pty handling into desktop
* update lockfile
Diffstat (limited to '')
| -rw-r--r-- | ui/backend/Cargo.lock | 471 | ||||
| -rw-r--r-- | ui/backend/Cargo.toml | 6 | ||||
| -rw-r--r-- | ui/backend/capabilities/migrated.json | 1 | ||||
| -rw-r--r-- | ui/backend/rust-toolchain.toml | 2 | ||||
| -rw-r--r-- | ui/backend/src/db.rs | 35 | ||||
| -rw-r--r-- | ui/backend/src/install.rs | 3 | ||||
| -rw-r--r-- | ui/backend/src/main.rs | 27 | ||||
| -rw-r--r-- | ui/backend/src/pty.rs | 112 | ||||
| -rw-r--r-- | ui/backend/src/run/mod.rs | 1 | ||||
| -rw-r--r-- | ui/backend/src/run/pty.rs | 93 | ||||
| -rw-r--r-- | ui/backend/src/state.rs | 10 |
11 files changed, 733 insertions, 28 deletions
diff --git a/ui/backend/Cargo.lock b/ui/backend/Cargo.lock index 90b5c8c4..827fd09b 100644 --- a/ui/backend/Cargo.lock +++ b/ui/backend/Cargo.lock @@ -153,6 +153,12 @@ dependencies = [ ] [[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] name = "async-broadcast" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -329,12 +335,6 @@ dependencies = [ ] [[package]] -name = "atomic" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" - -[[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -342,7 +342,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atuin-client" -version = "18.3.0" +version = "18.4.0-beta.1" dependencies = [ "async-trait", "atuin-common", @@ -390,10 +390,12 @@ dependencies = [ [[package]] name = "atuin-common" -version = "18.3.0" +version = "18.4.0-beta.1" dependencies = [ + "base64 0.22.1", "directories", "eyre", + "getrandom 0.2.15", "lazy_static", "rand 0.8.5", "semver", @@ -408,7 +410,7 @@ dependencies = [ [[package]] name = "atuin-dotfiles" -version = "0.3.0" +version = "0.4.0" dependencies = [ "atuin-client", "atuin-common", @@ -422,7 +424,7 @@ dependencies = [ [[package]] name = "atuin-history" -version = "0.2.0" +version = "0.3.0" dependencies = [ "async-trait", "atuin-client", @@ -505,6 +507,21 @@ dependencies = [ ] [[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -779,7 +796,8 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.1", + "terminal_size", ] [[package]] @@ -847,6 +865,26 @@ dependencies = [ ] [[package]] +name = "comrak" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0436149c9f6a1935b13306206c739b1ba84fa81f551b5eb87fc2ca7a13700af" +dependencies = [ + "clap", + "derive_builder", + "entities", + "memchr", + "once_cell", + "regex", + "shell-words", + "slug", + "syntect", + "typed-arena", + "unicode_categories", + "xdg", +] + +[[package]] name = "concurrent-queue" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1157,12 +1195,36 @@ dependencies = [ [[package]] name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.9", + "darling_macro 0.20.9", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", ] [[package]] @@ -1175,17 +1237,28 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.11.1", "syn 2.0.66", ] [[package]] name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ - "darling_core", + "darling_core 0.20.9", "quote", "syn 2.0.66", ] @@ -1229,6 +1302,37 @@ dependencies = [ ] [[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] name = "derive_more" version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1242,6 +1346,12 @@ dependencies = [ ] [[package]] +name = "deunicode" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" + +[[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1360,6 +1470,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] name = "dpi" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1470,6 +1586,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" [[package]] +name = "entities" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + +[[package]] name = "enumflags2" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1555,6 +1677,16 @@ dependencies = [ ] [[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] name = "fastrand" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1581,7 +1713,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ - "memoffset", + "memoffset 0.9.1", "rustc_version", ] @@ -2658,12 +2790,40 @@ dependencies = [ ] [[package]] +name = "ioctl-rs" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7970510895cee30b3e9128319f2cefd4bde883a39f38baa279567ba3a7eb97d" +dependencies = [ + "libc", +] + +[[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] name = "is_terminal_polyfill" version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3024,6 +3184,15 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" @@ -3127,6 +3296,20 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", + "pin-utils", +] + +[[package]] +name = "nix" version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" @@ -3134,7 +3317,19 @@ dependencies = [ "bitflags 2.5.0", "cfg-if", "libc", - "memoffset", + "memoffset 0.9.1", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "cfg_aliases", + "libc", ] [[package]] @@ -3443,6 +3638,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] +name = "open" +version = "5.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5ca541f22b1c46d4bb9801014f234758ab4297e7870b904b6a8415b980a7388" +dependencies = [ + "is-wsl", + "libc", + "pathdiff", +] + +[[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3465,6 +3671,16 @@ dependencies = [ ] [[package]] +name = "os_pipe" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29d73ba8daf8fac13b0501d1abeddcfe21ba7401ada61a819144b6c2a4f32209" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3841,6 +4057,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" [[package]] +name = "portable-pty" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806ee80c2a03dbe1a9fb9534f8d19e4c0546b790cde8fd1fea9d6390644cb0be" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "downcast-rs", + "filedescriptor", + "lazy_static", + "libc", + "log", + "nix 0.25.1", + "serial", + "shared_library", + "shell-words", + "winapi", + "winreg 0.10.1", +] + +[[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4605,9 +4842,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa 1.0.11", "ryu", @@ -4680,13 +4917,55 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" dependencies = [ - "darling", + "darling 0.20.9", "proc-macro2", "quote", "syn 2.0.66", ] [[package]] +name = "serial" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1237a96570fc377c13baa1b88c7589ab66edced652e43ffb17088f003db3e86" +dependencies = [ + "serial-core", + "serial-unix", + "serial-windows", +] + +[[package]] +name = "serial-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f46209b345401737ae2125fe5b19a77acce90cd53e1658cda928e4fe9a64581" +dependencies = [ + "libc", +] + +[[package]] +name = "serial-unix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03fbca4c9d866e24a459cbca71283f545a37f8e3e002ad8c70593871453cab7" +dependencies = [ + "ioctl-rs", + "libc", + "serial-core", + "termios", +] + +[[package]] +name = "serial-windows" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c6d3b776267a75d31bbdfd5d36c0ca051251caafc285827052bc53bcdc8162" +dependencies = [ + "libc", + "serial-core", +] + +[[package]] name = "serialize-to-javascript" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4750,6 +5029,32 @@ dependencies = [ ] [[package]] +name = "shared_child" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "shared_library" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +dependencies = [ + "lazy_static", + "libc", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] name = "shellexpand" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4820,6 +5125,16 @@ dependencies = [ ] [[package]] +name = "slug" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd94acec9c8da640005f8e135a39fc0372e74535e6b368b7a04b875f784c8c4" +dependencies = [ + "deunicode", + "wasm-bindgen", +] + +[[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5196,6 +5511,12 @@ dependencies = [ [[package]] name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" @@ -5264,6 +5585,7 @@ checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" dependencies = [ "bincode", "bitflags 1.3.2", + "fancy-regex", "flate2", "fnv", "once_cell", @@ -5553,6 +5875,27 @@ dependencies = [ ] [[package]] +name = "tauri-plugin-shell" +version = "2.0.0-beta.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8675bf7ab71f571a99192d0685ae870eb7af1264bdbbb66a1d655609f6c7ebd" +dependencies = [ + "encoding_rs", + "log", + "open", + "os_pipe", + "regex", + "schemars", + "serde", + "serde_json", + "shared_child", + "tauri", + "tauri-plugin", + "thiserror", + "tokio", +] + +[[package]] name = "tauri-plugin-single-instance" version = "2.0.0-beta.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5697,6 +6040,25 @@ dependencies = [ ] [[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "termios" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a" +dependencies = [ + "libc", +] + +[[package]] name = "thin-slice" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6068,6 +6430,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] name = "typed-builder" version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6099,7 +6467,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ - "memoffset", + "memoffset 0.9.1", "tempfile", "winapi", ] @@ -6112,7 +6480,11 @@ dependencies = [ "atuin-common", "atuin-dotfiles", "atuin-history", + "bytes", + "comrak", "eyre", + "nix 0.29.0", + "portable-pty", "serde", "serde_json", "sqlx", @@ -6120,11 +6492,13 @@ dependencies = [ "tauri", "tauri-build", "tauri-plugin-http", + "tauri-plugin-shell", "tauri-plugin-single-instance", "tauri-plugin-sql", "time", "tokio", "uuid", + "vt100", ] [[package]] @@ -6286,11 +6660,10 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" dependencies = [ - "atomic", "getrandom 0.2.15", "serde", ] @@ -6340,6 +6713,39 @@ dependencies = [ ] [[package]] +name = "vt100" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84cd863bf0db7e392ba3bd04994be3473491b31e66340672af5d11943c6274de" +dependencies = [ + "itoa 1.0.11", + "log", + "unicode-width", + "vte", +] + +[[package]] +name = "vte" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6976,6 +7382,15 @@ dependencies = [ [[package]] name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "winreg" version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" @@ -7070,6 +7485,12 @@ dependencies = [ ] [[package]] +name = "xdg" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" + +[[package]] name = "xdg-home" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7135,7 +7556,7 @@ dependencies = [ "futures-sink", "futures-util", "hex", - "nix", + "nix 0.27.1", "ordered-stream", "rand 0.8.5", "serde", diff --git a/ui/backend/Cargo.toml b/ui/backend/Cargo.toml index ed8ca070..d027e152 100644 --- a/ui/backend/Cargo.toml +++ b/ui/backend/Cargo.toml @@ -27,6 +27,12 @@ syntect = "5.2.0" tauri-plugin-http = "2.0.0-beta" tauri-plugin-single-instance = "2.0.0-beta" tokio = "1.38.0" +tauri-plugin-shell = "2.0.0-beta.7" +comrak = "0.22" +portable-pty = "0.8.1" +vt100 = "0.15.2" +bytes = "1.6.0" +nix = "0.29.0" [dependencies.sqlx] version = "0.7" diff --git a/ui/backend/capabilities/migrated.json b/ui/backend/capabilities/migrated.json index d6d8889c..e740ab1e 100644 --- a/ui/backend/capabilities/migrated.json +++ b/ui/backend/capabilities/migrated.json @@ -11,6 +11,7 @@ "resources:default", "menu:default", "tray:default", + "shell:allow-open", "sql:allow-load", "sql:allow-execute", "sql:allow-select", diff --git a/ui/backend/rust-toolchain.toml b/ui/backend/rust-toolchain.toml index fcc85b9e..c6e4d7d5 100644 --- a/ui/backend/rust-toolchain.toml +++ b/ui/backend/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.77" +channel = "1.79" diff --git a/ui/backend/src/db.rs b/ui/backend/src/db.rs index 1015ebf1..56d422ab 100644 --- a/ui/backend/src/db.rs +++ b/ui/backend/src/db.rs @@ -174,6 +174,41 @@ impl HistoryDB { Ok(history) } + pub async fn prefix_search(&self, query: &str) -> Result<Vec<UIHistory>, String> { + let context = Context { + session: "".to_string(), + cwd: "".to_string(), + host_id: "".to_string(), + hostname: "".to_string(), + git_root: None, + }; + + let filters = OptFilters { + limit: Some(5), + ..OptFilters::default() + }; + + let history = self + .0 + .search( + SearchMode::Prefix, + FilterMode::Global, + &context, + query, + filters, + ) + .await + .map_err(|e| e.to_string())?; + + let history = history + .into_iter() + .filter(|h| h.duration > 0) + .map(|h| h.into()) + .collect(); + + Ok(history) + } + pub async fn calendar(&self) -> Result<Vec<(String, u64)>, String> { let query = "select count(1) as count, strftime('%F', datetime(timestamp / 1000000000, 'unixepoch')) as day from history where timestamp > ((unixepoch() - 31536000) * 1000000000) group by day;"; diff --git a/ui/backend/src/install.rs b/ui/backend/src/install.rs index 43ad0c54..17896e3a 100644 --- a/ui/backend/src/install.rs +++ b/ui/backend/src/install.rs @@ -24,7 +24,8 @@ pub(crate) async fn install_cli() -> Result<(), String> { pub(crate) async fn is_cli_installed() -> Result<bool, String> { let shell = Shell::default_shell().map_err(|e| format!("Failed to get default shell: {e}"))?; let output = if shell == Shell::Powershell { - shell.run_interactive(&["atuin --version; if ($?) {echo 'ATUIN FOUND'}"]) + shell + .run_interactive(&["atuin --version; if ($?) {echo 'ATUIN FOUND'}"]) .map_err(|e| format!("Failed to run interactive command"))? } else { shell diff --git a/ui/backend/src/main.rs b/ui/backend/src/main.rs index 2ba67e50..7adbbbe5 100644 --- a/ui/backend/src/main.rs +++ b/ui/backend/src/main.rs @@ -1,6 +1,8 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +use tauri::State; + use std::path::PathBuf; use tauri::{AppHandle, Manager}; @@ -9,6 +11,9 @@ use time::format_description::well_known::Rfc3339; mod db; mod dotfiles; mod install; +mod pty; +mod run; +mod state; mod store; use atuin_client::settings::Settings; @@ -168,7 +173,7 @@ async fn home_info() -> Result<HomeInfo, String> { } // Match the format that the frontend library we use expects -// All the processing in Rust, not JS. +// All the processing in Rust, not JSunwrap. // Faaaassssssst af ⚡️🦀 #[derive(Debug, serde::Serialize)] pub struct HistoryCalendarDay { @@ -215,6 +220,19 @@ async fn history_calendar() -> Result<Vec<HistoryCalendarDay>, String> { Ok(ret) } +#[tauri::command] +async fn prefix_search(query: &str) -> Result<Vec<String>, String> { + let settings = Settings::new().map_err(|e| e.to_string())?; + + let db_path = PathBuf::from(settings.db_path.as_str()); + let db = HistoryDB::new(db_path, settings.local_timeout).await?; + + let history = db.prefix_search(query).await?; + let commands = history.into_iter().map(|h| h.command).collect(); + + Ok(commands) +} + fn show_window(app: &AppHandle) { let windows = app.webview_windows(); @@ -228,9 +246,11 @@ fn show_window(app: &AppHandle) { fn main() { tauri::Builder::default() + .plugin(tauri_plugin_shell::init()) .invoke_handler(tauri::generate_handler![ list, search, + prefix_search, global_stats, aliases, home_info, @@ -239,6 +259,10 @@ fn main() { login, register, history_calendar, + run::pty::pty_open, + run::pty::pty_write, + run::pty::pty_resize, + run::pty::pty_kill, install::install_cli, install::is_cli_installed, install::setup_cli, @@ -254,6 +278,7 @@ fn main() { .plugin(tauri_plugin_single_instance::init(|app, args, cwd| { let _ = show_window(app); })) + .manage(state::AtuinState::default()) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/ui/backend/src/pty.rs b/ui/backend/src/pty.rs new file mode 100644 index 00000000..07857824 --- /dev/null +++ b/ui/backend/src/pty.rs @@ -0,0 +1,112 @@ +use std::{ + io::Write, + sync::{Arc, Mutex}, +}; + +use bytes::Bytes; +use eyre::{eyre, Result}; +use portable_pty::{CommandBuilder, MasterPty, PtySize}; + +pub struct Pty { + tx: tokio::sync::mpsc::Sender<Bytes>, + + pub master: Arc<Mutex<Box<dyn MasterPty + Send>>>, + pub reader: Arc<Mutex<Box<dyn std::io::Read + Send>>>, +} + +impl Pty { + pub async fn open<'a>(rows: u16, cols: u16) -> Result<Self> { + let sys = portable_pty::native_pty_system(); + + let pair = sys + .openpty(PtySize { + rows, + cols, + pixel_width: 0, + pixel_height: 0, + }) + .map_err(|e| eyre!("Failed to open pty: {}", e))?; + + let cmd = CommandBuilder::new_default_prog(); + + tokio::task::spawn_blocking(move || { + let mut child = pair.slave.spawn_command(cmd).unwrap(); + // Wait for the child to exit + let _ = child.wait().unwrap(); + + // Ensure slave is dropped + // This closes file handles, we can deadlock if this is not done correctly. + drop(pair.slave); + }); + + // Handle input -> write to master writer + let (master_tx, mut master_rx) = tokio::sync::mpsc::channel::<Bytes>(32); + + let mut writer = pair.master.take_writer().unwrap(); + let reader = pair + .master + .try_clone_reader() + .map_err(|e| e.to_string()) + .expect("Failed to clone reader"); + + tokio::spawn(async move { + while let Some(bytes) = master_rx.recv().await { + writer.write_all(&bytes).unwrap(); + writer.flush().unwrap(); + } + + // When the channel has been closed, we won't be getting any more input. Close the + // writer and the master. + // This will also close the writer, which sends EOF to the underlying shell. Ensuring + // that is also closed. + drop(writer); + }); + + Ok(Pty { + tx: master_tx, + master: Arc::new(Mutex::new(pair.master)), + reader: Arc::new(Mutex::new(reader)), + }) + } + + pub async fn resize(&self, rows: u16, cols: u16) -> Result<()> { + let master = self + .master + .lock() + .map_err(|e| eyre!("Failed to lock pty master: {e}"))?; + + master + .resize(PtySize { + rows, + cols, + pixel_width: 0, + pixel_height: 0, + }) + .map_err(|e| eyre!("Failed to resize terminal: {e}"))?; + + Ok(()) + } + + pub async fn send_bytes(&self, bytes: Bytes) -> Result<()> { + self.tx + .send(bytes) + .await + .map_err(|e| eyre!("Failed to write to master tx: {}", e)) + } + + pub async fn send_string(&self, cmd: &str) -> Result<()> { + let bytes: Vec<u8> = cmd.bytes().collect(); + let bytes = Bytes::from(bytes); + + self.send_bytes(bytes).await + } + + pub async fn send_single_string(&self, cmd: &str) -> Result<()> { + let mut bytes: Vec<u8> = cmd.bytes().collect(); + bytes.push(0x04); + + let bytes = Bytes::from(bytes); + + self.send_bytes(bytes).await + } +} diff --git a/ui/backend/src/run/mod.rs b/ui/backend/src/run/mod.rs new file mode 100644 index 00000000..5ece0912 --- /dev/null +++ b/ui/backend/src/run/mod.rs @@ -0,0 +1 @@ +pub mod pty; diff --git a/ui/backend/src/run/pty.rs b/ui/backend/src/run/pty.rs new file mode 100644 index 00000000..382b45dd --- /dev/null +++ b/ui/backend/src/run/pty.rs @@ -0,0 +1,93 @@ +use eyre::{Result, WrapErr}; +use std::io::BufRead; +use std::path::PathBuf; + +use crate::state::AtuinState; +use tauri::{Manager, State}; + +use atuin_client::{database::Sqlite, record::sqlite_store::SqliteStore, settings::Settings}; + +#[tauri::command] +pub async fn pty_open<'a>( + app: tauri::AppHandle, + state: State<'a, AtuinState>, +) -> Result<uuid::Uuid, String> { + let id = uuid::Uuid::new_v4(); + let pty = crate::pty::Pty::open(24, 80).await.unwrap(); + + let reader = pty.reader.clone(); + + tauri::async_runtime::spawn_blocking(move || loop { + let mut buf = [0u8; 512]; + + match reader.lock().unwrap().read(&mut buf) { + // EOF + Ok(0) => { + println!("reader loop hit eof"); + break; + } + + Ok(n) => { + println!("read {n} bytes"); + + // TODO: sort inevitable encoding issues + let out = String::from_utf8_lossy(&buf).to_string(); + let out = out.trim_matches(char::from(0)); + let channel = format!("pty-{id}"); + + app.emit(channel.as_str(), out).unwrap(); + } + + Err(e) => { + println!("failed to read: {e}"); + break; + } + } + }); + + state.pty_sessions.write().await.insert(id, pty); + + Ok(id) +} + +#[tauri::command] +pub(crate) async fn pty_write( + pid: uuid::Uuid, + data: String, + state: tauri::State<'_, AtuinState>, +) -> Result<(), String> { + let sessions = state.pty_sessions.read().await; + let pty = sessions.get(&pid).ok_or("Pty not found")?; + + let bytes = data.as_bytes().to_vec(); + pty.send_bytes(bytes.into()) + .await + .map_err(|e| e.to_string())?; + Ok(()) +} + +#[tauri::command] +pub(crate) async fn pty_resize( + pid: uuid::Uuid, + rows: u16, + cols: u16, + state: tauri::State<'_, AtuinState>, +) -> Result<(), String> { + let sessions = state.pty_sessions.read().await; + let pty = sessions.get(&pid).ok_or("Pty not found")?; + + pty.resize(rows, cols).await.map_err(|e| e.to_string())?; + + Ok(()) +} + +#[tauri::command] +pub(crate) async fn pty_kill( + pid: uuid::Uuid, + state: tauri::State<'_, AtuinState>, +) -> Result<(), String> { + let pty = state.pty_sessions.write().await.remove(&pid).unwrap(); + println!("RIP {pid:?}"); + + Ok(()) +} diff --git a/ui/backend/src/state.rs b/ui/backend/src/state.rs new file mode 100644 index 00000000..de53b4c5 --- /dev/null +++ b/ui/backend/src/state.rs @@ -0,0 +1,10 @@ +use std::collections::HashMap; +use std::sync::Mutex; +use tauri::async_runtime::RwLock; + +use crate::pty::Pty; + +#[derive(Default)] +pub(crate) struct AtuinState { + pub pty_sessions: RwLock<HashMap<uuid::Uuid, Pty>>, +} |
