byebug 3.5.1 → 4.0.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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.rubocop.yml +18 -1
  4. data/.travis.yml +21 -1
  5. data/CHANGELOG.md +356 -308
  6. data/CONTRIBUTING.md +31 -15
  7. data/GUIDE.md +859 -475
  8. data/Gemfile +8 -10
  9. data/LICENSE +1 -1
  10. data/README.md +41 -45
  11. data/Rakefile +30 -28
  12. data/byebug.gemspec +18 -18
  13. data/ext/byebug/breakpoint.c +88 -75
  14. data/ext/byebug/byebug.c +253 -252
  15. data/ext/byebug/byebug.h +53 -53
  16. data/ext/byebug/context.c +188 -159
  17. data/ext/byebug/extconf.rb +9 -6
  18. data/ext/byebug/locker.c +53 -11
  19. data/ext/byebug/threads.c +137 -39
  20. data/lib/byebug/attacher.rb +7 -2
  21. data/lib/byebug/breakpoint.rb +30 -0
  22. data/lib/byebug/command.rb +36 -32
  23. data/lib/byebug/commands/break.rb +49 -48
  24. data/lib/byebug/commands/catch.rb +64 -0
  25. data/lib/byebug/commands/condition.rb +13 -9
  26. data/lib/byebug/commands/continue.rb +8 -4
  27. data/lib/byebug/commands/delete.rb +10 -4
  28. data/lib/byebug/commands/display.rb +33 -25
  29. data/lib/byebug/commands/edit.rb +18 -13
  30. data/lib/byebug/commands/enable_disable.rb +26 -24
  31. data/lib/byebug/commands/eval.rb +77 -35
  32. data/lib/byebug/commands/finish.rb +9 -5
  33. data/lib/byebug/commands/frame.rb +66 -125
  34. data/lib/byebug/commands/help.rb +14 -21
  35. data/lib/byebug/commands/history.rb +5 -1
  36. data/lib/byebug/commands/info.rb +41 -106
  37. data/lib/byebug/commands/interrupt.rb +6 -2
  38. data/lib/byebug/commands/irb.rb +5 -2
  39. data/lib/byebug/commands/kill.rb +6 -2
  40. data/lib/byebug/commands/list.rb +21 -14
  41. data/lib/byebug/commands/method.rb +17 -9
  42. data/lib/byebug/commands/pry.rb +13 -3
  43. data/lib/byebug/commands/quit.rb +10 -5
  44. data/lib/byebug/commands/restart.rb +12 -19
  45. data/lib/byebug/commands/save.rb +10 -6
  46. data/lib/byebug/commands/set.rb +15 -14
  47. data/lib/byebug/commands/show.rb +8 -8
  48. data/lib/byebug/commands/source.rb +14 -8
  49. data/lib/byebug/commands/stepping.rb +15 -29
  50. data/lib/byebug/commands/threads.rb +73 -49
  51. data/lib/byebug/commands/tracevar.rb +56 -0
  52. data/lib/byebug/commands/undisplay.rb +8 -4
  53. data/lib/byebug/commands/untracevar.rb +38 -0
  54. data/lib/byebug/commands/var.rb +107 -0
  55. data/lib/byebug/context.rb +78 -42
  56. data/lib/byebug/core.rb +78 -40
  57. data/lib/byebug/helper.rb +58 -42
  58. data/lib/byebug/history.rb +12 -1
  59. data/lib/byebug/interface.rb +91 -11
  60. data/lib/byebug/interfaces/local_interface.rb +12 -19
  61. data/lib/byebug/interfaces/remote_interface.rb +12 -15
  62. data/lib/byebug/interfaces/script_interface.rb +14 -18
  63. data/lib/byebug/interfaces/test_interface.rb +54 -0
  64. data/lib/byebug/printers/base.rb +64 -0
  65. data/lib/byebug/printers/plain.rb +53 -0
  66. data/lib/byebug/processor.rb +20 -1
  67. data/lib/byebug/processors/command_processor.rb +57 -172
  68. data/lib/byebug/processors/control_command_processor.rb +16 -43
  69. data/lib/byebug/remote.rb +13 -7
  70. data/lib/byebug/runner.rb +102 -54
  71. data/lib/byebug/setting.rb +45 -68
  72. data/lib/byebug/settings/autoeval.rb +2 -0
  73. data/lib/byebug/settings/autoirb.rb +3 -0
  74. data/lib/byebug/settings/autolist.rb +3 -0
  75. data/lib/byebug/settings/autosave.rb +2 -0
  76. data/lib/byebug/settings/basename.rb +2 -0
  77. data/lib/byebug/settings/callstyle.rb +2 -0
  78. data/lib/byebug/settings/fullpath.rb +2 -0
  79. data/lib/byebug/settings/histfile.rb +2 -0
  80. data/lib/byebug/settings/histsize.rb +2 -0
  81. data/lib/byebug/settings/linetrace.rb +2 -0
  82. data/lib/byebug/settings/listsize.rb +2 -0
  83. data/lib/byebug/settings/post_mortem.rb +7 -2
  84. data/lib/byebug/settings/stack_on_error.rb +2 -0
  85. data/lib/byebug/settings/verbose.rb +2 -0
  86. data/lib/byebug/settings/width.rb +2 -0
  87. data/lib/byebug/state.rb +12 -0
  88. data/lib/byebug/states/control_state.rb +26 -0
  89. data/lib/byebug/states/regular_state.rb +178 -0
  90. data/lib/byebug/version.rb +1 -1
  91. metadata +24 -109
  92. data/lib/byebug/commands/catchpoint.rb +0 -53
  93. data/lib/byebug/commands/reload.rb +0 -29
  94. data/lib/byebug/commands/trace.rb +0 -50
  95. data/lib/byebug/commands/variables.rb +0 -206
  96. data/lib/byebug/options.rb +0 -46
  97. data/lib/byebug/settings/autoreload.rb +0 -12
  98. data/lib/byebug/settings/forcestep.rb +0 -14
  99. data/lib/byebug/settings/testing.rb +0 -12
  100. data/lib/byebug/settings/tracing_plus.rb +0 -11
  101. data/test/commands/break_test.rb +0 -364
  102. data/test/commands/condition_test.rb +0 -85
  103. data/test/commands/continue_test.rb +0 -47
  104. data/test/commands/delete_test.rb +0 -26
  105. data/test/commands/display_test.rb +0 -37
  106. data/test/commands/edit_test.rb +0 -52
  107. data/test/commands/eval_test.rb +0 -89
  108. data/test/commands/finish_test.rb +0 -74
  109. data/test/commands/frame_test.rb +0 -223
  110. data/test/commands/help_test.rb +0 -66
  111. data/test/commands/history_test.rb +0 -61
  112. data/test/commands/info_test.rb +0 -238
  113. data/test/commands/interrupt_test.rb +0 -45
  114. data/test/commands/irb_test.rb +0 -28
  115. data/test/commands/kill_test.rb +0 -50
  116. data/test/commands/list_test.rb +0 -174
  117. data/test/commands/method_test.rb +0 -52
  118. data/test/commands/post_mortem_test.rb +0 -71
  119. data/test/commands/pry_test.rb +0 -26
  120. data/test/commands/quit_test.rb +0 -53
  121. data/test/commands/reload_test.rb +0 -39
  122. data/test/commands/restart_test.rb +0 -46
  123. data/test/commands/save_test.rb +0 -67
  124. data/test/commands/set_test.rb +0 -140
  125. data/test/commands/show_test.rb +0 -76
  126. data/test/commands/source_test.rb +0 -46
  127. data/test/commands/stepping_test.rb +0 -192
  128. data/test/commands/thread_test.rb +0 -164
  129. data/test/commands/trace_test.rb +0 -71
  130. data/test/commands/undisplay_test.rb +0 -75
  131. data/test/commands/variables_test.rb +0 -105
  132. data/test/debugger_alias_test.rb +0 -7
  133. data/test/runner_test.rb +0 -150
  134. data/test/support/matchers.rb +0 -65
  135. data/test/support/test_interface.rb +0 -59
  136. data/test/support/utils.rb +0 -122
  137. data/test/test_helper.rb +0 -58
