Verified Commit 0c9ba598 authored by Moritz Sokoll's avatar Moritz Sokoll 🦀
Browse files

reworked implementation of cursor control and display control

parent 827e27bd
Pipeline #317 passed with stages
in 1 minute and 25 seconds
image: rust:1.55.0
before_script:
- make format
build:
stage: build
script:
- make build
- cargo build
tags:
- x86_64
test:
stage: test
script:
- make test
- test test
tags:
- x86_64
[package]
name = "btui"
version = "0.6.6"
version = "0.6.7"
edition = "2018"
authors = ["Moritz Sokoll <moritz@sokoll.com>"]
license = "MIT"
......
all: build test format
build:
cargo build
test:
cargo test
format:
cargo fmt
......@@ -4,12 +4,12 @@
//! with btui you can create beautiful text user interfaces for the terminal.
//! To get started add `btui` as a dependency to your project:
//! ```toml
//! btui = "0.6.6"
//! btui = "0.6.7"
//! ```
//!
//! # Examples
//! This is a basic coloring example which will output hello world in red:
//! ```ignore
//! ```
//! use btui::effects::{Color, Special};
//! use btui::print::{fg, sp};
//!
......@@ -27,14 +27,26 @@ pub mod linux;
/// module containing a progressbar
pub mod pbar;
pub use linux::Terminal;
pub use ft::{effects, print};
#[cfg(test)]
mod tests {
use crate::effects::Color::Black;
use crate::print::fg;
use crate::Terminal;
#[test]
fn correct_color() {
assert_eq!(String::from("\x1b[30m"), fg(Black));
}
#[test]
fn printing_with_terminal() {
let t: Terminal = Terminal::default();
match t.println("Hello World!") {
Ok(_) => (),
Err(e) => panic!("{}", e),
}
}
}
use std::cmp::Ordering;
use std::io::{stderr, stdin, stdout};
use std::io::{Error, ErrorKind, Write};
use std::io::{Stderr, Stdin, Stdout};
use std::ops::Neg;
/// module containig different console actions for linux
#[deprecated(
since = "0.6.7",
note = "all functionality of console is now in a Terminal struct"
)]
pub mod console {
/// enum for display control
pub enum DisplayControl {
......@@ -54,3 +63,169 @@ pub mod console {
print!("{}", seq);
}
}
/// terminal for linux
pub struct Terminal {
stdo: Stdout,
stdi: Stdin,
stde: Stderr,
}
impl Terminal {
// init: {{{
/// construct a new Terminal from the standard libraries handles
pub fn new() -> Terminal {
Terminal {
stdo: stdout(),
stdi: stdin(),
stde: stderr(),
}
}
/// construct a new Terminal from custom handles
pub fn from_handles(stdo: Stdout, stdi: Stdin, stde: Stderr) -> Terminal {
Terminal { stdo, stdi, stde }
}
// }}}
// io: {{{
/// print to stdout with newline
pub fn println<T: std::fmt::Display>(&self, content: T) -> Result<(), Error> {
let mut handle = self.stdo.lock();
match writeln!(handle, "{}\n", content) {
Ok(_) => Ok(()),
Err(_) => Err(Error::new(ErrorKind::Other, "problems writing to stdout")),
}
}
/// print to stdout without newline
pub fn print<T: std::fmt::Display>(&self, content: T) -> Result<(), Error> {
let mut handle = self.stdo.lock();
match write!(handle, "{}", content) {
Ok(_) => Ok(()),
Err(_) => Err(Error::new(ErrorKind::Other, "problems writing to stdout")),
}
}
/// print to stderr with newline
pub fn eprintln<T: std::fmt::Display>(&self, content: T) -> Result<(), Error> {
let mut handle = self.stde.lock();
match writeln!(handle, "{}\n", content) {
Ok(_) => Ok(()),
Err(_) => Err(Error::new(ErrorKind::Other, "problems writing to stdout")),
}
}
/// print to stderr without newline
pub fn eprint<T: std::fmt::Display>(&self, content: T) -> Result<(), Error> {
let mut handle = self.stde.lock();
match write!(handle, "{}", content) {
Ok(_) => Ok(()),
Err(_) => Err(Error::new(ErrorKind::Other, "problems writing to stdout")),
}
}
/// read a line from stdin and trim any whitespace at the end
pub fn read_line_trimmed(&self) -> Result<String, Error> {
let mut input: String = String::new();
match self.stdi.read_line(&mut input) {
Ok(_) => (),
Err(e) => {
return Err(e);
}
}
Ok(input.trim_end().to_string())
}
/// read line from stdin without trimming
pub fn read_line(&self) -> Result<String, Error> {
let mut input: String = String::new();
match self.stdi.read_line(&mut input) {
Ok(_) => (),
Err(e) => {
return Err(e);
}
}
Ok(input)
}
// }}}
// cursor control: {{{
/// move the cursor the indicated amount in the direction
/// # Arguments
/// *`x`: the amuount of columns to move right (can be negative to move left)
/// *`y`: the amount of rows to go down (can be negative to move up)
pub fn move_cursor(&self, x: i32, y: i32) -> Result<(), Error> {
match x.cmp(&0) {
Ordering::Greater => match self.print(format!("\x1b[{}C", x)) {
Ok(_) => (),
Err(e) => {
return Err(e);
}
},
Ordering::Less => match self.print(format!("\x1b[{}C", x)) {
Ok(_) => (),
Err(e) => {
return Err(e);
}
},
Ordering::Equal => (),
}
match y.cmp(&0) {
Ordering::Less => match self.print(format!("\x1b[{}A", y.neg())) {
Ok(_) => (),
Err(e) => {
return Err(e);
}
},
Ordering::Greater => match self.print(format!("\x1b[{}B", y)) {
Ok(_) => (),
Err(e) => {
return Err(e);
}
},
Ordering::Equal => (),
}
Ok(())
}
/// set the cursors position to (x, y)
/// # Arguments
/// *`x`: the x position to move to
/// *`y`: the y position to move to
pub fn set_cursor(&self, x: usize, y: usize) -> Result<(), Error> {
match self.print(format!("\x1b[{};{}H", x, y)) {
Ok(()) => Ok(()),
Err(e) => Err(e),
}
}
/// clear the current line
pub fn clear_line(&self) -> Result<(), Error> {
self.print("\x1b[2K")
}
/// clear the screen
pub fn clear_screen(&self) -> Result<(), Error> {
self.print("\x1b[2J")
}
/// reset the screen
pub fn reset_screen(&self) -> Result<(), Error> {
self.print("\x1bc")
}
// }}}
}
impl Default for Terminal {
fn default() -> Self {
Terminal::new()
}
}
// vim: fdm=marker
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment