Handle auto-completion line as argv, not a single argument

It's easier to detect a script name if passed as argv list.
Arguments can be parsed with quoted spaces (e.g. in directory path)
This commit is contained in:
Daniil Fedotov 2017-01-24 14:40:31 +00:00
parent b58da01921
commit a5857e13d8
4 changed files with 51 additions and 53 deletions

View File

@ -18,18 +18,16 @@ defmodule Rabbitmq.CLI.AutoComplete do
alias RabbitMQ.CLI.Core.Parser, as: Parser
alias RabbitMQ.CLI.Core.CommandModules, as: CommandModules
@spec complete(String.t) :: [String.t]
def complete(script_name, str) do
tokens = String.split(str, " ", trim: true)
case List.last(tokens) do
nil -> [];
_last ->
case Parser.parse_global(tokens) do
%{script_name: _args_script_name} ->
complete(tokens);
_ ->
complete(["--script-name", script_name | tokens])
end
@spec complete(String.t, [String.t]) :: [String.t]
def complete(_, []) do
[]
end
def complete(script_name, args) do
case Parser.parse_global(args) do
%{script_name: _args_script_name} ->
complete(args);
_ ->
complete(["--script-name", script_name | args])
end
end
@ -48,6 +46,7 @@ defmodule Rabbitmq.CLI.AutoComplete do
{command, _} ->
complete_command_opts(command, last_token)
end
|> Enum.sort
end
defp complete_default_opts(opt) do

View File

@ -27,12 +27,12 @@ defmodule RabbitMQCtl do
@type options() :: Map.t
@type command_result() :: {:error, ExitCodes.exit_code, term()} | term()
def main(["--auto-complete", str]) do
case extract_auto_complete_args(str) do
#Script name is not supported
nil -> :ok;
{script_name, args_string} -> auto_complete(script_name, args_string)
end
def main(["--auto-complete" | []]) do
handle_shutdown(:ok)
end
def main(["--auto-complete", script_name | args]) do
script_basename = Path.basename(script_name)
auto_complete(script_basename, args)
end
def main(unparsed_command) do
unparsed_command
@ -91,22 +91,8 @@ defmodule RabbitMQCtl do
exit_program(ExitCodes.exit_ok)
end
def extract_auto_complete_args(str) do
Application.get_env(:rabbitmqctl, :scopes, [])
|> Enum.reduce(nil,
fn({key, _}, nil) ->
script_name = to_string(key)
case String.split(str, script_name <> " ", parts: 2) do
[_path, args] -> {script_name, args}
[_] -> nil
end;
# Skip remaining script names
(_, val) -> val
end)
end
def auto_complete(script_name, str) do
Rabbitmq.CLI.AutoComplete.complete(script_name, str)
def auto_complete(script_name, args) do
Rabbitmq.CLI.AutoComplete.complete(script_name, args)
|> Stream.map(&IO.puts/1) |> Stream.run
exit_program(ExitCodes.exit_ok)
end

View File

