mirror of
https://github.com/wez/wezterm.git
synced 2024-11-23 15:04:36 +03:00
pty: remove conpty support
It's too fiddly to setup in practice, and literally no one has expressed an interest in using it. Removing it simplifies some upcoming work. Closes: https://github.com/wez/wezterm/issues/35
This commit is contained in:
parent
ec082bec31
commit
82c824f371
@ -2,7 +2,7 @@
|
||||
//! to print your username. It is made more complex because there are multiple
|
||||
//! pipes involved and it is easy to get blocked/deadlocked if care and attention
|
||||
//! is not paid to those pipes!
|
||||
use portable_pty::{CommandBuilder, PtySize, PtySystemSelection};
|
||||
use portable_pty::{CommandBuilder, NativePtySystem, PtySize, PtySystem};
|
||||
|
||||
// Read all available data until we reach EOF or encounter an error
|
||||
// condition. Only returns an error if we didn't receive any data.
|
||||
@ -22,7 +22,7 @@ fn read_until_eof_or_error<R: std::io::Read>(mut r: R) -> std::io::Result<Vec<u8
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let pty_system = PtySystemSelection::default().get().unwrap();
|
||||
let pty_system = NativePtySystem::default();
|
||||
|
||||
let pair = pty_system
|
||||
.openpty(PtySize {
|
||||
|
@ -2,15 +2,15 @@
|
||||
//! psuedo terminal (pty) interfaces provided by the system.
|
||||
//! Unlike other crates in this space, this crate provides a set
|
||||
//! of traits that allow selecting from different implementations
|
||||
//! at runtime, which is important on Windows systems.
|
||||
//! at runtime.
|
||||
//! This crate is part of [wezterm](https://github.com/wez/wezterm).
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use portable_pty::{CommandBuilder, PtySize, PtySystemSelection};
|
||||
//! use portable_pty::{CommandBuilder, PtySize, native_pty_system, PtySystem};
|
||||
//! use anyhow::Error;
|
||||
//!
|
||||
//! // Use the native pty implementation for the system
|
||||
//! let pty_system = PtySystemSelection::default().get()?;
|
||||
//! let pty_system = native_pty_system();
|
||||
//!
|
||||
//! // Create a new pty
|
||||
//! let mut pair = pty_system.openpty(PtySize {
|
||||
@ -43,7 +43,7 @@
|
||||
//! `ssh::SshSession` type that can wrap an established ssh
|
||||
//! session with an implementation of `PtySystem`, allowing
|
||||
//! you to use the same pty interface with remote ptys.
|
||||
use anyhow::{anyhow, bail, Error};
|
||||
use anyhow::Error;
|
||||
#[cfg(feature = "serde_support")]
|
||||
use serde_derive::*;
|
||||
use std::io::Result as IoResult;
|
||||
@ -186,79 +186,11 @@ impl Child for std::process::Child {
|
||||
}
|
||||
}
|
||||
|
||||
/// `PtySystemSelection` allows selecting and constructing one of the
|
||||
/// pty implementations provided by this crate.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "serde_support", derive(Deserialize))]
|
||||
pub enum PtySystemSelection {
|
||||
/// The Unix style pty interface
|
||||
Unix,
|
||||
/// The Windows 10+ native Console Pty interface
|
||||
ConPty,
|
||||
/// rprichard's WinPty interface to cygwin and msys pty.
|
||||
/// This requires that `winpty.dll` be resolvable by the
|
||||
/// embedding application. Instructions on obtaining
|
||||
/// an appropriate implementation of `winpty.dll` can be
|
||||
/// found here:
|
||||
/// [winpty](https://github.com/rprichard/winpty)
|
||||
WinPty,
|
||||
pub fn native_pty_system() -> Box<dyn PtySystem> {
|
||||
Box::new(NativePtySystem::default())
|
||||
}
|
||||
|
||||
impl PtySystemSelection {
|
||||
/// Construct an instance of PtySystem described by the enum value.
|
||||
/// Windows specific enum variants result in an error.
|
||||
#[cfg(unix)]
|
||||
pub fn get(self) -> anyhow::Result<Box<dyn PtySystem>> {
|
||||
match self {
|
||||
PtySystemSelection::Unix => Ok(Box::new(unix::UnixPtySystem {})),
|
||||
_ => bail!("{:?} not available on unix", self),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an instance of PtySystem described by the enum value.
|
||||
/// Unix specific enum variants result in an error.
|
||||
#[cfg(windows)]
|
||||
pub fn get(&self) -> anyhow::Result<Box<dyn PtySystem>> {
|
||||
match self {
|
||||
PtySystemSelection::ConPty => Ok(Box::new(win::conpty::ConPtySystem {})),
|
||||
PtySystemSelection::WinPty => Ok(Box::new(win::winpty::WinPtySystem {})),
|
||||
_ => bail!("{:?} not available on Windows", self),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a list of the variant names.
|
||||
/// This can be useful for example to specify the list of allowable
|
||||
/// options in a clap argument specification.
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["Unix", "ConPty", "WinPty"]
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a string into a `PtySystemSelection` value.
|
||||
/// This is useful when parsing arguments or configuration files.
|
||||
impl std::str::FromStr for PtySystemSelection {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_ref() {
|
||||
"unix" => Ok(PtySystemSelection::Unix),
|
||||
"winpty" => Ok(PtySystemSelection::WinPty),
|
||||
"conpty" => Ok(PtySystemSelection::ConPty),
|
||||
_ => Err(anyhow!(
|
||||
"{} is not a valid PtySystemSelection variant, possible values are {:?}",
|
||||
s,
|
||||
PtySystemSelection::variants()
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PtySystemSelection {
|
||||
/// Returns the default, system native PtySystemSelection
|
||||
fn default() -> PtySystemSelection {
|
||||
#[cfg(unix)]
|
||||
return PtySystemSelection::Unix;
|
||||
#[cfg(windows)]
|
||||
return PtySystemSelection::ConPty;
|
||||
}
|
||||
}
|
||||
#[cfg(unix)]
|
||||
pub type NativePtySystem = unix::UnixPtySystem;
|
||||
#[cfg(windows)]
|
||||
pub type NativePtySystem = win::conpty::UnixPtySystem;
|
||||
|
@ -11,7 +11,9 @@ use std::os::unix::process::CommandExt;
|
||||
use std::process::Stdio;
|
||||
use std::ptr;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UnixPtySystem {}
|
||||
|
||||
impl PtySystem for UnixPtySystem {
|
||||
fn openpty(&self, size: PtySize) -> anyhow::Result<PtyPair> {
|
||||
let mut master: RawFd = -1;
|
||||
|
@ -24,7 +24,9 @@ use winapi::um::wincon::COORD;
|
||||
|
||||
const PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE: usize = 0x00020016;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ConPtySystem {}
|
||||
|
||||
impl PtySystem for ConPtySystem {
|
||||
fn openpty(&self, size: PtySize) -> anyhow::Result<PtyPair> {
|
||||
let stdin = Pipe::new()?;
|
||||
|
@ -8,7 +8,6 @@ use winapi::um::synchapi::WaitForSingleObject;
|
||||
use winapi::um::winbase::INFINITE;
|
||||
|
||||
pub mod conpty;
|
||||
pub mod winpty;
|
||||
|
||||
use filedescriptor::OwnedHandle;
|
||||
|
||||
|
@ -1,123 +0,0 @@
|
||||
use super::WinChild;
|
||||
use crate::cmdbuilder::CommandBuilder;
|
||||
use crate::win::winpty::safe::{
|
||||
AgentFlags, MouseMode, SpawnConfig, SpawnFlags, Timeout, WinPty, WinPtyConfig,
|
||||
};
|
||||
use crate::{Child, MasterPty, PtyPair, PtySize, PtySystem, SlavePty};
|
||||
use anyhow::bail;
|
||||
use filedescriptor::FileDescriptor;
|
||||
use log::debug;
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
mod safe;
|
||||
mod sys;
|
||||
|
||||
struct Inner {
|
||||
pty: WinPty,
|
||||
size: PtySize,
|
||||
reader: FileDescriptor,
|
||||
writer: FileDescriptor,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WinPtyMasterPty {
|
||||
inner: Arc<Mutex<Inner>>,
|
||||
}
|
||||
|
||||
pub struct WinPtySlavePty {
|
||||
inner: Arc<Mutex<Inner>>,
|
||||
}
|
||||
|
||||
impl MasterPty for WinPtyMasterPty {
|
||||
fn resize(&self, size: PtySize) -> anyhow::Result<()> {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
if inner.pty.set_size(size.cols as i32, size.rows as i32)? {
|
||||
inner.size = size;
|
||||
Ok(())
|
||||
} else {
|
||||
bail!("WinPtyMasterPty::resize returned false");
|
||||
}
|
||||
}
|
||||
|
||||
fn get_size(&self) -> anyhow::Result<PtySize> {
|
||||
Ok(self.inner.lock().unwrap().size)
|
||||
}
|
||||
|
||||
fn try_clone_reader(&self) -> anyhow::Result<Box<dyn std::io::Read + Send>> {
|
||||
Ok(Box::new(self.inner.lock().unwrap().reader.try_clone()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::io::Write for WinPtyMasterPty {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
|
||||
self.inner.lock().unwrap().writer.write(buf)
|
||||
}
|
||||
fn flush(&mut self) -> Result<(), std::io::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SlavePty for WinPtySlavePty {
|
||||
fn spawn_command(&self, cmd: CommandBuilder) -> anyhow::Result<Box<dyn Child>> {
|
||||
let (exe, cmdline) = cmd.cmdline()?;
|
||||
let cmd_os = OsString::from_wide(&cmdline);
|
||||
debug!(
|
||||
"Running: module: {} {:?}",
|
||||
Path::new(&OsString::from_wide(&exe)).display(),
|
||||
cmd_os
|
||||
);
|
||||
|
||||
let spawn_config = SpawnConfig::new(
|
||||
SpawnFlags::AUTO_SHUTDOWN | SpawnFlags::EXIT_AFTER_SHUTDOWN,
|
||||
Some(exe),
|
||||
Some(cmdline),
|
||||
None, // cwd
|
||||
None, // env
|
||||
)?;
|
||||
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
let spawned = inner.pty.spawn(&spawn_config)?;
|
||||
|
||||
let child = WinChild {
|
||||
proc: spawned.process_handle,
|
||||
};
|
||||
|
||||
Ok(Box::new(child))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WinPtySystem {}
|
||||
impl PtySystem for WinPtySystem {
|
||||
fn openpty(&self, size: PtySize) -> anyhow::Result<PtyPair> {
|
||||
let mut config = WinPtyConfig::new(AgentFlags::empty())?;
|
||||
|
||||
config.set_initial_size(size.cols as i32, size.rows as i32);
|
||||
config.set_mouse_mode(MouseMode::Auto);
|
||||
config.set_agent_timeout(Timeout::Milliseconds(10_000));
|
||||
|
||||
let pty = config.open()?;
|
||||
|
||||
let reader = pty.conout()?;
|
||||
let writer = pty.conin()?;
|
||||
|
||||
let inner = Arc::new(Mutex::new(Inner {
|
||||
pty,
|
||||
reader,
|
||||
writer,
|
||||
size,
|
||||
}));
|
||||
|
||||
let master = WinPtyMasterPty {
|
||||
inner: Arc::clone(&inner),
|
||||
};
|
||||
let slave = WinPtySlavePty { inner };
|
||||
|
||||
Ok(PtyPair {
|
||||
master: Box::new(master),
|
||||
slave: Box::new(slave),
|
||||
})
|
||||
}
|
||||
}
|
@ -1,280 +0,0 @@
|
||||
//! A type-safe wrapper around the sys module, which in turn exposes
|
||||
//! the API exported by winpty.dll.
|
||||
//! https://github.com/rprichard/winpty/blob/master/src/include/winpty.h
|
||||
#![allow(dead_code)]
|
||||
use super::sys::*;
|
||||
use anyhow::{anyhow, bail, ensure, Error};
|
||||
use bitflags::bitflags;
|
||||
use filedescriptor::{FileDescriptor, OwnedHandle};
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
use std::os::windows::io::FromRawHandle;
|
||||
use std::ptr;
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::shared::ntdef::LPCWSTR;
|
||||
use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
|
||||
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
|
||||
use winapi::um::winbase::INFINITE;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
use winapi::um::winnt::{GENERIC_READ, GENERIC_WRITE};
|
||||
|
||||
bitflags! {
|
||||
pub struct AgentFlags : u64 {
|
||||
const CONERR = WINPTY_FLAG_CONERR;
|
||||
const PLAIN_OUTPUT = WINPTY_FLAG_PLAIN_OUTPUT;
|
||||
const COLOR_ESCAPES = WINPTY_FLAG_COLOR_ESCAPES;
|
||||
const ALLOW_DESKTOP_CREATE = WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION;
|
||||
}
|
||||
}
|
||||
bitflags! {
|
||||
pub struct SpawnFlags : u64 {
|
||||
const AUTO_SHUTDOWN = WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN;
|
||||
const EXIT_AFTER_SHUTDOWN = WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
pub enum MouseMode {
|
||||
None = WINPTY_MOUSE_MODE_NONE,
|
||||
Auto = WINPTY_MOUSE_MODE_AUTO,
|
||||
Force = WINPTY_MOUSE_MODE_FORCE,
|
||||
}
|
||||
|
||||
pub enum Timeout {
|
||||
Infinite,
|
||||
Milliseconds(DWORD),
|
||||
}
|
||||
|
||||
pub struct WinPtyConfig {
|
||||
config: *mut winpty_config_t,
|
||||
}
|
||||
|
||||
fn wstr_to_osstr(wstr: LPCWSTR) -> Result<OsString, Error> {
|
||||
ensure!(!wstr.is_null(), "LPCWSTR is null");
|
||||
let slice = unsafe { std::slice::from_raw_parts(wstr, libc::wcslen(wstr)) };
|
||||
Ok(OsString::from_wide(slice))
|
||||
}
|
||||
|
||||
fn wstr_to_string(wstr: LPCWSTR) -> Result<String, Error> {
|
||||
ensure!(!wstr.is_null(), "LPCWSTR is null");
|
||||
let slice = unsafe { std::slice::from_raw_parts(wstr, libc::wcslen(wstr)) };
|
||||
String::from_utf16(slice).map_err(|e| anyhow!("String::from_utf16: {}", e))
|
||||
}
|
||||
|
||||
fn check_err<T>(err: winpty_error_ptr_t, value: T) -> Result<T, Error> {
|
||||
if err.is_null() {
|
||||
return Ok(value);
|
||||
}
|
||||
unsafe {
|
||||
let code = (WINPTY.winpty_error_code)(err);
|
||||
if code == WINPTY_ERROR_SUCCESS {
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
let converted = wstr_to_string((WINPTY.winpty_error_msg)(err))?;
|
||||
(WINPTY.winpty_error_free)(err);
|
||||
bail!("winpty error code {}: {}", code, converted)
|
||||
}
|
||||
}
|
||||
|
||||
impl WinPtyConfig {
|
||||
pub fn new(flags: AgentFlags) -> Result<Self, Error> {
|
||||
let mut err: winpty_error_ptr_t = ptr::null_mut();
|
||||
let config = unsafe { (WINPTY.winpty_config_new)(flags.bits(), &mut err) };
|
||||
let config = check_err(err, config)?;
|
||||
ensure!(
|
||||
!config.is_null(),
|
||||
"winpty_config_new returned nullptr but no error"
|
||||
);
|
||||
Ok(Self { config })
|
||||
}
|
||||
|
||||
pub fn set_initial_size(&mut self, cols: c_int, rows: c_int) {
|
||||
unsafe { (WINPTY.winpty_config_set_initial_size)(self.config, cols, rows) }
|
||||
}
|
||||
|
||||
pub fn set_mouse_mode(&mut self, mode: MouseMode) {
|
||||
unsafe { (WINPTY.winpty_config_set_mouse_mode)(self.config, mode as c_int) }
|
||||
}
|
||||
|
||||
pub fn set_agent_timeout(&mut self, timeout: Timeout) {
|
||||
let duration = match timeout {
|
||||
Timeout::Infinite => INFINITE,
|
||||
Timeout::Milliseconds(n) => n,
|
||||
};
|
||||
unsafe { (WINPTY.winpty_config_set_agent_timeout)(self.config, duration) }
|
||||
}
|
||||
|
||||
pub fn open(&self) -> Result<WinPty, Error> {
|
||||
let mut err: winpty_error_ptr_t = ptr::null_mut();
|
||||
let pty = unsafe { (WINPTY.winpty_open)(self.config, &mut err) };
|
||||
let pty = check_err(err, pty)?;
|
||||
ensure!(!pty.is_null(), "winpty_open returned nullptr but no error");
|
||||
Ok(WinPty { pty })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WinPtyConfig {
|
||||
fn drop(&mut self) {
|
||||
unsafe { (WINPTY.winpty_config_free)(self.config) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WinPty {
|
||||
pty: *mut winpty_t,
|
||||
}
|
||||
|
||||
impl Drop for WinPty {
|
||||
fn drop(&mut self) {
|
||||
unsafe { (WINPTY.winpty_free)(self.pty) }
|
||||
}
|
||||
}
|
||||
|
||||
fn pipe_client(name: LPCWSTR, for_read: bool) -> Result<FileDescriptor, Error> {
|
||||
let handle = unsafe {
|
||||
CreateFileW(
|
||||
name,
|
||||
if for_read {
|
||||
GENERIC_READ
|
||||
} else {
|
||||
GENERIC_WRITE
|
||||
},
|
||||
0,
|
||||
ptr::null_mut(),
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
if handle == INVALID_HANDLE_VALUE {
|
||||
let err = std::io::Error::last_os_error();
|
||||
bail!("failed to open {:?}: {}", wstr_to_string(name), err);
|
||||
} else {
|
||||
Ok(unsafe { FileDescriptor::from_raw_handle(handle) })
|
||||
}
|
||||
}
|
||||
|
||||
impl WinPty {
|
||||
pub fn agent_process(&self) -> HANDLE {
|
||||
unsafe { (WINPTY.winpty_agent_process)(self.pty) }
|
||||
}
|
||||
|
||||
pub fn conin(&self) -> Result<FileDescriptor, Error> {
|
||||
pipe_client(unsafe { (WINPTY.winpty_conin_name)(self.pty) }, false)
|
||||
}
|
||||
|
||||
pub fn conout(&self) -> Result<FileDescriptor, Error> {
|
||||
pipe_client(unsafe { (WINPTY.winpty_conout_name)(self.pty) }, true)
|
||||
}
|
||||
|
||||
pub fn conerr(&self) -> Result<FileDescriptor, Error> {
|
||||
pipe_client(unsafe { (WINPTY.winpty_conerr_name)(self.pty) }, true)
|
||||
}
|
||||
|
||||
pub fn set_size(&mut self, cols: c_int, rows: c_int) -> Result<bool, Error> {
|
||||
let mut err: winpty_error_ptr_t = ptr::null_mut();
|
||||
let result = unsafe { (WINPTY.winpty_set_size)(self.pty, cols, rows, &mut err) };
|
||||
Ok(result != 0)
|
||||
}
|
||||
|
||||
pub fn spawn(&mut self, config: &SpawnConfig) -> Result<SpawnedProcess, Error> {
|
||||
let mut err: winpty_error_ptr_t = ptr::null_mut();
|
||||
let mut create_process_error: DWORD = 0;
|
||||
let mut process_handle: HANDLE = ptr::null_mut();
|
||||
let mut thread_handle: HANDLE = ptr::null_mut();
|
||||
|
||||
let result = unsafe {
|
||||
(WINPTY.winpty_spawn)(
|
||||
self.pty,
|
||||
config.spawn_config,
|
||||
&mut process_handle,
|
||||
&mut thread_handle,
|
||||
&mut create_process_error,
|
||||
&mut err,
|
||||
)
|
||||
};
|
||||
let thread_handle = unsafe { OwnedHandle::from_raw_handle(thread_handle) };
|
||||
let process_handle = unsafe { OwnedHandle::from_raw_handle(process_handle) };
|
||||
let result = check_err(err, result)?;
|
||||
if result == 0 {
|
||||
let err = std::io::Error::from_raw_os_error(create_process_error as _);
|
||||
bail!("winpty_spawn failed: {}", err);
|
||||
}
|
||||
Ok(SpawnedProcess {
|
||||
thread_handle,
|
||||
process_handle,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SpawnedProcess {
|
||||
pub process_handle: OwnedHandle,
|
||||
pub thread_handle: OwnedHandle,
|
||||
}
|
||||
|
||||
pub struct SpawnConfig {
|
||||
spawn_config: *mut winpty_spawn_config_t,
|
||||
}
|
||||
|
||||
/// Construct a null terminated wide string from an OsStr
|
||||
fn str_to_wide(s: &OsStr) -> Vec<u16> {
|
||||
let mut wide: Vec<u16> = s.encode_wide().collect();
|
||||
wide.push(0);
|
||||
wide
|
||||
}
|
||||
|
||||
fn str_ptr(s: &Option<Vec<u16>>) -> LPCWSTR {
|
||||
match s {
|
||||
None => ptr::null(),
|
||||
Some(v) => v.as_ptr(),
|
||||
}
|
||||
}
|
||||
|
||||
impl SpawnConfig {
|
||||
pub fn with_os_str_args(
|
||||
flags: SpawnFlags,
|
||||
appname: Option<&OsStr>,
|
||||
cmdline: Option<&OsStr>,
|
||||
cwd: Option<&OsStr>,
|
||||
env: Option<&OsStr>,
|
||||
) -> Result<Self, Error> {
|
||||
let appname = appname.map(str_to_wide);
|
||||
let cmdline = cmdline.map(str_to_wide);
|
||||
let cwd = cwd.map(str_to_wide);
|
||||
let env = env.map(str_to_wide);
|
||||
Self::new(flags, appname, cmdline, cwd, env)
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
flags: SpawnFlags,
|
||||
appname: Option<Vec<u16>>,
|
||||
cmdline: Option<Vec<u16>>,
|
||||
cwd: Option<Vec<u16>>,
|
||||
env: Option<Vec<u16>>,
|
||||
) -> Result<Self, Error> {
|
||||
let mut err: winpty_error_ptr_t = ptr::null_mut();
|
||||
|
||||
let spawn_config = unsafe {
|
||||
(WINPTY.winpty_spawn_config_new)(
|
||||
flags.bits(),
|
||||
str_ptr(&appname),
|
||||
str_ptr(&cmdline),
|
||||
str_ptr(&cwd),
|
||||
str_ptr(&env),
|
||||
&mut err,
|
||||
)
|
||||
};
|
||||
let spawn_config = check_err(err, spawn_config)?;
|
||||
ensure!(
|
||||
!spawn_config.is_null(),
|
||||
"winpty_spawn_config_new returned nullptr but no error"
|
||||
);
|
||||
Ok(Self { spawn_config })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SpawnConfig {
|
||||
fn drop(&mut self) {
|
||||
unsafe { (WINPTY.winpty_spawn_config_free)(self.spawn_config) }
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
//! A rust wrapper around winpty.dll
|
||||
//! https://github.com/rprichard/winpty/blob/master/src/include/winpty.h
|
||||
//! This was partially generated by bindgen and then tweaked to work
|
||||
//! with the shared_library macro.
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use shared_library::shared_library;
|
||||
use std::path::Path;
|
||||
use winapi::shared::minwindef::{BOOL, DWORD};
|
||||
use winapi::shared::ntdef::LPCWSTR;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
pub use ::std::os::raw::c_int;
|
||||
|
||||
pub const WINPTY_ERROR_SUCCESS: u32 = 0;
|
||||
pub const WINPTY_ERROR_OUT_OF_MEMORY: u32 = 1;
|
||||
pub const WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED: u32 = 2;
|
||||
pub const WINPTY_ERROR_LOST_CONNECTION: u32 = 3;
|
||||
pub const WINPTY_ERROR_AGENT_EXE_MISSING: u32 = 4;
|
||||
pub const WINPTY_ERROR_UNSPECIFIED: u32 = 5;
|
||||
pub const WINPTY_ERROR_AGENT_DIED: u32 = 6;
|
||||
pub const WINPTY_ERROR_AGENT_TIMEOUT: u32 = 7;
|
||||
pub const WINPTY_ERROR_AGENT_CREATION_FAILED: u32 = 8;
|
||||
pub const WINPTY_FLAG_CONERR: u64 = 1;
|
||||
pub const WINPTY_FLAG_PLAIN_OUTPUT: u64 = 2;
|
||||
pub const WINPTY_FLAG_COLOR_ESCAPES: u64 = 4;
|
||||
pub const WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION: u64 = 8;
|
||||
pub const WINPTY_MOUSE_MODE_NONE: u32 = 0;
|
||||
pub const WINPTY_MOUSE_MODE_AUTO: u32 = 1;
|
||||
pub const WINPTY_MOUSE_MODE_FORCE: u32 = 2;
|
||||
pub const WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN: u64 = 1;
|
||||
pub const WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN: u64 = 2;
|
||||
|
||||
pub struct winpty_error_t {}
|
||||
pub struct winpty_t {}
|
||||
pub struct winpty_spawn_config_t {}
|
||||
pub struct winpty_config_t {}
|
||||
|
||||
pub type winpty_error_ptr_t = *mut winpty_error_t;
|
||||
pub type winpty_result_t = DWORD;
|
||||
|
||||
shared_library!(WinPtyFuncs,
|
||||
pub fn winpty_error_code(err: winpty_error_ptr_t) -> winpty_result_t,
|
||||
pub fn winpty_error_msg(err: winpty_error_ptr_t) -> LPCWSTR,
|
||||
pub fn winpty_error_free(err: winpty_error_ptr_t),
|
||||
pub fn winpty_config_new(
|
||||
agentFlags: u64,
|
||||
err: *mut winpty_error_ptr_t
|
||||
) -> *mut winpty_config_t,
|
||||
pub fn winpty_config_free(cfg: *mut winpty_config_t),
|
||||
pub fn winpty_config_set_initial_size(
|
||||
cfg: *mut winpty_config_t,
|
||||
cols: c_int,
|
||||
rows: c_int
|
||||
),
|
||||
pub fn winpty_config_set_mouse_mode(
|
||||
cfg: *mut winpty_config_t,
|
||||
mouseMode: c_int
|
||||
),
|
||||
pub fn winpty_config_set_agent_timeout(
|
||||
cfg: *mut winpty_config_t,
|
||||
timeoutMs: DWORD
|
||||
),
|
||||
pub fn winpty_open(cfg: *const winpty_config_t, err: *mut winpty_error_ptr_t) -> *mut winpty_t,
|
||||
pub fn winpty_agent_process(wp: *mut winpty_t) -> HANDLE,
|
||||
pub fn winpty_conin_name(wp: *mut winpty_t) -> LPCWSTR,
|
||||
pub fn winpty_conout_name(wp: *mut winpty_t) -> LPCWSTR,
|
||||
pub fn winpty_conerr_name(wp: *mut winpty_t) -> LPCWSTR,
|
||||
pub fn winpty_spawn_config_new(
|
||||
spawnFlags: u64,
|
||||
appname: LPCWSTR,
|
||||
cmdline: LPCWSTR,
|
||||
cwd: LPCWSTR,
|
||||
env: LPCWSTR,
|
||||
err: *mut winpty_error_ptr_t
|
||||
) -> *mut winpty_spawn_config_t,
|
||||
pub fn winpty_spawn_config_free(cfg: *mut winpty_spawn_config_t),
|
||||
pub fn winpty_spawn(
|
||||
wp: *mut winpty_t,
|
||||
cfg: *const winpty_spawn_config_t,
|
||||
process_handle: *mut HANDLE,
|
||||
thread_handle: *mut HANDLE,
|
||||
create_process_error: *mut DWORD,
|
||||
err: *mut winpty_error_ptr_t
|
||||
) -> BOOL,
|
||||
pub fn winpty_set_size(
|
||||
wp: *mut winpty_t,
|
||||
cols: c_int,
|
||||
rows: c_int,
|
||||
err: *mut winpty_error_ptr_t
|
||||
) -> BOOL,
|
||||
/*
|
||||
pub fn winpty_get_console_process_list(
|
||||
wp: *mut winpty_t,
|
||||
processList: *mut c_int,
|
||||
processCount: c_int,
|
||||
err: *mut winpty_error_ptr_t
|
||||
) -> c_int,
|
||||
*/
|
||||
pub fn winpty_free(wp: *mut winpty_t),
|
||||
);
|
||||
|
||||
lazy_static! {
|
||||
pub static ref WINPTY: WinPtyFuncs =
|
||||
WinPtyFuncs::open(Path::new("winpty.dll")).expect("winpty.dll is required");
|
||||
}
|
@ -8,7 +8,7 @@ use crate::frontend::FrontEndSelection;
|
||||
use crate::keyassignment::KeyAssignment;
|
||||
use anyhow::{anyhow, bail, Context, Error};
|
||||
use lazy_static::lazy_static;
|
||||
use portable_pty::{CommandBuilder, PtySystemSelection};
|
||||
use portable_pty::CommandBuilder;
|
||||
use serde::Deserialize;
|
||||
use std;
|
||||
use std::collections::HashMap;
|
||||
@ -357,9 +357,6 @@ pub struct Config {
|
||||
#[serde(default)]
|
||||
pub front_end: FrontEndSelection,
|
||||
|
||||
#[serde(default)]
|
||||
pub pty: PtySystemSelection,
|
||||
|
||||
/// The set of unix domains
|
||||
#[serde(default = "UnixDomain::default_unix_domains")]
|
||||
pub unix_domains: Vec<UnixDomain>,
|
||||
|
@ -14,8 +14,7 @@ use anyhow::{bail, Error};
|
||||
use async_trait::async_trait;
|
||||
use downcast_rs::{impl_downcast, Downcast};
|
||||
use log::info;
|
||||
use portable_pty::cmdbuilder::CommandBuilder;
|
||||
use portable_pty::{PtySize, PtySystem};
|
||||
use portable_pty::{native_pty_system, CommandBuilder, PtySize, PtySystem};
|
||||
use std::rc::Rc;
|
||||
|
||||
static DOMAIN_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0);
|
||||
@ -68,8 +67,7 @@ pub struct LocalDomain {
|
||||
|
||||
impl LocalDomain {
|
||||
pub fn new(name: &str) -> Result<Self, Error> {
|
||||
let pty_system = configuration().pty.get()?;
|
||||
Ok(Self::with_pty_system(name, pty_system))
|
||||
Ok(Self::with_pty_system(name, native_pty_system()))
|
||||
}
|
||||
|
||||
pub fn with_pty_system(name: &str, pty_system: Box<dyn PtySystem>) -> Self {
|
||||
|
@ -12,6 +12,7 @@ use anyhow::{anyhow, bail, Context, Error};
|
||||
use crossbeam_channel::TryRecvError;
|
||||
use filedescriptor::{pollfd, AsRawSocketDescriptor};
|
||||
use log::info;
|
||||
use portable_pty::{CommandBuilder, NativePtySystem, PtySystem};
|
||||
use promise::{Future, Promise};
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Read, Write};
|
||||
@ -371,9 +372,9 @@ impl Reconnectable {
|
||||
// conhost.exe, `wsl.exe` will fail to start up correctly.
|
||||
// This also has a nice side effect of not flashing up a
|
||||
// console window when we first spin up the wsl instance.
|
||||
let pty_system = portable_pty::PtySystemSelection::default().get()?;
|
||||
let pty_system = NativePtySystem::default();
|
||||
let pair = pty_system.openpty(Default::default())?;
|
||||
let mut cmd = portable_pty::CommandBuilder::new(&argv[0]);
|
||||
let mut cmd = CommandBuilder::new(&argv[0]);
|
||||
cmd.args(&argv[1..]);
|
||||
let mut child = pair.slave.spawn_command(cmd)?;
|
||||
let status = child.wait()?;
|
||||
|
Loading…
Reference in New Issue
Block a user