diff options
Diffstat (limited to 'lib/pry/prompt.rb')
-rw-r--r-- | lib/pry/prompt.rb | 196 |
1 files changed, 109 insertions, 87 deletions
diff --git a/lib/pry/prompt.rb b/lib/pry/prompt.rb index 072214b0..0479f0d1 100644 --- a/lib/pry/prompt.rb +++ b/lib/pry/prompt.rb @@ -1,9 +1,24 @@ class Pry - # Prompt represents the Pry prompt and holds necessary procs and constants to - # be used with Readline-like libraries. + # Prompt represents the Pry prompt, which can be used with Readline-like + # libraries. It defines a few default prompts (default prompt, simple prompt, + # etc) and also provides an API to add custom prompts. # + # @example + # Pry::Prompt.add( + # :ipython, + # 'IPython-like prompt', [':', '...:'] + # ) do |_context, _nesting, _pry_, sep| + # sep == ':' ? "In [#{_pry_.input_ring.count}]: " : ' ...: ' + # end + # + # # Produces: + # # In [3]: def foo + # # ...: puts 'foo' + # # ...: end + # # => :foo + # # In [4]: # @since v0.11.0 - # @api private + # @api public module Prompt # @return [String] DEFAULT_NAME = 'pry'.freeze @@ -12,60 +27,62 @@ class Pry # 1-line #inspect output suitable for prompt SAFE_CONTEXTS = [String, Numeric, Symbol, nil, true, false].freeze - # @return [String] - DEFAULT_TEMPLATE = - "[%<in_count>s] %<name>s(%<context>s)%<nesting>s%<separator>s ".freeze - - # @return [String] - SHELL_TEMPLATE = "%<name>s %<context>s:%<pwd>s %<separator>s ".freeze - - # @return [String] - NAV_TEMPLATE = "[%<in_count>s] (%<name>s) %<tree>s: %<stack_size>s> ".freeze + # A Hash that holds all prompts. The keys of the Hash are prompt + # names, the values are Hash instances of the format {:description, :value}. + @prompts = {} class << self - private - - # @return [Proc] the default prompt - def default(separator) - proc do |context, nesting, _pry_| - format( - DEFAULT_TEMPLATE, - in_count: _pry_.input_ring.count, - name: prompt_name(_pry_.config.prompt_name), - context: Pry.view_clip(context), - nesting: (nesting > 0 ? ":#{nesting}" : ''), - separator: separator - ) - end + # Retrieves a prompt. + # + # @example + # Prompt[:my_prompt][:value] + # + # @param [Symbol] prompt_name The name of the prompt you want to access + # @return [Hash{Symbol=>Object}] + # @since v0.12.0 + def [](prompt_name) + all[prompt_name.to_s] end - # @return [Proc] the shell prompt - def shell(separator) - proc do |context, _nesting, _pry_| - format( - SHELL_TEMPLATE, - name: prompt_name(_pry_.config.prompt_name), - context: Pry.view_clip(context), - pwd: Dir.pwd, - separator: separator - ) - end + # @return [Hash{Symbol=>Hash}] the duplicate of the internal prompts hash + # @note Use this for read-only operations + # @since v0.12.0 + def all + @prompts.dup end - # @return [Proc] the nav prompt - def nav - proc do |_context, _nesting, _pry_| - tree = _pry_.binding_stack.map { |b| Pry.view_clip(b.eval('self')) } - format( - NAV_TEMPLATE, - in_count: _pry_.input_ring.count, - name: prompt_name(_pry_.config.prompt_name), - tree: tree.join(' / '), - stack_size: _pry_.binding_stack.size - 1 - ) + # Adds a new prompt to the prompt hash. + # + # @param [Symbol] prompt_name + # @param [String] description + # @param [Array<String>] separators The separators to differentiate + # between prompt modes (default mode and class/method definition mode). + # The Array *must* have a size of 2. + # @yield [context, nesting, _pry_, sep] + # @yieldparam context [Object] the context where Pry is currently in + # @yieldparam nesting [Integer] whether the context is nested + # @yieldparam _pry_ [Pry] the Pry instance + # @yieldparam separator [String] separator string + # @return [nil] + # @raise [ArgumentError] if the size of `separators` is not 2 + # @since v0.12.0 + def add(prompt_name, description = '', separators = %w[> *]) + unless separators.size == 2 + raise ArgumentError, "separators size must be 2, given #{separators.size}" end + + @prompts[prompt_name.to_s] = { + description: description, + value: separators.map do |sep| + proc { |context, nesting, _pry_| yield(context, nesting, _pry_, sep) } + end + } + + nil end + private + def prompt_name(name) return name unless name.is_a?(Pry::Config::Lazy) @@ -73,48 +90,53 @@ class Pry end end - # The default Pry prompt, which includes the context and nesting level. - # @return [Array<Proc>] - DEFAULT = [default('>'), default('*')].freeze - - # Simple prompt doesn't display target or nesting level. - # @return [Array<Proc>] - SIMPLE = [proc { '>> ' }, proc { ' | ' }].freeze - - # @return [Array<Proc>] - NO_PROMPT = Array.new(2) { proc { '' } }.freeze - - # @return [Array<Proc>] - SHELL = [shell('$'), shell('*')].freeze - - # A prompt that includes the full object path as well as - # input/output (_in_ and _out_) information. Good for navigation. - NAV = Array.new(2) { nav }.freeze + add(:default, <<DESC) do |context, nesting, _pry_, sep| +The default Pry prompt. Includes information about the +current expression number, evaluation context, and nesting +level, plus a reminder that you're using Pry. +DESC + format( + "[%<in_count>s] %<name>s(%<context>s)%<nesting>s%<separator>s ", + in_count: _pry_.input_ring.count, + name: prompt_name(_pry_.config.prompt_name), + context: Pry.view_clip(context), + nesting: (nesting > 0 ? ":#{nesting}" : ''), + separator: sep + ) + end - # @return [Hash{String=>Hash}] - MAP = { - "default" => { - value: DEFAULT, - description: "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.".freeze - }, + add(:simple, "A simple '>>'.", ['>> ', ' | ']) do |_, _, _, sep| + sep + end - "simple" => { - value: SIMPLE, - description: "A simple '>>'.".freeze - }, + add(:nav, <<DESC, %w[> *]) do |context, nesting, _pry_, sep| +A prompt that displays the binding stack as a path and +includes information about _in_ and _out_. +DESC + tree = _pry_.binding_stack.map { |b| Pry.view_clip(b.eval('self')) } + format( + "[%<in_count>s] (%<name>s) %<tree>s: %<stack_size>s%<separator>s ", + in_count: _pry_.input_ring.count, + name: prompt_name(_pry_.config.prompt_name), + tree: tree.join(' / '), + stack_size: _pry_.binding_stack.size - 1, + separator: sep + ) + end - "nav" => { - value: NAV, - description: "A prompt that displays the binding stack as a path and\n" \ - "includes information about _in_ and _out_.".freeze - }, + add(:shell, <<DESC, %w[$ *]) do |context, nesting, _pry_, sep| +A prompt that displays the binding stack as a path and +includes information about _in_ and _out_. +DESC + format( + "%<name>s %<context>s:%<pwd>s %<separator>s ", + name: prompt_name(_pry_.config.prompt_name), + context: Pry.view_clip(context), + pwd: Dir.pwd, + separator: sep + ) + end - "none" => { - value: NO_PROMPT, - description: "Wave goodbye to the Pry prompt.".freeze - } - }.freeze + add(:none, 'Wave goodbye to the Pry prompt.', Array.new(2)) { '' } end end |