ruby_jard 0.1.0 → 0.3.0

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/workflows/documentation.yml +65 -0
  6. data/.github/workflows/rspec.yml +96 -0
  7. data/.gitignore +1 -0
  8. data/.rubocop.yml +90 -2
  9. data/CHANGELOG.md +112 -0
  10. data/Gemfile +14 -4
  11. data/README.md +95 -3
  12. data/benchmark/path_filter_bench.rb +58 -0
  13. data/bin/console +1 -2
  14. data/lib/ruby_jard.rb +68 -32
  15. data/lib/ruby_jard/box_drawer.rb +175 -0
  16. data/lib/ruby_jard/color_scheme.rb +28 -0
  17. data/lib/ruby_jard/color_schemes.rb +54 -0
  18. data/lib/ruby_jard/color_schemes/256_color_scheme.rb +50 -0
  19. data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +50 -0
  20. data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +49 -0
  21. data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +48 -0
  22. data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +47 -0
  23. data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +49 -0
  24. data/lib/ruby_jard/column.rb +26 -0
  25. data/lib/ruby_jard/commands/color_helpers.rb +32 -0
  26. data/lib/ruby_jard/commands/continue_command.rb +4 -9
  27. data/lib/ruby_jard/commands/down_command.rb +9 -8
  28. data/lib/ruby_jard/commands/exit_command.rb +27 -0
  29. data/lib/ruby_jard/commands/frame_command.rb +13 -11
  30. data/lib/ruby_jard/commands/jard/color_scheme_command.rb +74 -0
  31. data/lib/ruby_jard/commands/jard/filter_command.rb +136 -0
  32. data/lib/ruby_jard/commands/jard/hide_command.rb +40 -0
  33. data/lib/ruby_jard/commands/jard/output_command.rb +36 -0
  34. data/lib/ruby_jard/commands/jard/show_command.rb +41 -0
  35. data/lib/ruby_jard/commands/jard_command.rb +52 -0
  36. data/lib/ruby_jard/commands/list_command.rb +31 -0
  37. data/lib/ruby_jard/commands/next_command.rb +11 -8
  38. data/lib/ruby_jard/commands/step_command.rb +11 -8
  39. data/lib/ruby_jard/commands/step_out_command.rb +34 -0
  40. data/lib/ruby_jard/commands/up_command.rb +10 -8
  41. data/lib/ruby_jard/commands/validation_helpers.rb +50 -0
  42. data/lib/ruby_jard/config.rb +61 -0
  43. data/lib/ruby_jard/console.rb +158 -0
  44. data/lib/ruby_jard/control_flow.rb +73 -0
  45. data/lib/ruby_jard/decorators/array_decorator.rb +79 -0
  46. data/lib/ruby_jard/decorators/attributes_decorator.rb +172 -0
  47. data/lib/ruby_jard/decorators/color_decorator.rb +80 -0
  48. data/lib/ruby_jard/decorators/hash_decorator.rb +74 -0
  49. data/lib/ruby_jard/decorators/inspection_decorator.rb +109 -0
  50. data/lib/ruby_jard/decorators/loc_decorator.rb +108 -119
  51. data/lib/ruby_jard/decorators/object_decorator.rb +122 -0
  52. data/lib/ruby_jard/decorators/path_decorator.rb +56 -60
  53. data/lib/ruby_jard/decorators/rails_decorator.rb +194 -0
  54. data/lib/ruby_jard/decorators/source_decorator.rb +3 -1
  55. data/lib/ruby_jard/decorators/string_decorator.rb +41 -0
  56. data/lib/ruby_jard/decorators/struct_decorator.rb +79 -0
  57. data/lib/ruby_jard/frame.rb +68 -0
  58. data/lib/ruby_jard/key_binding.rb +14 -0
  59. data/lib/ruby_jard/key_bindings.rb +96 -0
  60. data/lib/ruby_jard/keys.rb +48 -0
  61. data/lib/ruby_jard/layout.rb +17 -88
  62. data/lib/ruby_jard/layout_calculator.rb +168 -0
  63. data/lib/ruby_jard/layout_picker.rb +34 -0
  64. data/lib/ruby_jard/layouts.rb +52 -0
  65. data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +32 -0
  66. data/lib/ruby_jard/layouts/narrow_vertical_layout.rb +32 -0
  67. data/lib/ruby_jard/layouts/tiny_layout.rb +29 -0
  68. data/lib/ruby_jard/layouts/wide_layout.rb +50 -0
  69. data/lib/ruby_jard/pager.rb +112 -0
  70. data/lib/ruby_jard/path_classifier.rb +133 -0
  71. data/lib/ruby_jard/path_filter.rb +125 -0
  72. data/lib/ruby_jard/reflection.rb +97 -0
  73. data/lib/ruby_jard/repl_processor.rb +151 -89
  74. data/lib/ruby_jard/repl_proxy.rb +337 -0
  75. data/lib/ruby_jard/row.rb +31 -0
  76. data/lib/ruby_jard/row_renderer.rb +119 -0
  77. data/lib/ruby_jard/screen.rb +14 -41
  78. data/lib/ruby_jard/screen_adjuster.rb +104 -0
  79. data/lib/ruby_jard/screen_drawer.rb +25 -0
  80. data/lib/ruby_jard/screen_manager.rb +167 -82
  81. data/lib/ruby_jard/screen_renderer.rb +152 -0
  82. data/lib/ruby_jard/screens.rb +31 -12
  83. data/lib/ruby_jard/screens/backtrace_screen.rb +118 -116
  84. data/lib/ruby_jard/screens/menu_screen.rb +73 -45
  85. data/lib/ruby_jard/screens/source_screen.rb +86 -106
  86. data/lib/ruby_jard/screens/threads_screen.rb +103 -78
  87. data/lib/ruby_jard/screens/variables_screen.rb +224 -142
  88. data/lib/ruby_jard/session.rb +151 -16
  89. data/lib/ruby_jard/span.rb +23 -0
  90. data/lib/ruby_jard/templates/layout_template.rb +35 -0
  91. data/lib/ruby_jard/templates/screen_template.rb +34 -0
  92. data/lib/ruby_jard/thread_info.rb +69 -0
  93. data/lib/ruby_jard/version.rb +1 -1
  94. data/ruby_jard.gemspec +7 -8
  95. metadata +84 -50
  96. data/.travis.yml +0 -6
  97. data/lib/ruby_jard/commands/finish_command.rb +0 -31
  98. data/lib/ruby_jard/decorators/text_decorator.rb +0 -61
  99. data/lib/ruby_jard/layout_template.rb +0 -101
  100. data/lib/ruby_jard/screens/breakpoints_screen.rb +0 -23
  101. data/lib/ruby_jard/screens/empty_screen.rb +0 -13
  102. data/lib/ruby_jard/screens/expressions_sreen.rb +0 -22
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ ##
5
+ # Check whether a particular path should be passed when debugging.
6
+ # Filtering is based on path classification (from PathClassifier),
7
+ # program's current filter mode, and filter included, excluded.
8
+ class PathFilter
9
+ FILTERS = [
10
+ FILTER_SOURCE_TREE = :source_tree,
11
+ FILTER_APPLICATION = :application,
12
+ FILTER_GEMS = :gems,
13
+ FILTER_EVERYTHING = :everything
14
+ ].freeze
15
+ def initialize(config: nil, path_classifier: nil)
16
+ @config = config || RubyJard.config
17
+ @path_classifier = path_classifier || RubyJard::PathClassifier.new
18
+ end
19
+
20
+ def match?(path)
21
+ case @config.filter
22
+ when FILTER_EVERYTHING
23
+ match_everything?(path)
24
+ when FILTER_GEMS
25
+ match_gems?(path)
26
+ when FILTER_APPLICATION
27
+ match_application?(path)
28
+ when FILTER_SOURCE_TREE
29
+ match_source_tree?(path)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def match_everything?(path)
36
+ return true if @config.filter_excluded.empty?
37
+
38
+ type, *info = @path_classifier.classify(path)
39
+
40
+ case type
41
+ when RubyJard::PathClassifier::TYPE_SOURCE_TREE, RubyJard::PathClassifier::TYPE_UNKNOWN
42
+ !match_excluded?(path)
43
+ when RubyJard::PathClassifier::TYPE_GEM
44
+ !match_excluded?(info[0], expand_path: false) && !match_excluded?(path)
45
+ when RubyJard::PathClassifier::TYPE_STDLIB
46
+ !match_excluded?(info[0], expand_path: false) && !match_excluded?(path)
47
+ else
48
+ true
49
+ end
50
+ end
51
+
52
+ def match_gems?(path)
53
+ type, *info = @path_classifier.classify(path)
54
+
55
+ case type
56
+ when RubyJard::PathClassifier::TYPE_SOURCE_TREE, RubyJard::PathClassifier::TYPE_UNKNOWN
57
+ !match_excluded?(path)
58
+ when RubyJard::PathClassifier::TYPE_GEM
59
+ !match_excluded?(info[0], expand_path: false) && !match_excluded?(path)
60
+ when RubyJard::PathClassifier::TYPE_STDLIB
61
+ match_included?(info[0], expand_path: false) || match_included?(path)
62
+ when RubyJard::PathClassifier::TYPE_RUBY_SCRIPT, RubyJard::PathClassifier::TYPE_EVALUATION
63
+ true
64
+ when RubyJard::PathClassifier::TYPE_INTERNAL
65
+ false
66
+ end
67
+ end
68
+
69
+ def match_application?(path)
70
+ type, *info = @path_classifier.classify(path)
71
+
72
+ case type
73
+ when RubyJard::PathClassifier::TYPE_SOURCE_TREE, RubyJard::PathClassifier::TYPE_UNKNOWN
74
+ !match_excluded?(path)
75
+ when RubyJard::PathClassifier::TYPE_GEM, RubyJard::PathClassifier::TYPE_STDLIB
76
+ match_included?(info[0], expand_path: false) || match_included?(path)
77
+ when RubyJard::PathClassifier::TYPE_RUBY_SCRIPT
78
+ true
79
+ when RubyJard::PathClassifier::TYPE_EVALUATION
80
+ false
81
+ when RubyJard::PathClassifier::TYPE_INTERNAL
82
+ false
83
+ end
84
+ end
85
+
86
+ def match_source_tree?(path)
87
+ type, *info = @path_classifier.classify(path)
88
+
89
+ case type
90
+ when RubyJard::PathClassifier::TYPE_SOURCE_TREE
91
+ !match_excluded?(path)
92
+ when RubyJard::PathClassifier::TYPE_UNKNOWN
93
+ match_included?(path)
94
+ when RubyJard::PathClassifier::TYPE_GEM, RubyJard::PathClassifier::TYPE_STDLIB
95
+ match_included?(info[0], expand_path: false) || match_included?(path)
96
+ when RubyJard::PathClassifier::TYPE_RUBY_SCRIPT
97
+ true
98
+ when RubyJard::PathClassifier::TYPE_EVALUATION
99
+ false
100
+ when RubyJard::PathClassifier::TYPE_INTERNAL
101
+ false
102
+ end
103
+ end
104
+
105
+ def match_excluded?(path, expand_path: true)
106
+ @config.filter_excluded.any? do |excluded|
107
+ if expand_path
108
+ File.fnmatch(File.expand_path(excluded), path)
109
+ else
110
+ File.fnmatch(excluded, path)
111
+ end
112
+ end
113
+ end
114
+
115
+ def match_included?(path, expand_path: true)
116
+ @config.filter_included.any? do |included|
117
+ if expand_path
118
+ File.fnmatch(File.expand_path(included), path)
119
+ else
120
+ File.fnmatch(included, path)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ ##
5
+ # User classes may override basic Kernel methods, such as #inspect
6
+ # or #to_s, or even #is_a?. It's not very wise to call those methods
7
+ # directly, as there maybe side effects. Therefore, this class is
8
+ # to extract unbound methods from Kernel module, and then call them
9
+ # in Object's context.
10
+ class Reflection
11
+ class << self
12
+ def call_class(object)
13
+ if call_is_a?(object, Module)
14
+ bind_call(Kernel, :class, object)
15
+ else
16
+ instance_bind_call(Kernel, :class, object)
17
+ end
18
+ end
19
+
20
+ def call_respond_to?(object, method_name)
21
+ if call_is_a?(object, Module)
22
+ bind_call(Kernel, :respond_to?, object, method_name)
23
+ else
24
+ instance_bind_call(Kernel, :respond_to?, object, method_name)
25
+ end
26
+ end
27
+
28
+ def call_instance_variables(object)
29
+ bind_call(Kernel, :instance_variables, object)
30
+ end
31
+
32
+ def call_instance_variable_get(object, variable)
33
+ bind_call(Kernel, :instance_variable_get, object, variable)
34
+ end
35
+
36
+ def call_instance_variable_set(object, variable, value)
37
+ bind_call(Kernel, :instance_variable_set, object, variable, value)
38
+ end
39
+
40
+ def call_inspect(object)
41
+ if call_is_a?(object, Module)
42
+ bind_call(Kernel, :inspect, object)
43
+ else
44
+ instance_bind_call(Kernel, :inspect, object)
45
+ end
46
+ end
47
+
48
+ def call_to_s(object)
49
+ if call_is_a?(object, Module)
50
+ bind_call(Kernel, :to_s, object)
51
+ else
52
+ instance_bind_call(Kernel, :to_s, object)
53
+ end
54
+ end
55
+
56
+ def call_is_a?(object, comparing_class)
57
+ bind_call(Kernel, :is_a?, object, comparing_class)
58
+ end
59
+
60
+ def call_const_get(object, const_name)
61
+ bind_call(Kernel, :const_get, object, const_name)
62
+ end
63
+
64
+ def call_const_defined?(object, const_name)
65
+ bind_call(Kernel, :const_defined?, object, const_name)
66
+ end
67
+
68
+ def bind_call(owner, method_name, object, *args)
69
+ @method_cache ||= {}
70
+ @method_cache[owner] ||= {}
71
+ @method_cache[owner][method_name] ||= fetch_method(owner, method_name)
72
+ @method_cache[owner][method_name].bind(object).call(*args)
73
+ end
74
+
75
+ def instance_bind_call(owner, method_name, object, *args)
76
+ @instance_method_cache ||= {}
77
+ @instance_method_cache[owner] ||= {}
78
+ @instance_method_cache[owner][method_name] ||= fetch_instance_method(owner, method_name)
79
+ @instance_method_cache[owner][method_name].bind(object).call(*args)
80
+ end
81
+
82
+ def fetch_method(object, method_name)
83
+ @method_cache ||= {}
84
+ @method_cache[::Kernel] ||= {}
85
+ @method_cache[::Kernel][:method] ||= ::Kernel.method(:method).unbind
86
+ @method_cache[::Kernel][:method].bind(object).call(method_name).unbind
87
+ end
88
+
89
+ def fetch_instance_method(object, method_name)
90
+ @method_cache ||= {}
91
+ @method_cache[::Kernel] ||= {}
92
+ @method_cache[::Kernel][:instance_method] ||= ::Kernel.method(:instance_method).unbind
93
+ @method_cache[::Kernel][:instance_method].bind(object).call(method_name)
94
+ end
95
+ end
96
+ end
97
+ end
@@ -1,143 +1,205 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ruby_jard/commands/validation_helpers'
4
+ require 'ruby_jard/commands/color_helpers'
5
+ require 'ruby_jard/commands/continue_command'
6
+ require 'ruby_jard/commands/exit_command'
7
+ require 'ruby_jard/commands/up_command'
8
+ require 'ruby_jard/commands/down_command'
9
+ require 'ruby_jard/commands/next_command'
10
+ require 'ruby_jard/commands/step_command'
11
+ require 'ruby_jard/commands/step_out_command'
12
+ require 'ruby_jard/commands/frame_command'
13
+ require 'ruby_jard/commands/list_command'
14
+ require 'ruby_jard/commands/jard_command'
15
+
3
16
  module RubyJard
