diff --git a/README.md b/README.md index 9a775c5..b3e5351 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Corgi is a command-line tool that helps with your repetitive command usages by organizing them into reusable snippet. See usage by simply running `corgi` or `corgi --help` -Current version: **v0.2.1** +Current version: **v0.2.2** ## Examples Create a new snippet to automate the commands you run repetitively @@ -145,9 +145,9 @@ corgi remove [] ``` ### Configure `corgi` -Currently the only editable option is your text editor choice (default is `vim`), to configure the corgi CLI, run +You can configure your text editor choice (default is `vim`) for snippet editing, and filter tool for interactive snippet selection. To configure the corgi CLI, run ``` -corgi config --editor <editor of your choice> +corgi config [--editor <editor of your choice>] [--filter-cmd <fzf, peco or something else>] ``` ## Roadmap diff --git a/cmd/config.go b/cmd/config.go index a292e4b..a22dded 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -1,6 +1,8 @@ package cmd -import "github.com/spf13/cobra" +import ( + "github.com/spf13/cobra" +) var configCmd = &cobra.Command{ Use: "config", @@ -9,6 +11,7 @@ var configCmd = &cobra.Command{ } var editor string +var filterCmd string func configure(cmd *cobra.Command, args []string) error { conf, _, err := loadConfigAndSnippetsMeta() @@ -21,10 +24,17 @@ func configure(cmd *cobra.Command, args []string) error { return err } } + if filterCmd != "" { + conf.FilterCmd = filterCmd + if err := conf.Save(); err != nil { + return err + } + } return nil } func init() { + configCmd.Flags().StringVar(&filterCmd, "filter-cmd", "", "Select the text editor you would like to use to edit snippet") configCmd.Flags().StringVar(&editor, "editor", "", "Select the text editor you would like to use to edit snippet") rootCmd.AddCommand(configCmd) } diff --git a/cmd/describe.go b/cmd/describe.go index c4ff305..56fc193 100644 --- a/cmd/describe.go +++ b/cmd/describe.go @@ -3,7 +3,7 @@ package cmd import "github.com/spf13/cobra" var describeCmd = &cobra.Command{ - Use: "describe", + Use: "describe [title]", Short: "Describe a snippet", Args: cobra.MaximumNArgs(1), RunE: describe, diff --git a/cmd/edit.go b/cmd/edit.go index 3dba72d..7fa5ce4 100644 --- a/cmd/edit.go +++ b/cmd/edit.go @@ -8,7 +8,7 @@ import ( ) var editCmd = &cobra.Command{ - Use: "edit", + Use: "edit [title]", Short: "Edit a snippet", Args: cobra.MaximumNArgs(1), RunE: edit, @@ -16,14 +16,14 @@ var editCmd = &cobra.Command{ func edit(cmd *cobra.Command, args []string) error { // load config & snippets - conf, snippets, err := loadConfigAndSnippetsMeta() + conf, snippetsMeta, err := loadConfigAndSnippetsMeta() if err != nil { return err } // find snippet title var title string if len(args) == 0 { - title, err = filterSnippetTitle(conf.FilterCmd, snippets.GetSnippetTitles()) + title, err = filterSnippetTitle(conf.FilterCmd, snippetsMeta.GetSnippetTitles()) if err != nil { return err } @@ -31,7 +31,7 @@ func edit(cmd *cobra.Command, args []string) error { title = args[0] } // find snippet - s, err := snippets.FindSnippet(title) + s, err := snippetsMeta.FindSnippet(title) if err != nil { return err } @@ -39,6 +39,11 @@ func edit(cmd *cobra.Command, args []string) error { if err := util.Execute(command, os.Stdin, os.Stdout); err != nil { return err } + // mark snippetsMeta dirty + snippetsMeta.IsMetaDirty = true + if err = snippetsMeta.Save(); err != nil { + return err + } return nil } diff --git a/cmd/exec.go b/cmd/exec.go index f8ae0c9..e4dc370 100644 --- a/cmd/exec.go +++ b/cmd/exec.go @@ -6,7 +6,7 @@ import ( ) var execCmd = &cobra.Command{ - Use: "exec", + Use: "exec [title]", Short: "Execute a snippet", Args: cobra.MaximumNArgs(1), RunE: execute, diff --git a/cmd/export.go b/cmd/export.go index de71f60..adc5e1b 100644 --- a/cmd/export.go +++ b/cmd/export.go @@ -7,7 +7,7 @@ import ( ) var exportCmd = &cobra.Command{ - Use: "export", + Use: "export [title]", Short: "Export a snippet to json file", Args: cobra.MaximumNArgs(1), RunE: export, diff --git a/cmd/import.go b/cmd/import.go index 7fdfe72..9bac257 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -6,8 +6,8 @@ import ( ) var importCmd = &cobra.Command{ - Use: "import", - Short: "Import a snippet from json file", + Use: "import [file1] [file2...]", + Short: "Import a snippet from one or multiple json files", Args: cobra.MinimumNArgs(1), RunE: importSnippet, } diff --git a/cmd/list.go b/cmd/list.go index 0ee1067..1db8f1d 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -14,13 +14,13 @@ var listCmd = &cobra.Command{ func list(cmd *cobra.Command, args []string) error { // load config & snippets - _, snippets, err := loadConfigAndSnippetsMeta() + _, snippetsMeta, err := loadConfigAndSnippetsMeta() if err != nil { return err } // display fmt.Println("Here is the list of corgi snippets saved on your system:") - for _, s := range snippets.Snippets { + for _, s := range snippetsMeta.Snippets { color.Yellow("- %s", s.Title) } return nil diff --git a/cmd/new.go b/cmd/new.go index 79f2ad0..7eb0146 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -29,7 +29,7 @@ func create(cmd *cobra.Command, args []string) error { } defer snippet.RemoveHistFile() // load config and snippets - conf, snippets, err := loadConfigAndSnippetsMeta() + conf, snippetsMeta, err := loadConfigAndSnippetsMeta() if err != nil { return err } @@ -40,7 +40,7 @@ func create(cmd *cobra.Command, args []string) error { return err } // add new sninppet to snippets meta and save - if err = snippets.SaveNewSnippet(newSnippet, conf.SnippetsDir); err != nil { + if err = snippetsMeta.SaveNewSnippet(newSnippet, conf.SnippetsDir); err != nil { return err } return nil diff --git a/cmd/remove.go b/cmd/remove.go index c708538..6d63458 100644 --- a/cmd/remove.go +++ b/cmd/remove.go @@ -3,7 +3,7 @@ package cmd import "github.com/spf13/cobra" var removeCmd = &cobra.Command{ - Use: "remove", + Use: "remove [title]", Short: "Remove a snippet", Args: cobra.MaximumNArgs(1), RunE: remove, diff --git a/cmd/root.go b/cmd/root.go index 59ff02f..084428f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -5,11 +5,11 @@ import ( "os" ) -var appVersion = "v0.2.1" +var appVersion = "v0.2.2" var rootCmd = &cobra.Command{ Use: "corgi", - Short: "Corgi is a smart dog that helps you organize your command flow for future usage", + Short: "Corgi is a smart dog that helps you manage your CLI workflow", Version: appVersion, SilenceUsage: true, Run: func(cmd *cobra.Command, args []string) { diff --git a/snippet/snippet.go b/snippet/snippet.go index 67b4265..a2cdf9c 100644 --- a/snippet/snippet.go +++ b/snippet/snippet.go @@ -98,9 +98,13 @@ func (snippet *Snippet) AskQuestion(options ...interface{}) error { return nil } +func getSnippetFileName(title string) string { + return fmt.Sprintf("%s.json", strings.Replace(title, " ", "_", -1)) +} + func (snippet *Snippet) Save(snippetsDir string) error { - fmt.Printf("Saving snippet %s... ", snippet.Title) - filePath := fmt.Sprintf("%s/%s.json", snippetsDir, strings.Replace(snippet.Title, " ", "_", -1)) + fmt.Printf("Saving snippet \"%s\"... ", snippet.Title) + filePath := fmt.Sprintf("%s/%s", snippetsDir, getSnippetFileName(snippet.Title)) snippet.fileLoc = filePath if err := snippet.writeToFile(filePath); err != nil { color.Red("Failure") diff --git a/snippet/snippets.go b/snippet/snippets.go index c4e19d7..deac32c 100644 --- a/snippet/snippets.go +++ b/snippet/snippets.go @@ -7,11 +7,15 @@ import ( "github.com/fatih/color" "io/ioutil" "os" + "path" + "strconv" + "time" ) type SnippetsMeta struct { - Snippets []*jsonSnippet `json:"snippets"` - fileLoc string + Snippets []*jsonSnippet `json:"snippets"` + IsMetaDirty bool `json:"is_meta_dirty"` + fileLoc string } type jsonSnippet struct { @@ -19,18 +23,46 @@ type jsonSnippet struct { Title string `json:"title"` } +func (sm *SnippetsMeta) syncWithSnippets() error { + for _, s := range sm.Snippets { + snippet, err := sm.FindSnippet(s.Title) + if err != nil { + return err + } + if s.Title != snippet.Title { + s.Title = snippet.Title + newFileName := getSnippetFileName(s.Title) + newFilePath := fmt.Sprintf("%s/%s", path.Dir(s.FileLoc), newFileName) + if err = os.Rename(s.FileLoc, newFilePath); err != nil { + return err + } + s.FileLoc = newFilePath + } + } + sm.IsMetaDirty = false + if err := sm.Save(); err != nil { + return err + } + return nil +} + func LoadSnippetsMeta(filePath string) (*SnippetsMeta, error) { if _, err := os.Stat(filePath); os.IsNotExist(err) { return nil, err } - snippets := &SnippetsMeta{} - if err := util.LoadJsonDataFromFile(filePath, snippets); err != nil { + snippetsMeta := &SnippetsMeta{} + if err := util.LoadJsonDataFromFile(filePath, snippetsMeta); err != nil { return nil, err } - if snippets.fileLoc == "" { - snippets.fileLoc = filePath + if snippetsMeta.fileLoc == "" { + snippetsMeta.fileLoc = filePath + } + if snippetsMeta.IsMetaDirty { + if err := snippetsMeta.syncWithSnippets(); err != nil { + return nil, err + } } - return snippets, nil + return snippetsMeta, nil } func (sm *SnippetsMeta) Save() error { @@ -49,9 +81,18 @@ func (sm *SnippetsMeta) Save() error { // Save new snippet into snippetsDir and update snippets meta file func (sm *SnippetsMeta) SaveNewSnippet(snippet *Snippet, snippetsDir string) error { + // check for duplicate + if sm.isDuplicate(snippet.Title) { + t := strconv.FormatInt(time.Now().Unix(), 10) + newTitle := fmt.Sprintf("%s-%s", snippet.Title, t) + color.Red("Snippet with title \"%s\" already existed - saving as \"%s\"", snippet.Title, newTitle) + snippet.Title = newTitle + } + // save snippet file if err := snippet.Save(snippetsDir); err != nil { return err } + // save to snippets meta file jsonSnippet := &jsonSnippet{ Title: snippet.Title, FileLoc: snippet.fileLoc, @@ -63,6 +104,15 @@ func (sm *SnippetsMeta) SaveNewSnippet(snippet *Snippet, snippetsDir string) err return nil } +func (sm *SnippetsMeta) isDuplicate(title string) bool { + for _, s := range sm.Snippets { + if s.Title == title { + return true + } + } + return false +} + func (sm *SnippetsMeta) DeleteSnippet(title string) error { idx, err := sm.findJsonSnippetIndex(title) if err != nil { diff --git a/snippet/step.go b/snippet/step.go index e391b62..c09d341 100644 --- a/snippet/step.go +++ b/snippet/step.go @@ -13,7 +13,6 @@ import ( type StepInfo struct { Command string `json:"command"` Description string `json:"description,omitempty"` - ExecuteConcurrent bool `json:"execute_concurrent"` } var TemplateParamsRegex = `<([^(<>|\s)]+)>`