@@ -5,13 +5,16 @@ end
5
5
 
6
6
  require 'mkmf'
7
7
 
8
- RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
8
+ makefile_config = RbConfig::MAKEFILE_CONFIG
9
9
 
10
- if RbConfig::MAKEFILE_CONFIG['CC'] =~ /gcc/
11
- $CFLAGS ||= ''
12
- $CFLAGS += ' -Wall -Werror -Wno-unused-parameter'
13
- $CFLAGS += ' -gdwarf-2 -g3 -O0' if ENV['debug']
10
+ makefile_config['CC'] = ENV['CC'] if ENV['CC']
11
+
12
+ makefile_config['CFLAGS'] << ' -Wall -Werror'
13
+ makefile_config['CFLAGS'] << ' -gdwarf-2 -g3 -O0' if ENV['debug']
14
+
15
+ if makefile_config['CC'] =~ /clang/
16
+ makefile_config['CFLAGS'] << ' -Wno-unknown-warning-option'
14
17
  end
15
18
 
16
19
  dir_config('ruby')
17
- create_makefile('byebug/byebug')
20
+ with_cflags(makefile_config['CFLAGS']) { create_makefile('byebug/byebug') }
@@ -1,6 +1,11 @@
1
1
  #include <byebug.h>
2
2
 
