class Byebug::InfoCommand

Implements byebug “info” command.

def execute

def execute
  return print_subcmds(Subcommands) unless @match[1]
  args = @match[1].split(/[ \t]+/)
  param = args.shift
  subcmd = find(Subcommands, param)
  if subcmd
    send("info_#{subcmd.name}", *args)
  else
    errmsg "Unknown info command #{param}\n"
  end
end

def help(args)

def help(args)
  # specific subcommand help
  if args[1]
    subcmd = find(Subcommands, args[1])
    return "Invalid \"info\" subcommand \"#{args[1]}\"." unless subcmd
    str = subcmd.short_help + '.'
    if 'file' == subcmd.name and args[2]
      subsubcmd = find(InfoFileSubcommands, args[2])
      return str += "\nInvalid \"file\" attribute \"#{args[2]}\"." \
        unless subsubcmd
      str += "\n" + subsubcmd.short_help + '.'
    else
      str += "\n" + subcmd.long_help if subcmd.long_help
    end
    return str
  end
  # general help
  s = %{
    Generic command for showing things about the program being debugged.
    --
    List of info subcommands:
    --
  }
  for subcmd in Subcommands do
    s += "info #{subcmd.name} -- #{subcmd.short_help}\n"
  end
  return s
end

def help_command

def help_command
  'info'
end

def info_args(*args)

def info_args(*args)
  unless @state.context
    print "No frame selected.\n"
    return
  end
  locals = @state.context.frame_locals(@state.frame_pos)
  args = @state.context.frame_args(@state.frame_pos)
  args.each do |name|
    s = "#{name} = #{locals[name].inspect}"
    pad_with_dots(s)
    print "#{s}\n"
  end
end

def info_breakpoints(*args)

def info_breakpoints(*args)
  unless @state.context
    print "info breakpoints not available here.\n"
    return
  end
  unless Byebug.breakpoints.empty?
    brkpts = Byebug.breakpoints.sort_by{|b| b.id}
    unless args.empty?
      indices = args.map{|a| a.to_i}
      brkpts = brkpts.select{|b| indices.member?(b.id)}
      if brkpts.empty?
        errmsg "No breakpoints found among list given.\n"
        return
      end
    end
    print "Num Enb What\n"
    brkpts.each do |b|
      if b.expr.nil?
        print "%3d %s   at %s:%s\n",
        b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos
      else
        print "%3d %s   at %s:%s if %s\n",
        b.id, (b.enabled? ? 'y' : 'n'), b.source, b.pos, b.expr
      end
      hits = b.hit_count
      if hits > 0
        s = (hits > 1) ? 's' : ''
        print "\tbreakpoint already hit #{hits} time#{s}\n"
      end
    end
  else
    print "No breakpoints.\n"
  end
end

def info_display(*args)

def info_display(*args)
  unless @state.context
    print "info display not available here.\n"
    return
  end
  if @state.display.find{|d| d[0]}
    print "Auto-display expressions now in effect:\n"
    print "Num Enb Expression\n"
    n = 1
    for d in @state.display
      print "%3d: %s  %s\n", n, (d[0] ? 'y' : 'n'), d[1] if
        d[0] != nil
      n += 1
    end
  else
    print "There are no auto-display expressions now.\n"
  end
end

def info_file(*args)

def info_file(*args)
  return info_files unless args[0]
  file = args[0]
  param =  args[1] ? args[1] : 'basic'
  subcmd = find(InfoFileSubcommands, param)
  return errmsg "Invalid parameter #{param}\n" unless subcmd
  unless LineCache::cached?(file)
    unless LineCache::cached_script?(file)
      return print "File #{file} is not cached\n"
    end
    LineCache::cache(file, Command.settings[:reload_source_on_change])
  end
  print "File #{file}"
  path = LineCache.path(file)
  if %w(all basic path).member?(subcmd.name) and path != file
    print " - #{path}"
  end
  print "\n"
  if %w(all basic lines).member?(subcmd.name)
    lines = LineCache.size(file)
    print "\t %d lines\n", lines if lines
  end
  if %w(all breakpoints).member?(subcmd.name)
    breakpoints = LineCache.trace_line_numbers(file)
    if breakpoints
      print "\tbreakpoint line numbers:\n"
      print columnize(breakpoints.to_a.sort, self.class.settings[:width])
    end
  end
  if %w(all mtime).member?(subcmd.name)
    stat = LineCache.stat(file)
    print "\t%s\n", stat.mtime if stat
  end
  if %w(all sha1).member?(subcmd.name)
    print "\t%s\n", LineCache.sha1(file)
  end
