diff options
-rw-r--r-- | commands/bug/bug_comment_add.go | 8 | ||||
-rw-r--r-- | commands/bug/bug_comment_edit.go | 8 | ||||
-rw-r--r-- | commands/bug/bug_new.go | 8 | ||||
-rw-r--r-- | commands/bug/bug_title_edit.go | 6 | ||||
-rw-r--r-- | commands/bug/input/input.go | 230 | ||||
-rw-r--r-- | commands/input/input.go | 235 | ||||
-rw-r--r-- | termui/termui.go | 30 |
7 files changed, 266 insertions, 259 deletions
diff --git a/commands/bug/bug_comment_add.go b/commands/bug/bug_comment_add.go index b676db3a..b445ffad 100644 --- a/commands/bug/bug_comment_add.go +++ b/commands/bug/bug_comment_add.go @@ -3,10 +3,10 @@ package bugcmd import ( "github.com/spf13/cobra" + buginput "github.com/MichaelMure/git-bug/commands/bug/input" "github.com/MichaelMure/git-bug/commands/bug/select" "github.com/MichaelMure/git-bug/commands/completion" "github.com/MichaelMure/git-bug/commands/execenv" - "github.com/MichaelMure/git-bug/commands/input" "github.com/MichaelMure/git-bug/util/text" ) @@ -50,7 +50,7 @@ func runBugCommentNew(env *execenv.Env, opts bugCommentNewOptions, args []string } if opts.messageFile != "" && opts.message == "" { - opts.message, err = input.BugCommentFileInput(opts.messageFile) + opts.message, err = buginput.BugCommentFileInput(opts.messageFile) if err != nil { return err } @@ -61,8 +61,8 @@ func runBugCommentNew(env *execenv.Env, opts bugCommentNewOptions, args []string env.Err.Println("No message given. Use -m or -F option to specify a message. Aborting.") return nil } - opts.message, err = input.BugCommentEditorInput(env.Backend, "") - if err == input.ErrEmptyMessage { + opts.message, err = buginput.BugCommentEditorInput(env.Backend, "") + if err == buginput.ErrEmptyMessage { env.Err.Println("Empty message, aborting.") return nil } diff --git a/commands/bug/bug_comment_edit.go b/commands/bug/bug_comment_edit.go index 2a0289f5..ded3d82a 100644 --- a/commands/bug/bug_comment_edit.go +++ b/commands/bug/bug_comment_edit.go @@ -3,8 +3,8 @@ package bugcmd import ( "github.com/spf13/cobra" + buginput "github.com/MichaelMure/git-bug/commands/bug/input" "github.com/MichaelMure/git-bug/commands/execenv" - "github.com/MichaelMure/git-bug/commands/input" ) type bugCommentEditOptions struct { @@ -47,7 +47,7 @@ func runBugCommentEdit(env *execenv.Env, opts bugCommentEditOptions, args []stri } if opts.messageFile != "" && opts.message == "" { - opts.message, err = input.BugCommentFileInput(opts.messageFile) + opts.message, err = buginput.BugCommentFileInput(opts.messageFile) if err != nil { return err } @@ -58,8 +58,8 @@ func runBugCommentEdit(env *execenv.Env, opts bugCommentEditOptions, args []stri env.Err.Println("No message given. Use -m or -F option to specify a message. Aborting.") return nil } - opts.message, err = input.BugCommentEditorInput(env.Backend, "") - if err == input.ErrEmptyMessage { + opts.message, err = buginput.BugCommentEditorInput(env.Backend, "") + if err == buginput.ErrEmptyMessage { env.Err.Println("Empty message, aborting.") return nil } diff --git a/commands/bug/bug_new.go b/commands/bug/bug_new.go index fbfb9def..9ef288e9 100644 --- a/commands/bug/bug_new.go +++ b/commands/bug/bug_new.go @@ -3,8 +3,8 @@ package bugcmd import ( "github.com/spf13/cobra" + buginput "github.com/MichaelMure/git-bug/commands/bug/input" "github.com/MichaelMure/git-bug/commands/execenv" - "github.com/MichaelMure/git-bug/commands/input" "github.com/MichaelMure/git-bug/util/text" ) @@ -45,16 +45,16 @@ func newBugNewCommand() *cobra.Command { func runBugNew(env *execenv.Env, opts bugNewOptions) error { var err error if opts.messageFile != "" && opts.message == "" { - opts.title, opts.message, err = input.BugCreateFileInput(opts.messageFile) + opts.title, opts.message, err = buginput.BugCreateFileInput(opts.messageFile) if err != nil { return err } } if !opts.nonInteractive && opts.messageFile == "" && (opts.message == "" || opts.title == "") { - opts.title, opts.message, err = input.BugCreateEditorInput(env.Backend, opts.title, opts.message) + opts.title, opts.message, err = buginput.BugCreateEditorInput(env.Backend, opts.title, opts.message) - if err == input.ErrEmptyTitle { + if err == buginput.ErrEmptyTitle { env.Out.Println("Empty title, aborting.") return nil } diff --git a/commands/bug/bug_title_edit.go b/commands/bug/bug_title_edit.go index e71330a1..bf9f6375 100644 --- a/commands/bug/bug_title_edit.go +++ b/commands/bug/bug_title_edit.go @@ -3,10 +3,10 @@ package bugcmd import ( "github.com/spf13/cobra" + buginput "github.com/MichaelMure/git-bug/commands/bug/input" "github.com/MichaelMure/git-bug/commands/bug/select" "github.com/MichaelMure/git-bug/commands/completion" "github.com/MichaelMure/git-bug/commands/execenv" - "github.com/MichaelMure/git-bug/commands/input" "github.com/MichaelMure/git-bug/util/text" ) @@ -53,8 +53,8 @@ func runBugTitleEdit(env *execenv.Env, opts bugTitleEditOptions, args []string) env.Err.Println("No title given. Use -m or -F option to specify a title. Aborting.") return nil } - opts.title, err = input.BugTitleEditorInput(env.Repo, snap.Title) - if err == input.ErrEmptyTitle { + opts.title, err = buginput.BugTitleEditorInput(env.Repo, snap.Title) + if err == buginput.ErrEmptyTitle { env.Out.Println("Empty title, aborting.") return nil } diff --git a/commands/bug/input/input.go b/commands/bug/input/input.go new file mode 100644 index 00000000..23c20acb --- /dev/null +++ b/commands/bug/input/input.go @@ -0,0 +1,230 @@ +package buginput + +import ( + "bytes" + "fmt" + "strings" + + "github.com/pkg/errors" + + "github.com/MichaelMure/git-bug/commands/input" + "github.com/MichaelMure/git-bug/repository" +) + +const messageFilename = "BUG_MESSAGE_EDITMSG" + +// ErrEmptyMessage is returned when the required message has not been entered +var ErrEmptyMessage = errors.New("empty message") + +// ErrEmptyTitle is returned when the required title has not been entered +var ErrEmptyTitle = errors.New("empty title") + +const bugTitleCommentTemplate = `%s%s + +# Please enter the title and comment message. The first non-empty line will be +# used as the title. Lines starting with '#' will be ignored. +# An empty title aborts the operation. +` + +// BugCreateEditorInput will open the default editor in the terminal with a +// template for the user to fill. The file is then processed to extract title +// and message. +func BugCreateEditorInput(repo repository.RepoCommonStorage, preTitle string, preMessage string) (string, string, error) { + if preMessage != "" { + preMessage = "\n\n" + preMessage + } + + template := fmt.Sprintf(bugTitleCommentTemplate, preTitle, preMessage) + + raw, err := input.LaunchEditorWithTemplate(repo, messageFilename, template) + if err != nil { + return "", "", err + } + + return processCreate(raw) +} + +// BugCreateFileInput read from either from a file or from the standard input +// and extract a title and a message +func BugCreateFileInput(fileName string) (string, string, error) { + raw, err := input.FromFile(fileName) + if err != nil { + return "", "", err + } + + return processCreate(raw) +} + +func processCreate(raw string) (string, string, error) { + lines := strings.Split(raw, "\n") + + var title string + var buffer bytes.Buffer + for _, line := range lines { + if strings.HasPrefix(line, "#") { + continue + } + + if title == "" { + trimmed := strings.TrimSpace(line) + if trimmed != "" { + title = trimmed + } + continue + } + + buffer.WriteString(line) + buffer.WriteString("\n") + } + + if title == "" { + return "", "", ErrEmptyTitle + } + + message := strings.TrimSpace(buffer.String()) + + return title, message, nil +} + +const bugCommentTemplate = `%s + +# Please enter the comment message. Lines starting with '#' will be ignored, +# and an empty message aborts the operation. +` + +// BugCommentEditorInput will open the default editor in the terminal with a +// template for the user to fill. The file is then processed to extract a comment. +func BugCommentEditorInput(repo repository.RepoCommonStorage, preMessage string) (string, error) { + template := fmt.Sprintf(bugCommentTemplate, preMessage) + + raw, err := input.LaunchEditorWithTemplate(repo, messageFilename, template) + if err != nil { + return "", err + } + + return processComment(raw) +} + +// BugCommentFileInput read from either from a file or from the standard input +// and extract a message +func BugCommentFileInput(fileName string) (string, error) { + raw, err := input.FromFile(fileName) + if err != nil { + return "", err + } + + return processComment(raw) +} + +func processComment(raw string) (string, error) { + lines := strings.Split(raw, "\n") + + var buffer bytes.Buffer + for _, line := range lines { + if strings.HasPrefix(line, "#") { + continue + } + buffer.WriteString(line) + buffer.WriteString("\n") + } + + message := strings.TrimSpace(buffer.String()) + + if message == "" { + return "", ErrEmptyMessage + } + + return message, nil +} + +const bugTitleTemplate = `%s + +# Please enter the new title. Only one line will used. +# Lines starting with '#' will be ignored, and an empty title aborts the operation. +` + +// BugTitleEditorInput will open the default editor in the terminal with a +// template for the user to fill. The file is then processed to extract a title. +func BugTitleEditorInput(repo repository.RepoCommonStorage, preTitle string) (string, error) { + template := fmt.Sprintf(bugTitleTemplate, preTitle) + + raw, err := input.LaunchEditorWithTemplate(repo, messageFilename, template) + if err != nil { + return "", err + } + + lines := strings.Split(raw, "\n") + + var title string + for _, line := range lines { + if strings.HasPrefix(line, "#") { + continue + } + trimmed := strings.TrimSpace(line) + if trimmed == "" { + continue + } + title = trimmed + break + } + + if title == "" { + return "", ErrEmptyTitle + } + + return title, nil +} + +const queryTemplate = `%s + +# Please edit the bug query. +# Lines starting with '#' will be ignored, and an empty query aborts the operation. +# +# Example: status:open author:"rené descartes" sort:edit +# +# Valid filters are: +# +# - status:open, status:closed +# - author:<query> +# - title:<title> +# - label:<label> +# - no:label +# +# Sorting +# +# - sort:id, sort:id-desc, sort:id-asc +# - sort:creation, sort:creation-desc, sort:creation-asc +# - sort:edit, sort:edit-desc, sort:edit-asc +# +# Notes +# +# - queries are case insensitive. +# - you can combine as many qualifiers as you want. +# - you can use double quotes for multi-word search terms (ex: author:"René Descartes") +` + +// QueryEditorInput will open the default editor in the terminal with a +// template for the user to fill. The file is then processed to extract a query. +func QueryEditorInput(repo repository.RepoCommonStorage, preQuery string) (string, error) { + template := fmt.Sprintf(queryTemplate, preQuery) + + raw, err := input.LaunchEditorWithTemplate(repo, messageFilename, template) + if err != nil { + return "", err + } + + lines := strings.Split(raw, "\n") + + for _, line := range lines { + if strings.HasPrefix(line, "#") { + continue + } + trimmed := strings.TrimSpace(line) + if trimmed == "" { + continue + } + return trimmed, nil + } + + return "", nil +} diff --git a/commands/input/input.go b/commands/input/input.go index ee343cd8..4ccfbd92 100644 --- a/commands/input/input.go +++ b/commands/input/input.go @@ -12,245 +12,24 @@ import ( "os" "os/exec" "path/filepath" - "strings" "github.com/go-git/go-billy/v5/util" - "github.com/pkg/errors" "github.com/MichaelMure/git-bug/repository" ) -const messageFilename = "BUG_MESSAGE_EDITMSG" - -// ErrEmptyMessage is returned when the required message has not been entered -var ErrEmptyMessage = errors.New("empty message") - -// ErrEmptyTitle is returned when the required title has not been entered -var ErrEmptyTitle = errors.New("empty title") - -const bugTitleCommentTemplate = `%s%s - -# Please enter the title and comment message. The first non-empty line will be -# used as the title. Lines starting with '#' will be ignored. -# An empty title aborts the operation. -` - -// BugCreateEditorInput will open the default editor in the terminal with a -// template for the user to fill. The file is then processed to extract title -// and message. -func BugCreateEditorInput(repo repository.RepoCommonStorage, preTitle string, preMessage string) (string, string, error) { - if preMessage != "" { - preMessage = "\n\n" + preMessage - } - - template := fmt.Sprintf(bugTitleCommentTemplate, preTitle, preMessage) - - raw, err := launchEditorWithTemplate(repo, messageFilename, template) - - if err != nil { - return "", "", err - } - - return processCreate(raw) -} - -// BugCreateFileInput read from either from a file or from the standard input -// and extract a title and a message -func BugCreateFileInput(fileName string) (string, string, error) { - raw, err := fromFile(fileName) - if err != nil { - return "", "", err - } - - return processCreate(raw) -} - -func processCreate(raw string) (string, string, error) { - lines := strings.Split(raw, "\n") - - var title string - var buffer bytes.Buffer - for _, line := range lines { - if strings.HasPrefix(line, "#") { - continue - } - - if title == "" { - trimmed := strings.TrimSpace(line) - if trimmed != "" { - title = trimmed - } - continue - } - - buffer.WriteString(line) - buffer.WriteString("\n") - } - - if title == "" { - return "", "", ErrEmptyTitle - } - - message := strings.TrimSpace(buffer.String()) - - return title, message, nil -} - -const bugCommentTemplate = `%s - -# Please enter the comment message. Lines starting with '#' will be ignored, -# and an empty message aborts the operation. -` - -// BugCommentEditorInput will open the default editor in the terminal with a -// template for the user to fill. The file is then processed to extract a comment. -func BugCommentEditorInput(repo repository.RepoCommonStorage, preMessage string) (string, error) { - template := fmt.Sprintf(bugCommentTemplate, preMessage) - - raw, err := launchEditorWithTemplate(repo, messageFilename, template) - if err != nil { - return "", err - } - - return processComment(raw) -} - -// BugCommentFileInput read from either from a file or from the standard input -// and extract a message -func BugCommentFileInput(fileName string) (string, error) { - raw, err := fromFile(fileName) - if err != nil { - return "", err - } - - return processComment(raw) -} - -func processComment(raw string) (string, error) { - lines := strings.Split(raw, "\n") - - var buffer bytes.Buffer - for _, line := range lines { - if strings.HasPrefix(line, "#") { - continue - } - buffer.WriteString(line) - buffer.WriteString("\n") - } - - message := strings.TrimSpace(buffer.String()) - - if message == "" { - return "", ErrEmptyMessage - } - - return message, nil -} - -const bugTitleTemplate = `%s - -# Please enter the new title. Only one line will used. -# Lines starting with '#' will be ignored, and an empty title aborts the operation. -` - -// BugTitleEditorInput will open the default editor in the terminal with a -// template for the user to fill. The file is then processed to extract a title. -func BugTitleEditorInput(repo repository.RepoCommonStorage, preTitle string) (string, error) { - template := fmt.Sprintf(bugTitleTemplate, preTitle) - - raw, err := launchEditorWithTemplate(repo, messageFilename, template) - if err != nil { - return "", err - } - - lines := strings.Split(raw, "\n") - - var title string - for _, line := range lines { - if strings.HasPrefix(line, "#") { - continue - } - trimmed := strings.TrimSpace(line) - if trimmed == "" { - continue - } - title = trimmed - break - } - - if title == "" { - return "", ErrEmptyTitle - } - - return title, nil -} - -const queryTemplate = `%s - -# Please edit the bug query. -# Lines starting with '#' will be ignored, and an empty query aborts the operation. -# -# Example: status:open author:"rené descartes" sort:edit -# -# Valid filters are: -# -# - status:open, status:closed -# - author:<query> -# - title:<title> -# - label:<label> -# - no:label -# -# Sorting -# -# - sort:id, sort:id-desc, sort:id-asc -# - sort:creation, sort:creation-desc, sort:creation-asc -# - sort:edit, sort:edit-desc, sort:edit-asc -# -# Notes -# -# - queries are case insensitive. -# - you can combine as many qualifiers as you want. -# - you can use double quotes for multi-word search terms (ex: author:"René Descartes") -` - -// QueryEditorInput will open the default editor in the terminal with a -// template for the user to fill. The file is then processed to extract a query. -func QueryEditorInput(repo repository.RepoCommonStorage, preQuery string) (string, error) { - template := fmt.Sprintf(queryTemplate, preQuery) - - raw, err := launchEditorWithTemplate(repo, messageFilename, template) - if err != nil { - return "", err - } - - lines := strings.Split(raw, "\n") - - for _, line := range lines { - if strings.HasPrefix(line, "#") { - continue - } - trimmed := strings.TrimSpace(line) - if trimmed == "" { - continue - } - return trimmed, nil - } - - return "", nil -} - -// launchEditorWithTemplate will launch an editor as launchEditor do, but with a +// LaunchEditorWithTemplate will launch an editor as LaunchEditor do, but with a // provided template. -func launchEditorWithTemplate(repo repository.RepoCommonStorage, fileName string, template string) (string, error) { +func LaunchEditorWithTemplate(repo repository.RepoCommonStorage, fileName string, template string) (string, error) { err := util.WriteFile(repo.LocalStorage(), fileName, []byte(template), 0644) if err != nil { return "", err } - return launchEditor(repo, fileName) + return LaunchEditor(repo, fileName) } -// launchEditor launches the default editor configured for the given repo. This +// LaunchEditor launches the default editor configured for the given repo. This // method blocks until the editor command has returned. // // The specified filename should be a temporary file and provided as a relative path @@ -259,7 +38,7 @@ func launchEditorWithTemplate(repo repository.RepoCommonStorage, fileName string // // This method returns the text that was read from the temporary file, or // an error if any step in the process failed. -func launchEditor(repo repository.RepoCommonStorage, fileName string) (string, error) { +func LaunchEditor(repo repository.RepoCommonStorage, fileName string) (string, error) { defer repo.LocalStorage().Remove(fileName) editor, err := repo.GetCoreEditor() @@ -302,11 +81,11 @@ func launchEditor(repo repository.RepoCommonStorage, fileName string) (string, e return string(output), err } -// fromFile loads and returns the contents of a given file. If - is passed +// FromFile loads and returns the contents of a given file. If - is passed // through, much like git, it will read from stdin. This can be piped data, // unless there is a tty in which case the user will be prompted to enter a // message. -func fromFile(fileName string) (string, error) { +func FromFile(fileName string) (string, error) { if fileName == "-" { stat, err := os.Stdin.Stat() if err != nil { diff --git a/termui/termui.go b/termui/termui.go index 79577ba9..d640ed1c 100644 --- a/termui/termui.go +++ b/termui/termui.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" "github.com/MichaelMure/git-bug/cache" - "github.com/MichaelMure/git-bug/commands/input" + buginput "github.com/MichaelMure/git-bug/commands/bug/input" "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/query" "github.com/MichaelMure/git-bug/util/text" @@ -187,14 +187,14 @@ func newBugWithEditor(repo *cache.RepoCache) error { ui.g.Close() ui.g = nil - title, message, err := input.BugCreateEditorInput(ui.cache, "", "") + title, message, err := buginput.BugCreateEditorInput(ui.cache, "", "") - if err != nil && err != input.ErrEmptyTitle { + if err != nil && err != buginput.ErrEmptyTitle { return err } var b *cache.BugCache - if err == input.ErrEmptyTitle { + if err == buginput.ErrEmptyTitle { ui.msgPopup.Activate(msgPopupErrorTitle, "Empty title, aborting.") initGui(nil) @@ -230,13 +230,11 @@ func addCommentWithEditor(bug *cache.BugCache) error { ui.g.Close() ui.g = nil - message, err := input.BugCommentEditorInput(ui.cache, "") - - if err != nil && err != input.ErrEmptyMessage { + message, err := buginput.BugCommentEditorInput(ui.cache, "") + if err != nil && err != buginput.ErrEmptyMessage { return err } - - if err == input.ErrEmptyMessage { + if err == buginput.ErrEmptyMessage { ui.msgPopup.Activate(msgPopupErrorTitle, "Empty message, aborting.") } else { _, _, err := bug.AddComment(text.Cleanup(message)) @@ -263,12 +261,12 @@ func editCommentWithEditor(bug *cache.BugCache, target entity.CombinedId, preMes ui.g.Close() ui.g = nil - message, err := input.BugCommentEditorInput(ui.cache, preMessage) - if err != nil && err != input.ErrEmptyMessage { + message, err := buginput.BugCommentEditorInput(ui.cache, preMessage) + if err != nil && err != buginput.ErrEmptyMessage { return err } - if err == input.ErrEmptyMessage { + if err == buginput.ErrEmptyMessage { // TODO: Allow comments to be deleted? ui.msgPopup.Activate(msgPopupErrorTitle, "Empty message, aborting.") } else if message == preMessage { @@ -300,13 +298,13 @@ func setTitleWithEditor(bug *cache.BugCache) error { snap := bug.Snapshot() - title, err := input.BugTitleEditorInput(ui.cache, snap.Title) + title, err := buginput.BugTitleEditorInput(ui.cache, snap.Title) - if err != nil && err != input.ErrEmptyTitle { + if err != nil && err != buginput.ErrEmptyTitle { return err } - if err == input.ErrEmptyTitle { + if err == buginput.ErrEmptyTitle { ui.msgPopup.Activate(msgPopupErrorTitle, "Empty title, aborting.") } else if title == snap.Title { ui.msgPopup.Activate(msgPopupErrorTitle, "No change, aborting.") @@ -335,7 +333,7 @@ func editQueryWithEditor(bt *bugTable) error { ui.g.Close() ui.g = nil - queryStr, err := input.QueryEditorInput(bt.repo, bt.queryStr) + queryStr, err := buginput.QueryEditorInput(bt.repo, bt.queryStr) if err != nil { return err |