alma 0.1.1

A Bevy-native modal text editor with Vim-style navigation.
Documentation
//! Escaped text for filesystem diagnostics and status output.

use std::path::Path;

/// Text escaped for single-line user-facing diagnostics.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EscapedDisplayText {
    /// Escaped text safe to interpolate into one-line output.
    value: String,
}

impl EscapedDisplayText {
    /// Builds escaped diagnostic text from displayable text.
    #[must_use]
    pub fn from_display_text(text: impl AsRef<str>) -> Self {
        let mut value = String::new();
        for character in text.as_ref().chars() {
            append_display_character(&mut value, character);
        }

        Self { value }
    }

    /// Builds escaped diagnostic text from a path.
    #[must_use]
    pub fn from_path(path: &Path) -> Self {
        Self::from_display_text(path.to_string_lossy())
    }

    /// Reads the escaped diagnostic text.
    #[must_use]
    pub fn as_str(&self) -> &str {
        &self.value
    }
}

/// Appends one character after escaping output-control input.
fn append_display_character(output: &mut String, character: char) {
    match character {
        '\\' => output.push_str("\\\\"),
        '"' => output.push_str("\\\""),
        '\n' => output.push_str("\\n"),
        '\r' => output.push_str("\\r"),
        '\t' => output.push_str("\\t"),
        character if character.is_control() || is_bidi_control(character) => {
            use std::fmt::Write as _;

            let _written = write!(output, "\\u{{{:X}}}", u32::from(character));
        }
        character => output.push(character),
    }
}

/// Returns whether `character` can visually reorder diagnostic text.
const fn is_bidi_control(character: char) -> bool {
    matches!(
        character,
        '\u{061C}'
            | '\u{200E}'
            | '\u{200F}'
            | '\u{202A}'..='\u{202E}'
            | '\u{2066}'..='\u{2069}'
    )
}