end

def info_files(*args)

def info_files(*args)
  files = LineCache::cached_files
  files += SCRIPT_LINES__.keys unless 'stat' == args[0]
  files.uniq.sort.each do |file|
    stat = LineCache::stat(file)
    path = LineCache::path(file)
    print "File %s", file
    if path and path != file
      print " - %s\n", path
    else
      print "\n"
    end
    print "\t%s\n", stat.mtime if stat
  end
end

def info_global_variables(*args)

def info_global_variables(*args)
  unless @state.context
    errmsg "info global_variables not available here.\n"
    return
  end
  var_global
end

def info_instance_variables(*args)

def info_instance_variables(*args)
  unless @state.context
    print "info instance_variables not available here.\n"
    return
  end
  obj = debug_eval('self')
  var_list(obj.instance_variables)
end

def info_line(*args)

def info_line(*args)
  unless @state.context
    errmsg "info line not available here.\n"
    return
  end
  print "Line %d of \"%s\"\n",  @state.line, @state.file
end

def info_locals(*args)

def info_locals(*args)
  unless @state.context
    errmsg "info line not available here.\n"
    return
  end
  locals = @state.context.frame_locals(@state.frame_pos)
  locals.keys.sort.each do |name|
    ### FIXME: make a common routine
    begin
      s = "#{name} = #{locals[name].inspect}"
    rescue
      begin
      s = "#{name} = #{locals[name].to_s}"
      rescue
        s = "*Error in evaluation*"
      end
    end
    pad_with_dots(s)
    print "#{s}\n"
  end
end

def info_program(*args)

def info_program(*args)
  if not @state.context
    print "The program being debugged is not being run.\n"
    return
  elsif @state.context.dead?
    print "The program crashed.\n"
    if Byebug.last_exception
      print("Exception: #{Byebug.last_exception.inspect}\n")
    end
    return
  end
  print "Program stopped. "
  case @state.context.stop_reason
  when :step
    print "It stopped after stepping, next'ing or initial start.\n"
  when :breakpoint
    print("It stopped at a breakpoint.\n")
  when :catchpoint
    print("It stopped at a catchpoint.\n")
  else
    print "unknown reason: %s\n" % @state.context.stop_reason.to_s
  end
end

def info_stack(*args)

def info_stack(*args)
  if not @state.context
    errmsg "info stack not available here.\n"
    return
  end
  print_backtrace
end

def info_variables(*args)

def info_variables(*args)
  if not @state.context
    errmsg "info variables not available here.\n"
    return
  end
  obj = debug_eval('self')
  locals = @state.context.frame_locals(@state.frame_pos)
  locals[:self] = @state.context.frame_self(@state.frame_pos)
  locals.keys.sort.each do |name|
    next if name =~ /^__dbg_/ # skip byebug pollution
    ### FIXME: make a common routine
    begin
      s = "#{name} = #{locals[name].inspect}"
    rescue
      begin
        s = "#{name} = #{locals[name].to_s}"
      rescue
        s = "#{name} = *Error in evaluation*"
      end
    end
    pad_with_dots(s)
    s.gsub!('%', '%%')  # protect against printf format strings
    print "#{s}\n"
  end
  var_list(obj.instance_variables, obj.instance_eval{binding()})
  var_class_self
end

def regexp

def regexp
  /^\s* i(?:nfo)? (?:\s+(.*))?$/ix
end