4
17
  ##
5
18
  # Byebug allows customizing processor with a series of hooks (https://github.com/deivid-rodriguez/byebug/blob/e1fb8209d56922f7bafd128af84e61568b6cd6a7/lib/byebug/processors/command_processor.rb)
6
19
  #
7
- # This class is a bridge between Pry and Byebug. It is inherited from
20
+ # This class is a bridge between REPL library and Byebug. It is inherited from
8
21
  # Byebug::CommandProcessor, the processor is triggered. It starts draw the
9
- # UI, starts a new pry session, listen for control-flow events threw from
10
- # pry commands (lib/commands/*), and triggers Byebug debugger if needed.
22
+ # UI, starts a new REPL session, listen for control-flow events threw from
23
+ # repl, and triggers Byebug debugger if needed.
11
24
  #
12
25
  class ReplProcessor < Byebug::CommandProcessor
13
- # Some commands overlaps with Jard, Ruby, and even cause confusion for
14
- # users. It's better ignore or re-implement those commands.
15
- PRY_EXCLUDED_COMMANDS = [
16
- 'pry-backtrace', # Redundant method for normal user
17
- 'watch', # Conflict with byebug and jard watch
18
- 'whereami', # Jard already provides similar. Keeping this command makes conflicted experience
19
- 'edit', # Sorry, but a file should not be editted while debugging, as it made breakpoints shifted
20
- 'play', # What if the played files or methods include jard again?
21
- 'stat', # Included in jard UI
22
- 'backtrace', # Re-implemented later
23
- 'break', # Re-implemented later
24
- 'exit', # Conflicted with continue
25
- 'exit-all', # Conflicted with continue
26
- 'exit-program', # We already have `exit` native command
27
- '!pry', # No need to complicate things
28
- 'jump-to', # No need to complicate things
29
- 'nesting', # No need to complicate things
30
- 'switch-to', # No need to complicate things
31
- 'disable-pry' # No need to complicate things
32
- ].freeze
33
-
34
- def initialize(context, interface = LocalInterface.new)
35
- super(context, interface)
26
+ def initialize(context, *args)
27
+ super(context, *args)
28
+ @config = RubyJard.config
29
+ @repl_proxy = RubyJard::ReplProxy.new(
30
+ key_bindings: RubyJard.global_key_bindings
31
+ )
32
+ @previous_flow = nil
36
33
  end
