diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/chapter5/.DS_Store b/chapter5/.DS_Store index 8b3d777..87109d7 100644 Binary files a/chapter5/.DS_Store and b/chapter5/.DS_Store differ diff --git a/chapter6/rstat/src/.DS_Store b/chapter6/rstat/src/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/chapter6/rstat/src/.DS_Store differ diff --git a/chapter7/tui/.DS_Store b/chapter7/tui/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/chapter7/tui/.DS_Store differ diff --git a/chapter7/tui/.gitignore b/chapter7/tui/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/chapter7/tui/.gitignore @@ -0,0 +1 @@ +/target diff --git a/chapter7/tui/Cargo.lock b/chapter7/tui/Cargo.lock new file mode 100644 index 0000000..b3e5c1b --- /dev/null +++ b/chapter7/tui/Cargo.lock @@ -0,0 +1,47 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "libc" +version = "0.2.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" + +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +dependencies = [ + "redox_syscall", +] + +[[package]] +name = "termion" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" +dependencies = [ + "libc", + "numtoa", + "redox_syscall", + "redox_termios", +] + +[[package]] +name = "tui" +version = "0.1.0" +dependencies = [ + "termion", +] diff --git a/chapter7/tui/Cargo.toml b/chapter7/tui/Cargo.toml new file mode 100644 index 0000000..1253afe --- /dev/null +++ b/chapter7/tui/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "tui" +version = "0.1.0" +authors = ["peshwar9"] +edition = "2018" + +[dependencies] +termion = "1.5.5" \ No newline at end of file diff --git a/chapter7/tui/src/.DS_Store b/chapter7/tui/src/.DS_Store new file mode 100644 index 0000000..ed22386 Binary files /dev/null and b/chapter7/tui/src/.DS_Store differ diff --git a/chapter7/tui/src/bin/mouse-events.rs b/chapter7/tui/src/bin/mouse-events.rs new file mode 100644 index 0000000..e2a3613 --- /dev/null +++ b/chapter7/tui/src/bin/mouse-events.rs @@ -0,0 +1,44 @@ +use std::io::{self, Write}; +use termion::cursor::{self, DetectCursorPos}; +use termion::event::*; +use termion::input::{MouseTerminal, TermRead}; +use termion::raw::IntoRawMode; + +fn main() { + let stdin = io::stdin(); + let mut stdout = MouseTerminal::from(io::stdout().into_raw_mode().unwrap()); + + writeln!( + stdout, + "{}{} Type q to exit.", + termion::clear::All, + termion::cursor::Goto(1, 1) + ) + .unwrap(); + + for c in stdin.events() { + let evt = c.unwrap(); + match evt { + Event::Key(Key::Char('q')) => break, + Event::Mouse(m) => match m { + MouseEvent::Press(_, a, b) | MouseEvent::Release(a, b) | MouseEvent::Hold(a, b) => { + write!(stdout, "{}", cursor::Goto(a, b)).unwrap(); + let (x, y) = stdout.cursor_pos().unwrap(); + write!( + stdout, + "{}{}Cursor is at: ({},{}){}", + cursor::Goto(5, 5), + termion::clear::UntilNewline, + x, + y, + cursor::Goto(a, b) + ) + .unwrap(); + } + }, + _ => {} + } + + stdout.flush().unwrap(); + } +} diff --git a/chapter7/tui/src/bin/text-viewer1.rs b/chapter7/tui/src/bin/text-viewer1.rs new file mode 100644 index 0000000..6133322 --- /dev/null +++ b/chapter7/tui/src/bin/text-viewer1.rs @@ -0,0 +1,118 @@ +use std::env::args; +use std::fs; +use std::io::{stdin, stdout, Write}; +use termion::event::Key; +use termion::input::TermRead; +use termion::raw::IntoRawMode; +use termion::{color, style}; +struct Doc { + lines: Vec, +} +#[derive(Debug)] +struct Coordinates { + pub x: usize, + pub y: usize, +} +struct TextViewer { + doc: Doc, + doc_length: usize, + cur_pos: Coordinates, + terminal_size: Coordinates, + file_name: String, +} + +impl TextViewer { + fn init(file_name: &str) -> Self { + let mut doc_file = Doc { lines: vec![] }; + let file_handle = fs::read_to_string(file_name).unwrap(); + for doc_line in file_handle.lines() { + doc_file.lines.push(doc_line.to_string()); + } + let mut doc_length = file_handle.lines().count(); + if doc_length == 0 { + doc_file.lines.push("".into()); + doc_length += 1; + } + let size = termion::terminal_size().unwrap(); + Self { + doc: doc_file, + cur_pos: Coordinates { + x: 1, + y: doc_length, + }, + doc_length: doc_length, + terminal_size: Coordinates { + x: size.0 as usize, + y: size.1 as usize, + }, + file_name: file_name.into(), + } + } + + fn show_document(&mut self) { + let pos = &self.cur_pos; + let (old_x, old_y) = (pos.x, pos.y); + print!("{}{}", termion::clear::All, termion::cursor::Goto(1, 1)); + println!( + "{}{}Welcome to Super text viewer\r{}", + color::Bg(color::Black), + color::Fg(color::White), + style::Reset + ); + for line in 0..self.doc_length { + println!("{}\r", self.doc.lines[line as usize]); + } + + println!( + "{}", + termion::cursor::Goto(0, (self.terminal_size.y - 2) as u16), + ); + println!( + "{}{} line-count={} Filename: {}{}", + color::Fg(color::Red), + style::Bold, + self.doc_length, + self.file_name, + style::Reset + ); + self.set_pos(old_x, old_y); + } + fn set_pos(&mut self, x: usize, y: usize) { + self.cur_pos.x = x; + self.cur_pos.y = y; + println!( + "{}", + termion::cursor::Goto(self.cur_pos.x as u16, (self.cur_pos.y) as u16) + ); + } + + fn run(&mut self) { + let mut stdout = stdout().into_raw_mode().unwrap(); + let stdin = stdin(); + for c in stdin.keys() { + match c.unwrap() { + Key::Ctrl('q') => { + break; + } + _ => {} + } + stdout.flush().unwrap(); + } + } +} + +fn main() { + //Get arguments from command line + let args: Vec = args().collect(); + //Check if file exists. If not, print error message and exit process + if !std::path::Path::new(&args[1]).exists() { + println!("File does not exist"); + std::process::exit(0); + } + // Open file & load into struct + println!("{}", termion::cursor::Show); + // Initialize viewer + let mut viewer = TextViewer::init(&args[1]); + viewer.show_document(); + viewer.run(); +} diff --git a/chapter7/tui/src/bin/text-viewer2.rs b/chapter7/tui/src/bin/text-viewer2.rs new file mode 100644 index 0000000..ca5e68b --- /dev/null +++ b/chapter7/tui/src/bin/text-viewer2.rs @@ -0,0 +1,188 @@ +use std::env::args; +use std::fs; +use std::io::{stdin, stdout, Write}; +use termion::event::Key; +use termion::input::TermRead; +use termion::raw::IntoRawMode; +use termion::{color, style}; +struct TextViewer { + doc: Doc, + doc_length: usize, + cur_pos: Coordinates, + terminal_size: Coordinates, + file_name: String, +} +impl TextViewer { + fn init(file_name: &str) -> Self { + let mut doc_file = Doc { lines: vec![] }; + let file_handle = fs::read_to_string(file_name).unwrap(); + for doc_line in file_handle.lines() { + doc_file.lines.push(doc_line.to_string()); + } + let mut doc_length = file_handle.lines().count(); + if doc_length == 0 { + doc_file.lines.push("".into()); + doc_length += 1; + } + let size = termion::terminal_size().unwrap(); + Self { + doc: doc_file, + cur_pos: Coordinates { + x: 1, + y: doc_length, + }, + doc_length: doc_length, + terminal_size: Coordinates { + x: size.0 as usize, + y: size.1 as usize, + }, + file_name: file_name.into(), + } + } + + fn show_document(&mut self) { + let pos = &self.cur_pos; + let (old_x, old_y) = (pos.x, pos.y); + print!("{}{}", termion::clear::All, termion::cursor::Goto(1, 1)); + println!( + "{}{}Welcome to Super text viewer\r{}", + color::Bg(color::Black), + color::Fg(color::White), + style::Reset + ); + if self.doc_length < self.terminal_size.y { + for line in 0..self.doc_length { + println!("{}\r", self.doc.lines[line as usize]); + } + } else { + if pos.y <= self.terminal_size.y { + for line in 0..self.terminal_size.y - 3 { + println!("{}\r", self.doc.lines[line as usize]); + } + } else { + for line in pos.y - (self.terminal_size.y - 3)..pos.y { + println!("{}\r", self.doc.lines[line as usize]); + } + } + } + println!( + "{}", + termion::cursor::Goto(0, (self.terminal_size.y - 2) as u16), + ); + println!( + "{}X={},Y={}, line-count={} Filename: {}{}", + color::Fg(color::Red), + old_x, + old_y, + self.doc_length, + self.file_name, + style::Reset + ); + self.set_pos(old_x, old_y); + } + fn set_pos(&mut self, x: usize, y: usize) { + self.cur_pos.x = x; + self.cur_pos.y = y; + println!( + "{}", + termion::cursor::Goto(self.cur_pos.x as u16, (self.cur_pos.y) as u16) + ); + } + fn inc_x(&mut self) { + if self.cur_pos.x < self.terminal_size.x { + self.cur_pos.x += 1; + } + println!( + "{}", + termion::cursor::Goto(self.cur_pos.x as u16, self.cur_pos.y as u16) + ); + } + fn dec_x(&mut self) { + if self.cur_pos.x > 1 { + self.cur_pos.x -= 1; + } + println!( + "{}", + termion::cursor::Goto(self.cur_pos.x as u16, self.cur_pos.y as u16) + ); + } + fn inc_y(&mut self) { + if self.cur_pos.y < self.doc_length { + self.cur_pos.y += 1; + } + + println!( + "{}", + termion::cursor::Goto(self.cur_pos.x as u16, self.cur_pos.y as u16) + ); + } + fn dec_y(&mut self) { + if self.cur_pos.y > 1 { + self.cur_pos.y -= 1; + } + println!( + "{}", + termion::cursor::Goto(self.cur_pos.x as u16, self.cur_pos.y as u16) + ); + } + + fn run(&mut self) { + let mut stdout = stdout().into_raw_mode().unwrap(); + let stdin = stdin(); + for c in stdin.keys() { + match c.unwrap() { + Key::Ctrl('q') => { + break; + } + Key::Left => { + self.dec_x(); + self.show_document(); + } + Key::Right => { + self.inc_x(); + self.show_document(); + } + Key::Up => { + self.dec_y(); + self.show_document(); + } + Key::Down => { + self.inc_y(); + self.show_document(); + } + Key::Backspace => { + self.dec_x(); + } + _ => {} + } + stdout.flush().unwrap(); + } + } +} +struct Doc { + lines: Vec, +} +#[derive(Debug)] +struct Coordinates { + pub x: usize, + pub y: usize, +} +fn main() { + //Get arguments from command line + let args: Vec = args().collect(); + //Check if file exists. If not, print error message and exit process + if !std::path::Path::new(&args[1]).exists() { + println!("File does not exist"); + std::process::exit(0); + } + // Clear full screen + println!("{}", termion::clear::All); + // Open file & load into struct + println!("{}", termion::cursor::Show); + println!("{}", termion::cursor::Goto(1, 1)); + // Initialize editor + let mut editor = TextViewer::init(&args[1]); + editor.show_document(); + editor.set_pos(1, 1); + editor.run(); +}