From 0dfdab489e343932df32d5d0b29f81952d3c8a0a Mon Sep 17 00:00:00 2001 From: maxwell letterlock Date: Wed, 27 Dec 2023 16:15:50 +0100 Subject: [PATCH] fix and slightly change save type detection --- Cargo.lock | 2 +- Cargo.toml | 5 +- README.md | 4 +- src/document.rs | 9 ++- src/editor.rs | 89 +++++++++++---------- src/main.rs | 208 ++++++++++++++++++++++++------------------------ 6 files changed, 164 insertions(+), 153 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3233b61..2fa96f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,7 +22,7 @@ checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "brr-editor" -version = "1.0.1" +version = "1.0.2" dependencies = [ "crossterm", "log", diff --git a/Cargo.toml b/Cargo.toml index 4468706..03f44eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "brr-editor" authors = ["maxwell letterlock"] -version = "1.0.1" +version = "1.0.2" edition = "2021" readme = "README.md" license = "GPL-3.0-or-later" @@ -21,3 +21,6 @@ simple-logging = "2.0.2" [build-dependencies] winres = "0.1" + +[profile.release] +strip = true diff --git a/README.md b/README.md index 76ad727..d162211 100644 --- a/README.md +++ b/README.md @@ -63,10 +63,10 @@ if you want to take a break from writing and look over what you've written, you ## configuration brr uses a simple plaintext config file that should be fairly straightforward to use, just open it in your favourite (actually functional) text editor and change the values after the equals symbols! the 'brr.conf.default' file contains all the default values and syntax, as well as some explanations for the various options. -on opening, brr will check the directory containing its executable for a 'brr.conf' file. if you're on linux, brr will first check "$XDG_CONFIG_HOME/brr" (if this is unset, it will also just check ~/.config/brr), before checking its own directory. +on opening, brr will check the directory containing its executable for a 'brr.conf' file. if you're on linux, brr will first check "`$XDG_CONFIG_HOME/brr`" (if this is unset, it will also just check `~/.config/brr`), before checking its own directory. ## logging and errors -if you're on windows, brr reports all errors through a log file placed in the same directory as the executable. if you're on linux, brr will first try to find (and create, if absent) "$XDG_STATE_HOME/brr". if $XDG_STATE_HOME is unset, it will default to "~/.local/state/brr". if it can't create that, it will just try to put the log in the directory containing its executable. +if you're on windows, brr reports all errors through a log file placed in the same directory as the executable. if you're on linux, brr will first try to find (and create, if absent) "`$XDG_STATE_HOME/brr`". if `$XDG_STATE_HOME` is unset, it will default to "`~/.local/state/brr`". if it can't create that, it will just try to put the log in the directory containing its executable. if brr encounters an unrecoverable error, it will panic and die, leaving you with the error that killed it. if you opened the executable from outside of a terminal (e.g. you just ran the executable), the terminal will close as the process exits, so you'll have to check the log for what happened. if you do encounter an error that kills brr, please report it as an issue, include your log file, and tell me what you were doing when brr was die. diff --git a/src/document.rs b/src/document.rs index caaf156..e4ab580 100644 --- a/src/document.rs +++ b/src/document.rs @@ -1,4 +1,4 @@ -use crate::{Terminal, Metadata, DisplayRow, AppendBuffer, Position, die}; +use crate::{Terminal, Metadata, DisplayRow, AppendBuffer, Position, die, SaveType}; use { unicode_segmentation::UnicodeSegmentation, words_count::WordsCount, @@ -76,7 +76,7 @@ impl Document { } } - pub fn save(&mut self, words: u8) -> Result<(), Error> { + pub fn save(&mut self, words: u8, save_type: SaveType) -> Result<(), Error> { let mut tmp_path = self.metadata.path.clone(); tmp_path.set_extension("tmp"); info!( @@ -88,7 +88,8 @@ impl Document { // words here is set in the config file and // refers to how many words brr should save // as they're written - if words > 1 { + if save_type == SaveType::Words + && words > 1 { if let Some((split_at_index, ..)) = self.append_buffer.buffer .unicode_word_indices() .nth(words.saturating_sub(1) as usize) { @@ -101,7 +102,7 @@ impl Document { } else if !self.append_buffer.buffer.is_empty() { self.content.push_str(&self.append_buffer.buffer); self.append_buffer.buffer.clear(); - }; + } self.count = words_count::count(&self.content); diff --git a/src/editor.rs b/src/editor.rs index fc235b1..31113b5 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -48,6 +48,13 @@ enum Mode { Prompt, } +#[derive(PartialEq, Clone, Copy)] +pub enum SaveType { + Words, + Time, + Manual, +} + struct Message { text: String, time: Instant, @@ -223,7 +230,7 @@ impl Editor { }; self.should_quit = true; }, - (KeyModifiers::CONTROL, KeyCode::Char('s')) => self.save(0), + (KeyModifiers::CONTROL, KeyCode::Char('s')) => self.save(0, SaveType::Manual), (KeyModifiers::CONTROL, KeyCode::Char('o')) => self.open(), (KeyModifiers::CONTROL, KeyCode::Char('h')) => { self.message = @@ -238,11 +245,13 @@ impl Editor { }, (_, KeyCode::Char(pressed_char)) if self.mode == Mode::Edit => { self.document.append_buffer.count_words(); - if self.document.append_buffer.word_count == self.config.save_words as usize { - self.save(self.config.save_words); + if self.document.append_buffer.word_count == self.config.save_words as usize + && self.config.save_words > 1 { + self.save(self.config.save_words, SaveType::Words); } else if self.document.last_edit.elapsed() > Duration::new(self.config.save_time as u64, 0) - && !self.document.append_buffer.buffer.is_empty() { - self.save(0); + && !self.document.append_buffer.buffer.is_empty() + && self.config.save_time > 0 { + self.save(0, SaveType::Time); } self.document.insert(pressed_char); self.snap_view(); @@ -251,9 +260,9 @@ impl Editor { (_, KeyCode::Backspace) if self.mode == Mode::Edit => { // skip checking word count if backspacing if self.document.last_edit.elapsed() > Duration::new(self.config.save_time as u64, 0) - && !self.document.append_buffer.buffer.is_empty() { - self.save(0); - self.message = Message::from("sorry, five seconds passed! file saved.".to_string()); + && !self.document.append_buffer.buffer.is_empty() + && self.config.save_time > 0 { + self.save(0, SaveType::Time); } if (self.view_pos.x > 0 || self.view_pos.y > 0) @@ -265,11 +274,13 @@ impl Editor { }, (_, KeyCode::Enter) if self.mode == Mode::Edit => { self.document.append_buffer.count_words(); - if self.document.append_buffer.word_count == self.config.save_words as usize { - self.save(self.config.save_words); + if self.document.append_buffer.word_count == self.config.save_words as usize + && self.config.save_words > 1 { + self.save(self.config.save_words, SaveType::Words); } else if self.document.last_edit.elapsed() > Duration::new(self.config.save_time as u64, 0) - && !self.document.append_buffer.buffer.is_empty() { - self.save(0); + && !self.document.append_buffer.buffer.is_empty() + && self.config.save_time > 0 { + self.save(0, SaveType::Time); } self.document.insert('\n'); self.snap_view(); @@ -326,7 +337,7 @@ impl Editor { }; self.should_quit = true; }, - (KeyEventKind::Press, KeyModifiers::CONTROL, KeyCode::Char('s')) => self.save(0), + (KeyEventKind::Press, KeyModifiers::CONTROL, KeyCode::Char('s')) => self.save(0, SaveType::Manual), (KeyEventKind::Press, KeyModifiers::CONTROL, KeyCode::Char('o')) => self.open(), (KeyEventKind::Press, KeyModifiers::CONTROL, KeyCode::Char('h')) => { self.message = @@ -341,11 +352,13 @@ impl Editor { }, (KeyEventKind::Press, _, KeyCode::Char(pressed_char)) if self.mode == Mode::Edit => { self.document.append_buffer.count_words(); - if self.document.append_buffer.word_count == self.config.save_words as usize { - self.save(self.config.save_words); + if self.document.append_buffer.word_count == self.config.save_words as usize + && self.config.save_words > 1 { + self.save(self.config.save_words, SaveType::Words); } else if self.document.last_edit.elapsed() > Duration::new(self.config.save_time as u64, 0) - && !self.document.append_buffer.buffer.is_empty() { - self.save(0); + && !self.document.append_buffer.buffer.is_empty() + && self.config.save_time > 0 { + self.save(0, SaveType::Time); } self.document.insert(pressed_char); self.snap_view(); @@ -354,8 +367,9 @@ impl Editor { (KeyEventKind::Press, _, KeyCode::Backspace) if self.mode == Mode::Edit => { // skip checking word count if backspacing if self.document.last_edit.elapsed() > Duration::new(self.config.save_time as u64, 0) - && !self.document.append_buffer.buffer.is_empty() { - self.save(0); + && !self.document.append_buffer.buffer.is_empty() + && self.config.save_time > 0 { + self.save(0, SaveType::Time); self.message = Message::from("sorry, five seconds passed! file saved.".to_string()); } if (self.view_pos.x > 0 @@ -368,11 +382,13 @@ impl Editor { }, (KeyEventKind::Press, _, KeyCode::Enter) if self.mode == Mode::Edit => { self.document.append_buffer.count_words(); - if self.document.append_buffer.word_count == self.config.save_words as usize { - self.save(self.config.save_words); + if self.document.append_buffer.word_count == self.config.save_words as usize + && self.config.save_words > 1 { + self.save(self.config.save_words, SaveType::Words); } else if self.document.last_edit.elapsed() > Duration::new(self.config.save_time as u64, 0) - && !self.document.append_buffer.buffer.is_empty() { - self.save(0); + && !self.document.append_buffer.buffer.is_empty() + && self.config.save_time > 0{ + self.save(0, SaveType::Time); } self.document.insert('\n'); self.snap_view(); @@ -554,24 +570,15 @@ impl Editor { Ok(()) } - pub fn save(&mut self, words: u8) { - if words > 1 { - match self.document.save(words) { - Ok(()) => (), - Err(error_msg) => { - self.message = Message::from("error writing file. see log for details.".to_string()); - error!("[document.rs -> editor.rs]: {error_msg} - could not save file."); - }, - }; - } else { - match self.document.save(words) { - Ok(()) => self.message = Message::from("file saved successfully.".to_string()), - Err(error_msg) => { - self.message = Message::from("error writing file. see log for details.".to_string()); - error!("[document.rs -> editor.rs]: {error_msg} - could not save file."); - }, - }; - }; + pub fn save(&mut self, words: u8, save_type: SaveType) { + match self.document.save(words, save_type) { + Ok(()) if save_type == SaveType::Manual => self.message = Message::from("file saved successfully.".to_string()), + Ok(()) => (), + Err(error_msg) => { + self.message = Message::from("error writing file. see log for details.".to_string()); + error!("[document.rs -> editor.rs]: {error_msg} - could not save file."); + }, + } } pub fn open(&mut self) { diff --git a/src/main.rs b/src/main.rs index 170ea97..affd1ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,104 +1,104 @@ -#![warn( - clippy::all, - clippy::pedantic, - clippy::correctness, - clippy::suspicious, - clippy::complexity, - clippy::perf, - clippy::expect_used, - clippy::unwrap_used, - clippy::unwrap_in_result, - clippy::indexing_slicing, - clippy::string_slice, -)] - -mod die; -mod config; -mod init; -mod terminal; -mod editor; -mod metadata; -mod document; -mod append_buffer; -mod row; - -use die::die; -use config::Config; -use init::Init; -use terminal::Terminal; -use editor::{Editor, Position}; -use metadata::{Metadata, get_conf_or_log_path}; -use document::{Document, render}; -use append_buffer::AppendBuffer; -use row::DisplayRow; - -use { - log::{LevelFilter, error, warn, info}, - simple_logging::log_to_file, -}; - -// ----------------- - -// note on converting usize to u16: -// in reality usize is unneccesary for brr because a document is -// very unlikely to pass 65536 lines (the maximum value of u16) -// by my calculations, to surpass 65k lines, a document would -// have to be (conservatively) over 2000 a4 pages long in standard -// manuscript format: -// https://en.wikipedia.org/wiki/Standard_manuscript_format -// likewise -- a single line would have to be about 40 pages long -// before it was truncated due to being longer than 65536 chars -// calculations: -// page size: a4 -// font size: 12pt monospaced -// line spacing: double -// chars per line: 65 -// lines per page: 25 -// max lines in document as pages: -// 65536 / 25 = 2621.44 -// max chars in line as pages: -// 65 * 25 = 1625 -// 65536 / 1625 = 40.33 - -// there's no official way to count words (and even counting -// characters is more complex than you think) so brr's word -// and character counts should be used as guidelines -// also brr doesn't currently count words or characters in -// the append buffer - -// NEXT: figure out packaging and distribution. - -// TODO: -// - !!! fix error handling in editor.rs::refresh_screen() -// - !!! look into if \r\n vs \n is going to cause platform specific problems on windows -// - !!! on linux systems, brr should look in ~/.config/brr for its config file -// - !! fix truncation in message bar and status bar -// - !! config file description -// - !! add code comments for clarity -// - ! https://doc.rust-lang.org/stable/rust-by-example/fn/closures.html -// MAYBE: -// - don't wrap spaces along with words -// - add search function to viewing mode -// - scrollbar -// - mouse scrolling in view mode -// - line numbers -// - handle wide characters https://github.com/rhysd/kiro-editor -// - truncate absolute paths? - -#[allow(clippy::unwrap_used)] -fn main() { - let args = std::env::args().nth(1); - - if let Some(log_path) = get_conf_or_log_path(false) { - log_to_file(&log_path, LevelFilter::Info).unwrap(); - - info!("using log path: {}", log_path.display()); - } else { - panic!("cannot find executable. do you have permission to access the folder containing brr?") - }; - - match Init::default().welcome(args) { - Ok(()) => (), - Err(error_msg) => error!("[init.rs -> main.rs]: {error_msg} - couldn't flush stdout."), - }; -} \ No newline at end of file +#![warn( + clippy::all, + clippy::pedantic, + clippy::correctness, + clippy::suspicious, + clippy::complexity, + clippy::perf, + clippy::expect_used, + clippy::unwrap_used, + clippy::unwrap_in_result, + clippy::indexing_slicing, + clippy::string_slice, +)] + +mod die; +mod config; +mod init; +mod terminal; +mod editor; +mod metadata; +mod document; +mod append_buffer; +mod row; + +use die::die; +use config::Config; +use init::Init; +use terminal::Terminal; +use editor::{Editor, Position, SaveType}; +use metadata::{Metadata, get_conf_or_log_path}; +use document::{Document, render}; +use append_buffer::AppendBuffer; +use row::DisplayRow; + +use { + log::{LevelFilter, error, warn, info}, + simple_logging::log_to_file, +}; + +// ----------------- + +// note on converting usize to u16: +// in reality usize is unneccesary for brr because a document is +// very unlikely to pass 65536 lines (the maximum value of u16) +// by my calculations, to surpass 65k lines, a document would +// have to be (conservatively) over 2000 a4 pages long in standard +// manuscript format: +// https://en.wikipedia.org/wiki/Standard_manuscript_format +// likewise -- a single line would have to be about 40 pages long +// before it was truncated due to being longer than 65536 chars +// calculations: +// page size: a4 +// font size: 12pt monospaced +// line spacing: double +// chars per line: 65 +// lines per page: 25 +// max lines in document as pages: +// 65536 / 25 = 2621.44 +// max chars in line as pages: +// 65 * 25 = 1625 +// 65536 / 1625 = 40.33 + +// there's no official way to count words (and even counting +// characters is more complex than you think) so brr's word +// and character counts should be used as guidelines +// also brr doesn't currently count words or characters in +// the append buffer + +// TODO: +// - !!! clean up save type detection in editor.rs + document.rs +// - !!! look into word detection code to see if i can't make it work more intuitively +// - !!! fix error handling in editor.rs::refresh_screen() +// - !!! look into if \r\n vs \n is going to cause platform specific problems on windows +// - !!! on linux systems, brr should look in ~/.config/brr for its config file +// - !! fix truncation in message bar and status bar +// - !! config file description +// - !! add code comments for clarity +// - ! https://doc.rust-lang.org/stable/rust-by-example/fn/closures.html +// MAYBE: +// - don't wrap spaces along with words +// - add search function to viewing mode +// - scrollbar +// - mouse scrolling in view mode +// - line numbers +// - handle wide characters https://github.com/rhysd/kiro-editor +// - truncate absolute paths? + +#[allow(clippy::unwrap_used)] +fn main() { + let args = std::env::args().nth(1); + + if let Some(log_path) = get_conf_or_log_path(false) { + log_to_file(&log_path, LevelFilter::Info).unwrap(); + + info!("using log path: {}", log_path.display()); + } else { + panic!("cannot find executable. do you have permission to access the folder containing brr?") + }; + + match Init::default().welcome(args) { + Ok(()) => (), + Err(error_msg) => error!("[init.rs -> main.rs]: {error_msg} - couldn't flush stdout."), + }; +}