@ -21,33 +21,41 @@ defmodule AutoCompleteTest do
test "Auto-completes a command" do
["canis_lupus", "canis_latrans", "canis_aureus"] = @subject.complete("rabbitmqctl", "canis")
["canis_lupus", "canis_latrans", "canis_aureus"] = @subject.complete("rabbitmqctl", "canis_")
["canis_lupus", "canis_latrans"] = @subject.complete("rabbitmqctl", "canis_l")
["canis_latrans"] = @subject.complete("rabbitmqctl", "canis_la")
["canis_aureus"] = @subject.complete("rabbitmqctl", "canis_a")
["canis_aureus"] = @subject.complete("rabbitmqctl", "--node foo --quet canis_a")
["canis_aureus", "canis_latrans", "canis_lupus"] = @subject.complete("rabbitmqctl", ["canis"])
["canis_aureus", "canis_latrans", "canis_lupus"] = @subject.complete("rabbitmqctl", ["canis_"])
["canis_latrans", "canis_lupus"] = @subject.complete("rabbitmqctl", ["canis_l"])
["canis_latrans"] = @subject.complete("rabbitmqctl", ["canis_la"])
["canis_aureus"] = @subject.complete("rabbitmqctl", ["canis_a"])
["canis_aureus"] = @subject.complete("rabbitmqctl", ["--node", "foo", "--quet", "canis_a"])
end
test "Auto-completes default options if command is not specified" do
["--vhost"] = @subject.complete("rabbitmqctl", "--vh")
["--vhost"] = @subject.complete("rabbitmqctl", ["--vh"])
## Prints script_name as script-name
["--script-name"] = @subject.complete("rabbitmqctl", "--script")
["--script-name"] = @subject.complete("rabbitmqctl", "--node foo --script")
["--script-name"] = @subject.complete("rabbitmqctl", ["--script"])
["--script-name"] = @subject.complete("rabbitmqctl", ["--node", "foo", "--script"])
end
test "Auto-completes the command options if full command is specified" do
["--colour", "--dingo", "--dog"] = @subject.complete("rabbitmqctl", "canis_lupus -")
["--colour", "--dingo", "--dog"] = @subject.complete("rabbitmqctl", "canis_lupus --")
["--dingo", "--dog"] = @subject.complete("rabbitmqctl", "canis_lupus --d")
["--colour", "--dingo", "--dog"] = @subject.complete("rabbitmqctl", ["canis_lupus", "-"])
["--colour", "--dingo", "--dog"] = @subject.complete("rabbitmqctl", ["canis_lupus", "--"])
["--dingo", "--dog"] = @subject.complete("rabbitmqctl", ["canis_lupus", "--d"])
end
test "Auto-completes scoped command" do
["enable"] = @subject.complete("rabbitmq-plugins", "enab")
["enable"] = @subject.complete("rabbitmq-plugins", ["enab"])
scopes = Application.get_env(:rabbitmqctl, :scopes)
scopes_with_wolf = Keyword.put(scopes, :rabbitmq_wolf, :wolf)
Application.put_env(:rabbitmqctl, :scopes, scopes_with_wolf)
on_exit(fn() ->
Application.put_env(:rabbitmqctl, :scopes, scopes)
end)
["canis_aureus", "canis_latrans", "canis_lupus"] = @subject.complete("rabbitmq_wolf", ["canis"])
end
test "Auto-completes scoped command with --script-name flag" do
["enable"] = @subject.complete("rabbitmqctl", "--script-name rabbitmq-plugins enab")
["enable"] = @subject.complete("rabbitmqctl", ["--script-name", "rabbitmq-plugins", "enab"])
end
end

View File

@ -165,11 +165,16 @@ defmodule RabbitMQCtlTest do
## ------------------------- Auto-complete ------------------------------------
test "rabbitmqctl auto-completes commands" do
check_output(["--auto-complete", "rabbitmqctl list_q"], "list_queues\n")
check_output(["--auto-complete", "/usr/bin/rabbitmqctl list_q"], "list_queues\n")
check_output(["--auto-complete", "/my/custom/path/rabbitmqctl list_q"], "list_queues\n")
check_output(["--auto-complete", "rabbitmq-plugins enab"], "enable\n")
check_output(["--auto-complete", "/path/to/rabbitmq-plugins enab"], "enable\n")
check_output(["--auto-complete", "rabbitmqctl", "list_q"], "list_queues\n")
check_output(["--auto-complete", "/usr/bin/rabbitmqctl", "list_q"], "list_queues\n")
check_output(["--auto-complete", "/my/custom/path/rabbitmqctl", "list_q"], "list_queues\n")
check_output(["--auto-complete", "rabbitmq-plugins", "enab"], "enable\n")
check_output(["--auto-complete", "/path/to/rabbitmq-plugins", "enab"], "enable\n")
end
test "invalid script name does not autocomplete" do
check_output(["--auto-complete", "rabbitmqinvalid list"], "")
check_output(["--auto-complete", "rabbitmqinvalid --script-name rabbitmqctl list"], "")
end
defp check_output(cmd, out) do