Class: Byebug::InfoCommand

Inherits:
Command
  • Object
show all
Includes:
Columnize
Defined in:
lib/byebug/commands/info.rb

Overview

Implements byebug “info” command.

Constant Summary collapse

Subcommands =
[
   ['args', 1, 'Argument variables of current stack frame'],
   ['breakpoints', 1, 'Status of user-settable breakpoints',
    'Without argument, list info about all breakpoints. With an integer ' \
    'argument, list info on that breakpoint.'],
   ['catch', 3,
    'Exceptions that can be caught in the current stack frame'],
   ['display', 2, 'Expressions to display when program stops'],
   ['file', 4, 'Info about a particular file read in',
    'After the file name is supplied, you can list file attributes that ' \
    'you wish to see. Attributes include: "all", "basic", "breakpoint", ' \
    '"lines", "mtime", "path" and "sha1".'],
   ['files', 5, 'File names and timestamps of files read in'],
   ['global_variables', 2, 'Global variables'],
   ['instance_variables', 2,
    'Instance variables of the current stack frame'],
   ['line', 2,
    'Line number and file name of current position in source file'],
   ['locals', 2, 'Local variables of the current stack frame'],
   ['program', 2, 'Execution status of the program'],
   ['stack', 2, 'Backtrace of the stack'],
   ['variables', 1,
    'Local and instance variables of the current stack frame']
  ].map do |name, min, short_help, long_help|
  SubcmdStruct.new(name, min, short_help, long_help)
end
InfoFileSubcommands =
[
   ['all', 1, 'All file information available - breakpoints, lines, ' \
    'mtime, path and sha1'],
   ['basic', 2, 'basic information - path, number of lines'],
   ['breakpoints', 2, 'Show trace line numbers',
    'These are the line number where a breakpoint can be set.'],
   ['lines', 1, 'Show number of lines in the file'],
   ['mtime', 1, 'Show modification time of file'],
   ['path', 4, 'Show full file path name for file'],
   ['sha1', 1, 'Show SHA1 hash of contents of the file']
  ].map do |name, min, short_help, long_help|
  SubcmdStruct.new(name, min, short_help, long_help)
end

Constants inherited from Command

Command::DEF_OPTIONS

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Command

commands, help, inherited, #initialize, load_commands, #match, method_missing, options, register_setting_get, register_setting_set, register_setting_var, settings, settings_map

Constructor Details

This class inherits a constructor from Byebug::Command

Class Method Details

.descriptionObject



359
360
361
362
363
364
365
# File 'lib/byebug/commands/info.rb', line 359

def description
  %{
    info[ subcommand]

    Generic command for showing things about the program being
  }
end

.namesObject



355
356
357
# File 'lib/byebug/commands/info.rb', line 355

def names
  %w(info)
end

Instance Method Details

#executeObject



71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/byebug/commands/info.rb', line 71

def execute
  return help(@match) unless @match[1]

  args = @match[1].split(/[ \t]+/)
  param = args.shift
  subcmd = find(Subcommands, param)
  if subcmd
    send("info_#{subcmd.name}", *args)
  else
    errmsg "Unknown info command #{param}\n"
  end
end

#help(args) ⇒ Object



330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/byebug/commands/info.rb', line 330

def help(args)
  if args[1]
    subcmd = find(Subcommands, args[1])
    if subcmd
      str = subcmd.short_help + '.'
      if 'file' == subcmd.name and args[2]
        subsubcmd = find(InfoFileSubcommands, args[2])
        if subsubcmd
          str += "\nInvalid \"file\" attribute \"#{args[2]}\"."
        else
          str += "\n" + subsubcmd.short_help + '.'
        end
      else
        str += "\n" + subcmd.long_help if subcmd.long_help
      end
    else
      str = "Invalid \"info\" subcommand \"#{args[1]}\"."
    end
  else
    str = InfoCommand.description + format_subcmds(Subcommands)
  end
  print str
end

#info_args(*args) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/byebug/commands/info.rb', line 84

def info_args(*args)
  unless @state.context
    print "No frame selected.\n"
    return
  end
  locals = @state.context.frame_locals(@state.frame_pos)
  args = @state.context.frame_args(@state.frame_pos)
  args.each do |name|
    s = "#{name} = #{locals[name].inspect}"
    pad_with_dots(s)
    print "#{s}\n"
  end
end

#info_breakpoints(*args) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/byebug/commands/info.rb', line 98

def info_breakpoints(*args)
  return print "\"info breakpoints\" not available here.\n" unless
    @state.context

  return print "No breakpoints.\n" if Byebug.breakpoints.empty?

  brkpts = Byebug.breakpoints.sort_by{|b| b.id}
  unless args.empty?
    indices = args.map{|a| a.to_i}
    brkpts = brkpts.select{|b| indices.member?(b.id)}
    return errmsg "No breakpoints found among list given.\n" if
      brkpts.empty?
  end
  print "Num Enb What\n"
  brkpts.each do |b|
    print "%-3d %-3s at %s:%s%s\n", b.id,
                                    b.enabled? ? 'y' : 'n',
                                    b.source,
                                    b.pos,
                                    b.expr.nil? ? '' : " if #{b.expr}"
    hits = b.hit_count
    if hits > 0
      s = (hits > 1) ? 's' : ''
      print "\tbreakpoint already hit #{hits} time#{s}\n"
    end
  end
