-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
windows doesn't detect stdin automatically #94
Comments
For what it's worth, you can detect this particular case. If you run
One caveat: this is true of cmd.exe. I don't know that other shells implement this the same way. |
Also noticed that |
@silverwind Does |
Nope, no such issue with I assume by installing through Oh, and I did some more testing with rg. I've also tested with https://github.com/rprichard/winpty which is basically a wrapper to
edit: updated, my bad. It doesn't work in any of the attempts. |
Oh, and because it likely matters, Rust nightly was installed in the
So far, I don't see any other issues. Everything work except this stdin issue. |
I don't have time at the moment to dig into this, but I'm skeptical that there's any big difference between compiling If you install with Please also consider that I don't know much about Windows. I'm making it up as I go. |
Take my answer with a grain of salts as I'm not really involved in low-level development, but as a long-time Cygwin user, this is my understanding: Natively build binaries (especially ones build under MSVS) target native Windows APIs, which are pretty much second-class citizens inside the Cygwin environment and prone to have a few bugs, especially when it comes to fundamental platform differences like TTY emulation. On the other hand the POSIX APIs are much better supported and it's a goal of the project enough of POSIX so that projects written for Linux can be built without any changes. |
On Windows 10 native terminal, this works perfectly: /// Returns true if there is a tty on stdin.
#[cfg(windows)]
pub fn on_stdin() -> bool {
use kernel32::{GetConsoleMode, GetStdHandle};
use winapi::winbase::STD_INPUT_HANDLE;
unsafe {
let mut out = 0;
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mut out) != 0
}
} From what I gather, this was removed due to #19. If the Cygwin environment can't be detected and skip this, I think Cygwin users should use a different build with the current behaviour. I prefer the native terminal and pipe is important enough for me to maintain a fork until this is resolved. Btw, ripgrep is awesome! |
Allow me to summarize where I'm at with this incredibly annoying issue:
What are the next steps?
That leads to the following logic: let on_stdin = unsafe {
let mut out = 0;
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mut out) != 0
};
if on_stdin {
// good enough, on_stdin is only true if there's a console
true
} else if on_stdout() || on_stderr() {
// on_stdin could be a false negative, but if stdout/stderr is a
// console, then we can trust the negative result.
false
} else {
// We don't know whether we have a console or not, so always pretend
// that we have a tty on stdin.
true
} I've tried this out and it does now at least let ripgrep operate sanely on native Windows. It doesn't fix the mintty problem and it can still spaz out on you. For example, running this produces unexpected results:
In this case, |
Sorry if I'm missing something here, but what's wrong with stealing the Git hack? It looks like it allows us to do exactly what we want, i.e. discover whether we're really using the console or not when |
@vadz I don't really understand it and I need to understand it before figuring out how to write it in Rust. (I am somewhat at the end of my rope on this issue too. For now, at least.) |
@vadz By "understand it" I think I'm just not familiar with these header files (like I said before, I'm making it up as I go when it comes to Windows):
Presumably these header files provide things like |
Conceptually it seems simple to me: we just check if we have a pipe and if the name of the pipe fits the pattern used by MSYS for the pipes it uses for terminal emulation. I think the confusing part could be all this BTW, notice that if we don't need to support XP (do we?), then we could use Win32 GetFileInformationByHandleEx() function instead. But OTOH P.S. Just got the page update with your latest reply. Unfortunately here it's my lack of Rust knowledge that works against me. I hoped that these function could be used in the same way as P.P.S. I do understand being sick of it very well though. |
@vadz With respect to
Ah! We definitely don't need to support XP, and So I think what I need to do is just use
This really helps actually. I didn't really grok much of that, so thank you for explaining that to me! |
Yes, I think so (but I didn't test it). AFAICS the only tricky thing risks to be interpreting the data returned by this function, as Rust code will somehow need to transmute the untyped byte buffer Good luck! |
Yup, I can definitely handle that part (Rust literally has a |
Yup, this does seem to work! Inside mintty, if I run |
This is the golden ticket for posterity: /// Returns true if there is an MSYS tty on the given handle.
#[cfg(windows)]
fn msys_tty_on_handle(handle: HANDLE) -> bool {
use std::ffi::OsString;
use std::mem;
use std::os::raw::c_void;
use std::os::windows::ffi::OsStringExt;
use std::slice;
use kernel32::{GetFileInformationByHandleEx};
use winapi::fileapi::FILE_NAME_INFO;
use winapi::minwinbase::FileNameInfo;
use winapi::minwindef::MAX_PATH;
unsafe {
let size = mem::size_of::<FILE_NAME_INFO>();
let mut name_info_bytes = vec![0u8; size + MAX_PATH];
let res = GetFileInformationByHandleEx(
handle,
FileNameInfo,
&mut *name_info_bytes as *mut _ as *mut c_void,
name_info_bytes.len() as u32);
if res == 0 {
return true;
}
let name_info: FILE_NAME_INFO =
*(name_info_bytes[0..size].as_ptr() as *const FILE_NAME_INFO);
let name_bytes =
&name_info_bytes[size..size + name_info.FileNameLength as usize];
let name_u16 = slice::from_raw_parts(
name_bytes.as_ptr() as *const u16, name_bytes.len() / 2);
let name = OsString::from_wide(name_u16)
.as_os_str().to_string_lossy().into_owned();
name.contains("msys-") || name.contains("-pty")
}
} |
With that bit done, everything seems to work perfectly now in both |
This commit completely guts all of the color handling code and replaces most of it with two new crates: wincolor and termcolor. wincolor provides a simple API to coloring using the Windows console and termcolor provides a platform independent coloring API tuned for multithreaded command line programs. This required a lot more flexibility than what the `term` crate provided, so it was dropped. We instead switch to writing ANSI escape sequences directly and ignore the TERMINFO database. In addition to fixing several bugs, this commit also permits end users to customize colors to a certain extent. For example, this command will set the match color to magenta and the line number background to yellow: rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo For tty handling, we've adopted a hack from `git` to do tty detection in MSYS/mintty terminals. As a result, ripgrep should get both color detection and piping correct on Windows regardless of which terminal you use. Finally, switch to line buffering. Performance doesn't seem to be impacted and it's an otherwise more user friendly option. Fixes #37, Fixes #51, Fixes #94, Fixes #117, Fixes #182, Fixes #231
Heatseeker attempts to use the Windows console API when running in Cygwin-type environments, which results in the process hanging. This change causes the command to fail fast when Cygwin is detected. It should be noted that detecting Cygwin is inordinately difficult; there doesn't appear to be a good, stable, documented way of doing it. The approach we take is to call Windows to obtain the file name associated with the standard input handle, as on Cygwin this name has a characteristic prefix or infix (on Windows it seems to be blank.) See also BurntSushi/ripgrep#94, where this technique was originally developed. Fixes #25.
Namely, running
rg pat < file
will recursively search the current directory instead offile
. A workaround is to dorg pat - < file
, which will search file.This is a consequence of fixing #19. Maybe there is a better way to detect whether stdin is a pipe automatically, but I don't know it. @vadz in particular points out that it is quite hairy:
I think you should still be able to detect whether stdin is a TTY when running inside the native console and you should be able to check for this (running inside console, I mean). But everything console-related in Windows is pretty hairy, just look at our own code for detecting whether we can write to a console...
The text was updated successfully, but these errors were encountered: