20
20
//!
21
21
//! ```text
22
22
//! $ grepdef parseQuery ./src
23
- //! // ./src/queries.js:function parseQuery {
23
+ //! ./src/queries.js:function parseQuery {
24
24
//! ```
25
25
//!
26
26
//! Just like `grep`, you can add the `-n` option to include line numbers.
27
27
//!
28
28
//! ```text
29
29
//! $ grepdef -n parseQuery ./src
30
- //! // ./src/queries.js:17:function parseQuery {
30
+ //! ./src/queries.js:17:function parseQuery {
31
31
//! ```
32
32
//!
33
33
//! The search will be faster if you specify what type of file you are searching for using the
34
34
//! `--type` option.
35
35
//!
36
36
//! ```text
37
37
//! $ grepdef --type js -n parseQuery ./src
38
- //! // ./src/queries.js:17:function parseQuery {
38
+ //! ./src/queries.js:17:function parseQuery {
39
39
//! ```
40
40
//!
41
41
//! To use the crate from other Rust code, use [Searcher].
@@ -52,6 +52,7 @@ use clap::Parser;
52
52
use colored:: Colorize ;
53
53
use ignore:: Walk ;
54
54
use regex:: Regex ;
55
+ use serde:: Serialize ;
55
56
use std:: error:: Error ;
56
57
use std:: fs;
57
58
use std:: io:: { self , BufRead , Seek } ;
@@ -119,6 +120,10 @@ pub struct Args {
119
120
/// (Advanced) The number of threads to use
120
121
#[ arg( short = 'j' , long = "threads" ) ]
121
122
pub threads : Option < NonZero < usize > > ,
123
+
124
+ /// The output format; defaults to 'grep'
125
+ #[ arg( long = "format" ) ]
126
+ pub format : Option < SearchResultFormat > ,
122
127
}
123
128
124
129
impl Args {
@@ -192,6 +197,9 @@ struct Config {
192
197
193
198
/// The number of threads to use for searching files
194
199
num_threads : NonZero < usize > ,
200
+
201
+ /// The output format
202
+ format : SearchResultFormat ,
195
203
}
196
204
197
205
impl Config {
@@ -224,6 +232,7 @@ impl Config {
224
232
no_color : args. no_color ,
225
233
search_method : args. search_method . unwrap_or_default ( ) ,
226
234
num_threads,
235
+ format : args. format . unwrap_or_default ( ) ,
227
236
} ;
228
237
debug ( & config, format ! ( "Created config {:?}" , config) . as_str ( ) ) ;
229
238
Ok ( config)
@@ -298,12 +307,21 @@ impl FileType {
298
307
}
299
308
}
300
309
301
- /// A result from calling [Searcher::search]
302
- ///
303
- /// The `line_number` will be set only if [Args::line_number] is true when calling [Searcher::search].
310
+ /// The output format of [SearchResult::to_string]
311
+ #[ derive( clap:: ValueEnum , Clone , Default , Debug , EnumString , PartialEq , Display , Copy ) ]
312
+ pub enum SearchResultFormat {
313
+ /// grep-like output; colon-separated path, line number, and text
314
+ #[ default]
315
+ Grep ,
316
+
317
+ /// JSON output; one document per match
318
+ JsonPerMatch ,
319
+ }
320
+
321
+ /// A result from calling [Searcher::search] or [Searcher::search_and_format]
304
322
///
305
- /// See [SearchResult::to_grep] as the most common formatting output .
306
- #[ derive( Debug , PartialEq , Clone ) ]
323
+ /// Note that `line_number` will be set only if [Args::line_number] is true when searching .
324
+ #[ derive( Debug , PartialEq , Clone , Serialize ) ]
307
325
pub struct SearchResult {
308
326
/// The path to the file containing the symbol definition
309
327
pub file_path : String ,
@@ -339,6 +357,11 @@ impl SearchResult {
339
357
None => format ! ( "{}:{}" , self . file_path. magenta( ) , self . text) ,
340
358
}
341
359
}
360
+
361
+ /// Return a formatted string for output in the "JSON_PER_MATCH" format
362
+ pub fn to_json_per_match ( & self ) -> String {
363
+ serde_json:: to_string ( self ) . unwrap_or_default ( )
364
+ }
342
365
}
343
366
344
367
/// A struct that can perform a search
@@ -356,8 +379,8 @@ impl SearchResult {
356
379
/// true
357
380
/// ))
358
381
/// .unwrap();
359
- /// for result in searcher.search ().unwrap() {
360
- /// println!("{}", result.to_grep() );
382
+ /// for result in searcher.search_and_format ().unwrap() {
383
+ /// println!("{}", result);
361
384
/// }
362
385
/// ```
363
386
pub struct Searcher {
@@ -371,7 +394,19 @@ impl Searcher {
371
394
Ok ( Searcher { config } )
372
395
}
373
396
374
- /// Perform the search this struct was built to do
397
+ /// Perform the search and return formatted strings
398
+ pub fn search_and_format ( & self ) -> Result < Vec < String > , Box < dyn Error > > {
399
+ let results = self . search ( ) ?;
400
+ Ok ( results
401
+ . iter ( )
402
+ . map ( |result| match self . config . format {
403
+ SearchResultFormat :: Grep => result. to_grep ( ) ,
404
+ SearchResultFormat :: JsonPerMatch => result. to_json_per_match ( ) ,
405
+ } )
406
+ . collect ( ) )
407
+ }
408
+
409
+ /// Perform the search and return [SearchResult] structs
375
410
pub fn search ( & self ) -> Result < Vec < SearchResult > , Box < dyn Error > > {
376
411
// Don't try to even calculate elapsed time if we are not going to print it
377
412
let start: Option < time:: Instant > = if self . config . debug {
0 commit comments