Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/micro/initlua.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ func luaImportMicroShell() *lua.LTable {
ulua.L.SetField(pkg, "ExecCommand", luar.New(ulua.L, shell.ExecCommand))
ulua.L.SetField(pkg, "RunCommand", luar.New(ulua.L, shell.RunCommand))
ulua.L.SetField(pkg, "RunBackgroundShell", luar.New(ulua.L, shell.RunBackgroundShell))
ulua.L.SetField(pkg, "ExecBackgroundCommand", luar.New(ulua.L, shell.ExecBackgroundCommand))
ulua.L.SetField(pkg, "RunBackgroundCommand", luar.New(ulua.L, shell.RunBackgroundCommand))
ulua.L.SetField(pkg, "RunInteractiveShell", luar.New(ulua.L, shell.RunInteractiveShell))
ulua.L.SetField(pkg, "JobStart", luar.New(ulua.L, shell.JobStart))
ulua.L.SetField(pkg, "JobSpawn", luar.New(ulua.L, shell.JobSpawn))
Expand Down
18 changes: 10 additions & 8 deletions internal/action/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,15 +873,17 @@ func (h *BufPane) UnbindCmd(args []string) {

// RunCmd runs a shell command in the background
func (h *BufPane) RunCmd(args []string) {
runf, err := shell.RunBackgroundShell(shellquote.Join(args...))
if err != nil {
InfoBar.Error(err)
} else {
go func() {
InfoBar.Message(runf())
screen.Redraw()
}()
if len(args) == 0 {
InfoBar.Error("No arguments")
return
}

shell.ExecBackgroundCommand(func(output string, runErr error) {
if runErr != nil {
output = fmt.Sprint(args[0], " exited with error: ", runErr)
}
InfoBar.Message(output)
}, args[0], args[1:]...)
}

// QuitCmd closes the main view
Expand Down
7 changes: 6 additions & 1 deletion internal/shell/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"io"
"os/exec"
"runtime"
)

var Jobs chan JobFunction
Expand Down Expand Up @@ -54,7 +55,11 @@ func (f *CallbackFile) Write(data []byte) (int, error) {
// JobStart starts a shell command in the background with the given callbacks
// It returns an *exec.Cmd as the job id
func JobStart(cmd string, onStdout, onStderr, onExit func(string, []any), userargs ...any) *Job {
return JobSpawn("sh", []string{"-c", cmd}, onStdout, onStderr, onExit, userargs...)
if runtime.GOOS == "windows" {
return JobSpawn("cmd", []string{"/v:on", "/c", cmd}, onStdout, onStderr, onExit, userargs...)
} else {
return JobSpawn("sh", []string{"-c", cmd}, onStdout, onStderr, onExit, userargs...)
}
}

// JobSpawn starts a process with args in the background with the given callbacks
Expand Down
38 changes: 38 additions & 0 deletions internal/shell/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func RunCommand(input string) (string, error) {
return ExecCommand(inputCmd, args[1:]...)
}

// **Deprecated, don't use**
// RunBackgroundShell runs a shell command in the background
// It returns a function which will run the command and returns a string
// message result
Expand All @@ -68,6 +69,43 @@ func RunBackgroundShell(input string) (func() string, error) {
}, nil
}

// ExecBackgroundCommand is similar to ExecCommand, except it runs in the
// background and accepts an optional callback function for the command output
// or an error if any
func ExecBackgroundCommand(cb func(string, error), name string, args ...string) {
go func() {
output, runErr := ExecCommand(name, args[0:]...)
if cb != nil {
wrapperFunc := func(output string, args []any) {
errVal, _ := args[0].(error)
cb(output, errVal)
}

var passArgs []any
passArgs = append(passArgs, runErr)
jobFunc := JobFunction{wrapperFunc, output, passArgs}
Jobs <- jobFunc
}
}()
}

// RunBackgroundCommand is similar to RunCommand, except it runs in the
// background and accept an optional callback function for the command output
// or an error if any.
// Returns an error immediately if it fails to split the input command
func RunBackgroundCommand(input string, cb func(string, error)) error {
args, err := shellquote.Split(input)
if err != nil {
return err
}
if len(args) == 0 {
return errors.New("No arguments")
}

ExecBackgroundCommand(cb, args[0], args[1:]...)
return nil
}

// RunInteractiveShell runs a shellcommand interactively
func RunInteractiveShell(input string, wait bool, getOutput bool) (string, error) {
args, err := shellquote.Split(input)
Expand Down
22 changes: 16 additions & 6 deletions runtime/help/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,18 @@ The packages and their contents are listed below (in Go type signatures):
two arguments in the `ExecCommand` argument list (quoting arguments
will preserve spaces).

- `RunBackgroundShell(input string) (func() string, error)`: returns a
function that will run the given shell command and return its output.
- **Deprecated** `RunBackgroundShell(input string) (func() string, error)`:
returns a function that will run the given shell command and return
its output.

- `ExecBackgroundCommand(cb func(string, error), name string, args ...string)`:
similar to `ExecCommand`, except it runs in the background and accepts
an optional callback function for the command output or an error if any.

- `RunBackgroundCommand(input string, cb func(string, error)) error`:
similar to `RunCommand`, except it runs in the background and accept an
optional callback function for the command output or an error if any.
Returns an error immediately if it fails to split the input command.

- `RunInteractiveShell(input string, wait bool, getOutput bool)
(string, error)`:
Expand All @@ -267,10 +277,10 @@ The packages and their contents are listed below (in Go type signatures):
onExit func(string, []any), userargs ...any)
*exec.Cmd`:
Starts a background job by running the shell on the given command
(using `sh -c`). Three callbacks can be provided which will be called
when the command generates stdout, stderr, or exits. The userargs will
be passed to the callbacks, along with the output as the first
argument of the callback. Returns the started command.
(using `sh -c` or `cmd /v:on /c`). Three callbacks can be provided which
will be called when the command generates stdout, stderr, or exits.
The userargs will be passed to the callbacks, along with the output
as the first argument of the callback. Returns the started command.

- `JobSpawn(cmd string, cmdArgs []string, onStdout, onStderr,
onExit func(string, []any), userargs ...any)
Expand Down