From ff7e3a4cee5b63d5ef70acf676f165d6169fe704 Mon Sep 17 00:00:00 2001 From: Sung Date: Sun, 12 Mar 2023 13:46:28 +1100 Subject: [PATCH] wip --- pkg/cli/cmd/add/add.go | 3 +-- pkg/cli/cmd/edit/edit.go | 9 +++------ pkg/cli/cmd/find/find.go | 3 +-- pkg/cli/cmd/remove/remove.go | 6 ++---- pkg/cli/cmd/sync/sync.go | 3 +-- pkg/cli/cmd/view/view.go | 4 ++-- pkg/cli/command/command.go | 36 +++++++++++++++++++++++++++------ pkg/cli/command/command_test.go | 5 +++-- 8 files changed, 43 insertions(+), 26 deletions(-) diff --git a/pkg/cli/cmd/add/add.go b/pkg/cli/cmd/add/add.go index bb04306e..52c848e9 100644 --- a/pkg/cli/cmd/add/add.go +++ b/pkg/cli/cmd/add/add.go @@ -73,8 +73,7 @@ func NewCmd(ctx context.DnoteCtx) *command.Command { } f := cmd.Flags() - f.StringVar(&contentFlag, "c", "", "Shorthand for --content") - f.StringVar(&contentFlag, "content", "", "The new content for the note") + f.StringVarP(&contentFlag, "content", "c", "", "The new content for the note") return cmd } diff --git a/pkg/cli/cmd/edit/edit.go b/pkg/cli/cmd/edit/edit.go index 2af46532..7d53ce94 100644 --- a/pkg/cli/cmd/edit/edit.go +++ b/pkg/cli/cmd/edit/edit.go @@ -60,12 +60,9 @@ func NewCmd(ctx context.DnoteCtx) *command.Command { } f := cmd.Flags() - f.StringVar(&contentFlag, "content", "", "a new content for the note") - f.StringVar(&contentFlag, "c", "", "a new content for the note") - f.StringVar(&bookFlag, "book", "", "the name of the book to move the note to") - f.StringVar(&bookFlag, "b", "", "the name of the book to move the note to") - f.StringVar(&nameFlag, "name", "", "a new name for a book") - f.StringVar(&nameFlag, "n", "", "a new name for a book") + f.StringVarP(&contentFlag, "content", "c", "", "a new content for the note") + f.StringVarP(&bookFlag, "book", "b", "", "the name of the book to move the note to") + f.StringVarP(&nameFlag, "name", "n", "", "a new name for a book") return cmd } diff --git a/pkg/cli/cmd/find/find.go b/pkg/cli/cmd/find/find.go index 2c23adc6..930ae07f 100644 --- a/pkg/cli/cmd/find/find.go +++ b/pkg/cli/cmd/find/find.go @@ -63,8 +63,7 @@ func NewCmd(ctx context.DnoteCtx) *command.Command { } f := cmd.Flags() - f.StringVar(&bookName, "book", "", "book name to find notes in") - f.StringVar(&bookName, "b", "", "Shorthand for --book") + f.StringVarP(&bookName, "book", "b", "", "book name to find notes in") return cmd } diff --git a/pkg/cli/cmd/remove/remove.go b/pkg/cli/cmd/remove/remove.go index 0a83db04..9611079b 100644 --- a/pkg/cli/cmd/remove/remove.go +++ b/pkg/cli/cmd/remove/remove.go @@ -56,10 +56,8 @@ func NewCmd(ctx context.DnoteCtx) *command.Command { } f := cmd.Flags() - f.StringVar(&bookFlag, "book", "", "The book name to delete") - f.StringVar(&bookFlag, "b", "", "Alias for --book") - f.BoolVar(&yesFlag, "yes", false, "Assume yes to the prompts and run in non-interactive mode") - f.BoolVar(&yesFlag, "y", false, "Assume yes to the prompts and run in non-interactive mode") + f.StringVarP(&bookFlag, "book", "b", "", "The book name to delete") + f.BoolVarP(&yesFlag, "yes", "y", false, "Assume yes to the prompts and run in non-interactive mode") // f.MarkDeprecated("book", "Pass the book name as an argument. e.g. `dnote rm book_name`") diff --git a/pkg/cli/cmd/sync/sync.go b/pkg/cli/cmd/sync/sync.go index 58275241..2f29a386 100644 --- a/pkg/cli/cmd/sync/sync.go +++ b/pkg/cli/cmd/sync/sync.go @@ -55,8 +55,7 @@ func NewCmd(ctx context.DnoteCtx) *command.Command { } f := cmd.Flags() - f.BoolVar(&isFullSync, "full", false, "perform a full sync instead of incrementally syncing only the changed data.") - f.BoolVar(&isFullSync, "f", false, "Alias for --full") + f.BoolVarP(&isFullSync, "full", "f", false, "perform a full sync instead of incrementally syncing only the changed data.") return cmd } diff --git a/pkg/cli/cmd/view/view.go b/pkg/cli/cmd/view/view.go index a7b4c8c6..faaaa3af 100644 --- a/pkg/cli/cmd/view/view.go +++ b/pkg/cli/cmd/view/view.go @@ -64,8 +64,8 @@ func NewCmd(ctx context.DnoteCtx) *command.Command { } f := cmd.Flags() - f.BoolVar(&nameOnly, "name-only", false, "print book names only") - f.BoolVar(&contentOnly, "content-only", false, "print the note content only") + f.BoolVarP(&nameOnly, "name-only", "", false, "print book names only") + f.BoolVarP(&contentOnly, "content-only", "", false, "print the note content only") return cmd } diff --git a/pkg/cli/command/command.go b/pkg/cli/command/command.go index 254f650c..aef0147f 100644 --- a/pkg/cli/command/command.go +++ b/pkg/cli/command/command.go @@ -1,6 +1,7 @@ package command import ( + "fmt" "os" "github.com/dnote/dnote/pkg/cli/log" @@ -41,6 +42,13 @@ type Command struct { Run func(cmd *Command, args []string) } +func (c *Command) HelpFunc() { + err := tmpl(os.Stdout, c.HelpTemplate(), c) + if err != nil { + fmt.Println(err) + } +} + // Flags returns a flag set for the command. If not initialized yet, it initializes // one and returns the result. func (c *Command) Flags() *flag.FlagSet { @@ -96,17 +104,24 @@ func (c *Command) Execute() error { args := c.Args() log.Debug("root command received arguments: %s\n", args) - cmd := c.findSubCommand(args[0]) + cmd, args := c.findCommand(args) if cmd == nil { // not found. show suggestion return nil } - cmd.execute(args[1:]) + if err := cmd.execute(args); err != nil { + if errors.Cause(err) == errNotRunnable { + cmd.Help() + } + + } return nil } +var errNotRunnable = errors.New("Command is not runnable.") + // execute runs the command. func (c *Command) execute(args []string) error { log.Debug("command '%s' called with arguments: %s\n", c.Name, args) @@ -118,6 +133,10 @@ func (c *Command) execute(args []string) error { nonFlagArgs := c.Flags().Args() log.Debug("command '%s' called with non-flag arguments: %s\n", c.Name, nonFlagArgs) + if c.RunE == nil { + return errNotRunnable + } + if err := c.RunE(c, nonFlagArgs); err != nil { return err } @@ -136,19 +155,24 @@ func (c *Command) hasAlias(targetAlias string) bool { return false } -// findSubCommand finds and returns an appropriate subcommand to be called, based +// findCommand finds and returns an appropriate subcommand to be called, based // on the given slice of arguments. It also returns a slice of arguments with which // the subcommand should be called. -func (c *Command) findSubCommand(name string) *Command { +func (c *Command) findCommand(args []string) (*Command, []string) { + if len(args) == 0 { + return c, args + } + + name := args[0] log.Debug("sub-command: '%s'\n", name) for _, cmd := range c.commands { if cmd.Name == name || cmd.hasAlias(name) { - return cmd + return cmd, args[1:] } } - return nil + return c, args } // AddCommand adds the given command as a subcommand. diff --git a/pkg/cli/command/command_test.go b/pkg/cli/command/command_test.go index 46bb8966..f9dfc34f 100644 --- a/pkg/cli/command/command_test.go +++ b/pkg/cli/command/command_test.go @@ -99,6 +99,7 @@ func TestFindSubcommand(t *testing.T) { assert.Equal(t, subCommand1.findSubCommand("bar"), (*Command)(nil), "Subcommand 'bar' mismatch") } -func executeCommand(root *Command, args ...string) error { - return root.Execute() +func executeCommand(cmd *Command, args ...string) error { + cmd.setArgs(args) + return cmd.Execute() }