Stepping into a specific call on a line
Problem Description It can be extremely tedious (and even hard to know how) to step into the intended method call on a line that has many method calls. Consider this sample code with 9 method/variable references:
writer.hset(meta_key(user), uuids_key, meta_uuids.excluding(uuid).join(","))
If my goal is to step into the hset call, I must first step into, finish, and step/next into the next call for up to 8 other method calls before I can step into hset. It's extremely easy to get lost during this process, especially in unfamiliar code and when it's unclear which references are to methods and which are to local variables.
Ideas I'm interested in your feedback about what would be feasible. Here are some ideas:
- The pry-moves debugger supports
step <method_name>: step into methodmethod_name, with partial name match supported. (implementation) If given a numeric argument,stepwould continue to step n times. If given a string argument, it would attempt to match step into the method where__callee__matches the given pattern. - The RubyMine editor provides a Smart step into feature that provides a solution that requires a cursor. Lacking the environment with the cursor, perhaps debug can provide a similar choice via a menu/list of calls on the current line that the user can select from to step into, maybe when the argument is
?, i.e.step ?.
Are any of these feasible? What are your thoughts? Thanks for considering!
Debugger supports breaking at an object's method call with the b[reak] command. So I think you can do b writer.hset and then c in this case.
@st0012 that's a really good workaround that I hadn't considered. Thank you!
The biggest issue I see is that it leaves lingering breakpoints that can be hit later, from what was intended to be a transient step operation. These breakpoints need to be manually deleted to keep the program from breaking there again later unintentionally. I think the community would appreciate having this built into step.
As an aside, the first scenario I ran into where I could use it was this, where I wanted to step into import:
result = described_class.new(operations).import
In this case, I couldn't break described_class.new(operations).import, because I'd be breaking on a new instance, different than the one that would be hit after continue. Moreover, I had to look up what described_class referred to. I ran break ThatReferencedClassName#import, which worked. This required some manual lookup, but at least it's not the most common case.
Regardless, thank you—this is useful in the meantime!
Alternatively, if we could create one-time breakpoints, this might be less effort to implement and still eliminate the biggest drawback to this workaround.
We do support one-time breakpoints internally but it's not exposed to commands yet. But I think it's worth considering for the cases you mentioned.
I think one-time breakpoint doesn't solve this issue because if the breakpoint is not reached (because of exception and so on) it will be remained.
Extending step command is considerable.
# c.rb
class C
def foo
end
end
I think pattern should be
- method name (
step foo/step #foo) - class/module name the method defined (
step C) - path (
step a.rb)
and combination? step C#foo
or only method name?
Note that regexp pattern should be use / like /foo/ on command.
... but I understand typing two / is inconvenient on this case.
I like the idea of extending step command 👍
Regarding the method signature, I think it should accept what break takes:
-
step C#foo -
step C.foo -
step c.foo
That'll give users enough options to navigate complicated method calls like
# step Template#format
# step Diestor.diest
# step template.virtual_path
digest = Digestor.digest(name: template.virtual_path, format: template.format, finder: lookup_context, dependencies: view_cache_dependencies)
maybe this feature can be decomposed into the following features
- introduce "temporary" breakpoint which will be removed just after stopping by any reasons. I'm not sure
breakcommand can make it (maybe it is not needed. At least there is request). - make
step XXXas a shortcut of the following two commands:-
break XXX as temporary breakpoint -
continue
-
English question:
step into XXX makes sense for me, but does step XXX make sense?
Step XXX maxes sense. “Into” can be implied.
I choose step into <name> because there are already step back and step reset commands.