37
34
 
38
35
  def at_line
39
- process_commands
36
+ process_commands_with_lock
40
37
  end
41
38
 
42
- def at_return(_)
43
- process_commands
39
+ def at_return(_return_value)
40
+ process_commands_with_lock
44
41
  end
45
42
 
46
43
  def at_end
47
- process_commands
44
+ process_commands_with_lock
48
45
  end
49
46
 
50
47
  private
51
48
 
52
- def process_commands
53
- RubyJard.current_session.refresh
54
- return_value = nil
49
+ def process_commands_with_lock
50
+ allowing_other_threads do
51
+ RubyJard::Session.lock do
52
+ RubyJard::Session.sync(@context)
53
+ unless RubyJard::Session.should_stop?
54
+ handle_flow(@previous_flow)
55
+ return
56
+ end
55
57
 
56
- flow = catch(:control_flow) do
57
- return_value = allowing_other_threads do
58
- start_pry_session
58
+ process_commands
59
59
  end
60
- {}
61
60
  end
61
+ end
62
+
63
+ def process_commands(redraw = true)
64
+ RubyJard::Session.sync(@context)
65
+ RubyJard::ScreenManager.draw_screens if redraw
66
+
67
+ return_value = nil
62
68
 
63
- @pry = flow[:pry]
64
- if @pry
65
- @pry.binding_stack.clear
66
- send("handle_#{flow[:command]}_command", @pry, flow[:options])
69
+ flow = RubyJard::ControlFlow.listen do
70
+ return_value = @repl_proxy.repl(frame._binding)
67
71
  end
