tcss_core/builtins/
strings.rs1use crate::context::Value;
14
15pub fn uppercase(args: &[Value]) -> Result<Value, String> {
17 if args.len() != 1 {
18 return Err("uppercase() expects 1 argument".to_string());
19 }
20
21 match &args[0] {
22 Value::String(s) => Ok(Value::String(s.to_uppercase())),
23 Value::Color(c) => Ok(Value::Color(c.to_uppercase())),
24 _ => Err("uppercase() expects a string argument".to_string()),
25 }
26}
27
28pub fn lowercase(args: &[Value]) -> Result<Value, String> {
30 if args.len() != 1 {
31 return Err("lowercase() expects 1 argument".to_string());
32 }
33
34 match &args[0] {
35 Value::String(s) => Ok(Value::String(s.to_lowercase())),
36 Value::Color(c) => Ok(Value::Color(c.to_lowercase())),
37 _ => Err("lowercase() expects a string argument".to_string()),
38 }
39}
40
41pub fn concat(args: &[Value]) -> Result<Value, String> {
43 if args.is_empty() {
44 return Err("concat() expects at least 1 argument".to_string());
45 }
46
47 let mut result = String::new();
48
49 for arg in args {
50 result.push_str(&arg.to_css_string());
51 }
52
53 Ok(Value::String(result))
54}
55
56pub fn quote(args: &[Value]) -> Result<Value, String> {
58 if args.len() != 1 {
59 return Err("quote() expects 1 argument".to_string());
60 }
61
62 let s = args[0].to_css_string();
63
64 if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
66 Ok(Value::String(s))
67 } else {
68 Ok(Value::String(format!("\"{}\"", s)))
69 }
70}
71
72pub fn unquote(args: &[Value]) -> Result<Value, String> {
74 if args.len() != 1 {
75 return Err("unquote() expects 1 argument".to_string());
76 }
77
78 let s = args[0].to_css_string();
79
80 let unquoted = if (s.starts_with('"') && s.ends_with('"')) || (s.starts_with('\'') && s.ends_with('\'')) {
82 s[1..s.len()-1].to_string()
83 } else {
84 s
85 };
86
87 Ok(Value::String(unquoted))
88}
89
90pub fn str_length(args: &[Value]) -> Result<Value, String> {
92 if args.len() != 1 {
93 return Err("str_length() expects 1 argument".to_string());
94 }
95
96 let s = args[0].to_css_string();
97 Ok(Value::Number(s.len() as f64))
98}
99
100pub fn str_slice(args: &[Value]) -> Result<Value, String> {
102 if args.len() < 2 || args.len() > 3 {
103 return Err("str_slice() expects 2 or 3 arguments: str, start, [end]".to_string());
104 }
105
106 let s = args[0].to_css_string();
107
108 let start = match &args[1] {
109 Value::Number(n) => *n as usize,
110 _ => return Err("str_slice() expects a number for start index".to_string()),
111 };
112
113 let end = if args.len() == 3 {
114 match &args[2] {
115 Value::Number(n) => *n as usize,
116 _ => return Err("str_slice() expects a number for end index".to_string()),
117 }
118 } else {
119 s.len()
120 };
121
122 if start > s.len() || end > s.len() || start > end {
123 return Err("str_slice() indices out of bounds".to_string());
124 }
125
126 Ok(Value::String(s[start..end].to_string()))
127}
128
129pub fn str_replace(args: &[Value]) -> Result<Value, String> {
131 if args.len() != 3 {
132 return Err("str_replace() expects 3 arguments: str, search, replace".to_string());
133 }
134
135 let s = args[0].to_css_string();
136 let search = args[1].to_css_string();
137 let replace = args[2].to_css_string();
138
139 Ok(Value::String(s.replace(&search, &replace)))
140}
141