require 'columnize' require 'linecache' require 'helper' class Debugger RUBY_DEBUG_DIR = File.expand_path(File.dirname(__FILE__)) unless defined?(RUBY_DEBUG_DIR) class Command # :nodoc: attr_accessor :context attr_accessor :state DEF_SETTINGS = { :argv => ARGV.clone, :basename => false, # use basename in showing files? :callstyle => :last, :debuggertesting => false, :force_stepping => false, :full_path => true, :listsize => 10, # number of lines in list command :stack_trace_on_error => false, :trace_plus => false, # different linetrace lines? :width => ENV['COLUMNS'].to_i } unless defined?(DEF_SETTINGS) SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless defined?(SubcmdStruct) include Columnize # Common routine for reporting debugger error messages. # Derived classed may want to override this to capture output. def errmsg(*args) if Debugger.annotate.to_i > 2 aprint 'error-begin' print(*args) aprint '' else print '*** ' print(*args) end end protected :errmsg # Find param in subcmds. param id downcased and can be abbreviated # to the minimum length listed in the subcommands def find(subcmds, param) param.downcase! for try_subcmd in subcmds do if (param.size >= try_subcmd.min) and (try_subcmd.name[0..param.size-1] == param) return try_subcmd end end return nil end class << self def commands @commands ||= [] end DEF_OPTIONS = { :allow_in_control => false, :allow_in_post_mortem => true, :event => true, :always_run => 0, :unknown => false, :need_context => false, } unless defined?(DEF_OPTIONS) def inherited(klass) DEF_OPTIONS.each do |o, v| klass.options[o] = v if klass.options[o].nil? end commands << klass end def load_commands Dir[File.join(Debugger.const_get(:RUBY_DEBUG_DIR), 'commands', '*')].each do |file| require file if file =~ /\.rb$/ end Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod| include mod end end def options @options ||= {} end end def settings(key) @settings[key] end def settings_set(key,value) @settings[key] = value end def initialize(state=nil) @state = state @allow_in_control = false @settings = DEF_SETTINGS end def match(input) @match = regexp.match(input) end def get_binding(pos=0) @state.context.frame_binding(pos) end protected def confirm(msg) 'y' == Readline::readline(msg, false) ## @state.confirm(msg) == 'y' end # def debug_eval(str, b = get_binding) # begin # val = eval(str, b) # rescue StandardError, ScriptError => e # if Command.settings[:stack_trace_on_error] # at = eval("caller(1)", b) # print "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '') # for i in at # print "\tfrom %s\n", i # end # else # print "#{e.class} Exception: #{e.message}\n" # end # throw :debug_error # end # end # def debug_silent_eval(str) # begin # eval(str, get_binding) # rescue StandardError, ScriptError # nil # end # end # def get_binding # @state.context.frame_binding(@state.frame_pos) # end # def line_at(file, line) # Debugger.line_at(file, line) # end # def get_context(thnum) # Debugger.contexts.find{|c| c.thnum == thnum} # end end Command.load_commands # Returns setting object. # Use Debugger.settings[] and Debugger.settings[]= methods to query and set # debugger settings. These settings are available: # # - :autolist - automatically calls 'list' command on breakpoint # - :autoeval - evaluates input in the current binding if it's not recognized as a debugger command # - :autoirb - automatically calls 'irb' command on breakpoint # - :stack_trace_on_error - shows full stack trace if eval command results with an exception # - :frame_full_path - displays full paths when showing frame stack # - :frame_class_names - displays method's class name when showing frame stack # - :reload_source_on_change - makes 'list' command to always display up-to-date source code # - :force_stepping - stepping command asways move to the new line # end