From af267bb2ba4d9c707972afa886de017c6a213b95 Mon Sep 17 00:00:00 2001 From: "M.Amin Rayej" Date: Sun, 19 Jan 2025 22:12:41 +0330 Subject: [PATCH 1/4] implement is_terminal for stdio types --- tokio/src/io/blocking.rs | 6 ++++++ tokio/src/io/stderr.rs | 12 ++++++++++++ tokio/src/io/stdin.rs | 12 +++++++++++- tokio/src/io/stdio_common.rs | 4 ++++ tokio/src/io/stdout.rs | 12 ++++++++++++ tokio/src/process/mod.rs | 15 +++++++++++++++ tokio/src/process/unix/mod.rs | 6 +++++- tokio/src/process/windows.rs | 14 +++++++++++++- 8 files changed, 78 insertions(+), 3 deletions(-) diff --git a/tokio/src/io/blocking.rs b/tokio/src/io/blocking.rs index 1af5065456d..36c380c2af1 100644 --- a/tokio/src/io/blocking.rs +++ b/tokio/src/io/blocking.rs @@ -50,6 +50,12 @@ cfg_io_blocking! { } } +impl Blocking { + pub(crate) fn inner(&self) -> Option<&T> { + self.inner.as_ref() + } +} + impl AsyncRead for Blocking where T: Read + Unpin + Send + 'static, diff --git a/tokio/src/io/stderr.rs b/tokio/src/io/stderr.rs index 0988e2d9da0..6c82d141b75 100644 --- a/tokio/src/io/stderr.rs +++ b/tokio/src/io/stderr.rs @@ -3,6 +3,7 @@ use crate::io::stdio_common::SplitByUtf8BoundaryIfWindows; use crate::io::AsyncWrite; use std::io; +use std::io::IsTerminal; use std::pin::Pin; use std::task::Context; use std::task::Poll; @@ -132,3 +133,14 @@ impl AsyncWrite for Stderr { Pin::new(&mut self.std).poll_shutdown(cx) } } + +impl Stderr { + /// Returns true if the descriptor/handle refers to a terminal/tty. + pub fn is_terminal(&self) -> bool { + self.std + .inner() + .inner() + .map(|stderr| stderr.is_terminal()) + .unwrap_or_default() + } +} diff --git a/tokio/src/io/stdin.rs b/tokio/src/io/stdin.rs index 877c48b30fb..1031745f51e 100644 --- a/tokio/src/io/stdin.rs +++ b/tokio/src/io/stdin.rs @@ -1,7 +1,7 @@ use crate::io::blocking::Blocking; use crate::io::{AsyncRead, ReadBuf}; -use std::io; +use std::io::{self, IsTerminal}; use std::pin::Pin; use std::task::Context; use std::task::Poll; @@ -96,3 +96,13 @@ impl AsyncRead for Stdin { Pin::new(&mut self.std).poll_read(cx, buf) } } + +impl Stdin { + /// Returns true if the descriptor/handle refers to a terminal/tty. + pub fn is_terminal(&self) -> bool { + self.std + .inner() + .map(|stdin| stdin.is_terminal()) + .unwrap_or_default() + } +} diff --git a/tokio/src/io/stdio_common.rs b/tokio/src/io/stdio_common.rs index 4adbfe23606..2d8064d27fc 100644 --- a/tokio/src/io/stdio_common.rs +++ b/tokio/src/io/stdio_common.rs @@ -17,6 +17,10 @@ impl SplitByUtf8BoundaryIfWindows { pub(crate) fn new(inner: W) -> Self { Self { inner } } + + pub(crate) fn inner(&self) -> &W { + &self.inner + } } // this constant is defined by Unicode standard. diff --git a/tokio/src/io/stdout.rs b/tokio/src/io/stdout.rs index f46ca0f05c4..0d779999b13 100644 --- a/tokio/src/io/stdout.rs +++ b/tokio/src/io/stdout.rs @@ -2,6 +2,7 @@ use crate::io::blocking::Blocking; use crate::io::stdio_common::SplitByUtf8BoundaryIfWindows; use crate::io::AsyncWrite; use std::io; +use std::io::IsTerminal; use std::pin::Pin; use std::task::Context; use std::task::Poll; @@ -181,3 +182,14 @@ impl AsyncWrite for Stdout { Pin::new(&mut self.std).poll_shutdown(cx) } } + +impl Stdout { + /// Returns true if the descriptor/handle refers to a terminal/tty. + pub fn is_terminal(&self) -> bool { + self.std + .inner() + .inner() + .map(|stdout| stdout.is_terminal()) + .unwrap_or_default() + } +} diff --git a/tokio/src/process/mod.rs b/tokio/src/process/mod.rs index 565795ac4e6..ecd0d39201f 100644 --- a/tokio/src/process/mod.rs +++ b/tokio/src/process/mod.rs @@ -1381,6 +1381,11 @@ impl ChildStdin { inner: imp::stdio(inner)?, }) } + + /// Returns true if the descriptor/handle refers to a terminal/tty. + pub fn is_terminal(&self) -> bool { + self.inner.is_terminal() + } } impl ChildStdout { @@ -1396,6 +1401,11 @@ impl ChildStdout { inner: imp::stdio(inner)?, }) } + + /// Returns true if the descriptor/handle refers to a terminal/tty. + pub fn is_terminal(&self) -> bool { + self.inner.is_terminal() + } } impl ChildStderr { @@ -1411,6 +1421,11 @@ impl ChildStderr { inner: imp::stdio(inner)?, }) } + + /// Returns true if the descriptor/handle refers to a terminal/tty. + pub fn is_terminal(&self) -> bool { + self.inner.is_terminal() + } } impl AsyncWrite for ChildStdin { diff --git a/tokio/src/process/unix/mod.rs b/tokio/src/process/unix/mod.rs index c9d1035f53d..4203a620522 100644 --- a/tokio/src/process/unix/mod.rs +++ b/tokio/src/process/unix/mod.rs @@ -41,7 +41,7 @@ use mio::unix::SourceFd; use std::fmt; use std::fs::File; use std::future::Future; -use std::io; +use std::io::{self, IsTerminal}; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use std::pin::Pin; use std::process::{Child as StdChild, ExitStatus, Stdio}; @@ -279,6 +279,10 @@ impl ChildStdio { pub(super) fn into_owned_fd(self) -> io::Result { convert_to_blocking_file(self).map(OwnedFd::from) } + + pub(crate) fn is_terminal(&self) -> bool { + self.as_fd().is_terminal() + } } impl fmt::Debug for ChildStdio { diff --git a/tokio/src/process/windows.rs b/tokio/src/process/windows.rs index db3c15790ce..ff6ca6d094a 100644 --- a/tokio/src/process/windows.rs +++ b/tokio/src/process/windows.rs @@ -24,7 +24,9 @@ use std::fmt; use std::fs::File as StdFile; use std::future::Future; use std::io; -use std::os::windows::prelude::{AsRawHandle, IntoRawHandle, OwnedHandle, RawHandle}; +use std::os::windows::prelude::{ + AsHandle, AsRawHandle, BorrowedHandle, IntoRawHandle, OwnedHandle, RawHandle, +}; use std::pin::Pin; use std::process::Stdio; use std::process::{Child as StdChild, Command as StdCommand, ExitStatus}; @@ -199,6 +201,10 @@ impl ChildStdio { pub(super) fn into_owned_handle(self) -> io::Result { convert_to_file(self).map(OwnedHandle::from) } + + pub(crate) fn is_terminal(&self) -> bool { + self.as_handle().is_terminal() + } } impl AsRawHandle for ChildStdio { @@ -207,6 +213,12 @@ impl AsRawHandle for ChildStdio { } } +impl AsHandle for ChildStdio { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.raw.as_handle() + } +} + impl AsyncRead for ChildStdio { fn poll_read( mut self: Pin<&mut Self>, From b931f0d93e02b7b3e673e4e3610bf64c0e05745b Mon Sep 17 00:00:00 2001 From: "M.Amin Rayej" Date: Sun, 19 Jan 2025 22:24:09 +0330 Subject: [PATCH 2/4] fix missing import on Windows --- tokio/src/process/windows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tokio/src/process/windows.rs b/tokio/src/process/windows.rs index ff6ca6d094a..c06a3fc4c90 100644 --- a/tokio/src/process/windows.rs +++ b/tokio/src/process/windows.rs @@ -24,6 +24,7 @@ use std::fmt; use std::fs::File as StdFile; use std::future::Future; use std::io; +use std::io::IsTerminal; use std::os::windows::prelude::{ AsHandle, AsRawHandle, BorrowedHandle, IntoRawHandle, OwnedHandle, RawHandle, }; From 1e131dac704e8d6632fbb354ba1a2ab7e2b33caf Mon Sep 17 00:00:00 2001 From: "M.Amin Rayej" Date: Sun, 19 Jan 2025 22:30:01 +0330 Subject: [PATCH 3/4] fix dead code warning --- tokio/src/io/blocking.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tokio/src/io/blocking.rs b/tokio/src/io/blocking.rs index 36c380c2af1..4d366c85f72 100644 --- a/tokio/src/io/blocking.rs +++ b/tokio/src/io/blocking.rs @@ -51,6 +51,7 @@ cfg_io_blocking! { } impl Blocking { + #[cfg_attr(not(feature = "io-std"), allow(dead_code))] pub(crate) fn inner(&self) -> Option<&T> { self.inner.as_ref() } From 6c44d7e51b5cc3b82794d8c2c84feef06ea4f53e Mon Sep 17 00:00:00 2001 From: "M.Amin Rayej" Date: Sun, 19 Jan 2025 22:45:04 +0330 Subject: [PATCH 4/4] update dictionary --- spellcheck.dic | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spellcheck.dic b/spellcheck.dic index e9f7eec22f6..faa855921b4 100644 --- a/spellcheck.dic +++ b/spellcheck.dic @@ -1,4 +1,4 @@ -299 +300 & + < @@ -263,6 +263,7 @@ tokio Tokio tokio's Tokio's +tty tuple Tuple tx