]> git.lizzy.rs Git - micro.git/commitdiff
Improve cmdbar parsing and add -l replace flag
authorZachary Yedidia <zyedidia@gmail.com>
Wed, 22 Nov 2017 18:54:39 +0000 (13:54 -0500)
committerZachary Yedidia <zyedidia@gmail.com>
Wed, 22 Nov 2017 18:54:39 +0000 (13:54 -0500)
The -l flag to the replace command means "literal" and will treat
the search term literally instead of as a regular expression.

The command bar also now supports expanding environment variables
and running expressions through the shell and using the result
in the command.

.gitmodules
cmd/micro/actions.go
cmd/micro/command.go
cmd/micro/messenger.go
cmd/micro/runtime.go
cmd/micro/util.go
cmd/micro/util_test.go
cmd/micro/vendor/github.com/mattn/go-shellwords [new submodule]
runtime/help/commands.md

index 2d9bffcde020d82c51aeae334173b9c1d9080f2f..6b75f5a1f09cec23fa13f1117f041a6dc5e7da48 100644 (file)
@@ -55,3 +55,6 @@
 [submodule "cmd/micro/vendor/github.com/flynn/json5"]
        path = cmd/micro/vendor/github.com/flynn/json5
        url = https://github.com/flynn/json5
+[submodule "cmd/micro/vendor/github.com/mattn/go-shellwords"]
+       path = cmd/micro/vendor/github.com/mattn/go-shellwords
+       url = https://github.com/mattn/go-shellwords
index f89db18046e334abc55a25ed64a880acb79bebd5..a7a5e09a6296397ab5b126c80188bbfaaccc144d 100644 (file)
@@ -997,7 +997,12 @@ func (v *View) SaveAs(usePlugin bool) bool {
                filename, canceled := messenger.Prompt("Filename: ", "", "Save", NoCompletion)
                if !canceled {
                        // the filename might or might not be quoted, so unquote first then join the strings.
-                       filename = strings.Join(SplitCommandArgs(filename), " ")
+                       args, err := SplitCommandArgs(filename)
+                       filename = strings.Join(args, " ")
+                       if err != nil {
+                               messenger.Error("Error parsing arguments: ", err)
+                               return false
+                       }
                        v.saveToFile(filename)
                }
 
index b71b16174cdcf61c5a8d02548d7099f025f7ee9a..b5c96cef50f0f418003f36e672f578e3eab0aae5 100644 (file)
@@ -277,7 +277,12 @@ func Open(args []string) {
        if len(args) > 0 {
                filename := args[0]
                // the filename might or might not be quoted, so unquote first then join the strings.
-               filename = strings.Join(SplitCommandArgs(filename), " ")
+               args, err := SplitCommandArgs(filename)
+               if err != nil {
+                       messenger.Error("Error parsing args ", err)
+                       return
+               }
+               filename = strings.Join(args, " ")
 
                CurView().Open(filename)
        } else {
@@ -508,24 +513,35 @@ func Save(args []string) {
 
 // Replace runs search and replace
 func Replace(args []string) {
-       if len(args) < 2 || len(args) > 3 {
+       if len(args) < 2 || len(args) > 4 {
                // We need to find both a search and replace expression
                messenger.Error("Invalid replace statement: " + strings.Join(args, " "))
                return
        }
 
-       allAtOnce := false
-       if len(args) == 3 {
-               // user added -a flag
-               if args[2] == "-a" {
-                       allAtOnce = true
-               } else {
-                       messenger.Error("Invalid replace flag: " + args[2])
-                       return
+       all := false
+       noRegex := false
+
+       if len(args) > 2 {
+               for _, arg := range args[2:] {
+                       switch arg {
+                       case "-a":
+                               all = true
+                       case "-l":
+                               noRegex = true
+                       default:
+                               messenger.Error("Invalid flag: " + arg)
+                               return
+                       }
                }
        }
 
        search := string(args[0])
+
+       if noRegex {
+               search = regexp.QuoteMeta(search)
+       }
+
        replace := string(args[1])
 
        regex, err := regexp.Compile("(?m)" + search)
@@ -561,7 +577,7 @@ func Replace(args []string) {
                view.Buf.MultipleReplace(deltas)
        }
 
-       if allAtOnce {
+       if all {
                replaceAll()
        } else {
                for {
@@ -621,15 +637,18 @@ func ReplaceAll(args []string) {
 
 // RunShellCommand executes a shell command and returns the output/error
 func RunShellCommand(input string) (string, error) {
-       inputCmd := SplitCommandArgs(input)[0]
-       args := SplitCommandArgs(input)[1:]
+       args, err := SplitCommandArgs(input)
+       if err != nil {
+               return "", err
+       }
+       inputCmd := args[0]
 
-       cmd := exec.Command(inputCmd, args...)
+       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
+       err = cmd.Wait() // wait for command to finish
        outstring := outputBytes.String()
        return outstring, err
 }
@@ -638,7 +657,11 @@ func RunShellCommand(input string) (string, error) {
 // 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 {
-       inputCmd := SplitCommandArgs(input)[0]
+       args, err := SplitCommandArgs(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...")
@@ -663,7 +686,7 @@ func HandleShellCommand(input string, openTerm bool, waitToFinish bool) string {
                screen.Fini()
                screen = nil
 
-               args := SplitCommandArgs(input)[1:]
+               args := args[1:]
 
                // Set up everything for the command
                var output string
@@ -704,7 +727,12 @@ func HandleShellCommand(input string, openTerm bool, waitToFinish bool) string {
 
 // HandleCommand handles input from the user
 func HandleCommand(input string) {
-       args := SplitCommandArgs(input)
+       args, err := SplitCommandArgs(input)
+       if err != nil {
+               messenger.Error("Error parsing args ", err)
+               return
+       }
+
        inputCmd := args[0]
 
        if _, ok := commands[inputCmd]; !ok {
index b38c3a1d3b7a4ebc9471b744af5a661fb416a03c..d281f017e7d883355776cd2db48852aa9fbe34c9 100644 (file)
@@ -272,9 +272,16 @@ func (m *Messenger) Prompt(prompt, placeholder, historyType string, completionTy
                                response, canceled = m.response, false
                                m.history[historyType][len(m.history[historyType])-1] = response
                        case tcell.KeyTab:
-                               args := SplitCommandArgs(m.response)
-                               currentArgNum := len(args) - 1
-                               currentArg := args[currentArgNum]
+                               args, err := SplitCommandArgs(m.response)
+                               if err != nil {
+                                       break
+                               }
+                               currentArg := ""
+                               currentArgNum := 0
+                               if len(args) > 0 {
+                                       currentArgNum = len(args) - 1
+                                       currentArg = args[currentArgNum]
+                               }
                                var completionType Completion
 
                                if completionTypes[0] == CommandCompletion && currentArgNum > 0 {
index 948dd5df815beeaacb71e96e2b588b374532dc7b..7cfef17c6c98924581b083e89e98a10a4efed6ca 100644 (file)
 // runtime/syntax/nim.yaml
 // runtime/syntax/objc.yaml
 // runtime/syntax/ocaml.yaml
+// runtime/syntax/octave.yaml
 // runtime/syntax/pascal.yaml
 // runtime/syntax/patch.yaml
 // runtime/syntax/peg.yaml
@@ -931,7 +932,7 @@ func runtimeHelpColorsMd() (*asset, error) {
        return a, nil
 }
 
-var _runtimeHelpCommandsMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x56\x4d\x8f\xdc\x36\x0c\x3d\x67\x7e\x05\xb1\x3d\x24\x29\x76\x9c\xfb\x5c\x8a\x22\x28\xd0\x02\x49\x9b\x22\xb9\xf4\x54\xc9\x36\x6d\x0b\x2b\x8b\x8e\x28\xcd\xc4\xfd\xf5\x05\x45\xd9\x33\xb3\x5b\xa0\xd9\xcb\x8e\x25\x8a\x8f\x1f\x8f\x4f\xfa\x01\x3e\x11\xb3\x6b\x3d\x42\x47\xf3\x6c\x43\xcf\x87\xc3\x5f\x94\xa1\xb3\x01\xf0\x1b\x76\x39\x21\xc8\xcf\xde\x25\x8a\x9b\x0d\xb4\x2b\x2c\x11\x99\x5d\x18\xc1\xbc\x4f\xd1\x1f\xd1\xc0\x40\xde\xd3\x05\xcb\x6e\x9a\x76\x87\xcd\xe1\x57\x8c\x08\x36\x62\x59\x5d\x9e\xe3\x41\x9a\x6c\x82\xb5\x62\x66\xc6\xe6\x70\xf8\x11\xcc\xd7\xec\x92\x39\xc1\x9f\xd9\x25\x86\xd9\x75\x91\x74\x9d\xed\x19\x61\x70\x1e\x83\x9d\xf1\x27\x73\x82\xcf\xf6\x8c\xac\x80\x39\x46\x0c\x09\xda\x3c\x0c\x18\x1b\xf8\x6d\x28\xcb\x9b\x31\x38\x86\x25\xd2\xd9\xf5\xd8\x83\x4b\x07\x80\x8b\xf3\x1e\x5e\x17\x8f\x96\x5f\xdf\x19\x2b\x58\xc4\xc5\xdb\x0e\xe1\x81\xd1\xc6\x6e\x7a\x80\x87\xb3\xf5\x19\x1f\x60\xf0\x76\x64\x73\x82\x2f\x93\x63\x75\xb3\x99\x1a\x35\x35\x70\x71\x69\x02\x53\xec\x4d\x03\x07\x00\xf8\x32\x21\x18\x3d\x59\xca\x41\x4b\x72\x14\xac\x6f\xe0\xe7\x04\x49\x3c\x2d\xe4\x42\x7a\x94\x40\x62\x09\x97\x82\x5f\x81\x02\x16\xbc\x13\x98\xa3\x35\x8f\x70\x99\x5c\x37\x89\xbf\x0a\xc9\x60\xbd\x07\xea\x34\xfd\xf2\x9d\x80\x42\x27\x39\x00\xc0\xef\x94\x50\x6b\xbc\x87\x36\x67\x4e\xd0\x22\x58\x38\x5b\xef\x7a\x88\x38\xe2\xb7\x06\xa4\x60\x02\x46\x5a\x37\x1b\xc7\x3c\x63\x48\x0c\x3d\x21\x43\x20\x29\x19\x4c\xa5\x5a\x61\x05\x5e\x0a\xb6\x0b\xe0\xd2\x63\xe9\xdf\x6c\x57\xa0\xd9\xa5\x72\xfa\x6b\xa6\x84\x7c\x57\x46\x09\xf3\x79\x25\xbf\xbf\x86\xe5\x83\x72\x09\x22\x33\x0a\x19\xc3\xe0\xe2\x6c\xa5\x88\xcd\xe1\xf0\xea\x33\xe2\x0e\x65\x76\xaa\x0e\x14\x61\x26\x29\x67\x18\xe8\x6a\x2d\x4c\xc2\x54\x5b\x00\x8a\x70\x02\xc6\xa4\x54\xaa\xeb\x89\x74\xab\x01\x71\x2e\x1b\x46\x77\xd8\xc0\x84\x7e\x81\x44\x8b\xeb\x04\x43\xa2\xb2\xe0\x1d\x27\x29\x5f\x35\xda\x59\xcd\x98\x76\x4c\x4f\x9d\xf5\xdf\x0b\x0c\xc5\xda\xaf\xf0\xa6\x50\xc1\x85\x5b\xa2\x0b\xa6\x72\xfd\x6d\xf5\x3e\xd1\xa5\x7a\x10\x9f\x13\x5d\xee\x07\x43\x5d\xd6\xf6\x8e\xee\x8c\xa1\x5a\xeb\x71\x3c\x5b\x0f\x0f\xf8\x4d\x47\x9b\x82\x34\xe7\x17\x39\x63\x93\x90\x0a\x3e\x64\x0b\xd7\xdd\xe6\x86\x59\x65\x3e\xb5\x87\x95\x26\x4b\x74\x21\x09\x4f\xd2\x24\x22\xc1\x54\x6a\xc1\x13\x65\xdf\x4b\xfb\xc0\xcc\xc8\x8c\x61\xc4\x78\xfa\x88\xcc\x76\xc4\x37\x4d\xd3\xbc\x35\x92\x7a\xef\x78\xf1\x76\x55\x7e\xe6\x6d\x16\x73\x00\x9e\x8e\xb5\xaf\xe6\x04\x31\x07\xbe\xc9\x84\x27\xf4\x7e\x6f\x7b\xad\x54\x6b\xbb\xa7\x31\x52\x0e\x7d\x53\xc6\x4f\x42\xab\x26\xaf\x19\x28\xa7\x25\x27\x8d\xbb\xc5\x0d\x16\xcb\x69\x19\x04\xef\x02\xc2\x65\x42\xa1\x38\x0c\x2e\x38\x9e\x90\x05\x37\xb8\x30\x6a\x54\xad\x0b\x3d\x3c\xe1\x0a\xb6\xab\x65\xef\x22\xd6\x7a\x3d\xe1\x2a\xdb\x92\xff\x10\x69\x2e\x66\x89\xaa\xe5\x95\x52\x8c\x65\x81\x25\x36\x0a\x37\xa7\x18\x6c\x4b\xa2\x76\xb7\x14\x96\x35\x89\x59\xca\xfe\x84\x2b\x83\x64\xab\x2e\xb9\xa8\x8a\x3d\x5b\xe7\x6d\xeb\x6b\xd9\xce\xbc\xf8\x12\xbd\xea\x9a\x39\x01\x2d\x28\xa6\x70\xc6\x98\x9c\x70\x51\x2d\x74\xd6\x76\xbb\x22\x9f\x81\x6e\xd5\x53\xfb\xaa\x02\xfa\xf8\xd2\x81\xe8\xd5\x82\x01\x7b\x75\x25\xb7\xc6\xbc\xa4\x75\x93\xe3\x12\xcd\xf4\x22\x1a\x16\xdf\x96\xb7\x40\x0d\xb4\x39\xed\x21\x4e\x14\xdd\x3f\x14\xd2\x15\x23\x70\x42\xdb\x0b\x87\xad\x84\x73\x1f\x82\x62\x24\xdb\xbe\x4c\xf7\xca\x13\xd9\x92\x06\x5b\x08\x78\x81\x64\xdb\xfd\x14\x5f\x5c\xea\x26\x59\xda\x54\x69\x63\x53\x61\xc8\xb6\x4d\xda\xb5\x05\x3b\x37\x38\xec\x8b\x0b\xd5\x76\x39\x29\xf3\x2e\x91\xa1\x13\x15\x57\x95\x95\x88\x42\x9e\x5b\x8c\x8f\x40\x51\x90\x25\x69\xc9\x41\xf1\x5f\xc9\x1f\x48\x14\x9e\xc6\x9b\x0e\x79\x1a\x8b\x95\xf7\x30\xeb\x8c\x68\xbb\x7b\x6c\xf3\x08\x9c\x6c\xc2\x22\xd0\x9a\xc1\xe2\xf3\x28\x6a\x1c\x38\xc9\x09\xfd\xfc\xbb\x56\xa1\xae\xde\x16\x42\x0d\xee\xce\x46\x9c\x85\x70\xf7\x47\x75\xf1\x7f\x4e\x8a\xf2\x99\x53\xf9\xa7\xf7\x51\x05\xc4\xbe\x5a\xdf\x07\x99\x97\xde\x26\x71\xae\x3f\xbe\xe7\x88\xde\x09\xcf\x62\xd3\x45\xe4\x32\x23\x2f\x02\xbc\x51\xa8\xaa\xc4\xd2\x99\x41\x46\xf6\xaa\xd5\x82\xbc\xcf\xcc\x86\x0c\xb6\xa8\xd8\xe8\xd2\x94\xdb\xa6\xa3\xf9\x5d\x91\xb8\xa3\xbe\x83\xde\xa9\xd5\xb1\x9b\x6c\x08\xe8\xf5\x9e\xdd\x5e\x4d\xd6\x33\x01\x23\xbe\xb8\x75\xea\xe4\x96\x47\x90\xa6\x34\xdb\x60\x47\x8c\x55\xac\xc4\x89\xf9\xa4\x3b\x1f\x75\xc7\x6c\xe2\xb0\x89\x76\x2d\xc6\xdd\xf5\x73\x57\xa5\x3d\x93\xda\x8c\x6b\x42\x7b\x8a\x52\xaa\x9e\x2e\xc1\x93\xed\xe1\x4d\x79\x77\xb8\xd0\xf9\xdc\x17\x76\xad\x65\xca\xeb\x21\x15\x77\xbb\x16\x1a\xfb\x88\xb6\x5f\xaf\x5d\x7a\xbb\x5d\xee\xe2\xa8\xf0\x44\x7e\x68\x2b\x63\x0e\xc9\xcd\xfa\x9c\xaa\x6d\xec\x7a\x58\x6c\x9a\xcc\x09\xde\x4f\x36\x8c\xaa\x7d\x17\x8a\x4f\xa2\x8f\xbd\x8b\xd8\x25\x8a\xeb\x36\x5e\xda\x47\x53\x4e\xd4\x04\x2f\x02\xf2\xa9\xdc\x2b\xb7\x97\xda\x0b\x17\x6a\x2e\x33\x74\x2b\x03\x7f\xc8\xb7\xdd\xa7\xff\x3f\xde\x8b\x87\xc3\xf1\x78\x3c\x1c\x64\x92\xf5\x29\x2b\x5e\xf7\x57\xaa\x48\xeb\xfe\x7a\xac\x2f\xdc\x1e\x07\x9b\xfd\x5e\xe3\x53\x01\xf6\x2e\xc8\x24\x7c\x78\x1e\x67\x41\x96\xda\x63\x8c\x14\xb9\x39\xfc\x1b\x00\x00\xff\xff\x45\x61\xad\x59\x7c\x0b\x00\x00")
+var _runtimeHelpCommandsMd = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x57\xcd\x8e\xdb\x46\x12\x3e\x9b\x4f\x51\x18\x1f\x3c\x63\x8c\xe4\xbb\x2e\x7b\xf0\xee\x62\x17\xb0\x93\x49\x6c\x20\xc8\x29\x2c\x91\x45\xb2\x31\xcd\x6e\xba\xab\x29\x0d\xf3\xf4\x41\x55\x35\x29\xc9\x13\x20\xf6\xc5\xa3\xae\xff\xbf\xaf\x8a\x6f\xe1\x29\x32\xbb\xa3\x27\x68\xe2\x38\x62\x68\xb9\xaa\x7e\x8f\x33\x34\x18\x80\x5e\xa8\x99\x33\x81\xfc\xd9\xba\x1c\xd3\xca\x03\xc7\x05\xa6\x44\xcc\x2e\xf4\x50\x7f\xcc\xc9\xef\xa8\x86\x2e\x7a\x1f\xcf\xa4\xd4\x3c\x6c\x0a\xf7\xd5\xff\x28\x11\x60\x22\x7d\x9d\xbe\xb7\x07\x79\xc0\x0c\x4b\xb1\x39\x33\xed\xab\xea\x3d\xd4\xdf\x66\x97\xeb\x03\xfc\x32\xbb\xcc\x30\xba\x26\x45\x7b\x67\x3c\x11\x74\xce\x53\xc0\x91\xfe\x55\x1f\xe0\x0b\x9e\x88\xcd\xe0\x9c\x12\x85\x0c\xc7\xb9\xeb\x28\xed\xe1\xff\x9d\x3e\xaf\xcc\xe0\x18\xa6\x14\x4f\xae\xa5\x16\x5c\xae\x00\xce\xce\x7b\x78\xa7\x1a\x91\xdf\xdd\x30\x9b\xb1\x44\x93\xc7\x86\xe0\x8e\x09\x53\x33\xdc\xc1\xdd\x09\xfd\x4c\x77\xd0\x79\xec\xb9\x3e\xc0\xd7\xc1\xb1\xa9\x59\x59\x6b\x63\xad\xe1\xec\xf2\x00\xb5\xf2\xd7\x7b\xa8\x00\xe0\xeb\x40\x50\x9b\xa4\xa6\x23\x4e\xd9\xc5\x80\x7e\x7f\x29\x82\x52\x85\x78\x10\x81\xf7\x50\xef\xb0\x3e\xc0\xaf\x45\x37\x7a\x0f\xb1\xb1\x30\x1b\x62\xc0\x0c\x31\x34\xb4\xb2\xfa\xfa\x00\xff\x8e\x80\xe0\x5d\xa6\x84\x1e\xcc\x15\x70\x81\x33\x61\x0b\xb1\x03\x84\x44\x3d\xbd\x14\x4a\x25\x92\x3f\xc5\x4c\x56\x83\xcd\xf5\x71\xe6\x0c\x47\x02\x84\x13\x7a\xd7\x16\x99\xfb\x39\x78\x62\x56\x43\x9a\x4b\x64\xa6\xf6\x41\xf3\x1c\x03\x69\x88\xd1\x52\x8e\xa9\x9f\x47\x0a\x99\xa1\x8d\xc4\x10\x62\x86\x41\xb3\x1c\x16\xe0\x09\xc5\x77\x17\xc0\xe5\x47\xad\xfb\x88\x0b\xc4\xd1\x65\x15\xfd\x36\xc7\x4c\x7c\x93\x7e\x09\xfb\xfb\x0a\xfc\x78\xee\xf5\x47\x9c\xa5\xde\xd2\x5d\xd2\xc4\xa1\x73\x69\x44\x49\xfe\xbe\xaa\xde\x7c\x21\xda\x4c\xd5\x5b\x8b\x77\x31\xc1\x18\x13\x81\x0b\x5d\xbc\x70\x4b\x07\x52\x2e\xa5\x03\xb3\x70\x00\xa6\x6c\x2d\x58\xde\x73\x34\xd2\x1e\x44\xb9\x10\x6a\xa3\x70\x0d\x03\xf9\x09\x72\x9c\x5c\x23\x36\xc4\x2b\x29\x18\x67\xc9\x5d\x61\xda\xa6\x81\x29\x6f\x36\x7d\x6c\xd0\xff\xa8\x61\x50\x6e\xbf\xc0\x7d\x0c\x7e\x91\x64\x5f\x0d\x88\xd8\xb4\x19\x79\x28\xda\x87\x78\x2e\x1a\x44\xe7\x10\xcf\xb7\x03\x65\x2a\x4b\x6d\x7b\x77\xa2\x50\xb8\x4d\x9c\x4e\xe8\xe1\x8e\x5e\x0c\x12\x62\x90\xe2\xfc\x47\x64\x30\x4b\x93\xc2\xa7\x19\xe1\x42\xdd\x5f\x75\x9c\xce\xb5\xd5\x30\x44\xf5\x6b\x4a\x2e\x64\xe9\x93\x3c\x08\xb8\x70\xd4\x5c\xf0\x10\x67\xdf\x4a\xf9\xa0\x1e\x89\x99\x42\x4f\xe9\xf0\x99\x98\xb1\xa7\xfb\xfd\x7e\xff\x50\x4b\xe8\xad\xe3\xc9\xe3\x62\x7d\x3b\xaf\x33\x3c\x07\xe0\x61\x57\xea\x5a\x1f\x20\xcd\x81\xaf\x22\xe1\x81\xbc\xdf\xca\x5e\x32\x75\xc4\xe6\xb9\x4f\x71\x0e\xed\x5e\xc7\x56\x5c\x2b\x2c\xef\x18\xe2\x9c\xa7\x39\x9b\xdf\x47\x5a\xcd\x92\x4a\xcb\x24\x78\x17\x08\xce\x03\x49\x8b\x43\xe7\x82\xe3\x81\x58\xec\x06\x17\x7a\xf3\xea\xe8\x42\x0b\xcf\xb4\x00\x36\x25\xed\x4d\xa2\x92\xaf\x67\x5a\x84\x2c\xf1\x77\x29\x8e\xca\x96\x63\xe1\xbc\xb4\x14\x93\x3e\xb0\xce\x5d\xb8\x92\x62\xc0\x63\x14\x94\xbc\x6e\x61\x79\x13\x9f\x25\xed\xcf\xb4\x30\x48\xb4\xa6\x52\x01\x07\xf0\x84\xce\xe3\xd1\x97\xb4\x9d\x78\xf2\xea\xbd\xe1\x61\x7d\x80\x38\x91\xb0\xc2\x89\x52\x76\xd2\x8b\xc6\x61\xb3\xb6\xf1\x29\x1c\x84\x78\x8d\xba\x56\x57\x03\xde\xc7\xd7\x0a\x1c\xab\x6a\x6a\x4d\x95\x6c\x9b\x71\xca\xcb\x0a\xe3\xea\xcd\xf0\xca\x1b\x16\xdd\xc8\xab\xa3\x35\x1c\xe7\xbc\xb9\x38\xc4\xe4\xfe\x8c\x21\x5f\x6c\x5c\x41\xa0\xb8\x73\xeb\x82\xd9\xc8\x78\x7c\x1d\xee\xa5\x4f\x84\x24\x05\x46\x08\x74\x86\x8c\xc7\x4d\x8a\xcf\x2e\x37\x83\x3c\xad\xa8\xb4\x76\x93\x76\xc8\x4a\x8e\x56\xb5\x89\x1a\xd7\x39\x6a\x55\x85\xed\x04\x91\x94\x79\x17\xcf\xc8\xe5\x81\x92\xa1\xaf\x78\x14\xe6\xf1\x48\xe9\x11\x62\x12\xcb\x12\xb4\xc2\xb8\xda\x7f\x23\xff\x40\xbc\xf0\xb1\xbf\xaa\x90\x8f\xbd\x72\x79\x0f\xa3\xcd\x88\x95\xbb\xa5\xe3\xdc\x03\x67\xcc\xa4\xe8\x6c\x11\x4c\x7e\xee\x05\x8d\x03\x67\x91\xb0\x9f\x7f\x94\x2c\x94\xd7\xeb\x44\x18\xc3\x8d\x6c\xa2\x51\x1a\xee\x56\xd4\x1e\xff\x41\x52\x90\xaf\x3e\xe8\x7f\xac\x0e\x17\x83\xd4\x16\xee\x5b\x27\xe7\xa9\xc5\x2c\xca\xed\x8f\x1f\x11\x29\x4b\xf0\xd6\x37\x7b\x24\xd6\x19\x79\xe5\xe0\x15\x42\x15\x24\x96\xca\x74\x32\xb2\x17\xac\x16\xcb\xdb\xcc\xac\x96\x01\x15\xc5\x7a\x97\x87\xf9\xb8\x6f\xe2\xf8\x41\x21\x6e\x67\xf7\xd3\x07\xe3\xda\x35\x03\x86\x40\x7e\xaf\xfb\x77\xbd\xb6\xd0\x73\x04\x26\x7a\xb5\x75\xca\xe4\xea\xf1\x64\x21\x8d\x18\xb0\xa7\x54\xc0\x4a\x94\xd4\x4f\x46\xf9\x6c\x94\x7a\x05\x87\x15\xb4\x4b\x32\x6e\xd6\xcf\x4d\x96\xb6\x48\x4a\x31\x2e\x01\x6d\x21\x4a\xaa\xda\x78\x0e\x3e\x62\x0b\xf7\x59\xfa\xdc\x85\xc6\xcf\xad\x76\xd7\xa2\x53\x5e\x84\x0c\xdc\x71\xd1\x36\xf6\x89\xb0\x5d\x2e\x55\x7a\x58\x97\xbb\x28\xd2\x3e\x91\x3f\xac\x94\x69\x0e\xd9\x8d\x76\x86\x95\x32\x36\x2d\x4c\x98\x87\xfa\x00\x1f\x07\x0c\xbd\x61\xdf\x39\xa6\x67\xc1\xc7\xd6\x25\x6a\x72\x4c\xcb\x3a\x5e\x56\xc7\x5a\x25\x4a\x80\x67\x31\xf2\xa4\x7b\xe5\x7a\xa9\xbd\x52\x61\xec\x32\x43\xd7\x30\xf0\xb3\xfc\xc6\x6d\xfa\xff\xe6\xce\x2c\xd1\xd8\xf8\x97\x53\xcd\xa2\xf1\x84\x8a\xe2\x82\x11\x06\x6e\xe5\xf8\x89\x69\xa3\x95\x17\xa5\x0a\x9f\xa4\xb1\xa5\x89\x0c\xff\xa3\x59\xdc\x16\xb0\xc2\x4d\x8e\x26\x24\x01\xee\x76\xbb\xaa\x12\x10\xb1\xeb\x5b\x64\xb6\xc3\x5a\x50\x7d\x3b\x78\xcb\x51\xde\x52\x87\xb3\xdf\xca\x7b\x50\xe7\xbd\x0b\x32\x84\x9f\xbe\x4f\x91\x06\x2d\x65\xa7\x94\x62\x92\x7a\xbc\x85\x8f\x05\xda\x9e\x30\xc9\xf9\x5f\x55\xbf\xc9\x9e\x2b\xbb\x0d\x70\xb5\xfe\x78\x7d\xd1\x03\xbd\xe4\x84\xc0\x4b\xc8\xf8\xf2\x6a\xf3\xd3\xcb\xa4\xdf\x14\xd4\xc5\x44\xd5\xaa\xe9\xfa\x0b\x02\xbe\x46\x55\x23\x53\x52\x2e\xcb\xb2\x2b\x2c\x7d\xeb\x31\xc9\x6e\x9c\xfc\x02\xb2\x9b\x15\xf3\xab\x72\x4c\xde\xce\x98\x3a\x14\x4e\x2e\xc5\x30\xda\x75\x93\x9c\x34\x38\x6f\xf5\x5d\xbf\x72\x30\x29\x6c\xe6\x81\x96\x6a\x5d\xf6\xe6\xad\xc0\xb7\x36\x9c\x4b\xeb\xa5\xf7\x5f\x17\xe4\xe2\xba\x04\x2e\x6e\xe8\x57\xd4\x7a\xf9\x88\x7e\x39\x2c\xb2\x6b\x9e\xb9\xd2\x6b\xe3\x72\x44\x50\x39\x98\xb6\x4a\xd9\x5d\x62\x59\x19\xf4\x3b\xea\xaf\x00\x00\x00\xff\xff\xb1\x91\xa9\x65\xad\x0d\x00\x00")
 
 func runtimeHelpCommandsMdBytes() ([]byte, error) {
        return bindataRead(
@@ -2631,6 +2632,26 @@ func runtimeSyntaxOcamlYaml() (*asset, error) {
        return a, nil
 }
 
+var _runtimeSyntaxOctaveYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x56\xdf\x6f\xdb\x36\x10\x7e\xd7\x5f\x71\x93\x9b\x25\x6e\x26\x29\xed\x0a\x6c\x13\xd6\x15\x5d\xb6\x00\x79\x68\x02\xac\x1b\x10\x20\xf2\x02\x8a\x3a\x59\x44\x28\x52\x20\x4f\x51\xbc\xd0\xfb\xdb\x07\x4a\xb2\x13\xbb\x9d\x9b\x6c\xd8\x80\xea\x45\xe4\xfd\xf8\x3e\xf2\xbb\xf3\x59\x13\xf8\x05\x4b\x34\xa8\x38\xda\x60\x02\x15\x51\x63\xd3\x24\x99\x0b\xaa\xda\x3c\xe6\xba\x4e\xfe\x58\x60\x21\x0a\xc1\x92\x5a\x70\xa3\x93\x5c\xea\x3c\xa9\x99\x25\x34\x89\x69\x15\x89\x1a\x13\xbb\x50\xc4\x6e\x93\xb9\x8e\x17\xac\x96\x1f\x87\xb9\x11\x75\x64\xb9\x11\x0d\xd9\x44\x73\x62\x37\x18\x7b\x53\xb4\x01\x38\x02\xdd\xfb\x83\x49\x30\x81\x5f\xcf\x7f\x3a\x0f\x26\x20\x14\x97\x6d\x81\xa0\x95\x5c\x80\x42\x2c\xb0\x00\xdd\xa0\x61\xa4\x8d\x3f\x7b\x1c\xc7\x50\x89\x79\x25\xc5\xbc\x22\xa1\xe6\xc1\x04\xf2\x56\x48\x8a\x84\x82\xb2\x55\x9c\x84\x56\x1b\x01\x6f\xfc\x49\x57\x7b\xc0\xc6\x26\x8d\x48\x10\x90\x78\x0c\xcc\xae\x73\x2c\x74\x15\x2a\x28\xb5\x94\xba\xc3\x02\xf2\x05\x1c\x4c\x83\x09\x74\x15\x23\x60\x06\xc1\x5e\x8b\x06\x98\x2a\x00\x8d\xd1\x06\x4a\x81\xb2\xb0\x20\x14\x58\x32\x42\xcd\xad\xe7\xa9\x5b\x49\x42\x0a\x85\xc0\x75\x5d\xa3\x22\x0b\x4a\x13\x74\xda\x5c\xfb\xa3\x06\xa5\x90\x48\x8b\x06\x53\x18\x2e\x1f\x04\x05\x12\x72\x4a\x03\x00\x00\xef\x55\xac\xc6\x14\xc2\x2c\x8b\xeb\x67\x61\x10\x98\x56\xa2\x1d\xbc\x13\x78\x4f\x8c\x70\x40\x5d\x49\xdf\x75\x5d\x3c\x57\x6d\xac\xcd\x3c\xb1\xba\xa4\x8e\x19\x1c\x85\x4d\x0a\xcd\x93\x9b\x57\xf1\x51\x7c\x94\xdc\x67\xc6\x15\xd5\xb2\xc7\x8b\xc0\xae\xac\x3d\x61\x7e\xb0\x92\xc2\xa1\x2a\xd6\x6b\x83\xd4\x9a\xde\xe4\xe6\x52\xe7\x4c\xba\x06\x8d\x15\x96\x50\xd1\x34\xcb\xf2\xf0\x6f\xc0\x44\xe9\x50\x5a\x1c\x5f\x3e\x5f\x94\xce\x76\x82\x78\xe5\x38\xb3\xe8\x34\x55\x68\x3a\x31\xf8\x06\xc7\x2e\xbc\xae\x12\xb2\x0f\x1d\x16\x85\x76\xbe\x2d\xa5\x2b\xb5\xe9\xcf\xab\x8d\x6b\x98\x19\x77\xe3\x2a\x37\xc8\xae\x1d\xd7\x8a\x84\x6a\x71\x17\x7a\xab\x3a\xa1\x8a\xab\xc6\x68\x5f\x0e\xb7\xb9\xbd\xe2\x12\x99\x6a\x1b\x8f\x7c\xb5\x15\x49\x66\xe1\x38\xf3\x97\xf2\x4e\x32\x8b\xab\x7e\x37\x70\x8d\x75\x3b\x5f\xb7\xef\x48\xbe\xa8\x73\x2d\xe3\x55\x57\xa7\x10\x5e\x46\x87\xc9\xf3\xd7\xdf\xff\xf0\xc5\x9f\x7b\x5f\xba\xdf\x67\x2e\x7d\xbd\x4e\xfe\xd1\x30\x7e\x8d\xb4\x95\x9b\x8f\xd6\x14\xc2\x83\x2c\xbb\x73\x59\xb6\x9c\x86\xbb\x42\x0e\x5c\x96\x4d\x77\x87\x5c\xba\x2c\x9b\x4d\xd7\xc4\xc7\xba\xae\xd9\x26\x6d\x0a\xe1\x57\x6b\xff\x59\x5b\xe7\x68\x9e\xd8\x8a\x2f\x92\x77\x8c\x2a\xac\x19\x09\xce\x64\x74\xac\x95\x25\xb6\xd5\x96\x7c\x34\xc6\xaa\x67\x18\x2b\x74\x79\x14\x7d\x37\x3b\x74\x47\xb7\x7e\xc1\xa2\xf2\x6d\x74\x32\x7b\xee\x65\x76\xfb\xf1\x7e\xb8\x33\xb5\x11\x0e\xdd\xa9\x3b\x55\xa5\x3b\x63\x67\x0e\x1b\xeb\x0c\x32\x59\xb3\xdb\xe1\x2d\x54\x8f\x73\x2f\xb9\xd6\xbe\xe0\xdb\x98\xb9\xee\x15\xf0\x88\x64\x5a\x74\x25\x93\x16\x37\x0a\xfd\x7e\x98\x04\x4f\x95\x64\x4c\xfb\xa8\x06\xc3\x70\x19\x26\x80\x7f\x2c\x31\xd3\x37\x6d\x18\xae\x6d\xa8\x8a\x2d\x8b\x9f\x55\xfd\x51\xb3\x2c\xbe\xb7\x3e\x18\x26\xab\xe7\x21\x53\x83\x5c\x30\x79\x5c\x31\xaf\xdb\x5e\xf8\xb8\x38\x4f\x71\xc9\xf2\x52\x19\xba\xd9\xcf\xb2\xac\x37\xcc\x9e\x90\xec\x0b\xfb\xcd\xec\xee\xeb\xa5\xbb\xbd\x7c\x1b\x9d\xb0\xa8\xf4\x85\xbe\x7b\xb9\x74\xed\xc3\xfd\xab\xa5\xfb\xed\xe1\xfe\xdb\xe5\xaa\x53\x1f\x21\xd6\xfe\xb6\x56\xfb\xff\x48\xaa\x7e\xf0\xa7\x10\xc6\xf1\xe1\x23\x2f\xf8\xf9\xa8\x38\xfc\xde\x9f\xfa\xdf\xf2\x32\x7e\x91\xac\xf2\x36\xdb\xb7\xb7\x7d\x58\x89\xbd\xed\x4a\x3c\xfb\x84\xe6\xa4\x0b\xed\xc7\x93\xff\x3a\x70\x17\x17\x17\xee\xe4\xf4\xe2\xdd\xcf\xd3\xf4\x4d\xf8\x29\xaa\xc9\xff\x47\xb5\x77\xb7\xcd\xb5\xb7\xfc\xef\xee\xf5\x01\xd9\xe4\x5f\x90\xfd\x15\x00\x00\xff\xff\xc0\x0a\x9c\xc0\x1a\x0a\x00\x00")
+
+func runtimeSyntaxOctaveYamlBytes() ([]byte, error) {
+       return bindataRead(
+               _runtimeSyntaxOctaveYaml,
+               "runtime/syntax/octave.yaml",
+       )
+}
+
+func runtimeSyntaxOctaveYaml() (*asset, error) {
+       bytes, err := runtimeSyntaxOctaveYamlBytes()
+       if err != nil {
+               return nil, err
+       }
+
+       info := bindataFileInfo{name: "runtime/syntax/octave.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
+       a := &asset{bytes: bytes, info: info}
+       return a, nil
+}
+
 var _runtimeSyntaxPascalYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x54\x6d\x8b\x23\x37\x0c\xfe\x9e\x5f\x11\xd2\x85\x26\xb7\xcd\x5e\x0b\xa5\xd0\x7c\x09\xa5\xd0\x3f\x91\x49\x41\x63\x6b\x32\xea\x7a\xec\x41\x92\xf3\xd2\xd5\xfd\xf7\x62\xcf\xde\xbe\x24\xd0\x3d\x2e\x84\xb1\x2c\xcb\xf2\xf3\x3c\xb2\xdc\x51\x40\xbd\x8c\xb8\x99\x8f\x20\x0e\xc2\x6c\xe6\x51\xd1\xe9\x66\x36\x9f\xcf\xe7\x65\x35\xc2\x80\x9b\xf9\xa2\x69\x1e\x46\x90\xbb\xc5\x6c\xc6\x39\xa0\x4c\xeb\xeb\xf9\xb4\x77\xd1\x34\xed\x72\x4b\x9b\xa5\x28\x53\x3c\x18\x44\xa1\x67\xf3\x44\x1e\x9f\x4d\xe9\x13\xeb\xb3\xed\x7a\xe0\x1a\x56\x8d\x12\x54\x8d\x36\xa5\x80\x10\xad\xbd\x28\x4e\xf1\x14\xd5\x4e\x89\xbd\xc9\x00\x21\x94\x59\x48\xf1\x50\x3d\x0e\xd8\x53\x84\x50\x3d\x65\x85\xa2\xe2\x01\xb9\x8c\xbf\xfd\x6a\x42\xf1\x10\xd0\x5c\x66\xc6\xe8\x2e\xe6\x53\x6e\x03\x1a\x9e\x15\xa3\x47\xbf\x5a\x35\x4d\xbb\x78\xa6\x21\x0a\x8a\x03\x46\x7d\xc3\x05\xa2\x37\x90\xc1\x80\x19\x2e\xd6\xe2\x81\xa2\xb5\x8c\xf0\x68\x0e\x04\xcd\xa5\x28\x3a\x7d\x39\x3b\x4d\x5c\x6c\xa5\x98\xd1\x2a\xe3\xc9\xe7\xe9\x68\x3e\x99\x4f\xa7\xa8\xc9\x30\x08\x1a\x46\x6f\x45\x58\xeb\x12\x5b\x97\xa3\x53\x4a\xd1\x0e\x49\x93\x51\x67\x34\x8c\xa1\x22\x81\xea\xa6\xf2\x0f\x14\xb1\x92\xe3\x0e\x1c\x5a\x80\x16\x83\x0d\xc9\x5b\x4c\x6a\xa9\xfd\x07\x9d\x5a\xea\x2c\x45\x4b\x23\x32\x94\x73\x13\xdb\x08\xee\x11\xbd\x8d\x9c\x1c\xfa\xcc\x58\xac\x03\xc3\x60\x8c\xae\xc8\xc7\x38\x22\xa8\x31\x4a\xca\xec\x5e\x8a\x84\x6a\xd2\x07\x93\x9e\x4d\x7b\x8c\xa6\xc9\x4a\x91\x2d\x47\x52\xcb\x51\x29\x58\x16\x14\x3b\x96\xba\xf5\x85\xc7\x89\xb4\xb7\x73\xe2\x8f\x15\x15\x73\x01\x44\xcc\x93\x8c\xa9\x48\x71\x76\x38\xaa\xe1\x99\xca\x67\x2c\xd7\xc3\xba\x52\x52\xfa\x77\xa2\x5f\x27\xe1\x62\x14\x7b\x64\x52\xf4\x46\x91\x94\x5e\x03\x48\x2c\x50\xcb\xc0\x17\x8b\x78\xaa\x12\x64\x2d\x4c\x47\x64\xbd\x18\x03\x09\x9a\x60\xe8\x4c\x7b\x46\xf0\x05\xb5\xf2\xe5\x63\xa8\xad\xa4\x90\x15\x0d\x5a\x51\x06\xa7\x06\x81\x40\x0c\x44\x70\x68\x03\xb2\x39\x8f\x2e\x98\x1b\xc7\x3a\x7a\xec\x20\x87\xaf\x2c\xea\x25\xe3\x72\x35\xbb\xc4\x27\x60\x6f\x07\x8c\xc8\xe4\x8c\xa2\xc7\xb3\x85\xe4\x20\x58\xe9\x2c\x8b\x49\x14\xdc\x63\xc7\x65\x92\x82\xef\x46\xe7\x20\x04\x4b\x47\x64\x26\x8f\x36\xf5\xa5\x8d\x4c\x47\xd0\x5a\xc4\xd2\x9f\xa5\xb0\xb9\x0d\xe4\xa6\x41\x7a\x2c\x05\x85\xf2\x39\x90\x28\xb2\x31\x52\x54\x4e\x3e\x3b\x34\x81\x0e\x6b\x56\x49\x9d\x76\x21\x81\x9a\x8c\xe8\xaa\x8e\x68\xa2\xbe\x2e\x1e\x89\x35\x43\xb0\x53\x51\xfa\x9d\x42\xf5\x96\xc3\x3b\x81\x3a\x28\x77\x59\x39\xa3\x45\x0a\xef\xf5\x9c\x52\x4f\x4f\x44\xf9\x89\x02\x97\xbd\x20\xc3\xe2\xc5\x89\xd1\x6f\xe6\x0b\x8c\xfe\xd5\x35\xbd\x2c\xf3\xdd\xfe\xea\xd8\x87\x98\x87\x16\xb9\x9e\x7e\xb7\xfb\x79\xfd\xfb\x1f\xeb\xbf\x60\xdd\xed\xef\xaf\xf1\xbd\x0d\x6c\x77\xf7\xeb\xfd\xb6\x44\xef\xef\x97\xbb\x87\xaf\xe6\x6a\x5b\xe0\xe3\x9b\xc5\xd5\xf6\x26\xcd\xd4\x0b\xb7\x04\x7e\xa8\x3b\x9e\x7e\xf9\xe9\xcb\x35\x8f\xbb\x1b\x16\x2f\xf3\xeb\xdc\x93\x3a\x7f\xf6\x30\xe1\x6c\x9a\x87\x6f\x3e\xff\xc7\xeb\x63\xdf\x38\xe4\x91\xc6\xf7\x09\x5f\xc1\x7c\x07\x96\x91\xb1\xbc\x1c\xb7\x18\x9e\x9a\xe6\xee\x1a\xc6\x97\xff\xab\xe1\x50\x5b\xeb\x26\xcf\xe7\xcf\x1f\x6b\xf8\x71\x96\xa6\x59\x36\xcd\xa7\xeb\x4c\x4d\xf3\xa9\x69\x56\xdf\x91\x6e\xf9\xb4\x5a\x6e\x37\xbb\xbf\xef\xf6\xab\x6f\xe2\x38\xfb\x2f\x00\x00\xff\xff\x99\x9e\xdd\x36\x40\x07\x00\x00")
 
 func runtimeSyntaxPascalYamlBytes() ([]byte, error) {
@@ -3683,6 +3704,7 @@ var _bindata = map[string]func() (*asset, error){
        "runtime/syntax/nim.yaml": runtimeSyntaxNimYaml,
        "runtime/syntax/objc.yaml": runtimeSyntaxObjcYaml,
        "runtime/syntax/ocaml.yaml": runtimeSyntaxOcamlYaml,
+       "runtime/syntax/octave.yaml": runtimeSyntaxOctaveYaml,
        "runtime/syntax/pascal.yaml": runtimeSyntaxPascalYaml,
        "runtime/syntax/patch.yaml": runtimeSyntaxPatchYaml,
        "runtime/syntax/peg.yaml": runtimeSyntaxPegYaml,
@@ -3907,6 +3929,7 @@ var _bintree = &bintree{nil, map[string]*bintree{
                        "nim.yaml": &bintree{runtimeSyntaxNimYaml, map[string]*bintree{}},
                        "objc.yaml": &bintree{runtimeSyntaxObjcYaml, map[string]*bintree{}},
                        "ocaml.yaml": &bintree{runtimeSyntaxOcamlYaml, map[string]*bintree{}},
+                       "octave.yaml": &bintree{runtimeSyntaxOctaveYaml, map[string]*bintree{}},
                        "pascal.yaml": &bintree{runtimeSyntaxPascalYaml, map[string]*bintree{}},
                        "patch.yaml": &bintree{runtimeSyntaxPatchYaml, map[string]*bintree{}},
                        "peg.yaml": &bintree{runtimeSyntaxPegYaml, map[string]*bintree{}},
index 9da6aebde098abfe41d0043c6d0792365ef832cb..3c1ef0d0ab3a3dbf2596e88792157cc409fa5858 100644 (file)
@@ -12,6 +12,7 @@ import (
        "unicode/utf8"
 
        "github.com/mattn/go-runewidth"
+       "github.com/mattn/go-shellwords"
        homedir "github.com/mitchellh/go-homedir"
 )
 
@@ -278,92 +279,50 @@ func ShortFuncName(i interface{}) string {
 
 // SplitCommandArgs separates multiple command arguments which may be quoted.
 // The returned slice contains at least one string
-func SplitCommandArgs(input string) []string {
-       var result []string
-       var curQuote *bytes.Buffer
-
-       curArg := new(bytes.Buffer)
-       escape := false
+func SplitCommandArgs(input string) ([]string, error) {
+       shellwords.ParseEnv = true
+       shellwords.ParseBacktick = true
+       return shellwords.Parse(input)
+}
 
-       finishQuote := func() {
-               if curQuote == nil {
-                       return
+// JoinCommandArgs joins multiple command arguments and quote the strings if needed.
+func JoinCommandArgs(args ...string) string {
+       var buf bytes.Buffer
+       for i, w := range args {
+               if i != 0 {
+                       buf.WriteByte(' ')
                }
-               str := curQuote.String()
-               if unquoted, err := strconv.Unquote(str); err == nil {
-                       str = unquoted
+               if w == "" {
+                       buf.WriteString("''")
+                       continue
                }
-               curArg.WriteString(str)
-               curQuote = nil
-       }
-
-       appendResult := func() {
-               finishQuote()
-               escape = false
-
-               str := curArg.String()
-               result = append(result, str)
-               curArg.Reset()
-       }
-
-       for _, r := range input {
-               if r == ' ' && curQuote == nil {
-                       appendResult()
-               } else {
-                       runeHandled := false
-                       appendRuneToBuff := func() {
-                               if curQuote != nil {
-                                       curQuote.WriteRune(r)
-                               } else {
-                                       curArg.WriteRune(r)
-                               }
-                               runeHandled = true
-                       }
 
-                       if r == '"' && curQuote == nil {
-                               curQuote = new(bytes.Buffer)
-                               appendRuneToBuff()
-                       } else {
-                               if curQuote != nil && !escape {
-                                       if r == '"' {
-                                               appendRuneToBuff()
-                                               finishQuote()
-                                       } else if r == '\\' {
-                                               appendRuneToBuff()
-                                               escape = true
-                                               continue
-                                       }
-                               }
-                       }
-                       if !runeHandled {
-                               appendRuneToBuff()
+               strBytes := []byte(w)
+               for _, b := range strBytes {
+                       switch b {
+                       case
+                               'a', 'b', 'c', 'd', 'e', 'f', 'g',
+                               'h', 'i', 'j', 'k', 'l', 'm', 'n',
+                               'o', 'p', 'q', 'r', 's', 't', 'u',
+                               'v', 'w', 'x', 'y', 'z',
+                               'A', 'B', 'C', 'D', 'E', 'F', 'G',
+                               'H', 'I', 'J', 'K', 'L', 'M', 'N',
+                               'O', 'P', 'Q', 'R', 'S', 'T', 'U',
+                               'V', 'W', 'X', 'Y', 'Z',
+                               '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+                               '_', '-', '.', ',', ':', '/', '@':
+                               buf.WriteByte(b)
+                       case '\n':
+                               buf.WriteString("'\n'")
+                       default:
+                               buf.WriteByte('\\')
+                               buf.WriteByte(b)
                        }
                }
 
-               escape = false
+               // return buf.String()
+               // buf.WriteString(w)
        }
-       appendResult()
-       return result
-}
-
-// JoinCommandArgs joins multiple command arguments and quote the strings if needed.
-func JoinCommandArgs(args ...string) string {
-       buf := new(bytes.Buffer)
-       first := true
-       for _, arg := range args {
-               if first {
-                       first = false
-               } else {
-                       buf.WriteRune(' ')
-               }
-               quoted := strconv.Quote(arg)
-               if quoted[1:len(quoted)-1] != arg || strings.ContainsRune(arg, ' ') {
-                       buf.WriteString(quoted)
-               } else {
-                       buf.WriteString(arg)
-               }
-       }
-
        return buf.String()
 }
 
index 0104218eb90b555cffb77dde751cf3a876dea81f..51a24e024e79d93c7a63e537799f3ec7bc13fc66 100644 (file)
@@ -1,7 +1,6 @@
 package main
 
 import (
-       "reflect"
        "testing"
 )
 
@@ -67,56 +66,6 @@ func TestIsWordChar(t *testing.T) {
        }
 }
 
-func TestJoinAndSplitCommandArgs(t *testing.T) {
-       tests := []struct {
-               Query  []string
-               Wanted string
-       }{
-               {[]string{`test case`}, `"test case"`},
-               {[]string{`quote "test"`}, `"quote \"test\""`},
-               {[]string{`slash\\\ test`}, `"slash\\\\\\ test"`},
-               {[]string{`path 1`, `path\" 2`}, `"path 1" "path\\\" 2"`},
-               {[]string{`foo`}, `foo`},
-               {[]string{`foo\"bar`}, `"foo\\\"bar"`},
-               {[]string{``}, ``},
-               {[]string{`"`}, `"\""`},
-               {[]string{`a`, ``}, `a `},
-               {[]string{``, ``, ``, ``}, `   `},
-               {[]string{"\n"}, `"\n"`},
-               {[]string{"foo\tbar"}, `"foo\tbar"`},
-       }
-
-       for i, test := range tests {
-               if result := JoinCommandArgs(test.Query...); test.Wanted != result {
-                       t.Errorf("JoinCommandArgs failed at Test %d\nGot: %q", i, result)
-               }
-
-               if result := SplitCommandArgs(test.Wanted); !reflect.DeepEqual(test.Query, result) {
-                       t.Errorf("SplitCommandArgs failed at Test %d\nGot: `%q`", i, result)
-               }
-       }
-
-       splitTests := []struct {
-               Query  string
-               Wanted []string
-       }{
-               {`"hallo""Welt"`, []string{`halloWelt`}},
-               {`"hallo" "Welt"`, []string{`hallo`, `Welt`}},
-               {`\"`, []string{`\"`}},
-               {`"foo`, []string{`"foo`}},
-               {`"foo"`, []string{`foo`}},
-               {`"\"`, []string{`"\"`}},
-               {`"C:\\"foo.txt`, []string{`C:\foo.txt`}},
-               {`"\n"new"\n"line`, []string{"\nnew\nline"}},
-       }
-
-       for i, test := range splitTests {
-               if result := SplitCommandArgs(test.Query); !reflect.DeepEqual(test.Wanted, result) {
-                       t.Errorf("SplitCommandArgs failed at Split-Test %d\nGot: `%q`", i, result)
-               }
-       }
-}
-
 func TestStringWidth(t *testing.T) {
        tabsize := 4
        if w := StringWidth("1\t2", tabsize); w != 5 {
diff --git a/cmd/micro/vendor/github.com/mattn/go-shellwords b/cmd/micro/vendor/github.com/mattn/go-shellwords
new file mode 160000 (submodule)
index 0000000..95c860c
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 95c860c1895b21b58903abdd1d9c591560b0601c
index 45264f2ac32f5e3546b164ad660354eab1a10e40..5c1ed45cebff79eddaf63a08af1002057cdc2777 100644 (file)
@@ -9,11 +9,12 @@ Here are the possible commands that you can use.
   will 'save as' the filename.
 
 * `replace "search" "value" flags`: This will replace `search` with `value`. 
-   The `flags` are optional. At this point, there is only one flag: `-a`, which
-   replaces all occurrences at once.
+   The `flags` are optional. Possible flags are:
+   * `-a`: Replace all occurrences at once
+   * `-l`: Do a literal search instead of a regex search
 
-   Note that `search` must be a valid regex.  If one of the arguments does not
-   have any spaces in it, you may omit the quotes.
+   Note that `search` must be a valid regex (unless `-l` is passed). If one 
+   of the arguments does not have any spaces in it, you may omit the quotes.
 
 * `replaceall "search" "value"`: This will replace `search` with `value` without
    user confirmation.
@@ -84,3 +85,11 @@ Here are the possible commands that you can use.
 The following commands are provided by the default plugins:
 
 * `lint`: Lint the current file for errors.
+
+# Command Parsing
+
+When running a command, you can use extra syntax that micro will expand before
+running the command. To use an argument with a space in it, simply put it in
+quotes. You can also use environment variables in the command bar and they
+will be expanded to their value. Finally, you can put an expression in backticks
+and it will be evaluated by the shell beforehand.