github.com/pengwynn/gh@v1.0.1-0.20140118055701-14327ca3942e/github/editor.go (about) 1 package github 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "github.com/jingweno/gh/cmd" 8 "github.com/jingweno/gh/git" 9 "io" 10 "io/ioutil" 11 "os" 12 "path/filepath" 13 "regexp" 14 "strings" 15 ) 16 17 func NewEditor(topic, message string) (editor *Editor, err error) { 18 messageFile, err := getMessageFile(topic) 19 if err != nil { 20 return 21 } 22 23 program, err := git.Editor() 24 if err != nil { 25 return 26 } 27 28 editor = &Editor{ 29 Program: program, 30 File: messageFile, 31 Message: message, 32 doEdit: doTextEditorEdit, 33 } 34 35 return 36 } 37 38 type Editor struct { 39 Program string 40 File string 41 Message string 42 doEdit func(program, file string) error 43 } 44 45 func (e *Editor) Edit() (content []byte, err error) { 46 if e.Message != "" { 47 err = ioutil.WriteFile(e.File, []byte(e.Message), 0644) 48 if err != nil { 49 return 50 } 51 } 52 defer os.Remove(e.File) 53 54 err = e.doEdit(e.Program, e.File) 55 if err != nil { 56 err = fmt.Errorf("error using text editor for editing message") 57 return 58 } 59 60 content, err = ioutil.ReadFile(e.File) 61 62 return 63 } 64 65 func (e *Editor) EditTitleAndBody() (title, body string, err error) { 66 content, err := e.Edit() 67 if err != nil { 68 return 69 } 70 71 reader := bufio.NewReader(bytes.NewReader(content)) 72 title, body, err = readTitleAndBody(reader) 73 74 return 75 } 76 77 func doTextEditorEdit(program, file string) error { 78 editCmd := cmd.New(program) 79 r := regexp.MustCompile("[mg]?vi[m]$") 80 if r.MatchString(program) { 81 editCmd.WithArg("-c") 82 editCmd.WithArg("set ft=gitcommit tw=0 wrap lbr") 83 } 84 editCmd.WithArg(file) 85 86 return editCmd.Exec() 87 } 88 89 func readTitleAndBody(reader *bufio.Reader) (title, body string, err error) { 90 r := regexp.MustCompile("\\S") 91 var titleParts, bodyParts []string 92 93 line, err := readLine(reader) 94 for err == nil { 95 if strings.HasPrefix(line, "#") { 96 break 97 } 98 99 if len(bodyParts) == 0 && r.MatchString(line) { 100 titleParts = append(titleParts, line) 101 } else { 102 bodyParts = append(bodyParts, line) 103 } 104 105 line, err = readLine(reader) 106 } 107 108 if err == io.EOF { 109 err = nil 110 } 111 112 title = strings.Join(titleParts, " ") 113 title = strings.TrimSpace(title) 114 115 body = strings.Join(bodyParts, "\n") 116 body = strings.TrimSpace(body) 117 118 return 119 } 120 121 func readLine(r *bufio.Reader) (string, error) { 122 var ( 123 isPrefix = true 124 err error 125 line, ln []byte 126 ) 127 128 for isPrefix && err == nil { 129 line, isPrefix, err = r.ReadLine() 130 ln = append(ln, line...) 131 } 132 133 return string(ln), err 134 } 135 136 func getMessageFile(about string) (string, error) { 137 gitDir, err := git.Dir() 138 if err != nil { 139 return "", err 140 } 141 142 return filepath.Join(gitDir, fmt.Sprintf("%s_EDITMSG", about)), nil 143 }