use crate::commands::WholeStreamCommand; use crate::prelude::*; use nu_errors::ShellError; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; pub struct Char; #[derive(Deserialize)] struct CharArgs { name: Tagged, } #[async_trait] impl WholeStreamCommand for Char { fn name(&self) -> &str { "char" } fn signature(&self) -> Signature { Signature::build("ansi").required( "character", SyntaxShape::Any, "the name of the character to output", ) } fn usage(&self) -> &str { "Output special characters (eg. 'newline')" } fn examples(&self) -> Vec { vec![ Example { description: "Output newline", example: r#"char newline"#, result: Some(vec![Value::from("\n")]), }, Example { description: "Output prompt character, newline and a hamburger character", example: r#"echo $(char prompt) $(char newline) $(char hamburger)"#, result: Some(vec![ UntaggedValue::string("\u{25b6}").into(), UntaggedValue::string("\n").into(), UntaggedValue::string("\u{2261}").into(), ]), }, ] } async fn run( &self, args: CommandArgs, registry: &CommandRegistry, ) -> Result { let (CharArgs { name }, _) = args.process(®istry).await?; let special_character = str_to_character(&name.item); if let Some(output) = special_character { Ok(OutputStream::one(ReturnSuccess::value( UntaggedValue::string(output).into_value(name.tag()), ))) } else { Err(ShellError::labeled_error( "Unknown character", "unknown character", name.tag(), )) } } } fn str_to_character(s: &str) -> Option { match s { "newline" | "enter" | "nl" => Some("\n".into()), "tab" => Some("\t".into()), "sp" | "space" => Some(" ".into()), // Unicode names came from https://www.compart.com/en/unicode // Private Use Area (U+E000-U+F8FF) "branch" => Some('\u{e0a0}'.to_string()), //  "segment" => Some('\u{e0b0}'.to_string()), //  "identical_to" | "hamburger" => Some('\u{2261}'.to_string()), // ≡ "not_identical_to" | "branch_untracked" => Some('\u{2262}'.to_string()), // ≢ "strictly_equivalent_to" | "branch_identical" => Some('\u{2263}'.to_string()), // ≣ "upwards_arrow" | "branch_ahead" => Some('\u{2191}'.to_string()), // ↑ "downwards_arrow" | "branch_behind" => Some('\u{2193}'.to_string()), // ↓ "up_down_arrow" | "branch_ahead_behind" => Some('\u{2195}'.to_string()), // ↕ "black_right_pointing_triangle" | "prompt" => Some('\u{25b6}'.to_string()), // ▶ "vector_or_cross_product" | "failed" => Some('\u{2a2f}'.to_string()), // ⨯ "high_voltage_sign" | "elevated" => Some('\u{26a1}'.to_string()), // ⚡ "tilde" | "twiddle" | "squiggly" | "home" => Some("~".into()), // ~ "hash" | "hashtag" | "pound_sign" | "sharp" | "root" => Some("#".into()), // # // Weather symbols "sun" => Some("\x1b[33;1m\u{2600}\x1b[0m".to_string()), // Yellow Bold ☀ "moon" => Some("\x1b[36m\u{263d}\x1b[0m".to_string()), // Cyan ☽ "clouds" => Some("\x1b[37;1m\u{2601}\x1b[0m".to_string()), // White Bold ☁ "rain" => Some("\x1b[37;1m\u{2614}\x1b[0m".to_string()), // White Bold ☔ "fog" => Some("\x1b[37;1m\u{2592}\x1b[0m".to_string()), // White Bold ▒ "mist" => Some("\x1b[34m\u{2591}\x1b[0m".to_string()), // Blue ░ "haze" => Some("\x1b[33m\u{2591}\x1b[0m".to_string()), // Yellow ░ "snow" => Some("\x1b[37;1m\u{2744}\x1b[0m".to_string()), // White Bold ❄ "thunderstorm" => Some("\x1b[33;1m\u{26a1}\x1b[0m".to_string()), // Yellow Bold ⚡ // Reference for ansi codes https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 // Another good reference http://ascii-table.com/ansi-escape-sequences.php // For setting title like `echo [$(char title) $(pwd) $(char bel)] | str collect` "title" => Some("\x1b]2;".to_string()), // ESC]2; xterm sets window title "bel" => Some('\x07'.to_string()), // Terminal Bell "backspace" => Some('\x08'.to_string()), // Backspace // Ansi Erase Sequences "clear_screen" => Some("\x1b[J".to_string()), // clears the screen "clear_screen_from_cursor_to_end" => Some("\x1b[0J".to_string()), // clears from cursor until end of screen "clear_screen_from_cursor_to_beginning" => Some("\x1b[1J".to_string()), // clears from cursor to beginning of screen "cls" | "clear_entire_screen" => Some("\x1b[2J".to_string()), // clears the entire screen "erase_line" => Some("\x1b[K".to_string()), // clears the current line "erase_line_from_cursor_to_end" => Some("\x1b[0K".to_string()), // clears from cursor to end of line "erase_line_from_cursor_to_beginning" => Some("\x1b[1K".to_string()), // clears from cursor to start of line "erase_entire_line" => Some("\x1b[2K".to_string()), // clears entire line _ => None, } } #[cfg(test)] mod tests { use super::Char; use super::ShellError; #[test] fn examples_work_as_expected() -> Result<(), ShellError> { use crate::examples::test as test_examples; Ok(test_examples(Char {})?) } }