mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	terminal: Split arguments inside the command function
Print and set need to receive their argument unsplit to support complex expressions
This commit is contained in:
		| @ -5,6 +5,8 @@ package terminal | |||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"go/parser" | ||||||
|  | 	"go/scanner" | ||||||
| 	"io" | 	"io" | ||||||
| 	"math" | 	"math" | ||||||
| 	"os" | 	"os" | ||||||
| @ -19,8 +21,8 @@ import ( | |||||||
| 	"github.com/derekparker/delve/service/debugger" | 	"github.com/derekparker/delve/service/debugger" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type cmdfunc func(t *Term, args ...string) error | type cmdfunc func(t *Term, args string) error | ||||||
| type scopedCmdfunc func(t *Term, scope api.EvalScope, args ...string) error | type scopedCmdfunc func(t *Term, scope api.EvalScope, args string) error | ||||||
|  |  | ||||||
| type filteringFunc func(t *Term, filter string) ([]string, error) | type filteringFunc func(t *Term, filter string) ([]string, error) | ||||||
| type scopedFilteringFunc func(t *Term, scope api.EvalScope, filter string) ([]string, error) | type scopedFilteringFunc func(t *Term, scope api.EvalScope, filter string) ([]string, error) | ||||||
| @ -129,20 +131,20 @@ func (c *Commands) Merge(allAliases map[string][]string) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func CommandFunc(fn func() error) cmdfunc { | func CommandFunc(fn func() error) cmdfunc { | ||||||
| 	return func(t *Term, args ...string) error { | 	return func(t *Term, args string) error { | ||||||
| 		return fn() | 		return fn() | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func noCmdAvailable(t *Term, args ...string) error { | func noCmdAvailable(t *Term, args string) error { | ||||||
| 	return fmt.Errorf("command not available") | 	return fmt.Errorf("command not available") | ||||||
| } | } | ||||||
|  |  | ||||||
| func nullCommand(t *Term, args ...string) error { | func nullCommand(t *Term, args string) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *Commands) help(t *Term, args ...string) error { | func (c *Commands) help(t *Term, args string) error { | ||||||
| 	fmt.Println("The following commands are available:") | 	fmt.Println("The following commands are available:") | ||||||
| 	w := new(tabwriter.Writer) | 	w := new(tabwriter.Writer) | ||||||
| 	w.Init(os.Stdout, 0, 8, 0, '-', 0) | 	w.Init(os.Stdout, 0, 8, 0, '-', 0) | ||||||
| @ -162,7 +164,7 @@ func (a byThreadID) Len() int           { return len(a) } | |||||||
| func (a byThreadID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | func (a byThreadID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | ||||||
| func (a byThreadID) Less(i, j int) bool { return a[i].ID < a[j].ID } | func (a byThreadID) Less(i, j int) bool { return a[i].ID < a[j].ID } | ||||||
|  |  | ||||||
| func threads(t *Term, args ...string) error { | func threads(t *Term, args string) error { | ||||||
| 	threads, err := t.client.ListThreads() | 	threads, err := t.client.ListThreads() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @ -188,11 +190,11 @@ func threads(t *Term, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func thread(t *Term, args ...string) error { | func thread(t *Term, args string) error { | ||||||
| 	if len(args) == 0 { | 	if len(args) == 0 { | ||||||
| 		return fmt.Errorf("you must specify a thread") | 		return fmt.Errorf("you must specify a thread") | ||||||
| 	} | 	} | ||||||
| 	tid, err := strconv.Atoi(args[0]) | 	tid, err := strconv.Atoi(args) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @ -223,7 +225,8 @@ func (a byGoroutineID) Len() int           { return len(a) } | |||||||
| func (a byGoroutineID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | func (a byGoroutineID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | ||||||
| func (a byGoroutineID) Less(i, j int) bool { return a[i].ID < a[j].ID } | func (a byGoroutineID) Less(i, j int) bool { return a[i].ID < a[j].ID } | ||||||
|  |  | ||||||
| func goroutines(t *Term, args ...string) error { | func goroutines(t *Term, argstr string) error { | ||||||
|  | 	args := strings.Split(argstr, " ") | ||||||
| 	var fgl = fglUserCurrent | 	var fgl = fglUserCurrent | ||||||
|  |  | ||||||
| 	switch len(args) { | 	switch len(args) { | ||||||
| @ -263,13 +266,13 @@ func goroutines(t *Term, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func goroutine(t *Term, args ...string) error { | func goroutine(t *Term, argstr string) error { | ||||||
| 	switch len(args) { | 	if argstr == "" { | ||||||
| 	case 0: |  | ||||||
| 		return printscope(t) | 		return printscope(t) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	case 1: | 	if strings.Index(argstr, " ") < 0 { | ||||||
| 		gid, err := strconv.Atoi(args[0]) | 		gid, err := strconv.Atoi(argstr) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @ -285,54 +288,61 @@ func goroutine(t *Term, args ...string) error { | |||||||
|  |  | ||||||
| 		fmt.Printf("Switched from %d to %d (thread %d)\n", oldState.SelectedGoroutine.ID, gid, newState.CurrentThread.ID) | 		fmt.Printf("Switched from %d to %d (thread %d)\n", oldState.SelectedGoroutine.ID, gid, newState.CurrentThread.ID) | ||||||
| 		return nil | 		return nil | ||||||
|  |  | ||||||
| 	default: |  | ||||||
| 		return scopePrefix(t, "goroutine", args...) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	return scopePrefix(t, "goroutine "+argstr) | ||||||
| } | } | ||||||
|  |  | ||||||
| func frame(t *Term, args ...string) error { | func frame(t *Term, args string) error { | ||||||
| 	return scopePrefix(t, "frame", args...) | 	return scopePrefix(t, "frame "+args) | ||||||
| } | } | ||||||
|  |  | ||||||
| func scopePrefix(t *Term, cmdname string, pargs ...string) error { | func scopePrefix(t *Term, cmdstr string) error { | ||||||
| 	fullargs := make([]string, 0, len(pargs)+1) |  | ||||||
| 	fullargs = append(fullargs, cmdname) |  | ||||||
| 	fullargs = append(fullargs, pargs...) |  | ||||||
|  |  | ||||||
| 	scope := api.EvalScope{-1, 0} | 	scope := api.EvalScope{-1, 0} | ||||||
| 	lastcmd := "" | 	lastcmd := "" | ||||||
|  | 	rest := cmdstr | ||||||
|  |  | ||||||
| 	callFilterSortAndOutput := func(fn scopedFilteringFunc, fnargs []string) error { | 	nexttok := func() string { | ||||||
|  | 		v := strings.SplitN(rest, " ", 2) | ||||||
|  | 		if len(v) > 1 { | ||||||
|  | 			rest = v[1] | ||||||
|  | 		} else { | ||||||
|  | 			rest = "" | ||||||
|  | 		} | ||||||
|  | 		return v[0] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	callFilterSortAndOutput := func(fn scopedFilteringFunc, fnargs string) error { | ||||||
| 		outfn := filterSortAndOutput(func(t *Term, filter string) ([]string, error) { | 		outfn := filterSortAndOutput(func(t *Term, filter string) ([]string, error) { | ||||||
| 			return fn(t, scope, filter) | 			return fn(t, scope, filter) | ||||||
| 		}) | 		}) | ||||||
| 		return outfn(t, fnargs...) | 		return outfn(t, fnargs) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for i := 0; i < len(fullargs); i++ { | 	for { | ||||||
| 		lastcmd = fullargs[i] | 		cmd := nexttok() | ||||||
| 		switch fullargs[i] { | 		if cmd == "" && rest == "" { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		switch cmd { | ||||||
| 		case "goroutine": | 		case "goroutine": | ||||||
| 			if i+1 >= len(fullargs) { | 			if rest == "" { | ||||||
| 				return fmt.Errorf("goroutine command needs an argument") | 				return fmt.Errorf("goroutine command needs an argument") | ||||||
| 			} | 			} | ||||||
| 			n, err := strconv.Atoi(fullargs[i+1]) | 			n, err := strconv.Atoi(nexttok()) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return fmt.Errorf("invalid argument to goroutine, expected integer") | 				return fmt.Errorf("invalid argument to goroutine, expected integer") | ||||||
| 			} | 			} | ||||||
| 			scope.GoroutineID = int(n) | 			scope.GoroutineID = int(n) | ||||||
| 			i++ |  | ||||||
| 		case "frame": | 		case "frame": | ||||||
| 			if i+1 >= len(fullargs) { | 			if rest == "" { | ||||||
| 				return fmt.Errorf("frame command needs an argument") | 				return fmt.Errorf("frame command needs an argument") | ||||||
| 			} | 			} | ||||||
| 			n, err := strconv.Atoi(fullargs[i+1]) | 			n, err := strconv.Atoi(nexttok()) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return fmt.Errorf("invalid argument to frame, expected integer") | 				return fmt.Errorf("invalid argument to frame, expected integer") | ||||||
| 			} | 			} | ||||||
| 			scope.Frame = int(n) | 			scope.Frame = int(n) | ||||||
| 			i++ |  | ||||||
| 		case "list", "ls": | 		case "list", "ls": | ||||||
| 			frame, gid := scope.Frame, scope.GoroutineID | 			frame, gid := scope.Frame, scope.GoroutineID | ||||||
| 			locs, err := t.client.Stacktrace(gid, frame, false) | 			locs, err := t.client.Stacktrace(gid, frame, false) | ||||||
| @ -345,7 +355,7 @@ func scopePrefix(t *Term, cmdname string, pargs ...string) error { | |||||||
| 			loc := locs[frame] | 			loc := locs[frame] | ||||||
| 			return printfile(t, loc.File, loc.Line, true) | 			return printfile(t, loc.File, loc.Line, true) | ||||||
| 		case "stack", "bt": | 		case "stack", "bt": | ||||||
| 			depth, full, err := parseStackArgs(fullargs[i+1:]) | 			depth, full, err := parseStackArgs(rest) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| @ -356,14 +366,17 @@ func scopePrefix(t *Term, cmdname string, pargs ...string) error { | |||||||
| 			printStack(stack, "") | 			printStack(stack, "") | ||||||
| 			return nil | 			return nil | ||||||
| 		case "locals": | 		case "locals": | ||||||
| 			return callFilterSortAndOutput(locals, fullargs[i+1:]) | 			return callFilterSortAndOutput(locals, rest) | ||||||
| 		case "args": | 		case "args": | ||||||
| 			return callFilterSortAndOutput(args, fullargs[i+1:]) | 			return callFilterSortAndOutput(args, rest) | ||||||
| 		case "print", "p": | 		case "print", "p": | ||||||
| 			return printVar(t, scope, fullargs[i+1:]...) | 			return printVar(t, scope, rest) | ||||||
|  | 		case "set": | ||||||
|  | 			return setVar(t, scope, rest) | ||||||
| 		default: | 		default: | ||||||
| 			return fmt.Errorf("unknown command %s", fullargs[i]) | 			return fmt.Errorf("unknown command %s", cmd) | ||||||
| 		} | 		} | ||||||
|  | 		lastcmd = cmd | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return fmt.Errorf("no command passed to %s", lastcmd) | 	return fmt.Errorf("no command passed to %s", lastcmd) | ||||||
| @ -433,7 +446,7 @@ func writeGoroutineLong(w io.Writer, g *api.Goroutine, prefix string) { | |||||||
| 		prefix, formatLocation(g.GoStatementLoc)) | 		prefix, formatLocation(g.GoStatementLoc)) | ||||||
| } | } | ||||||
|  |  | ||||||
| func restart(t *Term, args ...string) error { | func restart(t *Term, args string) error { | ||||||
| 	if err := t.client.Restart(); err != nil { | 	if err := t.client.Restart(); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @ -441,7 +454,7 @@ func restart(t *Term, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func cont(t *Term, args ...string) error { | func cont(t *Term, args string) error { | ||||||
| 	stateChan := t.client.Continue() | 	stateChan := t.client.Continue() | ||||||
| 	for state := range stateChan { | 	for state := range stateChan { | ||||||
| 		if state.Err != nil { | 		if state.Err != nil { | ||||||
| @ -452,7 +465,7 @@ func cont(t *Term, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func step(t *Term, args ...string) error { | func step(t *Term, args string) error { | ||||||
| 	state, err := t.client.Step() | 	state, err := t.client.Step() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @ -461,7 +474,7 @@ func step(t *Term, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func next(t *Term, args ...string) error { | func next(t *Term, args string) error { | ||||||
| 	state, err := t.client.Next() | 	state, err := t.client.Next() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @ -470,11 +483,11 @@ func next(t *Term, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func clear(t *Term, args ...string) error { | func clear(t *Term, args string) error { | ||||||
| 	if len(args) == 0 { | 	if len(args) == 0 { | ||||||
| 		return fmt.Errorf("not enough arguments") | 		return fmt.Errorf("not enough arguments") | ||||||
| 	} | 	} | ||||||
| 	id, err := strconv.Atoi(args[0]) | 	id, err := strconv.Atoi(args) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @ -486,15 +499,15 @@ func clear(t *Term, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func clearAll(t *Term, args ...string) error { | func clearAll(t *Term, args string) error { | ||||||
| 	breakPoints, err := t.client.ListBreakpoints() | 	breakPoints, err := t.client.ListBreakpoints() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var locPCs map[uint64]struct{} | 	var locPCs map[uint64]struct{} | ||||||
| 	if len(args) > 0 { | 	if args != "" { | ||||||
| 		locs, err := t.client.FindLocation(api.EvalScope{-1, 0}, args[0]) | 		locs, err := t.client.FindLocation(api.EvalScope{-1, 0}, args) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @ -526,7 +539,7 @@ func (a ById) Len() int           { return len(a) } | |||||||
| func (a ById) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | func (a ById) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | ||||||
| func (a ById) Less(i, j int) bool { return a[i].ID < a[j].ID } | func (a ById) Less(i, j int) bool { return a[i].ID < a[j].ID } | ||||||
|  |  | ||||||
| func breakpoints(t *Term, args ...string) error { | func breakpoints(t *Term, args string) error { | ||||||
| 	breakPoints, err := t.client.ListBreakpoints() | 	breakPoints, err := t.client.ListBreakpoints() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @ -557,7 +570,8 @@ func breakpoints(t *Term, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func setBreakpoint(t *Term, tracepoint bool, args ...string) error { | func setBreakpoint(t *Term, tracepoint bool, argstr string) error { | ||||||
|  | 	args := strings.Split(argstr, " ") | ||||||
| 	if len(args) < 1 { | 	if len(args) < 1 { | ||||||
| 		return fmt.Errorf("address required, specify either a function name or <file:line>") | 		return fmt.Errorf("address required, specify either a function name or <file:line>") | ||||||
| 	} | 	} | ||||||
| @ -601,17 +615,17 @@ func setBreakpoint(t *Term, tracepoint bool, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func breakpoint(t *Term, args ...string) error { | func breakpoint(t *Term, args string) error { | ||||||
| 	return setBreakpoint(t, false, args...) | 	return setBreakpoint(t, false, args) | ||||||
| } | } | ||||||
|  |  | ||||||
| func tracepoint(t *Term, args ...string) error { | func tracepoint(t *Term, args string) error { | ||||||
| 	return setBreakpoint(t, true, args...) | 	return setBreakpoint(t, true, args) | ||||||
| } | } | ||||||
|  |  | ||||||
| func g0f0(fn scopedCmdfunc) cmdfunc { | func g0f0(fn scopedCmdfunc) cmdfunc { | ||||||
| 	return func(t *Term, args ...string) error { | 	return func(t *Term, args string) error { | ||||||
| 		return fn(t, api.EvalScope{-1, 0}, args...) | 		return fn(t, api.EvalScope{-1, 0}, args) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -621,11 +635,11 @@ func g0f0filter(fn scopedFilteringFunc) filteringFunc { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func printVar(t *Term, scope api.EvalScope, args ...string) error { | func printVar(t *Term, scope api.EvalScope, args string) error { | ||||||
| 	if len(args) == 0 { | 	if len(args) == 0 { | ||||||
| 		return fmt.Errorf("not enough arguments") | 		return fmt.Errorf("not enough arguments") | ||||||
| 	} | 	} | ||||||
| 	val, err := t.client.EvalVariable(scope, args[0]) | 	val, err := t.client.EvalVariable(scope, args) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @ -634,12 +648,21 @@ func printVar(t *Term, scope api.EvalScope, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func setVar(t *Term, scope api.EvalScope, args ...string) error { | func setVar(t *Term, scope api.EvalScope, args string) error { | ||||||
| 	if len(args) != 2 { | 	// HACK: in go '=' is not an operator, we detect the error and try to recover from it by splitting the input string | ||||||
| 		return fmt.Errorf("wrong number of arguments") | 	_, err := parser.ParseExpr(args) | ||||||
|  | 	if err == nil { | ||||||
|  | 		return fmt.Errorf("syntax error '=' not found") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return t.client.SetVariable(scope, args[0], args[1]) | 	el, ok := err.(scanner.ErrorList) | ||||||
|  | 	if !ok || el[0].Msg != "expected '==', found '='" { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	lexpr := args[:el[0].Pos.Offset] | ||||||
|  | 	rexpr := args[el[0].Pos.Offset+1:] | ||||||
|  | 	return t.client.SetVariable(scope, lexpr, rexpr) | ||||||
| } | } | ||||||
|  |  | ||||||
| func filterVariables(vars []api.Variable, filter string) []string { | func filterVariables(vars []api.Variable, filter string) []string { | ||||||
| @ -689,7 +712,7 @@ func vars(t *Term, filter string) ([]string, error) { | |||||||
| 	return filterVariables(vars, filter), nil | 	return filterVariables(vars, filter), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func regs(t *Term, args ...string) error { | func regs(t *Term, args string) error { | ||||||
| 	regs, err := t.client.ListRegisters() | 	regs, err := t.client.ListRegisters() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @ -699,13 +722,13 @@ func regs(t *Term, args ...string) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func filterSortAndOutput(fn filteringFunc) cmdfunc { | func filterSortAndOutput(fn filteringFunc) cmdfunc { | ||||||
| 	return func(t *Term, args ...string) error { | 	return func(t *Term, args string) error { | ||||||
| 		var filter string | 		var filter string | ||||||
| 		if len(args) == 1 { | 		if len(args) > 0 { | ||||||
| 			if _, err := regexp.Compile(args[0]); err != nil { | 			if _, err := regexp.Compile(args); err != nil { | ||||||
| 				return fmt.Errorf("invalid filter argument: %s", err.Error()) | 				return fmt.Errorf("invalid filter argument: %s", err.Error()) | ||||||
| 			} | 			} | ||||||
| 			filter = args[0] | 			filter = args | ||||||
| 		} | 		} | ||||||
| 		data, err := fn(t, filter) | 		data, err := fn(t, filter) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @ -719,7 +742,7 @@ func filterSortAndOutput(fn filteringFunc) cmdfunc { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func stackCommand(t *Term, args ...string) error { | func stackCommand(t *Term, args string) error { | ||||||
| 	var ( | 	var ( | ||||||
| 		err         error | 		err         error | ||||||
| 		goroutineid = -1 | 		goroutineid = -1 | ||||||
| @ -736,11 +759,13 @@ func stackCommand(t *Term, args ...string) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func parseStackArgs(args []string) (int, bool, error) { | func parseStackArgs(argstr string) (int, bool, error) { | ||||||
| 	var ( | 	var ( | ||||||
| 		depth = 10 | 		depth = 10 | ||||||
| 		full  = false | 		full  = false | ||||||
| 	) | 	) | ||||||
|  | 	if argstr != "" { | ||||||
|  | 		args := strings.Split(argstr, " ") | ||||||
| 		for i := range args { | 		for i := range args { | ||||||
| 			if args[i] == "-full" { | 			if args[i] == "-full" { | ||||||
| 				full = true | 				full = true | ||||||
| @ -752,10 +777,11 @@ func parseStackArgs(args []string) (int, bool, error) { | |||||||
| 				depth = n | 				depth = n | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	return depth, full, nil | 	return depth, full, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func listCommand(t *Term, args ...string) error { | func listCommand(t *Term, args string) error { | ||||||
| 	if len(args) == 0 { | 	if len(args) == 0 { | ||||||
| 		state, err := t.client.GetState() | 		state, err := t.client.GetState() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @ -765,23 +791,23 @@ func listCommand(t *Term, args ...string) error { | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	locs, err := t.client.FindLocation(api.EvalScope{-1, 0}, args[0]) | 	locs, err := t.client.FindLocation(api.EvalScope{-1, 0}, args) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if len(locs) > 1 { | 	if len(locs) > 1 { | ||||||
| 		return debugger.AmbiguousLocationError{Location: args[0], CandidatesLocation: locs} | 		return debugger.AmbiguousLocationError{Location: args, CandidatesLocation: locs} | ||||||
| 	} | 	} | ||||||
| 	printfile(t, locs[0].File, locs[0].Line, false) | 	printfile(t, locs[0].File, locs[0].Line, false) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (cmds *Commands) sourceCommand(t *Term, args ...string) error { | func (cmds *Commands) sourceCommand(t *Term, args string) error { | ||||||
| 	if len(args) != 1 { | 	if len(args) != 1 { | ||||||
| 		return fmt.Errorf("wrong number of arguments: source <filename>") | 		return fmt.Errorf("wrong number of arguments: source <filename>") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return cmds.executeFile(t, args[0]) | 	return cmds.executeFile(t, args) | ||||||
| } | } | ||||||
|  |  | ||||||
| func digits(n int) int { | func digits(n int) int { | ||||||
| @ -925,7 +951,7 @@ func (ere ExitRequestError) Error() string { | |||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func exitCommand(t *Term, args ...string) error { | func exitCommand(t *Term, args string) error { | ||||||
| 	return ExitRequestError{} | 	return ExitRequestError{} | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -953,7 +979,7 @@ func (cmds *Commands) executeFile(t *Term, name string) error { | |||||||
|  |  | ||||||
| 		cmdstr, args := parseCommand(line) | 		cmdstr, args := parseCommand(line) | ||||||
| 		cmd := cmds.Find(cmdstr) | 		cmd := cmds.Find(cmdstr) | ||||||
| 		err := cmd(t, args...) | 		err := cmd(t, args) | ||||||
|  |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			fmt.Printf("%s:%d: %v\n", name, lineno, err) | 			fmt.Printf("%s:%d: %v\n", name, lineno, err) | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ func TestCommandDefault(t *testing.T) { | |||||||
| 		cmd  = cmds.Find("non-existant-command") | 		cmd  = cmds.Find("non-existant-command") | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	err := cmd(nil) | 	err := cmd(nil, "") | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		t.Fatal("cmd() did not default") | 		t.Fatal("cmd() did not default") | ||||||
| 	} | 	} | ||||||
| @ -26,16 +26,16 @@ func TestCommandDefault(t *testing.T) { | |||||||
|  |  | ||||||
| func TestCommandReplay(t *testing.T) { | func TestCommandReplay(t *testing.T) { | ||||||
| 	cmds := DebugCommands(nil) | 	cmds := DebugCommands(nil) | ||||||
| 	cmds.Register("foo", func(t *Term, args ...string) error { return fmt.Errorf("registered command") }, "foo command") | 	cmds.Register("foo", func(t *Term, args string) error { return fmt.Errorf("registered command") }, "foo command") | ||||||
| 	cmd := cmds.Find("foo") | 	cmd := cmds.Find("foo") | ||||||
|  |  | ||||||
| 	err := cmd(nil) | 	err := cmd(nil, "") | ||||||
| 	if err.Error() != "registered command" { | 	if err.Error() != "registered command" { | ||||||
| 		t.Fatal("wrong command output") | 		t.Fatal("wrong command output") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	cmd = cmds.Find("") | 	cmd = cmds.Find("") | ||||||
| 	err = cmd(nil) | 	err = cmd(nil, "") | ||||||
| 	if err.Error() != "registered command" { | 	if err.Error() != "registered command" { | ||||||
| 		t.Fatal("wrong command output") | 		t.Fatal("wrong command output") | ||||||
| 	} | 	} | ||||||
| @ -45,7 +45,7 @@ func TestCommandReplayWithoutPreviousCommand(t *testing.T) { | |||||||
| 	var ( | 	var ( | ||||||
| 		cmds = DebugCommands(nil) | 		cmds = DebugCommands(nil) | ||||||
| 		cmd  = cmds.Find("") | 		cmd  = cmds.Find("") | ||||||
| 		err  = cmd(nil) | 		err  = cmd(nil, "") | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -59,7 +59,7 @@ func TestCommandThread(t *testing.T) { | |||||||
| 		cmd  = cmds.Find("thread") | 		cmd  = cmds.Find("thread") | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	err := cmd(nil) | 	err := cmd(nil, "") | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		t.Fatal("thread terminal command did not default") | 		t.Fatal("thread terminal command did not default") | ||||||
| 	} | 	} | ||||||
| @ -75,11 +75,11 @@ func TestExecuteFile(t *testing.T) { | |||||||
| 	c := &Commands{ | 	c := &Commands{ | ||||||
| 		client: nil, | 		client: nil, | ||||||
| 		cmds: []command{ | 		cmds: []command{ | ||||||
| 			{aliases: []string{"trace"}, cmdFn: func(t *Term, args ...string) error { | 			{aliases: []string{"trace"}, cmdFn: func(t *Term, args string) error { | ||||||
| 				traceCount++ | 				traceCount++ | ||||||
| 				return nil | 				return nil | ||||||
| 			}}, | 			}}, | ||||||
| 			{aliases: []string{"break"}, cmdFn: func(t *Term, args ...string) error { | 			{aliases: []string{"break"}, cmdFn: func(t *Term, args string) error { | ||||||
| 				breakCount++ | 				breakCount++ | ||||||
| 				return nil | 				return nil | ||||||
| 			}}, | 			}}, | ||||||
|  | |||||||
| @ -107,7 +107,7 @@ func (t *Term) Run() (error, int) { | |||||||
|  |  | ||||||
| 		cmdstr, args := parseCommand(cmdstr) | 		cmdstr, args := parseCommand(cmdstr) | ||||||
| 		cmd := cmds.Find(cmdstr) | 		cmd := cmds.Find(cmdstr) | ||||||
| 		if err := cmd(t, args...); err != nil { | 		if err := cmd(t, args); err != nil { | ||||||
| 			if _, ok := err.(ExitRequestError); ok { | 			if _, ok := err.(ExitRequestError); ok { | ||||||
| 				return t.handleExit() | 				return t.handleExit() | ||||||
| 			} | 			} | ||||||
| @ -182,7 +182,10 @@ func (t *Term) handleExit() (error, int) { | |||||||
| 	return nil, 0 | 	return nil, 0 | ||||||
| } | } | ||||||
|  |  | ||||||
| func parseCommand(cmdstr string) (string, []string) { | func parseCommand(cmdstr string) (string, string) { | ||||||
| 	vals := strings.Split(cmdstr, " ") | 	vals := strings.SplitN(cmdstr, " ", 2) | ||||||
| 	return vals[0], vals[1:] | 	if len(vals) == 1 { | ||||||
|  | 		return vals[0], "" | ||||||
|  | 	} | ||||||
|  | 	return vals[0], strings.TrimSpace(vals[1]) | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 aarzilli
					aarzilli