mirror of
https://github.com/Xyverle/neutuino.git
synced 2026-08-29 10:50:03 -04:00
0.3.0, I really need to start breaking up these updates
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -4,4 +4,4 @@ version = 4
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neutuino"
|
name = "neutuino"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "neutuino"
|
name = "neutuino"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
repository = "https://github.com/Xyverle/neutuino"
|
repository = "https://github.com/Xyverle/neutuino"
|
||||||
description = "A minimal zero-dependancy pure-rust cross-platform TUI library"
|
description = "A minimal zero-dependancy pure-rust cross-platform TUI library"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Neutuino
|
# Neutuino
|
||||||
Zero dependancy cross-platform pure-rust simple TUI library
|
Zero dependancy cross-platform pure-rust simple TUI library
|
||||||
|
|
||||||
Supported OSes: Windows 10+, MacOS (untested), Linux
|
Supported OSes: Windows 10+, MacOS (untested), and Linux
|
||||||
|
|
||||||
This project is still highly work in progress and it will be a decent while until feature completeness
|
This project is still highly work in progress and it will be a decent while until feature completeness
|
||||||
|
|
||||||
## Todo
|
## Roadmap
|
||||||
- [x] Output (Unix)
|
- [x] Output (Unix)
|
||||||
- [x] Output (Windows)
|
- [x] Output (Windows)
|
||||||
- [x] Input (Unix) (Appears to work, more testing needed)
|
- [x] Input (Unix) (Appears to work, more testing needed)
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
use neutuino::ansi::{
|
use neutuino::prelude::*;
|
||||||
COLORS_BG, COLORS_FG, STYLE_BOLD, STYLE_ITALIC, STYLE_RESET, STYLE_UNDERLINE,
|
|
||||||
move_cursor_to_column, set_window_title,
|
|
||||||
};
|
|
||||||
use neutuino::input::{Event, KeyEvent, poll_input};
|
|
||||||
use neutuino::os::{disable_raw_mode, enable_ansi, enable_raw_mode, get_terminal_size};
|
|
||||||
use std::{io, time::Duration};
|
use std::{io, time::Duration};
|
||||||
|
|
||||||
fn print_line_style_reset(string: &str) {
|
fn print_line_style_reset(string: &str) {
|
||||||
@@ -16,13 +11,13 @@ fn main() -> io::Result<()> {
|
|||||||
let all_styles = format!("{STYLE_BOLD}{STYLE_ITALIC}{STYLE_UNDERLINE}");
|
let all_styles = format!("{STYLE_BOLD}{STYLE_ITALIC}{STYLE_UNDERLINE}");
|
||||||
|
|
||||||
enable_ansi()?;
|
enable_ansi()?;
|
||||||
enable_raw_mode()?;
|
let _raw_terminal = RawModeHandler::new()?;
|
||||||
|
|
||||||
println!("q to quit{}", move_cursor_to_column(0));
|
println!("q to quit{}", move_cursor_to_column(0));
|
||||||
let next = |x: usize| (x + 1) % COLORS_FG.len();
|
let next = |x: usize| (x + 1) % COLORS_FG.len();
|
||||||
|
|
||||||
let terminal_size = get_terminal_size()?;
|
let terminal_size = get_terminal_size()?;
|
||||||
let terminal_size_str = format!("{terminal_size:?}");
|
let terminal_size_str = format!("{:?}", terminal_size);
|
||||||
print!("{}", set_window_title(terminal_size_str).unwrap());
|
print!("{}", set_window_title(terminal_size_str).unwrap());
|
||||||
|
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
@@ -45,6 +40,5 @@ fn main() -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
counter = next(counter);
|
counter = next(counter);
|
||||||
}
|
}
|
||||||
disable_raw_mode()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
34
examples/simple.rs
Normal file
34
examples/simple.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
|
use neutuino::prelude::*;
|
||||||
|
use std::{
|
||||||
|
io::{self, Write},
|
||||||
|
thread, time,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
enable_ansi()?;
|
||||||
|
|
||||||
|
// makes the terminal raw until this value is dropped
|
||||||
|
let _raw_terminal = RawModeHandler::new()?;
|
||||||
|
let _alt_screen = AltScreenHandler::new()?;
|
||||||
|
|
||||||
|
// gets the size of the terminal
|
||||||
|
let terminal_size = get_terminal_size()?;
|
||||||
|
let middle = (terminal_size.0 / 2, terminal_size.1 / 2);
|
||||||
|
|
||||||
|
let string = "Hello, World!";
|
||||||
|
|
||||||
|
let adjusted_middle = (middle.0 - ((string.len() / 2) as u16), middle.1);
|
||||||
|
|
||||||
|
print!(
|
||||||
|
"{COLOR_RED_BG}{}{string}",
|
||||||
|
move_cursor_to_position(adjusted_middle.0, adjusted_middle.1)
|
||||||
|
);
|
||||||
|
io::stdout().flush()?; // VERY IMPORTANT!
|
||||||
|
|
||||||
|
thread::sleep(time::Duration::new(3, 0));
|
||||||
|
|
||||||
|
// no flush needed here as the program is about to end and it will be auto flushed
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
96
src/ansi.rs
96
src/ansi.rs
@@ -4,21 +4,21 @@
|
|||||||
//!
|
//!
|
||||||
//! For these to work on Windows you need to run the `enable_ansi` function in the os module
|
//! For these to work on Windows you need to run the `enable_ansi` function in the os module
|
||||||
|
|
||||||
/// Sets the terminal to an arbitrary 12-bit/truecolor color
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
/// Sets the terminal to an arbitrary 12-bit/truecolor color in the foreground when printed
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn rgb_color_code_fg(red: u8, green: u8, blue: u8) -> String {
|
pub fn rgb_color_code_fg(red: u8, green: u8, blue: u8) -> String {
|
||||||
format!("\x1b[38;2;{red};{green};{blue}m")
|
format!("\x1b[38;2;{red};{green};{blue}m")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the terminal to an arbitrary 12-bit/truecolor color
|
/// Sets the terminal to an arbitrary 12-bit/truecolor color in the background when printed
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn rgb_color_code_bg(red: u8, green: u8, blue: u8) -> String {
|
pub fn rgb_color_code_bg(red: u8, green: u8, blue: u8) -> String {
|
||||||
format!("\x1b[48;2;{red};{green};{blue}m")
|
format!("\x1b[48;2;{red};{green};{blue}m")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the title of the window
|
/// Sets the title of the window when printed
|
||||||
///
|
|
||||||
/// The title must be only in ASCII characters or **weird** things will happen
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn set_window_title<T: Into<String>>(title: T) -> Option<String> {
|
pub fn set_window_title<T: Into<String>>(title: T) -> Option<String> {
|
||||||
let title = title.into();
|
let title = title.into();
|
||||||
@@ -28,31 +28,31 @@ pub fn set_window_title<T: Into<String>>(title: T) -> Option<String> {
|
|||||||
Some(format!("\x1b]0;{title}\x1b\x5c"))
|
Some(format!("\x1b]0;{title}\x1b\x5c"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the cursor up {num} characters
|
/// Moves the cursor up {num} characters when printed
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn move_cursor_up(num: u16) -> String {
|
pub fn move_cursor_up(num: u16) -> String {
|
||||||
format!("\x1b[{num}A")
|
format!("\x1b[{num}A")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the cursor down {num} characters
|
/// Moves the cursor down {num} characters when printed
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn move_cursor_down(num: u16) -> String {
|
pub fn move_cursor_down(num: u16) -> String {
|
||||||
format!("\x1b[{num}B")
|
format!("\x1b[{num}B")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the cursor right {num} characters
|
/// Moves the cursor right {num} characters when printed
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn move_cursor_right(num: u16) -> String {
|
pub fn move_cursor_right(num: u16) -> String {
|
||||||
format!("\x1b[{num}C")
|
format!("\x1b[{num}C")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the cursor left {num} characters
|
/// Moves the cursor left {num} characters when printed
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn move_cursor_left(num: u16) -> String {
|
pub fn move_cursor_left(num: u16) -> String {
|
||||||
format!("\x1b[{num}A")
|
format!("\x1b[{num}A")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the cursor to {row}
|
/// Moves the cursor to {row} when printed
|
||||||
///
|
///
|
||||||
/// Origin is 0, 0
|
/// Origin is 0, 0
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -60,7 +60,7 @@ pub fn move_cursor_to_row(line: u16) -> String {
|
|||||||
format!("\x1b[{}d", line.saturating_add(1))
|
format!("\x1b[{}d", line.saturating_add(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the cursor to {column}
|
/// Moves the cursor to {column} when printed
|
||||||
///
|
///
|
||||||
/// Origin is 0, 0
|
/// Origin is 0, 0
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -68,7 +68,7 @@ pub fn move_cursor_to_column(column: u16) -> String {
|
|||||||
format!("\x1b[{}G", column.saturating_add(1))
|
format!("\x1b[{}G", column.saturating_add(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves the cursor to Position {x}, {y}
|
/// Moves the cursor to Position {x}, {y} when printed
|
||||||
///
|
///
|
||||||
/// Origin is 0, 0
|
/// Origin is 0, 0
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -250,3 +250,75 @@ pub const COLORS: [(&str, &str); 9] = [
|
|||||||
(COLOR_WHITE_FG, COLOR_WHITE_BG),
|
(COLOR_WHITE_FG, COLOR_WHITE_BG),
|
||||||
(COLOR_DEFAULT_FG, COLOR_DEFAULT_BG),
|
(COLOR_DEFAULT_FG, COLOR_DEFAULT_BG),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Struct that prints `ALT_SCREEN_ENTER` on construction
|
||||||
|
/// and `ALT_SCREEN_EXIT` on destruction
|
||||||
|
///
|
||||||
|
/// Prefered over function as it prints `ALT_SCREEN_EXIT` on panic
|
||||||
|
pub struct AltScreenHandler {
|
||||||
|
enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AltScreenHandler {
|
||||||
|
/// Creates a new instance and sets the terminal into the alternate screen
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If it fails to print or flush the output
|
||||||
|
pub fn new() -> io::Result<Self> {
|
||||||
|
print!("{ALT_SCREEN_ENTER}");
|
||||||
|
io::stdout().flush()?;
|
||||||
|
Ok(Self { enabled: true })
|
||||||
|
}
|
||||||
|
/// Enables raw mode
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Never errors if the alt screen is already enabled
|
||||||
|
///
|
||||||
|
/// If it fails to print or flush the output
|
||||||
|
pub fn enable(&mut self) -> io::Result<()> {
|
||||||
|
self.set(true)
|
||||||
|
}
|
||||||
|
/// Disables raw mode
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Never errors if the alt screen is already disabled
|
||||||
|
///
|
||||||
|
/// If it fails to print or flush the output
|
||||||
|
pub fn disable(&mut self) -> io::Result<()> {
|
||||||
|
self.set(false)
|
||||||
|
}
|
||||||
|
/// Sets raw mode
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Never errors if the alt screen is in the same state as the boolean
|
||||||
|
///
|
||||||
|
/// If it fails to print or flush the output
|
||||||
|
pub fn set(&mut self, alt: bool) -> io::Result<()> {
|
||||||
|
if self.enabled == alt {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if alt {
|
||||||
|
print!("{ALT_SCREEN_ENTER}");
|
||||||
|
} else {
|
||||||
|
print!("{ALT_SCREEN_EXIT}");
|
||||||
|
}
|
||||||
|
io::stdout().flush()?;
|
||||||
|
self.enabled = alt;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// Gets if the alt screen is enabled
|
||||||
|
#[must_use]
|
||||||
|
pub fn get(&self) -> bool {
|
||||||
|
self.enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for AltScreenHandler {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.disable().expect("Failed to disable alternate screen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
69
src/input.rs
69
src/input.rs
@@ -0,0 +1,69 @@
|
|||||||
|
//! Various input functions, structs, etc.
|
||||||
|
//!
|
||||||
|
//! Very incomplete currently
|
||||||
|
|
||||||
|
/// Different events that can happen through the terminal
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Event {
|
||||||
|
/// An event that happens upon a key being pressed
|
||||||
|
Key(KeyEvent),
|
||||||
|
/// An event that happens upon focus to the terminal window being gained
|
||||||
|
FocusGained,
|
||||||
|
/// An event that happens upon focus to the terminal window being lost
|
||||||
|
FocusLost,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An event that happens upon a key being pressed
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum KeyEvent {
|
||||||
|
/// The Backspace key
|
||||||
|
Backspace,
|
||||||
|
/// The Up arrow key
|
||||||
|
Up,
|
||||||
|
/// The Down arrow key
|
||||||
|
Down,
|
||||||
|
/// The Left arrow key
|
||||||
|
Left,
|
||||||
|
/// The Right arrow key
|
||||||
|
Right,
|
||||||
|
/// The Home key
|
||||||
|
Home,
|
||||||
|
/// The End key
|
||||||
|
End,
|
||||||
|
/// The PageUp key
|
||||||
|
PageUp,
|
||||||
|
/// The PageDown key
|
||||||
|
PageDown,
|
||||||
|
/// The Tab key
|
||||||
|
Tab,
|
||||||
|
/// Shift + Tab key
|
||||||
|
ShiftTab,
|
||||||
|
/// The delete key
|
||||||
|
Delete,
|
||||||
|
/// The insert key
|
||||||
|
Insert,
|
||||||
|
/// The f1-f12 keys
|
||||||
|
F(u8),
|
||||||
|
/// Any character inputted by the keyboard
|
||||||
|
Char(char),
|
||||||
|
/// Ctrl + Char
|
||||||
|
Ctrl(char),
|
||||||
|
/// The Escape key
|
||||||
|
Escape,
|
||||||
|
/// A null byte sent to the terminal
|
||||||
|
///
|
||||||
|
/// Can mean several different things
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<KeyEvent> for Event {
|
||||||
|
fn from(value: KeyEvent) -> Self {
|
||||||
|
Self::Key(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub use crate::unix::input::*;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub use crate::windows::input::*;
|
||||||
|
|||||||
77
src/lib.rs
77
src/lib.rs
@@ -1,62 +1,35 @@
|
|||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
// this lint has way too many false positives
|
||||||
pub mod ansi;
|
#![allow(clippy::doc_markdown)]
|
||||||
|
//! This crate is a simple and minimal TUI library that supports the following OSes:
|
||||||
|
//! - Windows 10+
|
||||||
|
//! - MacOS (currently untested)
|
||||||
|
//! - Linux
|
||||||
|
//!
|
||||||
|
//! ## Roadmap
|
||||||
|
//! - [x] Output (Unix)
|
||||||
|
//! - [x] Output (Windows)
|
||||||
|
//! - [x] Input (Unix) (Appears to work, more testing needed)
|
||||||
|
//! - [ ] Input (Windows) (WIP)
|
||||||
|
//! - [ ] Events (Focus reporting, Bracketed-paste) (Unix)
|
||||||
|
//! - [ ] Events (Focus reporting, Bracketed-paste) (Windows)
|
||||||
|
//! - [ ] Mouse input (Unix)
|
||||||
|
//! - [ ] Mouse input (Windows)
|
||||||
|
//! - [ ] Feature completeness / API cleanup
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mod unix;
|
mod unix;
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub use crate::unix::*;
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod windows;
|
mod windows;
|
||||||
|
|
||||||
#[cfg(windows)]
|
pub mod ansi;
|
||||||
pub use crate::windows::*;
|
pub mod input;
|
||||||
|
pub mod os;
|
||||||
|
|
||||||
pub mod input {
|
pub mod prelude {
|
||||||
//! Various input functions, structs, etc.
|
//! Covenience re-export of common members
|
||||||
//!
|
pub use crate::ansi::*;
|
||||||
//! Very incomplete currently
|
pub use crate::input::*;
|
||||||
|
pub use crate::os::*;
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum Event {
|
|
||||||
Key(KeyEvent),
|
|
||||||
FocusGained,
|
|
||||||
FocusLost,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum KeyEvent {
|
|
||||||
Backspace,
|
|
||||||
Up,
|
|
||||||
Down,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Home,
|
|
||||||
End,
|
|
||||||
PageUp,
|
|
||||||
PageDown,
|
|
||||||
Tab,
|
|
||||||
BackTab,
|
|
||||||
Delete,
|
|
||||||
Insert,
|
|
||||||
F(u8),
|
|
||||||
Char(char),
|
|
||||||
Ctrl(char),
|
|
||||||
Escape,
|
|
||||||
Null,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<KeyEvent> for Event {
|
|
||||||
fn from(value: KeyEvent) -> Self {
|
|
||||||
Self::Key(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub use crate::unix::input::*;
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub use crate::windows::input::*;
|
|
||||||
}
|
}
|
||||||
|
|||||||
88
src/os.rs
88
src/os.rs
@@ -1,5 +1,89 @@
|
|||||||
//! Collection of functions that help control the terminal
|
//! Collection of functions that help control the terminal
|
||||||
//!
|
//!
|
||||||
//! These are built to work at least on these platforms:
|
//! These are built to work on Windows, Linux, and MacOS
|
||||||
//! Windows, Linux, and Mac, but are likely to work on more
|
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub use crate::unix::os::*;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub use crate::windows::os::*;
|
||||||
|
|
||||||
|
/// Struct that calls `enable_raw_mode` on construction
|
||||||
|
/// and `disable_raw_mode` on destruction
|
||||||
|
///
|
||||||
|
/// Prefered over function as it calls `disable_raw_mode` on panic
|
||||||
|
pub struct RawModeHandler {
|
||||||
|
enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawModeHandler {
|
||||||
|
/// Creates a new instance and sets the terminal to raw mode
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If there is no stdin,
|
||||||
|
/// stdin is not a tty,
|
||||||
|
/// or it fails to change terminal settings
|
||||||
|
pub fn new() -> io::Result<Self> {
|
||||||
|
enable_raw_mode()?;
|
||||||
|
Ok(Self { enabled: true })
|
||||||
|
}
|
||||||
|
/// Enables raw mode
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Never errors if raw mode is already enabled
|
||||||
|
///
|
||||||
|
/// If there is no stdin,
|
||||||
|
/// stdin is not a tty,
|
||||||
|
/// or it fails to change terminal settings
|
||||||
|
pub fn enable(&mut self) -> io::Result<()> {
|
||||||
|
self.set(true)
|
||||||
|
}
|
||||||
|
/// Disables raw mode
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Never errors if raw mode is already disabled
|
||||||
|
///
|
||||||
|
/// If there is no stdin,
|
||||||
|
/// stdin is not a tty,
|
||||||
|
/// or it fails to change terminal settings
|
||||||
|
pub fn disable(&mut self) -> io::Result<()> {
|
||||||
|
self.set(false)
|
||||||
|
}
|
||||||
|
/// Sets raw mode
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Never errors if raw mode is in the same state as the boolean
|
||||||
|
///
|
||||||
|
/// If there is no stdin,
|
||||||
|
/// stdin is not a tty,
|
||||||
|
/// or it fails to change terminal settings
|
||||||
|
pub fn set(&mut self, raw: bool) -> io::Result<()> {
|
||||||
|
if self.enabled == raw {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if raw {
|
||||||
|
enable_raw_mode()?;
|
||||||
|
} else {
|
||||||
|
disable_raw_mode()?;
|
||||||
|
}
|
||||||
|
self.enabled = raw;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// Gets if raw mode is enabled
|
||||||
|
#[must_use]
|
||||||
|
pub fn get(&self) -> bool {
|
||||||
|
self.enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for RawModeHandler {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.disable().expect("Failed to disable terminal raw mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ unsafe extern "C" {
|
|||||||
|
|
||||||
const STDIN_FILENO: c_int = 0;
|
const STDIN_FILENO: c_int = 0;
|
||||||
const STDOUT_FILENO: c_int = 1;
|
const STDOUT_FILENO: c_int = 1;
|
||||||
pub const POLLIN: c_short = 1;
|
const POLLIN: c_short = 1;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(not(target_os = "macos"))]
|
||||||
const TIOCGWINSZ: c_ulong = 0x5413;
|
const TIOCGWINSZ: c_ulong = 0x5413;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(not(target_os = "macos"))]
|
||||||
const NCCS: usize = 0x20;
|
const NCCS: usize = 0x20;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
@@ -276,7 +276,7 @@ pub mod input {
|
|||||||
Some(Ok(b'B')) => Some(Event::Key(KeyEvent::Down)),
|
Some(Ok(b'B')) => Some(Event::Key(KeyEvent::Down)),
|
||||||
Some(Ok(b'H')) => Some(Event::Key(KeyEvent::Home)),
|
Some(Ok(b'H')) => Some(Event::Key(KeyEvent::Home)),
|
||||||
Some(Ok(b'F')) => Some(Event::Key(KeyEvent::End)),
|
Some(Ok(b'F')) => Some(Event::Key(KeyEvent::End)),
|
||||||
Some(Ok(b'Z')) => Some(Event::Key(KeyEvent::BackTab)),
|
Some(Ok(b'Z')) => Some(Event::Key(KeyEvent::ShiftTab)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ pub mod input {
|
|||||||
0x08 => KeyEvent::Backspace, // VK_BACK
|
0x08 => KeyEvent::Backspace, // VK_BACK
|
||||||
0x09 => {
|
0x09 => {
|
||||||
if shift {
|
if shift {
|
||||||
KeyEvent::BackTab
|
KeyEvent::ShiftTab
|
||||||
} else {
|
} else {
|
||||||
KeyEvent::Tab
|
KeyEvent::Tab
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user