github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/service/dap/command.go (about)

     1  package dap
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/go-delve/delve/pkg/config"
    11  	"github.com/google/go-dap"
    12  )
    13  
    14  func (s *Session) delveCmd(goid, frame int, cmdstr string) (string, error) {
    15  	vals := strings.SplitN(strings.TrimSpace(cmdstr), " ", 2)
    16  	cmdname := vals[0]
    17  	var args string
    18  	if len(vals) > 1 {
    19  		args = strings.TrimSpace(vals[1])
    20  	}
    21  	for _, cmd := range debugCommands(s) {
    22  		for _, alias := range cmd.aliases {
    23  			if alias == cmdname {
    24  				return cmd.cmdFn(goid, frame, args)
    25  			}
    26  		}
    27  	}
    28  	return "", errNoCmd
    29  }
    30  
    31  type cmdfunc func(goid, frame int, args string) (string, error)
    32  
    33  type command struct {
    34  	aliases []string
    35  	helpMsg string
    36  	cmdFn   cmdfunc
    37  }
    38  
    39  const (
    40  	msgHelp = `Prints the help message.
    41  	
    42  dlv help [command]
    43  
    44  Type "help" followed by the name of a command for more information about it.`
    45  
    46  	msgConfig = `Changes configuration parameters.
    47  	
    48  	dlv config -list
    49  	
    50  		Show all configuration parameters.
    51  
    52  	dlv config -list <parameter>
    53  	
    54  		Show value of a configuration parameter.
    55  	
    56  	dlv config <parameter> <value>
    57  	
    58  		Changes the value of a configuration parameter.
    59  	
    60  	dlv config substitutePath <from> <to>
    61  	dlv config substitutePath <from>
    62  	dlv config substitutePath -clear
    63  	
    64  		Adds or removes a path substitution rule. If -clear is used all substitutePath rules are removed.
    65  		See also Documentation/cli/substitutepath.md.`
    66  	msgSources = `Print list of source files.
    67  
    68  	dlv sources [<regex>]
    69  
    70  If regex is specified only the source files matching it will be returned.`
    71  )
    72  
    73  // debugCommands returns a list of commands with default commands defined.
    74  func debugCommands(s *Session) []command {
    75  	return []command{
    76  		{aliases: []string{"help", "h"}, cmdFn: s.helpMessage, helpMsg: msgHelp},
    77  		{aliases: []string{"config"}, cmdFn: s.evaluateConfig, helpMsg: msgConfig},
    78  		{aliases: []string{"sources", "s"}, cmdFn: s.sources, helpMsg: msgSources},
    79  	}
    80  }
    81  
    82  var errNoCmd = errors.New("command not available")
    83  
    84  func (s *Session) helpMessage(_, _ int, args string) (string, error) {
    85  	var buf bytes.Buffer
    86  	if args != "" {
    87  		for _, cmd := range debugCommands(s) {
    88  			for _, alias := range cmd.aliases {
    89  				if alias == args {
    90  					return cmd.helpMsg, nil
    91  				}
    92  			}
    93  		}
    94  		return "", errNoCmd
    95  	}
    96  
    97  	fmt.Fprintln(&buf, "The following commands are available:")
    98  
    99  	for _, cmd := range debugCommands(s) {
   100  		h := cmd.helpMsg
   101  		if idx := strings.Index(h, "\n"); idx >= 0 {
   102  			h = h[:idx]
   103  		}
   104  		if len(cmd.aliases) > 1 {
   105  			fmt.Fprintf(&buf, "    dlv %s (alias: %s) \t %s\n", cmd.aliases[0], strings.Join(cmd.aliases[1:], " | "), h)
   106  		} else {
   107  			fmt.Fprintf(&buf, "    dlv %s \t %s\n", cmd.aliases[0], h)
   108  		}
   109  	}
   110  
   111  	fmt.Fprintln(&buf)
   112  	fmt.Fprintln(&buf, "Type 'dlv help' followed by a command for full documentation.")
   113  	return buf.String(), nil
   114  }
   115  
   116  func (s *Session) evaluateConfig(_, _ int, expr string) (string, error) {
   117  	argv := config.Split2PartsBySpace(expr)
   118  	name := argv[0]
   119  	if name == "-list" {
   120  		if len(argv) > 1 {
   121  			return config.ConfigureListByName(&s.args, argv[1], "cfgName"), nil
   122  		}
   123  		return listConfig(&s.args), nil
   124  	}
   125  	updated, res, err := configureSet(&s.args, expr)
   126  	if err != nil {
   127  		return "", err
   128  	}
   129  
   130  	if updated {
   131  		// Send invalidated events for areas that are affected by configuration changes.
   132  		switch name {
   133  		case "showGlobalVariables", "showRegisters":
   134  			// Variable data has become invalidated.
   135  			s.send(&dap.InvalidatedEvent{
   136  				Event: *newEvent("invalidated"),
   137  				Body: dap.InvalidatedEventBody{
   138  					Areas: []dap.InvalidatedAreas{"variables"},
   139  				},
   140  			})
   141  		case "goroutineFilters", "hideSystemGoroutines":
   142  			// Thread related data has become invalidated.
   143  			s.send(&dap.InvalidatedEvent{
   144  				Event: *newEvent("invalidated"),
   145  				Body: dap.InvalidatedEventBody{
   146  					Areas: []dap.InvalidatedAreas{"threads"},
   147  				},
   148  			})
   149  		}
   150  		res += "\nUpdated"
   151  	}
   152  	return res, nil
   153  }
   154  
   155  func (s *Session) sources(_, _ int, filter string) (string, error) {
   156  	sources, err := s.debugger.Sources(filter)
   157  	if err != nil {
   158  		return "", err
   159  	}
   160  	sort.Strings(sources)
   161  	return strings.Join(sources, "\n"), nil
   162  }