terminal: add prompt when breakpoint is hit during next/step/stepout (#2548)
* terminal: add prompt when breakpoint is hit during next/step/stepout Adds a prompt asking the user what to do when a breakpoint is hit on a different goroutine while next/step/stepout is being executed. Gives the user the opportunity to cancel next/step/stepout, continue once skipping the breakpoint or automatically skipping all other concurrent breakpoints until next/step/stepout is finished. Fixes #2317
This commit is contained in:
parent
e9b20d5ee1
commit
2ecc025311
@ -1446,8 +1446,28 @@ func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string, sho
|
||||
}
|
||||
return nil
|
||||
}
|
||||
skipBreakpoints := false
|
||||
for {
|
||||
fmt.Printf("\tbreakpoint hit during %s, continuing...\n", op)
|
||||
fmt.Printf("\tbreakpoint hit during %s", op)
|
||||
if !skipBreakpoints {
|
||||
fmt.Printf("\n")
|
||||
answer, err := promptAutoContinue(t, op)
|
||||
switch answer {
|
||||
case "f": // finish next
|
||||
skipBreakpoints = true
|
||||
fallthrough
|
||||
case "c": // continue once
|
||||
fmt.Printf("continuing...\n")
|
||||
case "s": // stop and cancel
|
||||
fallthrough
|
||||
default:
|
||||
t.client.CancelNext()
|
||||
printfile(t, state.CurrentThread.File, state.CurrentThread.Line, true)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(", continuing...\n")
|
||||
}
|
||||
stateChan := t.client.DirectionCongruentContinue()
|
||||
var state *api.DebuggerState
|
||||
for state = range stateChan {
|
||||
@ -1464,6 +1484,20 @@ func continueUntilCompleteNext(t *Term, state *api.DebuggerState, op string, sho
|
||||
}
|
||||
}
|
||||
|
||||
func promptAutoContinue(t *Term, op string) (string, error) {
|
||||
for {
|
||||
answer, err := t.line.Prompt(fmt.Sprintf("[c] continue [s] stop here and cancel %s, [f] finish %s skipping all breakpoints? ", op, op))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
answer = strings.ToLower(strings.TrimSpace(answer))
|
||||
switch answer {
|
||||
case "f", "c", "s":
|
||||
return answer, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scopePrefixSwitch(t *Term, ctx callContext) error {
|
||||
if ctx.Scope.GoroutineID > 0 {
|
||||
_, err := t.client.SwitchGoroutine(ctx.Scope.GoroutineID)
|
||||
|
@ -582,47 +582,6 @@ func countOccurrences(s, needle string) int {
|
||||
return count
|
||||
}
|
||||
|
||||
func TestIssue387(t *testing.T) {
|
||||
if runtime.GOOS == "freebsd" {
|
||||
t.Skip("test is not valid on FreeBSD")
|
||||
}
|
||||
// a breakpoint triggering during a 'next' operation will interrupt it
|
||||
test.AllowRecording(t)
|
||||
withTestTerminal("issue387", t, func(term *FakeTerminal) {
|
||||
breakpointHitCount := 0
|
||||
term.MustExec("break dostuff")
|
||||
for {
|
||||
outstr, err := term.Exec("continue")
|
||||
breakpointHitCount += countOccurrences(outstr, "issue387.go:8")
|
||||
t.Log(outstr)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "exited") {
|
||||
t.Fatalf("Unexpected error executing 'continue': %v", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
pos := 9
|
||||
|
||||
for {
|
||||
outstr = term.MustExec("next")
|
||||
breakpointHitCount += countOccurrences(outstr, "issue387.go:8")
|
||||
t.Log(outstr)
|
||||
if countOccurrences(outstr, fmt.Sprintf("issue387.go:%d", pos)) == 0 {
|
||||
t.Fatalf("did not continue to expected position %d", pos)
|
||||
}
|
||||
pos++
|
||||
if pos >= 11 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if breakpointHitCount != 10 {
|
||||
t.Fatalf("Breakpoint hit wrong number of times, expected 10 got %d", breakpointHitCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func listIsAt(t *testing.T, term *FakeTerminal, listcmd string, cur, start, end int) {
|
||||
t.Helper()
|
||||
outstr := term.MustExec(listcmd)
|
||||
|
Loading…
Reference in New Issue
Block a user