diff --git a/Cargo.lock b/Cargo.lock index 9d3cd745a..183670639 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1288,7 +1288,9 @@ dependencies = [ "once_cell", "prost-types", "regex", + "serde", "tokio", + "toml", "tonic", "tracing", "tracing-journald", @@ -1342,6 +1344,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + [[package]] name = "tonic" version = "0.6.1" diff --git a/console.toml b/console.toml new file mode 100644 index 000000000..b0a663e2a --- /dev/null +++ b/console.toml @@ -0,0 +1,9 @@ +no_colors = false +lang = "en_us.UTF-8" +ascii_only = true +palette = "8" + + +[toggles] +color_durations = true +color_terminated = true diff --git a/tokio-console/Cargo.toml b/tokio-console/Cargo.toml index 6e2f7347b..fc844795b 100644 --- a/tokio-console/Cargo.toml +++ b/tokio-console/Cargo.toml @@ -44,3 +44,5 @@ h2 = "0.3" regex = "1.5" once_cell = "1.8" humantime = "2.1.0" +serde = { version = "1", features = ["derive"] } +toml = "0.5" diff --git a/tokio-console/src/config.rs b/tokio-console/src/config.rs index 9379642e2..01e7e5d79 100644 --- a/tokio-console/src/config.rs +++ b/tokio-console/src/config.rs @@ -1,5 +1,9 @@ use crate::view::Palette; use clap::{ArgGroup, Parser as Clap, ValueHint}; +use serde::{Deserialize, Serialize}; +use std::env; +use std::fs; +use std::path::Path; use std::process::Command; use std::str::FromStr; use std::time::Duration; @@ -28,7 +32,7 @@ pub struct Config { #[clap(long = "log", env = "RUST_LOG", default_value = "off")] pub(crate) env_filter: tracing_subscriber::EnvFilter, - #[clap(flatten)] + #[clap(skip)] pub(crate) view_options: ViewOptions, /// How long to continue displaying completed tasks and dropped resources @@ -66,7 +70,7 @@ pub struct Config { #[derive(Debug)] struct RetainFor(Option<Duration>); -#[derive(Clap, Debug, Clone)] +#[derive(Clap, Debug, Clone, Default, Deserialize, Serialize)] #[clap(group = ArgGroup::new("colors").conflicts_with("no-colors"))] pub struct ViewOptions { /// Disable ANSI colors entirely. @@ -107,7 +111,7 @@ pub struct ViewOptions { } /// Toggles on and off color coding for individual UI elements. -#[derive(Clap, Debug, Copy, Clone)] +#[derive(Clap, Debug, Copy, Clone, Deserialize, Serialize)] pub struct ColorToggles { /// Disable color-coding for duration units. #[clap(long = "no-duration-colors", parse(from_flag = std::ops::Not::not), group = "colors")] @@ -118,9 +122,37 @@ pub struct ColorToggles { pub(crate) color_terminated: bool, } +impl Default for ColorToggles { + fn default() -> Self { + Self { + color_durations: true, + color_terminated: true, + } + } +} + // === impl Config === impl Config { + pub fn from_config() -> color_eyre::Result<Self> { + let xdg_config_path = env::var_os("XDG_CONFIG_HOME").map(|mut base| { + base.push("/tokio-console/console.toml"); + base + }); + let xdg_view_opt = xdg_config_path.and_then(ViewOptions::from_config); + let current_view_opt = ViewOptions::from_config("console.toml"); + + let config = Config::parse(); + + match xdg_view_opt.or(current_view_opt) { + None => Ok(config), + Some(view_opt) => Ok(Self { + view_options: view_opt, + ..config + }), + } + } + pub fn trace_init(&mut self) -> color_eyre::Result<()> { let filter = std::mem::take(&mut self.env_filter); use tracing_subscriber::prelude::*; @@ -166,6 +198,16 @@ impl Config { // === impl ViewOptions === impl ViewOptions { + pub(crate) fn from_config<P>(path: P) -> Option<Self> + where + P: AsRef<Path> + std::fmt::Debug, + { + match fs::read_to_string(&path) { + Err(_) => None, + Ok(conf) => toml::from_str(&conf).ok(), + } + } + pub fn is_utf8(&self) -> bool { self.lang.ends_with("UTF-8") && !self.ascii_only } diff --git a/tokio-console/src/main.rs b/tokio-console/src/main.rs index e41241d7c..190843d3f 100644 --- a/tokio-console/src/main.rs +++ b/tokio-console/src/main.rs @@ -2,7 +2,6 @@ use color_eyre::{eyre::eyre, Help, SectionExt}; use console_api::tasks::TaskDetails; use state::State; -use clap::Parser as Clap; use futures::stream::StreamExt; use tokio::sync::{mpsc, watch}; use tui::{ @@ -26,7 +25,7 @@ mod warnings; #[tokio::main] async fn main() -> color_eyre::Result<()> { - let mut args = config::Config::parse(); + let mut args = config::Config::from_config()?; let retain_for = args.retain_for(); args.trace_init()?; tracing::debug!(?args.target_addr, ?args.view_options); diff --git a/tokio-console/src/view/styles.rs b/tokio-console/src/view/styles.rs index 1f183ec0e..069aa38c3 100644 --- a/tokio-console/src/view/styles.rs +++ b/tokio-console/src/view/styles.rs @@ -1,4 +1,5 @@ use crate::config; +use serde::{Deserialize, Serialize}; use std::{borrow::Cow, str::FromStr}; use tui::{ style::{Color, Modifier, Style}, @@ -12,17 +13,23 @@ pub struct Styles { pub(crate) utf8: bool, } -#[derive(Debug, PartialEq, Eq, Copy, Clone)] +// possible_values = &["8", "16", "256", "all", "off"], +#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)] #[repr(u8)] pub enum Palette { + #[serde(rename = "off")] NoColors, /// Use ANSI 8 color palette only. + #[serde(rename = "8")] Ansi8, /// Use ANSI 16 color palette only. + #[serde(rename = "16")] Ansi16, /// Enable ANSI 256-color palette. + #[serde(rename = "256")] Ansi256, /// Enable all RGB colors. + #[serde(rename = "all")] All, }