From c594cd8a6ac062579b43a804eb6b93546a4fecd2 Mon Sep 17 00:00:00 2001 From: djairoh Date: Thu, 11 May 2023 17:00:38 +0200 Subject: [PATCH] inline code documentation completed to satisfactory level --- src/print_players.rs | 3 ++ src/print_text.rs | 71 +++++++++++++++++++++++++++++++++++++------ src/structs/config.rs | 2 +- src/update_message.rs | 34 +++++++++++++++++++++ src/update_players.rs | 26 +++++++++++++--- 5 files changed, 121 insertions(+), 15 deletions(-) diff --git a/src/print_players.rs b/src/print_players.rs index 2571827..1bc2ca0 100644 --- a/src/print_players.rs +++ b/src/print_players.rs @@ -1,7 +1,10 @@ +//! This file contains functions used in debugging mode. use log::error; use mpris::PlayerFinder; +/// This function finds and prints the identities of all players on the system to stdout. +/// It is intended to help people find the right identities to use in their configuration files. pub fn print_players(pf: &PlayerFinder) { match pf.find_all() { Ok(players) => { diff --git a/src/print_text.rs b/src/print_text.rs index 9272cbb..d038e21 100644 --- a/src/print_text.rs +++ b/src/print_text.rs @@ -1,14 +1,26 @@ +//! This file deals with formatting and outputting to stdout. use std::collections::HashMap; -use log::info; +use log::{info, error}; use string_builder::Builder; use crate::structs::{config::{Field, Config}, data::Data}; - +/// This function finds the last whitespace in a string and returns its' index. +/// If there is no whitespace it returns usize::MAX instead. fn fuzzy_cutoff(str: &str) -> usize { str.rfind(char::is_whitespace).unwrap_or_else( || usize::MAX) } +/// This function helps deal with non-UTF8 strings. +/// It returns the nearest character boundary from the given usize. +/// Note it only looks before the max_len indicated index (that is, it never returns a value > max_len). +/// +/// Input: +/// str: string to check +/// max_len: usize to check if it's a boundary or not +/// +/// Returns: +/// usize indicatheing the index of the character boundary nearest max_len. fn get_char_boundary(str: &str, max_len: usize) -> usize { match max_len > str.len() || str.is_char_boundary(max_len) { true => max_len, @@ -22,6 +34,14 @@ fn get_char_boundary(str: &str, max_len: usize) -> usize { } } +/// This function applies truncation to each strings in the given hashmap, as dictated by the values in the given Fields. +/// It also applies fuzzy cutoff if the configuration option for this is enabled. +/// +/// Input: +/// field: Vec of Fields, necessary to know where to truncate each string. +/// brk: Optional, character to insert when a string is truncated. +/// fuzzy: Whether to apply the fuzzy truncation function or not. +/// strings: Hashmap containing the strings to be truncated. Key values should match with the names of the Fields Vec. fn cutoff(fields: &Vec, brk: Option, fuzzy: bool, strings: &mut HashMap) { for field in fields { if let Some(str) = strings.get_mut(&field.field) { @@ -36,25 +56,47 @@ fn cutoff(fields: &Vec, brk: Option, fuzzy: bool, strings: &mut Has } } +/// This function appends the prefix character to the given string builder. +/// +/// Input: +/// b: mutable String builder to append to. +/// data: Data struct containing the current prefix character. fn append_prefix(b: &mut Builder, data: &Data) { b.append(data.prefix); b.append(" "); } +/// This function appends each field in the Data.field_text Hashmap to the given String builder. +/// It does some formatting as well. +/// +/// Input: +/// b: mutable String builder to append to. +/// cfg: Config struct for the program. +/// data: Data struct containing the field-text HashMap. fn append_fields(b: &mut Builder, cfg: &Config, data: &Data) { - let mut idx = 0; let len = data.field_text.len() as i32; - for string in &cfg.metadata_fields { - if let Some(string) = data.field_text.get(&string.field) { + let mut idx = 0; + let len = data.field_text.len() as i32; + + for field in &cfg.metadata_fields { + if let Some(string) = data.field_text.get(&field.field) { idx += 1; b.append(string.clone()); - if idx < len {b.append(format!("{}", cfg.metadata_separator))}; + if idx < len {b.append(cfg.metadata_separator.clone())}; } else { - info!("failed to get {} value!", string.field); + info!("failed to get {} value!", field.field); } } } -fn build_string(cfg: &Config, data: &mut Data) -> String { +/// This higher level function formats and appends the entire output to a string builder. +/// +/// Input: +/// cfg: Config struct for the program. +/// data: Data struct containing the state of the program. +/// +/// Returns: +/// String to be outputted. +fn build_string(cfg: &Config, data: &Data) -> String { let mut b = Builder::default(); if cfg.render_prefix { @@ -62,9 +104,20 @@ fn build_string(cfg: &Config, data: &mut Data) -> String { } append_fields(&mut b, cfg, data); - b.string().unwrap_or("Failed to unwrap string!".to_owned()) + b.string().unwrap_or_else(|e| { + error!("{e}"); + "Failed to unwrap string!".to_owned() + }) } +/// This higher level function calls the appropriate string building function depending on a few settings: +/// If either no metadata is specified in the config or no metadata is currently available => it prints an empty line. +/// If no player is currently active and hide_output is true => it prints an empty line. +/// Else => it builds and prints the appropriate output string. +/// +/// Input: +/// cfg: Config struct for the program. +/// data: mutable Data struct containing the state of the program. pub fn print_text(cfg: &Config, data: &mut Data) { if (cfg.hide_output && data.current_player.is_none()) || data.field_text.is_empty() || cfg.metadata_fields.is_empty() { println!(""); diff --git a/src/structs/config.rs b/src/structs/config.rs index 01f3692..546b501 100644 --- a/src/structs/config.rs +++ b/src/structs/config.rs @@ -58,7 +58,7 @@ impl Rating { /// c: character to repeat /// n: number of times to repeat the character /// - /// output: + /// returns: /// string of the form ' '{n} fn repeat(c: char, n: usize) -> String { let mut s = c.to_string(); diff --git a/src/update_message.rs b/src/update_message.rs index 561b428..51fa39c 100644 --- a/src/update_message.rs +++ b/src/update_message.rs @@ -1,7 +1,21 @@ +//! This file deals with updating the actual message, including proper formatting. +use log::{debug, trace}; use mpris::{MetadataValue}; use crate::structs::{config::Config, data::Data}; +/// This function converts a given MetadataValue to a String. +/// Note that two types of the MetadataValue enum are currently unsupported: +/// Both the Map and Unsupported types currently lead the program to panic! +/// The HashMap because I honestly don't know when a metadata value would be encoded as such (and am too lazy to dig through the crate's source code), +/// The Unsupported type should be self-explanatory. +/// +/// Input: +/// v: MetadataValue to convert. +/// sep: seperation character to insert between entries of a Vec. +/// +/// Output: +/// String representing the input MetadataValue. fn value_to_string(v: &MetadataValue, sep: char) -> String { match v { MetadataValue::String(v) => v.to_string(), @@ -28,6 +42,16 @@ fn value_to_string(v: &MetadataValue, sep: char) -> String { } } +/// This function converts one specific instance of MetadataValue to an appropriate String. +/// It deals with the xesam:userRating type. This is a float (0.0 <= v <= 1.0), but should be represented on a scale fron 0 to 10 (according to me). +/// As such, it converts the float value to a visually appealing 5-symbol string. +/// +/// Input: +/// r: MetadataValue, should be of the enum type f64 (unchecked). +/// str: Vec containing precomputed rating strings to select from. +/// +/// Output: +/// Some(String) if a rating exists, None otherwise. fn rating_to_string(r: Option<&MetadataValue>, str: &Vec) -> Option { match r { Some(rating) => { @@ -38,15 +62,25 @@ fn rating_to_string(r: Option<&MetadataValue>, str: &Vec) -> Option { + trace!("no userRating MetadataValue found!"); None }, } } +/// This higher level function updates the to be output Hashmap of strings. +/// It does so by querying each metadata field in config to the current player, then updating the Hashmap in Data with the new value(s). +/// "xesam:userRating" is treated separately, due to requiring a different output format. +/// +/// Input: +/// cfg: Config struct for the program. Contains the wanted metadata fields. +/// data: mutable Data struct for the program. Its' Hashmap containing strings is updated. +/// ratings: Vec of precomputed rating strings. pub fn update_message(cfg: &Config, data: &mut Data, ratings: &Vec) { if let Some(player) = &data.current_player { if let Ok(meta) = player.get_metadata() { diff --git a/src/update_players.rs b/src/update_players.rs index 988b6ad..fde6c5a 100644 --- a/src/update_players.rs +++ b/src/update_players.rs @@ -1,9 +1,19 @@ +//! This file deals with updating the active player. +//! It also updates the prefix, which kind of breaks seperation of concerns, but this saves me a lot of headache so I'm not changing it. use std::collections::BTreeMap; use log::trace; use mpris::{PlayerFinder, Player}; use crate::structs::{data::Data, config::Config}; + +/// This function updates the current prefix. +/// If no entry is found in config containing the active player, a default value is used instead ('>'). +/// +/// Input: +/// cfg: Config struct for the program, containing the hashmap of prefixes. +/// data: mutable char containing the active prefix. +/// name: name of active player, to fetch the appropriate prefix from cfg. fn update_prefix(cfg: &Config, data: &mut char, name: &str) { if let Some(char) = cfg.player_prefixes.get(name) { *data = char.clone(); @@ -14,11 +24,16 @@ fn update_prefix(cfg: &Config, data: &mut char, name: &str) { } } -pub fn update_players( - pf: &PlayerFinder, - cfg: &Config, - mut data: &mut Data, -) { +/// This function updates which player is selected as 'active'. +/// It only considers players present in the config.player_priorities field to be valid candidates, then selects the active one with the highest rating. +/// If none of the acceptable players are available, current_player is set to None instead. +/// +/// Input: +/// pf: PlayerFinder instance of the program. +/// cfg: Config struct of the program, containing the list of acceptable players. +/// data: mutable Data struct of the program, containing a marker for the currently active player. +pub fn update_players(pf: &PlayerFinder, cfg: &Config, mut data: &mut Data) { + // get all acceptable players let players = pf.find_all().unwrap_or(Vec::new()); if players.is_empty() { data.current_player = None; @@ -31,6 +46,7 @@ pub fn update_players( } } + // select the player with the highest priority. if let Some((_, player)) = active.pop_first() { update_prefix(cfg, &mut data.prefix, player.identity()); data.current_player = Some(player);