mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 13:21:38 +03:00
pty: async example using smol
refs: https://github.com/wez/wezterm/issues/166
This commit is contained in:
parent
e2d044bb14
commit
2ef985aa18
188
Cargo.lock
generated
188
Cargo.lock
generated
@ -134,7 +134,7 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "538ecb01eb64eecd772087e5b6f7540cbc917f047727339a472dafed2185b267"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"async-task 1.3.1",
|
||||
"crossbeam-channel 0.4.2",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils 0.7.2",
|
||||
@ -163,6 +163,12 @@ dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.30"
|
||||
@ -1050,16 +1056,79 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.4"
|
||||
name = "futures"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
|
||||
checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6"
|
||||
checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.4",
|
||||
"syn 1.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
@ -1067,6 +1136,26 @@ version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
@ -2165,6 +2254,26 @@ dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82c3bfbfb5bb42f99498c7234bbd768c220eb0cea6818259d0d18a1aa3d2595d"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccbf6449dcfb18562c015526b085b8df1aa3cdab180af8ec2ebd300a3bd28f63"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12",
|
||||
"quote 1.0.4",
|
||||
"syn 1.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.1.4"
|
||||
@ -2177,6 +2286,16 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "piper"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6d62a6ea407d82215154475927b288219b79c8670e3371166210328e758ebaa"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.7.2",
|
||||
"futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.17"
|
||||
@ -2202,6 +2321,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 1.2.1",
|
||||
"filedescriptor",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
@ -2210,6 +2330,7 @@ dependencies = [
|
||||
"serial",
|
||||
"shared_library",
|
||||
"shell-words",
|
||||
"smol",
|
||||
"ssh2",
|
||||
"uds_windows",
|
||||
"winapi 0.3.8",
|
||||
@ -2286,6 +2407,12 @@ version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
@ -2310,7 +2437,7 @@ version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-std",
|
||||
"async-task",
|
||||
"async-task 1.3.1",
|
||||
"lazy_static",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
@ -2653,6 +2780,12 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls-hkt"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2e9d7eaddb227e8fbaaa71136ae0e1e913ca159b86c7da82f3e8f0044ad3a63"
|
||||
|
||||
[[package]]
|
||||
name = "scoped_threadpool"
|
||||
version = "0.1.9"
|
||||
@ -2876,6 +3009,24 @@ dependencies = [
|
||||
"wayland-protocols",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smol"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f92bf48a84965d40061dbd596c17cfe0bff734b5aaf94d9408b0b3e382f7c06e"
|
||||
dependencies = [
|
||||
"async-task 3.0.0",
|
||||
"crossbeam",
|
||||
"futures",
|
||||
"nix",
|
||||
"once_cell",
|
||||
"piper",
|
||||
"scoped-tls-hkt",
|
||||
"slab",
|
||||
"socket2",
|
||||
"wepoll-binding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.3.12"
|
||||
@ -3611,13 +3762,32 @@ dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wepoll-binding"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "720cc52662740f7097c7bbc15f7906e4d3f6e64e5ec70e84eb4690b70ce1afc5"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1",
|
||||
"wepoll-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wepoll-sys"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9082a777aed991f6769e2b654aa0cb29f1c3d615daf009829b07b66c7aff6a24"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wezterm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"allsorts",
|
||||
"anyhow",
|
||||
"async-task",
|
||||
"async-task 1.3.1",
|
||||
"async-trait",
|
||||
"base64 0.10.1",
|
||||
"base91",
|
||||
@ -3740,7 +3910,7 @@ name = "window"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-task",
|
||||
"async-task 1.3.1",
|
||||
"bitflags 1.2.1",
|
||||
"cgl",
|
||||
"clipboard",
|
||||
|
@ -37,3 +37,7 @@ winapi = { version = "0.3", features = [
|
||||
"namedpipeapi",
|
||||
"synchapi",
|
||||
]}
|
||||
|
||||
[dev-dependencies]
|
||||
smol = "0.1"
|
||||
futures = "0.3"
|
||||
|
60
pty/examples/whoami_async.rs
Normal file
60
pty/examples/whoami_async.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use anyhow::anyhow;
|
||||
use futures::prelude::*;
|
||||
use portable_pty::{native_pty_system, CommandBuilder, PtySize};
|
||||
|
||||
// This example shows how to use the `smol` crate to use portable_pty
|
||||
// in an asynchronous application.
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
smol::run(async {
|
||||
let pty_system = native_pty_system();
|
||||
|
||||
let pair = pty_system.openpty(PtySize {
|
||||
rows: 24,
|
||||
cols: 80,
|
||||
pixel_width: 0,
|
||||
pixel_height: 0,
|
||||
})?;
|
||||
|
||||
let cmd = CommandBuilder::new("whoami");
|
||||
|
||||
// Move the slave to another thread to block and spawn a
|
||||
// command.
|
||||
// Note that this implicitly drops slave and closes out
|
||||
// file handles which is important to avoid deadlock
|
||||
// when waiting for the child process!
|
||||
let slave = pair.slave;
|
||||
let mut child = smol::blocking!(slave.spawn_command(cmd))?;
|
||||
|
||||
let reader = pair.master.try_clone_reader()?;
|
||||
println!(
|
||||
"child status: {:?}",
|
||||
smol::blocking!(child
|
||||
.wait()
|
||||
.map_err(|e| anyhow!("waiting for child: {}", e)))?
|
||||
);
|
||||
|
||||
// We hold handles on the pty. Now that the child is complete
|
||||
// there are no processes remaining that will write to it until
|
||||
// we spawn more. We're not going to do that in this example,
|
||||
// so we should close it down. If we didn't drop it explicitly
|
||||
// here, then the attempt to read its output would block forever
|
||||
// waiting for a future child that will never be spawned.
|
||||
drop(pair.master);
|
||||
|
||||
let mut lines = futures::io::BufReader::new(smol::reader(reader)).lines();
|
||||
while let Some(line) = lines.next().await {
|
||||
let line = line.map_err(|e| anyhow!("problem reading line: {}", e))?;
|
||||
// We print with escapes escaped because the windows conpty
|
||||
// implementation synthesizes title change escape sequences
|
||||
// in the output stream and it can be confusing to see those
|
||||
// printed out raw in another terminal.
|
||||
print!("output: len={} ", line.len());
|
||||
for c in line.escape_debug() {
|
||||
print!("{}", c);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
@ -124,7 +124,7 @@ pub trait Child: std::fmt::Debug {
|
||||
/// Can be used to spawn processes into the pty.
|
||||
pub trait SlavePty {
|
||||
/// Spawns the command specified by the provided CommandBuilder
|
||||
fn spawn_command(&self, cmd: CommandBuilder) -> Result<Box<dyn Child>, Error>;
|
||||
fn spawn_command(&self, cmd: CommandBuilder) -> Result<Box<dyn Child + Send>, Error>;
|
||||
}
|
||||
|
||||
/// Represents the exit status of a child process.
|
||||
@ -159,8 +159,8 @@ impl From<std::process::ExitStatus> for ExitStatus {
|
||||
pub struct PtyPair {
|
||||
// slave is listed first so that it is dropped first.
|
||||
// The drop order is stable and specified by rust rfc 1857
|
||||
pub slave: Box<dyn SlavePty>,
|
||||
pub master: Box<dyn MasterPty>,
|
||||
pub slave: Box<dyn SlavePty + Send>,
|
||||
pub master: Box<dyn MasterPty + Send>,
|
||||
}
|
||||
|
||||
/// The `PtySystem` trait allows an application to work with multiple
|
||||
|
@ -99,7 +99,7 @@ struct Slave {
|
||||
}
|
||||
|
||||
impl SlavePty for Slave {
|
||||
fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child>> {
|
||||
fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child + Send>> {
|
||||
ensure!(
|
||||
cmd.is_default_prog(),
|
||||
"can only use default prog commands with serial tty implementations"
|
||||
|
@ -190,7 +190,7 @@ struct SshSlave {
|
||||
}
|
||||
|
||||
impl SlavePty for SshSlave {
|
||||
fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child>> {
|
||||
fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child + Send>> {
|
||||
self.pty.with_channel(|channel| {
|
||||
for (key, val) in cmd.iter_env_as_str() {
|
||||
channel
|
||||
@ -205,7 +205,7 @@ impl SlavePty for SshSlave {
|
||||
channel.exec(&command)?;
|
||||
}
|
||||
|
||||
let child: Box<dyn Child> = Box::new(SshChild {
|
||||
let child: Box<dyn Child + Send> = Box::new(SshChild {
|
||||
pty: self.pty.clone(),
|
||||
});
|
||||
|
||||
|
@ -225,7 +225,7 @@ fn cloexec(fd: RawFd) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
impl SlavePty for UnixSlavePty {
|
||||
fn spawn_command(&self, builder: CommandBuilder) -> Result<Box<dyn Child>, Error> {
|
||||
fn spawn_command(&self, builder: CommandBuilder) -> Result<Box<dyn Child + Send>, Error> {
|
||||
Ok(Box::new(self.fd.spawn_command(builder)?))
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ impl io::Write for ConPtyMasterPty {
|
||||
}
|
||||
|
||||
impl SlavePty for ConPtySlavePty {
|
||||
fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child>> {
|
||||
fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child + Send>> {
|
||||
let inner = self.inner.lock().unwrap();
|
||||
let child = inner.con.spawn_command(cmd)?;
|
||||
Ok(Box::new(child))
|
||||
|
Loading…
Reference in New Issue
Block a user