]> git.lizzy.rs Git - micro.git/blob - cmd/micro/shell.go
88a8c656b8530b64e41a8058852c49dfc99d9aab
[micro.git] / cmd / micro / shell.go
1 package main
2
3 import (
4         "bytes"
5         "io"
6         "os"
7         "os/exec"
8         "os/signal"
9         "strings"
10
11         "github.com/zyedidia/micro/cmd/micro/shellwords"
12 )
13
14 // ExecCommand executes a command using exec
15 // It returns any output/errors
16 func ExecCommand(name string, arg ...string) (string, error) {
17         var err error
18         cmd := exec.Command(name, arg...)
19         outputBytes := &bytes.Buffer{}
20         cmd.Stdout = outputBytes
21         cmd.Stderr = outputBytes
22         err = cmd.Start()
23         if err != nil {
24                 return "", err
25         }
26         err = cmd.Wait() // wait for command to finish
27         outstring := outputBytes.String()
28         return outstring, err
29 }
30
31 // RunShellCommand executes a shell command and returns the output/error
32 func RunShellCommand(input string) (string, error) {
33         args, err := shellwords.Split(input)
34         if err != nil {
35                 return "", err
36         }
37         inputCmd := args[0]
38
39         return ExecCommand(inputCmd, args[1:]...)
40 }
41
42 func RunBackgroundShell(input string) {
43         args, err := shellwords.Split(input)
44         if err != nil {
45                 messenger.Error(err)
46                 return
47         }
48         inputCmd := args[0]
49         messenger.Message("Running...")
50         go func() {
51                 output, err := RunShellCommand(input)
52                 totalLines := strings.Split(output, "\n")
53
54                 if len(totalLines) < 3 {
55                         if err == nil {
56                                 messenger.Message(inputCmd, " exited without error")
57                         } else {
58                                 messenger.Message(inputCmd, " exited with error: ", err, ": ", output)
59                         }
60                 } else {
61                         messenger.Message(output)
62                 }
63                 // We have to make sure to redraw
64                 RedrawAll()
65         }()
66 }
67
68 func RunInteractiveShell(input string, wait bool, getOutput bool) (string, error) {
69         args, err := shellwords.Split(input)
70         if err != nil {
71                 return "", err
72         }
73         inputCmd := args[0]
74
75         // Shut down the screen because we're going to interact directly with the shell
76         screen.Fini()
77         screen = nil
78
79         args = args[1:]
80
81         // Set up everything for the command
82         outputBytes := &bytes.Buffer{}
83         cmd := exec.Command(inputCmd, args...)
84         cmd.Stdin = os.Stdin
85         if getOutput {
86                 cmd.Stdout = io.MultiWriter(os.Stdout, outputBytes)
87         } else {
88                 cmd.Stdout = os.Stdout
89         }
90         cmd.Stderr = os.Stderr
91
92         // This is a trap for Ctrl-C so that it doesn't kill micro
93         // Instead we trap Ctrl-C to kill the program we're running
94         c := make(chan os.Signal, 1)
95         signal.Notify(c, os.Interrupt)
96         go func() {
97                 for range c {
98                         cmd.Process.Kill()
99                 }
100         }()
101
102         cmd.Start()
103         err = cmd.Wait()
104
105         output := outputBytes.String()
106
107         if wait {
108                 // This is just so we don't return right away and let the user press enter to return
109                 TermMessage("")
110         }
111
112         // Start the screen back up
113         InitScreen()
114
115         return output, err
116 }
117
118 // HandleShellCommand runs the shell command
119 // The openTerm argument specifies whether a terminal should be opened (for viewing output
120 // or interacting with stdin)
121 func HandleShellCommand(input string, openTerm bool, waitToFinish bool) string {
122         if !openTerm {
123                 RunBackgroundShell(input)
124                 return ""
125         } else {
126                 return RunInteractiveShell(input, waitToFinish, false)
127         }
128 }