byebug 3.5.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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