github.com/abdfnx/gh-api@v0.0.0-20210414084727-f5432eec23b8/pkg/surveyext/editor_manual.go (about) 1 package surveyext 2 3 import ( 4 "bytes" 5 "io" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 10 "github.com/cli/safeexec" 11 shellquote "github.com/kballard/go-shellquote" 12 ) 13 14 type showable interface { 15 Show() 16 } 17 18 func Edit(editorCommand, fn, initialValue string, stdin io.Reader, stdout io.Writer, stderr io.Writer, cursor showable) (string, error) { 19 // prepare the temp file 20 pattern := fn 21 if pattern == "" { 22 pattern = "survey*.txt" 23 } 24 f, err := ioutil.TempFile("", pattern) 25 if err != nil { 26 return "", err 27 } 28 defer os.Remove(f.Name()) 29 30 // write utf8 BOM header 31 // The reason why we do this is because notepad.exe on Windows determines the 32 // encoding of an "empty" text file by the locale, for example, GBK in China, 33 // while golang string only handles utf8 well. However, a text file with utf8 34 // BOM header is not considered "empty" on Windows, and the encoding will then 35 // be determined utf8 by notepad.exe, instead of GBK or other encodings. 36 if _, err := f.Write(bom); err != nil { 37 return "", err 38 } 39 40 // write initial value 41 if _, err := f.WriteString(initialValue); err != nil { 42 return "", err 43 } 44 45 // close the fd to prevent the editor unable to save file 46 if err := f.Close(); err != nil { 47 return "", err 48 } 49 50 if editorCommand == "" { 51 editorCommand = defaultEditor 52 } 53 args, err := shellquote.Split(editorCommand) 54 if err != nil { 55 return "", err 56 } 57 args = append(args, f.Name()) 58 59 editorExe, err := safeexec.LookPath(args[0]) 60 if err != nil { 61 return "", err 62 } 63 64 cmd := exec.Command(editorExe, args[1:]...) 65 cmd.Stdin = stdin 66 cmd.Stdout = stdout 67 cmd.Stderr = stderr 68 69 if cursor != nil { 70 cursor.Show() 71 } 72 73 // open the editor 74 if err := cmd.Run(); err != nil { 75 return "", err 76 } 77 78 // raw is a BOM-unstripped UTF8 byte slice 79 raw, err := ioutil.ReadFile(f.Name()) 80 if err != nil { 81 return "", err 82 } 83 84 // strip BOM header 85 return string(bytes.TrimPrefix(raw, bom)), nil 86 }