summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert <r-obert@users.noreply.github.com>2017-09-01 01:22:17 +0100
committerGitHub <noreply@github.com>2017-09-01 01:22:17 +0100
commit4e5c42f81779bd1bb7b075f8eab8ffb8b2a64b22 (patch)
treeea7e70d1081e3a799df66cc7b4ef3bab5f27727d
parent7ea22e76883aacb67cd4191da32dda1b97e27f65 (diff)
parent3cc7f056df3ceae9fbf705f29d48c2f89591eaad (diff)
downloadpry-4e5c42f81779bd1bb7b075f8eab8ffb8b2a64b22.tar.gz
Merge branch 'master' into add-clear-screen-commandadd-clear-screen-command
-rw-r--r--CHANGELOG.md7
-rw-r--r--Gemfile2
-rw-r--r--lib/pry/commands/alias_prompt.rb33
-rw-r--r--lib/pry/commands/change_prompt.rb21
-rw-r--r--lib/pry/commands/list_prompts.rb26
-rw-r--r--lib/pry/config/default.rb2
-rw-r--r--lib/pry/prompt.rb137
-rw-r--r--lib/pry/pry_instance.rb8
-rw-r--r--spec/prompt_spec.rb68
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
diff --git a/Gemfile b/Gemfile
index 43c0d13f..7c199855 100644
--- a/Gemfile
+++ b/Gemfile
@@ -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