1
0
mirror of https://github.com/Llewellynvdm/starship.git synced 2024-12-13 06:27:46 +00:00
starship/src/modules/character.rs
David Knaack 2d4b183fce
refactor: replace module_config_derive with serde (#3786)
* refactor: replace module_config_derive with serde

Changes include:
* Removing `starship_module_config_derive` and replacing it with `serde::Deserialize`
* Removing `RootModuleConfig::load_config`. While potentially useful, it was only used in tests. And it would require something like `serde::DeserializeSeed` which is not derived by serde.
* Merging `RootModuleConfig` into `ModuleConfig`
* Implementing a `ValueDeserializer` that holds a reference to a `toml::Value` in `serde_utils.rs`
* Deserialization errors (invalid type) are now logged and include the current key and the struct names
* Unknown keys are now considered an error. "Did you mean?"-messages are still possible

* fix typo

Co-authored-by: Matan Kushner <hello@matchai.dev>

Co-authored-by: Matan Kushner <hello@matchai.dev>
2022-03-26 10:42:19 +01:00

231 lines
7.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use super::{Context, Module, ModuleConfig, Shell};
use crate::configs::character::CharacterConfig;
use crate::formatter::StringFormatter;
/// Creates a module for the prompt character
///
/// The character segment prints an arrow character in a color dependant on the
/// exit-code of the last executed command:
/// - If the exit-code was "0", it will be formatted with `success_symbol`
/// (green arrow by default)
/// - If the exit-code was anything else, it will be formatted with
/// `error_symbol` (red arrow by default)
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
enum ShellEditMode {
Normal,
Insert,
}
const ASSUMED_MODE: ShellEditMode = ShellEditMode::Insert;
// TODO: extend config to more modes
let mut module = context.new_module("character");
let config: CharacterConfig = CharacterConfig::try_load(module.config);
let props = &context.properties;
let exit_code = props.status_code.as_deref().unwrap_or("0");
let keymap = props.keymap.as_str();
let exit_success = exit_code == "0";
// Match shell "keymap" names to normalized vi modes
// NOTE: in vi mode, fish reports normal mode as "default".
// Unfortunately, this is also the name of the non-vi default mode.
// We do some environment detection in src/init.rs to translate.
// The result: in non-vi fish, keymap is always reported as "insert"
let mode = match (&context.shell, keymap) {
(Shell::Fish, "default") | (Shell::Zsh, "vicmd") | (Shell::Cmd, "vi") => {
ShellEditMode::Normal
}
_ => ASSUMED_MODE,
};
let symbol = match mode {
ShellEditMode::Normal => config.vicmd_symbol,
ShellEditMode::Insert => {
if exit_success {
config.success_symbol
} else {
config.error_symbol
}
}
};
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
formatter
.map_meta(|variable, _| match variable {
"symbol" => Some(symbol),
_ => None,
})
.parse(None, Some(context))
});
module.set_segments(match parsed {
Ok(segments) => segments,
Err(error) => {
log::warn!("Error in module `character`:\n{}", error);
return None;
}
});
Some(module)
}
#[cfg(test)]
mod test {
use crate::context::Shell;
use crate::test::ModuleRenderer;
use ansi_term::Color;
#[test]
fn success_status() {
let expected = Some(format!("{} ", Color::Green.bold().paint("")));
// Status code 0
let actual = ModuleRenderer::new("character").status(0).collect();
assert_eq!(expected, actual);
// No status code
let actual = ModuleRenderer::new("character").collect();
assert_eq!(expected, actual);
}
#[test]
fn failure_status() {
let expected = Some(format!("{} ", Color::Red.bold().paint("")));
let exit_values = [1, 54321, -5000];
for status in &exit_values {
let actual = ModuleRenderer::new("character").status(*status).collect();
assert_eq!(expected, actual);
}
}
#[test]
fn custom_symbol() {
let expected_fail = Some(format!("{} ", Color::Red.bold().paint("")));
let expected_success = Some(format!("{} ", Color::Green.bold().paint("")));
let exit_values = [1, 54321, -5000];
// Test failure values
for status in &exit_values {
let actual = ModuleRenderer::new("character")
.config(toml::toml! {
[character]
success_symbol = "[➜](bold green)"
error_symbol = "[✖](bold red)"
})
.status(*status)
.collect();
assert_eq!(expected_fail, actual);
}
// Test success
let actual = ModuleRenderer::new("character")
.config(toml::toml! {
[character]
success_symbol = "[➜](bold green)"
error_symbol = "[✖](bold red)"
})
.status(0)
.collect();
assert_eq!(expected_success, actual);
}
#[test]
fn zsh_keymap() {
let expected_vicmd = Some(format!("{} ", Color::Green.bold().paint("")));
let expected_specified = Some(format!("{} ", Color::Green.bold().paint("V")));
let expected_other = Some(format!("{} ", Color::Green.bold().paint("")));
// zle keymap is vicmd
let actual = ModuleRenderer::new("character")
.shell(Shell::Zsh)
.keymap("vicmd")
.collect();
assert_eq!(expected_vicmd, actual);
// specified vicmd character
let actual = ModuleRenderer::new("character")
.config(toml::toml! {
[character]
vicmd_symbol = "[V](bold green)"
})
.shell(Shell::Zsh)
.keymap("vicmd")
.collect();
assert_eq!(expected_specified, actual);
// zle keymap is other
let actual = ModuleRenderer::new("character")
.shell(Shell::Zsh)
.keymap("visual")
.collect();
assert_eq!(expected_other, actual);
}
#[test]
fn fish_keymap() {
let expected_vicmd = Some(format!("{} ", Color::Green.bold().paint("")));
let expected_specified = Some(format!("{} ", Color::Green.bold().paint("V")));
let expected_other = Some(format!("{} ", Color::Green.bold().paint("")));
// fish keymap is default
let actual = ModuleRenderer::new("character")
.shell(Shell::Fish)
.keymap("default")
.collect();
assert_eq!(expected_vicmd, actual);
// specified vicmd character
let actual = ModuleRenderer::new("character")
.config(toml::toml! {
[character]
vicmd_symbol = "[V](bold green)"
})
.shell(Shell::Fish)
.keymap("default")
.collect();
assert_eq!(expected_specified, actual);
// fish keymap is other
let actual = ModuleRenderer::new("character")
.shell(Shell::Fish)
.keymap("visual")
.collect();
assert_eq!(expected_other, actual);
}
#[test]
fn cmd_keymap() {
let expected_vicmd = Some(format!("{} ", Color::Green.bold().paint("")));
let expected_specified = Some(format!("{} ", Color::Green.bold().paint("V")));
let expected_other = Some(format!("{} ", Color::Green.bold().paint("")));
// cmd keymap is vi
let actual = ModuleRenderer::new("character")
.shell(Shell::Cmd)
.keymap("vi")
.collect();
assert_eq!(expected_vicmd, actual);
// specified vicmd character
let actual = ModuleRenderer::new("character")
.config(toml::toml! {
[character]
vicmd_symbol = "[V](bold green)"
})
.shell(Shell::Cmd)
.keymap("vi")
.collect();
assert_eq!(expected_specified, actual);
// cmd keymap is other
let actual = ModuleRenderer::new("character")
.shell(Shell::Cmd)
.keymap("visual")
.collect();
assert_eq!(expected_other, actual);
}
}