3
- typedef struct locked_thread_t {
3
+ /**
4
+ * A simple linked list containing locked threads, FIFO style.
5
+ */
6
+
7
+ typedef struct locked_thread_t
8
+ {
4
9
  VALUE thread;
5
10
  struct locked_thread_t *next;
6
11
  } locked_thread_t;
@@ -13,12 +18,13 @@ is_in_locked(VALUE thread)
13
18
  {
14
19
  locked_thread_t *node;
15
20
 
16
- if (!locked_head) return 0;
21
+ if (!locked_head)
22
+ return 0;
17
23
 
18
24
  for (node = locked_head; node != locked_tail; node = node->next)
19
- {
20
- if (node->thread == thread) return 1;
21
- }
25
+ if (node->thread == thread)
26
+ return 1;
27
+
22
28
  return 0;
23
29
  }
24
30
 
@@ -27,28 +33,64 @@ add_to_locked(VALUE thread)
27
33
  {
28
34
  locked_thread_t *node;
29
35
 
30
- if (is_in_locked(thread)) return;
36
+ if (is_in_locked(thread))
37
+ return;
31
38
 
32
39
  node = ALLOC(locked_thread_t);
33
40
  node->thread = thread;
34
41
  node->next = NULL;
35
- if (locked_tail) locked_tail->next = node;
42
+
43
+ if (locked_tail)
44
+ locked_tail->next = node;
45
+
36
46
  locked_tail = node;
37
- if (!locked_head) locked_head = node;
47
+
48
+ if (!locked_head)
49
+ locked_head = node;
38
50
  }
39
51
 
40
52
  extern VALUE
41
- remove_from_locked()
53
+ pop_from_locked()
42
54
  {
43
55
  VALUE thread;
44
56
  locked_thread_t *node;
45
57
 
46
- if (locked_head == NULL) return Qnil;
58
+ if (!locked_head)
59
+ return Qnil;
47
60
 
48
61
  node = locked_head;
49
62
  locked_head = locked_head->next;
50
- if (locked_tail == node) locked_tail = NULL;
63
+
64
+ if (locked_tail == node)
65
+ locked_tail = NULL;
66
+
51
67
  thread = node->thread;
52
68
  xfree(node);
69
+
53
70
  return thread;
54
71
  }
72
+
73
+ extern void
74
+ 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
+ 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
+ }
@@ -3,31 +3,41 @@
3
3
  /* Threads table class */
4
4
  static VALUE cThreadsTable;
5
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
+ VALUE locker = Qnil;
11
+
6
12
  static int
7
13
  t_tbl_mark_keyvalue(st_data_t key, st_data_t value, st_data_t tbl)
8
14
  {
9
- VALUE thread = (VALUE)key;
15
+ UNUSED(tbl);
10
16
 
11
- if (!value) return ST_CONTINUE;
17
+ rb_gc_mark((VALUE) key);
12
18
 
13
- rb_gc_mark((VALUE)value);
14
- rb_gc_mark(thread);
19
+ if (!value)
20
+ return ST_CONTINUE;
21
+
22
+ rb_gc_mark((VALUE) value);
15
23
 
16
24
  return ST_CONTINUE;
17
25
  }
18
26
 
19
27
  static void
