class Pry::Command::Edit

def apply_runtime_patch

def apply_runtime_patch
  if patch_exception?
    ExceptionPatcher.new(_pry_, state, file_and_line_for_current_exception).perform_patch
  else
    if code_object.is_a?(Pry::Method)
      MethodPatcher.new(_pry_, code_object).perform_patch
    else
      raise NotImplementedError, "Cannot yet patch #{code_object} objects!"
    end
  end
end

def bad_option_combination?

def bad_option_combination?
  [opts.present?(:ex), opts.present?(:temp),
   opts.present?(:in), opts.present?(:method), !filename_argument.empty?].count(true) > 1
end

def code_object

def code_object
  @code_object ||= !probably_a_file?(filename_argument) &&
    Pry::CodeObject.lookup(filename_argument, _pry_)
end

def complete(search)

def complete(search)
  super + Bond::Rc.files(search.split(" ").last || '')
end

def ensure_file_name_is_valid(file_name)

def ensure_file_name_is_valid(file_name)
  raise CommandError, "Cannot find a valid file for #{filename_argument}" if !file_name
  raise CommandError, "#{file_name} is not a valid file name, cannot edit!" if not_a_real_file?(file_name)
end

def file_and_line

def file_and_line
  file_name, line = if opts.present?(:current)
                      FileAndLineLocator.from_binding(target)
                    elsif opts.present?(:ex)
                      file_and_line_for_current_exception
                    elsif code_object
                      FileAndLineLocator.from_code_object(code_object, filename_argument)
                    else
                      # when file and line are passed as a single arg, e.g my_file.rb:30
                      FileAndLineLocator.from_filename_argument(filename_argument)
                    end
  [file_name, opts.present?(:line) ? opts[:l].to_i : line]
end

def file_and_line_for_current_exception

def file_and_line_for_current_exception
  FileAndLineLocator.from_exception(_pry_.last_exception, opts[:ex].to_i)
end

def file_based_exception?

def file_based_exception?
  opts.present?(:ex) && !opts.present?(:patch)
end

def file_edit

def file_edit
  file_name, line = file_and_line
  ensure_file_name_is_valid(file_name)
  Pry::Editor.invoke_editor(file_name, line, reload?(file_name))
  set_file_and_dir_locals(file_name)
  if reload?(file_name)
    silence_warnings do
      TOPLEVEL_BINDING.eval(File.read(file_name), file_name)
    end
  end
end

def filename_argument

def filename_argument
  args.join(' ')
end

def initial_temp_file_content

def initial_temp_file_content
  case
  when opts.present?(:temp)
    ""
  when opts.present?(:in)
    input_expression
  when eval_string.strip != ""
    eval_string
  else
    _pry_.input_array.reverse_each.find { |x| x && x.strip != "" } || ""
  end
end

def input_expression

def input_expression
  case opts[:i]
  when Range
    (_pry_.input_array[opts[:i]] || []).join
  when Fixnum
    _pry_.input_array[opts[:i]] || ""
  else
    raise Pry::CommandError, "Not a valid range: #{opts[:i]}"
  end
end

def never_reload?

def never_reload?
  opts.present?(:'no-reload') || Pry.config.disable_auto_reload
end

def options(opt)

def options(opt)
  opt.on :e, :ex,      "Open the file that raised the most recent exception (_ex_.file)",
                       :optional_argument => true, :as => Integer
  opt.on :i, :in,      "Open a temporary file containing the Nth input expression. N may be a range",
                       :optional_argument => true, :as => Range, :default => -1..-1
  opt.on :t, :temp,    "Open an empty temporary file"
  opt.on :l, :line,    "Jump to this line in the opened file",
                       :argument => true, :as => Integer
  opt.on :n, :"no-reload", "Don't automatically reload the edited code"
  opt.on :c, :current, "Open the current __FILE__ and at __LINE__ (as returned by `whereami`)"
  opt.on :r, :reload,  "Reload the edited code immediately (default for ruby files)"
  opt.on :p, :patch,   "Instead of editing the object's file, try to edit in a tempfile and apply as a monkey patch"
  opt.on :m, :method,  "Explicitly edit the _current_ method (when inside a method context)."
end

def patch_exception?

def patch_exception?
  opts.present?(:ex) && opts.present?(:patch)
end

def probably_a_file?(str)

def probably_a_file?(str)
  [".rb", ".c", ".py", ".yml", ".gemspec"].include? File.extname(str) ||
    str =~ /\/|\\/
end

def process

def process
  if bad_option_combination?
    raise CommandError, "Only one of --ex, --temp, --in, --method and FILE may be specified."
  end
  if repl_edit?
    # code defined in pry, eval'd within pry.
    repl_edit
  elsif runtime_patch?
    # patch code without persisting changes
    apply_runtime_patch
  else
    # code stored in actual files, eval'd at top-level
    file_edit
  end
end

def pry_method?(code_object)

def pry_method?(code_object)
  code_object.is_a?(Pry::Method) &&
    code_object.pry_method?
end

def reload?(file_name="")

def reload?(file_name="")
  (reloadable? || file_name.end_with?(".rb")) && !never_reload?
end

def reloadable?

def reloadable?
  opts.present?(:reload) || opts.present?(:ex)
end

def repl_edit

def repl_edit
  content = Pry::Editor.edit_tempfile_with_content(initial_temp_file_content,
                                                   initial_temp_file_content.lines.count)
  if repl_reload?
    silence_warnings do
      eval_string.replace content
    end
  end
end

def repl_edit?

def repl_edit?
  !opts.present?(:ex) && !opts.present?(:current) && !opts.present?(:method) &&
    filename_argument.empty?
end

def repl_reload?

conditions much less strict than for reload? (which is for file-based reloads)
def repl_reload?
  !never_reload?
end

def runtime_patch?

def runtime_patch?
   !file_based_exception? && (opts.present?(:patch) || pry_method?(code_object))
end