Skip to content

Commit

Permalink
Add config option to allow defining a custom shell path.
Browse files Browse the repository at this point in the history
  • Loading branch information
lemoony committed Feb 14, 2022
1 parent 7f57770 commit 9c8cf59
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 7 deletions.
22 changes: 19 additions & 3 deletions docs/configuration/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ snipkit manager add

For more information on the different managers supported, please see [Managers][managers].

## Editor
## Config options

### Editor

When typing `snipkit config edit` the configuration file will be opened in an editor of your choice.

Expand All @@ -64,7 +66,21 @@ config:
If no value is provided at all, SnipKit will try to use `vim`.

## Theme
### Shell

The shell for script executions is defined by the `$SHELL` environment variable. This behavior can be overwritten by
setting the `shell` option to a non-empty string, e.g.:

```yaml
version: 1.0.0
config:
shell: "/bin/zsh"
```

If neither `$SHELL` nor the config option `shell` is defined, SnipKit will try to use `/bin/bash` as a fallback value.


### Theme

SnipKit supports multiple themes out of the box and also allows you to define your own themes:

Expand All @@ -79,7 +95,7 @@ must be located at `<SNIPKIT_HOME>/<xxx>.yaml`.

For a list of supported default themes, have a look at the [Themes][themes] page.

## Default Root Command
### Default Root Command

Most of the time, you want to call the same subcommand, e.g. `print` or `exec`. You can configure `snipkit` so that this
command gets executed by default:
Expand Down
8 changes: 5 additions & 3 deletions internal/app/app_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/lemoony/snipkit/internal/utils/stringutil"
)

const fallbackShell = "/bin/bash"

func (a *appImpl) LookupAndExecuteSnippet() {
snippet := a.LookupSnippet()
if snippet == nil {
Expand All @@ -21,12 +23,12 @@ func (a *appImpl) LookupAndExecuteSnippet() {
parameters := parser.ParseParameters(snippet.GetContent())
if parameterValues, ok := a.tui.ShowParameterForm(parameters, ui.OkButtonExecute); ok {
script := parser.CreateSnippet(snippet.GetContent(), parameters, parameterValues)
executeScript(script)
executeScript(script, a.config.Shell)
}
}

func executeScript(script string) {
shell := stringutil.StringOrDefault(os.Getenv("SHELL"), "/bin/bash")
func executeScript(script, configuredShell string) {
shell := stringutil.FirstNotEmpty(configuredShell, os.Getenv("SHELL"), fallbackShell)

//nolint:gosec // since it would report G204 complaining about using a variable as input for exec.Command
cmd := exec.Command(shell, "-c", script)
Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type VersionWrapper struct {
type Config struct {
Style ui.Config `yaml:"style" mapstructure:"style"`
Editor string `yaml:"editor" mapstructure:"editor" head_comment:"Your preferred editor to open the config file when typing 'snipkit config edit'." line_comment:"Defaults to a reasonable value for your operation system when empty."`
Shell string `yaml:"shell" mapstructure:"shell" head_comment:"The path to the shell to execute scripts with. If not set or empty, $SHELL will be used instead. Fallback is '/bin/bash'."`
DefaultRootCommand string `yaml:"defaultRootCommand" mapstructure:"defaultRootCommand" head_comment:"The command which should run if you don't provide any subcommand." line_comment:"If not set, the help text will be shown."`
Manager managers.Config `yaml:"manager" mapstructure:"manager"`
}
1 change: 1 addition & 0 deletions internal/config/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func Test_serializeToYamlWithComment(t *testing.T) {
var testConfig VersionWrapper
testConfig.Version = "1.0.0"
testConfig.Config.Editor = "foo-editor"
testConfig.Config.Shell = "/bin/zsh"
testConfig.Config.Style.Theme = "simple"
testConfig.Config.Manager.SnippetsLab = &snippetslab.Config{}
testConfig.Config.Manager.SnippetsLab.Enabled = true
Expand Down
2 changes: 2 additions & 0 deletions internal/config/testdata/example-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ config:
theme: simple
# Your preferred editor to open the config file when typing 'snipkit config edit'.
editor: foo-editor # Defaults to a reasonable value for your operation system when empty.
# The path to the shell to execute scripts with. If not set or empty, $SHELL will be used instead. Fallback is '/bin/bash'.
shell: /bin/zsh
# The command which should run if you don't provide any subcommand.
defaultRootCommand: "" # If not set, the help text will be shown.
manager:
Expand Down
9 changes: 9 additions & 0 deletions internal/utils/stringutil/string_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,12 @@ func SplitWithEscape(s string, split uint8, escape uint8, trim bool) []string {

return result
}

func FirstNotEmpty(values ...string) string {
for _, value := range values {
if value != "" {
return value
}
}
return ""
}
21 changes: 20 additions & 1 deletion internal/utils/stringutil/string_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,29 @@ func Test_SplitWithSingleEscapedCharacter(t *testing.T) {
assert.Equal(t, "String without split, character", splits[0])
}

func Test_SplitWihtoutTrimming(t *testing.T) {
func Test_SplitWithoutTrimming(t *testing.T) {
s := " One, Two"
splits := SplitWithEscape(s, ',', '\\', false)
assert.Len(t, splits, 2)
assert.Equal(t, " One", splits[0])
assert.Equal(t, " Two", splits[1])
}

func Test_FirstNotEmpty(t *testing.T) {
tests := []struct {
name string
values []string
expected string
}{
{name: "no values", values: []string{}, expected: ""},
{name: "nil", values: nil, expected: ""},
{name: "first value", values: []string{"first", ""}, expected: "first"},
{name: "last value", values: []string{"", "last"}, expected: "last"},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, FirstNotEmpty(tt.values...))
})
}
}

0 comments on commit 9c8cf59

Please sign in to comment.