diff --git a/lib/better_errors/code_formatter.rb b/lib/better_errors/code_formatter.rb index 4c6824d1..fea2643f 100644 --- a/lib/better_errors/code_formatter.rb +++ b/lib/better_errors/code_formatter.rb @@ -12,12 +12,16 @@ class CodeFormatter ".haml" => :haml } - attr_reader :filename, :line, :context + attr_reader :filename, :line, :uperlines, :lowerlines - def initialize(filename, line, context = 5) - @filename = filename - @line = line - @context = context + def initialize(filename, line, uperlines = nil, lowerlines = nil) + @filename = filename + @line = line + @uperlines = uperlines || line - 5 + @lowerlines = lowerlines || line + 5 + + @uperlines = 1 if begin_of_file_reached? + @lowerlines = source_lines.count if end_of_file_reached? end def output @@ -55,9 +59,15 @@ def source_lines end def line_range - min = [line - context, 1].max - max = [line + context, source_lines.count].min - min..max + uperlines..lowerlines + end + + def begin_of_file_reached? + uperlines <= 1 + end + + def end_of_file_reached? + lowerlines >= source_lines.count end end end diff --git a/lib/better_errors/code_formatter/html.rb b/lib/better_errors/code_formatter/html.rb index ec96a214..4a116b59 100644 --- a/lib/better_errors/code_formatter/html.rb +++ b/lib/better_errors/code_formatter/html.rb @@ -19,8 +19,40 @@ def formatted_nums } end + def diff_expander_icon + '' + end + def formatted_code - %{
#{formatted_nums.join}
#{super}
} + code = '' + + if true + code << '' \ + "" \ + "#{diff_expander_icon}" \ + "" \ + '' + end + + code << "
#{formatted_nums.join}
" + code << "
#{super}
" + + if true + code << '' \ + "" \ + "#{diff_expander_icon}" \ + "" \ + '' + end + + code end end end diff --git a/lib/better_errors/error_page.rb b/lib/better_errors/error_page.rb index 40cccb1c..0102199e 100644 --- a/lib/better_errors/error_page.rb +++ b/lib/better_errors/error_page.rb @@ -31,8 +31,7 @@ def render(template_name = "main") end def do_variables(opts) - index = opts["index"].to_i - @frame = backtrace_frames[index] + load_frame_from(opts) @var_start_time = Time.now.to_f { html: render("variable_info") } end @@ -50,6 +49,16 @@ def do_eval(opts) eval_and_respond(index, code) end + def do_diffexpand(opts) + load_frame_from(opts) + + @frame.uperlines -= 5 if opts['direction'] == 'up' + @frame.lowerlines += 5 if opts['direction'] == 'down' + + @var_start_time = Time.now.to_f + { html: render("trace_info") } + end + def backtrace_frames exception.backtrace end @@ -92,7 +101,8 @@ def request_path end def html_formatted_code_block(frame) - CodeFormatter::HTML.new(frame.filename, frame.line).output + CodeFormatter::HTML.new(frame.filename, frame.line, frame.uperlines, + frame.lowerlines).output end def text_formatted_code_block(frame) @@ -138,5 +148,10 @@ def eval_and_respond(index, code) result: result } end + + def load_frame_from(opts) + index = opts["index"].to_i + @frame = backtrace_frames[index] + end end end diff --git a/lib/better_errors/stack_frame.rb b/lib/better_errors/stack_frame.rb index 46518031..56c78d6c 100644 --- a/lib/better_errors/stack_frame.rb +++ b/lib/better_errors/stack_frame.rb @@ -8,12 +8,15 @@ def self.from_exception(exception) end attr_reader :filename, :line, :name, :frame_binding + attr_accessor :uperlines, :lowerlines - def initialize(filename, line, name, frame_binding = nil) + def initialize(filename, line, name, frame_binding = nil, uperlines = nil, lowerlines = nil) @filename = filename @line = line @name = name @frame_binding = frame_binding + @uperlines = uperlines || line - 5 + @lowerlines = lowerlines || line + 5 set_pretty_method_name if frame_binding end diff --git a/lib/better_errors/templates/main.erb b/lib/better_errors/templates/main.erb index 81487982..3e3a8160 100644 --- a/lib/better_errors/templates/main.erb +++ b/lib/better_errors/templates/main.erb @@ -474,11 +474,23 @@ float:left; } + .code_block span.diff-expander { + display: block; + padding: 0 12px; + height: 23px; + } + .code_linenums span{ display:block; padding:0 12px; } + .code_block span.diff-expander a { + position: relative; + top: 3px; + margin-bottom: 2px; + } + .code { margin-bottom: -1px; border-top-left-radius:2px; @@ -929,6 +941,33 @@ if (replInput) replInput.focus(); } + function connectDiffExpanders() { + var allDiffExpanders = document.querySelectorAll(".diff-expander a"); + var selectedFrame = document.querySelector("ul.frames li.selected"); + + for(var i = 0; i < allDiffExpanders.length; i++) { + (function(i, el) { + var el = allDiffExpanders[i]; + el.onclick = function() { + var direction = el.getAttribute("data-direction"); + var index = selectedFrame.getAttribute("data-index"); + apiCall("diffexpand", { "direction": direction, "index": index }, function(response) { + if(response.error) { + el.innerHTML = "

" + escapeHTML(response.error) + "

"; + if(response.explanation) { + el.innerHTML += "

" + escapeHTML(response.explanation) + "

"; + } + el.innerHTML += "

More about Better Errors

"; + } else { + document.querySelector(".code_block").innerHTML = response.html; + connectDiffExpanders(); + } + }); + } + })(i); + } + } + function selectFrameInfo(index) { var el = allFrameInfos[index]; if(el) { @@ -947,6 +986,8 @@ } else { el.innerHTML = response.html; + connectDiffExpanders(); + var repl = el.querySelector(".be-repl .be-console"); if(repl) { new REPL(index).install(repl); diff --git a/lib/better_errors/templates/trace_info.erb b/lib/better_errors/templates/trace_info.erb new file mode 100644 index 00000000..bc16e370 --- /dev/null +++ b/lib/better_errors/templates/trace_info.erb @@ -0,0 +1 @@ +<%== html_formatted_code_block @frame %>