ruby_jard 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. data/.github/workflows/ruby.yml +85 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +70 -1
  7. data/CHANGELOG.md +31 -0
  8. data/Gemfile +6 -3
  9. data/README.md +122 -8
  10. data/bin/console +1 -2
  11. data/docs/color_schemes/256-light.png +0 -0
  12. data/docs/color_schemes/gruvbox.png +0 -0
  13. data/docs/color_schemes/one-half-dark.png +0 -0
  14. data/docs/color_schemes/one-half-light.png +0 -0
  15. data/lib/ruby_jard.rb +5 -5
  16. data/lib/ruby_jard/box_drawer.rb +4 -1
  17. data/lib/ruby_jard/color_schemes.rb +31 -15
  18. data/lib/ruby_jard/color_schemes/256_color_scheme.rb +37 -37
  19. data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +62 -0
  20. data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +36 -36
  21. data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +62 -0
  22. data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +61 -0
  23. data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +62 -0
  24. data/lib/ruby_jard/column.rb +3 -1
  25. data/lib/ruby_jard/commands/continue_command.rb +2 -3
  26. data/lib/ruby_jard/commands/down_command.rb +9 -5
  27. data/lib/ruby_jard/commands/exit_command.rb +27 -0
  28. data/lib/ruby_jard/commands/frame_command.rb +11 -10
  29. data/lib/ruby_jard/commands/jard/color_scheme_command.rb +52 -0
  30. data/lib/ruby_jard/commands/jard/hide_command.rb +40 -0
  31. data/lib/ruby_jard/commands/jard/output_command.rb +28 -0
  32. data/lib/ruby_jard/commands/jard/show_command.rb +41 -0
  33. data/lib/ruby_jard/commands/jard_command.rb +50 -0
  34. data/lib/ruby_jard/commands/list_command.rb +5 -4
  35. data/lib/ruby_jard/commands/next_command.rb +10 -5
  36. data/lib/ruby_jard/commands/step_command.rb +10 -5
  37. data/lib/ruby_jard/commands/step_out_command.rb +10 -5
  38. data/lib/ruby_jard/commands/up_command.rb +10 -5
  39. data/lib/ruby_jard/commands/validation_helpers.rb +50 -0
  40. data/lib/ruby_jard/config.rb +7 -3
  41. data/lib/ruby_jard/console.rb +10 -22
  42. data/lib/ruby_jard/control_flow.rb +3 -3
  43. data/lib/ruby_jard/decorators/color_decorator.rb +11 -5
  44. data/lib/ruby_jard/decorators/loc_decorator.rb +1 -1
  45. data/lib/ruby_jard/decorators/path_decorator.rb +20 -7
  46. data/lib/ruby_jard/decorators/source_decorator.rb +2 -0
  47. data/lib/ruby_jard/frame.rb +55 -0
  48. data/lib/ruby_jard/keys.rb +0 -3
  49. data/lib/ruby_jard/layout.rb +9 -2
  50. data/lib/ruby_jard/layout_calculator.rb +29 -12
  51. data/lib/ruby_jard/layout_picker.rb +34 -0
  52. data/lib/ruby_jard/layouts.rb +52 -0
  53. data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +28 -0
  54. data/lib/ruby_jard/layouts/narrow_vertical_layout.rb +32 -0
  55. data/lib/ruby_jard/layouts/tiny_layout.rb +25 -0
  56. data/lib/ruby_jard/layouts/wide_layout.rb +13 -15
  57. data/lib/ruby_jard/pager.rb +96 -0
  58. data/lib/ruby_jard/repl_processor.rb +61 -31
  59. data/lib/ruby_jard/repl_proxy.rb +193 -89
  60. data/lib/ruby_jard/row.rb +16 -1
  61. data/lib/ruby_jard/row_renderer.rb +51 -42
  62. data/lib/ruby_jard/screen.rb +2 -12
  63. data/lib/ruby_jard/screen_adjuster.rb +104 -0
  64. data/lib/ruby_jard/screen_drawer.rb +3 -0
  65. data/lib/ruby_jard/screen_manager.rb +32 -54
  66. data/lib/ruby_jard/screen_renderer.rb +30 -16
  67. data/lib/ruby_jard/screens.rb +31 -12
  68. data/lib/ruby_jard/screens/backtrace_screen.rb +23 -26
  69. data/lib/ruby_jard/screens/menu_screen.rb +53 -22
  70. data/lib/ruby_jard/screens/source_screen.rb +65 -37
  71. data/lib/ruby_jard/screens/threads_screen.rb +14 -14
  72. data/lib/ruby_jard/screens/variables_screen.rb +59 -34
  73. data/lib/ruby_jard/session.rb +19 -10
  74. data/lib/ruby_jard/span.rb +3 -0
  75. data/lib/ruby_jard/templates/layout_template.rb +1 -1
  76. data/lib/ruby_jard/templates/screen_template.rb +3 -4
  77. data/lib/ruby_jard/version.rb +1 -1
  78. data/ruby_jard.gemspec +1 -1
  79. metadata +38 -9
  80. data/lib/ruby_jard/commands/color_scheme_command.rb +0 -42
  81. data/lib/ruby_jard/layouts/narrow_layout.rb +0 -41
  82. data/lib/ruby_jard/screens/empty_screen.rb +0 -13
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # rubocop:disable Metrics/MethodLength
4
- # rubocop:disable Metrics/CyclomaticComplexity
5
4
  module RubyJard
