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
|
use crate::prelude::*;
use std::process::{Command, Stdio};
lazy_static! {
pub static ref VAR_TLDR_REGEX: Regex = Regex::new(r"\{\{(.*?)\}\}").expect("Invalid regex");
pub static ref NON_VAR_CHARS_REGEX: Regex = Regex::new(r"[^\da-zA-Z_]").expect("Invalid regex");
}
static VERSION_DISCLAIMER: &str = "The tldr client written in C (the default one in Homebrew) doesn't support markdown files, so navi can't use it.
The client written in Rust is recommended. The one available in npm works, too.";
fn convert_tldr_vars(line: &str) -> String {
let caps = VAR_TLDR_REGEX.find_iter(line);
let mut new_line: String = line.to_string();
for cap in caps {
let braced_var = cap.as_str();
let var = &braced_var[2..braced_var.len() - 2];
let mut new_var = NON_VAR_CHARS_REGEX.replace_all(var, "_").to_string();
if let Some(c) = new_var.chars().next() {
if c.to_string().parse::<u8>().is_ok() {
new_var = format!("example_{new_var}");
}
}
let bracketed_var = format!("<{new_var}>");
new_line = new_line.replace(braced_var, &bracketed_var);
}
new_line
}
fn convert_tldr(line: &str) -> String {
let line = line.trim();
if line.starts_with('-') {
format!("{}{}", "# ", &line[2..line.len() - 1])
} else if line.starts_with('`') {
convert_tldr_vars(&line[1..line.len() - 1])
} else if line.starts_with('%') {
line.to_string()
} else {
"".to_string()
}
}
fn markdown_lines(query: &str, markdown: &str) -> Vec<String> {
format!(
"% {query}, tldr
{markdown}"
)
.lines()
.map(convert_tldr)
.collect()
}
pub fn call(query: &str) -> Result<Vec<String>> {
let args = [query, "--markdown"];
let child = Command::new("tldr")
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn();
let child = match child {
Ok(x) => x,
Err(_) => {
let msg = format!(
"navi was unable to call tldr.
Make sure tldr is correctly installed.
Refer to https://github.com/tldr-pages/tldr for more info.
Note:
{VERSION_DISCLAIMER}
"
);
return Err(anyhow!(msg));
}
};
let out = child.wait_with_output().context("Failed to wait for tldr")?;
if let Some(0) = out.status.code() {
let stdout = out.stdout;
let markdown = String::from_utf8(stdout).context("Output is invalid utf8")?;
let lines = markdown_lines(query, &markdown);
Ok(lines)
} else {
let msg = format!(
"Failed to call:
tldr {}
Output:
{}
Error:
{}
Note:
Please make sure you're using a version that supports the --markdown flag.
If you are already using a supported version you can ignore this message.
{}
",
args.join(" "),
String::from_utf8(out.stdout).unwrap_or_else(|_e| "Unable to get output message".to_string()),
String::from_utf8(out.stderr).unwrap_or_else(|_e| "Unable to get error message".to_string()),
VERSION_DISCLAIMER,
);
Err(anyhow!(msg))
}
}
|