runger_byebug 11.2.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 (132) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +954 -0
  3. data/CONTRIBUTING.md +58 -0
  4. data/GUIDE.md +1806 -0
  5. data/LICENSE +23 -0
  6. data/README.md +199 -0
  7. data/exe/byebug +6 -0
  8. data/ext/byebug/breakpoint.c +521 -0
  9. data/ext/byebug/byebug.c +900 -0
  10. data/ext/byebug/byebug.h +145 -0
  11. data/ext/byebug/context.c +687 -0
  12. data/ext/byebug/extconf.rb +12 -0
  13. data/ext/byebug/locker.c +96 -0
  14. data/ext/byebug/threads.c +241 -0
  15. data/lib/byebug/attacher.rb +48 -0
  16. data/lib/byebug/breakpoint.rb +94 -0
  17. data/lib/byebug/command.rb +111 -0
  18. data/lib/byebug/command_list.rb +34 -0
  19. data/lib/byebug/commands/break.rb +114 -0
  20. data/lib/byebug/commands/catch.rb +78 -0
  21. data/lib/byebug/commands/condition.rb +55 -0
  22. data/lib/byebug/commands/continue.rb +68 -0
  23. data/lib/byebug/commands/debug.rb +38 -0
  24. data/lib/byebug/commands/delete.rb +55 -0
  25. data/lib/byebug/commands/disable/breakpoints.rb +42 -0
  26. data/lib/byebug/commands/disable/display.rb +43 -0
  27. data/lib/byebug/commands/disable.rb +33 -0
  28. data/lib/byebug/commands/display.rb +66 -0
  29. data/lib/byebug/commands/down.rb +45 -0
  30. data/lib/byebug/commands/edit.rb +69 -0
  31. data/lib/byebug/commands/enable/breakpoints.rb +42 -0
  32. data/lib/byebug/commands/enable/display.rb +43 -0
  33. data/lib/byebug/commands/enable.rb +33 -0
  34. data/lib/byebug/commands/finish.rb +57 -0
  35. data/lib/byebug/commands/frame.rb +57 -0
  36. data/lib/byebug/commands/help.rb +64 -0
  37. data/lib/byebug/commands/history.rb +39 -0
  38. data/lib/byebug/commands/info/breakpoints.rb +65 -0
  39. data/lib/byebug/commands/info/display.rb +49 -0
  40. data/lib/byebug/commands/info/file.rb +80 -0
  41. data/lib/byebug/commands/info/line.rb +35 -0
  42. data/lib/byebug/commands/info/program.rb +49 -0
  43. data/lib/byebug/commands/info.rb +37 -0
  44. data/lib/byebug/commands/interrupt.rb +34 -0
  45. data/lib/byebug/commands/irb.rb +50 -0
  46. data/lib/byebug/commands/kill.rb +45 -0
  47. data/lib/byebug/commands/list.rb +159 -0
  48. data/lib/byebug/commands/method.rb +53 -0
  49. data/lib/byebug/commands/next.rb +40 -0
  50. data/lib/byebug/commands/pry.rb +41 -0
  51. data/lib/byebug/commands/quit.rb +42 -0
  52. data/lib/byebug/commands/restart.rb +64 -0
  53. data/lib/byebug/commands/save.rb +72 -0
  54. data/lib/byebug/commands/set.rb +79 -0
  55. data/lib/byebug/commands/show.rb +45 -0
  56. data/lib/byebug/commands/skip.rb +85 -0
  57. data/lib/byebug/commands/source.rb +40 -0
  58. data/lib/byebug/commands/step.rb +40 -0
  59. data/lib/byebug/commands/thread/current.rb +37 -0
  60. data/lib/byebug/commands/thread/list.rb +43 -0
  61. data/lib/byebug/commands/thread/resume.rb +45 -0
  62. data/lib/byebug/commands/thread/stop.rb +43 -0
  63. data/lib/byebug/commands/thread/switch.rb +46 -0
  64. data/lib/byebug/commands/thread.rb +34 -0
  65. data/lib/byebug/commands/tracevar.rb +54 -0
  66. data/lib/byebug/commands/undisplay.rb +51 -0
  67. data/lib/byebug/commands/untracevar.rb +36 -0
  68. data/lib/byebug/commands/up.rb +45 -0
  69. data/lib/byebug/commands/var/all.rb +41 -0
  70. data/lib/byebug/commands/var/args.rb +39 -0
  71. data/lib/byebug/commands/var/const.rb +49 -0
  72. data/lib/byebug/commands/var/global.rb +37 -0
  73. data/lib/byebug/commands/var/instance.rb +39 -0
  74. data/lib/byebug/commands/var/local.rb +39 -0
  75. data/lib/byebug/commands/var.rb +37 -0
  76. data/lib/byebug/commands/where.rb +64 -0
  77. data/lib/byebug/commands.rb +40 -0
  78. data/lib/byebug/context.rb +157 -0
  79. data/lib/byebug/core.rb +115 -0
  80. data/lib/byebug/errors.rb +29 -0
  81. data/lib/byebug/frame.rb +185 -0
  82. data/lib/byebug/helpers/bin.rb +47 -0
  83. data/lib/byebug/helpers/eval.rb +134 -0
  84. data/lib/byebug/helpers/file.rb +63 -0
  85. data/lib/byebug/helpers/frame.rb +75 -0
  86. data/lib/byebug/helpers/parse.rb +80 -0
  87. data/lib/byebug/helpers/path.rb +40 -0
  88. data/lib/byebug/helpers/reflection.rb +19 -0
  89. data/lib/byebug/helpers/string.rb +33 -0
  90. data/lib/byebug/helpers/thread.rb +67 -0
  91. data/lib/byebug/helpers/toggle.rb +62 -0
  92. data/lib/byebug/helpers/var.rb +70 -0
  93. data/lib/byebug/history.rb +130 -0
  94. data/lib/byebug/interface.rb +146 -0
  95. data/lib/byebug/interfaces/local_interface.rb +63 -0
  96. data/lib/byebug/interfaces/remote_interface.rb +50 -0
  97. data/lib/byebug/interfaces/script_interface.rb +33 -0
  98. data/lib/byebug/interfaces/test_interface.rb +67 -0
  99. data/lib/byebug/option_setter.rb +95 -0
  100. data/lib/byebug/printers/base.rb +68 -0
  101. data/lib/byebug/printers/plain.rb +44 -0
  102. data/lib/byebug/printers/texts/base.yml +115 -0
  103. data/lib/byebug/printers/texts/plain.yml +33 -0
  104. data/lib/byebug/processors/command_processor.rb +173 -0
  105. data/lib/byebug/processors/control_processor.rb +24 -0
  106. data/lib/byebug/processors/post_mortem_processor.rb +18 -0
  107. data/lib/byebug/processors/script_processor.rb +49 -0
  108. data/lib/byebug/remote/client.rb +57 -0
  109. data/lib/byebug/remote/server.rb +47 -0
  110. data/lib/byebug/remote.rb +85 -0
  111. data/lib/byebug/runner.rb +198 -0
  112. data/lib/byebug/setting.rb +79 -0
  113. data/lib/byebug/settings/autoirb.rb +29 -0
  114. data/lib/byebug/settings/autolist.rb +29 -0
  115. data/lib/byebug/settings/autopry.rb +29 -0
  116. data/lib/byebug/settings/autosave.rb +17 -0
  117. data/lib/byebug/settings/basename.rb +16 -0
  118. data/lib/byebug/settings/callstyle.rb +20 -0
  119. data/lib/byebug/settings/fullpath.rb +16 -0
  120. data/lib/byebug/settings/histfile.rb +20 -0
  121. data/lib/byebug/settings/histsize.rb +20 -0
  122. data/lib/byebug/settings/linetrace.rb +22 -0
  123. data/lib/byebug/settings/listsize.rb +21 -0
  124. data/lib/byebug/settings/post_mortem.rb +27 -0
  125. data/lib/byebug/settings/savefile.rb +20 -0
  126. data/lib/byebug/settings/stack_on_error.rb +15 -0
  127. data/lib/byebug/settings/width.rb +20 -0
  128. data/lib/byebug/source_file_formatter.rb +71 -0
  129. data/lib/byebug/subcommands.rb +54 -0
  130. data/lib/byebug/version.rb +8 -0
  131. data/lib/byebug.rb +3 -0
  132. metadata +194 -0
