diff --git a/Cargo.lock b/Cargo.lock index 209d7ad..5f6afed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.18" @@ -1134,6 +1143,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "reqwest" version = "0.11.27" @@ -1712,6 +1750,7 @@ dependencies = [ "dotenv", "html2text", "ratatui", + "regex", "reqwest", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 2c17a1e..de142cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +regex = "1" toml = "0.5" dirs = "4.0" tokio = { version = "1", features = ["full"] } diff --git a/src/api.rs b/src/api.rs index 1eab872..711ef29 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,6 +1,7 @@ use crate::models::{Task, TaskDetail}; use reqwest::Client; -use std::collections::HashMap; +use serde_json::json; +use std::error::Error; pub async fn fetch_tasks( instance_url: &str, @@ -48,17 +49,23 @@ pub async fn create_new_task( instance_url: &str, api_key: &str, task_title: &str, -) -> Result<(), Box> { + priority: Option, +) -> Result<(), Box> { let client = Client::new(); let url = format!("{}/api/v1/projects/1/tasks", instance_url); - let mut map = HashMap::new(); - map.insert("title", task_title); + let mut task_data = json!({ + "title": task_title + }); + + if let Some(priority_value) = priority { + task_data["priority"] = json!(priority_value); + } let res = client .put(&url) .header("Authorization", format!("Bearer {}", api_key)) - .json(&map) + .json(&task_data) .send() .await?; diff --git a/src/app.rs b/src/app.rs index efa4bc3..75feda2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,5 +1,6 @@ use crate::api::{create_new_task, fetch_task_detail, fetch_tasks}; use crate::models::{Task, TaskDetail}; +use crate::parser::parse_task_input; use crossterm::event::KeyCode; use ratatui::widgets::ListState; use std::io; @@ -149,10 +150,18 @@ impl App { InputMode::Editing => { match key.code { KeyCode::Enter => { - // Handle task submission if !self.new_task_title.trim().is_empty() { - if let Err(err) = - create_new_task(instance_url, api_key, &self.new_task_title).await + // Use the parser to extract the task title, priority, and label titles + let parsed_task = parse_task_input(&self.new_task_title); + + // Create the new task with the parsed title, priority, and labels + if let Err(err) = create_new_task( + instance_url, + api_key, + &parsed_task.title, + parsed_task.priority, + ) + .await { eprintln!("Error creating task: {}", err); } else { diff --git a/src/main.rs b/src/main.rs index 9f79278..2d25978 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod api; mod app; mod models; +mod parser; mod ui; use crate::api::fetch_tasks; diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..89ac909 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,29 @@ +use regex::Regex; + +pub struct ParsedTask { + pub title: String, + pub priority: Option, +} + +pub fn parse_task_input(input: &str) -> ParsedTask { + // Regex for priority pattern, e.g. !1 to !5 + let priority_re = Regex::new(r"!(\d)").unwrap(); + + let mut priority = None; + let mut title = input.to_string(); + + // Capture priority if it exists + if let Some(caps) = priority_re.captures(input) { + if let Some(priority_match) = caps.get(1) { + if let Ok(p) = priority_match.as_str().parse::() { + if (1..=5).contains(&p) { + priority = Some(p); + } + } + } + // Remove the priority pattern from the title + title = priority_re.replace(input, "").trim().to_string(); + } + + ParsedTask { title, priority } +}