File size: 4,250 Bytes
d90101d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! Centralized display constants for consistent UI messaging
//!
//! This module provides a single source of truth for all display values used
//! across the application. When adding new constants, follow these conventions:
//!
//! - **Placeholders** (missing/unknown data): Use angle brackets `<value>`
//! - **Special markers**: Use square brackets `[value]`
//! - **Status values**: Use lowercase for user-facing strings
//! - **Type discriminators**: Use enums instead of string constants
//!
//! # Examples
//!
//! ```rust,ignore
//! use crate::display_constants::{placeholders, status};
//!
//! // For special values
//! let empty = placeholders::EMPTY;  // "[empty]"
//!
//! // For status indicators
//! info.add_key_value("status", status::ENABLED);  // "[enabled]"
//! ```

use std::fmt;

/// Status indicator values.
///
/// Use lowercase for user-facing status strings to maintain consistency.
pub mod status {
    /// Indicates a resource is enabled/configured
    pub const YES: &str = "[yes]";

    /// Indicates a resource is disabled
    pub const NO: &str = "[no]";
}

/// Table column headers for porcelain (machine-readable) output.
///
/// These headers use the `$` prefix to distinguish them as metadata columns.
pub mod headers {
    /// Default ID column header
    pub const ID: &str = "ID";

    /// Field name column header
    pub const FIELD: &str = "FIELD";

    /// Field value column header
    pub const VALUE: &str = "VALUE";
}

/// Special markers for specific contexts.
///
/// These use square brackets to indicate special/synthetic values.
pub mod markers {
    /// Indicates an empty value (distinct from null/unset)
    pub const EMPTY: &str = "[empty]";

    /// Indicates a built-in (non-user-defined) component
    pub const BUILT_IN: &str = "[built-in]";
}

/// Type discriminator for commands, agents, and custom entries.
///
/// Use this enum instead of string constants for type-safe discrimination
/// between command types in listings and displays.
///
/// # Examples
///
/// ```rust,ignore
/// let cmd_type = CommandType::Agent;
/// info.add_key_value("type", cmd_type.as_str());
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommandType {
    /// Built-in command
    Command,
    /// Agent (AI assistant with specific role)
    Agent,
    /// User-defined custom command
    Custom,
}

impl CommandType {
    /// Returns the string representation of the command type.
    ///
    /// This is the canonical way to convert a CommandType to a string
    /// for display purposes.
    pub const fn as_str(&self) -> &'static str {
        match self {
            Self::Command => "command",
            Self::Agent => "agent",
            Self::Custom => "custom",
        }
    }
}

impl fmt::Display for CommandType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_command_type_display() {
        assert_eq!(CommandType::Command.to_string(), "command");
        assert_eq!(CommandType::Agent.to_string(), "agent");
        assert_eq!(CommandType::Custom.to_string(), "custom");
    }

    #[test]
    fn test_command_type_as_str() {
        assert_eq!(CommandType::Command.as_str(), "command");
        assert_eq!(CommandType::Agent.as_str(), "agent");
        assert_eq!(CommandType::Custom.as_str(), "custom");
    }

    #[test]
    fn test_placeholders_use_square_brackets() {
        // EMPTY uses square brackets like other special markers
        assert!(markers::EMPTY.starts_with('['));
        assert!(markers::EMPTY.ends_with(']'));
    }

    #[test]
    fn test_markers_have_square_brackets() {
        assert!(markers::BUILT_IN.starts_with('['));
        assert!(markers::BUILT_IN.ends_with(']'));
        assert!(markers::EMPTY.starts_with('['));
        assert!(markers::EMPTY.ends_with(']'));
    }

    #[test]
    fn test_status_values_use_square_brackets() {
        // Status values use square brackets to distinguish them from raw strings
        assert!(status::YES.starts_with('['));
        assert!(status::YES.ends_with(']'));
        assert!(status::NO.starts_with('['));
        assert!(status::NO.ends_with(']'));
    }
}