diff --git a/pkg/commands/git_cmd_obj_builder.go b/pkg/commands/git_cmd_obj_builder.go index 21f300bb379..7cb4f149641 100644 --- a/pkg/commands/git_cmd_obj_builder.go +++ b/pkg/commands/git_cmd_obj_builder.go @@ -38,6 +38,10 @@ func (self *gitCmdObjBuilder) NewShell(cmdStr string) oscommands.ICmdObj { return self.innerBuilder.NewShell(cmdStr).AddEnvVars(defaultEnvVar) } +func (self *gitCmdObjBuilder) NewInteractiveShell(cmdStr string) oscommands.ICmdObj { + return self.innerBuilder.NewInteractiveShell(cmdStr).AddEnvVars(defaultEnvVar) +} + func (self *gitCmdObjBuilder) Quote(str string) string { return self.innerBuilder.Quote(str) } diff --git a/pkg/commands/oscommands/cmd_obj_builder.go b/pkg/commands/oscommands/cmd_obj_builder.go index 540487ed46e..3e89ce10293 100644 --- a/pkg/commands/oscommands/cmd_obj_builder.go +++ b/pkg/commands/oscommands/cmd_obj_builder.go @@ -14,6 +14,8 @@ type ICmdObjBuilder interface { New(args []string) ICmdObj // NewShell takes a string like `git commit` and returns an executable shell command for it e.g. `sh -c 'git commit'` NewShell(commandStr string) ICmdObj + // Like NewShell, but uses the user's shell rather than "bash", and passes -i to it + NewInteractiveShell(commandStr string) ICmdObj // Quote wraps a string in quotes with any necessary escaping applied. The reason for bundling this up with the other methods in this interface is that we basically always need to make use of this when creating new command objects. Quote(str string) string } @@ -43,10 +45,23 @@ func (self *CmdObjBuilder) NewWithEnviron(args []string, env []string) ICmdObj { } func (self *CmdObjBuilder) NewShell(commandStr string) ICmdObj { - var quotedCommand string + quotedCommand := self.quotedCommandString(commandStr) + cmdArgs := str.ToArgv(fmt.Sprintf("%s %s %s", self.platform.Shell, self.platform.ShellArg, quotedCommand)) + + return self.New(cmdArgs) +} + +func (self *CmdObjBuilder) NewInteractiveShell(commandStr string) ICmdObj { + quotedCommand := self.quotedCommandString(commandStr) + cmdArgs := str.ToArgv(fmt.Sprintf("%s %s %s %s", self.platform.InteractiveShell, self.platform.InteractiveShellArg, self.platform.ShellArg, quotedCommand)) + + return self.New(cmdArgs) +} + +func (self *CmdObjBuilder) quotedCommandString(commandStr string) string { // Windows does not seem to like quotes around the command if self.platform.OS == "windows" { - quotedCommand = strings.NewReplacer( + return strings.NewReplacer( "^", "^^", "&", "^&", "|", "^|", @@ -54,13 +69,9 @@ func (self *CmdObjBuilder) NewShell(commandStr string) ICmdObj { ">", "^>", "%", "^%", ).Replace(commandStr) - } else { - quotedCommand = self.Quote(commandStr) } - cmdArgs := str.ToArgv(fmt.Sprintf("%s %s %s", self.platform.Shell, self.platform.ShellArg, quotedCommand)) - - return self.New(cmdArgs) + return self.Quote(commandStr) } func (self *CmdObjBuilder) CloneWithNewRunner(decorate func(ICmdObjRunner) ICmdObjRunner) *CmdObjBuilder { diff --git a/pkg/commands/oscommands/dummies.go b/pkg/commands/oscommands/dummies.go index 3f72a6f0652..ab528782fa6 100644 --- a/pkg/commands/oscommands/dummies.go +++ b/pkg/commands/oscommands/dummies.go @@ -51,11 +51,13 @@ func NewDummyCmdObjBuilder(runner ICmdObjRunner) *CmdObjBuilder { } var dummyPlatform = &Platform{ - OS: "darwin", - Shell: "bash", - ShellArg: "-c", - OpenCommand: "open {{filename}}", - OpenLinkCommand: "open {{link}}", + OS: "darwin", + Shell: "bash", + InteractiveShell: "bash", + ShellArg: "-c", + InteractiveShellArg: "-i", + OpenCommand: "open {{filename}}", + OpenLinkCommand: "open {{link}}", } func NewDummyOSCommandWithRunner(runner *FakeCmdObjRunner) *OSCommand { diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index 7771dffba5f..7f31b533239 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -35,11 +35,13 @@ type OSCommand struct { // Platform stores the os state type Platform struct { - OS string - Shell string - ShellArg string - OpenCommand string - OpenLinkCommand string + OS string + Shell string + InteractiveShell string + ShellArg string + InteractiveShellArg string + OpenCommand string + OpenLinkCommand string } // NewOSCommand os command runner diff --git a/pkg/commands/oscommands/os_default_platform.go b/pkg/commands/oscommands/os_default_platform.go index fd4967d9576..196e4d9f634 100644 --- a/pkg/commands/oscommands/os_default_platform.go +++ b/pkg/commands/oscommands/os_default_platform.go @@ -4,15 +4,26 @@ package oscommands import ( + "os" "runtime" ) func GetPlatform() *Platform { return &Platform{ - OS: runtime.GOOS, - Shell: "bash", - ShellArg: "-c", - OpenCommand: "open {{filename}}", - OpenLinkCommand: "open {{link}}", + OS: runtime.GOOS, + Shell: "bash", + InteractiveShell: getUserShell(), + ShellArg: "-c", + InteractiveShellArg: "-i", + OpenCommand: "open {{filename}}", + OpenLinkCommand: "open {{link}}", } } + +func getUserShell() string { + if shell := os.Getenv("SHELL"); shell != "" { + return shell + } + + return "bash" +} diff --git a/pkg/commands/oscommands/os_windows.go b/pkg/commands/oscommands/os_windows.go index 783f50518a1..32cd59edb0a 100644 --- a/pkg/commands/oscommands/os_windows.go +++ b/pkg/commands/oscommands/os_windows.go @@ -2,8 +2,10 @@ package oscommands func GetPlatform() *Platform { return &Platform{ - OS: "windows", - Shell: "cmd", - ShellArg: "/c", + OS: "windows", + Shell: "cmd", + InteractiveShell: "cmd", + ShellArg: "/c", + InteractiveShellArg: "", } } diff --git a/pkg/gui/controllers/custom_command_action.go b/pkg/gui/controllers/custom_command_action.go index 39777e70a0d..7b8cbc641bf 100644 --- a/pkg/gui/controllers/custom_command_action.go +++ b/pkg/gui/controllers/custom_command_action.go @@ -31,7 +31,7 @@ func (self *CustomCommandAction) Call() error { self.c.LogAction(self.c.Tr.Actions.CustomCommand) return self.c.RunSubprocessAndRefresh( - self.c.OS().Cmd.NewShell(command), + self.c.OS().Cmd.NewInteractiveShell(command), ) }, HandleDeleteSuggestion: func(index int) error {