6
5
  ##
7
6
  # Layout calculator based on screen resolution to decide the height, width,
@@ -12,27 +11,31 @@ module RubyJard
12
11
  new(**args).calculate
13
12
  end
14
13
 
15
- def initialize(layout_template:, width: 0, height: 0, x: 0, y: 0)
14
+ def initialize(
15
+ layout_template:, width: 0, height: 0, x: 0, y: 0,
16
+ config: RubyJard.config
17
+ )
16
18
  @layout_template = layout_template
17
19
  @width = width
18
20
  @height = height
19
21
  @x = x
20
22
  @y = y
21
23
  @layouts = []
24
+ @config = config
22
25
  end
23
26
 
24
27
  def calculate
25
28
  @layouts = []
26
- calculate_layout(@layout_template, @width, @height, @x, @y)
29
+ calculate_layout(@layout_template, @width, @height, @x, @y, nil)
27
30
  @layouts
28
31
  end
29
32
 
30
33
  private
31
34
 
32
- def calculate_layout(template, width, height, x, y)
35
+ def calculate_layout(template, width, height, x, y, parent_template)
33
36
  if template.is_a?(RubyJard::Templates::ScreenTemplate)
34
37
  layout = RubyJard::Layout.new(
35
- template: template,
38
+ template: template, parent_template: parent_template,
36
39
  width: width - 2, height: height - 2, x: x + 1, y: y + 1,
37
40
  box_width: width, box_height: height, box_x: x, box_y: y
38
41
  )
@@ -45,7 +48,7 @@ module RubyJard
45
48
  max_height = 0
46
49
 
47
50
  lines = [[]]
48
- template.children.each do |child_template|
51
+ visible_children(template).each do |child_template|
49
52
  child_height = calculate_child_height(child_template, height)
50
53
  child_width = calculate_child_width(child_template, width)
51
54
 
@@ -57,23 +60,37 @@ module RubyJard
57
60
  overflow_width = 0
58
61
  max_height = child_height
59
62
  lines << []
60
- else
61
- max_height = child_height if max_height < child_height
63
+ elsif max_height < child_height
64
+ max_height = child_height
62
65
  end
63
66
 
64
67
  lines.last << [child_template, child_width, child_height, child_x, child_y]
65
68
  child_x += child_width
66
69
  end
67
70
 
68
- stretch_lines(template, width, height, lines)
71
+ stretch_children_layouts(template, width, height, lines)
69
72
  lines.each do |line|
70
73
  line.each do |child_template, child_width, child_height, xx, yy|
71
- calculate_layout(child_template, child_width, child_height, xx, yy)
74
+ calculate_layout(child_template, child_width, child_height, xx, yy, template)
72
75
  end
73
76
  end
74
77
  end
75
78
  end
76
79
 
80
+ def visible_children(template)
81
+ template.children.select do |child|
82
+ visible?(child)
83
+ end
84
+ end
85
+
86
+ def visible?(template)
87
+ if template.is_a?(RubyJard::Templates::ScreenTemplate)
88
+ @config.enabled_screens.include?(template.screen.to_s.strip)
89
+ else
90
+ template.children.any? { |child| visible?(child) }
91
+ end
92
+ end
93
+
77
94
  def adjust_layout_overlap(layout)
78
95
  if layout.box_x != 0
