Extract several components into crates

This commit is contained in:
Savanni D'Gerinel 2024-05-06 00:58:17 -04:00
parent 61127339bc
commit 4a62372fd3
3 changed files with 127 additions and 111 deletions

View File

@ -1,12 +1,14 @@
mod state;
mod types;
use crossterm::{ use crossterm::{
event::{self, KeyCode, KeyEvent, KeyModifiers}, event::{self, KeyCode, KeyEvent, KeyModifiers},
terminal::{disable_raw_mode, enable_raw_mode}, terminal::{disable_raw_mode, enable_raw_mode},
}; };
use state::AppState;
use std::{ use std::{
env, env,
fs::File, io,
io::{self, BufRead, BufReader, Read},
path::PathBuf,
sync::mpsc, sync::mpsc,
thread, thread,
time::{Duration, Instant}, time::{Duration, Instant},
@ -23,112 +25,6 @@ const TITLE: &str = "Text Editor Challenge";
const COPYRIGHT: &str = "(c) Savanni D'Gerinel - all rights reserved"; const COPYRIGHT: &str = "(c) Savanni D'Gerinel - all rights reserved";
const TICK_RATE_MS: u64 = 200; const TICK_RATE_MS: u64 = 200;
#[derive(Default)]
struct Document {
rows: Vec<String>
}
impl Document {
fn contents(&self) -> String {
self.rows.join("\n")
}
fn row_length(&self, idx: usize) -> usize {
self.rows[idx].len()
}
fn row_count(&self) -> usize {
self.rows.len()
}
}
#[derive(Default)]
struct AppState {
path: Option<PathBuf>,
cursor: Cursor,
contents: Document, // Obviously this is bad, but it's also only temporary.
}
impl AppState {
fn open(path: PathBuf) -> Self {
let mut file = File::open(path.clone()).unwrap();
let mut reader = BufReader::new(file);
let contents = reader
.lines()
.collect::<Result<Vec<String>, std::io::Error>>()
.unwrap();
Self {
path: Some(path),
cursor: Default::default(),
contents: Document{ rows: contents },
}
}
fn cursor_up(&mut self) {
self.cursor.cursor_up(&self.contents);
}
fn cursor_down(&mut self) {
self.cursor.cursor_down(&self.contents);
}
fn cursor_right(&mut self) {
self.cursor.cursor_right(&self.contents);
}
fn cursor_left(&mut self) {
self.cursor.cursor_left();
}
}
#[derive(Default)]
struct Cursor {
row: usize,
column: usize,
desired_column: usize,
}
impl Cursor {
fn cursor_up(&mut self, doc: &Document) {
if self.row > 0 {
self.row -= 1;
}
self.correct_columns(doc);
}
fn cursor_down(&mut self, doc: &Document) {
if self.row < doc.row_count() - 1 {
self.row += 1;
}
self.correct_columns(doc);
}
fn correct_columns(&mut self, doc: &Document) {
let row_len = doc.row_length(self.row);
if self.desired_column < row_len {
self.column = self.desired_column;
} else {
self.column = row_len;
}
}
fn cursor_right(&mut self, doc: &Document) {
if self.column < doc.row_length(self.row) {
self.column += 1;
}
self.desired_column = self.column;
}
fn cursor_left(&mut self) {
if self.column > 0 {
self.column -= 1;
}
self.desired_column = self.column;
}
}
fn render<T>(app_state: &AppState, terminal: &mut Terminal<T>) -> Result<(), anyhow::Error> fn render<T>(app_state: &AppState, terminal: &mut Terminal<T>) -> Result<(), anyhow::Error>
where where
T: tui::backend::Backend, T: tui::backend::Backend,
@ -183,8 +79,9 @@ where
rect.render_widget(contents, chunks[1]); rect.render_widget(contents, chunks[1]);
// TODO: keeping track of the index of the top row and subtract that from the cursor row. // TODO: keeping track of the index of the top row and subtract that from the cursor row.
let row = app_state.cursor.row as u16; let (row, column) = app_state.cursor.addr();
let column = app_state.cursor.column as u16; let row = row as u16;
let column = column as u16;
rect.set_cursor(chunks[1].x + column, chunks[1].y + row); rect.set_cursor(chunks[1].x + column, chunks[1].y + row);
})?; })?;
Ok(()) Ok(())

View File

@ -0,0 +1,42 @@
use crate::types::{Cursor, Document};
use std::{fs::File, io::{BufRead, BufReader}, path::PathBuf};
#[derive(Default)]
pub struct AppState {
pub path: Option<PathBuf>,
pub cursor: Cursor,
pub contents: Document, // Obviously this is bad, but it's also only temporary.
}
impl AppState {
pub fn open(path: PathBuf) -> Self {
let file = File::open(path.clone()).unwrap();
let reader = BufReader::new(file);
let contents = reader
.lines()
.collect::<Result<Vec<String>, std::io::Error>>()
.unwrap();
Self {
path: Some(path),
cursor: Default::default(),
contents: Document::new(contents),
}
}
pub fn cursor_up(&mut self) {
self.cursor.cursor_up(&self.contents);
}
pub fn cursor_down(&mut self) {
self.cursor.cursor_down(&self.contents);
}
pub fn cursor_right(&mut self) {
self.cursor.cursor_right(&self.contents);
}
pub fn cursor_left(&mut self) {
self.cursor.cursor_left();
}
}

View File

@ -0,0 +1,77 @@
#[derive(Default)]
pub struct Document {
rows: Vec<String>
}
impl Document {
pub fn new(contents: Vec<String>) -> Self {
Self{
rows: contents
}
}
pub fn contents(&self) -> String {
self.rows.join("\n")
}
pub fn row_length(&self, idx: usize) -> usize {
self.rows[idx].len()
}
pub fn row_count(&self) -> usize {
self.rows.len()
}
}
#[derive(Default)]
pub struct Cursor {
row: usize,
column: usize,
desired_column: usize,
}
impl Cursor {
pub fn addr(&self) -> (usize, usize) {
(self.row, self.column)
}
pub fn cursor_up(&mut self, doc: &Document) {
if self.row > 0 {
self.row -= 1;
}
self.correct_columns(doc);
}
pub fn cursor_down(&mut self, doc: &Document) {
if self.row < doc.row_count() - 1 {
self.row += 1;
}
self.correct_columns(doc);
}
pub fn correct_columns(&mut self, doc: &Document) {
let row_len = doc.row_length(self.row);
if self.desired_column < row_len {
self.column = self.desired_column;
} else {
self.column = row_len;
}
}
pub fn cursor_right(&mut self, doc: &Document) {
if self.column < doc.row_length(self.row) {
self.column += 1;
}
self.desired_column = self.column;
}
pub fn cursor_left(&mut self) {
if self.column > 0 {
self.column -= 1;
}
self.desired_column = self.column;
}
}