12
12
-include (" cli_console_command.hrl" ).
13
13
-include_lib (" stdlib/include/ms_transform.hrl" ).
14
14
15
- -export ([start_link /0 , register /4 , run /2 , get_help / 1 , handle_info / 2 ]).
16
- -export ([init /1 , handle_call /3 , handle_cast /2 ]).
15
+ -export ([start_link /0 , register /4 , register /2 , run / 2 , get_help / 1 ]).
16
+ -export ([init /1 , handle_call /3 , handle_cast /2 , handle_info / 2 ]).
17
17
18
18
-define (SERVER , ? MODULE ).
19
19
-define (ETS_TABLE_NAME , cli_commands ).
20
+ -define (PERSISTENT_TERM_KEY , {? MODULE , register_command_callbacks }).
20
21
21
22
-record (state , {
22
23
running_commands = [] :: [{CommandPid :: pid (), From :: {pid (), term ()}}]
28
29
% %% API
29
30
% %%===================================================================
30
31
31
- -spec register ([command ()], [command_argument ()], command_fun (), string ()) -> ok .
32
+ -spec register ([command ()], [command_argument ()], command_fun (), string ()) ->
33
+ ok | {error , {multiple_argument_definitions , Name :: string ()}}.
32
34
register (Command , Arguments , Fun , Description ) ->
33
35
gen_server :call (? SERVER , {register , Command , Arguments , Fun , Description }).
34
36
37
+ -spec register (module (), atom ()) ->
38
+ ok | {error , {multiple_argument_definitions , Name :: string ()}}.
39
+ register (Module , Function ) ->
40
+ gen_server :call (? SERVER , {register , Module , Function }).
41
+
35
42
-spec run ([string ()], proplists :proplist ()) ->
36
43
{ok , term ()} |
37
44
{error , command_not_found } |
@@ -58,7 +65,8 @@ start_link() ->
58
65
-spec init (term ()) -> {ok , state ()}.
59
66
init (_ ) ->
60
67
process_flag (trap_exit , true ),
61
- ets :new (cli_commands , [set , protected , named_table ]),
68
+ ets :new (? ETS_TABLE_NAME , [set , protected , named_table ]),
69
+ init_commands_from_registered_callback (),
62
70
{ok , # state {}}.
63
71
64
72
-spec handle_call (term (), {pid (), Tag :: term ()}, state ()) ->
@@ -81,7 +89,15 @@ handle_call({get_help, Command}, _From, State = #state{}) ->
81
89
{reply , {ok , [cli_console_formatter :title (" Help~n " ) | Output ]}, State };
82
90
handle_call ({register , Command , ArgsDef , Fun , Description }, _From ,
83
91
State = # state {}) ->
84
- {reply , register_command (Command , ArgsDef , Fun , Description ), State }.
92
+ {reply , register_command (Command , ArgsDef , Fun , Description ), State };
93
+ handle_call ({register , Module , Function }, _From , State = # state {}) ->
94
+ case catch register_commands_via_callback ([{Module , Function }]) of
95
+ ok ->
96
+ store_command_register_callback (Module , Function ),
97
+ {reply , ok , State };
98
+ Else ->
99
+ {reply , {error , Else }, State }
100
+ end .
85
101
86
102
-spec handle_cast (term (), state ()) -> {noreply , state ()}.
87
103
handle_cast (_Request , State = # state {}) ->
@@ -123,9 +139,7 @@ run_command(Command, Args, ArgsDef, Fun) ->
123
139
true ->
124
140
get_help (Command );
125
141
_ ->
126
- MissingArguments = get_missing_arguments (ArgsDef , NewArgs ),
127
- evaluate_argument_check (MissingArguments ,
128
- fun () -> execute_fun (Fun , NewArgs ) end )
142
+ evaluate_argument_check (ArgsDef , NewArgs , Fun )
129
143
end ;
130
144
Else ->
131
145
Else
@@ -141,6 +155,10 @@ execute_fun(Fun, NewArgs) ->
141
155
]}
142
156
end .
143
157
158
+ evaluate_argument_check (ArgsDef , NewArgs , Fun ) ->
159
+ MissingArguments = get_missing_arguments (ArgsDef , NewArgs ),
160
+ evaluate_argument_check (MissingArguments , fun () -> execute_fun (Fun , NewArgs ) end ).
161
+
144
162
evaluate_argument_check ([], Fun ) ->
145
163
Fun ();
146
164
evaluate_argument_check (MissingArguments , _Fun ) ->
@@ -281,7 +299,7 @@ format_command({Commands, Desc}) ->
281
299
cli_console_formatter :text (" ~ts ~ts " , [CommandStr , Desc ]).
282
300
283
301
format_command_string (# argument {name = Name }) ->
284
- " <" ++ Name ++ " >" ;
302
+ " <" ++ Name ++ " >" ;
285
303
format_command_string (Command ) ->
286
304
Command .
287
305
@@ -321,8 +339,10 @@ register_command(Command, ArgsDef, Fun, Description) ->
321
339
CommandArguments = get_command_arguments (Command ),
322
340
case check_multiple_argdefs (ArgsDef ++ CommandArguments ) of
323
341
ok ->
324
- ets :match_delete (? ETS_TABLE_NAME , {generate_match_head (Command ),
325
- generate_filter (Command ), []}),
342
+ % need to clean up previous commands to make does not register multiple
343
+ % wildcard argument command
344
+ [ets :delete (? ETS_TABLE_NAME , PrevCommand ) ||
345
+ {PrevCommand , _ , _ , _ } <- get_wildcard_command (Command )],
326
346
true = ets :insert (? ETS_TABLE_NAME , {Command , ArgsDef , Fun , Description }),
327
347
ok ;
328
348
Else ->
@@ -388,17 +408,53 @@ generate_filter([], _ItemCount, Where) ->
388
408
lists :reverse (Where );
389
409
generate_filter ([Command | Rest ], ItemCount , Where ) ->
390
410
Item = item_num (ItemCount ),
391
- Filter = {'orelse' ,
392
- {'==' , Command , Item },
393
- {'==' , argument , {element , 1 , Item }}
394
- },
411
+ Filter = generate_filter (Command , Item ),
395
412
generate_filter (Rest , ItemCount + 1 , [Filter | Where ]).
396
413
414
+ generate_filter (# argument {}, Item ) ->
415
+ {'==' , argument , {element , 1 , Item }};
416
+ generate_filter (Command , Item ) ->
417
+ {'orelse' ,
418
+ {'==' , Command , Item },
419
+ {'==' , argument , {element , 1 , Item }}
420
+ }.
421
+
397
422
item_num (ItemNum ) ->
398
423
list_to_atom (" $" ++ integer_to_list (ItemNum )).
399
424
400
425
extract_command_args (CommandSpec , Command , Args ) ->
401
426
CommandArgWithIndex = get_command_arguments_with_index (CommandSpec ),
402
427
lists :foldl (fun ({Index , # argument {name = Name }}, Acc ) ->
403
428
[{Name , lists :nth (Index , Command )} | Acc ]
404
- end , Args , CommandArgWithIndex ).
429
+ end , Args , CommandArgWithIndex ).
430
+
431
+ store_command_register_callback (Module , Function ) ->
432
+ Callbacks = get_command_register_callbacks (),
433
+ Data = {Module , Function },
434
+ NewCallbacks =
435
+ case lists :member (Data , Callbacks ) of
436
+ true ->
437
+ Callbacks ;
438
+ false ->
439
+ [Data | Callbacks ]
440
+ end ,
441
+ persistent_term :put (? PERSISTENT_TERM_KEY , NewCallbacks ).
442
+
443
+ get_command_register_callbacks () ->
444
+ persistent_term :get (? PERSISTENT_TERM_KEY , []).
445
+
446
+ init_commands_from_registered_callback () ->
447
+ register_commands_via_callback (get_command_register_callbacks ()).
448
+
449
+ register_commands_via_callback ([]) ->
450
+ ok ;
451
+ register_commands_via_callback ([{Module , Function } | Rest ]) ->
452
+ Result = apply (Module , Function , []),
453
+ register_command_callback_result (Result ),
454
+ register_commands_via_callback (Rest ).
455
+
456
+ register_command_callback_result ([]) ->
457
+ ok ;
458
+ register_command_callback_result ([{Command , ArgDef , Fun , Description } | Rest ]) ->
459
+ ok = register_command (Command , ArgDef , Fun , Description ),
460
+ register_command_callback_result (Rest ).
0 commit comments