github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/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 return edit(editorCommand, fn, initialValue, stdin, stdout, stderr, cursor, defaultLookPath) 20 } 21 22 func defaultLookPath(name string) ([]string, []string, error) { 23 exe, err := safeexec.LookPath(name) 24 if err != nil { 25 return nil, nil, err 26 } 27 return []string{exe}, nil, nil 28 } 29 30 func edit(editorCommand, fn, initialValue string, stdin io.Reader, stdout io.Writer, stderr io.Writer, cursor showable, lookPath func(string) ([]string, []string, error)) (string, error) { 31 // prepare the temp file 32 pattern := fn 33 if pattern == "" { 34 pattern = "survey*.txt" 35 } 36 f, err := ioutil.TempFile("", pattern) 37 if err != nil { 38 return "", err 39 } 40 defer os.Remove(f.Name()) 41 42 // write utf8 BOM header 43 // The reason why we do this is because notepad.exe on Windows determines the 44 // encoding of an "empty" text file by the locale, for example, GBK in China, 45 // while golang string only handles utf8 well. However, a text file with utf8 46 // BOM header is not considered "empty" on Windows, and the encoding will then 47 // be determined utf8 by notepad.exe, instead of GBK or other encodings. 48 if _, err := f.Write(bom); err != nil { 49 return "", err 50 } 51 52 // write initial value 53 if _, err := f.WriteString(initialValue); err != nil { 54 return "", err 55 } 56 57 // close the fd to prevent the editor unable to save file 58 if err := f.Close(); err != nil { 59 return "", err 60 } 61 62 if editorCommand == "" { 63 editorCommand = defaultEditor 64 } 65 args, err := shellquote.Split(editorCommand) 66 if err != nil { 67 return "", err 68 } 69 args = append(args, f.Name()) 70 71 editorExe, env, err := lookPath(args[0]) 72 if err != nil { 73 return "", err 74 } 75 args = append(editorExe, args[1:]...) 76 77 cmd := exec.Command(args[0], args[1:]...) 78 cmd.Env = env 79 cmd.Stdin = stdin 80 cmd.Stdout = stdout 81 cmd.Stderr = stderr 82 83 if cursor != nil { 84 cursor.Show() 85 } 86 87 // open the editor 88 if err := cmd.Run(); err != nil { 89 return "", err 90 } 91 92 // raw is a BOM-unstripped UTF8 byte slice 93 raw, err := ioutil.ReadFile(f.Name()) 94 if err != nil { 95 return "", err 96 } 97 98 // strip BOM header 99 return string(bytes.TrimPrefix(raw, bom)), nil 100 }