package main
import (
- "bytes"
"fmt"
"os"
- "os/exec"
- "os/signal"
"path/filepath"
"regexp"
"runtime"
func Term(args []string) {
var err error
if len(args) == 0 {
- err = CurView().StartTerminal([]string{os.Getenv("SHELL"), "-i"})
+ err = CurView().StartTerminal([]string{os.Getenv("SHELL"), "-i"}, true, false, "")
} else {
- err = CurView().StartTerminal(args)
+ err = CurView().StartTerminal(args, true, false, "")
}
if err != nil {
messenger.Error(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]
-
- cmd := exec.Command(inputCmd, args[1:]...)
- outputBytes := &bytes.Buffer{}
- cmd.Stdout = outputBytes
- cmd.Stderr = outputBytes
- cmd.Start()
- err = cmd.Wait() // wait for command to finish
- outstring := outputBytes.String()
- return outstring, 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 {
- args, err := shellwords.Split(input)
- if err != nil {
- return ""
- }
- inputCmd := args[0]
- if !openTerm {
- // Simply run the command in the background and notify the user when it's done
- 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()
- }()
- } else {
- // 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
- var output string
- cmd := exec.Command(inputCmd, args...)
- cmd.Stdin = os.Stdin
- 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()
-
- if err != nil {
- output = err.Error()
- }
-
- if waitToFinish {
- // 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
- }
- return ""
-}
-
// HandleCommand handles input from the user
func HandleCommand(input string) {
args, err := shellwords.Split(input)
--- /dev/null
+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 {
+ args, err := shellwords.Split(input)
+ if err != nil {
+ return ""
+ }
+ 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 err != nil {
+ output = err.Error()
+ }
+
+ 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
+}
+
+// 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 {
+ return RunInteractiveShell(input, waitToFinish, false)
+ }
+}
--- /dev/null
+// +build linux darwin dragonfly solaris openbsd netbsd freebsd
+
+package main
+
+import (
+ "github.com/zyedidia/micro/cmd/micro/shellwords"
+)
+
+const TermEmuSupported = true
+
+func RunTermEmulator(input string, wait bool, getOutput bool) error {
+ args, err := shellwords.Split(input)
+ if err != nil {
+ return err
+ }
+ err = CurView().StartTerminal(args, wait, false, "")
+ return err
+}
--- /dev/null
+// +build plan9 nacl windows
+
+package main
+
+const TermEmuSupported = false
+
+func RunTermEmulator(input string, wait bool, getOutput bool) string {
+ return "Unsupported"
+}
"os"
"os/exec"
"strconv"
+ "strings"
"github.com/zyedidia/clipboard"
"github.com/zyedidia/tcell"
status int
selection [2]Loc
wait bool
+ getOutput bool
+ callback string
}
// HasSelection returns whether this terminal has a valid selection
// is ready for a new command to execute
func (t *Terminal) Close() {
t.status = VTIdle
+ // call the lua function that the user has given as a callback
+ _, err := Call(t.callback)
+ if err != nil && !strings.HasPrefix(err.Error(), "function does not exist") {
+ TermMessage(err)
+ }
}
// WriteString writes a given string to this terminal's pty
}
// StartTerminal execs a command in this view
-func (v *View) StartTerminal(execCmd []string) error {
+func (v *View) StartTerminal(execCmd []string, wait bool, getOutput bool, luaCallback string) error {
err := v.term.Start(execCmd, v)
+ v.term.wait = wait
+ v.term.getOutput = getOutput
+ v.term.callback = luaCallback
if err == nil {
v.term.Resize(v.Width, v.Height)
v.Type = vtTerm