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
use std::borrow::Cow;
use std::mem;
use lazy_static::lazy_static;
use percent_encoding::percent_decode;
use regex::Regex;
use crate::shell;
pub fn split_at_comma(source: &str) -> Vec<String> {
let mut items = Vec::new();
let mut escaped = false;
let mut item = String::new();
for ch in source.chars() {
if ch == ',' && !escaped {
item = item.replace("\\,", ",");
let mut new_item = String::new();
mem::swap(&mut item, &mut new_item);
items.push(new_item);
} else {
item.push(ch);
}
escaped = ch == '\\';
}
if !item.is_empty() {
items.push(item.replace("\\,", ","));
}
items
}
pub fn escape_filename<'t>(filename: &'t str) -> Cow<'t, str> {
lazy_static! {
static ref SPECIAL_CHARS: Regex = if cfg!(target_os = "windows") {
Regex::new(r"[[:ascii:]&&[^0-9a-zA-Z._:\\-]]").unwrap()
} else {
Regex::new(r"[[:ascii:]&&[^0-9a-zA-Z._/-]]").unwrap()
};
}
SPECIAL_CHARS.replace_all(&*filename, r"\$0")
}
pub fn decode_uri(uri: &str) -> Option<String> {
let path = match uri.split_at(8) {
("file:///", path) => path,
_ => return None,
};
let path = percent_decode(path.as_bytes()).decode_utf8().ok()?;
if cfg!(target_os = "windows") {
lazy_static! {
static ref SLASH: Regex = Regex::new(r"/").unwrap();
}
Some(String::from(SLASH.replace_all(&*path, r"\")))
} else {
Some("/".to_owned() + &path)
}
}
pub fn about_comments() -> String {
format!(
"Build on top of neovim\n\
Minimum supported neovim version: {}",
shell::MINIMUM_SUPPORTED_NVIM_VERSION
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_comma_split() {
let res = split_at_comma("a,b");
assert_eq!(2, res.len());
assert_eq!("a", res[0]);
assert_eq!("b", res[1]);
let res = split_at_comma("a,b\\,c");
assert_eq!(2, res.len());
assert_eq!("a", res[0]);
assert_eq!("b,c", res[1]);
}
}