Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start vim from go?

I've got a command line tool written in Golang and I need to start vim from it. However it's not working, and there's not any error or much else to work with. I've reduced the code to just this:

package main

import (
    "fmt"
    "os/exec"
)

func main() {
    cmd := exec.Command("vim", "test.txt")
    err := cmd.Run()
    fmt.Println(err)
}

When I run this, I can see the vim process for a 2-3 seconds but the application doesn't actually open. Then the program simply exits (and the vim process closes) with an "exit status 1".

I've also tried this to capture stderr:

package main

import (
    "bytes"
    "fmt"
    "os/exec"
)

func main() {
    cmd := exec.Command("vim", "test.txt")
    var stderr bytes.Buffer
    cmd.Stderr = &stderr
    err := cmd.Run()
    fmt.Println(err)
    fmt.Println(stderr)
}

But in this case, the program gets stuck indefinitely.

Any idea what could be the issue?

like image 923
laurent Avatar asked Feb 02 '14 16:02

laurent


2 Answers

Pass on stdin and stdout from the calling program which, provided it was run from a terminal (likely for a command line program) will start vim for you and return control when the user has finished editing the file.

package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    cmd := exec.Command("vim", "test.txt")
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    err := cmd.Run()
    fmt.Println(err)
}
like image 183
Nick Craig-Wood Avatar answered Oct 08 '22 03:10

Nick Craig-Wood


VIM needs a proper terminal and detects the absence of one.

If you use the StderrPipe and read it while vim is running you will see this:

2014/02/02 20:25:49 Vim: Warning: Output is not to a terminal
2014/02/02 20:25:49 Vim: Warning: Input is not from a terminal

Example for reading stderr while executing (on play):

func logger(pipe io.ReadCloser) {
    reader := bufio.NewReader(pipe)

    for {
        output, err := reader.ReadString('\n')

        if err != nil {
            log.Println(err)
            return
        }

        log.Print(string(output))
    }
}

pipe, err := cmd.StderrPipe()

go logger(pipe)
cmd.Run()

For vim to run you probably need to emulate a terminal.

Maybe goat (doc) can help you out:

tty := term.NewTTY(os.Stdin)

cmd := exec.Command("vim", "test.txt")
cmd.Stdin = t
cmd.Stdout = t

// ...
like image 37
nemo Avatar answered Oct 08 '22 05:10

nemo