From 25727f9d944148e3a79e8c3bce94d54cab893608 Mon Sep 17 00:00:00 2001 From: Son Tran-Nguyen Date: Mon, 31 May 2021 14:27:17 -0500 Subject: [PATCH] feat: optional param An option can be set as optional through the syntax: `$VARIABLE:-default` `default` can be empty, but `-` is required to make the param optional. See README for examples. Closes #3 --- README.md | 7 +++++++ command.go | 30 +++++++++++++++++++++--------- utils.go | 17 +++++++++-------- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 681e966..b54a0c3 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,15 @@ options: ## Examples ```shell +# Command with no param. shell2discord /hello 'echo "World"' +# Optional param `word` with empty default value. +shell2discord /hello 'echo "Hello ${word-}"' +# Optional param `word` with default value of "World". +shell2discord /hello 'echo "Hello ${word-World}"' +# Command with required params. shell2discord /mirror 'curl "${url}" > "${outfile}"' +# Command with allowed environment variables. shell2discord --export-vars=GOOGLE_MAPS_API_KEY \ /geocode 'curl "https://maps.googleapis.com/maps/api/geocode/json?latlng=${latlng}&key=$GOOGLE_MAPS_API_KEY"' ``` diff --git a/command.go b/command.go index 8088563..31353a1 100644 --- a/command.go +++ b/command.go @@ -11,24 +11,26 @@ import ( type Command struct { *discordgo.ApplicationCommand Script string + Params map[string]string Env []string } // Creates a new command from `/command 'shell command'`. func NewCommand(slashCommand string, shellCommand string) *Command { commandName, params := parseBotCommand(slashCommand, shellCommand) - paramsLen := len(params) - options := make([]*discordgo.ApplicationCommandOption, paramsLen) - for i := 0; i < paramsLen; i++ { - options[i] = &discordgo.ApplicationCommandOption{ + options := []*discordgo.ApplicationCommandOption{} + for paramName, paramValue := range params { + option := &discordgo.ApplicationCommandOption{ // Shell variables have no type, so we just use String in Discord. Type: discordgo.ApplicationCommandOptionString, - Name: params[i], + Name: paramName, // @TODO: Parse option description from flag. - Description: params[i], - Required: true, + Description: paramName, + Required: paramValue == "", } + + options = append(options, option) } return &Command{ @@ -38,6 +40,7 @@ func NewCommand(slashCommand string, shellCommand string) *Command { Options: options, }, Script: shellCommand, + Params: params, } } @@ -55,10 +58,19 @@ func (command Command) Exec(session *discordgo.Session, interaction *discordgo.I var options = interaction.Data.Options shellCommand := command.Script + params := command.Params for i := 0; i < len(options); i++ { option := options[i] - variable := fmt.Sprintf("${%s}", option.Name) - shellCommand = strings.Replace(shellCommand, variable, option.StringValue(), -1) + optionName := option.Name + defaultValue := params[optionName] + variable := fmt.Sprintf("${%s%s}", optionName, defaultValue) + value := option.StringValue() + // Optional option will have empty value, use default value instead. + if value == "" { + // Default value has a `-` at the begining. + value = defaultValue[1:] + } + shellCommand = strings.Replace(shellCommand, variable, value, -1) } var reply string diff --git a/utils.go b/utils.go index 1a57602..516cb73 100644 --- a/utils.go +++ b/utils.go @@ -10,7 +10,7 @@ import ( ) // parseBotCommand - parse command-line arguments for one bot command -func parseBotCommand(slashCommand string, shellCommand string) (commandName string, params []string) { +func parseBotCommand(slashCommand string, shellCommand string) (commandName string, params map[string]string) { commandRe := regexp.MustCompile(`^/([\w-]{1,32})$`) commandMatches := commandRe.FindStringSubmatch(slashCommand) @@ -19,17 +19,18 @@ func parseBotCommand(slashCommand string, shellCommand string) (commandName stri } commandName = commandMatches[1] - paramsRe := regexp.MustCompile(`\${(\w+)}`) + // Parse variable with optional default value, `${foo-bar}` + paramsRe := regexp.MustCompile(`\${(\w+)(-\w*)?}`) matches := paramsRe.FindAllStringSubmatch(shellCommand, -1) matchesLen := len(matches) - paramsMap := map[string]bool{} - + params = map[string]string{} for i := 0; i < matchesLen; i++ { - param := matches[i][1] - if !paramsMap[param] { - params = append(params, param) - paramsMap[param] = true + name := matches[i][1] + value := matches[i][2] + + if _, ok := params[name]; !ok { + params[name] = value } }