terminal/command: add support for next [count] (#1629)
* terminal/command: add support for next [count] * disallow negative counts. * handle github comments, and regen docs. * Fix the fact that we don't print the file info in the last step of the next count. * Fix a typo, cleanup a few other observations.
This commit is contained in:
parent
dc3fca3f7b
commit
1a478cdb53
@ -296,6 +296,11 @@ If regex is specified only local variables with a name matching it will be retur
|
|||||||
## next
|
## next
|
||||||
Step over to next source line.
|
Step over to next source line.
|
||||||
|
|
||||||
|
next [count]
|
||||||
|
|
||||||
|
Optional [count] argument allows you to skip multiple lines.
|
||||||
|
|
||||||
|
|
||||||
Aliases: n
|
Aliases: n
|
||||||
|
|
||||||
## on
|
## on
|
||||||
|
@ -138,7 +138,12 @@ the arguments. With -noargs, the process starts with an empty commandline.
|
|||||||
{aliases: []string{"continue", "c"}, cmdFn: c.cont, helpMsg: "Run until breakpoint or program termination."},
|
{aliases: []string{"continue", "c"}, cmdFn: c.cont, helpMsg: "Run until breakpoint or program termination."},
|
||||||
{aliases: []string{"step", "s"}, cmdFn: c.step, helpMsg: "Single step through program."},
|
{aliases: []string{"step", "s"}, cmdFn: c.step, helpMsg: "Single step through program."},
|
||||||
{aliases: []string{"step-instruction", "si"}, allowedPrefixes: revPrefix, cmdFn: c.stepInstruction, helpMsg: "Single step a single cpu instruction."},
|
{aliases: []string{"step-instruction", "si"}, allowedPrefixes: revPrefix, cmdFn: c.stepInstruction, helpMsg: "Single step a single cpu instruction."},
|
||||||
{aliases: []string{"next", "n"}, cmdFn: c.next, helpMsg: "Step over to next source line."},
|
{aliases: []string{"next", "n"}, cmdFn: c.next, helpMsg: `Step over to next source line.
|
||||||
|
|
||||||
|
next [count]
|
||||||
|
|
||||||
|
Optional [count] argument allows you to skip multiple lines.
|
||||||
|
`},
|
||||||
{aliases: []string{"stepout"}, cmdFn: c.stepout, helpMsg: "Step out of the current function."},
|
{aliases: []string{"stepout"}, cmdFn: c.stepout, helpMsg: "Step out of the current function."},
|
||||||
{aliases: []string{"call"}, cmdFn: c.call, helpMsg: `Resumes process, injecting a function call (EXPERIMENTAL!!!)
|
{aliases: []string{"call"}, cmdFn: c.call, helpMsg: `Resumes process, injecting a function call (EXPERIMENTAL!!!)
|
||||||
|
|
||||||
@ -864,6 +869,15 @@ func parseArgs(args string) ([]string, error) {
|
|||||||
return v[0], nil
|
return v[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseOptionalCount parses an optional count argument.
|
||||||
|
// If there are not arguments, a value of 1 is returned as the default.
|
||||||
|
func parseOptionalCount(arg string) (int64, error) {
|
||||||
|
if len(arg) == 0 {
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
return strconv.ParseInt(arg, 0, 64)
|
||||||
|
}
|
||||||
|
|
||||||
func restart(t *Term, ctx callContext, args string) error {
|
func restart(t *Term, ctx callContext, args string) error {
|
||||||
v, err := parseArgs(args)
|
v, err := parseArgs(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -932,9 +946,11 @@ func (c *Commands) cont(t *Term, ctx callContext, args string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string) error {
|
func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string, shouldPrintFile bool) error {
|
||||||
if !state.NextInProgress {
|
if !state.NextInProgress {
|
||||||
|
if shouldPrintFile {
|
||||||
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
|
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
@ -983,7 +999,7 @@ func (c *Commands) step(t *Term, ctx callContext, args string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
printcontext(t, state)
|
printcontext(t, state)
|
||||||
return continueUntilCompleteNext(t, state, "step")
|
return continueUntilCompleteNext(t, state, "step", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
var notOnFrameZeroErr = errors.New("not on topmost frame")
|
var notOnFrameZeroErr = errors.New("not on topmost frame")
|
||||||
@ -1032,13 +1048,29 @@ func (c *Commands) next(t *Term, ctx callContext, args string) error {
|
|||||||
if c.frame != 0 {
|
if c.frame != 0 {
|
||||||
return notOnFrameZeroErr
|
return notOnFrameZeroErr
|
||||||
}
|
}
|
||||||
|
var count int64
|
||||||
|
var err error
|
||||||
|
if count, err = parseOptionalCount(args); err != nil {
|
||||||
|
return err
|
||||||
|
} else if count <= 0 {
|
||||||
|
return errors.New("Invalid next count")
|
||||||
|
}
|
||||||
|
for ; count > 0; count-- {
|
||||||
state, err := exitedToError(t.client.Next())
|
state, err := exitedToError(t.client.Next())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printcontextNoState(t)
|
printcontextNoState(t)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// If we're about the exit the loop, print the context.
|
||||||
|
finishedNext := count == 1
|
||||||
|
if finishedNext {
|
||||||
printcontext(t, state)
|
printcontext(t, state)
|
||||||
return continueUntilCompleteNext(t, state, "next")
|
}
|
||||||
|
if err := continueUntilCompleteNext(t, state, "next", finishedNext); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) stepout(t *Term, ctx callContext, args string) error {
|
func (c *Commands) stepout(t *Term, ctx callContext, args string) error {
|
||||||
@ -1054,7 +1086,7 @@ func (c *Commands) stepout(t *Term, ctx callContext, args string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
printcontext(t, state)
|
printcontext(t, state)
|
||||||
return continueUntilCompleteNext(t, state, "stepout")
|
return continueUntilCompleteNext(t, state, "stepout", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) call(t *Term, ctx callContext, args string) error {
|
func (c *Commands) call(t *Term, ctx callContext, args string) error {
|
||||||
@ -1074,7 +1106,7 @@ func (c *Commands) call(t *Term, ctx callContext, args string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
printcontext(t, state)
|
printcontext(t, state)
|
||||||
return continueUntilCompleteNext(t, state, "call")
|
return continueUntilCompleteNext(t, state, "call", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func clear(t *Term, ctx callContext, args string) error {
|
func clear(t *Term, ctx callContext, args string) error {
|
||||||
|
@ -664,6 +664,15 @@ func TestCheckpoints(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNextWithCount(t *testing.T) {
|
||||||
|
test.AllowRecording(t)
|
||||||
|
withTestTerminal("nextcond", t, func(term *FakeTerminal) {
|
||||||
|
term.MustExec("break main.main")
|
||||||
|
listIsAt(t, term, "continue", 8, -1, -1)
|
||||||
|
listIsAt(t, term, "next 2", 10, -1, -1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestRestart(t *testing.T) {
|
func TestRestart(t *testing.T) {
|
||||||
withTestTerminal("restartargs", t, func(term *FakeTerminal) {
|
withTestTerminal("restartargs", t, func(term *FakeTerminal) {
|
||||||
term.MustExec("break main.printArgs")
|
term.MustExec("break main.printArgs")
|
||||||
|
Loading…
Reference in New Issue
Block a user