1
0
mirror of https://github.com/Llewellynvdm/starship.git synced 2024-06-04 01:20:51 +00:00
starship/src/modules/battery.rs
Tilmann Meyer 2233683410
feat: add error messaging (#1576)
This creates a custom logger for the log crate which logs everything to a file (/tmp/starship/session_$STARSHIP_SESSION_KEY.log) and it logs everything above Warn to stderr, but only if the log file does not contain the line that should be logged resulting in an error or warning to be only logged at the first starship invocation after opening the shell.
2020-09-28 16:38:50 -04:00

150 lines
5.1 KiB
Rust

use super::{Context, Module, RootModuleConfig, Shell};
use crate::configs::battery::BatteryConfig;
use crate::formatter::StringFormatter;
/// Creates a module for the battery percentage and charging state
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
// TODO: Update when v1.0 printing refactor is implemented to only
// print escapes in a prompt context.
let percentage_char = match context.shell {
Shell::Zsh => "%%", // % is an escape in zsh, see PROMPT in `man zshmisc`
_ => "%",
};
let battery_status = get_battery_status()?;
let BatteryStatus { state, percentage } = battery_status;
let mut module = context.new_module("battery");
let config: BatteryConfig = BatteryConfig::try_load(module.config);
// Parse config under `display`.
// Select the first style that match the threshold,
// if all thresholds are lower do not display battery module.
let display_style = config
.display
.iter()
.find(|display_style| percentage <= display_style.threshold as f32)?;
// Parse the format string and build the module
match StringFormatter::new(config.format) {
Ok(formatter) => {
let formatter = formatter
.map_meta(|variable, _| match variable {
"symbol" => match state {
battery::State::Full => Some(config.full_symbol),
battery::State::Charging => Some(config.charging_symbol),
battery::State::Discharging => Some(config.discharging_symbol),
battery::State::Unknown => config.unknown_symbol,
battery::State::Empty => config.empty_symbol,
_ => {
log::debug!("Unhandled battery state `{}`", state);
None
}
},
_ => None,
})
.map_style(|style| match style {
"style" => Some(Ok(display_style.style)),
_ => None,
})
.map(|variable| match variable {
"percentage" => Some(Ok(format!("{}{}", percentage.round(), percentage_char))),
_ => None,
});
match formatter.parse(None) {
Ok(format_string) => {
module.set_segments(format_string);
Some(module)
}
Err(e) => {
log::warn!("Cannot parse `battery.format`: {}", e);
None
}
}
}
Err(e) => {
log::warn!("Cannot load `battery.format`: {}", e);
None
}
}
}
fn get_battery_status() -> Option<BatteryStatus> {
let battery_manager = battery::Manager::new().ok()?;
let batteries = battery_manager.batteries().ok()?;
let battery_contructor = batteries
.filter_map(|battery| match battery {
Ok(battery) => {
log::debug!("Battery found: {:?}", battery);
Some(BatteryInfo {
energy: battery.energy().value,
energy_full: battery.energy_full().value,
state: battery.state(),
})
}
Err(e) => {
log::warn!("Unable to access battery information:\n{}", &e);
None
}
})
.fold(
BatteryInfo {
energy: 0.0,
energy_full: 0.0,
state: battery::State::Unknown,
},
|mut acc, x| {
acc.energy += x.energy;
acc.energy_full += x.energy_full;
acc.state = merge_battery_states(acc.state, x.state);
acc
},
);
if battery_contructor.energy_full != 0.0 {
let battery = BatteryStatus {
percentage: battery_contructor.energy / battery_contructor.energy_full * 100.0,
state: battery_contructor.state,
};
log::debug!("Battery status: {:?}", battery);
Some(battery)
} else {
None
}
}
/// the merge returns Charging if at least one is charging
/// Discharging if at least one is Discharging
/// Full if both are Full or one is Full and the other Unknow
/// Empty if both are Empty or one is Empty and the other Unknow
/// Unknown otherwise
fn merge_battery_states(state1: battery::State, state2: battery::State) -> battery::State {
use battery::State::{Charging, Discharging, Unknown};
if state1 == Charging || state2 == Charging {
Charging
} else if state1 == Discharging || state2 == Discharging {
Discharging
} else if state1 == state2 {
state1
} else if state1 == Unknown {
state2
} else if state2 == Unknown {
state1
} else {
Unknown
}
}
struct BatteryInfo {
energy: f32,
energy_full: f32,
state: battery::State,
}
#[derive(Debug)]
struct BatteryStatus {
percentage: f32,
state: battery::State,
}