Skip to content

Commit

Permalink
Merge pull request #25 from laurent22/editor-spaces
Browse files Browse the repository at this point in the history
Spaces in path to editor working. Fixed #19
  • Loading branch information
Laurent Cozic committed Dec 6, 2015
2 parents 69f4ce9 + 1a25e5f commit ae4c57d
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ tests/
.DS_Store
testing/
createfiles.sh
.vscode
.vscode
run.sh
73 changes: 70 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,68 @@ func guessEditorCommand() (string, error) {
return "", errors.New("could not guess editor command")
}

// Returns the executable path and arguments
func parseEditorCommand(editorCmd string) (string, []string, error) {
var args []string
state := "start"
current := ""
quote := "\""
for i := 0; i < len(editorCmd); i++ {
c := editorCmd[i]

if state == "quotes" {
if string(c) != quote {
current += string(c)
} else {
args = append(args, current)
current = ""
state = "start"
}
continue
}

if c == '"' || c == '\'' {
state = "quotes"
quote = string(c)
continue
}

if state == "arg" {
if c == ' ' || c == '\t' {
args = append(args, current)
current = ""
state = "start"
} else {
current += string(c)
}
continue
}

if c != ' ' && c != '\t' {
state = "arg"
current += string(c)
}
}

if state == "quotes" {
return "", []string{}, errors.New(fmt.Sprintf("Unclosed quote in command line: %s", editorCmd))
}

if current != "" {
args = append(args, current)
}

if len(args) <= 0 {
return "", []string{}, errors.New("Empty command line")
}

if len(args) == 1 {
return args[0], []string{}, nil
}

return args[0], args[1:], nil
}

func editFile(filePath string) error {
var err error
editorCmd := config_.String("editor")
Expand All @@ -181,9 +243,14 @@ func editFile(filePath string) error {
}
}

pieces := strings.Split(editorCmd, " ")
pieces = append(pieces, filePath)
cmd := exec.Command(pieces[0], pieces[1:]...)
commandString, args, err := parseEditorCommand(editorCmd)
if err != nil {
return err
}

args = append(args, filePath)
// Run the properly formed command
cmd := exec.Command(commandString, args[0:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
err = cmd.Run()
Expand Down
85 changes: 85 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,91 @@ ijkl
}
}

func Test_parseEditorCommand(t *testing.T) {
type TestCase struct {
editorCmd string
executable string
args []string
hasError bool
}

var testCases []TestCase

testCases = append(testCases, TestCase{
editorCmd: "subl",
executable: "subl",
args: []string{},
hasError: false,
})

testCases = append(testCases, TestCase{
editorCmd: "/usr/bin/vim -f",
executable: "/usr/bin/vim",
args: []string{ "-f" },
hasError: false,
})

testCases = append(testCases, TestCase{
editorCmd: "\"F:\\Sublime Text 3\\sublime_text.exe\" /n /w",
executable: "F:\\Sublime Text 3\\sublime_text.exe",
args: []string{ "/n", "/w" },
hasError: false,
})

testCases = append(testCases, TestCase{
editorCmd: "subl -w --command \"something with spaces\"",
executable: "subl",
args: []string{ "-w", "--command", "something with spaces" },
hasError: false,
})

testCases = append(testCases, TestCase{
editorCmd: "notepad.exe /PT",
executable: "notepad.exe",
args: []string{ "/PT" },
hasError: false,
})

testCases = append(testCases, TestCase{
editorCmd: "vim -e \"unclosed quote",
executable: "",
args: []string{},
hasError: true,
})

testCases = append(testCases, TestCase{
editorCmd: "subl -e 'unclosed single-quote",
executable: "",
args: []string{},
hasError: true,
})

testCases = append(testCases, TestCase{
editorCmd: "",
executable: "",
args: []string{},
hasError: true,
})

for _, testCase := range testCases {
executable, args, err := parseEditorCommand(testCase.editorCmd)
if (err != nil && !testCase.hasError) || (err == nil && testCase.hasError) {
t.Errorf("Error status did not match: %b: %s", testCase.hasError, err)
}
if executable != testCase.executable {
t.Errorf("Expected '%s', got '%s'", testCase.executable, executable)
}
if len(args) != len(testCase.args) {
t.Errorf("Expected and result args don't have the same length: [%s], [%s]", strings.Join(testCase.args, ", "), strings.Join(args, ", "))
}
for i, arg := range testCase.args {
if arg != args[i] {
t.Errorf("Expected and result args differ: [%s], [%s]", strings.Join(testCase.args, ", "), strings.Join(args, ", "))
}
}
}
}

func Test_processFileActions(t *testing.T) {
setup(t)
defer teardown(t)
Expand Down
2 changes: 1 addition & 1 deletion version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package main

import "fmt"

const VERSION = "1.4.0"
const VERSION = "1.5.0"

func handleVersionCommand(opts *CommandLineOptions, args []string) error {
fmt.Println(VERSION)
Expand Down

0 comments on commit ae4c57d

Please sign in to comment.