79
96
  layout.width += 1
@@ -90,7 +107,8 @@ module RubyJard
90
107
  end
91
108
  end
92
109
 
93
- def stretch_lines(parent_template, parent_width, parent_height, lines)
110
+ # Stretch the children layouts to fill the gaps, remove redundant spaces inside the parent layout
111
+ def stretch_children_layouts(parent_template, parent_width, parent_height, lines)
94
112
  total_height = 0
95
113
  lines.each_with_index do |line, line_index|
96
114
  desired_height =
@@ -148,4 +166,3 @@ module RubyJard
148
166
  end
149
167
 
150
168
  # rubocop:enable Metrics/MethodLength
151
- # rubocop:enable Metrics/CyclomaticComplexity
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ ##
5
+ # Pick layout smartly depending on current window height and width
6
+ class LayoutPicker
7
+ def initialize(width, height, layouts: RubyJard::Layouts, config: RubyJard.config)
8
+ @width = width
9
+ @height = height
10
+ @layouts = layouts
11
+ @config = config
12
+ end
13
+
14
+ def pick
15
+ unless @config.layout.nil?
16
+ return @layouts[@config.layout] || @layouts.fallback_layout
17
+ end
18
+
19
+ @layouts.each do |_name, template|
20
+ matched = true
21
+ matched &&= (
22
+ template.min_width.nil? ||
23
+ @width > template.min_width
24
+ )
25
+ matched &&= (
26
+ template.min_height.nil? ||
27
+ @height > template.min_height
28
+ )
29
+ return template if matched
30
+ end
31
+ @layouts.fallback_layout
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby_jard/layout'
4
+ require 'ruby_jard/templates/layout_template'
5
+ require 'ruby_jard/templates/screen_template'
6
+ require 'ruby_jard/layout_picker'
7
+ require 'ruby_jard/layout_calculator'
8
+
9
+ module RubyJard
10
+ ##
11
+ # Layouts registry.
12
+ class Layouts
13
+ class << self
14
+ extend Forwardable
15
+ def_delegators :instance, :fallback_layout, :add_layout, :[], :get, :each
16
+
17
+ def instance
18
+ @instance ||= new
19
+ end
20
+ end
21
+
22
+ attr_reader :fallback_layout
23
+
24
+ def initialize(fallback_layout = RubyJard::Layouts::WideLayout)
25
+ @layout_registry = {}
26
+ @fallback_layout = fallback_layout
27
+ end
28
+
29
+ def add_layout(name, layout_class)
30
+ unless layout_class.is_a?(RubyJard::Templates::LayoutTemplate)
31
+ raise RubyJard::Error, "#{layout_class} must be a #{RubyJard::Templates::LayoutTemplate}"
32
+ end
33
+
34
+ @layout_registry[name] = layout_class
35
+ end
36
+
37
+ def [](name)
38
+ @layout_registry[name.to_s.strip]
39
+ end
40
+ alias_method :get, :[]
41
+
42
+ def each(&block)
43
+ @layout_registry.each(&block)
44
+ end
45
+ end
46
+ end
47
+
48
+ # Registering order is also priority when picking layout
49
+ require 'ruby_jard/layouts/wide_layout'
50
+ require 'ruby_jard/layouts/narrow_vertical_layout'
51
+ require 'ruby_jard/layouts/narrow_horizontal_layout'
52
+ require 'ruby_jard/layouts/tiny_layout'
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ class Layouts
5
+ NarrowHorizontalLayout = RubyJard::Templates::LayoutTemplate.new(
6
+ min_width: 80,
7
+ min_height: 10,
8
+ fill_height: false,
9
+ children: [
10
+ RubyJard::Templates::LayoutTemplate.new(
11
+ height_ratio: 80,
12
+ width_ratio: 100,
13
+ children: [
14
+ RubyJard::Templates::ScreenTemplate.new(
15
+ screen: :source,
16
+ width_ratio: 60
17
+ ),
18
+ RubyJard::Templates::ScreenTemplate.new(
19
+ screen: :variables,
20
+ width_ratio: 40
21
+ )
22
+ ]
23
+ )
24
+ ]
25
+ )
26
+ end
27
+ end
28
+ RubyJard::Layouts.add_layout('narrow-horizontal', RubyJard::Layouts::NarrowHorizontalLayout)
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ class Layouts
5
+ NarrowVerticalLayout = RubyJard::Templates::LayoutTemplate.new(
6
+ min_width: 40,
7
+ min_height: 24,
8
+ fill_height: false,
9
+ children: [
10
+ RubyJard::Templates::LayoutTemplate.new(
11
+ height_ratio: 80,
12
+ width_ratio: 100,
13
+ children: [
14
+ RubyJard::Templates::ScreenTemplate.new(
15
+ screen: :source,
16
+ height_ratio: 60
17
+ ),
18
+ RubyJard::Templates::ScreenTemplate.new(
19
+ screen: :variables,
20
+ height_ratio: 40
21
+ )
22
+ ]
23
+ ),
24
+ RubyJard::Templates::ScreenTemplate.new(
25
+ height: 2,
26
+ screen: :menu
27
+ )
28
+ ]
29
+ )
30
+ end
31
+ end
32
+ RubyJard::Layouts.add_layout('narrow-vertical', RubyJard::Layouts::NarrowVerticalLayout)
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ class Layouts
5
+ TinyLayout = RubyJard::Templates::LayoutTemplate.new(
6
+ min_height: 10,
7
+ fill_height: false,
8
+ children: [
9
+ RubyJard::Templates::LayoutTemplate.new(
10
+ height_ratio: 80,
11
+ width_ratio: 100,
12
+ min_height: 7,
13
+ fill_height: true,
14
+ children: [
15
+ RubyJard::Templates::ScreenTemplate.new(
16
+ screen: :source,
17
+ height_ratio: 100
18
+ )
19
+ ]
20
+ )
21
+ ]
22
+ )
23
+ end
24
+ end
25
+ RubyJard::Layouts.add_layout('tiny', RubyJard::Layouts::TinyLayout)
@@ -1,26 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyJard
4
- module Layouts
4
+ class Layouts
5
5
  WideLayout = RubyJard::Templates::LayoutTemplate.new(
6
6
  min_width: 120,
7
- min_height: 10,
8
- fill_width: true,
7
+ min_height: 24,
8
+ fill_height: false,
9
9
  children: [
10
10
  RubyJard::Templates::LayoutTemplate.new(
11
11
  height_ratio: 80,
12
12
  width_ratio: 50,
13
- min_height: 7,
14
- fill_height: true,
15
13
  children: [
16
14
  RubyJard::Templates::ScreenTemplate.new(
17
15
  screen: :source,
18
- height_ratio: 60
16
+ height_ratio: 70,
17
+ adjust_mode: :expand
19
18
  ),
20
19
  RubyJard::Templates::ScreenTemplate.new(
21
- screen: :variables,
22
- width_ratio: 100,
23
- height_ratio: 40,
20
+ screen: :backtrace,
21
+ height_ratio: 30,
24
22
  min_height: 3
25
23
  )
26
24
  ]
@@ -28,17 +26,16 @@ module RubyJard
28
26
  RubyJard::Templates::LayoutTemplate.new(
29
27
  height_ratio: 80,
30
28
  width_ratio: 50,
31
- fill_height: true,
32
29
  children: [
33
30
  RubyJard::Templates::ScreenTemplate.new(
34
- screen: :backtrace,
35
- height_ratio: 50,
36
- fill_height: true
31
+ screen: :variables,
32
+ height_ratio: 80,
33
+ adjust_mode: :expand
37
34
  ),
38
35
  RubyJard::Templates::ScreenTemplate.new(
39
36
  screen: :threads,
40
- height_ratio: 50,
41
- fill_height: true
37
+ height_ratio: 20,
38
+ min_height: 3
42
39
  )
43
40
  ]
44
41
  ),
@@ -50,3 +47,4 @@ module RubyJard
50
47
  )
51
48
  end
52
49
  end
50
+ RubyJard::Layouts.add_layout('wide', RubyJard::Layouts::WideLayout)
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ ##
5
+ # Override Pry's pager system. Again, Pry doesn't support customizing pager. So...
6
+ class Pager
7
+ def initialize(pry_instance)
8
+ @pry_instance = pry_instance
9
+ end
10
+
11
+ def page(text)
12
+ open do |pager|
13
+ pager << text
14
+ end
15
+ end
16
+
17
+ def open(options = {})
18
+ pager = LessPager.new(@pry_instance, **options)
19
+ yield pager
20
+ rescue Pry::Pager::StopPaging
21
+ # Ignore
22
+ ensure
23
+ pager.close
24
+ end
25
+
26
+ private
27
+
28
+ def enabled?
29
+ !!@enabled
30
+ end
31
+
32
+ ##
33
+ # Pager using GNU Less
34
+ class LessPager < Pry::Pager::NullPager
35
+ def initialize(pry_instance, force_open: false, pager_start_at_the_end: false)
36
+ super(pry_instance.output)
37
+ @pry_instance = pry_instance
38
+ @buffer = ''
39
+
40
+ @pager_start_at_the_end = pager_start_at_the_end
41
+
42
+ @tracker = Pry::Pager::PageTracker.new(height, width)
43
+ @pager = force_open ? open_pager : nil
44
+ end
45
+
46
+ def write(str)
47
+ if invoked_pager?
48
+ write_into_pager str
49
+ else
50
+ @tracker.record str
51
+ @buffer += str
52
+ if @tracker.page?
53
+ @pager = open_pager
54
+ write_into_pager(@buffer)
55
+ end
56
+ end
57
+ rescue Errno::EPIPE
58
+ raise Pry::Pager::StopPaging
59
+ end
60
+
61
+ def close
62
+ if invoked_pager?
63
+ @pager.close
64
+ @pry_instance.exec_hook :after_pager, self
65
+
66
+ prompt = @pry_instance.prompt.wait_proc.call
67
+ # TODO: should show this tip even pager not invoked, when the size exceed a certain height
68
+ @out.puts "#{prompt}Tips: You can use `list` command to show back debugger screens"
69
+ else
70
+ @out.write @buffer
71
+ end
72
+ end
73
+
74
+ def invoked_pager?
75
+ @pager
76
+ end
77
+
78
+ def open_pager
79
+ @pry_instance.exec_hook :before_pager, self
80
+ less_command = ['less', '-R', '-X']
81
+ less_command << '+G' if @pager_start_at_the_end
82
+
83
+ IO.popen(
84
+ less_command.join(' '), 'w',
85
+ out: @pry_instance.output, err: @pry_instance.output
86
+ )
87
+ end
88
+
89
+ def write_into_pager(str)
90
+ return unless invoked_pager?
91
+
92
+ @pager.write str.encode('UTF-8', undef: :replace)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,5 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ruby_jard/commands/validation_helpers'
4
+ require 'ruby_jard/commands/continue_command'
5
+ require 'ruby_jard/commands/exit_command'
6
+ require 'ruby_jard/commands/up_command'
7
+ require 'ruby_jard/commands/down_command'
8
+ require 'ruby_jard/commands/next_command'
9
+ require 'ruby_jard/commands/step_command'
10
+ require 'ruby_jard/commands/step_out_command'
11
+ require 'ruby_jard/commands/frame_command'
12
+ require 'ruby_jard/commands/list_command'
13
+ require 'ruby_jard/commands/jard_command'
14
+
3
15
  module RubyJard
4
16
  ##
5
17
  # Byebug allows customizing processor with a series of hooks (https://github.com/deivid-rodriguez/byebug/blob/e1fb8209d56922f7bafd128af84e61568b6cd6a7/lib/byebug/processors/command_processor.rb)
@@ -10,8 +22,8 @@ module RubyJard
10
22
  # repl, and triggers Byebug debugger if needed.
11
23
  #
12
24
  class ReplProcessor < Byebug::CommandProcessor
13
- def initialize(context, interface = LocalInterface.new)
14
- super(context, interface)
25
+ def initialize(context, *args)
26
+ super(context, *args)
15
27
  @repl_proxy = RubyJard::ReplProxy.new(
16
28
  key_bindings: RubyJard.global_key_bindings
17
29
  )
@@ -21,7 +33,7 @@ module RubyJard
21
33
  process_commands_with_lock
22
34
  end
23
35
 
24
- def at_return(_)
36
+ def at_return(_return_value)
25
37
  process_commands_with_lock
26
38
  end
27
39
 
@@ -61,44 +73,39 @@ module RubyJard
61
73
  raise
62
74
  end
63
75
 
64
- def handle_next_command(_options = {})
65
- Byebug.current_context.step_over(1, Byebug.current_context.frame.pos)
76
+ def handle_next_command(options = {})
77
+ times = options[:times] || 1
78
+ Byebug.current_context.step_over(times, Byebug.current_context.frame.pos)
66
79
  proceed!
67
80
  end
68
81
 
69
- def handle_step_command(_options = {})
70
- Byebug.current_context.step_into(1, Byebug.current_context.frame.pos)
82
+ def handle_step_command(options = {})
83
+ times = options[:times] || 1
84
+ Byebug.current_context.step_into(times, Byebug.current_context.frame.pos)
71
85
  proceed!
72
86
  end
73
87
 
74
- def handle_step_out_command(_options = {})
75
- # TODO: handle c-frame and out of range frames
76
- Byebug.current_context.frame = 1
77
- proceed!
88
+ def handle_step_out_command(options = {})
89
+ times = options[:times] || 1
90
+
91
+ next_frame = up_n_frames(Byebug.current_context.frame.pos, times)
92
+ Byebug.current_context.frame = next_frame
78
93
  Byebug.current_context.step_over(1, Byebug.current_context.frame.pos)
79
94
  proceed!
80
95
  end
81
96
 
82
- def handle_up_command(_options = {})
83
- next_frame = [
84
- Byebug.current_context.frame.pos + 1,
85
- Byebug.current_context.backtrace.length - 1
86
- ].min
87
- while Byebug::Frame.new(Byebug.current_context, next_frame).c_frame? &&
88
- next_frame < Byebug.current_context.backtrace.length - 1
89
- next_frame += 1
90
- end
97
+ def handle_up_command(options = {})
98
+ times = options[:times] || 1
99
+
100
+ next_frame = up_n_frames(Byebug.current_context.frame.pos, times)
91
101
  Byebug.current_context.frame = next_frame
92
102
  proceed!
93
103
  process_commands
94
104
  end
95
105
 
96
- def handle_down_command(_options = {})
97
- next_frame = [Byebug.current_context.frame.pos - 1, 0].max
98
- while Byebug::Frame.new(Byebug.current_context, next_frame).c_frame? &&
99
- next_frame > 0
100
- next_frame -= 1
101
- end
106
+ def handle_down_command(options = {})
107
+ times = options[:times] || 1
108
+ next_frame = down_n_frames(Byebug.current_context.frame.pos, times)
102
109
  Byebug.current_context.frame = next_frame
103
110
  proceed!
104
111
  process_commands
@@ -107,7 +114,7 @@ module RubyJard
107
114
  def handle_frame_command(options)
108
115
  next_frame = options[:frame].to_i
109
116
  if Byebug::Frame.new(Byebug.current_context, next_frame).c_frame?
110
- puts "Error: Frame #{next_frame} is a c-frame. Not able to inspect c layer!"
117
+ RubyJard::ScreenManager.puts "Error: Frame #{next_frame} is a c-frame. Not able to inspect c layer!"
111
118
  process_commands(false)
112
119
  else
113
120
  Byebug.current_context.frame = next_frame
@@ -117,7 +124,11 @@ module RubyJard
117
124
  end
118
125
 
119
126
  def handle_continue_command(_options = {})
120
- # Do nothing
127
+ RubyJard::ScreenManager.puts '► ► Program resumed ► ►'
128
+ end
129
+
130
+ def handle_exit_command(_options = {})
131
+ Kernel.exit
121
132
  end
122
133
 
123
134
  def handle_key_binding_command(options = {})
@@ -134,9 +145,28 @@ module RubyJard
134
145
  process_commands
135
146
  end
136
147
 
137
- def handle_color_scheme_command(options = {})
138
- RubyJard.config.color_scheme = options[:color_scheme]
139
- process_commands
148
+ def up_n_frames(current_frame, times)
149
+ next_frame = current_frame
150
+ times.times do
151
+ next_frame = [next_frame + 1, Byebug.current_context.backtrace.length - 1].min
152
+ while Byebug::Frame.new(Byebug.current_context, next_frame).c_frame? &&
153
+ next_frame < Byebug.current_context.backtrace.length - 1
154
+ next_frame += 1
155
+ end
156
+ end
157
+ next_frame
158
+ end
159
+
160
+ def down_n_frames(current_frame, times)
161
+ next_frame = current_frame
162
+ times.times do
163
+ next_frame = [next_frame - 1, 0].max
164
+ while Byebug::Frame.new(Byebug.current_context, next_frame).c_frame? &&
165
+ next_frame > 0
166
+ next_frame -= 1
167
+ end
168
+ end
169
+ next_frame
140
170
  end
141
171
  end
142
172
  end