Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,10 @@ The `<...>` notation means the argument.
* Show predecessor lines as opposed to the `list` command.
* `l[ist] <start>` or `l[ist] <start>-<end>`
* Show current frame's source code from the line <start> to <end> if given.
* `ls`
* Executes `irb`'s `ls` command with current binding.
* `ls <obj>`
* Executes `irb`'s `ls` command with the given obj.
* `edit`
* Open the current file on the editor (use `EDITOR` environment variable).
* Note that edited file will not be reloaded.
Expand Down
11 changes: 11 additions & 0 deletions lib/debug/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,17 @@ def process_command line
return :retry
end

# * `ls`
# * Executes `irb`'s `ls` command with current binding.
# * `ls <obj>`
# * Executes `irb`'s `ls` command with the given obj.
when 'ls'
if @ui.remote?
@ui.puts "not supported on the remote console."

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason it can't run on remote console either. I think we can sort it out later.

return :retry
end
@tc << [:irb, :ls, arg]

# * `edit`
# * Open the current file on the editor (use `EDITOR` environment variable).
# * Note that edited file will not be reloaded.
Expand Down
33 changes: 33 additions & 0 deletions lib/debug/thread_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'objspace'
require 'pp'
require "irb"

require_relative 'frame_info'
require_relative 'color'
Expand All @@ -15,6 +16,7 @@ def self.current
end
end

extend IRB::ExtendCommandBundle

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module injects irb commands as methods. Pretty handy 👍
https://github.com/ruby/irb/blob/master/lib/irb/extend-command.rb

include Color

attr_reader :location, :thread, :mode, :id
Expand Down Expand Up @@ -579,6 +581,26 @@ def wait_next_action
else
raise "unsupported frame operation: #{arg.inspect}"
end
event! :result, nil
when :irb
cmd, arg_expr = *args

raise "unsupported irb command: #{cmd}" unless cmd == :ls

begin
# most irb commands require irb workplace or irb session present in the environment to work
init_irb_context

if arg_expr
arg = frame_eval(arg_expr)
self.class.send("irb_#{cmd}", arg)
else
self.class.send("irb_#{cmd}")
end
ensure
reset_irb_context
end

event! :result, nil
when :show
type = args.shift
Expand Down Expand Up @@ -658,5 +680,16 @@ def to_s
str += " (not under control)" unless self.mode
str
end

def init_irb_context
IRB.init_config(nil)
workspace = IRB::WorkSpace.new(current_frame.binding)
irb = IRB::Irb.new(workspace, nil)
IRB.conf[:MAIN_CONTEXT] = irb.context
end

def reset_irb_context
IRB.conf[:MAIN_CONTEXT] = nil

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is needed, but just in case.

end
end
end
59 changes: 59 additions & 0 deletions test/debug/ls_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

require_relative '../support/test_case'

module DEBUGGER__
class LsTest < TestCase
def program
<<~RUBY
1| class Foo
2| def initialize
3| @var = "foobar"
4| end
5|
6| def bar; end
7| def self.baz; end
8| end
9|
10| foo = Foo.new
11|
12| binding.b
RUBY
end

def test_ls_lists_local_variables
debug_code(program, remote: false) do
type 'c'
type 'ls'
assert_line_text(/locals.*: _ foo/)
type 'c'
end
end

def test_ls_lists_object_info
debug_code(program, remote: false) do
type 'c'
type 'ls foo'
assert_line_text([
/Foo#methods.*: bar/,
/instance variables.*: @var/
])
type 'c'
end
end

def test_ls_lists_class_info
debug_code(program, remote: false) do
type 'c'
type 'ls Foo'
assert_line_text(
[
/Class#methods.*: allocate/,
/Foo\.methods.*: baz/,
]
)
type 'c'
end
end
end
end