diff --git a/src/cmd/list.rs b/src/cmd/list.rs index 9c13971be84140b57da0b076569fca6d85e97210..ae772564b0f180270e5034181b63473d279b6936 100644 --- a/src/cmd/list.rs +++ b/src/cmd/list.rs @@ -1,8 +1,9 @@ use anyhow::Result; use comfy_table::presets::NOTHING; -use comfy_table::Table; +use comfy_table::{Cell, Color, Table}; use std::path::Path; +use crate::color::{cell_bold, cell_fg, stdout_use_color}; use crate::db; pub fn run( @@ -67,17 +68,17 @@ pub fn run( .collect::>()?; println!("{}", serde_json::to_string(&details)?); } else { - let c = crate::color::stdout_theme(); + let use_color = stdout_use_color(); let mut table = Table::new(); table.load_preset(NOTHING); table.set_header(vec!["ID", "STATUS", "PRIORITY", "EFFORT", "TITLE"]); for t in &tasks { table.add_row(vec![ - format!("{}{}{}", c.bold, t.id, c.reset), - format!("{}[{}]{}", c.yellow, t.status, c.reset), - format!("{}{}{}", c.red, db::priority_label(t.priority), c.reset), - format!("{}{}{}", c.blue, db::effort_label(t.effort), c.reset), - t.title.clone(), + cell_bold(&t.id, use_color), + cell_fg(format!("[{}]", t.status), Color::Yellow, use_color), + cell_fg(db::priority_label(t.priority), Color::Red, use_color), + cell_fg(db::effort_label(t.effort), Color::Blue, use_color), + Cell::new(&t.title), ]); } if !tasks.is_empty() { diff --git a/src/cmd/next.rs b/src/cmd/next.rs index fe9e082a349437f2715089c51c4e6f8f00165335..8327342b6492f214ea467c22a3cce819158b4df5 100644 --- a/src/cmd/next.rs +++ b/src/cmd/next.rs @@ -1,9 +1,10 @@ use anyhow::{bail, Result}; use comfy_table::presets::NOTHING; -use comfy_table::Table; +use comfy_table::{Cell, Table}; use std::collections::HashSet; use std::path::Path; +use crate::color::{cell_bold, stdout_use_color}; use crate::db; use crate::score::{self, Mode}; @@ -90,17 +91,17 @@ pub fn run(root: &Path, mode_str: &str, verbose: bool, limit: usize, json: bool) .collect(); println!("{}", serde_json::to_string(&items)?); } else { + let use_color = stdout_use_color(); let mut table = Table::new(); table.load_preset(NOTHING); table.set_header(vec!["#", "ID", "SCORE", "TITLE"]); for (i, s) in scored.iter().enumerate() { - let c = crate::color::stdout_theme(); table.add_row(vec![ - format!("{}", i + 1), - format!("{}{}{}", c.bold, s.id, c.reset), - format!("{:.2}", s.score), - s.title.clone(), + Cell::new(i + 1), + cell_bold(&s.id, use_color), + Cell::new(format!("{:.2}", s.score)), + Cell::new(&s.title), ]); } println!("{table}"); diff --git a/src/cmd/ready.rs b/src/cmd/ready.rs index 25b6d5d8a5c473a9bea5ded6db372ad3e103707b..a9fe622b689769f33cb3d89772de2ac50ed40f0e 100644 --- a/src/cmd/ready.rs +++ b/src/cmd/ready.rs @@ -1,8 +1,9 @@ use anyhow::Result; use comfy_table::presets::NOTHING; -use comfy_table::Table; +use comfy_table::{Cell, Color, Table}; use std::path::Path; +use crate::color::{cell_bold, cell_fg, stdout_use_color}; use crate::db; pub fn run(root: &Path, json: bool) -> Result<()> { @@ -38,16 +39,16 @@ pub fn run(root: &Path, json: bool) -> Result<()> { .collect(); println!("{}", serde_json::to_string(&summary)?); } else { - let c = crate::color::stdout_theme(); + let use_color = stdout_use_color(); let mut table = Table::new(); table.load_preset(NOTHING); table.set_header(vec!["ID", "PRIORITY", "EFFORT", "TITLE"]); for t in &tasks { table.add_row(vec![ - format!("{}{}{}", c.green, t.id, c.reset), - format!("{}{}{}", c.red, db::priority_label(t.priority), c.reset), - format!("{}{}{}", c.blue, db::effort_label(t.effort), c.reset), - t.title.clone(), + cell_bold(&t.id, use_color), + cell_fg(db::priority_label(t.priority), Color::Red, use_color), + cell_fg(db::effort_label(t.effort), Color::Blue, use_color), + Cell::new(&t.title), ]); } if !tasks.is_empty() { diff --git a/src/cmd/search.rs b/src/cmd/search.rs index e85f678128ce807c30121bab8a20aef2dff24c3b..30c4eab315543ea630095ab9c28d09072e56e886 100644 --- a/src/cmd/search.rs +++ b/src/cmd/search.rs @@ -1,8 +1,9 @@ use anyhow::Result; use comfy_table::presets::NOTHING; -use comfy_table::Table; +use comfy_table::{Cell, Table}; use std::path::Path; +use crate::color::{cell_bold, stdout_use_color}; use crate::db; pub fn run(root: &Path, query: &str, json: bool) -> Result<()> { @@ -32,14 +33,11 @@ pub fn run(root: &Path, query: &str, json: bool) -> Result<()> { .collect(); println!("{}", serde_json::to_string(&summary)?); } else { - let c = crate::color::stdout_theme(); + let use_color = stdout_use_color(); let mut table = Table::new(); table.load_preset(NOTHING); for t in &tasks { - table.add_row(vec![ - format!("{}{}{}", c.bold, t.id, c.reset), - t.title.clone(), - ]); + table.add_row(vec![cell_bold(&t.id, use_color), Cell::new(&t.title)]); } if !tasks.is_empty() { println!("{table}"); diff --git a/src/color.rs b/src/color.rs index e348dc65041dd2f30431ad1cd453769531133185..91eb5a50cadd0d7a24f65efd2fb1ff711f7347ef 100644 --- a/src/color.rs +++ b/src/color.rs @@ -1,3 +1,4 @@ +use comfy_table::{Attribute, Cell, Color}; use std::io::IsTerminal; pub struct Theme { @@ -48,3 +49,28 @@ pub fn stderr_theme() -> &'static Theme { &OFF } } + +/// Whether stdout should use colour. +pub fn stdout_use_color() -> bool { + use_color(std::io::stdout().is_terminal()) +} + +/// A table cell with bold text. +pub fn cell_bold(text: impl ToString, use_color: bool) -> Cell { + let cell = Cell::new(text); + if use_color { + cell.add_attribute(Attribute::Bold) + } else { + cell + } +} + +/// A table cell with a coloured foreground. +pub fn cell_fg(text: impl ToString, color: Color, use_color: bool) -> Cell { + let cell = Cell::new(text); + if use_color { + cell.fg(color) + } else { + cell + } +}