end

#info_display(*args) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/byebug/commands/info.rb', line 126

def info_display(*args)
  unless @state.context
    print "info display not available here.\n"
    return
  end
  if @state.display.find{|d| d[0]}
    print "Auto-display expressions now in effect:\n"
    print "Num Enb Expression\n"
    n = 1
    for d in @state.display
      print "%3d: %s  %s\n", n, (d[0] ? 'y' : 'n'), d[1] if
        d[0] != nil
      n += 1
    end
  else
    print "There are no auto-display expressions now.\n"
  end
end

#info_file(*args) ⇒ Object



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/byebug/commands/info.rb', line 179

def info_file(*args)
  return info_files unless args[0]
  file = args[0]

  param =  args[1] ? args[1] : 'basic'

  subcmd = find(InfoFileSubcommands, param)
  return errmsg "Invalid parameter #{param}\n" unless subcmd

  unless LineCache::cached?(file)
    unless LineCache::cached_script?(file)
      return print "File #{file} is not cached\n"
    end
    LineCache::cache(file, Command.settings[:reload_source_on_change])
  end

  print "File #{file}"
  info_file_path(file) if %w(all basic path).member?(subcmd.name)
  print "\n"

  info_file_lines(file) if %w(all basic lines).member?(subcmd.name)
  info_file_breakpoints(file) if %w(all breakpoints).member?(subcmd.name)
  info_file_mtime(file) if %w(all mtime).member?(subcmd.name)
  info_file_sha1(file) if %w(all sha1).member?(subcmd.name)
end

#info_files(*args) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/byebug/commands/info.rb', line 205

def info_files(*args)
  files = LineCache::cached_files
  files += SCRIPT_LINES__.keys unless 'stat' == args[0]
  files.uniq.sort.each do |file|
    stat = LineCache::stat(file)
    path = LineCache::path(file)
    print "File %s", file
    if path and path != file
      print " - %s\n", path
    else
      print "\n"
    end
    print "\t%s\n", stat.mtime if stat
  end
end

#info_global_variables(*args) ⇒ Object



294
295
296
297
298
299
300
# File 'lib/byebug/commands/info.rb', line 294

def info_global_variables(*args)
  unless @state.context
    errmsg "info global_variables not available here.\n"
    return
  end
  var_global
end

#info_instance_variables(*args) ⇒ Object



221
222
223
224
225
226
227
228
# File 'lib/byebug/commands/info.rb', line 221

def info_instance_variables(*args)
  unless @state.context
    print "info instance_variables not available here.\n"
    return
  end
  obj = debug_eval('self')
  var_list(obj.instance_variables)
end

#info_line(*args) ⇒ Object



230
231
232
233
234
235
236
# File 'lib/byebug/commands/info.rb', line 230

def info_line(*args)
  unless @state.context
    errmsg "info line not available here.\n"
    return
  end
  print "Line %d of \"%s\"\n",  @state.line, @state.file
end

#info_locals(*args) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/byebug/commands/info.rb', line 238

def info_locals(*args)
  unless @state.context
    errmsg "info line not available here.\n"
    return
  end
  locals = @state.context.frame_locals(@state.frame_pos)
  locals.keys.sort.each do |name|
    ### FIXME: make a common routine
    begin
      s = "#{name} = #{locals[name].inspect}"
    rescue
      begin
      s = "#{name} = #{locals[name].to_s}"
      rescue
        s = "*Error in evaluation*"
      end
    end
    pad_with_dots(s)
    print "#{s}\n"
  end
end

#info_program(*args) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
# File 'lib/byebug/commands/info.rb', line 274

def info_program(*args)
  return print "The program being debugged is not being run.\n" if
    not @state.context

  return print "The program crashed.\n" + Byebug.last_exception ?
               "Exception: #{Byebug.last_exception.inspect}" : "" + "\n" if
    @state.context.dead?

  print "Program stopped. "
  info_stop_reason @state.context.stop_reason
end

#info_stack(*args) ⇒ Object



286
287
288
289
290
291
292
# File 'lib/byebug/commands/info.rb', line 286

def info_stack(*args)
  if not @state.context
    errmsg "info stack not available here.\n"
    return
  end
  print_backtrace
end

#info_variables(*args) ⇒ Object



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/byebug/commands/info.rb', line 302

def info_variables(*args)
  if not @state.context
    errmsg "info variables not available here.\n"
    return
  end
  obj = debug_eval('self')
  locals = @state.context.frame_locals(@state.frame_pos)
  locals[:self] = @state.context.frame_self(@state.frame_pos)
  locals.keys.sort.each do |name|
    next if name =~ /^__dbg_/ # skip byebug pollution
    ### FIXME: make a common routine
    begin
      s = "#{name} = #{locals[name].inspect}"
    rescue
      begin
        s = "#{name} = #{locals[name].to_s}"
      rescue
        s = "#{name} = *Error in evaluation*"
      end
    end
    pad_with_dots(s)
    s.gsub!('%', '%%')  # protect against printf format strings
    print "#{s}\n"
  end
  var_list(obj.instance_variables, obj.instance_eval{binding()})
  var_class_self
end

#regexpObject



67
68
69
# File 'lib/byebug/commands/info.rb', line 67

def regexp
  /^\s* i(?:nfo)? (?:\s+(.*))?$/ix
end