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}