navi/src/cheat.rs

148 lines
4.2 KiB
Rust
Raw Normal View History

2020-03-04 21:01:23 +00:00
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 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 parts = text.split(' ');
while let Some(p) = parts.next() {
match p {
"--multi" => multi = true,
"--header" | "--header-lines" => {
header_lines = parts.next().unwrap().parse::<u8>().unwrap()
}
"--column" => column = Some(parts.next().unwrap().parse::<u8>().unwrap()),
_ => (),
}
}
SuggestionOpts {
header_lines,
column,
multi,
}
}
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("");
2020-03-07 21:03:51 +00:00
let (tag_width, comment_width) = *display::WIDTHS;
2020-03-04 21:01:23 +00:00
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..]);
}
// 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);
2020-03-07 21:03:51 +00:00
match stdin.write_all(
2020-03-04 21:01:23 +00:00
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 fallback = format!("{}/cheats", filesystem::exe_path_string());
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
}