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
use ast::with_error_checking_parse;
use core::{Match, MatchType, Session};
use typeinf::get_function_declaration;
use syntex_syntax::ast::ImplItemKind;
pub fn snippet_for_match(m: &Match, session: &Session) -> String {
match m.mtype {
MatchType::Function => {
let method = get_function_declaration(&m, session);
if let Some(m) = MethodInfo::from_source_str(&method) {
m.snippet()
} else {
"".into()
}
}
_ => m.matchstr.clone()
}
}
struct MethodInfo {
name: String,
args: Vec<String>
}
impl MethodInfo {
fn from_source_str(source: &str) -> Option<MethodInfo> {
let trim: &[_] = &['\n', '\r', '{', ' '];
let decorated = format!("{} {{}}()", source.trim_right_matches(trim));
with_error_checking_parse(decorated, |p| {
use std::result::Result::{Ok, Err};
use syntex_syntax::diagnostic::FatalError;
match p.parse_impl_item() {
Ok(method) => {
match method.node {
ImplItemKind::Method(ref msig, _) => {
let ref decl = msig.decl;
Some(MethodInfo {
name: method.ident.name.as_str().to_string(),
args: decl.inputs
.iter()
.map(|arg| {
let ref codemap = p.sess.span_diagnostic.cm;
match codemap.span_to_snippet(arg.pat.span) {
Ok(name) => name,
_ => "".into()
}
})
.collect()
})
},
_ => {
debug!("Unable to parse method declaration. |{}|", source);
None
}
}
},
Err(FatalError) => {
debug!("Unable to parse method declaration. |{}|", source);
None
}
}
})
}
fn snippet(&self) -> String {
format!("{}({})",
self.name,
&self.args
.iter()
.filter(|&s| *s != "self")
.enumerate()
.fold(String::new(), |cur, (i, ref s)| {
let arg = format!("${{{}:{}}}", i + 1, s);
let delim = if i > 0 {
", "
} else {
""
};
cur + delim + &arg
}))
}
}
#[test]
fn method_info_test() {
let info = MethodInfo::from_source_str("pub fn new() -> Vec<T>").unwrap();
assert_eq!(info.name, "new");
assert_eq!(info.args.len(), 0);
assert_eq!(info.snippet(), "new()");
let info = MethodInfo::from_source_str("pub fn reserve(&mut self, additional: uint)").unwrap();
assert_eq!(info.name, "reserve");
assert_eq!(info.args.len(), 2);
assert_eq!(info.args[0], "self");
assert_eq!(info.snippet(), "reserve(${1:additional})");
}