byebug 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +9 -0
- data/CONTRIBUTING.md +13 -1
- data/GUIDE.md +181 -1
- data/README.md +67 -211
- data/Rakefile +1 -0
- data/bin/byebug +1 -8
- data/ext/byebug/byebug.c +66 -25
- data/ext/byebug/context.c +16 -20
- data/ext/byebug/extconf.rb +2 -1
- data/lib/byebug.rb +16 -9
- data/lib/byebug/command.rb +3 -3
- data/lib/byebug/commands/condition.rb +2 -2
- data/lib/byebug/commands/edit.rb +12 -9
- data/lib/byebug/commands/eval.rb +0 -16
- data/lib/byebug/commands/frame.rb +7 -17
- data/lib/byebug/commands/info.rb +2 -9
- data/lib/byebug/commands/list.rb +1 -1
- data/lib/byebug/commands/reload.rb +11 -0
- data/lib/byebug/commands/repl.rb +3 -6
- data/lib/byebug/commands/set.rb +5 -5
- data/lib/byebug/commands/show.rb +5 -0
- data/lib/byebug/commands/threads.rb +4 -4
- data/lib/byebug/commands/trace.rb +2 -1
- data/lib/byebug/context.rb +14 -5
- data/lib/byebug/interface.rb +1 -1
- data/lib/byebug/processor.rb +1 -1
- data/lib/byebug/remote.rb +1 -24
- data/lib/byebug/version.rb +1 -1
- data/old_doc/byebug.1 +0 -3
- data/old_doc/byebug.texi +2 -3
- data/test/breakpoints_test.rb +75 -52
- data/test/conditions_test.rb +2 -3
- data/test/continue_test.rb +6 -0
- data/test/edit_test.rb +3 -3
- data/test/eval_test.rb +14 -5
- data/test/examples/breakpoint.rb +4 -13
- data/test/examples/breakpoint_deep.rb +1 -21
- data/test/examples/conditions.rb +1 -1
- data/test/examples/continue.rb +2 -1
- data/test/examples/edit.rb +1 -0
- data/test/examples/eval.rb +1 -11
- data/test/examples/finish.rb +0 -17
- data/test/examples/frame.rb +2 -26
- data/test/examples/frame_deep.rb +0 -19
- data/test/examples/help.rb +0 -1
- data/test/examples/info.rb +4 -36
- data/test/examples/kill.rb +1 -1
- data/test/examples/list.rb +1 -1
- data/test/examples/method.rb +2 -13
- data/test/examples/post_mortem.rb +1 -16
- data/test/examples/quit.rb +1 -1
- data/test/examples/reload.rb +1 -1
- data/test/examples/restart.rb +1 -1
- data/test/examples/show.rb +0 -1
- data/test/examples/stepping.rb +2 -19
- data/test/examples/thread.rb +0 -27
- data/test/examples/variables.rb +0 -22
- data/test/finish_test.rb +22 -6
- data/test/frame_test.rb +89 -56
- data/test/info_test.rb +71 -46
- data/test/kill_test.rb +6 -1
- data/test/list_test.rb +1 -2
- data/test/method_test.rb +32 -13
- data/test/post_mortem_test.rb +34 -21
- data/test/quit_test.rb +0 -1
- data/test/restart_test.rb +6 -0
- data/test/set_test.rb +1 -1
- data/test/show_test.rb +17 -17
- data/test/source_test.rb +2 -3
- data/test/stepping_test.rb +31 -7
- data/test/support/test_dsl.rb +11 -1
- data/test/test_helper.rb +9 -0
- data/test/thread_test.rb +57 -23
- data/test/trace_test.rb +0 -1
- data/test/variables_test.rb +36 -17
- metadata +3 -9
- data/test/examples/breakpoint2.rb +0 -7
- data/test/examples/jump.rb +0 -14
- data/test/examples/set_annotate.rb +0 -12
data/Rakefile
CHANGED
data/bin/byebug
CHANGED
@@ -62,9 +62,8 @@ require File.dirname(__FILE__) + "/../lib/byebug"
|
|
62
62
|
|
63
63
|
def debug_program(options)
|
64
64
|
# Make sure Ruby script syntax checks okay.
|
65
|
-
# Otherwise we get a load message that looks like byebug has a problem.
|
66
65
|
output = `ruby -c "#{Byebug::PROG_SCRIPT}" 2>&1`
|
67
|
-
if $?.exitstatus != 0
|
66
|
+
if $?.exitstatus != 0
|
68
67
|
puts output
|
69
68
|
exit $?.exitstatus
|
70
69
|
end
|
@@ -96,7 +95,6 @@ options = OpenStruct.new(
|
|
96
95
|
'script' => nil,
|
97
96
|
'stop' => true,
|
98
97
|
'tracing' => false,
|
99
|
-
'verbose_long' => false
|
100
98
|
)
|
101
99
|
|
102
100
|
def process_options(options)
|
@@ -158,10 +156,6 @@ EOB
|
|
158
156
|
puts "byebug #{Byebug::VERSION}"
|
159
157
|
exit
|
160
158
|
end
|
161
|
-
opts.on('--verbose', 'Turn on verbose mode') do
|
162
|
-
$VERBOSE = true
|
163
|
-
options.verbose_long = true
|
164
|
-
end
|
165
159
|
opts.on_tail('-v', 'Print version number, then turn on verbose mode') do
|
166
160
|
puts "byebug #{Byebug::VERSION}"
|
167
161
|
$VERBOSE = true
|
@@ -198,7 +192,6 @@ rescue StandardError => e
|
|
198
192
|
end
|
199
193
|
|
200
194
|
if ARGV.empty?
|
201
|
-
exit if $VERBOSE and not options.verbose_long
|
202
195
|
puts opts
|
203
196
|
puts
|
204
197
|
puts 'Must specify a script to run'
|
data/ext/byebug/byebug.c
CHANGED
@@ -4,7 +4,7 @@ static VALUE mByebug; /* Ruby Byebug Module object */
|
|
4
4
|
|
5
5
|
static VALUE tracing = Qfalse;
|
6
6
|
static VALUE post_mortem = Qfalse;
|
7
|
-
static VALUE
|
7
|
+
static VALUE verbose = Qfalse;
|
8
8
|
|
9
9
|
static VALUE catchpoints = Qnil;
|
10
10
|
static VALUE breakpoints = Qnil;
|
@@ -69,7 +69,7 @@ cleanup(debug_context_t *dc)
|
|
69
69
|
VALUE context; \
|
70
70
|
thread_context_lookup(rb_thread_current(), &context); \
|
71
71
|
Data_Get_Struct(context, debug_context_t, dc); \
|
72
|
-
if (
|
72
|
+
if (verbose == Qtrue) trace_print(trace_arg, dc); \
|
73
73
|
|
74
74
|
#define EVENT_COMMON if (!trace_common(trace_arg, dc)) { return; }
|
75
75
|
|
@@ -182,13 +182,15 @@ call_at_line_check(VALUE context_obj, debug_context_t *dc,
|
|
182
182
|
static void
|
183
183
|
line_event(VALUE trace_point, void *data)
|
184
184
|
{
|
185
|
+
VALUE breakpoint, file, line, binding;
|
186
|
+
int moved = 0;
|
187
|
+
|
185
188
|
EVENT_SETUP
|
186
189
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
int moved = 0;
|
190
|
+
breakpoint = Qnil;
|
191
|
+
file = rb_tracearg_path(trace_arg);
|
192
|
+
line = rb_tracearg_lineno(trace_arg);
|
193
|
+
binding = rb_tracearg_binding(trace_arg);
|
192
194
|
|
193
195
|
EVENT_COMMON
|
194
196
|
|
@@ -209,7 +211,12 @@ line_event(VALUE trace_point, void *data)
|
|
209
211
|
if (dc->stack_size <= dc->dest_frame)
|
210
212
|
{
|
211
213
|
dc->lines = dc->lines <= 0 ? -1 : dc->lines - 1;
|
212
|
-
dc->
|
214
|
+
if (dc->stack_size < dc->dest_frame)
|
215
|
+
{
|
216
|
+
dc->dest_frame = dc->stack_size;
|
217
|
+
rb_funcall(mByebug, rb_intern("print"), 1,
|
218
|
+
rb_str_new2("Next went up a frame because previous frame finished\n"));
|
219
|
+
}
|
213
220
|
}
|
214
221
|
}
|
215
222
|
|
@@ -227,19 +234,21 @@ line_event(VALUE trace_point, void *data)
|
|
227
234
|
static void
|
228
235
|
call_event(VALUE trace_point, void *data)
|
229
236
|
{
|
237
|
+
VALUE breakpoint, klass, mid, binding, self, file, line;
|
238
|
+
|
230
239
|
EVENT_SETUP
|
231
240
|
|
232
241
|
dc->stack_size++;
|
233
242
|
|
234
243
|
EVENT_COMMON
|
235
244
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
245
|
+
breakpoint = Qnil;
|
246
|
+
klass = rb_tracearg_defined_class(trace_arg);
|
247
|
+
mid = SYM2ID(rb_tracearg_method_id(trace_arg));
|
248
|
+
binding = rb_tracearg_binding(trace_arg);
|
249
|
+
self = rb_tracearg_self(trace_arg);
|
250
|
+
file = rb_tracearg_path(trace_arg);
|
251
|
+
line = rb_tracearg_lineno(trace_arg);
|
243
252
|
|
244
253
|
breakpoint = find_breakpoint_by_method(breakpoints, klass, mid, binding, self);
|
245
254
|
if (breakpoint != Qnil)
|
@@ -262,9 +271,11 @@ return_event(VALUE trace_point, void *data)
|
|
262
271
|
|
263
272
|
if (dc->stack_size + 1 == dc->before_frame)
|
264
273
|
{
|
274
|
+
VALUE file, line;
|
275
|
+
|
265
276
|
reset_stepping_stop_points(dc);
|
266
|
-
|
267
|
-
|
277
|
+
file = rb_tracearg_path(trace_arg);
|
278
|
+
line = rb_tracearg_lineno(trace_arg);
|
268
279
|
call_at_return(context, dc, file, line);
|
269
280
|
}
|
270
281
|
|
@@ -304,19 +315,22 @@ c_return_event(VALUE trace_point, void *data)
|
|
304
315
|
static void
|
305
316
|
raise_event(VALUE trace_point, void *data)
|
306
317
|
{
|
307
|
-
EVENT_SETUP
|
308
|
-
|
309
318
|
VALUE expn_class, aclass;
|
310
|
-
VALUE err
|
319
|
+
VALUE err;
|
311
320
|
VALUE ancestors;
|
312
321
|
int i;
|
313
322
|
debug_context_t *new_dc;
|
323
|
+
VALUE binding, path, lineno;
|
324
|
+
|
325
|
+
EVENT_SETUP
|
326
|
+
|
327
|
+
err = rb_errinfo();
|
314
328
|
|
315
329
|
EVENT_COMMON
|
316
330
|
|
317
|
-
|
318
|
-
|
319
|
-
|
331
|
+
binding = rb_tracearg_binding(trace_arg);
|
332
|
+
path = rb_tracearg_path(trace_arg);
|
333
|
+
lineno = rb_tracearg_lineno(trace_arg);
|
320
334
|
|
321
335
|
if (post_mortem == Qtrue)
|
322
336
|
{
|
@@ -374,8 +388,6 @@ register_tracepoints(VALUE self)
|
|
374
388
|
|
375
389
|
if (NIL_P(traces))
|
376
390
|
{
|
377
|
-
traces = rb_ary_new();
|
378
|
-
|
379
391
|
int line_msk = RUBY_EVENT_LINE;
|
380
392
|
int call_msk = RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS;
|
381
393
|
int return_msk = RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END;
|
@@ -390,6 +402,7 @@ register_tracepoints(VALUE self)
|
|
390
402
|
VALUE tpCReturn = rb_tracepoint_new(Qnil, c_return_msk, c_return_event, 0);
|
391
403
|
VALUE tpRaise = rb_tracepoint_new(Qnil, raise_msk , raise_event , 0);
|
392
404
|
|
405
|
+
traces = rb_ary_new();
|
393
406
|
rb_ary_push(traces, tpLine);
|
394
407
|
rb_ary_push(traces, tpCall);
|
395
408
|
rb_ary_push(traces, tpReturn);
|
@@ -613,6 +626,32 @@ bb_load(int argc, VALUE *argv, VALUE self)
|
|
613
626
|
return status;
|
614
627
|
}
|
615
628
|
|
629
|
+
/*
|
630
|
+
* call-seq:
|
631
|
+
* Byebug.verbose -> bool
|
632
|
+
*
|
633
|
+
* Returns +true+ if verbose output of TracePoint API events is enabled.
|
634
|
+
*/
|
635
|
+
static VALUE
|
636
|
+
bb_verbose(VALUE self)
|
637
|
+
{
|
638
|
+
return verbose;
|
639
|
+
}
|
640
|
+
|
641
|
+
/*
|
642
|
+
* call-seq:
|
643
|
+
* Byebug.verbose = bool
|
644
|
+
*
|
645
|
+
* Enable verbose output of every TracePoint API events, useful for debugging
|
646
|
+
* byebug.
|
647
|
+
*/
|
648
|
+
static VALUE
|
649
|
+
bb_set_verbose(VALUE self, VALUE value)
|
650
|
+
{
|
651
|
+
verbose = RTEST(value) ? Qtrue : Qfalse;
|
652
|
+
return value;
|
653
|
+
}
|
654
|
+
|
616
655
|
static VALUE
|
617
656
|
set_current_skipped_status(VALUE status)
|
618
657
|
{
|
@@ -784,6 +823,8 @@ Init_byebug()
|
|
784
823
|
rb_define_module_function(mByebug, "thread_context" , bb_thread_context , 1);
|
785
824
|
rb_define_module_function(mByebug, "tracing?" , bb_tracing , 0);
|
786
825
|
rb_define_module_function(mByebug, "tracing=" , bb_set_tracing , 1);
|
826
|
+
rb_define_module_function(mByebug, "verbose" , bb_verbose , 0);
|
827
|
+
rb_define_module_function(mByebug, "verbose=" , bb_set_verbose , 1);
|
787
828
|
|
788
829
|
cThreadsTable = rb_define_class_under(mByebug, "ThreadsTable", rb_cObject);
|
789
830
|
|
data/ext/byebug/context.c
CHANGED
@@ -45,13 +45,9 @@ context_free(void *data)
|
|
45
45
|
}
|
46
46
|
|
47
47
|
static int
|
48
|
-
real_stack_size(
|
48
|
+
real_stack_size()
|
49
49
|
{
|
50
|
-
|
51
|
-
if (locs == Qnil)
|
52
|
-
return 0;
|
53
|
-
|
54
|
-
return (int)RARRAY_LEN(locs);
|
50
|
+
return FIX2INT(rb_funcall(cContext, rb_intern("real_stack_size"), 0));
|
55
51
|
}
|
56
52
|
|
57
53
|
extern VALUE
|
@@ -62,7 +58,7 @@ context_create(VALUE thread)
|
|
62
58
|
context->last_file = Qnil;
|
63
59
|
context->last_line = Qnil;
|
64
60
|
context->flags = 0;
|
65
|
-
context->stack_size = real_stack_size(
|
61
|
+
context->stack_size = real_stack_size();
|
66
62
|
context->thnum = ++thnum_max;
|
67
63
|
context->thread = thread;
|
68
64
|
reset_stepping_stop_points(context);
|
@@ -97,13 +93,15 @@ static VALUE
|
|
97
93
|
dc_frame_get(const debug_context_t *context, int frame_index,
|
98
94
|
enum frame_component type)
|
99
95
|
{
|
96
|
+
VALUE frame;
|
97
|
+
|
100
98
|
if (NIL_P(dc_backtrace(context)))
|
101
99
|
rb_raise(rb_eRuntimeError, "Backtrace information is not available");
|
102
100
|
|
103
101
|
if (frame_index >= RARRAY_LEN(dc_backtrace(context)))
|
104
102
|
rb_raise(rb_eRuntimeError, "That frame doesn't exist!");
|
105
103
|
|
106
|
-
|
104
|
+
frame = rb_ary_entry(dc_backtrace(context), frame_index);
|
107
105
|
return rb_ary_entry(frame, type);
|
108
106
|
}
|
109
107
|
|
@@ -243,9 +241,11 @@ Context_frame_class(int argc, VALUE *argv, VALUE self)
|
|
243
241
|
static VALUE
|
244
242
|
Context_frame_file(int argc, VALUE *argv, VALUE self)
|
245
243
|
{
|
244
|
+
VALUE loc;
|
245
|
+
|
246
246
|
FRAME_SETUP
|
247
247
|
|
248
|
-
|
248
|
+
loc = dc_frame_location(context, frame_n);
|
249
249
|
|
250
250
|
return rb_funcall(loc, rb_intern("path"), 0);
|
251
251
|
}
|
@@ -259,9 +259,11 @@ Context_frame_file(int argc, VALUE *argv, VALUE self)
|
|
259
259
|
static VALUE
|
260
260
|
Context_frame_line(int argc, VALUE *argv, VALUE self)
|
261
261
|
{
|
262
|
+
VALUE loc;
|
263
|
+
|
262
264
|
FRAME_SETUP
|
263
265
|
|
264
|
-
|
266
|
+
loc = dc_frame_location(context, frame_n);
|
265
267
|
|
266
268
|
return rb_funcall(loc, rb_intern("lineno"), 0);
|
267
269
|
}
|
@@ -275,9 +277,11 @@ Context_frame_line(int argc, VALUE *argv, VALUE self)
|
|
275
277
|
static VALUE
|
276
278
|
Context_frame_method(int argc, VALUE *argv, VALUE self)
|
277
279
|
{
|
280
|
+
VALUE loc;
|
281
|
+
|
278
282
|
FRAME_SETUP
|
279
283
|
|
280
|
-
|
284
|
+
loc = dc_frame_location(context, frame_n);
|
281
285
|
|
282
286
|
return rb_str_intern(rb_funcall(loc, rb_intern("label"), 0));
|
283
287
|
}
|
@@ -354,16 +358,8 @@ Context_stack_size(VALUE self)
|
|
354
358
|
{
|
355
359
|
debug_context_t *context;
|
356
360
|
Data_Get_Struct(self, debug_context_t, context);
|
357
|
-
VALUE backtrace = dc_backtrace(context);
|
358
|
-
|
359
|
-
if (NIL_P(backtrace))
|
360
|
-
return INT2FIX(context->stack_size);
|
361
|
-
|
362
|
-
if (context->stack_size != RARRAY_LEN(backtrace))
|
363
|
-
rb_warn("Calculated stack size is %d but there are actually %ld frames",
|
364
|
-
context->stack_size, RARRAY_LEN(backtrace));
|
365
361
|
|
366
|
-
return INT2FIX(
|
362
|
+
return INT2FIX(context->stack_size);
|
367
363
|
}
|
368
364
|
|
369
365
|
static VALUE
|
data/ext/byebug/extconf.rb
CHANGED
data/lib/byebug.rb
CHANGED
@@ -4,12 +4,11 @@ require_relative 'byebug/context'
|
|
4
4
|
require_relative 'byebug/processor'
|
5
5
|
require_relative 'byebug/remote'
|
6
6
|
require 'stringio'
|
7
|
+
require 'tracer'
|
7
8
|
require 'linecache19'
|
8
9
|
|
9
10
|
module Byebug
|
10
11
|
|
11
|
-
self.handler = CommandProcessor.new
|
12
|
-
|
13
12
|
# List of files byebug will ignore while debugging
|
14
13
|
IGNORED_FILES = Dir[Pathname.new(__FILE__) + "../**/*.rb"].map {
|
15
14
|
|f| File.expand_path(f) }
|
@@ -26,14 +25,17 @@ module Byebug
|
|
26
25
|
|
27
26
|
class << self
|
28
27
|
|
28
|
+
# processor modules provide +handler+ object
|
29
|
+
attr_accessor :handler
|
30
|
+
Byebug.handler = CommandProcessor.new
|
31
|
+
|
29
32
|
attr_accessor :last_exception
|
30
33
|
Byebug.last_exception = nil
|
31
34
|
|
32
35
|
def source_reload
|
33
|
-
Object.send(:remove_const,
|
34
|
-
Object.const_defined?(
|
35
|
-
Object.const_set(
|
36
|
-
LineCache::clear_file_cache
|
36
|
+
Object.send(:remove_const, 'SCRIPT_LINES__') if
|
37
|
+
Object.const_defined?('SCRIPT_LINES__')
|
38
|
+
Object.const_set('SCRIPT_LINES__', {})
|
37
39
|
end
|
38
40
|
|
39
41
|
#
|
@@ -42,9 +44,11 @@ module Byebug
|
|
42
44
|
# @return "\n" if there was a problem. Leaking blanks are stripped off.
|
43
45
|
#
|
44
46
|
def line_at(filename, line_number)
|
45
|
-
|
46
|
-
|
47
|
-
return "\n" unless
|
47
|
+
source_reload
|
48
|
+
|
49
|
+
return "\n" unless File.exist?(filename)
|
50
|
+
line = Tracer::Single.get_line(filename, line_number)
|
51
|
+
|
48
52
|
return "#{line.gsub(/^\s+/, '').chomp}"
|
49
53
|
end
|
50
54
|
|
@@ -69,6 +73,9 @@ module Byebug
|
|
69
73
|
handler.interface = value
|
70
74
|
end
|
71
75
|
|
76
|
+
extend Forwardable
|
77
|
+
def_delegators :"handler.interface", :print
|
78
|
+
|
72
79
|
#
|
73
80
|
# Byebug.start(options) -> bool
|
74
81
|
# Byebug.start(options) { ... } -> obj
|
data/lib/byebug/command.rb
CHANGED
@@ -31,7 +31,7 @@ module Byebug
|
|
31
31
|
need_context: false } unless defined?(DEF_OPTIONS)
|
32
32
|
|
33
33
|
def help(args)
|
34
|
-
output = description.gsub(/^ +/, '')
|
34
|
+
output = description.gsub(/^ +/, '') + "\n"
|
35
35
|
|
36
36
|
if defined? self::Subcommands
|
37
37
|
return output += format_subcmds unless args and args[1]
|
@@ -176,7 +176,7 @@ module Byebug
|
|
176
176
|
register_setting_var(:argv, Byebug::ARGV)
|
177
177
|
|
178
178
|
def initialize(state)
|
179
|
-
@state = state
|
179
|
+
@match, @state = nil, state
|
180
180
|
end
|
181
181
|
|
182
182
|
def match(input)
|
@@ -197,7 +197,7 @@ module Byebug
|
|
197
197
|
eval(str, b)
|
198
198
|
rescue StandardError, ScriptError => e
|
199
199
|
if Command.settings[:stack_trace_on_error]
|
200
|
-
at = eval("Thread.current.backtrace_locations
|
200
|
+
at = eval("Thread.current.backtrace_locations", b)
|
201
201
|
print "#{at.shift}: #{e.class} Exception(#{e.message})\n"
|
202
202
|
for i in at
|
203
203
|
print "\tfrom #{i}\n"
|
@@ -17,8 +17,8 @@ module Byebug
|
|
17
17
|
return print "No breakpoints have been set.\n" if 0 == largest
|
18
18
|
return unless pos = get_int(@match[1], "Condition", 1, largest)
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
breakpoint = breakpoints.select{ |b| b.id == pos }.first
|
21
|
+
breakpoint.expr = @match[2] if breakpoint
|
22
22
|
end
|
23
23
|
|
24
24
|
class << self
|
data/lib/byebug/commands/edit.rb
CHANGED
@@ -9,21 +9,24 @@ module Byebug
|
|
9
9
|
|
10
10
|
def execute
|
11
11
|
if not @match[1]
|
12
|
-
unless @state.
|
13
|
-
errmsg "We are not in a state that has an associated file.\n"
|
14
|
-
return
|
12
|
+
unless @state.file
|
13
|
+
return errmsg "We are not in a state that has an associated file.\n"
|
15
14
|
end
|
16
15
|
file = @state.file
|
17
|
-
|
16
|
+
line = @state.line if @state.line
|
18
17
|
elsif @pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1])
|
19
|
-
file,
|
18
|
+
file, line = @pos_match.captures
|
19
|
+
elsif File.exist?(@match[1])
|
20
|
+
file = @match[1]
|
20
21
|
else
|
21
|
-
errmsg "Invalid file
|
22
|
-
return
|
22
|
+
return errmsg "Invalid file[:line] number specification: #{@match[1]}\n"
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
|
+
editor = ENV['EDITOR'] || 'vim'
|
26
|
+
|
25
27
|
if File.readable?(file)
|
26
|
-
system("#{editor} +#{
|
28
|
+
system("#{editor} +#{line} #{file}") if line
|
29
|
+
system("#{editor} #{file}") unless line
|
27
30
|
else
|
28
31
|
errmsg "File \"#{file}\" is not readable.\n"
|
29
32
|
end
|