68
72
 
73
+ handle_flow(flow)
74
+
69
75
  return_value
76
+ rescue StandardError => e
77
+ RubyJard::ScreenManager.draw_error(e)
78
+ raise
70
79
  end
71
80
 
72
- def start_pry_session
73
- if @pry.nil?
74
- @pry = Pry.start(
75
- frame._binding,
76
- prompt: pry_jard_prompt,
77
- quiet: true,
78
- commands: pry_command_set
79
- )
80
- else
81
- @pry.repl(frame._binding)
82
- end
81
+ def handle_flow(flow)
82
+ return if flow.nil?
83
+
84
+ @previous_flow = flow
85
+ command = flow.command
86
+ send("handle_#{command}_command", flow.arguments)
83
87
  end
84
88
 
85
- def handle_next_command(_pry_instance, _options)
86
- Byebug::NextCommand.new(self, 'next').execute
89
+ def handle_next_command(options = {})
90
+ times = options[:times] || 1
91
+ RubyJard::Session.step_over(times)
87
92
  end
88
93
 
89
- def handle_step_command(_pry_instance, _options)
90
- Byebug::StepCommand.new(self, 'step').execute
94
+ def handle_step_command(options = {})
95
+ times = options[:times] || 1
96
+ RubyJard::Session.step_into(times)
91
97
  end
92
98
 
93
- def handle_up_command(_pry_instance, _options)
94
- Byebug::UpCommand.new(self, 'up 1').execute
99
+ def handle_step_out_command(options = {})
100
+ times = options[:times] || 1
95
101
 
102
+ next_frame = up_n_frames(RubyJard::Session.current_frame.real_pos, times)
103
+ RubyJard::Session.frame = next_frame
104
+ RubyJard::Session.step_over(1)
105
+ end
106
+
107
+ def handle_up_command(options = {})
108
+ times = options[:times] || 1
109
+
110
+ next_frame = up_n_frames(RubyJard::Session.current_frame.real_pos, times)
111
+ RubyJard::Session.frame = next_frame
96
112
  process_commands
97
113
  end
98
114
 
99
- def handle_down_command(_pry_instance, _options)
100
- Byebug::DownCommand.new(self, 'down 1').execute
115
+ def handle_down_command(options = {})
116
+ times = options[:times] || 1
117
+ next_frame = down_n_frames(RubyJard::Session.current_frame.real_pos, times)
118
+ RubyJard::Session.frame = next_frame
119
+ process_commands
120
+ end
101
121
 
122
+ def handle_frame_command(options)
123
+ next_frame = find_frame(options[:frame].to_i)
124
+ if next_frame.nil?
125
+ # There must be an error in outer validators
126
+ RubyJard::ScreenManager.puts 'Error: Frame not found. There should be an error with Jard.'
127
+ process_commands(false)
128
+ elsif next_frame.c_frame?
129
+ RubyJard::ScreenManager.puts "Error: Frame #{next_frame} is a c-frame. Not able to inspect c layer!"
130
+ process_commands(false)
131
+ else
132
+ RubyJard::Session.frame = next_frame.real_pos
133
+ process_commands(true)
134
+ end
135
+ end
136
+
137
+ def handle_continue_command(_options = {})
138
+ RubyJard::ScreenManager.puts '▸▸ Program resumed ▸▸'
139
+ Byebug.stop if Byebug.stoppable?
140
+ end
141
+
142
+ def handle_exit_command(_options = {})
143
+ Kernel.exit
144
+ end
145
+
146
+ def handle_key_binding_command(options = {})
147
+ method_name = "handle_#{options[:action]}_command"
148
+ if respond_to?(method_name, true)
149
+ send(method_name)
150
+ else
151
+ raise RubyJard::Error,
152
+ "Fail to handle key binding `#{options[:action]}`"
153
+ end
154
+ end
155
+
156
+ def handle_list_command(_options = {})
102
157
  process_commands
103
158
  end
104
159
 
105
- def handle_finish_command(_pry_instance, _options)
106
- RubyJard.current_session.disable
107
- context.step_out(2, true)
108
- Byebug::NextCommand.new(self, 'next').execute
109
- RubyJard.current_session.enable
160
+ def handle_switch_filter_command(_options = {})
161
+ index = RubyJard::PathFilter::FILTERS.index(@config.filter) || -1
162
+ index = (index + 1) % RubyJard::PathFilter::FILTERS.length
163
+ @config.filter = RubyJard::PathFilter::FILTERS[index]
164
+
165
+ process_commands
110
166
  end
111
167
 
112
- def handle_continue_command(_pry_instance, _options)
113
- # Do nothing
168
+ def up_n_frames(real_pos, times)
169
+ next_frame = real_pos
170
+ times.times do
171
+ next_frame = [next_frame + 1, RubyJard::Session.current_backtrace.length - 1].min
172
+ while next_frame < RubyJard::Session.current_backtrace.length &&
173
+ (
174
+ RubyJard::Session.current_backtrace[next_frame].c_frame? ||
175
+ RubyJard::Session.current_backtrace[next_frame].hidden?
176
+ )
177
+ next_frame += 1
178
+ end
179
+ return real_pos if next_frame >= RubyJard::Session.current_backtrace.length
180
+ end
181
+ next_frame
114
182
  end