@@ -0,0 +1,96 @@
1
+ #include "byebug.h"
2
+
3
+ /**
4
+ * A simple linked list containing locked threads, FIFO style.
5
+ */
6
+
7
+ typedef struct locked_thread_t
8
+ {
9
+ VALUE thread;
10
+ struct locked_thread_t *next;
11
+ } locked_thread_t;
12
+
13
+ static locked_thread_t *locked_head = NULL;
14
+ static locked_thread_t *locked_tail = NULL;
15
+
16
+ static int
17
+ is_in_locked(VALUE thread)
18
+ {
19
+ locked_thread_t *node;
20
+
21
+ if (!locked_head)
22
+ return 0;
23
+
24
+ for (node = locked_head; node != locked_tail; node = node->next)
25
+ if (node->thread == thread)
26
+ return 1;
27
+
28
+ return 0;
29
+ }
30
+
31
+ extern void
32
+ byebug_add_to_locked(VALUE thread)
33
+ {
34
+ locked_thread_t *node;
35
+
36
+ if (is_in_locked(thread))
37
+ return;
38
+
39
+ node = ALLOC(locked_thread_t);
40
+ node->thread = thread;
41
+ node->next = NULL;
42
+
43
+ if (locked_tail)
44
+ locked_tail->next = node;
45
+
46
+ locked_tail = node;
47
+
48
+ if (!locked_head)
49
+ locked_head = node;
50
+ }
51
+
52
+ extern VALUE
53
+ byebug_pop_from_locked()
54
+ {
55
+ VALUE thread;
56
+ locked_thread_t *node;
57
+
58
+ if (!locked_head)
59
+ return Qnil;
60
+
61
+ node = locked_head;
62
+ locked_head = locked_head->next;
63
+
64
+ if (locked_tail == node)
65
+ locked_tail = NULL;
66
+
67
+ thread = node->thread;
68
+ xfree(node);
69
+
70
+ return thread;
71
+ }
72
+
73
+ extern void
74
+ byebug_remove_from_locked(VALUE thread)
75
+ {
76
+ locked_thread_t *node;
77
+ locked_thread_t *next_node;
78
+
79
+ if (NIL_P(thread) || !locked_head || !is_in_locked(thread))
80
+ return;
81
+
82
+ if (locked_head->thread == thread)
83
+ {
84
+ byebug_pop_from_locked();
85
+ return;
86
+ }
87
+
88
+ for (node = locked_head; node != locked_tail; node = node->next)
89
+ if (node->next && node->next->thread == thread)
90
+ {
91
+ next_node = node->next;
92
+ node->next = next_node->next;
93
+ xfree(next_node);
94
+ return;
95
+ }
96
+ }
@@ -0,0 +1,241 @@
1
+ #include "byebug.h"
2
+
3
+ /* Threads table class */
4
+ static VALUE cThreadsTable;
5
+
6
+ /* If not Qnil, holds the next thread that must be run */
7
+ VALUE next_thread = Qnil;
8
+
9
+ /* To allow thread syncronization, we must stop threads when debugging */
10
+ static VALUE locker = Qnil;
11
+
12
+ static int
13
+ t_tbl_mark_keyvalue(st_data_t key, st_data_t value, st_data_t tbl)
14
+ {
15
+ UNUSED(tbl);
16
+
17
+ rb_gc_mark((VALUE)key);
18
+
19
+ if (!value)
20
+ return ST_CONTINUE;
21
+
22
+ rb_gc_mark((VALUE)value);
23
+
24
+ return ST_CONTINUE;
25
+ }
26
+
27
+ static void
28
+ t_tbl_mark(void *data)
29
+ {
30
+ threads_table_t *t_tbl = (threads_table_t *)data;
31
+ st_table *tbl = t_tbl->tbl;
32
+
33
+ st_foreach(tbl, t_tbl_mark_keyvalue, (st_data_t)tbl);
34
+ }
35
+
36
+ static void
37
+ t_tbl_free(void *data)
38
+ {
39
+ threads_table_t *t_tbl = (threads_table_t *)data;
40
+
41
+ st_free_table(t_tbl->tbl);
42
+ xfree(t_tbl);
43
+ }
44
+
45
+ /*
46
+ * Creates a numeric hash whose keys are the currently active threads and
47
+ * whose values are their associated contexts.
48
+ */
49
+ VALUE
50
+ create_threads_table(void)
51
+ {
52
+ threads_table_t *t_tbl;
53
+
54
+ t_tbl = ALLOC(threads_table_t);
55
+ t_tbl->tbl = st_init_numtable();
56
+ return Data_Wrap_Struct(cThreadsTable, t_tbl_mark, t_tbl_free, t_tbl);
57
+ }
58
+
59
+ /*
60
+ * Checks a single entry in the threads table.
61
+ *
62
+ * If it has no associated context or the key doesn't correspond to a living
63
+ * thread, the entry is removed from the thread's list.
64
+ */
65
+ static int
66
+ check_thread_i(st_data_t key, st_data_t value, st_data_t data)
67
+ {
68
+ UNUSED(data);
69
+
70
+ if (!value)
71
+ return ST_DELETE;
72
+
73
+ if (!is_living_thread((VALUE)key))
74
+ return ST_DELETE;
75
+
76
+ return ST_CONTINUE;
77
+ }
78
+
79
+ /*
80
+ * Checks whether a thread is either in the running or sleeping state.
81
+ */
82
+ int
83
+ is_living_thread(VALUE thread)
84
+ {
85
+ VALUE status = rb_funcall(thread, rb_intern("status"), 0);
86
+
87
+ if (NIL_P(status) || status == Qfalse)
88
+ return 0;
89
+
90
+ if (rb_str_cmp(status, rb_str_new2("run")) == 0
91
+ || rb_str_cmp(status, rb_str_new2("sleep")) == 0)
92
+ return 1;
93
+
94
+ return 0;
95
+ }
96
+
97
+ /*
98
+ * Checks threads table for dead/finished threads.
99
+ */
100
+ static void
101
+ cleanup_dead_threads(void)
102
+ {
103
+ threads_table_t *t_tbl;
104
+
105
+ Data_Get_Struct(threads, threads_table_t, t_tbl);
106
+ st_foreach(t_tbl->tbl, check_thread_i, 0);
107
+ }
108
+
109
+ /*
110
+ * Looks up a context in the threads table. If not present, it creates it.
111
+ */
112
+ void
113
+ thread_context_lookup(VALUE thread, VALUE *context)
114
+ {
115
+ threads_table_t *t_tbl;
116
+
117
+ Data_Get_Struct(threads, threads_table_t, t_tbl);
118
+
119
+ if (!st_lookup(t_tbl->tbl, thread, context) || !*context)
120
+ {
121
+ *context = byebug_context_create(thread);
122
+ st_insert(t_tbl->tbl, thread, *context);
123
+ }
124
+ }
125
+
126
+ /*
127
+ * Holds thread execution while another thread is active.
128
+ *
129
+ * Thanks to this, all threads are "frozen" while the user is typing commands.
130
+ */
131
+ void
132
+ acquire_lock(debug_context_t *dc)
133
+ {
134
+ while ((!NIL_P(locker) && locker != rb_thread_current())
135
+ || CTX_FL_TEST(dc, CTX_FL_SUSPEND))
136
+ {
137
+ byebug_add_to_locked(rb_thread_current());
138
+ rb_thread_stop();
139
+
140
+ if (CTX_FL_TEST(dc, CTX_FL_SUSPEND))
141
+ CTX_FL_SET(dc, CTX_FL_WAS_RUNNING);
142
+ }
143
+
144
+ locker = rb_thread_current();
145
+ }
146
+
147
+ /*
148
+ * Releases our global lock and passes execution on to another thread, either
149
+ * the thread specified by +next_thread+ or any other thread if +next_thread+
150
+ * is nil.
151
+ */
152
+ void
153
+ release_lock(void)
154
+ {
155
+ VALUE thread;
156
+
157
+ cleanup_dead_threads();
158
+
159
+ locker = Qnil;
160
+
161
+ if (NIL_P(next_thread))
162
+ thread = byebug_pop_from_locked();
163
+ else
164
+ {
165
+ byebug_remove_from_locked(next_thread);
166
+ thread = next_thread;
167
+ next_thread = Qnil;
168
+ }
169
+
170
+ if (!NIL_P(thread) && is_living_thread(thread))
171
+ rb_thread_run(thread);
172
+ }
173
+
174
+ /*
175
+ * call-seq:
176
+ * Byebug.unlock -> nil
177
+ *
178
+ * Unlocks global switch so other threads can run.
179
+ */
180
+ static VALUE
181
+ Unlock(VALUE self)
182
+ {
183
+ debug_context_t *dc;
184
+ VALUE context;
185
+
186
+ UNUSED(self);
187
+
188
+ thread_context_lookup(rb_thread_current(), &context);
189
+ Data_Get_Struct(context, debug_context_t, dc);
190
+
191
+ CTX_FL_SET(dc, CTX_FL_IGNORE);
192
+
193
+ release_lock();
194
+
195
+ return locker;
196
+ }
197
+
198
+ /*
199
+ * call-seq:
200
+ * Byebug.lock -> Thread.current
201
+ *
202
+ * Locks global switch to reserve execution to current thread exclusively.
203
+ */
204
+ static VALUE
205
+ Lock(VALUE self)
206
+ {
207
+ debug_context_t *dc;
208
+ VALUE context;
209
+
210
+ UNUSED(self);
211
+
212
+ if (!is_living_thread(rb_thread_current()))
213
+ rb_raise(rb_eRuntimeError, "Current thread is dead!");
214
+
215
+ thread_context_lookup(rb_thread_current(), &context);
216
+ Data_Get_Struct(context, debug_context_t, dc);
217
+
218
+ acquire_lock(dc);
219
+
220
+ CTX_FL_UNSET(dc, CTX_FL_IGNORE);
221
+
222
+ return locker;
223
+ }
224
+
225
+ /*
226
+ *
227
+ * Document-class: ThreadsTable
228
+ *
229
+ * == Sumary
230
+ *
231
+ * Hash table holding currently active threads and their associated contexts
232
+ */
233
+ void
234
+ Init_threads_table(VALUE mByebug)
235
+ {
236
+ cThreadsTable = rb_define_class_under(mByebug, "ThreadsTable", rb_cObject);
237
+ rb_undef_alloc_func(cThreadsTable);
238
+
239
+ rb_define_module_function(mByebug, "unlock", Unlock, 0);
240
+ rb_define_module_function(mByebug, "lock", Lock, 0);
241
+ }
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Main Container for all of Byebug's code
5
+ #
6
+ module Byebug
7
+ #
8
+ # Starts byebug, and stops at the first line of user's code.
9
+ #
10
+ def self.attach
11
+ unless started?
12
+ self.mode = :attached
13
+
14
+ start
15
+ run_init_script
16
+ end
17
+
18
+ current_context.step_out(3, true)
19
+ end
20
+
21
+ def self.spawn(host = "localhost", port = nil)
22
+ require_relative "core"
23
+
24
+ self.wait_connection = true
25
+ start_server(host, port || PORT)
26
+ end
27
+ end
28
+
29
+ #
30
+ # Adds a `byebug` method to the Kernel module.
31
+ #
32
+ # Dropping a `byebug` call anywhere in your code, you get a debug prompt.
33
+ #
34
+ module Kernel
35
+ def byebug
36
+ require_relative "core"
37
+
38
+ Byebug.attach unless Byebug.mode == :off
39
+ end
40
+
41
+ def remote_byebug(host = "localhost", port = nil)
42
+ Byebug.spawn(host, port)
43
+
44
+ Byebug.attach
45
+ end
46
+
47
+ alias debugger byebug
48
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Byebug
4
+ #
5
+ # Implements breakpoints
6
+ #
7
+ class Breakpoint
8
+ #
9
+ # First breakpoint, in order of creation
10
+ #
11
+ def self.first
12
+ Byebug.breakpoints.first
13
+ end
14
+
15
+ #
16
+ # Last breakpoint, in order of creation
17
+ #
18
+ def self.last
19
+ Byebug.breakpoints.last
20
+ end
21
+
22
+ #
23
+ # Adds a new breakpoint
24
+ #
25
+ # @param [String] file
26
+ # @param [Fixnum] line
27
+ # @param [String] expr
28
+ #
29
+ def self.add(file, line, expr = nil)
30
+ breakpoint = Breakpoint.new(file, line, expr)
31
+ Byebug.breakpoints << breakpoint
32
+ breakpoint
33
+ end
34
+
35
+ #
36
+ # Removes a breakpoint
37
+ #
38
+ # @param id [integer] breakpoint number
39
+ #
40
+ def self.remove(id)
41
+ Byebug.breakpoints.reject! { |b| b.id == id }
42
+ end
43
+
44
+ #
45
+ # Returns an array of line numbers in file named +filename+ where
46
+ # breakpoints could be set. The list will contain an entry for each
47
+ # distinct line event call so it is possible (and possibly useful) for a
48
+ # line number appear more than once.
49
+ #
50
+ # @param filename [String] File name to inspect for possible breakpoints
51
+ #
52
+ def self.potential_lines(filename)
53
+ name = "#{Time.new.to_i}_#{rand(2**31)}"
54
+ iseq = RubyVM::InstructionSequence.compile(File.read(filename), name)
55
+
56
+ potential_lines_with_trace_points(iseq, {})
57
+ end
58
+
59
+ def self.potential_lines_with_trace_points(iseq, lines)
60
+ iseq.trace_points.each { |(line, _)| lines[line] = true }
61
+ iseq.each_child do |child|
62
+ potential_lines_with_trace_points(child, lines)
63
+ end
64
+
65
+ lines.keys.sort
66
+ end
67
+
68
+ private_class_method :potential_lines_with_trace_points
69
+
70
+ #
71
+ # Returns true if a breakpoint could be set in line number +lineno+ in file
72
+ # name +filename.
73
+ #
74
+ def self.potential_line?(filename, lineno)
75
+ potential_lines(filename).member?(lineno)
76
+ end
77
+
78
+ #
79
+ # True if there's no breakpoints
80
+ #
81
+ def self.none?
82
+ Byebug.breakpoints.empty?
83
+ end
84
+
85
+ #
86
+ # Prints all information associated to the breakpoint
87
+ #
88
+ def inspect
89
+ meths = %w[id pos source expr hit_condition hit_count hit_value enabled?]
90
+ values = meths.map { |field| "#{field}: #{send(field)}" }.join(", ")
91
+ "#<Byebug::Breakpoint #{values}>"
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require_relative "helpers/string"
5
+
6
+ module Byebug
7
+ #
8
+ # Parent class of all byebug commands.
9
+ #
10
+ # Subclass it and name the subclass ending with the word Command to implement
11
+ # your own custom command.
12
+ #
13
+ # @example Define a custom command
14
+ #
15
+ # class MyCustomCommand < Command
16
+ # def self.regexp
17
+ # /custom_regexp/
18
+ # end
19
+ #
20
+ # def self.description
21
+ # "Custom long desc"
22
+ # end
23
+ #
24
+ # def.short_description
25
+ # "Custom short desc"
26
+ # end
27
+ #
28
+ # def execute
29
+ # # My command's implementation
30
+ # end
31
+ # end
32
+ #
33
+ class Command
34
+ extend Forwardable
35
+
36
+ attr_reader :processor
37
+
38
+ def initialize(processor, input = self.class.to_s)
39
+ @processor = processor
40
+ @match = match(input)
41
+ end
42
+
43
+ def context
44
+ @context ||= processor.context
45
+ end
46
+
47
+ def frame
48
+ @frame ||= context.frame
49
+ end
50
+
51
+ def arguments
52
+ @match[0].split(" ").drop(1).join(" ")
53
+ end
54
+
55
+ def_delegators "self.class", :help, :match
56
+
57
+ def_delegator "processor.printer", :print, :pr
58
+ def_delegator "processor.printer", :print_collection, :prc
59
+ def_delegator "processor.printer", :print_variables, :prv
60
+
61
+ def_delegators "processor.interface", :errmsg, :puts, :print, :confirm
62
+
63
+ class << self
64
+ include Helpers::StringHelper
65
+
66
+ #
67
+ # Special methods to allow command filtering in processors
68
+ #
69
+ attr_accessor :allow_in_control, :allow_in_post_mortem
70
+
71
+ attr_writer :always_run
72
+
73
+ def always_run
74
+ @always_run ||= 0
75
+ end
76
+
77
+ #
78
+ # Name of the command, as executed by the user.
79
+ #
80
+ def to_s
81
+ name
82
+ .split("::")
83
+ .map { |n| n.gsub(/Command$/, "").downcase if /Command$/.match?(n) }
84
+ .compact
85
+ .join(" ")
86
+ end
87
+
88
+ def columnize(width)
89
+ format(
90
+ " %-<name>#{width}s -- %<description>s\n",
91
+ name: to_s,
92
+ description: short_description
93
+ )
94
+ end
95
+
96
+ #
97
+ # Default help text for a command.
98
+ #
99
+ def help
100
+ prettify(description)
101
+ end
102
+
103
+ #
104
+ # Command's regexp match against an input
105
+ #
106
+ def match(input)
107
+ regexp.match(input)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "errors"
4
+
5
+ module Byebug
6
+ #
7
+ # Holds an array of subcommands for a command
8
+ #
9
+ class CommandList
10
+ include Enumerable
11
+
12
+ def initialize(commands)
13
+ @commands = commands.sort_by(&:to_s)
14
+ end
15
+
16
+ def match(input)
17
+ find { |cmd| cmd.match(input) }
18
+ end
19
+
20
+ def each
21
+ @commands.each { |cmd| yield(cmd) }
22
+ end
23
+
24
+ def to_s
25
+ "\n" + map { |cmd| cmd.columnize(width) }.join + "\n"
26
+ end
27
+
28
+ private
29
+
30
+ def width
31
+ @width ||= map(&:to_s).max_by(&:size).size
32
+ end
33
+ end
34
+ end