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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/workflows/documentation.yml +65 -0
- data/.github/workflows/rspec.yml +96 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +90 -2
- data/CHANGELOG.md +112 -0
- data/Gemfile +14 -4
- data/README.md +95 -3
- data/benchmark/path_filter_bench.rb +58 -0
- data/bin/console +1 -2
- data/lib/ruby_jard.rb +68 -32
- data/lib/ruby_jard/box_drawer.rb +175 -0
- data/lib/ruby_jard/color_scheme.rb +28 -0
- data/lib/ruby_jard/color_schemes.rb +54 -0
- data/lib/ruby_jard/color_schemes/256_color_scheme.rb +50 -0
- data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +50 -0
- data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +49 -0
- data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +48 -0
- data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +47 -0
- data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +49 -0
- data/lib/ruby_jard/column.rb +26 -0
- data/lib/ruby_jard/commands/color_helpers.rb +32 -0
- data/lib/ruby_jard/commands/continue_command.rb +4 -9
- data/lib/ruby_jard/commands/down_command.rb +9 -8
- data/lib/ruby_jard/commands/exit_command.rb +27 -0
- data/lib/ruby_jard/commands/frame_command.rb +13 -11
- data/lib/ruby_jard/commands/jard/color_scheme_command.rb +74 -0
- data/lib/ruby_jard/commands/jard/filter_command.rb +136 -0
- data/lib/ruby_jard/commands/jard/hide_command.rb +40 -0
- data/lib/ruby_jard/commands/jard/output_command.rb +36 -0
- data/lib/ruby_jard/commands/jard/show_command.rb +41 -0
- data/lib/ruby_jard/commands/jard_command.rb +52 -0
- data/lib/ruby_jard/commands/list_command.rb +31 -0
- data/lib/ruby_jard/commands/next_command.rb +11 -8
- data/lib/ruby_jard/commands/step_command.rb +11 -8
- data/lib/ruby_jard/commands/step_out_command.rb +34 -0
- data/lib/ruby_jard/commands/up_command.rb +10 -8
- data/lib/ruby_jard/commands/validation_helpers.rb +50 -0
- data/lib/ruby_jard/config.rb +61 -0
- data/lib/ruby_jard/console.rb +158 -0
- data/lib/ruby_jard/control_flow.rb +73 -0
- data/lib/ruby_jard/decorators/array_decorator.rb +79 -0
- data/lib/ruby_jard/decorators/attributes_decorator.rb +172 -0
- data/lib/ruby_jard/decorators/color_decorator.rb +80 -0
- data/lib/ruby_jard/decorators/hash_decorator.rb +74 -0
- data/lib/ruby_jard/decorators/inspection_decorator.rb +109 -0
- data/lib/ruby_jard/decorators/loc_decorator.rb +108 -119
- data/lib/ruby_jard/decorators/object_decorator.rb +122 -0
- data/lib/ruby_jard/decorators/path_decorator.rb +56 -60
- data/lib/ruby_jard/decorators/rails_decorator.rb +194 -0
- data/lib/ruby_jard/decorators/source_decorator.rb +3 -1
- data/lib/ruby_jard/decorators/string_decorator.rb +41 -0
- data/lib/ruby_jard/decorators/struct_decorator.rb +79 -0
- data/lib/ruby_jard/frame.rb +68 -0
- data/lib/ruby_jard/key_binding.rb +14 -0
- data/lib/ruby_jard/key_bindings.rb +96 -0
- data/lib/ruby_jard/keys.rb +48 -0
- data/lib/ruby_jard/layout.rb +17 -88
- data/lib/ruby_jard/layout_calculator.rb +168 -0
- data/lib/ruby_jard/layout_picker.rb +34 -0
- data/lib/ruby_jard/layouts.rb +52 -0
- data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +32 -0
- data/lib/ruby_jard/layouts/narrow_vertical_layout.rb +32 -0
- data/lib/ruby_jard/layouts/tiny_layout.rb +29 -0
- data/lib/ruby_jard/layouts/wide_layout.rb +50 -0
- data/lib/ruby_jard/pager.rb +112 -0
- data/lib/ruby_jard/path_classifier.rb +133 -0
- data/lib/ruby_jard/path_filter.rb +125 -0
- data/lib/ruby_jard/reflection.rb +97 -0
- data/lib/ruby_jard/repl_processor.rb +151 -89
- data/lib/ruby_jard/repl_proxy.rb +337 -0
- data/lib/ruby_jard/row.rb +31 -0
- data/lib/ruby_jard/row_renderer.rb +119 -0
- data/lib/ruby_jard/screen.rb +14 -41
- data/lib/ruby_jard/screen_adjuster.rb +104 -0
- data/lib/ruby_jard/screen_drawer.rb +25 -0
- data/lib/ruby_jard/screen_manager.rb +167 -82
- data/lib/ruby_jard/screen_renderer.rb +152 -0
- data/lib/ruby_jard/screens.rb +31 -12
- data/lib/ruby_jard/screens/backtrace_screen.rb +118 -116
- data/lib/ruby_jard/screens/menu_screen.rb +73 -45
- data/lib/ruby_jard/screens/source_screen.rb +86 -106
- data/lib/ruby_jard/screens/threads_screen.rb +103 -78
- data/lib/ruby_jard/screens/variables_screen.rb +224 -142
- data/lib/ruby_jard/session.rb +151 -16
- data/lib/ruby_jard/span.rb +23 -0
- data/lib/ruby_jard/templates/layout_template.rb +35 -0
- data/lib/ruby_jard/templates/screen_template.rb +34 -0
- data/lib/ruby_jard/thread_info.rb +69 -0
- data/lib/ruby_jard/version.rb +1 -1
- data/ruby_jard.gemspec +7 -8
- metadata +84 -50
- data/.travis.yml +0 -6
- data/lib/ruby_jard/commands/finish_command.rb +0 -31
- data/lib/ruby_jard/decorators/text_decorator.rb +0 -61
- data/lib/ruby_jard/layout_template.rb +0 -101
- data/lib/ruby_jard/screens/breakpoints_screen.rb +0 -23
- data/lib/ruby_jard/screens/empty_screen.rb +0 -13
- 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
|
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
|
10
|
-
#
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
36
|
+
process_commands_with_lock
|
40
37
|
end
|
41
38
|
|
42
|
-
def at_return(
|
43
|
-
|
39
|
+
def at_return(_return_value)
|
40
|
+
process_commands_with_lock
|
44
41
|
end
|
45
42
|
|
46
43
|
def at_end
|
47
|
-
|
44
|
+
process_commands_with_lock
|
48
45
|
end
|
49
46
|
|
50
47
|
private
|
51
48
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
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
|
-
|
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
|
-
|
64
|
-
|
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
|
73
|
-
if
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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(
|
86
|
-
|
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(
|
90
|
-
|
94
|
+
def handle_step_command(options = {})
|
95
|
+
times = options[:times] || 1
|
96
|
+
RubyJard::Session.step_into(times)
|
91
97
|
end
|
92
98
|
|
93
|
-
def
|
94
|
-
|
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(
|
100
|
-
|
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
|
106
|
-
RubyJard.
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
113
|
-
|
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
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
129
|
-
|
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
|