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:
		
							parent
							
								
									b58da01921
								
							
						
					
					
						commit
						a5857e13d8
					
				|  | @ -18,18 +18,16 @@ defmodule Rabbitmq.CLI.AutoComplete do | ||||||
|   alias RabbitMQ.CLI.Core.Parser, as: Parser |   alias RabbitMQ.CLI.Core.Parser, as: Parser | ||||||
|   alias RabbitMQ.CLI.Core.CommandModules, as: CommandModules |   alias RabbitMQ.CLI.Core.CommandModules, as: CommandModules | ||||||
| 
 | 
 | ||||||
|   @spec complete(String.t) :: [String.t] |   @spec complete(String.t, [String.t]) :: [String.t] | ||||||
|   def complete(script_name, str) do |   def complete(_, []) do | ||||||
|     tokens = String.split(str, " ", trim: true) |     [] | ||||||
|     case List.last(tokens) do |   end | ||||||
|       nil   -> []; |   def complete(script_name, args) do | ||||||
|       _last -> |     case Parser.parse_global(args) do | ||||||
|         case Parser.parse_global(tokens) do |       %{script_name: _args_script_name} -> | ||||||
|           %{script_name: _args_script_name} -> |         complete(args); | ||||||
|             complete(tokens); |       _                                -> | ||||||
|           _                                -> |         complete(["--script-name", script_name | args]) | ||||||
|             complete(["--script-name", script_name | tokens]) |  | ||||||
|         end |  | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -48,6 +46,7 @@ defmodule Rabbitmq.CLI.AutoComplete do | ||||||
|       {command, _} -> |       {command, _} -> | ||||||
|         complete_command_opts(command, last_token) |         complete_command_opts(command, last_token) | ||||||
|     end |     end | ||||||
|  |     |> Enum.sort | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   defp complete_default_opts(opt) do |   defp complete_default_opts(opt) do | ||||||
|  |  | ||||||
|  | @ -27,12 +27,12 @@ defmodule RabbitMQCtl do | ||||||
|   @type options() :: Map.t |   @type options() :: Map.t | ||||||
|   @type command_result() :: {:error, ExitCodes.exit_code, term()} | term() |   @type command_result() :: {:error, ExitCodes.exit_code, term()} | term() | ||||||
| 
 | 
 | ||||||
|   def main(["--auto-complete", str]) do |   def main(["--auto-complete" | []]) do | ||||||
|     case extract_auto_complete_args(str) do |     handle_shutdown(:ok) | ||||||
|       #Script name is not supported |   end | ||||||
|       nil -> :ok; |   def main(["--auto-complete", script_name | args]) do | ||||||
|       {script_name, args_string} -> auto_complete(script_name, args_string) |     script_basename = Path.basename(script_name) | ||||||
|     end |     auto_complete(script_basename, args) | ||||||
|   end |   end | ||||||
|   def main(unparsed_command) do |   def main(unparsed_command) do | ||||||
|     unparsed_command |     unparsed_command | ||||||
|  | @ -91,22 +91,8 @@ defmodule RabbitMQCtl do | ||||||
|     exit_program(ExitCodes.exit_ok) |     exit_program(ExitCodes.exit_ok) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def extract_auto_complete_args(str) do |   def auto_complete(script_name, args) do | ||||||
|     Application.get_env(:rabbitmqctl, :scopes, []) |     Rabbitmq.CLI.AutoComplete.complete(script_name, args) | ||||||
|     |> 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) |  | ||||||
|     |> Stream.map(&IO.puts/1) |> Stream.run |     |> Stream.map(&IO.puts/1) |> Stream.run | ||||||
|     exit_program(ExitCodes.exit_ok) |     exit_program(ExitCodes.exit_ok) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -21,33 +21,41 @@ defmodule AutoCompleteTest do | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|   test "Auto-completes a command" do |   test "Auto-completes a command" do | ||||||
|     ["canis_lupus", "canis_latrans", "canis_aureus"] = @subject.complete("rabbitmqctl", "canis") |     ["canis_aureus", "canis_latrans", "canis_lupus"] = @subject.complete("rabbitmqctl", ["canis"]) | ||||||
|     ["canis_lupus", "canis_latrans", "canis_aureus"] = @subject.complete("rabbitmqctl", "canis_") |     ["canis_aureus", "canis_latrans", "canis_lupus"] = @subject.complete("rabbitmqctl", ["canis_"]) | ||||||
|     ["canis_lupus", "canis_latrans"] = @subject.complete("rabbitmqctl", "canis_l") |     ["canis_latrans", "canis_lupus"] = @subject.complete("rabbitmqctl", ["canis_l"]) | ||||||
|     ["canis_latrans"] = @subject.complete("rabbitmqctl", "canis_la") |     ["canis_latrans"] = @subject.complete("rabbitmqctl", ["canis_la"]) | ||||||
|     ["canis_aureus"] = @subject.complete("rabbitmqctl", "canis_a") |     ["canis_aureus"] = @subject.complete("rabbitmqctl", ["canis_a"]) | ||||||
|     ["canis_aureus"] = @subject.complete("rabbitmqctl", "--node foo --quet canis_a") |     ["canis_aureus"] = @subject.complete("rabbitmqctl", ["--node", "foo", "--quet", "canis_a"]) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   test "Auto-completes default options if command is not specified" do |   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 |     ## Prints script_name as script-name | ||||||
|     ["--script-name"] = @subject.complete("rabbitmqctl", "--script") |     ["--script-name"] = @subject.complete("rabbitmqctl", ["--script"]) | ||||||
|     ["--script-name"] = @subject.complete("rabbitmqctl", "--node foo --script") |     ["--script-name"] = @subject.complete("rabbitmqctl", ["--node", "foo", "--script"]) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   test "Auto-completes the command options if full command is specified" do |   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", "-"]) | ||||||
|     ["--colour", "--dingo", "--dog"] = @subject.complete("rabbitmqctl", "canis_lupus --") |     ["--colour", "--dingo", "--dog"] = @subject.complete("rabbitmqctl", ["canis_lupus", "--"]) | ||||||
|     ["--dingo", "--dog"] = @subject.complete("rabbitmqctl", "canis_lupus --d") |     ["--dingo", "--dog"] = @subject.complete("rabbitmqctl", ["canis_lupus", "--d"]) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   test "Auto-completes scoped command" do |   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 |   end | ||||||
| 
 | 
 | ||||||
|   test "Auto-completes scoped command with --script-name flag" do |   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 | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -165,11 +165,16 @@ defmodule RabbitMQCtlTest do | ||||||
| ## ------------------------- Auto-complete ------------------------------------ | ## ------------------------- Auto-complete ------------------------------------ | ||||||
| 
 | 
 | ||||||
|   test "rabbitmqctl auto-completes commands" do |   test "rabbitmqctl auto-completes commands" do | ||||||
|     check_output(["--auto-complete", "rabbitmqctl list_q"], "list_queues\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", "/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", "/my/custom/path/rabbitmqctl", "list_q"], "list_queues\n") | ||||||
|     check_output(["--auto-complete", "rabbitmq-plugins enab"], "enable\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", "/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 |   end | ||||||
| 
 | 
 | ||||||
|   defp check_output(cmd, out) do |   defp check_output(cmd, out) do | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue