]> git.lizzy.rs Git - micro.git/blob - cmd/micro/command.go
Rewrite gofmt and goimports as plugins
[micro.git] / cmd / micro / command.go
1 package main
2
3 import (
4         "bytes"
5         "os"
6         "os/exec"
7         "os/signal"
8         "regexp"
9         "strings"
10 )
11
12 // RunShellCommand executes a shell command and returns the output/error
13 func RunShellCommand(input string) (string, error) {
14         inputCmd := strings.Split(input, " ")[0]
15         args := strings.Split(input, " ")[1:]
16
17         cmd := exec.Command(inputCmd, args...)
18         outputBytes := &bytes.Buffer{}
19         cmd.Stdout = outputBytes
20         cmd.Stderr = outputBytes
21         cmd.Start()
22         err := cmd.Wait() // wait for command to finish
23         outstring := outputBytes.String()
24         return outstring, err
25 }
26
27 // HandleShellCommand runs the shell command and outputs to DisplayBlock
28 func HandleShellCommand(input string, view *View, openTerm bool) {
29         inputCmd := strings.Split(input, " ")[0]
30         if !openTerm {
31                 messenger.Message("Running...")
32                 go func() {
33                         output, err := RunShellCommand(input)
34                         totalLines := strings.Split(output, "\n")
35
36                         if len(totalLines) < 3 {
37                                 if err == nil {
38                                         messenger.Message(inputCmd, " exited without error")
39                                 } else {
40                                         messenger.Message(inputCmd, " exited with error: ", err, ": ", output)
41                                 }
42                         } else {
43                                 messenger.Message(output)
44                         }
45                         Redraw(view)
46                 }()
47         } else {
48                 screen.Fini()
49                 screen = nil
50
51                 args := strings.Split(input, " ")[1:]
52
53                 cmd := exec.Command(inputCmd, args...)
54                 cmd.Stdin = os.Stdin
55                 cmd.Stdout = os.Stdout
56                 cmd.Stderr = os.Stderr
57
58                 c := make(chan os.Signal, 1)
59                 signal.Notify(c, os.Interrupt)
60                 go func() {
61                         for range c {
62                                 cmd.Process.Kill()
63                         }
64                 }()
65
66                 cmd.Start()
67                 cmd.Wait()
68
69                 TermMessage("")
70
71                 InitScreen()
72         }
73 }
74
75 // HandleCommand handles input from the user
76 func HandleCommand(input string, view *View) {
77         inputCmd := strings.Split(input, " ")[0]
78         args := strings.Split(input, " ")[1:]
79
80         commands := []string{"set", "quit", "save", "replace", "run"}
81
82         i := 0
83         cmd := inputCmd
84
85         for _, c := range commands {
86                 if strings.HasPrefix(c, inputCmd) {
87                         i++
88                         cmd = c
89                 }
90         }
91         if i == 1 {
92                 inputCmd = cmd
93         }
94
95         switch inputCmd {
96         case "set":
97                 SetOption(view, args)
98         case "run":
99                 HandleShellCommand(strings.Join(args, " "), view, false)
100         case "quit":
101                 if view.CanClose("Quit anyway? (yes, no, save) ") {
102                         screen.Fini()
103                         os.Exit(0)
104                 }
105         case "save":
106                 view.Save()
107         case "replace":
108                 r := regexp.MustCompile(`"[^"\\]*(?:\\.[^"\\]*)*"|[^\s]*`)
109                 replaceCmd := r.FindAllString(strings.Join(args, " "), -1)
110                 if len(replaceCmd) < 2 {
111                         messenger.Error("Invalid replace statement: " + strings.Join(args, " "))
112                         return
113                 }
114
115                 var flags string
116                 if len(replaceCmd) == 3 {
117                         // The user included some flags
118                         flags = replaceCmd[2]
119                 }
120
121                 search := string(replaceCmd[0])
122                 replace := string(replaceCmd[1])
123
124                 if strings.HasPrefix(search, `"`) && strings.HasSuffix(search, `"`) {
125                         search = search[1 : len(search)-1]
126                 }
127                 if strings.HasPrefix(replace, `"`) && strings.HasSuffix(replace, `"`) {
128                         replace = replace[1 : len(replace)-1]
129                 }
130
131                 search = strings.Replace(search, `\"`, `"`, -1)
132                 replace = strings.Replace(replace, `\"`, `"`, -1)
133
134                 // messenger.Error(search + " -> " + replace)
135
136                 regex, err := regexp.Compile(search)
137                 if err != nil {
138                         messenger.Error(err.Error())
139                         return
140                 }
141
142                 found := false
143                 for {
144                         match := regex.FindStringIndex(view.Buf.String())
145                         if match == nil {
146                                 break
147                         }
148                         found = true
149                         if strings.Contains(flags, "c") {
150                                 // The 'check' flag was used
151                                 Search(search, view, true)
152                                 view.Relocate()
153                                 Redraw(view)
154                                 choice, canceled := messenger.YesNoPrompt("Perform replacement? (y,n)")
155                                 if canceled {
156                                         if view.Cursor.HasSelection() {
157                                                 view.Cursor.SetLoc(view.Cursor.curSelection[0])
158                                                 view.Cursor.ResetSelection()
159                                         }
160                                         messenger.Reset()
161                                         return
162                                 }
163                                 if choice {
164                                         view.Cursor.DeleteSelection()
165                                         view.eh.Insert(match[0], replace)
166                                         view.Cursor.ResetSelection()
167                                         messenger.Reset()
168                                 } else {
169                                         if view.Cursor.HasSelection() {
170                                                 searchStart = view.Cursor.curSelection[1]
171                                         } else {
172                                                 searchStart = ToCharPos(view.Cursor.x, view.Cursor.y, view.Buf)
173                                         }
174                                         continue
175                                 }
176                         } else {
177                                 view.eh.Replace(match[0], match[1], replace)
178                         }
179                 }
180                 if !found {
181                         messenger.Message("Nothing matched " + search)
182                 }
183         default:
184                 messenger.Error("Unknown command: " + inputCmd)
185         }
186 }