aboutsummaryrefslogtreecommitdiff
path: root/src/tty/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/tty/windows')
-rw-r--r--src/tty/windows/conpty.rs289
-rw-r--r--src/tty/windows/mod.rs303
-rw-r--r--src/tty/windows/winpty.rs169
3 files changed, 0 insertions, 761 deletions
diff --git a/src/tty/windows/conpty.rs b/src/tty/windows/conpty.rs
deleted file mode 100644
index f23d78a7..00000000
--- a/src/tty/windows/conpty.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use super::{Pty, HANDLE};
-
-use std::i16;
-use std::io::Error;
-use std::mem;
-use std::os::windows::io::IntoRawHandle;
-use std::ptr;
-use std::sync::Arc;
-
-use dunce::canonicalize;
-use mio_anonymous_pipes::{EventedAnonRead, EventedAnonWrite};
-use miow;
-use widestring::U16CString;
-use winapi::shared::basetsd::{PSIZE_T, SIZE_T};
-use winapi::shared::minwindef::{BYTE, DWORD};
-use winapi::shared::ntdef::{HANDLE, HRESULT, LPWSTR};
-use winapi::shared::winerror::S_OK;
-use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
-use winapi::um::processthreadsapi::{
- CreateProcessW, InitializeProcThreadAttributeList, UpdateProcThreadAttribute,
- PROCESS_INFORMATION, STARTUPINFOW,
-};
-use winapi::um::winbase::{EXTENDED_STARTUPINFO_PRESENT, STARTF_USESTDHANDLES, STARTUPINFOEXW};
-use winapi::um::wincontypes::{COORD, HPCON};
-
-use crate::cli::Options;
-use crate::config::{Config, Shell};
-use crate::display::OnResize;
-use crate::term::SizeInfo;
-
-/// Dynamically-loaded Pseudoconsole API from kernel32.dll
-///
-/// The field names are deliberately PascalCase as this matches
-/// the defined symbols in kernel32 and also is the convention
-/// that the `winapi` crate follows.
-#[allow(non_snake_case)]
-struct ConptyApi {
- CreatePseudoConsole:
- unsafe extern "system" fn(COORD, HANDLE, HANDLE, DWORD, *mut HPCON) -> HRESULT,
- ResizePseudoConsole: unsafe extern "system" fn(HPCON, COORD) -> HRESULT,
- ClosePseudoConsole: unsafe extern "system" fn(HPCON),
-}
-
-impl ConptyApi {
- /// Load the API or None if it cannot be found.
- pub fn new() -> Option<Self> {
- // Unsafe because windows API calls
- unsafe {
- let hmodule = GetModuleHandleA("kernel32\0".as_ptr() as _);
- assert!(!hmodule.is_null());
-
- let cpc = GetProcAddress(hmodule, "CreatePseudoConsole\0".as_ptr() as _);
- let rpc = GetProcAddress(hmodule, "ResizePseudoConsole\0".as_ptr() as _);
- let clpc = GetProcAddress(hmodule, "ClosePseudoConsole\0".as_ptr() as _);
-
- if cpc.is_null() || rpc.is_null() || clpc.is_null() {
- None
- } else {
- Some(Self {
- CreatePseudoConsole: mem::transmute(cpc),
- ResizePseudoConsole: mem::transmute(rpc),
- ClosePseudoConsole: mem::transmute(clpc),
- })
- }
- }
- }
-}
-
-/// RAII Pseudoconsole
-pub struct Conpty {
- pub handle: HPCON,
- api: ConptyApi,
-}
-
-/// Handle can be cloned freely and moved between threads.
-pub type ConptyHandle = Arc<Conpty>;
-
-impl Drop for Conpty {
- fn drop(&mut self) {
- unsafe { (self.api.ClosePseudoConsole)(self.handle) }
- }
-}
-
-// The Conpty API can be accessed from multiple threads.
-unsafe impl Send for Conpty {}
-unsafe impl Sync for Conpty {}
-
-pub fn new<'a>(
- config: &Config,
- options: &Options,
- size: &SizeInfo,
- _window_id: Option<usize>,
-) -> Option<Pty<'a>> {
- if !config.enable_experimental_conpty_backend() {
- return None;
- }
-
- let api = ConptyApi::new()?;
-
- let mut pty_handle = 0 as HPCON;
-
- // Passing 0 as the size parameter allows the "system default" buffer
- // size to be used. There may be small performance and memory advantages
- // to be gained by tuning this in the future, but it's likely a reasonable
- // start point.
- let (conout, conout_pty_handle) = miow::pipe::anonymous(0).unwrap();
- let (conin_pty_handle, conin) = miow::pipe::anonymous(0).unwrap();
-
- let coord =
- coord_from_sizeinfo(size).expect("Overflow when creating initial size on pseudoconsole");
-
- // Create the Pseudo Console, using the pipes
- let result = unsafe {
- (api.CreatePseudoConsole)(
- coord,
- conin_pty_handle.into_raw_handle(),
- conout_pty_handle.into_raw_handle(),
- 0,
- &mut pty_handle as *mut HPCON,
- )
- };
-
- assert!(result == S_OK);
-
- let mut success;
-
- // Prepare child process startup info
-
- let mut size: SIZE_T = 0;
-
- let mut startup_info_ex: STARTUPINFOEXW = Default::default();
-
- let title = options.title.as_ref().map(String::as_str).unwrap_or("Alacritty");
- let title = U16CString::from_str(title).unwrap();
- startup_info_ex.StartupInfo.lpTitle = title.as_ptr() as LPWSTR;
-
- startup_info_ex.StartupInfo.cb = mem::size_of::<STARTUPINFOEXW>() as u32;
-
- // Setting this flag but leaving all the handles as default (null) ensures the
- // pty process does not inherit any handles from this Alacritty process.
- startup_info_ex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
-
- // Create the appropriately sized thread attribute list.
- unsafe {
- let failure =
- InitializeProcThreadAttributeList(ptr::null_mut(), 1, 0, &mut size as PSIZE_T) > 0;
-
- // This call was expected to return false.
- if failure {
- panic_shell_spawn();
- }
- }
-
- let mut attr_list: Box<[BYTE]> = vec![0; size].into_boxed_slice();
-
- // Set startup info's attribute list & initialize it
- //
- // Lint failure is spurious; it's because winapi's definition of PROC_THREAD_ATTRIBUTE_LIST
- // implies it is one pointer in size (32 or 64 bits) but really this is just a dummy value.
- // Casting a *mut u8 (pointer to 8 bit type) might therefore not be aligned correctly in
- // the compiler's eyes.
- #[allow(clippy::cast_ptr_alignment)]
- {
- startup_info_ex.lpAttributeList = attr_list.as_mut_ptr() as _;
- }
-
- unsafe {
- success = InitializeProcThreadAttributeList(
- startup_info_ex.lpAttributeList,
- 1,
- 0,
- &mut size as PSIZE_T,
- ) > 0;
-
- if !success {
- panic_shell_spawn();
- }
- }
-
- // Set thread attribute list's Pseudo Console to the specified ConPTY
- unsafe {
- success = UpdateProcThreadAttribute(
- startup_info_ex.lpAttributeList,
- 0,
- 22 | 0x0002_0000, // PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
- pty_handle,
- mem::size_of::<HPCON>(),
- ptr::null_mut(),
- ptr::null_mut(),
- ) > 0;
-
- if !success {
- panic_shell_spawn();
- }
- }
-
- // Get process commandline
- let default_shell = &Shell::new("powershell");
- let shell = config.shell().unwrap_or(default_shell);
- let initial_command = options.command().unwrap_or(shell);
- let mut cmdline = initial_command.args().to_vec();
- cmdline.insert(0, initial_command.program().into());
-
- // Warning, here be borrow hell
- let cwd = options.working_dir.as_ref().map(|dir| canonicalize(dir).unwrap());
- let cwd = cwd.as_ref().map(|dir| dir.to_str().unwrap());
-
- // Create the client application, using startup info containing ConPTY info
- let cmdline = U16CString::from_str(&cmdline.join(" ")).unwrap();
- let cwd = cwd.map(|s| U16CString::from_str(&s).unwrap());
-
- let mut proc_info: PROCESS_INFORMATION = Default::default();
- unsafe {
- success = CreateProcessW(
- ptr::null(),
- cmdline.as_ptr() as LPWSTR,
- ptr::null_mut(),
- ptr::null_mut(),
- false as i32,
- EXTENDED_STARTUPINFO_PRESENT,
- ptr::null_mut(),
- cwd.as_ref().map_or_else(ptr::null, |s| s.as_ptr()),
- &mut startup_info_ex.StartupInfo as *mut STARTUPINFOW,
- &mut proc_info as *mut PROCESS_INFORMATION,
- ) > 0;
-
- if !success {
- panic_shell_spawn();
- }
- }
-
- // Store handle to console
- unsafe {
- HANDLE = proc_info.hProcess;
- }
-
- let conin = EventedAnonWrite::new(conin);
- let conout = EventedAnonRead::new(conout);
-
- let agent = Conpty { handle: pty_handle, api };
-
- Some(Pty {
- handle: super::PtyHandle::Conpty(ConptyHandle::new(agent)),
- conout: super::EventedReadablePipe::Anonymous(conout),
- conin: super::EventedWritablePipe::Anonymous(conin),
- read_token: 0.into(),
- write_token: 0.into(),
- })
-}
-
-// Panic with the last os error as message
-fn panic_shell_spawn() {
- panic!("Unable to spawn shell: {}", Error::last_os_error());
-}
-
-impl OnResize for ConptyHandle {
- fn on_resize(&mut self, sizeinfo: &SizeInfo) {
- if let Some(coord) = coord_from_sizeinfo(sizeinfo) {
- let result = unsafe { (self.api.ResizePseudoConsole)(self.handle, coord) };
- assert!(result == S_OK);
- }
- }
-}
-
-/// Helper to build a COORD from a SizeInfo, returing None in overflow cases.
-fn coord_from_sizeinfo(sizeinfo: &SizeInfo) -> Option<COORD> {
- let cols = sizeinfo.cols().0;
- let lines = sizeinfo.lines().0;
-
- if cols <= i16::MAX as usize && lines <= i16::MAX as usize {
- Some(COORD { X: sizeinfo.cols().0 as i16, Y: sizeinfo.lines().0 as i16 })
- } else {
- None
- }
-}
diff --git a/src/tty/windows/mod.rs b/src/tty/windows/mod.rs
deleted file mode 100644
index c87c5257..00000000
--- a/src/tty/windows/mod.rs
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use std::io::{self, Read, Write};
-use std::os::raw::c_void;
-use std::sync::atomic::{AtomicBool, Ordering};
-
-use mio::{self, Evented, Poll, PollOpt, Ready, Token};
-use mio_anonymous_pipes::{EventedAnonRead, EventedAnonWrite};
-use mio_named_pipes::NamedPipe;
-
-use winapi::shared::winerror::WAIT_TIMEOUT;
-use winapi::um::synchapi::WaitForSingleObject;
-use winapi::um::winbase::WAIT_OBJECT_0;
-
-use crate::cli::Options;
-use crate::config::Config;
-use crate::display::OnResize;
-use crate::term::SizeInfo;
-use crate::tty::{EventedPty, EventedReadWrite};
-
-mod conpty;
-mod winpty;
-
-/// Handle to the winpty agent or conpty process. Required so we know when it closes.
-static mut HANDLE: *mut c_void = 0usize as *mut c_void;
-static IS_CONPTY: AtomicBool = AtomicBool::new(false);
-
-pub fn process_should_exit() -> bool {
- unsafe {
- match WaitForSingleObject(HANDLE, 0) {
- // Process has exited
- WAIT_OBJECT_0 => {
- info!("wait_object_0");
- true
- },
- // Reached timeout of 0, process has not exited
- WAIT_TIMEOUT => false,
- // Error checking process, winpty gave us a bad agent handle?
- _ => {
- info!("Bad exit: {}", ::std::io::Error::last_os_error());
- true
- },
- }
- }
-}
-
-pub fn is_conpty() -> bool {
- IS_CONPTY.load(Ordering::Relaxed)
-}
-
-#[derive(Clone)]
-pub enum PtyHandle<'a> {
- Winpty(winpty::WinptyHandle<'a>),
- Conpty(conpty::ConptyHandle),
-}
-
-pub struct Pty<'a> {
- handle: PtyHandle<'a>,
- // TODO: It's on the roadmap for the Conpty API to support Overlapped I/O.
- // See https://github.com/Microsoft/console/issues/262
- // When support for that lands then it should be possible to use
- // NamedPipe for the conout and conin handles
- conout: EventedReadablePipe,
- conin: EventedWritablePipe,
- read_token: mio::Token,
- write_token: mio::Token,
-}
-
-impl<'a> Pty<'a> {
- pub fn resize_handle(&self) -> impl OnResize + 'a {
- self.handle.clone()
- }
-}
-
-pub fn new<'a>(
- config: &Config,
- options: &Options,
- size: &SizeInfo,
- window_id: Option<usize>,
-) -> Pty<'a> {
- if let Some(pty) = conpty::new(config, options, size, window_id) {
- info!("Using Conpty agent");
- IS_CONPTY.store(true, Ordering::Relaxed);
- pty
- } else {
- info!("Using Winpty agent");
- winpty::new(config, options, size, window_id)
- }
-}
-
-// TODO: The ConPTY API curently must use synchronous pipes as the input
-// and output handles. This has led to the need to support two different
-// types of pipe.
-//
-// When https://github.com/Microsoft/console/issues/262 lands then the
-// Anonymous variant of this enum can be removed from the codebase and
-// everything can just use NamedPipe.
-pub enum EventedReadablePipe {
- Anonymous(EventedAnonRead),
- Named(NamedPipe),
-}
-
-pub enum EventedWritablePipe {
- Anonymous(EventedAnonWrite),
- Named(NamedPipe),
-}
-
-impl Evented for EventedReadablePipe {
- fn register(
- &self,
- poll: &Poll,
- token: Token,
- interest: Ready,
- opts: PollOpt,
- ) -> io::Result<()> {
- match self {
- EventedReadablePipe::Anonymous(p) => p.register(poll, token, interest, opts),
- EventedReadablePipe::Named(p) => p.register(poll, token, interest, opts),
- }
- }
-
- fn reregister(
- &self,
- poll: &Poll,
- token: Token,
- interest: Ready,
- opts: PollOpt,
- ) -> io::Result<()> {
- match self {
- EventedReadablePipe::Anonymous(p) => p.reregister(poll, token, interest, opts),
- EventedReadablePipe::Named(p) => p.reregister(poll, token, interest, opts),
- }
- }
-
- fn deregister(&self, poll: &Poll) -> io::Result<()> {
- match self {
- EventedReadablePipe::Anonymous(p) => p.deregister(poll),
- EventedReadablePipe::Named(p) => p.deregister(poll),
- }
- }
-}
-
-impl Read for EventedReadablePipe {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- match self {
- EventedReadablePipe::Anonymous(p) => p.read(buf),
- EventedReadablePipe::Named(p) => p.read(buf),
- }
- }
-}
-
-impl Evented for EventedWritablePipe {
- fn register(
- &self,
- poll: &Poll,
- token: Token,
- interest: Ready,
- opts: PollOpt,
- ) -> io::Result<()> {
- match self {
- EventedWritablePipe::Anonymous(p) => p.register(poll, token, interest, opts),
- EventedWritablePipe::Named(p) => p.register(poll, token, interest, opts),
- }
- }
-
- fn reregister(
- &self,
- poll: &Poll,
- token: Token,
- interest: Ready,
- opts: PollOpt,
- ) -> io::Result<()> {
- match self {
- EventedWritablePipe::Anonymous(p) => p.reregister(poll, token, interest, opts),
- EventedWritablePipe::Named(p) => p.reregister(poll, token, interest, opts),
- }
- }
-
- fn deregister(&self, poll: &Poll) -> io::Result<()> {
- match self {
- EventedWritablePipe::Anonymous(p) => p.deregister(poll),
- EventedWritablePipe::Named(p) => p.deregister(poll),
- }
- }
-}
-
-impl Write for EventedWritablePipe {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- match self {
- EventedWritablePipe::Anonymous(p) => p.write(buf),
- EventedWritablePipe::Named(p) => p.write(buf),
- }
- }
-
- fn flush(&mut self) -> io::Result<()> {
- match self {
- EventedWritablePipe::Anonymous(p) => p.flush(),
- EventedWritablePipe::Named(p) => p.flush(),
- }
- }
-}
-
-impl<'a> OnResize for PtyHandle<'a> {
- fn on_resize(&mut self, sizeinfo: &SizeInfo) {
- match self {
- PtyHandle::Winpty(w) => w.resize(sizeinfo),
- PtyHandle::Conpty(c) => {
- let mut handle = c.clone();
- handle.on_resize(sizeinfo)
- },
- }
- }
-}
-
-impl<'a> EventedReadWrite for Pty<'a> {
- type Reader = EventedReadablePipe;
- type Writer = EventedWritablePipe;
-
- #[inline]
- fn register(
- &mut self,
- poll: &mio::Poll,
- token: &mut dyn Iterator<Item = mio::Token>,
- interest: mio::Ready,
- poll_opts: mio::PollOpt,
- ) -> io::Result<()> {
- self.read_token = token.next().unwrap();
- self.write_token = token.next().unwrap();
-
- if interest.is_readable() {
- poll.register(&self.conout, self.read_token, mio::Ready::readable(), poll_opts)?
- } else {
- poll.register(&self.conout, self.read_token, mio::Ready::empty(), poll_opts)?
- }
- if interest.is_writable() {
- poll.register(&self.conin, self.write_token, mio::Ready::writable(), poll_opts)?
- } else {
- poll.register(&self.conin, self.write_token, mio::Ready::empty(), poll_opts)?
- }
- Ok(())
- }
-
- #[inline]
- fn reregister(
- &mut self,
- poll: &mio::Poll,
- interest: mio::Ready,
- poll_opts: mio::PollOpt,
- ) -> io::Result<()> {
- if interest.is_readable() {
- poll.reregister(&self.conout, self.read_token, mio::Ready::readable(), poll_opts)?;
- } else {
- poll.reregister(&self.conout, self.read_token, mio::Ready::empty(), poll_opts)?;
- }
- if interest.is_writable() {
- poll.reregister(&self.conin, self.write_token, mio::Ready::writable(), poll_opts)?;
- } else {
- poll.reregister(&self.conin, self.write_token, mio::Ready::empty(), poll_opts)?;
- }
- Ok(())
- }
-
- #[inline]
- fn deregister(&mut self, poll: &mio::Poll) -> io::Result<()> {
- poll.deregister(&self.conout)?;
- poll.deregister(&self.conin)?;
- Ok(())
- }
-
- #[inline]
- fn reader(&mut self) -> &mut Self::Reader {
- &mut self.conout
- }
-
- #[inline]
- fn read_token(&self) -> mio::Token {
- self.read_token
- }
-
- #[inline]
- fn writer(&mut self) -> &mut Self::Writer {
- &mut self.conin
- }
-
- #[inline]
- fn write_token(&self) -> mio::Token {
- self.write_token
- }
-}
-
-impl<'a> EventedPty for Pty<'a> {}
diff --git a/src/tty/windows/winpty.rs b/src/tty/windows/winpty.rs
deleted file mode 100644
index 10bd9d01..00000000
--- a/src/tty/windows/winpty.rs
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use super::{Pty, HANDLE};
-
-use std::fs::OpenOptions;
-use std::io;
-use std::os::windows::fs::OpenOptionsExt;
-use std::os::windows::io::{FromRawHandle, IntoRawHandle};
-use std::sync::Arc;
-use std::u16;
-
-use dunce::canonicalize;
-use mio_named_pipes::NamedPipe;
-use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
-use winpty::Config as WinptyConfig;
-use winpty::{ConfigFlags, MouseMode, SpawnConfig, SpawnFlags, Winpty};
-
-use crate::cli::Options;
-use crate::config::{Config, Shell};
-use crate::display::OnResize;
-use crate::term::SizeInfo;
-
-// We store a raw pointer because we need mutable access to call
-// on_resize from a separate thread. Winpty internally uses a mutex
-// so this is safe, despite outwards appearance.
-pub struct Agent<'a> {
- winpty: *mut Winpty<'a>,
-}
-
-/// Handle can be cloned freely and moved between threads.
-pub type WinptyHandle<'a> = Arc<Agent<'a>>;
-
-// Because Winpty has a mutex, we can do this.
-unsafe impl<'a> Send for Agent<'a> {}
-unsafe impl<'a> Sync for Agent<'a> {}
-
-impl<'a> Agent<'a> {
- pub fn new(winpty: Winpty<'a>) -> Self {
- Self { winpty: Box::into_raw(Box::new(winpty)) }
- }
-
- /// Get immutable access to Winpty.
- pub fn winpty(&self) -> &Winpty<'a> {
- unsafe { &*self.winpty }
- }
-
- pub fn resize(&self, size: &SizeInfo) {
- // This is safe since Winpty uses a mutex internally.
- unsafe {
- (&mut *self.winpty).on_resize(size);
- }
- }
-}
-
-impl<'a> Drop for Agent<'a> {
- fn drop(&mut self) {
- unsafe {
- Box::from_raw(self.winpty);
- }
- }
-}
-
-/// How long the winpty agent should wait for any RPC request
-/// This is a placeholder value until we see how often long responses happen
-const AGENT_TIMEOUT: u32 = 10000;
-
-pub fn new<'a>(
- config: &Config,
- options: &Options,
- size: &SizeInfo,
- _window_id: Option<usize>,
-) -> Pty<'a> {
- // Create config
- let mut wconfig = WinptyConfig::new(ConfigFlags::empty()).unwrap();
-
- wconfig.set_initial_size(size.cols().0 as i32, size.lines().0 as i32);
- wconfig.set_mouse_mode(&MouseMode::Auto);
- wconfig.set_agent_timeout(AGENT_TIMEOUT);
-
- // Start agent
- let mut winpty = Winpty::open(&wconfig).unwrap();
- let (conin, conout) = (winpty.conin_name(), winpty.conout_name());
-
- // Get process commandline
- let default_shell = &Shell::new("powershell");
- let shell = config.shell().unwrap_or(default_shell);
- let initial_command = options.command().unwrap_or(shell);
- let mut cmdline = initial_command.args().to_vec();
- cmdline.insert(0, initial_command.program().into());
-
- // Warning, here be borrow hell
- let cwd = options.working_dir.as_ref().map(|dir| canonicalize(dir).unwrap());
- let cwd = cwd.as_ref().map(|dir| dir.to_str().unwrap());
-
- // Spawn process
- let spawnconfig = SpawnConfig::new(
- SpawnFlags::AUTO_SHUTDOWN | SpawnFlags::EXIT_AFTER_SHUTDOWN,
- None, // appname
- Some(&cmdline.join(" ")),
- cwd,
- None, // Env
- )
- .unwrap();
-
- let default_opts = &mut OpenOptions::new();
- default_opts.share_mode(0).custom_flags(FILE_FLAG_OVERLAPPED);
-
- let (conout_pipe, conin_pipe);
- unsafe {
- conout_pipe = NamedPipe::from_raw_handle(
- default_opts.clone().read(true).open(conout).unwrap().into_raw_handle(),
- );
- conin_pipe = NamedPipe::from_raw_handle(
- default_opts.clone().write(true).open(conin).unwrap().into_raw_handle(),
- );
- };
-
- if let Some(err) = conout_pipe.connect().err() {
- if err.kind() != io::ErrorKind::WouldBlock {
- panic!(err);
- }
- }
- assert!(conout_pipe.take_error().unwrap().is_none());
-
- if let Some(err) = conin_pipe.connect().err() {
- if err.kind() != io::ErrorKind::WouldBlock {
- panic!(err);
- }
- }
- assert!(conin_pipe.take_error().unwrap().is_none());
-
- winpty.spawn(&spawnconfig).unwrap();
-
- unsafe {
- HANDLE = winpty.raw_handle();
- }
-
- let agent = Agent::new(winpty);
-
- Pty {
- handle: super::PtyHandle::Winpty(WinptyHandle::new(agent)),
- conout: super::EventedReadablePipe::Named(conout_pipe),
- conin: super::EventedWritablePipe::Named(conin_pipe),
- read_token: 0.into(),
- write_token: 0.into(),
- }
-}
-
-impl<'a> OnResize for Winpty<'a> {
- fn on_resize(&mut self, sizeinfo: &SizeInfo) {
- let (cols, lines) = (sizeinfo.cols().0, sizeinfo.lines().0);
- if cols > 0 && cols <= u16::MAX as usize && lines > 0 && lines <= u16::MAX as usize {
- self.set_size(cols as u16, lines as u16)
- .unwrap_or_else(|_| info!("Unable to set winpty size, did it die?"));
- }
- }
-}