1use std::path::PathBuf;
2use std::fs::read_dir;
3
4use crate::framebuffer_types::{ Dimensions, Point };
5
6pub fn min(one: usize, two: usize) -> usize {
7 if one > two { two } else { one }
8}
9
10pub fn random_u32(seed: u32) -> u32 {
11 let mut seed = seed;
12 seed ^= seed << 13;
13 seed ^= seed >> 17;
14 seed ^= seed >> 5;
15 seed
16}
17
18pub trait Substring {
19 fn substring(&self, start: usize, end: usize) -> &str;
20 fn remove(&self, index: usize, len: usize) -> String;
21 fn remove_last(&self) -> String;
22 fn find_substring(&self, substr: &str) -> Option<usize>;
23}
24
25impl Substring for String {
26 fn substring(&self, start: usize, end: usize) -> &str {
27 let mut byte_start = 0;
28 let mut byte_end = 0;
29 let mut chars = self.chars();
30 for i in 0..end {
31 let char_length = chars.next().unwrap().len_utf8();
32 if i < start {
33 byte_start += char_length;
34 }
35 if i == end {
36 break;
37 }
38 byte_end += char_length;
39 }
40 &self[byte_start..byte_end]
41 }
50
51 fn remove(&self, index: usize, len: usize) -> String {
52 self.substring(0, index).to_string() + self.substring(index + len, self.chars().count())
53 }
54
55 fn remove_last(&self) -> String {
56 self.substring(0, self.chars().count() - 1).to_string()
57 }
58
59 fn find_substring(&self, substr: &str) -> Option<usize> {
60 let substr_len = substr.chars().count();
62 let self_len = self.chars().count();
63 if substr_len <= self_len {
64 for start in 0..=(self_len - substr_len) {
65 if self.substring(start, start + substr_len) == substr {
66 return Some(start);
67 }
68 }
69 }
70 None
71 }
72}
73
74pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_per_line: usize, one_extra: bool) -> Vec<(bool, usize, String)> {
76 let mut actual_lines = Vec::new();
77 for (line_num, real_line) in lines.enumerate() {
78 let mut line = real_line.to_string() + if one_extra { " " } else { "" };
79 let mut first = true;
80 loop {
81 if line.chars().count() <= max_chars_per_line {
82 actual_lines.push((first, line_num, line));
83 break;
84 } else {
85 let mut line_chars = line.chars();
86 let mut push_string = String::new();
87 for _i in 0..max_chars_per_line {
88 push_string += &line_chars.next().unwrap().to_string();
89 }
90 actual_lines.push((first, line_num, push_string));
91 line = line_chars.collect();
92 }
93 first = false;
94 }
95 }
96 actual_lines
97}
98
99pub fn concat_paths(current_path: &str, add_path: &str) -> Result<PathBuf, ()> {
100 let mut new_path = PathBuf::from(current_path);
101 if new_path.is_file() {
103 new_path = new_path.parent().unwrap().to_path_buf();
104 }
105 if add_path.starts_with("/") {
106 new_path = PathBuf::from(add_path);
108 } else {
109 for part in add_path.split("/") {
111 if part == ".." {
112 if let Some(parent) = new_path.parent() {
113 new_path = parent.to_path_buf();
114 } else {
115 return Err(());
116 }
117 } else {
118 new_path.push(part);
119 }
120 }
121 }
122 Ok(new_path)
123}
124
125pub fn format_seconds(seconds: u64) -> String {
127 let mut m = (seconds / 60).to_string(); if m.len() == 1 {
129 m = "0".to_string() + &m;
130 }
131 let mut s = (seconds % 60).to_string();
132 if s.len() == 1 {
133 s = "0".to_string() + &s;
134 }
135 m + ":" + &s
136}
137
138pub const HEX_CHARS: [char; 16] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
139
140pub fn u8_to_hex(u: u8) -> String {
141 let mut h = String::new();
142 h.push(HEX_CHARS[(u / 16) as usize]);
143 h.push(HEX_CHARS[(u % 16) as usize]);
144 h
145}
146
147pub fn hex_to_u8(c1: char, c2: char) -> u8 {
148 (HEX_CHARS.iter().position(|c| c == &c1).unwrap() * 16 + HEX_CHARS.iter().position(|c| c == &c2).unwrap()) as u8
149}
150
151pub fn is_hex(c: char) -> bool {
152 HEX_CHARS.iter().any(|hc| hc == &c)
153}
154
155pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool {
156 let x = point[0];
157 let y = point[1];
158 let x2 = top_left[0];
159 let y2 = top_left[1];
160 let x3 = x2 + size[0];
161 let y3 = y2 + size[1];
162 x >= x2 && y >= y2 && x <= x3 && y <= y3
163}
164
165pub fn get_rest_of_split(split: &mut dyn Iterator<Item = &str>, sep: Option<&str>) -> String {
166 let mut rest = String::new();
167 let mut n = split.next();
168 loop {
169 if n.is_none() {
170 break;
171 }
172 rest += &n.unwrap();
173 n = split.next();
174 if n.is_some() && sep.is_some() {
175 rest += sep.unwrap();
176 }
177 }
178 rest
179}
180
181pub fn path_autocomplete(current_path: &str, partial_path: &str) -> Option<String> {
182 if let Ok(new_path) = concat_paths(current_path, &partial_path) {
183 let partial_name;
184 let parent;
185 if partial_path.ends_with("/") {
186 partial_name = "".to_string();
187 parent = new_path.as_path();
188 } else {
189 partial_name = new_path.clone().file_name().unwrap().to_os_string().to_string_lossy().to_string();
191 parent = new_path.parent().unwrap();
192 };
193 if let Ok(entries) = read_dir(parent) {
194 for entry in entries {
195 let entry_path = entry.unwrap().path();
196 let name = entry_path.file_name().unwrap().to_os_string().to_string_lossy().to_string();
197 if name.starts_with(&partial_name) {
198 let add = name[partial_name.len()..].to_string();
199 let add_len = add.len();
200 return Some(add + if entry_path.is_dir() && add_len > 0 {
201 "/"
202 } else {
203 ""
204 });
205 }
206 }
207 }
208 None
209 } else {
210 None
211 }
212}
213
214pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> {
215 let mut files = Vec::new();
216 for entry in read_dir(dir).unwrap() {
217 let path = entry.unwrap().path();
218 if path.is_dir() {
219 files.extend(get_all_files(path));
220 } else {
221 files.push(path);
222 }
223 }
224 files
225}
226