input.go

  1package buginput
  2
  3import (
  4	"bytes"
  5	"fmt"
  6	"strings"
  7
  8	"github.com/pkg/errors"
  9
 10	"github.com/git-bug/git-bug/commands/input"
 11	"github.com/git-bug/git-bug/repository"
 12)
 13
 14const messageFilename = "BUG_EDITMSG"
 15
 16// ErrEmptyMessage is returned when the required message has not been entered
 17var ErrEmptyMessage = errors.New("empty message")
 18
 19// ErrEmptyTitle is returned when the required title has not been entered
 20var ErrEmptyTitle = errors.New("empty title")
 21
 22const bugTitleCommentTemplate = `%s%s
 23
 24# Please enter the title and comment message. The first non-empty line will be
 25# used as the title. Lines starting with '#' will be ignored.
 26# An empty title aborts the operation.
 27`
 28
 29// BugCreateEditorInput will open the default editor in the terminal with a
 30// template for the user to fill. The file is then processed to extract title
 31// and message.
 32func BugCreateEditorInput(repo repository.RepoCommonStorage, preTitle string, preMessage string) (string, string, error) {
 33	if preMessage != "" {
 34		preMessage = "\n\n" + preMessage
 35	}
 36
 37	template := fmt.Sprintf(bugTitleCommentTemplate, preTitle, preMessage)
 38
 39	raw, err := input.LaunchEditorWithTemplate(repo, messageFilename, template)
 40	if err != nil {
 41		return "", "", err
 42	}
 43
 44	return processCreate(raw)
 45}
 46
 47// BugCreateFileInput read from either from a file or from the standard input
 48// and extract a title and a message
 49func BugCreateFileInput(fileName string) (string, string, error) {
 50	raw, err := input.FromFile(fileName)
 51	if err != nil {
 52		return "", "", err
 53	}
 54
 55	return processCreate(raw)
 56}
 57
 58func processCreate(raw string) (string, string, error) {
 59	lines := strings.Split(raw, "\n")
 60
 61	var title string
 62	var buffer bytes.Buffer
 63	for _, line := range lines {
 64		if strings.HasPrefix(line, "#") {
 65			continue
 66		}
 67
 68		if title == "" {
 69			trimmed := strings.TrimSpace(line)
 70			if trimmed != "" {
 71				title = trimmed
 72			}
 73			continue
 74		}
 75
 76		buffer.WriteString(line)
 77		buffer.WriteString("\n")
 78	}
 79
 80	if title == "" {
 81		return "", "", ErrEmptyTitle
 82	}
 83
 84	message := strings.TrimSpace(buffer.String())
 85
 86	return title, message, nil
 87}
 88
 89const bugCommentTemplate = `%s
 90
 91# Please enter the comment message. Lines starting with '#' will be ignored,
 92# and an empty message aborts the operation.
 93`
 94
 95// BugCommentEditorInput will open the default editor in the terminal with a
 96// template for the user to fill. The file is then processed to extract a comment.
 97func BugCommentEditorInput(repo repository.RepoCommonStorage, preMessage string) (string, error) {
 98	template := fmt.Sprintf(bugCommentTemplate, preMessage)
 99
100	raw, err := input.LaunchEditorWithTemplate(repo, messageFilename, template)
101	if err != nil {
102		return "", err
103	}
104
105	return processComment(raw)
106}
107
108// BugCommentFileInput read from either from a file or from the standard input
109// and extract a message
110func BugCommentFileInput(fileName string) (string, error) {
111	raw, err := input.FromFile(fileName)
112	if err != nil {
113		return "", err
114	}
115
116	return processComment(raw)
117}
118
119func processComment(raw string) (string, error) {
120	lines := strings.Split(raw, "\n")
121
122	var buffer bytes.Buffer
123	for _, line := range lines {
124		if strings.HasPrefix(line, "#") {
125			continue
126		}
127		buffer.WriteString(line)
128		buffer.WriteString("\n")
129	}
130
131	message := strings.TrimSpace(buffer.String())
132
133	if message == "" {
134		return "", ErrEmptyMessage
135	}
136
137	return message, nil
138}
139
140const bugTitleTemplate = `%s
141
142# Please enter the new title. Only one line will used.
143# Lines starting with '#' will be ignored, and an empty title aborts the operation.
144`
145
146// BugTitleEditorInput will open the default editor in the terminal with a
147// template for the user to fill. The file is then processed to extract a title.
148func BugTitleEditorInput(repo repository.RepoCommonStorage, preTitle string) (string, error) {
149	template := fmt.Sprintf(bugTitleTemplate, preTitle)
150
151	raw, err := input.LaunchEditorWithTemplate(repo, messageFilename, template)
152	if err != nil {
153		return "", err
154	}
155
156	lines := strings.Split(raw, "\n")
157
158	var title string
159	for _, line := range lines {
160		if strings.HasPrefix(line, "#") {
161			continue
162		}
163		trimmed := strings.TrimSpace(line)
164		if trimmed == "" {
165			continue
166		}
167		title = trimmed
168		break
169	}
170
171	if title == "" {
172		return "", ErrEmptyTitle
173	}
174
175	return title, nil
176}
177
178const queryTemplate = `%s
179
180# Please edit the bug query.
181# Lines starting with '#' will be ignored, and an empty query aborts the operation.
182#
183# Example: status:open author:"rené descartes" sort:edit
184#
185# Valid filters are:
186#
187# - status:open, status:closed
188# - author:<query>
189# - title:<title>
190# - label:<label>
191# - no:label
192#
193# Sorting
194#
195# - sort:id, sort:id-desc, sort:id-asc
196# - sort:creation, sort:creation-desc, sort:creation-asc
197# - sort:edit, sort:edit-desc, sort:edit-asc
198#
199# Notes
200#
201# - queries are case insensitive.
202# - you can combine as many qualifiers as you want.
203# - you can use double quotes for multi-word search terms (ex: author:"René Descartes")
204`
205
206// QueryEditorInput will open the default editor in the terminal with a
207// template for the user to fill. The file is then processed to extract a query.
208func QueryEditorInput(repo repository.RepoCommonStorage, preQuery string) (string, error) {
209	template := fmt.Sprintf(queryTemplate, preQuery)
210
211	raw, err := input.LaunchEditorWithTemplate(repo, messageFilename, template)
212	if err != nil {
213		return "", err
214	}
215
216	lines := strings.Split(raw, "\n")
217
218	for _, line := range lines {
219		if strings.HasPrefix(line, "#") {
220			continue
221		}
222		trimmed := strings.TrimSpace(line)
223		if trimmed == "" {
224			continue
225		}
226		return trimmed, nil
227	}
228
229	return "", nil
230}