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  }