inline code documentation completed to satisfactory level
This commit is contained in:
parent
bc1a1c00a4
commit
c594cd8a6a
|
|
@ -1,7 +1,10 @@
|
||||||
|
//! This file contains functions used in debugging mode.
|
||||||
use log::error;
|
use log::error;
|
||||||
use mpris::PlayerFinder;
|
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) {
|
pub fn print_players(pf: &PlayerFinder) {
|
||||||
match pf.find_all() {
|
match pf.find_all() {
|
||||||
Ok(players) => {
|
Ok(players) => {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,26 @@
|
||||||
|
//! This file deals with formatting and outputting to stdout.
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use log::info;
|
use log::{info, error};
|
||||||
use string_builder::Builder;
|
use string_builder::Builder;
|
||||||
|
|
||||||
use crate::structs::{config::{Field, Config}, data::Data};
|
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 {
|
fn fuzzy_cutoff(str: &str) -> usize {
|
||||||
str.rfind(char::is_whitespace).unwrap_or_else( || usize::MAX)
|
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 {
|
fn get_char_boundary(str: &str, max_len: usize) -> usize {
|
||||||
match max_len > str.len() || str.is_char_boundary(max_len) {
|
match max_len > str.len() || str.is_char_boundary(max_len) {
|
||||||
true => 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<Field>, brk: Option<char>, fuzzy: bool, strings: &mut HashMap<String, String>) {
|
fn cutoff(fields: &Vec<Field>, brk: Option<char>, fuzzy: bool, strings: &mut HashMap<String, String>) {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
if let Some(str) = strings.get_mut(&field.field) {
|
if let Some(str) = strings.get_mut(&field.field) {
|
||||||
|
|
@ -36,25 +56,47 @@ fn cutoff(fields: &Vec<Field>, brk: Option<char>, 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) {
|
fn append_prefix(b: &mut Builder, data: &Data) {
|
||||||
b.append(data.prefix);
|
b.append(data.prefix);
|
||||||
b.append(" ");
|
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) {
|
fn append_fields(b: &mut Builder, cfg: &Config, data: &Data) {
|
||||||
let mut idx = 0; let len = data.field_text.len() as i32;
|
let mut idx = 0;
|
||||||
for string in &cfg.metadata_fields {
|
let len = data.field_text.len() as i32;
|
||||||
if let Some(string) = data.field_text.get(&string.field) {
|
|
||||||
|
for field in &cfg.metadata_fields {
|
||||||
|
if let Some(string) = data.field_text.get(&field.field) {
|
||||||
idx += 1;
|
idx += 1;
|
||||||
b.append(string.clone());
|
b.append(string.clone());
|
||||||
if idx < len {b.append(format!("{}", cfg.metadata_separator))};
|
if idx < len {b.append(cfg.metadata_separator.clone())};
|
||||||
} else {
|
} 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();
|
let mut b = Builder::default();
|
||||||
|
|
||||||
if cfg.render_prefix {
|
if cfg.render_prefix {
|
||||||
|
|
@ -62,9 +104,20 @@ fn build_string(cfg: &Config, data: &mut Data) -> String {
|
||||||
}
|
}
|
||||||
append_fields(&mut b, cfg, data);
|
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) {
|
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() {
|
if (cfg.hide_output && data.current_player.is_none()) || data.field_text.is_empty() || cfg.metadata_fields.is_empty() {
|
||||||
println!("");
|
println!("");
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ impl Rating {
|
||||||
/// c: character to repeat
|
/// c: character to repeat
|
||||||
/// n: number of times to repeat the character
|
/// n: number of times to repeat the character
|
||||||
///
|
///
|
||||||
/// output:
|
/// returns:
|
||||||
/// string of the form '<c> '{n}
|
/// string of the form '<c> '{n}
|
||||||
fn repeat(c: char, n: usize) -> String {
|
fn repeat(c: char, n: usize) -> String {
|
||||||
let mut s = c.to_string();
|
let mut s = c.to_string();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,21 @@
|
||||||
|
//! This file deals with updating the actual message, including proper formatting.
|
||||||
|
use log::{debug, trace};
|
||||||
use mpris::{MetadataValue};
|
use mpris::{MetadataValue};
|
||||||
|
|
||||||
use crate::structs::{config::Config, data::Data};
|
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 {
|
fn value_to_string(v: &MetadataValue, sep: char) -> String {
|
||||||
match v {
|
match v {
|
||||||
MetadataValue::String(v) => v.to_string(),
|
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<String>) -> Option<String> {
|
fn rating_to_string(r: Option<&MetadataValue>, str: &Vec<String>) -> Option<String> {
|
||||||
match r {
|
match r {
|
||||||
Some(rating) => {
|
Some(rating) => {
|
||||||
|
|
@ -38,15 +62,25 @@ fn rating_to_string(r: Option<&MetadataValue>, str: &Vec<String>) -> Option<Stri
|
||||||
|
|
||||||
Some(str[i as usize].clone()) //TODO: still inefficient. would be better to note the idx and load it in print_text
|
Some(str[i as usize].clone()) //TODO: still inefficient. would be better to note the idx and load it in print_text
|
||||||
} else {
|
} else {
|
||||||
|
debug!("failed to convert MetadataValue to f64!");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
trace!("no userRating MetadataValue found!");
|
||||||
None
|
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<String>) {
|
pub fn update_message(cfg: &Config, data: &mut Data, ratings: &Vec<String>) {
|
||||||
if let Some(player) = &data.current_player {
|
if let Some(player) = &data.current_player {
|
||||||
if let Ok(meta) = player.get_metadata() {
|
if let Ok(meta) = player.get_metadata() {
|
||||||
|
|
|
||||||
|
|
@ -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 std::collections::BTreeMap;
|
||||||
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use mpris::{PlayerFinder, Player};
|
use mpris::{PlayerFinder, Player};
|
||||||
use crate::structs::{data::Data, config::Config};
|
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) {
|
fn update_prefix(cfg: &Config, data: &mut char, name: &str) {
|
||||||
if let Some(char) = cfg.player_prefixes.get(name) {
|
if let Some(char) = cfg.player_prefixes.get(name) {
|
||||||
*data = char.clone();
|
*data = char.clone();
|
||||||
|
|
@ -14,11 +24,16 @@ fn update_prefix(cfg: &Config, data: &mut char, name: &str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_players(
|
/// This function updates which player is selected as 'active'.
|
||||||
pf: &PlayerFinder,
|
/// It only considers players present in the config.player_priorities field to be valid candidates, then selects the active one with the highest rating.
|
||||||
cfg: &Config,
|
/// If none of the acceptable players are available, current_player is set to None instead.
|
||||||
mut data: &mut Data,
|
///
|
||||||
) {
|
/// 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());
|
let players = pf.find_all().unwrap_or(Vec::new());
|
||||||
if players.is_empty() {
|
if players.is_empty() {
|
||||||
data.current_player = None;
|
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() {
|
if let Some((_, player)) = active.pop_first() {
|
||||||
update_prefix(cfg, &mut data.prefix, player.identity());
|
update_prefix(cfg, &mut data.prefix, player.identity());
|
||||||
data.current_player = Some(player);
|
data.current_player = Some(player);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue