summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKlas Johansson <klas.johansson@gmail.com>2011-01-24 16:55:18 +0100
committerTuncer Ayaz <tuncer.ayaz@gmail.com>2011-01-24 17:18:33 +0100
commit6978504d43de4d12d791db974e4748e2cb4c2092 (patch)
tree6f494354cd04432a2c98b9b84570ff3ea2d36462 /src
parentd1ff83a8989cd11fbbed794a97c6e13cf6388e21 (diff)
Add support for abbreviated command names
This change makes it possible to type the beginning (the prefix) of a command name and rebar will guess the full name of the command, thereby saving the user precious keystrokes. As long as the prefix matches only one command, rebar runs that command, otherwise rebar prints a list of candidate command names. The "-" character is considered to be a word separator and the prefix matching is done per word. Example prefix matches: co ==> compile cl ==> clean create ==> create create-a ==> create-app c-a ==> create-app c-app ==> create-app
Diffstat (limited to 'src')
-rw-r--r--src/rebar.erl66
-rw-r--r--src/rebar_core.erl21
2 files changed, 75 insertions, 12 deletions
diff --git a/src/rebar.erl b/src/rebar.erl
index 673a4c1..69725b3 100644
--- a/src/rebar.erl
+++ b/src/rebar.erl
@@ -90,7 +90,7 @@ parse_args(Args) ->
%% Filter all the flags (i.e. strings of form key=value) from the
%% command line arguments. What's left will be the commands to run.
- filter_flags(NonOptArgs, []);
+ unabbreviate_command_names(filter_flags(NonOptArgs, []));
{error, {Reason, Data}} ->
?ERROR("Error: ~s ~p~n~n", [Reason, Data]),
@@ -222,3 +222,67 @@ filter_flags([Item | Rest], Commands) ->
?CONSOLE("Ignoring command line argument: ~p\n", [Other]),
filter_flags(Rest, Commands)
end.
+
+command_names() ->
+ ["build-plt", "check-deps", "check-plt", "clean", "compile", "create",
+ "create-app", "create-node", "ct", "delete-deps", "dialyze", "doc",
+ "eunit", "generate", "get-deps", "help", "list-templates", "update-deps",
+ "version", "xref"].
+
+unabbreviate_command_names([]) ->
+ [];
+unabbreviate_command_names([Command | Commands]) ->
+ case get_command_name_candidates(Command) of
+ [] ->
+ %% let the rest of the code detect that the command doesn't exist
+ %% (this would perhaps be a good place to fail)
+ [Command | unabbreviate_command_names(Commands)];
+ [FullCommand] ->
+ [FullCommand | unabbreviate_command_names(Commands)];
+ Candidates ->
+ ?ABORT("Found more than one match for abbreviated command name "
+ " '~s',~nplease be more specific. Possible candidates:~n"
+ " ~s~n",
+ [Command, string:join(Candidates, ", ")])
+ end.
+
+get_command_name_candidates(Command) ->
+ %% Get the command names which match the given (abbreviated) command name.
+ %% * "c" matches commands like compile, clean and create-app
+ %% * "create" matches command create only, since it's unique
+ %% * "create-" matches commands starting with create-
+ %% * "c-a" matches create-app
+ %% * "create-a" matches create-app
+ %% * "c-app" matches create-app
+ Candidates = [Candidate || Candidate <- command_names(),
+ is_command_name_candidate(Command, Candidate)],
+ %% Is there a complete match? If so return only that, return a
+ %% list of candidates otherwise
+ case Candidates of
+ [Command] = Match -> Match;
+ _ -> Candidates
+ end.
+
+is_command_name_candidate(Command, Candidate) ->
+ lists:prefix(Command, Candidate)
+ orelse is_command_name_sub_word_candidate(Command, Candidate).
+
+is_command_name_sub_word_candidate(Command, Candidate) ->
+ %% Allow for parts of commands to be abbreviated, i.e. create-app
+ %% can be shortened to "create-a", "c-a" or "c-app" (but not
+ %% "create-" since that would be ambiguous).
+ CommandSubWords = re:split(Command, "-", [{return, list}]),
+ CandidateSubWords = re:split(Candidate, "-", [{return, list}]),
+ is_command_name_sub_word_candidate_aux(CommandSubWords, CandidateSubWords).
+
+is_command_name_sub_word_candidate_aux([CmdSW | CmdSWs], [CandSW | CandSWs]) ->
+ case lists:prefix(CmdSW, CandSW) of
+ true ->
+ is_command_name_sub_word_candidate_aux(CmdSWs, CandSWs);
+ false ->
+ false
+ end;
+is_command_name_sub_word_candidate_aux([], []) ->
+ true;
+is_command_name_sub_word_candidate_aux(_CmdSWs, _CandSWs) ->
+ false.
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index 86607e2..cb08cdf 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -46,22 +46,21 @@
%% Public API
%% ===================================================================
-run(["help"]) ->
- rebar:help(),
- ok;
-run(["version"]) ->
- %% Load application spec and display vsn and build time info
- ok = application:load(rebar),
- rebar:version(),
- ok;
run(RawArgs) ->
%% Pre-load the rebar app so that we get default configuration
ok = application:load(rebar),
-
%% Parse out command line arguments -- what's left is a list of commands to
- %% run
- Commands = rebar:parse_args(RawArgs),
+ %% run -- and start running commands
+ run_aux(rebar:parse_args(RawArgs)).
+run_aux(["help"]) ->
+ rebar:help(),
+ ok;
+run_aux(["version"]) ->
+ %% Display vsn and build time info
+ rebar:version(),
+ ok;
+run_aux(Commands) ->
%% Make sure crypto is running
ok = crypto:start(),