115
183
 
116
- def pry_command_set
117
- @pry_command_set ||=
118
- begin
119
- set = Pry::CommandSet.new
120
- set.import_from(
121
- Pry.config.commands,
122
- *(Pry.config.commands.list_commands - PRY_EXCLUDED_COMMANDS)
123
- )
124
- set
184
+ def down_n_frames(real_pos, times)
185
+ next_frame = real_pos
186
+ times.times do
187
+ next_frame = [next_frame - 1, 0].max
188
+ while next_frame >= 0 &&
189
+ (
190
+ RubyJard::Session.current_backtrace[next_frame].c_frame? ||
191
+ RubyJard::Session.current_backtrace[next_frame].hidden?
192
+ )
193
+
194
+ next_frame -= 1
125
195
  end
196
+ return real_pos if next_frame < 0
197
+ end
198
+ next_frame
126
199
  end
127
200
 
128
- def pry_jard_prompt
129
- @pry_jard_prompt ||=
130
- Pry::Prompt.new(
131
- :jard,
132
- 'Custom pry promt for Jard', [
133
- proc do |_context, _nesting, _pry_instance|
134
- 'jard >> '
135
- end,
136
- proc do |_context, _nesting, _pry_instance|
137
- 'jard *> '
138
- end
139
- ]
140
- )
201
+ def find_frame(virtual_pos)
202
+ RubyJard::Session.current_backtrace.find { |frame| frame.virtual_pos == virtual_pos }
141
203
  end
142
204
  end
143
205
  end