summaryrefslogtreecommitdiff
path: root/alacritty_terminal
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal')
-rw-r--r--alacritty_terminal/Cargo.toml4
-rw-r--r--alacritty_terminal/src/tty/windows/automatic_backend.rs189
-rw-r--r--alacritty_terminal/src/tty/windows/conpty.rs10
-rw-r--r--alacritty_terminal/src/tty/windows/mod.rs184
-rw-r--r--alacritty_terminal/src/tty/windows/winpty.rs10
5 files changed, 232 insertions, 165 deletions
diff --git a/alacritty_terminal/Cargo.toml b/alacritty_terminal/Cargo.toml
index 99ed6a21..f6f0f365 100644
--- a/alacritty_terminal/Cargo.toml
+++ b/alacritty_terminal/Cargo.toml
@@ -29,7 +29,7 @@ nix = "0.17.0"
signal-hook = { version = "0.1", features = ["mio-support"] }
[target.'cfg(windows)'.dependencies]
-winpty = "0.2.0"
+winpty = { version = "0.2.0", optional = true }
mio-named-pipes = "0.1"
miow = "0.3"
winapi = { version = "0.3.7", features = [
@@ -42,7 +42,7 @@ mio-anonymous-pipes = "0.1"
objc = "0.2.2"
[features]
-default = ["x11", "wayland"]
+default = ["x11", "wayland", "winpty"]
x11 = ["copypasta/x11"]
wayland = ["copypasta/wayland"]
nightly = []
diff --git a/alacritty_terminal/src/tty/windows/automatic_backend.rs b/alacritty_terminal/src/tty/windows/automatic_backend.rs
new file mode 100644
index 00000000..74a546dd
--- /dev/null
+++ b/alacritty_terminal/src/tty/windows/automatic_backend.rs
@@ -0,0 +1,189 @@
+/// Types to determine the appropriate PTY backend at runtime.
+///
+/// Unless the winpty feature is disabled, the PTY backend will automatically fall back to
+/// WinPTY when the newer ConPTY API is not supported, as long as the user hasn't explicitly
+/// opted into the WinPTY config option.
+use std::io::{self, Read, Write};
+
+use log::info;
+use mio::{Evented, Poll, PollOpt, Ready, Token};
+use mio_anonymous_pipes::{EventedAnonRead, EventedAnonWrite};
+use mio_named_pipes::NamedPipe;
+
+use crate::config::Config;
+use crate::event::OnResize;
+use crate::term::SizeInfo;
+
+use super::{conpty, winpty, Pty};
+
+pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) -> Pty {
+ if let Some(pty) = conpty::new(config, size, window_id) {
+ info!("Using ConPTY backend");
+ pty
+ } else {
+ info!("Using WinPTY backend");
+ winpty::new(config, size, window_id)
+ }
+}
+
+pub enum PtyBackend {
+ Winpty(winpty::Agent),
+ Conpty(conpty::Conpty),
+}
+
+impl OnResize for PtyBackend {
+ fn on_resize(&mut self, size: &SizeInfo) {
+ match self {
+ PtyBackend::Winpty(w) => w.on_resize(size),
+ PtyBackend::Conpty(c) => c.on_resize(size),
+ }
+ }
+}
+
+// TODO: The ConPTY API currently 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 From<winpty::Agent> for PtyBackend {
+ fn from(inner: winpty::Agent) -> Self {
+ PtyBackend::Winpty(inner)
+ }
+}
+
+impl From<conpty::Conpty> for PtyBackend {
+ fn from(inner: conpty::Conpty) -> Self {
+ PtyBackend::Conpty(inner)
+ }
+}
+
+impl From<EventedAnonRead> for EventedReadablePipe {
+ fn from(inner: EventedAnonRead) -> Self {
+ EventedReadablePipe::Anonymous(inner)
+ }
+}
+
+impl From<NamedPipe> for EventedReadablePipe {
+ fn from(inner: NamedPipe) -> Self {
+ EventedReadablePipe::Named(inner)
+ }
+}
+
+impl From<EventedAnonWrite> for EventedWritablePipe {
+ fn from(inner: EventedAnonWrite) -> Self {
+ EventedWritablePipe::Anonymous(inner)
+ }
+}
+
+impl From<NamedPipe> for EventedWritablePipe {
+ fn from(inner: NamedPipe) -> Self {
+ EventedWritablePipe::Named(inner)
+ }
+}
diff --git a/alacritty_terminal/src/tty/windows/conpty.rs b/alacritty_terminal/src/tty/windows/conpty.rs
index 2056f3d6..561df71d 100644
--- a/alacritty_terminal/src/tty/windows/conpty.rs
+++ b/alacritty_terminal/src/tty/windows/conpty.rs
@@ -231,15 +231,7 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) ->
let child_watcher = ChildExitWatcher::new(proc_info.hProcess).unwrap();
let conpty = Conpty { handle: pty_handle, api };
- Some(Pty {
- backend: super::PtyBackend::Conpty(conpty),
- conout: super::EventedReadablePipe::Anonymous(conout),
- conin: super::EventedWritablePipe::Anonymous(conin),
- read_token: 0.into(),
- write_token: 0.into(),
- child_event_token: 0.into(),
- child_watcher,
- })
+ Some(Pty::new(conpty, conout, conin, child_watcher))
}
// Panic with the last os error as message.
diff --git a/alacritty_terminal/src/tty/windows/mod.rs b/alacritty_terminal/src/tty/windows/mod.rs
index 8e5b4668..47b03d90 100644
--- a/alacritty_terminal/src/tty/windows/mod.rs
+++ b/alacritty_terminal/src/tty/windows/mod.rs
@@ -13,181 +13,78 @@
// limitations under the License.
use std::ffi::OsStr;
-use std::io::{self, Read, Write};
+use std::io;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
-use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::TryRecvError;
-use mio::{self, Evented, Poll, PollOpt, Ready, Token};
-use mio_anonymous_pipes::{EventedAnonRead, EventedAnonWrite};
-use mio_named_pipes::NamedPipe;
-
-use log::info;
-
use crate::config::{Config, Shell};
use crate::event::OnResize;
use crate::term::SizeInfo;
use crate::tty::windows::child::ChildExitWatcher;
use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
+#[cfg(feature = "winpty")]
+mod automatic_backend;
mod child;
mod conpty;
+#[cfg(feature = "winpty")]
mod winpty;
-static IS_CONPTY: AtomicBool = AtomicBool::new(false);
-
-pub fn is_conpty() -> bool {
- IS_CONPTY.load(Ordering::Relaxed)
-}
+#[cfg(not(feature = "winpty"))]
+use conpty::Conpty as Backend;
+#[cfg(not(feature = "winpty"))]
+use mio_anonymous_pipes::{EventedAnonRead as ReadPipe, EventedAnonWrite as WritePipe};
-enum PtyBackend {
- Winpty(winpty::Agent),
- Conpty(conpty::Conpty),
-}
+#[cfg(feature = "winpty")]
+use automatic_backend::{
+ EventedReadablePipe as ReadPipe, EventedWritablePipe as WritePipe, PtyBackend as Backend,
+};
pub struct Pty {
// XXX: Backend is required to be the first field, to ensure correct drop order. Dropping
- // `conout` before `backend` will cause a deadlock.
- backend: PtyBackend,
- // 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,
+ // `conout` before `backend` will cause a deadlock (with Conpty).
+ backend: Backend,
+ conout: ReadPipe,
+ conin: WritePipe,
read_token: mio::Token,
write_token: mio::Token,
child_event_token: mio::Token,
child_watcher: ChildExitWatcher,
}
+#[cfg(not(feature = "winpty"))]
pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) -> Pty {
- if let Some(pty) = conpty::new(config, size, window_id) {
- info!("Using ConPTY backend");
- IS_CONPTY.store(true, Ordering::Relaxed);
- pty
- } else {
- info!("Using WinPTY backend");
- winpty::new(config, size, window_id)
- }
-}
-
-// TODO: The ConPTY API currently 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),
- }
- }
+ conpty::new(config, size, window_id).expect("Failed to create ConPTY backend")
}
-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),
- }
- }
+#[cfg(feature = "winpty")]
+pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) -> Pty {
+ automatic_backend::new(config, size, window_id)
}
-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 Pty {
+ fn new(
+ backend: impl Into<Backend>,
+ conout: impl Into<ReadPipe>,
+ conin: impl Into<WritePipe>,
+ child_watcher: ChildExitWatcher,
+ ) -> Self {
+ Self {
+ backend: backend.into(),
+ conout: conout.into(),
+ conin: conin.into(),
+ read_token: 0.into(),
+ write_token: 0.into(),
+ child_event_token: 0.into(),
+ child_watcher,
}
}
}
impl EventedReadWrite for Pty {
- type Reader = EventedReadablePipe;
- type Writer = EventedWritablePipe;
+ type Reader = ReadPipe;
+ type Writer = WritePipe;
#[inline]
fn register(
@@ -295,10 +192,7 @@ impl EventedPty for Pty {
impl OnResize for Pty {
fn on_resize(&mut self, size: &SizeInfo) {
- match &mut self.backend {
- PtyBackend::Winpty(w) => w.on_resize(size),
- PtyBackend::Conpty(c) => c.on_resize(size),
- }
+ self.backend.on_resize(size)
}
}
diff --git a/alacritty_terminal/src/tty/windows/winpty.rs b/alacritty_terminal/src/tty/windows/winpty.rs
index d466955d..acfa6748 100644
--- a/alacritty_terminal/src/tty/windows/winpty.rs
+++ b/alacritty_terminal/src/tty/windows/winpty.rs
@@ -70,15 +70,7 @@ pub fn new<C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) ->
let child_watcher = ChildExitWatcher::new(agent.raw_handle()).unwrap();
- Pty {
- backend: super::PtyBackend::Winpty(agent),
- conout: super::EventedReadablePipe::Named(conout_pipe),
- conin: super::EventedWritablePipe::Named(conin_pipe),
- read_token: 0.into(),
- write_token: 0.into(),
- child_event_token: 0.into(),
- child_watcher,
- }
+ Pty::new(agent, conout_pipe, conin_pipe, child_watcher)
}
impl OnResize for Agent {