diff options
Diffstat (limited to 'crates/cli')
-rw-r--r-- | crates/cli/Cargo.toml | 11 | ||||
-rw-r--r-- | crates/cli/src/main.rs | 95 |
2 files changed, 106 insertions, 0 deletions
diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml new file mode 100644 index 000000000..ac89a48d3 --- /dev/null +++ b/crates/cli/Cargo.toml | |||
@@ -0,0 +1,11 @@ | |||
1 | [package] | ||
2 | name = "cli" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Aleksey Kladov <[email protected]>"] | ||
5 | publish = false | ||
6 | |||
7 | [dependencies] | ||
8 | clap = "2.32.0" | ||
9 | failure = "0.1.1" | ||
10 | libeditor = { path = "../libeditor" } | ||
11 | tools = { path = "../tools" } | ||
diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs new file mode 100644 index 000000000..45e0a1e4f --- /dev/null +++ b/crates/cli/src/main.rs | |||
@@ -0,0 +1,95 @@ | |||
1 | extern crate clap; | ||
2 | #[macro_use] | ||
3 | extern crate failure; | ||
4 | extern crate libeditor; | ||
5 | extern crate tools; | ||
6 | |||
7 | use std::{ | ||
8 | fs, io::Read, path::Path, | ||
9 | time::Instant | ||
10 | }; | ||
11 | use clap::{App, Arg, SubCommand}; | ||
12 | use tools::collect_tests; | ||
13 | use libeditor::{ast, syntax_tree, symbols}; | ||
14 | |||
15 | type Result<T> = ::std::result::Result<T, failure::Error>; | ||
16 | |||
17 | fn main() -> Result<()> { | ||
18 | let matches = App::new("libsyntax2-cli") | ||
19 | .setting(clap::AppSettings::SubcommandRequiredElseHelp) | ||
20 | .subcommand( | ||
21 | SubCommand::with_name("render-test") | ||
22 | .arg( | ||
23 | Arg::with_name("line") | ||
24 | .long("--line") | ||
25 | .required(true) | ||
26 | .takes_value(true), | ||
27 | ) | ||
28 | .arg( | ||
29 | Arg::with_name("file") | ||
30 | .long("--file") | ||
31 | .required(true) | ||
32 | .takes_value(true), | ||
33 | ), | ||
34 | ) | ||
35 | .subcommand( | ||
36 | SubCommand::with_name("parse") | ||
37 | .arg(Arg::with_name("no-dump").long("--no-dump")) | ||
38 | ) | ||
39 | .subcommand(SubCommand::with_name("symbols")) | ||
40 | .get_matches(); | ||
41 | match matches.subcommand() { | ||
42 | ("parse", Some(matches)) => { | ||
43 | let start = Instant::now(); | ||
44 | let file = file()?; | ||
45 | let elapsed = start.elapsed(); | ||
46 | if !matches.is_present("no-dump") { | ||
47 | println!("{}", syntax_tree(&file)); | ||
48 | } | ||
49 | eprintln!("parsing: {:?}", elapsed); | ||
50 | ::std::mem::forget(file); | ||
51 | } | ||
52 | ("symbols", _) => { | ||
53 | let file = file()?; | ||
54 | for s in symbols(&file) { | ||
55 | println!("{:?}", s); | ||
56 | } | ||
57 | } | ||
58 | ("render-test", Some(matches)) => { | ||
59 | let file = matches.value_of("file").unwrap(); | ||
60 | let file = Path::new(file); | ||
61 | let line: usize = matches.value_of("line").unwrap().parse()?; | ||
62 | let line = line - 1; | ||
63 | let (test, tree) = render_test(file, line)?; | ||
64 | println!("{}\n{}", test, tree); | ||
65 | } | ||
66 | _ => unreachable!(), | ||
67 | } | ||
68 | Ok(()) | ||
69 | } | ||
70 | |||
71 | fn file() -> Result<ast::File> { | ||
72 | let text = read_stdin()?; | ||
73 | Ok(ast::File::parse(&text)) | ||
74 | } | ||
75 | |||
76 | fn read_stdin() -> Result<String> { | ||
77 | let mut buff = String::new(); | ||
78 | ::std::io::stdin().read_to_string(&mut buff)?; | ||
79 | Ok(buff) | ||
80 | } | ||
81 | |||
82 | fn render_test(file: &Path, line: usize) -> Result<(String, String)> { | ||
83 | let text = fs::read_to_string(file)?; | ||
84 | let tests = collect_tests(&text); | ||
85 | let test = tests.into_iter().find(|(start_line, t)| { | ||
86 | *start_line <= line && line <= *start_line + t.text.lines().count() | ||
87 | }); | ||
88 | let test = match test { | ||
89 | None => bail!("No test found at line {} at {}", line, file.display()), | ||
90 | Some((_start_line, test)) => test, | ||
91 | }; | ||
92 | let file = ast::File::parse(&test.text); | ||
93 | let tree = syntax_tree(&file); | ||
94 | Ok((test.text, tree)) | ||
95 | } | ||