1
1
mod analysis_stats;
2
2
mod analysis_bench;
3
+ mod help;
3
4
4
- use std:: { error:: Error , io:: Read } ;
5
+ use std:: { error:: Error , fmt :: Write , io:: Read } ;
5
6
6
- use clap:: { App , Arg , SubCommand } ;
7
7
use flexi_logger:: Logger ;
8
+ use pico_args:: Arguments ;
8
9
use ra_ide_api:: { file_structure, Analysis } ;
9
10
use ra_prof:: profile;
10
11
use ra_syntax:: { AstNode , SourceFile } ;
@@ -13,77 +14,89 @@ type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;
13
14
14
15
fn main ( ) -> Result < ( ) > {
15
16
Logger :: with_env ( ) . start ( ) ?;
16
- let matches = App :: new ( "ra-cli" )
17
- . setting ( clap:: AppSettings :: SubcommandRequiredElseHelp )
18
- . subcommand ( SubCommand :: with_name ( "parse" ) . arg ( Arg :: with_name ( "no-dump" ) . long ( "--no-dump" ) ) )
19
- . subcommand ( SubCommand :: with_name ( "symbols" ) )
20
- . subcommand (
21
- SubCommand :: with_name ( "highlight" )
22
- . arg ( Arg :: with_name ( "rainbow" ) . short ( "r" ) . long ( "rainbow" ) ) ,
23
- )
24
- . subcommand (
25
- SubCommand :: with_name ( "analysis-stats" )
26
- . arg ( Arg :: with_name ( "verbose" ) . short ( "v" ) . long ( "verbose" ) )
27
- . arg ( Arg :: with_name ( "memory-usage" ) . long ( "memory-usage" ) )
28
- . arg ( Arg :: with_name ( "only" ) . short ( "o" ) . takes_value ( true ) )
29
- . arg ( Arg :: with_name ( "path" ) ) ,
30
- )
31
- . subcommand (
32
- SubCommand :: with_name ( "analysis-bench" )
33
- . arg ( Arg :: with_name ( "verbose" ) . short ( "v" ) . long ( "verbose" ) )
34
- . arg (
35
- Arg :: with_name ( "highlight" )
36
- . long ( "highlight" )
37
- . takes_value ( true )
38
- . conflicts_with ( "complete" )
39
- . value_name ( "PATH" )
40
- . help ( "highlight this file" ) ,
41
- )
42
- . arg (
43
- Arg :: with_name ( "complete" )
44
- . long ( "complete" )
45
- . takes_value ( true )
46
- . conflicts_with ( "highlight" )
47
- . value_name ( "PATH:LINE:COLUMN" )
48
- . help ( "compute completions at this location" ) ,
49
- )
50
- . arg ( Arg :: with_name ( "path" ) . value_name ( "PATH" ) . help ( "project to analyze" ) ) ,
51
- )
52
- . get_matches ( ) ;
53
- match matches. subcommand ( ) {
54
- ( "parse" , Some ( matches) ) => {
17
+
18
+ let subcommand = match std:: env:: args_os ( ) . nth ( 1 ) {
19
+ None => {
20
+ eprintln ! ( "{}" , help:: GLOBAL_HELP ) ;
21
+ return Ok ( ( ) ) ;
22
+ }
23
+ Some ( s) => s,
24
+ } ;
25
+ let mut matches = Arguments :: from_vec ( std:: env:: args_os ( ) . skip ( 2 ) . collect ( ) ) ;
26
+
27
+ match & * subcommand. to_string_lossy ( ) {
28
+ "parse" => {
29
+ if matches. contains ( [ "-h" , "--help" ] ) {
30
+ eprintln ! ( "{}" , help:: PARSE_HELP ) ;
31
+ return Ok ( ( ) ) ;
32
+ }
33
+ let no_dump = matches. contains ( "--no-dump" ) ;
34
+ matches. finish ( ) . or_else ( handle_extra_flags) ?;
35
+
55
36
let _p = profile ( "parsing" ) ;
56
37
let file = file ( ) ?;
57
- if !matches . is_present ( "no-dump" ) {
38
+ if !no_dump {
58
39
println ! ( "{:#?}" , file. syntax( ) ) ;
59
40
}
60
41
std:: mem:: forget ( file) ;
61
42
}
62
- ( "symbols" , _) => {
43
+ "symbols" => {
44
+ if matches. contains ( [ "-h" , "--help" ] ) {
45
+ eprintln ! ( "{}" , help:: SYMBOLS_HELP ) ;
46
+ return Ok ( ( ) ) ;
47
+ }
48
+ matches. finish ( ) . or_else ( handle_extra_flags) ?;
63
49
let file = file ( ) ?;
64
50
for s in file_structure ( & file) {
65
51
println ! ( "{:?}" , s) ;
66
52
}
67
53
}
68
- ( "highlight" , Some ( matches) ) => {
54
+ "highlight" => {
55
+ if matches. contains ( [ "-h" , "--help" ] ) {
56
+ eprintln ! ( "{}" , help:: HIGHLIGHT_HELP ) ;
57
+ return Ok ( ( ) ) ;
58
+ }
59
+ let rainbow_opt = matches. contains ( [ "-r" , "--rainbow" ] ) ;
60
+ matches. finish ( ) . or_else ( handle_extra_flags) ?;
69
61
let ( analysis, file_id) = Analysis :: from_single_file ( read_stdin ( ) ?) ;
70
- let html = analysis. highlight_as_html ( file_id, matches . is_present ( "rainbow" ) ) . unwrap ( ) ;
62
+ let html = analysis. highlight_as_html ( file_id, rainbow_opt ) . unwrap ( ) ;
71
63
println ! ( "{}" , html) ;
72
64
}
73
- ( "analysis-stats" , Some ( matches) ) => {
74
- let verbose = matches. is_present ( "verbose" ) ;
75
- let memory_usage = matches. is_present ( "memory-usage" ) ;
76
- let path = matches. value_of ( "path" ) . unwrap_or ( "" ) ;
77
- let only = matches. value_of ( "only" ) ;
78
- analysis_stats:: run ( verbose, memory_usage, path. as_ref ( ) , only) ?;
65
+ "analysis-stats" => {
66
+ if matches. contains ( [ "-h" , "--help" ] ) {
67
+ eprintln ! ( "{}" , help:: ANALYSIS_STATS_HELP ) ;
68
+ return Ok ( ( ) ) ;
69
+ }
70
+ let verbose = matches. contains ( [ "-v" , "--verbose" ] ) ;
71
+ let memory_usage = matches. contains ( "--memory-usage" ) ;
72
+ let path: String = matches. value_from_str ( "--path" ) ?. unwrap_or_default ( ) ;
73
+ let only = matches. value_from_str ( [ "-o" , "--only" ] ) ?. map ( |v : String | v. to_owned ( ) ) ;
74
+ matches. finish ( ) . or_else ( handle_extra_flags) ?;
75
+ analysis_stats:: run (
76
+ verbose,
77
+ memory_usage,
78
+ path. as_ref ( ) ,
79
+ only. as_ref ( ) . map ( String :: as_ref) ,
80
+ ) ?;
79
81
}
80
- ( "analysis-bench" , Some ( matches) ) => {
81
- let verbose = matches. is_present ( "verbose" ) ;
82
- let path = matches. value_of ( "path" ) . unwrap_or ( "" ) ;
83
- let op = if let Some ( path) = matches. value_of ( "highlight" ) {
82
+ "analysis-bench" => {
83
+ if matches. contains ( [ "-h" , "--help" ] ) {
84
+ eprintln ! ( "{}" , help:: ANALYSIS_BENCH_HELP ) ;
85
+ return Ok ( ( ) ) ;
86
+ }
87
+ let verbose = matches. contains ( [ "-v" , "--verbose" ] ) ;
88
+ let path: String = matches. value_from_str ( "--path" ) ?. unwrap_or_default ( ) ;
89
+ let highlight_path = matches. value_from_str ( "--highlight" ) ?;
90
+ let complete_path = matches. value_from_str ( "--complete" ) ?;
91
+ if highlight_path. is_some ( ) && complete_path. is_some ( ) {
92
+ panic ! ( "either --highlight or --complete must be set, not both" )
93
+ }
94
+ let op = if let Some ( path) = highlight_path {
95
+ let path: String = path;
84
96
analysis_bench:: Op :: Highlight { path : path. into ( ) }
85
- } else if let Some ( path_line_col) = matches. value_of ( "complete" ) {
86
- let ( path_line, column) = rsplit_at_char ( path_line_col, ':' ) ?;
97
+ } else if let Some ( path_line_col) = complete_path {
98
+ let path_line_col: String = path_line_col;
99
+ let ( path_line, column) = rsplit_at_char ( path_line_col. as_str ( ) , ':' ) ?;
87
100
let ( path, line) = rsplit_at_char ( path_line, ':' ) ?;
88
101
analysis_bench:: Op :: Complete {
89
102
path : path. into ( ) ,
@@ -93,13 +106,27 @@ fn main() -> Result<()> {
93
106
} else {
94
107
panic ! ( "either --highlight or --complete must be set" )
95
108
} ;
109
+ matches. finish ( ) . or_else ( handle_extra_flags) ?;
96
110
analysis_bench:: run ( verbose, path. as_ref ( ) , op) ?;
97
111
}
98
- _ => unreachable ! ( ) ,
112
+ _ => eprintln ! ( "{}" , help :: GLOBAL_HELP ) ,
99
113
}
100
114
Ok ( ( ) )
101
115
}
102
116
117
+ fn handle_extra_flags ( e : pico_args:: Error ) -> Result < ( ) > {
118
+ if let pico_args:: Error :: UnusedArgsLeft ( flags) = e {
119
+ let mut invalid_flags = String :: new ( ) ;
120
+ for flag in flags {
121
+ write ! ( & mut invalid_flags, "{}, " , flag) ?;
122
+ }
123
+ let ( invalid_flags, _) = invalid_flags. split_at ( invalid_flags. len ( ) - 2 ) ;
124
+ Err ( format ! ( "Invalid flags: {}" , invalid_flags) . into ( ) )
125
+ } else {
126
+ Err ( e. to_string ( ) . into ( ) )
127
+ }
128
+ }
129
+
103
130
fn file ( ) -> Result < SourceFile > {
104
131
let text = read_stdin ( ) ?;
105
132
Ok ( SourceFile :: parse ( & text) . tree ( ) )
0 commit comments