From 58ecbb3ec9a08c8bf049ea3ccf6bbea725a0e9fe Mon Sep 17 00:00:00 2001 From: Thang Do Date: Fri, 11 Oct 2024 22:45:05 +1030 Subject: [PATCH 1/7] doc: missing code block wrappers --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d7b6101..447fcb6 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,7 @@ All `toml` files will be scraped and found snippets will be added. Example1: single directory +```toml [GHEGist] base_url = "" # GHE base URL upload_url = "" # GHE upload URL (often the same as the base URL) @@ -275,6 +276,7 @@ Example1: single directory gist_id = "" # Gist ID public = false # public or priate auto_sync = false # sync automatically when editing snippets +``` ``` $ pet configure From 0c724d4999b05c201b929d20ab7f27beeade9c85 Mon Sep 17 00:00:00 2001 From: Thang Do Date: Fri, 11 Oct 2024 23:26:31 +1030 Subject: [PATCH 2/7] feat: support relative paths for snippet's filename attribute --- cmd/new.go | 3 ++- config/config.go | 11 ++++++----- snippet/snippet.go | 17 +++++++++-------- sync/sync.go | 2 +- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/cmd/new.go b/cmd/new.go index e9857a1..d06d0ff 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -167,10 +167,11 @@ func createAndEditSnippet(newSnippet snippet.SnippetInfo, snippets snippet.Snipp func countSnippetLines() int { // Count lines in snippet file - f, err := os.Open(config.Conf.General.SnippetFile) + f, err := os.Open(config.ExpandPath(config.Conf.General.SnippetFile)) if err != nil { panic("Error reading snippet file") } + lineCount, err := CountLines(f) if err != nil { panic("Error counting lines in snippet file") diff --git a/config/config.go b/config/config.go index cba6a82..b0df2b9 100644 --- a/config/config.go +++ b/config/config.go @@ -98,9 +98,8 @@ func (cfg *Config) Load(file string) error { return err } var snippetdirs []string - cfg.General.SnippetFile = expandPath(cfg.General.SnippetFile) for _, dir := range cfg.General.SnippetDirs { - snippetdirs = append(snippetdirs, expandPath(dir)) // note the = instead of := + snippetdirs = append(snippetdirs, dir) // note the = instead of := } cfg.General.SnippetDirs = snippetdirs return nil @@ -109,6 +108,7 @@ func (cfg *Config) Load(file string) error { if !os.IsNotExist(err) { return err } + f, err := os.Create(file) if err != nil { return err @@ -119,9 +119,10 @@ func (cfg *Config) Load(file string) error { return errors.Wrap(err, "Failed to get the default config directory") } cfg.General.SnippetFile = filepath.Join(dir, "snippet.toml") - _, err = os.Create(cfg.General.SnippetFile) + + _, err = os.Create(ExpandPath(cfg.General.SnippetFile)) if err != nil { - return errors.Wrap(err, "Failed to create a config file") + return errors.Wrap(err, "Failed to create a snippet file") } cfg.General.Editor = os.Getenv("EDITOR") @@ -165,7 +166,7 @@ func GetDefaultConfigDir() (dir string, err error) { return dir, nil } -func expandPath(s string) string { +func ExpandPath(s string) string { if len(s) >= 2 && s[0] == '~' && os.IsPathSeparator(s[1]) { if runtime.GOOS == "windows" { s = filepath.Join(os.Getenv("USERPROFILE"), s[2:]) diff --git a/snippet/snippet.go b/snippet/snippet.go index 4ed5a84..e44e137 100644 --- a/snippet/snippet.go +++ b/snippet/snippet.go @@ -30,12 +30,11 @@ func (snippets *Snippets) Load(includeDirs bool) error { // Create a list of snippet files to load snippets from var snippetFiles []string - // Load snippets from the main snippet file - // Raise an error if the file is not found / not configured - snippetFile := config.Conf.General.SnippetFile - if snippetFile != "" { + if config.Conf.General.SnippetFile != "" { + snippetFile := config.ExpandPath(config.Conf.General.SnippetFile) + if _, err := os.Stat(snippetFile); err == nil { - snippetFiles = append(snippetFiles, snippetFile) + snippetFiles = append(snippetFiles, config.Conf.General.SnippetFile) } else if !os.IsNotExist(err) { return fmt.Errorf("failed to load snippet file. %v", err) } else { @@ -43,7 +42,7 @@ func (snippets *Snippets) Load(includeDirs bool) error { `snippet file not found. %s Please run 'pet configure' and provide a correct file path, or remove this if you only want to provide snippetdirs instead`, - snippetFile, + config.Conf.General.SnippetFile, ) } } @@ -59,12 +58,13 @@ if you only want to provide snippetdirs instead`, } snippetFiles = append(snippetFiles, getFiles(dir)...) } + snippetFiles = append(snippetFiles, getFiles(config.ExpandPath(dir))...) } // Read files and load snippets for _, file := range snippetFiles { tmp := Snippets{} - f, err := os.ReadFile(file) + f, err := os.ReadFile(config.ExpandPath(file)) if err != nil { return fmt.Errorf("failed to load snippet file. %v", err) } @@ -98,7 +98,8 @@ func (snippets *Snippets) Save() error { newSnippets.Snippets = append(newSnippets.Snippets, snippet) } } - f, err := os.Create(snippetFile) + + f, err := os.Create(config.ExpandPath(snippetFile)) if err != nil { return fmt.Errorf("failed to save snippet file. err: %s", err) } diff --git a/sync/sync.go b/sync/sync.go index 6c28344..7571d24 100644 --- a/sync/sync.go +++ b/sync/sync.go @@ -100,7 +100,7 @@ func upload(client Client) (err error) { // download downloads snippets from the remote repository // and saves them to the main snippet file - directories ignored func download(content string) error { - snippetFile := config.Conf.General.SnippetFile + snippetFile := config.ExpandPath(config.Conf.General.SnippetFile) var snippets snippet.Snippets if err := snippets.Load(false); err != nil { From 48941bc6bad4e36039949e3bd378d424b25ab8fa Mon Sep 17 00:00:00 2001 From: Thang Do Date: Fri, 11 Oct 2024 23:27:11 +1030 Subject: [PATCH 3/7] bug: fix pet new causing panic when SnippetFile attribute is missing --- cmd/new.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/new.go b/cmd/new.go index d06d0ff..8a8c74d 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -167,6 +167,10 @@ func createAndEditSnippet(newSnippet snippet.SnippetInfo, snippets snippet.Snipp func countSnippetLines() int { // Count lines in snippet file + if config.Conf.General.SnippetFile != "" { + return 0 + } + f, err := os.Open(config.ExpandPath(config.Conf.General.SnippetFile)) if err != nil { panic("Error reading snippet file") From 67985aa7c1be7afcbb0db5a22c2f28b473aa1192 Mon Sep 17 00:00:00 2001 From: Thang Do Date: Sat, 12 Oct 2024 00:49:39 +1030 Subject: [PATCH 4/7] fixed a typo --- cmd/new.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/new.go b/cmd/new.go index 8a8c74d..0cbe404 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -1,4 +1,4 @@ -package cmd +paackage cmd import ( "errors" @@ -167,7 +167,7 @@ func createAndEditSnippet(newSnippet snippet.SnippetInfo, snippets snippet.Snipp func countSnippetLines() int { // Count lines in snippet file - if config.Conf.General.SnippetFile != "" { + if config.Conf.General.SnippetFile == "" { return 0 } From 8c6671d550fd8e46b1749016ae9e2c17720dc478 Mon Sep 17 00:00:00 2001 From: Thang Do Date: Sat, 12 Oct 2024 12:27:46 +1030 Subject: [PATCH 5/7] fixed another typo --- cmd/new.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/new.go b/cmd/new.go index 0cbe404..c7e8fb8 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -1,4 +1,4 @@ -paackage cmd +package cmd import ( "errors" From e87166e2b2691cd91a0940d07cedbfa4eca563f3 Mon Sep 17 00:00:00 2001 From: Thang Do Date: Wed, 16 Oct 2024 19:20:59 +1030 Subject: [PATCH 6/7] Rewrite ExpandPath to utilise builtin os.UserHomeDir() validate string, raise err and other minor typos --- cmd/edit.go | 2 +- cmd/new.go | 9 +++++---- config/config.go | 37 +++++++++++++++++++++++++++++-------- snippet/snippet.go | 41 ++++++++++++++++++++++++++--------------- sync/sync.go | 12 +++++++++--- 5 files changed, 70 insertions(+), 31 deletions(-) diff --git a/cmd/edit.go b/cmd/edit.go index dc66edb..6fdcfe1 100644 --- a/cmd/edit.go +++ b/cmd/edit.go @@ -39,7 +39,7 @@ func edit(cmd *cobra.Command, args []string) (err error) { } if snippetFile == "" { - return errors.New("No sippet file seleted") + return errors.New("No snippet file seleted") } // file content before editing diff --git a/cmd/new.go b/cmd/new.go index c7e8fb8..dc97151 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -166,12 +166,12 @@ func createAndEditSnippet(newSnippet snippet.SnippetInfo, snippets snippet.Snipp } func countSnippetLines() int { - // Count lines in snippet file - if config.Conf.General.SnippetFile == "" { + filepath, err := config.ExpandPath(config.Conf.General.SnippetFile) + if err != nil { return 0 } - f, err := os.Open(config.ExpandPath(config.Conf.General.SnippetFile)) + f, err := os.Open(filepath) if err != nil { panic("Error reading snippet file") } @@ -223,10 +223,10 @@ func _new(in io.ReadCloser, out io.Writer, args []string) (err error) { } return createAndEditSnippet(newSnippet, snippets, lineCount+3) - } else { command, err = scan(color.HiYellowString("Command> "), out, in, false) } + if err != nil { return err } @@ -263,6 +263,7 @@ func _new(in io.ReadCloser, out io.Writer, args []string) (err error) { Command: command, Tag: tags, } + snippets.Snippets = append(snippets.Snippets, newSnippet) if err = snippets.Save(); err != nil { return err diff --git a/config/config.go b/config/config.go index b0df2b9..fae9d69 100644 --- a/config/config.go +++ b/config/config.go @@ -6,6 +6,7 @@ import ( "os/exec" "path/filepath" "runtime" + "strings" "github.com/pelletier/go-toml" "github.com/pkg/errors" @@ -99,6 +100,10 @@ func (cfg *Config) Load(file string) error { } var snippetdirs []string for _, dir := range cfg.General.SnippetDirs { + if !strings.HasSuffix(dir, "/") { + dir = dir + "/" + } + snippetdirs = append(snippetdirs, dir) // note the = instead of := } cfg.General.SnippetDirs = snippetdirs @@ -118,9 +123,14 @@ func (cfg *Config) Load(file string) error { if err != nil { return errors.Wrap(err, "Failed to get the default config directory") } + cfg.General.SnippetFile = filepath.Join(dir, "snippet.toml") + file_path, err := ExpandPath(cfg.General.SnippetFile) + if err != nil { + return errors.Wrap(err, "SnippetFile path is invalid: %v") + } - _, err = os.Create(ExpandPath(cfg.General.SnippetFile)) + _, err = os.Create(file_path) if err != nil { return errors.Wrap(err, "Failed to create a snippet file") } @@ -133,6 +143,7 @@ func (cfg *Config) Load(file string) error { cfg.General.Editor = "vim" } } + cfg.General.Column = 40 cfg.General.SelectCmd = "fzf --ansi --layout=reverse --border --height=90% --pointer=* --cycle --prompt=Snippets:" cfg.General.Backend = "gist" @@ -166,15 +177,25 @@ func GetDefaultConfigDir() (dir string, err error) { return dir, nil } -func ExpandPath(s string) string { - if len(s) >= 2 && s[0] == '~' && os.IsPathSeparator(s[1]) { - if runtime.GOOS == "windows" { - s = filepath.Join(os.Getenv("USERPROFILE"), s[2:]) - } else { - s = filepath.Join(os.Getenv("HOME"), s[2:]) +// Given a path to either a file or directory, returns its absolute path format. +// ExpandPath resolves "~/" prefix in a given system path. +// Raise error if path is an empty string as it +func ExpandPath(path string) (string, error) { + if path == "" { + error := errors.New("path to file/directory is not set.") + return path, error + } + + if strings.HasPrefix(path, "~/") { + homedir, err := os.UserHomeDir() + if err != nil { + return path, err } + + return filepath.Join(homedir, path[2:]), nil } - return os.Expand(s, os.Getenv) + + return path, nil } func isCommandAvailable(name string) bool { diff --git a/snippet/snippet.go b/snippet/snippet.go index e44e137..70b9cbd 100644 --- a/snippet/snippet.go +++ b/snippet/snippet.go @@ -30,9 +30,8 @@ func (snippets *Snippets) Load(includeDirs bool) error { // Create a list of snippet files to load snippets from var snippetFiles []string - if config.Conf.General.SnippetFile != "" { - snippetFile := config.ExpandPath(config.Conf.General.SnippetFile) - + snippetFile, err := config.ExpandPath(config.Conf.General.SnippetFile) + if err == nil { if _, err := os.Stat(snippetFile); err == nil { snippetFiles = append(snippetFiles, config.Conf.General.SnippetFile) } else if !os.IsNotExist(err) { @@ -47,28 +46,35 @@ if you only want to provide snippetdirs instead`, } } - // Optionally load snippets from snippet directories - if includeDirs { - for _, dir := range config.Conf.General.SnippetDirs { - if _, err := os.Stat(dir); err != nil { - if os.IsNotExist(err) { - return fmt.Errorf("snippet directory not found. %s", dir) - } - return fmt.Errorf("failed to load snippet directory. %v", err) + for _, snippetDir := range config.Conf.General.SnippetDirs { + dir, err := config.ExpandPath(snippetDir) + if err != nil { + return fmt.Errorf("snippet directory not found. %s", snippetDir) + } + + if _, err := os.Stat(dir); err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("snippet directory not found. %s", snippetDir) } snippetFiles = append(snippetFiles, getFiles(dir)...) } - snippetFiles = append(snippetFiles, getFiles(config.ExpandPath(dir))...) + + snippetFiles = append(snippetFiles, getFiles(dir)...) } // Read files and load snippets for _, file := range snippetFiles { - tmp := Snippets{} - f, err := os.ReadFile(config.ExpandPath(file)) + file_path, err := config.ExpandPath(file) if err != nil { return fmt.Errorf("failed to load snippet file. %v", err) } + f, err := os.ReadFile(file_path) + if err != nil { + return fmt.Errorf("failed to load snippet file. %v", err) + } + + tmp := Snippets{} err = toml.Unmarshal(f, &tmp) if err != nil { return fmt.Errorf("failed to parse snippet file. %v", err) @@ -99,7 +105,12 @@ func (snippets *Snippets) Save() error { } } - f, err := os.Create(config.ExpandPath(snippetFile)) + file_path, err := config.ExpandPath(snippetFile) + if err != nil { + return fmt.Errorf("failed to save snippet file. err: %s", err) + } + + f, err := os.Create(file_path) if err != nil { return fmt.Errorf("failed to save snippet file. err: %s", err) } diff --git a/sync/sync.go b/sync/sync.go index 7571d24..829b641 100644 --- a/sync/sync.go +++ b/sync/sync.go @@ -100,16 +100,16 @@ func upload(client Client) (err error) { // download downloads snippets from the remote repository // and saves them to the main snippet file - directories ignored func download(content string) error { - snippetFile := config.ExpandPath(config.Conf.General.SnippetFile) - var snippets snippet.Snippets if err := snippets.Load(false); err != nil { return err } + body, err := snippets.ToString() if err != nil { return err } + if content == body { // no need to download fmt.Println("Already up-to-date") @@ -117,5 +117,11 @@ func download(content string) error { } fmt.Println("Download success") - return os.WriteFile(snippetFile, []byte(content), os.ModePerm) + + file_path, err := config.ExpandPath(config.Conf.General.SnippetFile) + if err != nil { + return err + } + + return os.WriteFile(file_path, []byte(content), os.ModePerm) } From 78f9832cca3d791fb50ce9c80374cea1cff74ea7 Mon Sep 17 00:00:00 2001 From: Thang Do Date: Fri, 25 Oct 2024 09:45:20 +1030 Subject: [PATCH 7/7] Resolve merge conflicts --- snippet/snippet.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/snippet/snippet.go b/snippet/snippet.go index 70b9cbd..31a3a6a 100644 --- a/snippet/snippet.go +++ b/snippet/snippet.go @@ -46,20 +46,22 @@ if you only want to provide snippetdirs instead`, } } - for _, snippetDir := range config.Conf.General.SnippetDirs { - dir, err := config.ExpandPath(snippetDir) - if err != nil { - return fmt.Errorf("snippet directory not found. %s", snippetDir) - } - - if _, err := os.Stat(dir); err != nil { - if os.IsNotExist(err) { + if includeDirs { + for _, snippetDir := range config.Conf.General.SnippetDirs { + dir, err := config.ExpandPath(snippetDir) + if err != nil { return fmt.Errorf("snippet directory not found. %s", snippetDir) } + + if _, err := os.Stat(dir); err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("snippet directory not found. %s", snippetDir) + } + snippetFiles = append(snippetFiles, getFiles(dir)...) + } + snippetFiles = append(snippetFiles, getFiles(dir)...) } - - snippetFiles = append(snippetFiles, getFiles(dir)...) } // Read files and load snippets