Skip to content

Commit

Permalink
add support for arbitrary file descriptors on unix
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mueller678 committed Apr 2, 2022
1 parent 4d48e58 commit e48ce23
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 19 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,14 @@ default = ["with-dirs"]
with-dirs = ["dirs-next"]
with-fuzzy = ["skim"]
case_insensitive_history_search = ["regex"]
arbitrary-file-descriptors=[]

[package.metadata.docs.rs]
features = ["with-dirs", "with-fuzzy"]
all-features = false
no-default-features = true
default-target = "x86_64-unknown-linux-gnu"

[[example]]
name = "arbitrary_file_descriptors"
required-features = ["arbitrary-file-descriptors"]
29 changes: 29 additions & 0 deletions examples/arbitrary_file_descriptors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use rustyline::{Behavior, Config, Editor, Result};
use std::fs::OpenOptions;
use std::io;

fn main() -> Result<()> {
#![cfg(all(unix, not(target_arch = "wasm32")))]
{
use std::os::unix::io::IntoRawFd;

let mut path = String::new();
io::stdin().read_line(&mut path)?;
let terminal = OpenOptions::new()
.read(true)
.write(true)
.open(path.trim())?;
let terminal_fd = terminal.into_raw_fd();
let config = Config::builder()
.behavior(Behavior::ArbitraryFileDescriptors {
output: terminal_fd,
input: terminal_fd,
})
.build();
let mut rl = Editor::<()>::with_config(config);
loop {
let line = rl.readline("> ")?;
println!("Line: {}", line);
}
}
}
11 changes: 11 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,17 @@ pub enum Behavior {
/// Use terminal-style interaction whenever possible, even if 'stdin' and/or
/// 'stdout' are not terminals.
PreferTerm,

/// Use the provided file descriptors.
/// rustyline will not automatically close these file descriptors.
#[cfg(feature = "arbitrary-file-descriptors")]
#[cfg(all(unix, not(target_arch = "wasm32")))]
ArbitraryFileDescriptors {
/// the file descriptor for input
input: std::os::unix::io::RawFd,
/// the file descriptor for output
output: std::os::unix::io::RawFd,
},
// TODO
// Use file-style interaction, reading input from the given file.
// useFile
Expand Down
54 changes: 35 additions & 19 deletions src/tty/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1182,33 +1182,49 @@ impl Term for PosixTerminal {
bell_style: BellStyle,
enable_bracketed_paste: bool,
) -> Self {
let (tty_in, is_in_a_tty, tty_out, is_out_a_tty, close_on_drop) =
if behavior == Behavior::PreferTerm {
let tty = OpenOptions::new().read(true).write(true).open("/dev/tty");
if let Ok(tty) = tty {
let fd = tty.into_raw_fd();
let is_a_tty = is_a_tty(fd); // TODO: useless ?
(fd, is_a_tty, fd, is_a_tty, true)
} else {
(
libc::STDIN_FILENO,
is_a_tty(libc::STDIN_FILENO),
libc::STDOUT_FILENO,
is_a_tty(libc::STDOUT_FILENO),
false,
)
let (tty_in, is_in_a_tty, tty_out, is_out_a_tty, close_on_drop, use_controlling_terminal) =
match behavior {
#[cfg(feature = "arbitrary-file-descriptors")]
#[cfg(all(unix, not(target_arch = "wasm32")))]
Behavior::ArbitraryFileDescriptors { input, output } => (
input,
is_a_tty(input),
output,
is_a_tty(output),
false,
false,
),
Behavior::PreferTerm => {
let tty = OpenOptions::new().read(true).write(true).open("/dev/tty");
if let Ok(tty) = tty {
let fd = tty.into_raw_fd();
let is_a_tty = is_a_tty(fd); // TODO: useless ?
(fd, is_a_tty, fd, is_a_tty, true, true)
} else {
(
libc::STDIN_FILENO,
is_a_tty(libc::STDIN_FILENO),
libc::STDOUT_FILENO,
is_a_tty(libc::STDOUT_FILENO),
false,
true,
)
}
}
} else {
(
Behavior::Stdio => (
libc::STDIN_FILENO,
is_a_tty(libc::STDIN_FILENO),
libc::STDOUT_FILENO,
is_a_tty(libc::STDOUT_FILENO),
false,
)
true,
),
};
let term = Self {
unsupported: is_unsupported_term(),
// if we are not using the controlling terminal of the process,
// the identity of the terminal used cannot be determined.
// So just assume the it is supported
unsupported: use_controlling_terminal && is_unsupported_term(),
tty_in,
is_in_a_tty,
tty_out,
Expand Down

0 comments on commit e48ce23

Please sign in to comment.