diff --git a/lib/ruby-debug-ide/xml_printer.rb b/lib/ruby-debug-ide/xml_printer.rb
index d5fd24b..5e449d1 100644
--- a/lib/ruby-debug-ide/xml_printer.rb
+++ b/lib/ruby-debug-ide/xml_printer.rb
@@ -5,7 +5,13 @@
module Debugger
- class MemoryLimitError < StandardError
+ module OverflowMessageType
+ NIL_MESSAGE = lambda {|e| nil}
+ EXCEPTION_MESSAGE = lambda {|e| e.message}
+ SPECIAL_SYMBOL_MESSAGE = lambda {|e| '>'}
+ end
+
+ class MemoryLimitError < StandardError
attr_reader :message
attr_reader :backtrace
@@ -13,9 +19,9 @@ def initialize(message, backtrace = '')
@message = message
@backtrace = backtrace
end
- end
+ end
- class TimeLimitError < StandardError
+ class TimeLimitError < StandardError
attr_reader :message
attr_reader :backtrace
@@ -23,11 +29,11 @@ def initialize(message, backtrace = '')
@message = message
@backtrace = backtrace
end
- end
+ end
class XmlPrinter # :nodoc:
class ExceptionProxy
- instance_methods.each { |m| undef_method m unless m =~ /(^__|^send$|^object_id$|^instance_variables$|^instance_eval$)/ }
+ instance_methods.each {|m| undef_method m unless m =~ /(^__|^send$|^object_id$|^instance_variables$|^instance_eval$)/}
def initialize(exception)
@exception = exception
@@ -35,9 +41,9 @@ def initialize(exception)
@backtrace = Debugger.cleanup_backtrace(exception.backtrace)
end
- private
- def method_missing(called, *args, &block)
- @exception.__send__(called, *args, &block)
+ private
+ def method_missing(called, *args, &block)
+ @exception.__send__(called, *args, &block)
end
end
@@ -52,15 +58,15 @@ def #{mname}(*args, &block)
end
end
}
- end
+ end
@@monitor = Monitor.new
attr_accessor :interface
-
+
def initialize(interface)
@interface = interface
end
-
+
def print_msg(*args)
msg, *args = args
xml_message = CGI.escapeHTML(msg % args)
@@ -83,7 +89,7 @@ def print_error(*args)
print CGI.escapeHTML(msg % args)
end
end
-
+
def print_frames(context, current_frame_id)
print_element("frames") do
(0...context.stack_size).each do |id|
@@ -91,18 +97,18 @@ def print_frames(context, current_frame_id)
end
end
end
-
+
def print_current_frame(frame_pos)
print_debug "Selected frame no #{frame_pos}"
end
-
+
def print_frame(context, frame_id, current_frame_id)
# idx + 1: one-based numbering as classic-debugger
file = context.frame_file(frame_id)
print "",
- frame_id + 1, CGI.escapeHTML(File.expand_path(file)), context.frame_line(frame_id)
+ frame_id + 1, CGI.escapeHTML(File.expand_path(file)), context.frame_line(frame_id)
end
-
+
def print_contexts(contexts)
print_element("threads") do
contexts.each do |c|
@@ -110,11 +116,11 @@ def print_contexts(contexts)
end
end
end
-
+
def print_context(context)
print "", context.thnum, context.thread.status, Process.pid
end
-
+
def print_variables(vars, kind)
print_element("variables") do
# print self at top position
@@ -124,26 +130,26 @@ def print_variables(vars, kind)
end
end
end
-
+
def print_array(array)
print_element("variables") do
- index = 0
- array.each { |e|
- print_variable('[' + index.to_s + ']', e, 'instance')
- index += 1
+ index = 0
+ array.each {|e|
+ print_variable('[' + index.to_s + ']', e, 'instance')
+ index += 1
}
end
end
-
+
def print_hash(hash)
print_element("variables") do
- hash.keys.each { | k |
+ hash.keys.each {|k|
if k.class.name == "String"
name = '\'' + k + '\''
else
- name = k.to_s
+ name = exec_with_allocation_control(k, ENV['DEBUGGER_MEMORY_LIMIT'].to_i, ENV['INSPECT_TIME_LIMIT'].to_i, :to_s, OverflowMessageType::EXCEPTION_MESSAGE)
end
- print_variable(name, hash[k], 'instance')
+ print_variable(name, hash[k], 'instance')
}
end
end
@@ -155,33 +161,40 @@ def print_string(string)
InspectCommand.reference_result(bytes)
print_variable('bytes', bytes, 'instance')
end
- print_variable('encoding', string.encoding, 'instance') if string.respond_to?('encoding')
+ print_variable('encoding', string.encoding, 'instance') if string.respond_to?('encoding')
end
end
- def exec_with_allocation_control(value, memory_limit, time_limit, exec_method, return_message_if_overflow)
+ def exec_with_allocation_control(value, memory_limit, time_limit, exec_method, overflow_message_type)
+ check_memory_limit = true
+ if (defined?(JRUBY_VERSION) || ENV['DEBUGGER_MEMORY_LIMIT'].to_i <= 0)
+ check_memory_limit = false
+ end
curr_thread = Thread.current
result = nil
inspect_thread = DebugThread.start {
- start_alloc_size = ObjectSpace.memsize_of_all
+
+ start_alloc_size = ObjectSpace.memsize_of_all if (check_memory_limit)
start_time = Time.now.to_f
-
+
trace = TracePoint.new(:c_call, :call) do |tp|
-
- if(rand > 0.75)
- curr_alloc_size = ObjectSpace.memsize_of_all
+
+ if (rand > 0.75)
curr_time = Time.now.to_f
-
- if((curr_time - start_time) * 1e3 > time_limit)
- curr_thread.raise TimeLimitError.new("Timeout: evaluation of #{exec_method} took longer than #{time_limit}ms.", "#{caller.map{|l| "\t#{l}"}.join("\n")}")
+
+ if ((curr_time - start_time) * 1e3 > time_limit)
+ curr_thread.raise TimeLimitError.new("Timeout: evaluation of #{exec_method} took longer than #{time_limit}ms.", "#{caller.map {|l| "\t#{l}"}.join("\n")}")
inspect_thread.kill
end
- start_alloc_size = curr_alloc_size if (curr_alloc_size < start_alloc_size)
-
- if(curr_alloc_size - start_alloc_size > 1e6 * memory_limit)
- curr_thread.raise MemoryLimitError.new("Out of memory: evaluation of #{exec_method} took more than #{memory_limit}mb.", "#{caller.map{|l| "\t#{l}"}.join("\n")}")
- inspect_thread.kill
+ if (check_memory_limit)
+ curr_alloc_size = ObjectSpace.memsize_of_all
+ start_alloc_size = curr_alloc_size if (curr_alloc_size < start_alloc_size)
+
+ if (curr_alloc_size - start_alloc_size > 1e6 * memory_limit)
+ curr_thread.raise MemoryLimitError.new("Out of memory: evaluation of #{exec_method} took more than #{memory_limit}mb.", "#{caller.map {|l| "\t#{l}"}.join("\n")}")
+ inspect_thread.kill
+ end
end
end
end.enable {
@@ -193,8 +206,8 @@ def exec_with_allocation_control(value, memory_limit, time_limit, exec_method, r
return result
rescue MemoryLimitError, TimeLimitError => e
print_debug(e.message + "\n" + e.backtrace)
-
- return return_message_if_overflow ? e.message : nil
+
+ return overflow_message_type.call(e)
end
def print_variable(name, value, kind)
@@ -206,7 +219,7 @@ def print_variable(name, value, kind)
if value.is_a?(Array) || value.is_a?(Hash)
has_children = !value.empty?
if has_children
- size = value.size
+ size = value.size
value_str = "#{value.class} (#{value.size} element#{size > 1 ? "s" : "" })"
else
value_str = "Empty #{value.class}"
@@ -214,33 +227,29 @@ def print_variable(name, value, kind)
elsif value.is_a?(String)
has_children = value.respond_to?('bytes') || value.respond_to?('encoding')
value_str = value
- else
+ else
has_children = !value.instance_variables.empty? || !value.class.class_variables.empty?
-
- value_str = if (defined?(JRUBY_VERSION) || ENV['DEBUGGER_MEMORY_LIMIT'].to_i <= 0)
- value.to_s || 'nil' rescue "<#to_s method raised exception: #{$!}>"
- else
- exec_with_allocation_control(value, ENV['DEBUGGER_MEMORY_LIMIT'].to_i, ENV['INSPECT_TIME_LIMIT'].to_i, :to_s, true) || 'nil' rescue "<#to_s method raised exception: #{$!}>"
- end
-
+
+ value_str = exec_with_allocation_control(value, ENV['DEBUGGER_MEMORY_LIMIT'].to_i, ENV['INSPECT_TIME_LIMIT'].to_i, :to_s, OverflowMessageType::EXCEPTION_MESSAGE) || 'nil' rescue "<#to_s method raised exception: #{$!}>"
+
unless value_str.is_a?(String)
- value_str = "ERROR: #{value.class}.to_s method returns #{value_str.class}. Should return String."
+ value_str = "ERROR: #{value.class}.to_s method returns #{value_str.class}. Should return String."
end
end
if value_str.respond_to?('encode')
# noinspection RubyEmptyRescueBlockInspection
begin
- value_str = value_str.encode("UTF-8")
+ value_str = value_str.encode("UTF-8")
rescue
end
end
value_str = handle_binary_data(value_str)
escaped_value_str = CGI.escapeHTML(value_str)
print("",
- CGI.escapeHTML(name), build_compact_value_attr(value, value_str), kind,
- build_value_attr(escaped_value_str), value.class,
- has_children, value.respond_to?(:object_id) ? value.object_id : value.id)
+ CGI.escapeHTML(name), build_compact_value_attr(value, value_str), kind,
+ build_value_attr(escaped_value_str), value.class,
+ has_children, value.respond_to?(:object_id) ? value.object_id : value.id)
print("", escaped_value_str) if Debugger.value_as_nested_element
print('')
rescue StandardError => e
@@ -263,28 +272,28 @@ def print_file_filter_status(status)
def print_breakpoints(breakpoints)
print_element 'breakpoints' do
- breakpoints.sort_by{|b| b.id }.each do |b|
+ breakpoints.sort_by {|b| b.id}.each do |b|
print "", b.id, CGI.escapeHTML(b.source), b.pos.to_s
end
end
end
-
+
def print_breakpoint_added(b)
print "", b.id, CGI.escapeHTML(b.source), b.pos
end
-
+
def print_breakpoint_deleted(b)
print "", b.id
end
-
+
def print_breakpoint_enabled(b)
print "", b.id
end
-
+
def print_breakpoint_disabled(b)
print "", b.id
end
-
+
def print_contdition_set(bp_id)
print "", bp_id
end
@@ -304,37 +313,37 @@ def print_catchpoint_deleted(exception_class_name)
def print_expressions(exps)
print_element "expressions" do
exps.each_with_index do |(exp, value), idx|
- print_expression(exp, value, idx+1)
+ print_expression(exp, value, idx + 1)
end
end unless exps.empty?
end
-
+
def print_expression(exp, value, idx)
print "", exp, value, idx
end
def print_expression_info(incomplete, prompt, indent)
print "",
- incomplete, CGI.escapeHTML(prompt), indent
+ incomplete, CGI.escapeHTML(prompt), indent
end
-
+
def print_eval(exp, value)
- print "", CGI.escapeHTML(exp), value
+ print "", CGI.escapeHTML(exp), value
end
-
+
def print_pp(value)
print value
end
-
+
def print_list(b, e, file, line)
print "[%d, %d] in %s\n", b, e, file
if (lines = Debugger.source_for(file))
b.upto(e) do |n|
- if n > 0 && lines[n-1]
+ if n > 0 && lines[n - 1]
if n == line
- print "=> %d %s\n", n, lines[n-1].chomp
+ print "=> %d %s\n", n, lines[n - 1].chomp
else
- print " %d %s\n", n, lines[n-1].chomp
+ print " %d %s\n", n, lines[n - 1].chomp
end
end
end
@@ -342,7 +351,7 @@ def print_list(b, e, file, line)
print "No source-file available for %s\n", file
end
end
-
+
def print_methods(methods)
print_element "methods" do
methods.each do |method|
@@ -350,31 +359,31 @@ def print_methods(methods)
end
end
end
-
+
# Events
-
+
def print_breakpoint(_, breakpoint)
print("",
- CGI.escapeHTML(breakpoint.source), breakpoint.pos, Debugger.current_context.thnum)
+ CGI.escapeHTML(breakpoint.source), breakpoint.pos, Debugger.current_context.thnum)
end
-
+
def print_catchpoint(exception)
context = Debugger.current_context
- print("",
- CGI.escapeHTML(context.frame_file(0)), context.frame_line(0), exception.class, CGI.escapeHTML(exception.to_s), context.thnum)
+ print("",
+ CGI.escapeHTML(context.frame_file(0)), context.frame_line(0), exception.class, CGI.escapeHTML(exception.to_s), context.thnum)
end
-
+
def print_trace(context, file, line)
Debugger::print_debug "trace: location=\"%s:%s\", threadId=%d", file, line, context.thnum
# TBD: do we want to clog fronend with the elements? There are tons of them.
# print "", file, line, context.thnum
end
-
+
def print_at_line(context, file, line)
print "",
CGI.escapeHTML(File.expand_path(file)), line, context.thnum, context.stack_size
end
-
+
def print_exception(exception, _)
print_element("variables") do
proxy = ExceptionProxy.new(exception)
@@ -382,21 +391,21 @@ def print_exception(exception, _)
print_variable('error', proxy, 'exception')
end
rescue Exception
- print "",
- exception.class, CGI.escapeHTML(exception.to_s)
+ print "",
+ exception.class, CGI.escapeHTML(exception.to_s)
end
-
+
def print_inspect(eval_result)
- print_element("variables") do
+ print_element("variables") do
print_variable("eval_result", eval_result, 'local')
end
end
-
- def print_load_result(file, exception=nil)
+
+ def print_load_result(file, exception = nil)
if exception
- print("", file, exception.class, CGI.escapeHTML(exception.to_s))
+ print("", file, exception.class, CGI.escapeHTML(exception.to_s))
else
- print("", file)
+ print("", file)
end
end
@@ -410,7 +419,7 @@ def print_element(name)
end
private
-
+
def print(*params)
Debugger::print_debug(*params)
@interface.print(*params)
@@ -446,28 +455,35 @@ def max_compact_name_size
end
def compact_array_str(value)
- slice = value[0..10]
-
- compact = if (defined?(JRUBY_VERSION) || ENV['DEBUGGER_MEMORY_LIMIT'].to_i <= 0)
- slice.inspect
- else
- exec_with_allocation_control(slice, ENV['DEBUGGER_MEMORY_LIMIT'].to_i, ENV['INSPECT_TIME_LIMIT'].to_i, :inspect, true)
- end
-
+ slice = value[0..10]
+
+ compact = exec_with_allocation_control(slice, ENV['DEBUGGER_MEMORY_LIMIT'].to_i, ENV['INSPECT_TIME_LIMIT'].to_i, :inspect, OverflowMessageType::NIL_MESSAGE)
+
if compact && value.size != slice.size
- compact[0..compact.size-2] + ", ...]"
+ compact[0..compact.size - 2] + ", ...]"
end
- compact
+ compact
end
def compact_hash_str(value)
- slice = value.sort_by { |k, _| k.to_s }[0..5]
- compact = slice.map { |kv| "#{kv[0]}: #{handle_binary_data(kv[1])}" }.join(", ")
+ keys_strings = Hash.new
+
+ slice = value.sort_by do |k, _|
+ keys_string = exec_with_allocation_control(k, ENV['DEBUGGER_MEMORY_LIMIT'].to_i, ENV['INSPECT_TIME_LIMIT'].to_i, :to_s, OverflowMessageType::SPECIAL_SYMBOL_MESSAGE)
+ keys_strings[k] = keys_string
+ keys_string
+ end[0..5]
+
+ compact = slice.map do |kv|
+ key_string = keys_strings[kv[0]]
+ value_string = exec_with_allocation_control(kv[1], ENV['DEBUGGER_MEMORY_LIMIT'].to_i, ENV['INSPECT_TIME_LIMIT'].to_i, :to_s, OverflowMessageType::SPECIAL_SYMBOL_MESSAGE)
+ "#{key_string}: #{handle_binary_data(value_string)}"
+ end.join(", ")
"{" + compact + (slice.size != value.size ? ", ..." : "") + "}"
end
def build_compact_value_attr(value, value_str)
- compact_value_str = build_compact_name(value, value_str)
+ compact_value_str = build_compact_name(value, value_str)
compact_value_str.nil? ? '' : "compactValue=\"#{CGI.escapeHTML(compact_value_str)}\""
end
@@ -493,7 +509,7 @@ def build_value_attr(escaped_value_str)
protect m
end
end
-
+
end
end