diff options
author | Robert <r-obert@users.noreply.github.com> | 2017-09-01 01:22:17 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-01 01:22:17 +0100 |
commit | 4e5c42f81779bd1bb7b075f8eab8ffb8b2a64b22 (patch) | |
tree | ea7e70d1081e3a799df66cc7b4ef3bab5f27727d | |
parent | 7ea22e76883aacb67cd4191da32dda1b97e27f65 (diff) | |
parent | 3cc7f056df3ceae9fbf705f29d48c2f89591eaad (diff) | |
download | pry-4e5c42f81779bd1bb7b075f8eab8ffb8b2a64b22.tar.gz |
Merge branch 'master' into add-clear-screen-commandadd-clear-screen-command
-rw-r--r-- | CHANGELOG.md | 7 | ||||
-rw-r--r-- | Gemfile | 2 | ||||
-rw-r--r-- | lib/pry/commands/alias_prompt.rb | 33 | ||||
-rw-r--r-- | lib/pry/commands/change_prompt.rb | 21 | ||||
-rw-r--r-- | lib/pry/commands/list_prompts.rb | 26 | ||||
-rw-r--r-- | lib/pry/config/default.rb | 2 | ||||
-rw-r--r-- | lib/pry/prompt.rb | 137 | ||||
-rw-r--r-- | lib/pry/pry_instance.rb | 8 | ||||
-rw-r--r-- | spec/prompt_spec.rb | 68 |
9 files changed, 263 insertions, 41 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 10670063..f44729fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ ### HEAD * Add clear-screen command ([#1630](https://github.com/pry/pry/pull/1630)) -* Add `Pry::Prompt.add_prompt()`, `Pry::Prompt.get_prompt()`, and `Pry::Prompt.remove_prompt()`, for integrating custom prompts with Pry ([#1628](https://github.com/pry/pry/pull/1628)) +* Add 'alias-prompt' command. + +* Add `Pry::Prompt.[]`, `Pry::Prompt.add_prompt()`, `Pry::Prompt.alias_prompt()` and + `Pry::Prompt.remove_prompt()`, plus more, for integrating custom prompts with Pry + ([#1628](https://github.com/pry/pry/pull/1628)). See Pry::Prompt for complete details. + * Add text helpers for background colors ([#1624](https://github.com/pry/pry/pull/1624)) * Fix string literal methods completion. ([#1590](https://github.com/pry/pry/pull/1590)) * Make sure Pry::WrappedModule::Candidate#source_location returns non-nil value when `.name` has @@ -2,11 +2,9 @@ source 'https://rubygems.org' gemspec gem 'rake', '~> 10.0' -# For Guard group :development do gem 'gist' gem 'yard' - gem 'rb-inotify', :require => false gem 'rb-fsevent', :require => false end diff --git a/lib/pry/commands/alias_prompt.rb b/lib/pry/commands/alias_prompt.rb new file mode 100644 index 00000000..a5f7a5ab --- /dev/null +++ b/lib/pry/commands/alias_prompt.rb @@ -0,0 +1,33 @@ +class Pry + class Command::AliasPrompt < Pry::ClassCommand + match "alias-prompt" + group 'Input and Output' + description "Create an alternative alias for a prompt" + banner <<-BANNER + alias-prompt PROMPT_NAME ALIAS_PROMPT + + Create an alternative alias for a prompt that can be seen from list-prompts and + used by the change-prompt commands. + BANNER + + command_options argument_required: true + + def process(prompt_name, alias_name) + if not args_ok?([prompt_name, alias_name]) + return output.puts help + end + if Pry::Prompt[prompt_name] + Pry::Prompt.alias_prompt prompt_name, alias_name + output.puts "Alias '#{alias_name}' created" + else + raise Pry::CommandError, "prompt #{prompt_name} cannot be aliased because it doesn't exist." + end + end + + private + def args_ok?(args) + args.size == 2 and args.all?{|s| String === s} + end + Pry::Commands.add_command(self) + end +end diff --git a/lib/pry/commands/change_prompt.rb b/lib/pry/commands/change_prompt.rb index 4fe32d71..859825a2 100644 --- a/lib/pry/commands/change_prompt.rb +++ b/lib/pry/commands/change_prompt.rb @@ -11,16 +11,29 @@ class Pry::Command::ChangePrompt < Pry::ClassCommand BANNER def process(prompt) - if prompt_map.key?(prompt) - _pry_.prompt = prompt_map[prompt][:value] + prompts = Pry::Prompt.all_by_name(prompt) + if prompts.size == 1 + _pry_.prompt = prompts[0] + elsif prompts.size > 1 + multiple_choice(prompts) else raise Pry::CommandError, "'#{prompt}' isn't a known prompt!" end end private - def prompt_map - Pry::Prompt::PROMPT_MAP + def multiple_choice(prompts) + _pry_.pager.page "Multiple aliases found, please choose:\n" + prompts.each.with_index(1) do |prompt, i| + _pry_.pager.page "#{i}) #{prompt.name} => #{prompt.alias_for}" + end + output.write "Choice: " + reply = (_pry_.input.respond_to?(:gets) ? _pry_.input.gets : _pry_.input.readline).strip + if reply =~ /^[1-9][0-9]*$/ and reply.to_i <= prompts.size + _pry_.prompt = prompts[reply.to_i-1] + else + multiple_choice(prompts) + end end Pry::Commands.add_command(self) end diff --git a/lib/pry/commands/list_prompts.rb b/lib/pry/commands/list_prompts.rb index 9177a629..b8c2b29b 100644 --- a/lib/pry/commands/list_prompts.rb +++ b/lib/pry/commands/list_prompts.rb @@ -10,26 +10,28 @@ class Pry::Command::ListPrompts < Pry::ClassCommand BANNER def process - output.puts heading("Available prompts") + "\n" - prompt_map.each do |name, prompt| - output.write "Name: #{text.bold(name)}" - output.puts selected_prompt?(prompt) ? selected_text : "" - output.puts prompt[:description] + output.puts heading("Available prompts") + "\n\n" + all_prompts.each do |prompt| + next if prompt.alias? + aliases = Pry::Prompt.aliases_for(prompt.name) + output.write "Name: #{text.bold(prompt.name)}" + output.puts selected_prompt?([prompt].concat(aliases)) ? text.green(" [active]") : "" + output.puts "Aliases: #{aliases.map {|s| text.bold(s.name) }.join(',')}" if aliases.any? + output.puts prompt.description output.puts end end private - def prompt_map - Pry::Prompt::PROMPT_MAP - end - def selected_text - text.red " (selected) " + def all_prompts + Pry::Prompt.all_prompts end - def selected_prompt?(prompt) - _pry_.prompt == prompt[:value] + def selected_prompt?(prompts) + prompts.any? do |prompt| + _pry_.prompt == prompt or _pry_.prompt == prompt.proc_array + end end Pry::Commands.add_command(self) end diff --git a/lib/pry/config/default.rb b/lib/pry/config/default.rb index e4ae3fb6..1a653520 100644 --- a/lib/pry/config/default.rb +++ b/lib/pry/config/default.rb @@ -16,7 +16,7 @@ class Pry::Config::Default Pry::DEFAULT_PROMPT_NAME }, prompt: proc { - Pry::DEFAULT_PROMPT + Pry::Prompt['default'] }, prompt_safe_objects: proc { Pry::DEFAULT_PROMPT_SAFE_OBJECTS diff --git a/lib/pry/prompt.rb b/lib/pry/prompt.rb index 2d8bcb36..ea71b346 100644 --- a/lib/pry/prompt.rb +++ b/lib/pry/prompt.rb @@ -1,6 +1,72 @@ +require 'set' module Pry::Prompt extend self PROMPT_MAP = {} + private_constant :PROMPT_MAP + AliasError = Class.new(RuntimeError) + PromptInfo = Struct.new(:name, :description, :proc_array, :alias_for) do + # + # @return [Boolean] + # Returns true if the prompt is an alias of another prompt. + # + def alias? + alias_for != nil + end + + def <=>(other) + name == other.alias_for ? 1 : 0 + end + + def to_a + proc_array + end + + def eql?(other) + return false if not Pry::Prompt::PromptInfo === other + # Aliases are eql? + [:proc_array].all? {|m| public_send(m) == other.public_send(m) } + end + end + + # + # @return [Array<PromptInfo>] + # Returns an Array of {PromptInfo} objects. + # + def all_prompts + PROMPT_MAP.values.map{|s| s.to_a}.flatten + end + + # + # @param [String] prompt + # The name of a prompt. + # + # @return [Array<PromptInfo>] + # Returns an array of aliases for _prompt_, as {PromptInfo} objects. + # + def aliases_for(prompt) + all_prompts.select{|prompt_info| prompt_info.alias_for == prompt.to_s} + end + + # + # @return [Array<PromptInfo>] + # Returns an array of all prompt aliases, as {PromptInfo} objects. + # + def aliased_prompts + all_prompts.select(&:alias?) + end + + # + # @param [Array<Proc,Proc>] proc_array + # An array in the form of [proc{}, proc{}] + # + # @return [PromptInfo] + # Returns the first {PromptInfo} object who holds value eql? to `proc_array`. + # + def first_matching_proc_array(proc_array) + all_prompts.find do |prompt| + prompt.proc_array == proc_array and not prompt.alias? + end + end # # Integrate a custom prompt with Pry. @@ -17,23 +83,34 @@ module Pry::Prompt # A prompt in the form of [proc {}, proc {}]. # def add_prompt(name, description, value) - PROMPT_MAP[name.to_s] = { - value: value, - description: description - } + PROMPT_MAP[name.to_s] = SortedSet.new [PromptInfo.new(name.to_s, description.to_s, value, nil)] end # # @example # # # .pryrc - # Pry.config.prompt = Pry::Prompt.get_prompt('simple') + # Pry.configure do |config| + # config.prompt = Pry::Prompt['simple'].proc_array + # end # - # @return [Array<Proc,Proc>] - # Returns a prompt in the form of [proc{}, proc{}] + # @return [PromptInfo] + # Returns a prompt in the form of a PromptInfo object. # - def get_prompt(name) - PROMPT_MAP.key?(name.to_s) and PROMPT_MAP[name.to_s][:value] + def [](name) + all_prompts.find {|prompt| prompt.name == name.to_s } + end + + # + # @param [String] name + # The name of a prompt. + # + # @return [Array<PromptInfo>] + # An array of {PromptInfo} objects. + # + def all_by_name(name) + name = name.to_s + all_prompts.select{|prompt| prompt.name == name} end # @@ -41,6 +118,9 @@ module Pry::Prompt # It will no longer be visible in the output of "list-prompts" or usable with the # "change-prompt" command. # + # @note + # Aliases are also removed. + # # @param [String] name # The name of a prompt. # @@ -48,7 +128,44 @@ module Pry::Prompt # Returns truthy if a prompt was deleted, otherwise nil. # def remove_prompt(name) - PROMPT_MAP.delete name.to_s if PROMPT_MAP.key?(name.to_s) + prompt = self[name.to_s] + PROMPT_MAP.delete name.to_s if prompt + end + + # + # Provide alternative name for a prompt, which can be used from the list-prompts + # and change-prompt commands. + # + # @param [String] prompt_name + # The name of the prompt to alias. + # + # @param [String] aliased_prompt + # The name of the aliased prompt. + # + def alias_prompt(prompt_name, aliased_prompt) + prompt_name = prompt_name.to_s + prompt = self[prompt_name] + if not prompt + raise AliasError, "prompt '#{prompt}' cannot be aliased because it doesn't exist" + elsif prompt.alias? + prompt_name = prompt.alias_for + end + PROMPT_MAP[prompt_name].add PromptInfo.new *[aliased_prompt.to_s, prompt.description, + prompt.proc_array, prompt_name] + end + + # + # @param [String] alias_name + # Name of a prompt alias. + # + # @return [Integer] + # Returns the number of removed aliases. + # + def remove_alias(alias_name) + alias_name = alias_name.to_s + all_prompts.count do |prompt| + PROMPT_MAP[prompt.alias_for].delete(prompt) if prompt.alias? and prompt.name == alias_name + end end add_prompt "default", diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index 0ee7b790..4ffe4c58 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -88,14 +88,16 @@ class Pry # self.prompt = Pry::SIMPLE_PROMPT # self.prompt # => Pry::SIMPLE_PROMPT # - # @return [Array<Proc>] Current prompt. + # @return [Pry::Prompt::PromptInfo, Array<Proc, Proc>] Current prompt. def prompt - prompt_stack.last + proc_array = prompt_stack.last + Pry::Prompt.first_matching_proc_array(proc_array) or proc_array end def prompt=(new_prompt) + new_prompt = new_prompt.to_a if prompt_stack.empty? - push_prompt new_prompt + push_prompt(new_prompt) else prompt_stack[-1] = new_prompt end diff --git a/spec/prompt_spec.rb b/spec/prompt_spec.rb index 45c21fd6..55692703 100644 --- a/spec/prompt_spec.rb +++ b/spec/prompt_spec.rb @@ -5,8 +5,12 @@ RSpec.describe Pry::Prompt do [proc{},proc{}] end + let(:prompt_desc) do + "$my custom prompt description$" + end + before do - described_class.add_prompt "prompt-name", "prompt description", prompt_value + described_class.add_prompt "prompt-name", prompt_desc, prompt_value end after do @@ -14,20 +18,68 @@ RSpec.describe Pry::Prompt do end describe ".add_prompt" do - specify "it adds a new prompt to Pry" do - new_prompt = described_class::PROMPT_MAP['prompt-name'] - expect(new_prompt).to eq(description: "prompt description", value: prompt_value) + specify "adds new Prompt" do + expect(described_class['prompt-name']).to be_instance_of(Pry::Prompt::PromptInfo) + end + + specify "prompt appears in list-prompts" do expect(pry_eval("list-prompts")).to include("prompt-name") - expect(pry_eval("list-prompts")).to include("prompt description") - expect(pry_eval("change-prompt prompt-name", "_pry_.prompt")).to eq(prompt_value) + expect(pry_eval("list-prompts")).to include(prompt_desc) + end + + specify "prompt is changed to via change-prompt" do + expect(pry_eval("change-prompt prompt-name", "_pry_.prompt")).to eq(described_class['prompt-name']) end end describe ".remove_prompt" do - specify "it removes a prompt from Pry" do + specify "removes a prompt" do + described_class.remove_prompt 'prompt-name' + expect(described_class['prompt-name']).to eq(nil) + end + + specify "prompt disappears from list-prompts" do described_class.remove_prompt 'prompt-name' expect(pry_eval("list-prompts")).to_not include("prompt-name") - expect(pry_eval("list-prompts")).to_not include("prompt description") + end + + specify "does not remove aliases" do + described_class.alias_prompt "prompt-name", "prompt-alias" + described_class.remove_prompt 'prompt-alias' + expect(described_class['prompt-alias']).to_not be_nil + end + end + + describe ".alias_prompt" do + before do + described_class.alias_prompt "prompt-name", "prompt-alias" + end + + specify "creates alias" do + expect(described_class.aliases_for("prompt-name")).to eq([described_class['prompt-alias']]) + end + + specify "alias appears in list-prompts" do + expect(pry_eval("list-prompts")).to include("Aliases: prompt-alias") + end + + specify "alias is changed to via change-prompt" do + expect(pry_eval("change-prompt prompt-alias", "_pry_.prompt")).to eq(described_class['prompt-name']) + end + end + + describe ".remove_alias" do + before do + described_class.alias_prompt "prompt-name", "prompt-alias" + end + + specify "returns number of removed aliases" do + expect(described_class.remove_alias("prompt-alias")).to eq(1) + end + + specify "removes alias from Pry::Prompt" do + expect(described_class.remove_alias("prompt-alias")).to eq(1) + expect(described_class['prompt-alias']).to eq(nil) end end end |