summaryrefslogtreecommitdiff
path: root/lib/pry/prompt.rb
blob: 6696b71d1ed50701d0729510d1c5a7788a94a666 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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.
  # The prompt will be visible in the output of the "list-prompts" command, and
  # it can be used with the "change-prompt"command.
  #
  # @param [String] name
  #   The name of the prompt.
  #
  # @param [String] description
  #   A short description of the prompt.
  #
  # @param [Array<Proc,Proc>] value
  #  A prompt in the form of [proc {}, proc {}].
  #
  def add_prompt(name, description, value)
    PROMPT_MAP[name.to_s] = SortedSet.new [PromptInfo.new(name.to_s, description.to_s, value, nil)]
  end

  #
  # @example
  #
  #   # .pryrc
  #   Pry.configure do |config|
  #     config.prompt = Pry::Prompt['simple'].proc_array
  #   end
  #
  # @return [PromptInfo]
  #   Returns a prompt in the form of a PromptInfo object.
  #
  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

  #
  # Remove a prompt from Pry.
  # 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.
  #
  # @return [Object, nil]
  #   Returns truthy if a prompt was deleted, otherwise nil.
  #
  def remove_prompt(name)
    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

  add_prompt "default",
             "The default Pry prompt. Includes information about the\n" \
             "current expression number, evaluation context, and nesting\n" \
             "level, plus a reminder that you're using Pry.",
             Pry::DEFAULT_PROMPT

  add_prompt "nav",
             "A prompt that displays the binding stack as a path and\n" \
             "includes information about _in_ and _out_.",
             Pry::NAV_PROMPT

  add_prompt "simple", "A simple '>>'.", Pry::SIMPLE_PROMPT
  add_prompt "none", "Wave goodbye to the Pry prompt.", Pry::NO_PROMPT
end