Open 39555 opened 3 months ago
So this is what I found by looking at the history:
shellopts
was introduced because of #102, to allow specifying additional options when invoking the shell (e.g. -f
to disable globbing).shellflag
was introduced because of #597, to override the default -c
option (/c
for Windows), primarily to allow the use of other shells in Windows.I agree that such high-level configuration options can be inflexible, and that it would be beneficial to provide a more low-level method of specifying the shell invocation. However, modifying the existing shell
configuration option is a breaking change, and given that the shell is a core feature of lf
, I am not sure if this is a good idea.
I think it might be better to introduce a new option (e.g. shellcmd
) instead, implemented like below (similar changes required for os_windows.go
):
Although I suppose we could just keep shell
as a string option and apply the new handling logic based on whether it consists of a single word or not. I could be convinced either way on this.
Thanks for the hint! Im going to implement it and we will see how it plays out
I experimented a bit with Windows CMD, unfortunately it has its own way of dealing with quoted arguments and requires special handling. You can find some notes about it in the description for #1309.
It might be better to implement the shell
option as a string value, something like below:
func shellCommand(s string, args []string) *exec.Cmd {
// Windows CMD requires special handling to deal with quoted arguments
if strings.HasPrefix(strings.ToLower(gOpts.shell), "cmd ") {
var quotedArgs []string
for _, arg := range args {
quotedArgs = append(quotedArgs, fmt.Sprintf(`"%s"`), arg)
}
cmdline := strings.ReplaceAll(gOpts.shell, "$c", s)
cmdline = strings.ReplaceAll(cmdline, "$a", strings.Join(quotedArgs, " "))
cmd := exec.Command("cmd")
cmd.SysProcAttr = &windows.SysProcAttr{CmdLine: cmdline}
return cmd
}
if strings.Contains(gOpts.shell, " ") {
var words []string
for _, word := range tokenize(gOpts.shell) {
switch word {
case "$a":
words = append(words, args...)
case "$c":
words = append(words, s)
default:
words = append(words, word)
}
}
return exec.Command(words[0], words[1:]...)
}
// original legacy configuration which uses shellopts and shellflag
args = append([]string{gOpts.shellflag, s}, args...)
args = append(gOpts.shellopts, args...)
return exec.Command(gOpts.shell, args...)
}
This should work for Windows CMD:
set shell 'cmd /c "$c $a"'
And for PowerShell:
set shell 'pwsh -CommandWithArgs $c $a'
The only other suggestions I have are:
shell
command (must be backwards compatible)$c
and $a
) or something longer like $cmd
and $args
Anyway I think this is a great idea, and an improvement over the current design. Feel free to submit a PR if you get this working.
I would like to reopen the discussion around the double-hyphen
--
placeholder https://github.com/gokcehan/lf/pull/1606I found that when I use cygwin bash or any 'posix compliant' shell on windows, arguments to any shell command shift to the command_name
$0
because lf uses platform specific functions and doesn't add the--
placeholder on windows:Idea
My idea is to set shell as a template parameter for the entire shell invocation not just the shell path, options and args:
Than when invoking a script lf would replace placeholders for command $c and args $a inside the template