mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-10 03:10:41 +00:00
Add methods to initialize backends from stdio
This commit is contained in:
parent
b4dfaf4d9f
commit
bf25cb90ae
@ -1,11 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## Next version (cursive-core 0.1.2)
|
||||
## Next version (cursive-core 0.1.2, cursive 0.15.1)
|
||||
|
||||
### API updates
|
||||
|
||||
- Add `ProgressBar::set_{min,max,range,counter,label}` for non-chained API.
|
||||
- Derive Clone, Copy, Debug, PartialEq, Hash for more types.
|
||||
- Add backend initializers using other files than /dev/tty for ncurses and termion.
|
||||
|
||||
### Improvements
|
||||
|
||||
|
@ -193,6 +193,7 @@ impl Backend {
|
||||
{
|
||||
enable_raw_mode()?;
|
||||
|
||||
// TODO: Use the stdout we define down there
|
||||
execute!(
|
||||
io::stdout(),
|
||||
EnterAlternateScreen,
|
||||
|
@ -56,7 +56,24 @@ fn write_to_tty(bytes: &[u8]) -> io::Result<()> {
|
||||
|
||||
impl Backend {
|
||||
/// Creates a new ncurses-based backend.
|
||||
///
|
||||
/// Uses `/dev/tty` for input/output.
|
||||
pub fn init() -> io::Result<Box<dyn backend::Backend>> {
|
||||
Self::init_with_files("/dev/tty", "/dev/tty")
|
||||
}
|
||||
|
||||
/// Creates a new ncurses-based backend.
|
||||
///
|
||||
/// Uses stdin/stdout for input/output.
|
||||
pub fn init_stdio() -> io::Result<Box<dyn backend::Backend>> {
|
||||
Self::init_with_files("/dev/stdin", "/dev/stdout")
|
||||
}
|
||||
|
||||
/// Creates a new ncurses-based backend using the given files for input/output.
|
||||
pub fn init_with_files(
|
||||
input_path: &str,
|
||||
output_path: &str,
|
||||
) -> io::Result<Box<dyn backend::Backend>> {
|
||||
// Check the $TERM variable.
|
||||
if std::env::var("TERM")
|
||||
.map(|var| var.is_empty())
|
||||
@ -79,10 +96,17 @@ impl Backend {
|
||||
|
||||
// Don't output to standard IO, directly feed into /dev/tty
|
||||
// This leaves stdin and stdout usable for other purposes.
|
||||
let tty_path = CString::new("/dev/tty").unwrap();
|
||||
let mode = CString::new("r+").unwrap();
|
||||
let tty = unsafe { libc::fopen(tty_path.as_ptr(), mode.as_ptr()) };
|
||||
ncurses::newterm(None, tty, tty);
|
||||
let input = {
|
||||
let mode = CString::new("r").unwrap();
|
||||
let path = CString::new(input_path).unwrap();
|
||||
unsafe { libc::fopen(path.as_ptr(), mode.as_ptr()) }
|
||||
};
|
||||
let output = {
|
||||
let mode = CString::new("w").unwrap();
|
||||
let path = CString::new(output_path).unwrap();
|
||||
unsafe { libc::fopen(path.as_ptr(), mode.as_ptr()) }
|
||||
};
|
||||
ncurses::newterm(None, output, input);
|
||||
// Enable keypad (like arrows)
|
||||
ncurses::keypad(ncurses::stdscr(), true);
|
||||
|
||||
|
@ -29,6 +29,7 @@ use std::thread;
|
||||
|
||||
/// Backend using termion
|
||||
pub struct Backend {
|
||||
// Do we want to make this generic on the writer?
|
||||
terminal:
|
||||
RefCell<AlternateScreen<MouseTerminal<RawTerminal<BufWriter<File>>>>>,
|
||||
current_style: Cell<theme::ColorPair>,
|
||||
@ -42,12 +43,35 @@ pub struct Backend {
|
||||
|
||||
impl Backend {
|
||||
/// Creates a new termion-based backend.
|
||||
///
|
||||
/// Uses `/dev/tty` for input and output.
|
||||
pub fn init() -> std::io::Result<Box<dyn backend::Backend>> {
|
||||
Self::init_with_files(
|
||||
File::open("/dev/tty")?,
|
||||
File::create("/dev/tty")?,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new termion-based backend.
|
||||
///
|
||||
/// Uses `stdin` and `stdout` for input/output.
|
||||
pub fn init_stdio() -> std::io::Result<Box<dyn backend::Backend>> {
|
||||
Self::init_with_files(
|
||||
File::open("/dev/stdin")?,
|
||||
File::create("/dev/stdout")?,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new termion-based backend using the given input and output files.
|
||||
pub fn init_with_files(
|
||||
input: File,
|
||||
output: File,
|
||||
) -> std::io::Result<Box<dyn backend::Backend>> {
|
||||
// Use a ~8MB buffer
|
||||
// Should be enough for a single screen most of the time.
|
||||
let terminal =
|
||||
RefCell::new(AlternateScreen::from(MouseTerminal::from(
|
||||
BufWriter::with_capacity(8_000_000, File::create("/dev/tty")?)
|
||||
BufWriter::with_capacity(8_000_000, output_file?)
|
||||
.into_raw_mode()?,
|
||||
)));
|
||||
|
||||
@ -67,7 +91,7 @@ impl Backend {
|
||||
// We want nonblocking input, but termion is blocking by default
|
||||
// Read input from a separate thread
|
||||
thread::spawn(move || {
|
||||
let input = std::fs::File::open("/dev/tty").unwrap();
|
||||
let input = input_file.unwrap();
|
||||
let mut events = input.events();
|
||||
|
||||
// Take all the events we can
|
||||
@ -244,7 +268,7 @@ impl backend::Backend for Backend {
|
||||
|
||||
fn screen_size(&self) -> Vec2 {
|
||||
// TODO: termion::terminal_size currently requires stdout.
|
||||
// When available, we should try to use /dev/tty instead.
|
||||
// When available, we should try to use self.terminal or something instead.
|
||||
let (x, y) = termion::terminal_size().unwrap_or((1, 1));
|
||||
(x, y).into()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user