github.com/nkprince007/lab@v0.6.2-0.20171218071646-19d68b56f403/internal/git/edit.go (about) 1 package git 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "regexp" 11 "strings" 12 ) 13 14 // Edit opens a file in the users editor and returns the title and body 15 func Edit(filePrefix, message string) (string, string, error) { 16 gitDir, err := GitDir() 17 if err != nil { 18 return "", "", err 19 } 20 filePath := filepath.Join(gitDir, fmt.Sprintf("%s_EDITMSG", filePrefix)) 21 if os.Getenv("DEBUG") != "" { 22 log.Println("msgFile:", filePath) 23 } 24 25 editorPath, err := editorPath() 26 if err != nil { 27 return "", "", err 28 } 29 defer os.Remove(filePath) 30 31 // Write generated/tempate message to file 32 if _, err := os.Stat(filePath); os.IsNotExist(err) && message != "" { 33 err = ioutil.WriteFile(filePath, []byte(message), 0644) 34 if err != nil { 35 return "", "", err 36 } 37 } 38 39 cmd := editorCMD(editorPath, filePath) 40 err = cmd.Run() 41 if err != nil { 42 return "", "", err 43 } 44 45 contents, err := ioutil.ReadFile(filePath) 46 if err != nil { 47 return "", "", err 48 } 49 50 return parseTitleBody(strings.TrimSpace(string(contents))) 51 } 52 53 func editorPath() (string, error) { 54 cmd := New("var", "GIT_EDITOR") 55 cmd.Stdout = nil 56 e, err := cmd.Output() 57 if err != nil { 58 return "", err 59 } 60 return strings.TrimSpace(string(e)), nil 61 } 62 63 func editorCMD(editorPath, filePath string) *exec.Cmd { 64 parts := strings.Split(editorPath, " ") 65 r := regexp.MustCompile("[nmg]?vi[m]?$") 66 args := make([]string, 0, 3) 67 if r.MatchString(editorPath) { 68 args = append(args, "--cmd", "set ft=gitcommit tw=0 wrap lbr") 69 } 70 args = append(args, parts[1:]...) 71 args = append(args, filePath) 72 cmd := exec.Command(parts[0], args...) 73 cmd.Stdin = os.Stdin 74 cmd.Stdout = os.Stdout 75 cmd.Stderr = os.Stderr 76 return cmd 77 } 78 79 func parseTitleBody(message string) (string, string, error) { 80 // Grab all the lines that don't start with the comment char 81 cc := CommentChar() 82 r := regexp.MustCompile(`(?m:^)[^` + cc + `].*(?m:$)`) 83 cr := regexp.MustCompile(`(?m:^)\s*#`) 84 parts := r.FindAllString(message, -1) 85 noComments := make([]string, 0) 86 for _, p := range parts { 87 if !cr.MatchString(p) { 88 noComments = append(noComments, p) 89 } 90 } 91 msg := strings.Join(noComments, "\n") 92 if strings.TrimSpace(msg) == "" { 93 return "", "", nil 94 } 95 96 r = regexp.MustCompile(`\n\s*\n`) 97 parts = r.Split(msg, 2) 98 title := strings.Replace(parts[0], "\n", " ", -1) 99 if len(parts) < 2 { 100 return title, "", nil 101 } 102 return title, parts[1], nil 103 }