From b3bcf1f0316149a7934d64cf99fc2c8a9f83f5f3 Mon Sep 17 00:00:00 2001 From: ThatBoiDev Date: Fri, 15 Mar 2024 16:51:00 +0100 Subject: [PATCH 1/7] conditional compiling by attributes instead of if-statements\ added donation notice to README.md --- src/main.rs | 8 ++++---- src/utilities/cursor_to_origin.rs | 16 +++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7e8f974..41dab8e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ use crate::{ return_to_main::return_to_main, utilities::{ cursor_to_origin::cursor_to_origin, - format_md::{inline, paragraph}, + format_md::paragraph, truncate_note::truncate_note, }, }; @@ -57,16 +57,16 @@ fn display_about() -> Result<(), Box> { println!("{}", paragraph(&skin, &format!("# About Notabena"))); println!( "{}", - inline( + paragraph( &skin, - "**Notabena** is a FOSS note-taking CLI tool, written in Rust.\n" + "**Notabena** is a FOSS note-taking CLI tool, written in Rust.\nDonations are always a great way to help us keeping the project alive. It can be done here: https://paypal.me/Notabena (ctrl+click to follow link)." ) ); println!( "version: v{}, licensed under: GPL v3", env!("CARGO_PKG_VERSION") ); - println!("COPYRIGHT (c) 2023-PRESENT NOTABENA ORGANISATION\nPROJECT LEADS @ThatFrogDev, @MrSerge01, GITHUB CONTRIBUTORS\n"); + println!("COPYRIGHT (c) 2023-PRESENT NOTABENA ORGANISATION\nPROJECT LEADS @ThatFrogDev, @MrSerge01, GITHUB CONTRIBUTORS\n\n(scroll up if you can't read everything)"); Ok(()) } diff --git a/src/utilities/cursor_to_origin.rs b/src/utilities/cursor_to_origin.rs index 2508638..3b7e74f 100644 --- a/src/utilities/cursor_to_origin.rs +++ b/src/utilities/cursor_to_origin.rs @@ -1,11 +1,13 @@ use std::process::Command; +#[cfg(target_os = "windows")] pub fn cursor_to_origin() -> Result<(), Box> { - if cfg!(target_os = "windows") { - Command::new("cmd").args(["/c", "cls"]).spawn()?.wait()?; - Ok(()) - } else { - Command::new("clear").spawn()?.wait()?; - Ok(()) - } + Command::new("cmd").args(["/c", "cls"]).spawn()?.wait()?; + Ok(()) +} + +#[cfg(not(target_os = "windows"))] +pub fn cursor_to_origin() -> Result<(), Box> { + Command::new("clear").spawn()?.wait()?; + Ok(()) } From 62d958008c5b2190c8fa122b8735141c4dd5250b Mon Sep 17 00:00:00 2001 From: Mart Zielman <93423789+ThatFrogDev@users.noreply.github.com> Date: Sat, 16 Mar 2024 15:59:20 +0100 Subject: [PATCH 2/7] feat: add the ability to donate via GitHub sponsors --- .github/FUNDING.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..408d0bc --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,14 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +polar: # Replace with a single Polar username +buy_me_a_coffee: # Replace with a single Buy Me a Coffee username +custom: 'paypal.me/notabena' From 365182461ec8f2c8937e9a05695504fb94e18b0a Mon Sep 17 00:00:00 2001 From: ThatBoiDev Date: Sat, 16 Mar 2024 16:02:43 +0100 Subject: [PATCH 3/7] fmt --- src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 41dab8e..9dc1c8b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,9 +12,7 @@ use crate::{ prompts::{multiselect::multiselect, select::select}, return_to_main::return_to_main, utilities::{ - cursor_to_origin::cursor_to_origin, - format_md::paragraph, - truncate_note::truncate_note, + cursor_to_origin::cursor_to_origin, format_md::paragraph, truncate_note::truncate_note, }, }; use async_std::path::PathBuf; From 9f4f9e58ba88459fab6336e564fd78f8e5360c0e Mon Sep 17 00:00:00 2001 From: ThatBoiDev Date: Mon, 18 Mar 2024 16:49:03 +0100 Subject: [PATCH 4/7] sort notes by newest first --- src/api.rs | 4 ++++ src/note.rs | 25 ++++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/api.rs b/src/api.rs index c55d935..816b060 100644 --- a/src/api.rs +++ b/src/api.rs @@ -65,5 +65,9 @@ pub fn get_notes(db_file: &PathBuf) -> Result> { notes.push(note?); } + // sort notes by date: newest first + notes.sort_by(|a, b| a.created.cmp(&b.created)); + notes.reverse(); + Ok(notes) } diff --git a/src/note.rs b/src/note.rs index b049452..385b539 100644 --- a/src/note.rs +++ b/src/note.rs @@ -1,7 +1,7 @@ use crate::{ api, multiselect, prompts::{confirm::confirm, input::input, select::select}, - return_to_main, truncate_note, + truncate_note, utilities::{cursor_to_origin::cursor_to_origin, display::display}, }; use async_std::path::PathBuf; @@ -18,18 +18,33 @@ pub struct Note { impl Note { pub fn create(db_file: &PathBuf) -> Result<(), Box> { + let sqlite = Connection::open(db_file)?; + + // fetch IDs from database, sort and find the first gap. if it does not exist, use the length of the array + 1 + let mut stmt = sqlite.prepare("SELECT id FROM saved_notes")?; + let ids: Result, _> = stmt + .query_map(params![], |row| row.get(0))? + .collect(); + let mut ids = ids?; + ids.sort_unstable(); + let id = ids.clone() + .into_iter() + .enumerate() + .find(|(i, id)| i + 1 != *id) + .map_or_else(|| ids.len() + 1, |(i, _)| i + 1); + cursor_to_origin()?; println!( "If you're done inputting a field, you can press Enter twice to continue or save, or Alt/Option-Q to return to the main menu.\r" ); - let mut inputted_note = Note { - id: api::get_notes(db_file)?.len(), + let inputted_note = Note { + id: id, name: input("Name:", "".to_string())?, content: input("Content:", "".to_string())?, created: format!("{}", Local::now().format("%A %e %B, %H:%M")), }; - Connection::open(db_file)?.execute( + sqlite.execute( "INSERT INTO saved_notes (id, name, content, created) VALUES (?1, ?2, ?3, ?4);", params![ &inputted_note.id, @@ -58,7 +73,7 @@ impl Note { let mut selected_note = &saved_notes[selection]; cursor_to_origin()?; - display(&mut selected_note); + display(&mut selected_note)?; Ok(()) } From ad0e73f7467dcfb279a9906345eea08d66a05ffe Mon Sep 17 00:00:00 2001 From: ThatBoiDev Date: Mon, 18 Mar 2024 17:40:38 +0100 Subject: [PATCH 5/7] cap character limit of title to 64 to avoid line overflow --- src/note.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/note.rs b/src/note.rs index 385b539..8406f6f 100644 --- a/src/note.rs +++ b/src/note.rs @@ -37,9 +37,23 @@ impl Note { println!( "If you're done inputting a field, you can press Enter twice to continue or save, or Alt/Option-Q to return to the main menu.\r" ); + + let mut name: String; + loop { + name = input("Name:", "".to_string())?; + if name.len() > 64 { + cursor_to_origin()?; + println!( + "If you're done inputting a field, you can press Enter twice to continue or save, or Alt/Option-Q to return to the main menu.\n\n\ + error: The name is too long, it must be 64 characters or less.\r" + ); + } else { + break; + } + } let inputted_note = Note { id: id, - name: input("Name:", "".to_string())?, + name: name, content: input("Content:", "".to_string())?, created: format!("{}", Local::now().format("%A %e %B, %H:%M")), }; From 6d38572a47dbf5f4920766f9a8ffbc20fbf905d8 Mon Sep 17 00:00:00 2001 From: ThatBoiDev Date: Mon, 18 Mar 2024 17:42:46 +0100 Subject: [PATCH 6/7] fmt --- src/note.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/note.rs b/src/note.rs index 8406f6f..ae6920d 100644 --- a/src/note.rs +++ b/src/note.rs @@ -22,12 +22,11 @@ impl Note { // fetch IDs from database, sort and find the first gap. if it does not exist, use the length of the array + 1 let mut stmt = sqlite.prepare("SELECT id FROM saved_notes")?; - let ids: Result, _> = stmt - .query_map(params![], |row| row.get(0))? - .collect(); + let ids: Result, _> = stmt.query_map(params![], |row| row.get(0))?.collect(); let mut ids = ids?; ids.sort_unstable(); - let id = ids.clone() + let id = ids + .clone() .into_iter() .enumerate() .find(|(i, id)| i + 1 != *id) @@ -40,16 +39,16 @@ impl Note { let mut name: String; loop { - name = input("Name:", "".to_string())?; - if name.len() > 64 { - cursor_to_origin()?; - println!( + name = input("Name:", "".to_string())?; + if name.len() > 64 { + cursor_to_origin()?; + println!( "If you're done inputting a field, you can press Enter twice to continue or save, or Alt/Option-Q to return to the main menu.\n\n\ error: The name is too long, it must be 64 characters or less.\r" ); - } else { - break; - } + } else { + break; + } } let inputted_note = Note { id: id, From 3d83f2401840ede99e7e010742e3b91cbddc6409 Mon Sep 17 00:00:00 2001 From: ThatBoiDev Date: Mon, 18 Mar 2024 18:03:05 +0100 Subject: [PATCH 7/7] fix some clippy errors --- src/main.rs | 2 +- src/note.rs | 26 ++++++++++++-------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9dc1c8b..d311b84 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,7 +52,7 @@ fn display_about() -> Result<(), Box> { let skin: MadSkin = MadSkin::default(); cursor_to_origin()?; - println!("{}", paragraph(&skin, &format!("# About Notabena"))); + println!("{}", paragraph(&skin, "# About Notabena")); println!( "{}", paragraph( diff --git a/src/note.rs b/src/note.rs index ae6920d..d53b378 100644 --- a/src/note.rs +++ b/src/note.rs @@ -51,8 +51,8 @@ impl Note { } } let inputted_note = Note { - id: id, - name: name, + id, + name, content: input("Content:", "".to_string())?, created: format!("{}", Local::now().format("%A %e %B, %H:%M")), }; @@ -83,10 +83,10 @@ impl Note { let mut options: Vec = Vec::new(); truncate_note(&mut options, db_file)?; let selection = select("Select the note that you want to view:", &options); - let mut selected_note = &saved_notes[selection]; + let selected_note = &saved_notes[selection]; cursor_to_origin()?; - display(&mut selected_note)?; + display(selected_note)?; Ok(()) } @@ -107,7 +107,7 @@ impl Note { let selection = select("Select the note that you want to edit:", &options); let selected_note = &saved_notes[selection]; let updated_note = Note { - id: selected_note.id.clone(), + id: selected_note.id, name: input("Name:", selected_note.name.clone())?, content: input("Content:", selected_note.content.clone())?, created: selected_note.created.clone(), @@ -148,16 +148,14 @@ impl Note { if selections.is_empty() { println!("You didn't select any notes."); Ok(()) + } else if confirm(prompt) { + api::delete_notes(selections, db_file)?; + cursor_to_origin()?; + println!("Notes deleted successfully."); + Ok(()) } else { - if confirm(prompt) { - api::delete_notes(selections, db_file)?; - cursor_to_origin()?; - println!("Notes deleted successfully."); - Ok(()) - } else { - cursor_to_origin()?; - Ok(()) - } + cursor_to_origin()?; + Ok(()) } } }