From 4af5c70dd35baff96952d8f2d577af34a8c78e1a Mon Sep 17 00:00:00 2001 From: Alan Vardy Date: Sat, 4 Jan 2025 11:13:41 -0800 Subject: [PATCH] Add max_comment_length to config --- CHANGELOG.md | 1 + docs/configuration.md | 11 +++++++++++ src/config.rs | 8 ++++++++ src/error.rs | 14 +++++++++++++- src/tasks/format.rs | 29 +++++++++++++++++++++++++---- src/test.rs | 19 +++++++++++++++++++ 6 files changed, 77 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d489d0..3ef92b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased (on main branch only) - Render attachment URLs in comments +- Make `max_comment_length` configurable ## 2025-01-02 v0.6.26 diff --git a/docs/configuration.md b/docs/configuration.md index 635a917..6cf9142 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -6,6 +6,7 @@ - [Values](#values) - [disable_links](#disable_links) - [last_version_check](#last_version_check) + - [max_comment_length](#max_comment_length) - [next_id](#next_id) - [path](#path) - [natural_language_only](#natural_language_only) @@ -66,6 +67,16 @@ If true, disables OSC8 linking and just displays plain text Holds a string date, i.e. `"2023-08-30"` representing the last time crates.io was checked for the latest `tod` version. Tod will check crates.io a maximum of once per day. +### max_comment_length + +``` + type: nullable positive integer + default: null + possible_values: Any positive integer or null +``` + +The maximum number of characters that will be printed in total when showing comments. + ### next_id ``` diff --git a/src/config.rs b/src/config.rs index 7caf7c5..432e8e2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,6 +9,8 @@ use tokio::fs; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::sync::mpsc::UnboundedSender; +const MAX_COMMENT_LENGTH: u32 = 500; + #[derive(Deserialize, Serialize, Debug, Clone)] pub struct Completed { count: u32, @@ -45,6 +47,8 @@ pub struct Config { #[serde(default)] pub disable_links: bool, pub completed: Option, + // Maximum length for printing comments + pub max_comment_length: Option, pub verbose: Option, /// Don't ask for sections pub no_sections: Option, @@ -108,6 +112,9 @@ impl Default for SortValue { } } impl Config { + pub fn max_comment_length(self: &Config) -> u32 { + self.max_comment_length.unwrap_or(MAX_COMMENT_LENGTH) + } pub async fn reload_projects(self: &mut Config) -> Result { let all_projects = todoist::projects(self).await?; let current_projects = self.projects.clone().unwrap_or_default(); @@ -255,6 +262,7 @@ impl Config { natural_language_only: None, mock_string: None, mock_select: None, + max_comment_length: None, verbose: None, internal: Internal { tx: Some(tx) }, args: Args { diff --git a/src/error.rs b/src/error.rs index 22f640e..f10d665 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,7 @@ -use std::{fmt::Display, num::ParseIntError}; +use std::{ + fmt::Display, + num::{ParseIntError, TryFromIntError}, +}; use crate::color; use homedir::GetHomeError; @@ -32,6 +35,15 @@ impl From for Error { } } +impl From for Error { + fn from(value: TryFromIntError) -> Self { + Self { + source: String::from("TryFromIntError"), + message: format!("{value}"), + } + } +} + impl From for Error { fn from(value: JoinError) -> Self { Self { diff --git a/src/tasks/format.rs b/src/tasks/format.rs index 2bc104a..bc9754f 100644 --- a/src/tasks/format.rs +++ b/src/tasks/format.rs @@ -5,8 +5,6 @@ use supports_hyperlinks::Stream; use super::{priority, DateTimeInfo, Duration, Task, Unit}; use crate::{color, config::Config, error::Error, projects::Project, time, todoist}; -const MAX_COMMENT_LENGTH: usize = 500; - pub fn content(task: &Task, config: &Config) -> String { let content = match task.priority { priority::Priority::Low => color::blue_string(&task.content), @@ -146,9 +144,10 @@ pub async fn comments(config: &Config, task: &Task) -> Result { comments.reverse(); let comments = comments.join("\n\n"); let mut formatted_string = format!("\n\n{comment_icon} Comments {comment_icon}\n\n{comments}"); + let max_comment_length: usize = config.max_comment_length().try_into()?; - if formatted_string.len() > MAX_COMMENT_LENGTH { - formatted_string.truncate(MAX_COMMENT_LENGTH); + if formatted_string.len() > max_comment_length { + formatted_string.truncate(max_comment_length); formatted_string.push_str("[TRUNCATED]"); }; @@ -157,6 +156,8 @@ pub async fn comments(config: &Config, task: &Task) -> Result { #[cfg(test)] mod tests { + use crate::test; + use super::*; use pretty_assertions::assert_eq; @@ -176,4 +177,24 @@ mod tests { String::from("\x1B]8;;https://app.todoist.com/app/task/1\x1B\\[link]\x1B]8;;\x1B\\") ) } + + #[tokio::test] + async fn test_comments() { + let mut server = mockito::Server::new_async().await; + let mock = server + .mock("GET", "/rest/v2/comments/?task_id=222") + .with_status(200) + .with_header("content-type", "application/json") + .with_body(test::responses::comments()) + .create_async() + .await; + + let config = test::fixtures::config().await.mock_url(server.url()); + let task = test::fixtures::task(); + + let comments = comments(&config, &task).await.unwrap(); + + assert_matches!(comments.as_str(), "\n\nā˜… Comments ā˜…\n\nPosted 2016-09-22 00:00:00 PDT\nAttachment \u{1b}]8;;https://s3.amazonaws.com/domorebe[TRUNCATED]"); + mock.expect(1); + } } diff --git a/src/test.rs b/src/test.rs index e5bd978..1552216 100644 --- a/src/test.rs +++ b/src/test.rs @@ -44,6 +44,7 @@ pub mod fixtures { disable_links: false, completed: None, bell_on_success: false, + max_comment_length: Some(100), bell_on_failure: true, internal: Internal { tx: tx() }, projects: Some(vec![Project { @@ -335,6 +336,24 @@ pub mod responses { ) } + pub fn comments() -> String { + String::from( + "[{ + \"content\": \"Need one bottle of milk\", + \"id\": \"2992679862\", + \"posted_at\": \"2016-09-22T07:00:00.000000Z\", + \"project_id\": null, + \"task_id\": \"2995104339\", + \"attachment\": { + \"file_name\": \"File.pdf\", + \"file_type\": \"application/pdf\", + \"file_url\": \"https://s3.amazonaws.com/domorebetter/Todoist+Setup+Guide.pdf\", + \"resource_type\": \"file\" + } + }]", + ) + } + pub fn user() -> String { String::from( "\