1use console::{style, StyledObject};
9
10use crate::cache::SymbolType;
11use crate::constraints::LockLevel;
12
13pub struct TreeRenderer {
15 pub use_unicode: bool,
16}
17
18impl Default for TreeRenderer {
19 fn default() -> Self {
20 Self { use_unicode: true }
21 }
22}
23
24impl TreeRenderer {
25 pub fn branch(&self) -> &'static str {
27 if self.use_unicode {
28 "├─"
29 } else {
30 "|-"
31 }
32 }
33
34 pub fn last_branch(&self) -> &'static str {
36 if self.use_unicode {
37 "└─"
38 } else {
39 "`-"
40 }
41 }
42
43 pub fn vertical(&self) -> &'static str {
45 if self.use_unicode {
46 "│ "
47 } else {
48 "| "
49 }
50 }
51
52 pub fn separator(&self, width: usize) -> String {
54 if self.use_unicode {
55 "━".repeat(width)
56 } else {
57 "=".repeat(width)
58 }
59 }
60}
61
62pub fn format_symbol_ref(name: &str, symbol_type: &SymbolType, line: usize) -> String {
64 let type_abbrev = match symbol_type {
65 SymbolType::Function => "fn",
66 SymbolType::Method => "method",
67 SymbolType::Class => "class",
68 SymbolType::Interface => "iface",
69 SymbolType::Type => "type",
70 SymbolType::Enum => "enum",
71 SymbolType::Struct => "struct",
72 SymbolType::Trait => "trait",
73 SymbolType::Const => "const",
74 };
75 format!("{} ({}:{})", name, type_abbrev, line)
76}
77
78pub fn format_symbol_ref_range(name: &str, symbol_type: &SymbolType, lines: [usize; 2]) -> String {
80 let type_abbrev = match symbol_type {
81 SymbolType::Function => "fn",
82 SymbolType::Method => "method",
83 SymbolType::Class => "class",
84 SymbolType::Interface => "iface",
85 SymbolType::Type => "type",
86 SymbolType::Enum => "enum",
87 SymbolType::Struct => "struct",
88 SymbolType::Trait => "trait",
89 SymbolType::Const => "const",
90 };
91 format!("{} ({}:{}-{})", name, type_abbrev, lines[0], lines[1])
92}
93
94pub fn format_constraint_level(level: &LockLevel) -> StyledObject<&'static str> {
96 match level {
97 LockLevel::Frozen => style("frozen").red().bold(),
98 LockLevel::Restricted => style("restricted").yellow(),
99 LockLevel::ApprovalRequired => style("approval-required").yellow(),
100 LockLevel::TestsRequired => style("tests-required").cyan(),
101 LockLevel::DocsRequired => style("docs-required").cyan(),
102 LockLevel::ReviewRequired => style("review-required").cyan(),
103 LockLevel::Normal => style("normal").green(),
104 LockLevel::Experimental => style("experimental").magenta(),
105 }
106}
107
108pub fn constraint_level_str(level: &LockLevel) -> &'static str {
110 match level {
111 LockLevel::Frozen => "frozen",
112 LockLevel::Restricted => "restricted",
113 LockLevel::ApprovalRequired => "approval-required",
114 LockLevel::TestsRequired => "tests-required",
115 LockLevel::DocsRequired => "docs-required",
116 LockLevel::ReviewRequired => "review-required",
117 LockLevel::Normal => "normal",
118 LockLevel::Experimental => "experimental",
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_tree_renderer() {
128 let renderer = TreeRenderer::default();
129 assert_eq!(renderer.branch(), "├─");
130 assert_eq!(renderer.last_branch(), "└─");
131 assert_eq!(renderer.vertical(), "│ ");
132 }
133
134 #[test]
135 fn test_format_symbol_ref() {
136 assert_eq!(
137 format_symbol_ref("validate", &SymbolType::Function, 45),
138 "validate (fn:45)"
139 );
140 assert_eq!(
141 format_symbol_ref("User", &SymbolType::Class, 10),
142 "User (class:10)"
143 );
144 }
145
146 #[test]
147 fn test_format_symbol_ref_range() {
148 assert_eq!(
149 format_symbol_ref_range("validate", &SymbolType::Function, [45, 89]),
150 "validate (fn:45-89)"
151 );
152 }
153}