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