20
- t_tbl_mark(void* data)
28
+ t_tbl_mark(void *data)
21
29
  {
22
- threads_table_t *t_tbl = (threads_table_t *)data;
30
+ threads_table_t *t_tbl = (threads_table_t *) data;
23
31
  st_table *tbl = t_tbl->tbl;
24
- st_foreach(tbl, t_tbl_mark_keyvalue, (st_data_t)tbl);
32
+
33
+ st_foreach(tbl, t_tbl_mark_keyvalue, (st_data_t) tbl);
25
34
  }
26
35
 
27
36
  static void
28
- t_tbl_free(void* data)
37
+ t_tbl_free(void *data)
29
38
  {
30
- threads_table_t *t_tbl = (threads_table_t*)data;
39
+ threads_table_t *t_tbl = (threads_table_t *) data;
40
+
31
41
  st_free_table(t_tbl->tbl);
32
42
  xfree(t_tbl);
33
43
  }
@@ -46,16 +56,6 @@ create_threads_table(void)
46
56
  return Data_Wrap_Struct(cThreadsTable, t_tbl_mark, t_tbl_free, t_tbl);
47
57
  }
48
58
 
49
- /*
50
- * The condition to be in the thread's table is to be either running or
51
- * sleeping, namely, to be Thread#alive?
52
- */
53
- static int
54
- is_living_thread(VALUE thread)
55
- {
56
- return rb_funcall(thread, rb_intern("alive?"), 0) == Qtrue;
57
- }
58
-
59
59
  /*
60
60
  * Checks a single entry in the threads table.
61
61
  *
@@ -63,20 +63,42 @@ is_living_thread(VALUE thread)
63
63
  * thread, the entry is removed from the thread's list.
64
64
  */
65
65
  static int
66
- check_thread_i(st_data_t key, st_data_t value, st_data_t dummy)
66
+ check_thread_i(st_data_t key, st_data_t value, st_data_t data)
67
67
  {
68
- if (!value) return ST_DELETE;
68
+ UNUSED(data);
69
69
 
70
- if (!is_living_thread((VALUE)key)) return ST_DELETE;
70
+ if (!value)
71
+ return ST_DELETE;
72
+
73
+ if (!is_living_thread((VALUE) key))
74
+ return ST_DELETE;
71
75
 
72
76
  return ST_CONTINUE;
73
77
  }
74
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
+
75
97
  /*
76
98
  * Checks threads table for dead/finished threads.
77
99
  */
78
100
  void
79
- check_threads_table(void)
101
+ cleanup_dead_threads(void)
80
102
  {
81
103
  threads_table_t *t_tbl;
82
104
 
@@ -84,12 +106,16 @@ check_threads_table(void)
84
106
  st_foreach(t_tbl->tbl, check_thread_i, 0);
85
107
  }
86
108
 
109
+ /*
110
+ * Looks up a context in the threads table. If not present, it creates it.
111
+ */
87
112
  void
88
- thread_context_lookup(VALUE thread, VALUE *context)
113
+ thread_context_lookup(VALUE thread, VALUE * context)
89
114
  {
90
115
  threads_table_t *t_tbl;
91
116
 
92
117
  Data_Get_Struct(threads, threads_table_t, t_tbl);
118
+
93
119
  if (!st_lookup(t_tbl->tbl, thread, context) || !*context)
94
120
  {
95
121
  *context = context_create(thread);
@@ -97,26 +123,95 @@ thread_context_lookup(VALUE thread, VALUE *context)
97
123
  }
98
124
  }
99
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
+ */
100
131
  void
