@@ -11,7 +11,7 @@ use foundry_common::{
11
11
selectors:: { SelectorImportData , import_selectors} ,
12
12
} ;
13
13
use foundry_compilers:: { artifacts:: output_selection:: ContractOutputSelection , info:: ContractInfo } ;
14
- use std:: fs:: canonicalize;
14
+ use std:: { collections :: BTreeMap , fs:: canonicalize} ;
15
15
16
16
/// CLI arguments for `forge selectors`.
17
17
#[ derive( Clone , Debug , Parser ) ]
@@ -56,6 +56,9 @@ pub enum SelectorsSubcommands {
56
56
57
57
#[ command( flatten) ]
58
58
project_paths : ProjectPathOpts ,
59
+
60
+ #[ arg( long, help = "Do not group the selectors by contract in separate tables." ) ]
61
+ no_group : bool ,
59
62
} ,
60
63
61
64
/// Find if a selector is present in the project
@@ -225,7 +228,7 @@ impl SelectorsSubcommands {
225
228
sh_println ! ( "\n {table}\n " ) ?;
226
229
}
227
230
}
228
- Self :: List { contract, project_paths } => {
231
+ Self :: List { contract, project_paths, no_group } => {
229
232
sh_println ! ( "Listing selectors for contracts in the project..." ) ?;
230
233
let build_args = BuildOpts {
231
234
project_paths,
@@ -273,41 +276,90 @@ impl SelectorsSubcommands {
273
276
274
277
let mut artifacts = artifacts. into_iter ( ) . peekable ( ) ;
275
278
276
- while let Some ( ( contract, artifact) ) = artifacts. next ( ) {
277
- let abi = artifact. abi . ok_or_else ( || eyre:: eyre!( "Unable to fetch abi" ) ) ?;
278
- if abi. functions . is_empty ( ) && abi. events . is_empty ( ) && abi. errors . is_empty ( ) {
279
- continue ;
279
+ #[ derive( PartialEq , PartialOrd , Eq , Ord ) ]
280
+ enum SelectorType {
281
+ Function ,
282
+ Event ,
283
+ Error ,
284
+ }
285
+ impl std:: fmt:: Display for SelectorType {
286
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
287
+ match self {
288
+ Self :: Function => write ! ( f, "Function" ) ,
289
+ Self :: Event => write ! ( f, "Event" ) ,
290
+ Self :: Error => write ! ( f, "Error" ) ,
291
+ }
280
292
}
293
+ }
281
294
282
- sh_println ! ( "{contract}" ) ?;
295
+ let mut selectors =
296
+ BTreeMap :: < String , BTreeMap < SelectorType , Vec < ( String , String ) > > > :: new ( ) ;
283
297
284
- let mut table = Table :: new ( ) ;
285
- table . apply_modifier ( UTF8_ROUND_CORNERS ) ;
298
+ for ( contract , artifact ) in artifacts . by_ref ( ) {
299
+ let abi = artifact . abi . ok_or_else ( || eyre :: eyre! ( "Unable to fetch abi" ) ) ? ;
286
300
287
- table . set_header ( [ "Type" , "Signature" , "Selector" ] ) ;
301
+ let contract_selectors = selectors . entry ( contract . clone ( ) ) . or_default ( ) ;
288
302
289
303
for func in abi. functions ( ) {
290
304
let sig = func. signature ( ) ;
291
305
let selector = func. selector ( ) ;
292
- table. add_row ( [ "Function" , & sig, & hex:: encode_prefixed ( selector) ] ) ;
306
+ contract_selectors
307
+ . entry ( SelectorType :: Function )
308
+ . or_default ( )
309
+ . push ( ( hex:: encode_prefixed ( selector) , sig) ) ;
293
310
}
294
311
295
312
for event in abi. events ( ) {
296
313
let sig = event. signature ( ) ;
297
314
let selector = event. selector ( ) ;
298
- table. add_row ( [ "Event" , & sig, & hex:: encode_prefixed ( selector) ] ) ;
315
+ contract_selectors
316
+ . entry ( SelectorType :: Event )
317
+ . or_default ( )
318
+ . push ( ( hex:: encode_prefixed ( selector) , sig) ) ;
299
319
}
300
320
301
321
for error in abi. errors ( ) {
302
322
let sig = error. signature ( ) ;
303
323
let selector = error. selector ( ) ;
304
- table. add_row ( [ "Error" , & sig, & hex:: encode_prefixed ( selector) ] ) ;
324
+ contract_selectors
325
+ . entry ( SelectorType :: Error )
326
+ . or_default ( )
327
+ . push ( ( hex:: encode_prefixed ( selector) , sig) ) ;
305
328
}
329
+ }
306
330
307
- sh_println ! ( "\n {table}\n " ) ?;
331
+ if no_group {
332
+ let mut table = Table :: new ( ) ;
333
+ table. apply_modifier ( UTF8_ROUND_CORNERS ) ;
334
+ table. set_header ( [ "Type" , "Signature" , "Selector" , "Contract" ] ) ;
335
+
336
+ for ( contract, contract_selectors) in selectors {
337
+ for ( selector_type, selectors) in contract_selectors {
338
+ for ( selector, sig) in selectors {
339
+ table. add_row ( [
340
+ selector_type. to_string ( ) ,
341
+ sig,
342
+ selector,
343
+ contract. to_string ( ) ,
344
+ ] ) ;
345
+ }
346
+ }
347
+ }
308
348
309
- if artifacts. peek ( ) . is_some ( ) {
310
- sh_println ! ( ) ?
349
+ sh_println ! ( "\n {table}" ) ?;
350
+ } else {
351
+ for ( idx, ( contract, contract_selectors) ) in selectors. into_iter ( ) . enumerate ( ) {
352
+ sh_println ! ( "{}{contract}" , if idx == 0 { "" } else { "\n " } ) ?;
353
+ let mut table = Table :: new ( ) ;
354
+ table. apply_modifier ( UTF8_ROUND_CORNERS ) ;
355
+ table. set_header ( [ "Type" , "Signature" , "Selector" ] ) ;
356
+
357
+ for ( selector_type, selectors) in contract_selectors {
358
+ for ( selector, sig) in selectors {
359
+ table. add_row ( [ selector_type. to_string ( ) , sig, selector] ) ;
360
+ }
361
+ }
362
+ sh_println ! ( "\n {table}" ) ?;
311
363
}
312
364
}
313
365
}
0 commit comments