|
1 | 1 | use std::{
|
2 |
| - fs, |
3 |
| - io::{self, BufWriter, Write as _}, |
| 2 | + fs::{self, File}, |
| 3 | + io::{self, BufWriter, IsTerminal as _, Write as _}, |
4 | 4 | mem,
|
5 | 5 | os::windows::prelude::*,
|
6 | 6 | ptr,
|
@@ -45,14 +45,55 @@ const CP_UTF8: CodePageID = 65001;
|
45 | 45 | // This crate however uses `windows-sys` instead of `winapi` and has a slightly different API for
|
46 | 46 | // the `InputHandle` and `OutputHandle`.
|
47 | 47 |
|
| 48 | +#[derive(Debug)] |
| 49 | +pub enum Handle { |
| 50 | + Owned(OwnedHandle), |
| 51 | + Borrowed(BorrowedHandle<'static>), |
| 52 | +} |
| 53 | + |
| 54 | +impl AsRawHandle for Handle { |
| 55 | + fn as_raw_handle(&self) -> RawHandle { |
| 56 | + match self { |
| 57 | + Self::Owned(handle) => handle.as_raw_handle(), |
| 58 | + Self::Borrowed(handle) => handle.as_raw_handle(), |
| 59 | + } |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +impl Handle { |
| 64 | + pub fn stdin() -> Self { |
| 65 | + let stdin = io::stdin().as_raw_handle(); |
| 66 | + Self::Borrowed(unsafe { BorrowedHandle::borrow_raw(stdin) }) |
| 67 | + } |
| 68 | + |
| 69 | + pub fn stdout() -> Self { |
| 70 | + let stdout = io::stdout().as_raw_handle(); |
| 71 | + Self::Borrowed(unsafe { BorrowedHandle::borrow_raw(stdout) }) |
| 72 | + } |
| 73 | + |
| 74 | + pub fn try_clone(&self) -> io::Result<Self> { |
| 75 | + let this = match self { |
| 76 | + Self::Owned(handle) => Self::Owned(handle.try_clone()?), |
| 77 | + Self::Borrowed(handle) => Self::Borrowed(*handle), |
| 78 | + }; |
| 79 | + Ok(this) |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +impl From<File> for Handle { |
| 84 | + fn from(file: File) -> Self { |
| 85 | + Self::Owned(OwnedHandle::from(file)) |
| 86 | + } |
| 87 | +} |
| 88 | + |
48 | 89 | #[derive(Debug)]
|
49 | 90 | pub(crate) struct InputHandle {
|
50 |
| - handle: OwnedHandle, |
| 91 | + handle: Handle, |
51 | 92 | }
|
52 | 93 |
|
53 | 94 | impl InputHandle {
|
54 |
| - fn new<H: Into<OwnedHandle>>(h: H) -> Self { |
55 |
| - Self { handle: h.into() } |
| 95 | + fn new(handle: Handle) -> Self { |
| 96 | + Self { handle } |
56 | 97 | }
|
57 | 98 |
|
58 | 99 | fn try_clone(&self) -> io::Result<Self> {
|
@@ -151,12 +192,12 @@ impl AsRawHandle for InputHandle {
|
151 | 192 |
|
152 | 193 | #[derive(Debug)]
|
153 | 194 | pub struct OutputHandle {
|
154 |
| - handle: OwnedHandle, |
| 195 | + handle: Handle, |
155 | 196 | }
|
156 | 197 |
|
157 | 198 | impl OutputHandle {
|
158 |
| - fn new<H: Into<OwnedHandle>>(h: H) -> Self { |
159 |
| - Self { handle: h.into() } |
| 199 | + fn new(handle: Handle) -> Self { |
| 200 | + Self { handle } |
160 | 201 | }
|
161 | 202 |
|
162 | 203 | fn get_mode(&self) -> io::Result<CONSOLE_MODE> {
|
@@ -248,20 +289,22 @@ impl io::Write for OutputHandle {
|
248 | 289 | }
|
249 | 290 |
|
250 | 291 | fn open_pty() -> io::Result<(InputHandle, OutputHandle)> {
|
251 |
| - // TODO: attempt to handle stdin/stdout? |
252 |
| - let input = InputHandle::new( |
253 |
| - fs::OpenOptions::new() |
| 292 | + let (input, output) = if io::stdin().is_terminal() { |
| 293 | + (Handle::stdin(), Handle::stdout()) |
| 294 | + } else { |
| 295 | + let input = fs::OpenOptions::new() |
254 | 296 | .read(true)
|
255 | 297 | .write(true)
|
256 |
| - .open("CONIN$")?, |
257 |
| - ); |
258 |
| - let output = OutputHandle::new( |
259 |
| - fs::OpenOptions::new() |
| 298 | + .open("CONIN$")? |
| 299 | + .into(); |
| 300 | + let output = fs::OpenOptions::new() |
260 | 301 | .read(true)
|
261 | 302 | .write(true)
|
262 |
| - .open("CONOUT$")?, |
263 |
| - ); |
264 |
| - Ok((input, output)) |
| 303 | + .open("CONOUT$")? |
| 304 | + .into(); |
| 305 | + (input, output) |
| 306 | + }; |
| 307 | + Ok((InputHandle::new(input), OutputHandle::new(output))) |
265 | 308 | }
|
266 | 309 |
|
267 | 310 | // CREDIT: Again, like the UnixTerminal in the unix module this is mostly based on WezTerm but
|
|
0 commit comments