forked from denisidoro/navi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcheat.rs
158 lines (141 loc) · 4.55 KB
/
cheat.rs
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use crate::display;
use crate::filesystem;
use crate::option::Config;
use regex::Regex;
use std::collections::HashMap;
use std::fs;
use std::io::Write;
pub struct SuggestionOpts {
pub header_lines: u8,
pub column: Option<u8>,
pub multi: bool,
pub delimiter: Option<String>,
}
pub type Value = (String, Option<SuggestionOpts>);
fn gen_snippet(snippet: &str, line: &str) -> String {
if snippet.is_empty() {
line.to_string()
} else {
format!("{}{}", &snippet[..snippet.len() - 2], line)
}
}
fn parse_opts(text: &str) -> SuggestionOpts {
let mut header_lines: u8 = 0;
let mut column: Option<u8> = None;
let mut multi = false;
let mut delimiter: Option<String> = None;
let mut parts = text.split(' ');
while let Some(p) = parts.next() {
match p {
"--multi" => multi = true,
"--header" | "--headers" | "--header-lines" => {
header_lines = parts.next().unwrap().parse::<u8>().unwrap()
}
"--column" => column = Some(parts.next().unwrap().parse::<u8>().unwrap()),
"--delimiter" => delimiter = Some(parts.next().unwrap().to_string()),
_ => (),
}
}
SuggestionOpts {
header_lines,
column,
multi,
delimiter,
}
}
fn parse_variable_line(line: &str) -> (&str, &str, Option<SuggestionOpts>) {
let re = Regex::new(r"^\$\s*([^:]+):(.*)").unwrap();
let caps = re.captures(line).unwrap();
let variable = caps.get(1).unwrap().as_str().trim();
let mut command_plus_opts = caps.get(2).unwrap().as_str().split("---");
let command = command_plus_opts.next().unwrap();
let opts = match command_plus_opts.next() {
Some(o) => Some(parse_opts(o)),
None => None,
};
(variable, command, opts)
}
fn read_file(
path: &str,
variables: &mut HashMap<String, Value>,
stdin: &mut std::process::ChildStdin,
) {
let mut tags = String::from("");
let mut comment = String::from("");
let mut snippet = String::from("");
let (tag_width, comment_width) = *display::WIDTHS;
if let Ok(lines) = filesystem::read_lines(path) {
for l in lines {
let line = l.unwrap();
// tag
if line.starts_with('%') {
tags = String::from(&line[2..]);
}
// metacomment
else if line.starts_with(';') {
}
// comment
else if line.starts_with('#') {
comment = String::from(&line[2..]);
}
// variable
else if line.starts_with('$') {
let (variable, command, opts) = parse_variable_line(&line[..]);
variables.insert(
format!("{};{}", tags, variable),
(String::from(command), opts),
);
}
// snippet with line break
else if line.ends_with('\\') {
snippet = if !snippet.is_empty() {
format!("{}{}", &snippet[..snippet.len() - 2], line)
} else {
line
}
}
// blank
else if line.is_empty() {
}
// snippet
else {
let full_snippet = gen_snippet(&snippet, &line);
match stdin.write_all(
display::format_line(
&tags[..],
&comment[..],
&full_snippet[..],
tag_width,
comment_width,
)
.as_bytes(),
) {
Ok(_) => snippet = String::from(""),
Err(_) => break,
}
}
}
}
}
pub fn read_all(config: &Config, stdin: &mut std::process::ChildStdin) -> HashMap<String, Value> {
let mut variables: HashMap<String, Value> = HashMap::new();
let current_exe = filesystem::exe_path_string();
let fallback = format!(
"{path}/cheats:{path}/../cheats:{path}/../libexec/cheats",
path = current_exe
);
let folders_str = config.path.as_ref().unwrap_or(&fallback);
let folders = folders_str.split(':');
for folder in folders {
if let Ok(paths) = fs::read_dir(folder) {
for path in paths {
read_file(
path.unwrap().path().into_os_string().to_str().unwrap(),
&mut variables,
stdin,
);
}
}
}
variables
}