Skip to content
This repository has been archived by the owner on Nov 18, 2024. It is now read-only.

Commit

Permalink
Merge pull request #62 from ThatFrogDev/dev
Browse files Browse the repository at this point in the history
Support for multi-liners
  • Loading branch information
ThatFrogDev authored Apr 2, 2024
2 parents bb1aed4 + 94db98e commit 5886601
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 33 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ categories = [ "command-line-utilities", "gui", "text-processing" ]
[dependencies]
async-std = "1.12.0"
directories = "5.0.1"
chrono = "0.4.35"
chrono = "0.4.37"
dialoguer = "0.11.0"
crossterm = "0.27.0"
rusqlite = { version = "0.31.0", features = ["bundled"] }
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ fn display_about() -> Result<(), Box<dyn std::error::Error>> {
"{}",
paragraph(
&skin,
"**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)."
"**Notabena** is a FOSS note-taking CLI tool, written in Rust."
)
);
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\n(scroll up if you can't read everything)");
println!("COPYRIGHT (c) 2023-PRESENT NOTABENA ORGANISATION\nAUTHOR: @ThatFrogDev, GITHUB CONTRIBUTORS\n\n(scroll up if you can't read everything)");

Ok(())
}
21 changes: 14 additions & 7 deletions src/note.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use crate::{
api, multiselect,
prompts::{confirm::confirm, input::input, select::select},
prompts::{
confirm::confirm,
input::{multi, single},
select::select,
},
truncate_note,
utilities::{cursor_to_origin::cursor_to_origin, display::display},
};
Expand All @@ -20,7 +24,8 @@ impl Note {
pub fn create(db_file: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
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
// 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<Vec<usize>, _> = stmt.query_map(params![], |row| row.get(0))?.collect();
let mut ids = ids?;
Expand All @@ -34,12 +39,14 @@ impl Note {

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"
"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\
For the \"Content\" field: to end a paragraph press Space and then Enter. To end your note, press Enter on a second new line.\n\
You can use Markdown to format your notes.\r"
);

let mut name: String;
loop {
name = input("Name:", "".to_string())?;
name = single("Name:", "".to_string(), true)?;
if name.len() > 64 {
cursor_to_origin()?;
println!(
Expand All @@ -53,7 +60,7 @@ impl Note {
let inputted_note = Note {
id,
name,
content: input("Content:", "".to_string())?,
content: multi("Content:", "".to_string())?,
created: format!("{}", Local::now().format("%A %e %B, %H:%M")),
};

Expand Down Expand Up @@ -108,8 +115,8 @@ impl Note {
let selected_note = &saved_notes[selection];
let updated_note = Note {
id: selected_note.id,
name: input("Name:", selected_note.name.clone())?,
content: input("Content:", selected_note.content.clone())?,
name: single("Name:", selected_note.name.clone(), true)?,
content: multi("Content:", selected_note.content.clone())?,
created: selected_note.created.clone(),
};

Expand Down
69 changes: 54 additions & 15 deletions src/prompts/input.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
use crate::return_to_main::{continue_event, return_event};
use crate::{main, return_to_main};
use dialoguer::{theme::ColorfulTheme, Input};

pub fn input(prompt: &str, initial_text: String) -> Result<String, Box<dyn std::error::Error>> {
let result = match initial_text.as_str() {
"" => Input::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.interact_text()
.unwrap(),
_ => Input::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.with_initial_text(initial_text)
.interact_text()
.unwrap(),
};
pub fn single(
prompt: &str,
initial_text: String,
is_required: bool,
) -> Result<String, Box<dyn std::error::Error>> {
let mut result: String;

loop {
result = match initial_text.as_str() {
"" => Input::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.interact_text()
.unwrap(),
_ => Input::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.with_initial_text(initial_text.clone())
.interact_text()
.unwrap(),
};

if !is_required || !result.trim().is_empty() {
break;
}
}

match return_to_main() {
Ok(value) => {
if value == return_event() {
if value == "userReturned" {
main()?;
} else if value == continue_event() {
} else if value == "userContinued" {
return Ok(result);
}
}
Expand All @@ -28,3 +39,31 @@ pub fn input(prompt: &str, initial_text: String) -> Result<String, Box<dyn std::

Ok(result)
}

pub fn multi(prompt: &str, initial_text: String) -> Result<String, Box<dyn std::error::Error>> {
let mut result = String::new();
let mut t_enter = 0;
let mut first_iteration = true;

loop {
let line = if first_iteration {
first_iteration = false;
single(prompt, initial_text.clone(), false)?
} else {
single("", initial_text.clone(), false)?
};

if line.trim().is_empty() {
t_enter += 1;
if t_enter == 2 {
break;
}
} else {
t_enter = 0;
}
result.push_str(&line);
result.push('\n');
}

Ok(result)
}
10 changes: 5 additions & 5 deletions src/return_to_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use std::time::Duration;

// very hacky way to make these values public
pub fn return_event() -> KeyEvent {
fn return_event() -> KeyEvent {
KeyEvent {
code: KeyCode::Char('q'),
modifiers: KeyModifiers::ALT,
Expand All @@ -13,7 +13,7 @@ pub fn return_event() -> KeyEvent {
}
}

pub fn continue_event() -> KeyEvent {
fn continue_event() -> KeyEvent {
KeyEvent {
code: KeyCode::Enter,
modifiers: KeyModifiers::NONE,
Expand All @@ -22,17 +22,17 @@ pub fn continue_event() -> KeyEvent {
}
}

pub fn return_to_main() -> Result<KeyEvent, Box<dyn std::error::Error>> {
pub fn return_to_main() -> Result<&'static str, Box<dyn std::error::Error>> {
enable_raw_mode()?;

loop {
if event::poll(Duration::from_millis(1000))? {
if let Event::Key(event) = event::read()? {
if event == return_event() {
return Ok(return_event());
return Ok("userReturned");
}
if event == continue_event() {
return Ok(continue_event());
return Ok("userContinued");
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/utilities/truncate_note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ pub fn truncate_note(
db_file: &PathBuf,
) -> Result<(), Box<dyn std::error::Error>> {
for note in &get_notes(db_file)? {
let mut truncated_content: String = note.content.chars().take(10).collect();
let mut truncated_content: String = note
.content
.chars()
.take(10)
.collect::<String>()
.replace("\n", " ");
if truncated_content.chars().count() == 10 {
truncated_content += "..."; // this is cursed and awesome at the same time
}
Expand Down

0 comments on commit 5886601

Please sign in to comment.