mirror of
https://github.com/zyedidia/micro.git
synced 2026-02-05 22:50:21 +09:00
130 lines
2.8 KiB
Go
130 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"strings"
|
|
|
|
"github.com/zyedidia/micro/cmd/micro/shellwords"
|
|
)
|
|
|
|
// ExecCommand executes a command using exec
|
|
// It returns any output/errors
|
|
func ExecCommand(name string, arg ...string) (string, error) {
|
|
var err error
|
|
cmd := exec.Command(name, arg...)
|
|
outputBytes := &bytes.Buffer{}
|
|
cmd.Stdout = outputBytes
|
|
cmd.Stderr = outputBytes
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
err = cmd.Wait() // wait for command to finish
|
|
outstring := outputBytes.String()
|
|
return outstring, err
|
|
}
|
|
|
|
// RunShellCommand executes a shell command and returns the output/error
|
|
func RunShellCommand(input string) (string, error) {
|
|
args, err := shellwords.Split(input)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
inputCmd := args[0]
|
|
|
|
return ExecCommand(inputCmd, args[1:]...)
|
|
}
|
|
|
|
func RunBackgroundShell(input string) {
|
|
args, err := shellwords.Split(input)
|
|
if err != nil {
|
|
messenger.Error(err)
|
|
return
|
|
}
|
|
inputCmd := args[0]
|
|
messenger.Message("Running...")
|
|
go func() {
|
|
output, err := RunShellCommand(input)
|
|
totalLines := strings.Split(output, "\n")
|
|
|
|
if len(totalLines) < 3 {
|
|
if err == nil {
|
|
messenger.Message(inputCmd, " exited without error")
|
|
} else {
|
|
messenger.Message(inputCmd, " exited with error: ", err, ": ", output)
|
|
}
|
|
} else {
|
|
messenger.Message(output)
|
|
}
|
|
// We have to make sure to redraw
|
|
RedrawAll()
|
|
}()
|
|
}
|
|
|
|
func RunInteractiveShell(input string, wait bool, getOutput bool) (string, error) {
|
|
args, err := shellwords.Split(input)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
inputCmd := args[0]
|
|
|
|
// Shut down the screen because we're going to interact directly with the shell
|
|
screen.Fini()
|
|
screen = nil
|
|
|
|
args = args[1:]
|
|
|
|
// Set up everything for the command
|
|
outputBytes := &bytes.Buffer{}
|
|
cmd := exec.Command(inputCmd, args...)
|
|
cmd.Stdin = os.Stdin
|
|
if getOutput {
|
|
cmd.Stdout = io.MultiWriter(os.Stdout, outputBytes)
|
|
} else {
|
|
cmd.Stdout = os.Stdout
|
|
}
|
|
cmd.Stderr = os.Stderr
|
|
|
|
// This is a trap for Ctrl-C so that it doesn't kill micro
|
|
// Instead we trap Ctrl-C to kill the program we're running
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, os.Interrupt)
|
|
go func() {
|
|
for range c {
|
|
cmd.Process.Kill()
|
|
}
|
|
}()
|
|
|
|
cmd.Start()
|
|
err = cmd.Wait()
|
|
|
|
output := outputBytes.String()
|
|
|
|
if wait {
|
|
// This is just so we don't return right away and let the user press enter to return
|
|
TermMessage("")
|
|
}
|
|
|
|
// Start the screen back up
|
|
InitScreen()
|
|
|
|
return output, err
|
|
}
|
|
|
|
// HandleShellCommand runs the shell command
|
|
// The openTerm argument specifies whether a terminal should be opened (for viewing output
|
|
// or interacting with stdin)
|
|
func HandleShellCommand(input string, openTerm bool, waitToFinish bool) string {
|
|
if !openTerm {
|
|
RunBackgroundShell(input)
|
|
return ""
|
|
} else {
|
|
output, _ := RunInteractiveShell(input, waitToFinish, false)
|
|
return output
|
|
}
|
|
}
|