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
pub fn is_digit(string: &str) -> bool {
string.chars().all(|c| c.is_ascii_digit())
}
pub fn is_exec(string: &str) -> bool {
string.starts_with("$ ")
}
pub fn is_garden(string: &str) -> bool {
string.starts_with(':')
}
pub fn is_group(string: &str) -> bool {
string.starts_with('%')
}
pub fn is_tree(string: &str) -> bool {
string.starts_with('@')
}
pub fn is_graft(string: &str) -> bool {
string.contains("::")
}
pub fn is_git_dir(string: &str) -> bool {
string.len() > 4 && string.ends_with(".git") && !string.ends_with("/.git")
}
pub fn trim(string: &str) -> &str {
let needs_trim = is_group(string) || is_tree(string) || is_garden(string);
if !string.is_empty() && needs_trim {
&string[1..]
} else {
string
}
}
pub fn trim_exec(string: &str) -> &str {
let prefix = "$ ";
let prefix_len = prefix.len();
if string.len() >= prefix_len && string.starts_with(prefix) {
&string[prefix_len..]
} else {
string
}
}
pub fn split_string<'a>(string: &'a str, split: &str) -> (bool, &'a str, &'a str) {
let end = string.len();
let split_len = split.len();
let before = string.find(split).unwrap_or(end);
let ok = before <= (end - split_len);
let after = if ok { before + split_len } else { before };
(ok, &string[..before], &string[after..])
}
pub fn split_graft(string: &str) -> (bool, &str, &str) {
split_string(string, "::")
}
pub fn trim_graft(string: &str) -> Option<String> {
let (ok, _before, after) = split_graft(string);
if !ok {
return None;
}
let result;
if is_garden(string) {
result = ":".to_string() + after;
} else if is_group(string) {
result = "%".to_string() + after;
} else if is_tree(string) {
result = "@".to_string() + after;
} else {
result = after.to_string();
}
Some(result)
}
pub fn graft_basename(string: &str) -> Option<String> {
let (ok, before, _after) = split_graft(string);
if !ok {
return None;
}
let result = if is_garden(string) || is_group(string) || is_tree(string) {
trim(before)
} else {
before
}
.to_string();
Some(result)
}
pub fn escape_shell_variables(string: &str) -> String {
let mut result = String::new();
let mut potential_variable = false;
for c in string.chars() {
if potential_variable {
if c.is_alphanumeric() || c == '_' {
result.push('$'); result.push(c);
} else if c == '$' {
result.push('$'); } else {
result.push(c);
}
potential_variable = false;
} else {
result.push(c);
potential_variable = c == '$';
}
}
result
}