101
- halt_while_other_thread_is_active(debug_context_t *dc)
132
+ acquire_lock(debug_context_t * dc)
102
133
  {
103
- while (1)
134
+ while ((!NIL_P(locker) && locker != rb_thread_current())
135
+ || CTX_FL_TEST(dc, CTX_FL_SUSPEND))
104
136
  {
105
- /* halt execution of current thread if debugger is activated in another */
106
- while (locker != Qnil && locker != rb_thread_current())
107
- {
108
- add_to_locked(rb_thread_current());
109
- rb_thread_stop();
110
- }
111
-
112
- /* stop the current thread if it's marked as suspended */
113
- if (CTX_FL_TEST(dc, CTX_FL_SUSPEND) && locker != rb_thread_current())
114
- {
137
+ add_to_locked(rb_thread_current());
138
+ rb_thread_stop();
139
+
140
+ if (CTX_FL_TEST(dc, CTX_FL_SUSPEND))
115
141
  CTX_FL_SET(dc, CTX_FL_WAS_RUNNING);
116
- rb_thread_stop();
117
- }
118
- else break;
119
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 = pop_from_locked();
163
+ else
164
+ {
165
+ remove_from_locked(next_thread);
166
+ thread = next_thread;
167
+ }
168
+
169
+ if (thread == next_thread)
170
+ next_thread = Qnil;
171
+
172
+ if (!NIL_P(thread) && is_living_thread(thread))
173
+ rb_thread_run(thread);
174
+ }
175
+
176
+ /*
177
+ * call-seq:
178
+ * Byebug.unlock -> nil
179
+ *
180
+ * Unlocks global switch so other threads can run.
181
+ */
182
+ static VALUE
183
+ Unlock(VALUE self)
184
+ {
185
+ UNUSED(self);
186
+
187
+ release_lock();
188
+
189
+ return locker;
190
+ }
191
+
192
+ /*
193
+ * call-seq:
194
+ * Byebug.lock -> Thread.current
195
+ *
196
+ * Locks global switch to reserve execution to current thread exclusively.
197
+ */
198
+ static VALUE
199
+ Lock(VALUE self)
200
+ {
201
+ debug_context_t *dc;
202
+ VALUE context;
203
+
204
+ UNUSED(self);
205
+
206
+ if (!is_living_thread(rb_thread_current()))
207
+ rb_raise(rb_eRuntimeError, "Current thread is dead!");
208
+
209
+ thread_context_lookup(rb_thread_current(), &context);
210
+ Data_Get_Struct(context, debug_context_t, dc);
211
+
212
+ acquire_lock(dc);
213
+
214
+ return locker;
120
215
  }
121
216
 
122
217
  /*
@@ -131,4 +226,7 @@ void
131
226
  Init_threads_table(VALUE mByebug)
132
227
  {
133
228
  cThreadsTable = rb_define_class_under(mByebug, "ThreadsTable", rb_cObject);
229
+
230
+ rb_define_module_function(mByebug, "unlock", Unlock, 0);
231
+ rb_define_module_function(mByebug, "lock", Lock, 0);
134
232
  }
@@ -1,12 +1,17 @@
1
+ #
2
+ # Main Container for all of Byebug's code
3
+ #
1
4
  module Byebug
2
5
  #
3
6
  # Enters byebug right before (or right after if _before_ is false) return
4
7
  # events occur. Before entering byebug the init script is read.
5
8
  #
6
9
  def self.attach(steps_out, before)
10
+ setup_cmd_line_args
11
+
7
12
  start
8
- self.debugged_program = $PROGRAM_NAME
9
- run_init_script(StringIO.new)
13
+ run_init_script
14
+
10
15
  current_context.step_out(steps_out, before)
11
16
  end
12
17
  end
@@ -39,6 +39,36 @@ module Byebug
39
39
  Byebug.breakpoints.reject! { |b| b.id == id }
40
40
  end
41
41
 
42
+ #
43
+ # Returns an array of line numbers in file named +filename+ where
44
+ # breakpoints could be set. The list will contain an entry for each
45
+ # distinct line event call so it is possible (and possibly useful) for a
46
+ # line number appear more than once.
47
+ #
48
+ # @param filename [String] File name to inspect for possible breakpoints
49
+ #
50
+ def self.potential_lines(filename)
51
+ name, lines = "#{Time.new.to_i}_#{rand(2**31)}", {}
52
+ iseq = RubyVM::InstructionSequence.compile(File.read(filename), name)
53
+
54
+ iseq.disasm.each_line do |line|
55
+ res = /^\d+ (?<insn>\w+)\s+.+\(\s*(?<lineno>\d+)\)$/.match(line)
56
+ next unless res && res[:insn] == 'trace'
57
+
58
+ lines[res[:lineno].to_i] = true
59
+ end
60
+
61
+ lines.keys
62
+ end
63
+
64
+ #
65
+ # Returns true if a breakpoint could be set in line number +lineno+ in file
66
+ # name +filename.
67
+ #
68
+ def self.potential_line?(filename, lineno)
69
+ potential_lines(filename).member?(lineno)
70
+ end
71
+
42
72
  #
43
73
  # True if there's no breakpoints
44
74
  #
@@ -9,6 +9,11 @@ module Byebug
9
9
  # Subclasses need to implement a `regexp` and an `execute` command.
10
10
  #
11
11
  class Command
12
+ extend Forwardable
13
+
14
+ include ParseFunctions
15
+ include FileFunctions
16
+
12
17
  Subcmd = Struct.new(:name, :min, :help)
13
18
 
14
19
  def initialize(state)
@@ -19,36 +24,49 @@ module Byebug
19
24
  @match = regexp.match(input)
20
25
  end
21
26
 
22
- protected
27
+ def_delegator :"Byebug.printer", :print, :pr
28
+ def_delegator :"Byebug.printer", :print_collection, :prc
29
+ def_delegator :"Byebug.printer", :print_variables, :prv
23
30
 
24
- extend Forwardable
25
- def_delegators :@state, :errmsg, :puts
31
+ protected
26
32
 
27
- def confirm(msg)
28
- @state.confirm(msg) == 'y'
29
- end
33
+ def_delegators :@state, :errmsg, :puts, :print, :confirm
30
34
 
35
+ #
36
+ # Evaluates a string containing Ruby code, using binding +b+. In case of
37
+ # error full stack trace and error are printed.
38
+ #
31
39
  def bb_eval(str, b = get_binding)
32
- eval(str, b)
40
+ b.eval(str)
33
41
  rescue StandardError, ScriptError => e
34
- at = eval('Thread.current.backtrace_locations', b)
35
- puts "#{at.shift}: #{e.class} Exception(#{e.message})"
36
- at.each { |path| puts "\tfrom #{path}" }
42
+ at = e.backtrace
43
+ locations = []
44
+ locations << "#{at.shift}: #{e.class} Exception(#{e.message})"
45
+ locations += at.map { |path| "\tfrom #{path}" }
46
+
47
+ errmsg(pr('eval.exception', text_message: locations.join("\n")))
37
48
  nil
38
49
  end
39
50
 
51
+ #
52
+ # Evaluates a string containing Ruby code, using binding +b+. In case of
53
+ # error, an error message with the exception is printed.
54
+ #
40
55
  def bb_warning_eval(str, b = get_binding)
41
- eval(str, b)
56
+ b.eval(str)
42
57
  rescue StandardError, ScriptError => e
43
- puts "#{e.class} Exception: #{e.message}"
58
+ text_message = "#{e.class} Exception: #{e.message}"
59
+ errmsg(pr('eval.exception', text_message: text_message))
44
60
  nil
45
61
  end
46
62
 
47
- def get_binding(pos = @state.frame_pos)
63
+ def get_binding(pos = @state.frame)
48
64
  @state.context ? @state.context.frame_binding(pos) : TOPLEVEL_BINDING
49
65
  end
50
66
 
51
67
  class << self
68
+ include StringFunctions
69
+
52
70
  attr_accessor :allow_in_control
53
71
  attr_writer :allow_in_post_mortem, :always_run
54
72
 
@@ -60,13 +78,11 @@ module Byebug
60
78
  @always_run ||= 0
61
79
  end
62
80
 
63
- def help(args = nil)
64
- if args && args[1]
65
- output = format_subcmd(args[1])
66
- else
67
- output = description.gsub(/^ +/, '') + "\n"
68
- output += format_subcmds if defined? self::Subcommands
69
- end
81
+ def help(subcmd = nil)
82
+ return format_subcmd(subcmd) if subcmd
83
+
84
+ output = description
85
+ output += format_subcmds if defined? self::Subcommands
70
86
  output
71
87
  end
72
88
 
@@ -106,18 +122,6 @@ module Byebug
106
122
  def inherited(klass)
107
123
  commands << klass
108
124
  end
109
-
110
- def load_commands
111
- Dir.glob(File.expand_path('../commands/*.rb', __FILE__)).each do |file|
112
- require file
113
- end
114
-
115
- Byebug.constants.grep(/Functions$/).map do |name|
116
- include Byebug.const_get(name)
117
- end
118
- end
119
125
  end
120
126
  end
121
-
122
- Command.load_commands
123
127
  end