Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support relative path for snippet's filename attribute #322

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cmd/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 9 additions & 3 deletions cmd/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,16 @@ func createAndEditSnippet(newSnippet snippet.SnippetInfo, snippets snippet.Snipp
}

func countSnippetLines() int {
// Count lines in snippet file
f, err := os.Open(config.Conf.General.SnippetFile)
filepath, err := config.ExpandPath(config.Conf.General.SnippetFile)
if err != nil {
return 0
}
csessh marked this conversation as resolved.
Show resolved Hide resolved

f, err := os.Open(filepath)
if err != nil {
panic("Error reading snippet file")
}

lineCount, err := CountLines(f)
if err != nil {
panic("Error counting lines in snippet file")
Expand Down Expand Up @@ -218,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
}
Expand Down Expand Up @@ -258,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
Expand Down
44 changes: 33 additions & 11 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
"strings"

"github.com/pelletier/go-toml"
"github.com/pkg/errors"
Expand Down Expand Up @@ -98,9 +99,12 @@ func (cfg *Config) Load(file string) error {
return err
}
var snippetdirs []string
cfg.General.SnippetFile = expandPath(cfg.General.SnippetFile)
RamiAwar marked this conversation as resolved.
Show resolved Hide resolved
for _, dir := range cfg.General.SnippetDirs {
snippetdirs = append(snippetdirs, expandPath(dir)) // note the = instead of :=
if !strings.HasSuffix(dir, "/") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I recall correctly, that's because it would lead to new snippet filename being incorrect.

snippetFile = config.Conf.General.SnippetDirs[0] + fmt.Sprintf("%s.toml", strings.ToLower(sanitize.BaseName(snippet.Description)))

for example:

/var/tmp/petNewCommand.toml

instead of

/var/tmp/pet/NewCommand.toml

dir = dir + "/"
}

snippetdirs = append(snippetdirs, dir) // note the = instead of :=
}
cfg.General.SnippetDirs = snippetdirs
return nil
Expand All @@ -109,6 +113,7 @@ func (cfg *Config) Load(file string) error {
if !os.IsNotExist(err) {
return err
}

f, err := os.Create(file)
if err != nil {
return err
Expand All @@ -118,10 +123,16 @@ 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")
_, err = os.Create(cfg.General.SnippetFile)
file_path, err := ExpandPath(cfg.General.SnippetFile)
if err != nil {
return errors.Wrap(err, "Failed to create a config file")
return errors.Wrap(err, "SnippetFile path is invalid: %v")
}

_, err = os.Create(file_path)
if err != nil {
return errors.Wrap(err, "Failed to create a snippet file")
}

cfg.General.Editor = os.Getenv("EDITOR")
Expand All @@ -132,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"
Expand Down Expand Up @@ -165,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, "~/") {
csessh marked this conversation as resolved.
Show resolved Hide resolved
homedir, err := os.UserHomeDir()
if err != nil {
return path, err
}

return filepath.Join(homedir, path[2:]), nil
csessh marked this conversation as resolved.
Show resolved Hide resolved
}
return os.Expand(s, os.Getenv)

return path, nil
}

func isCommandAvailable(name string) bool {
Expand Down
63 changes: 63 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package config

import (
"os"
"runtime"
"testing"
)

func getUserHomeDir() string {
if runtime.GOOS == "windows" {
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
if home == "" {
home = os.Getenv("USERPROFILE")
}
return home
}
return os.Getenv("HOME")
}

func TestExpandPathWithTilde(t *testing.T) {
test_path := "~/.config/pet"
expectedPath := getUserHomeDir() + "/.config/pet"
csessh marked this conversation as resolved.
Show resolved Hide resolved

result, err := ExpandPath(test_path)

if err != nil {
t.Errorf("Expected no error, but %v was raised", err)
}

if result != expectedPath {
t.Errorf("Expected result to be %s, but got %s", expectedPath, result)
}
}

func TestExpandAbsolutePath(t *testing.T) {
test_path := "/var/tmp/"
expectedPath := "/var/tmp/"

result, err := ExpandPath(test_path)

if err != nil {
t.Errorf("Expected no error, but %v was raised", err)
}

if result != expectedPath {
t.Errorf("Expected result to be %s, but got %s", expectedPath, result)
}
}

func TestExpandPathWithEmptyInput(t *testing.T) {
test_path := ""
expectedPath := ""

result, err := ExpandPath(test_path)

if err == nil {
t.Errorf("Expected error to be raised, but got nil")
}

if result != expectedPath {
t.Errorf("Expected result to be empty, but got %s", result)
}
}
40 changes: 27 additions & 13 deletions snippet/snippet.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,45 +30,53 @@ 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 != "" {
snippetFile, err := config.ExpandPath(config.Conf.General.SnippetFile)
if err == nil {
if _, err := os.Stat(snippetFile); err == nil {
snippetFiles = append(snippetFiles, snippetFile)
snippetFiles = append(snippetFiles, config.Conf.General.SnippetFile)
csessh marked this conversation as resolved.
Show resolved Hide resolved
} else if !os.IsNotExist(err) {
return fmt.Errorf("failed to load snippet file. %v", err)
} else {
return fmt.Errorf(
`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,
)
}
}

// Optionally load snippets from snippet directories
if includeDirs {
for _, dir := range config.Conf.General.SnippetDirs {
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", dir)
return fmt.Errorf("snippet directory not found. %s", snippetDir)
}
return fmt.Errorf("failed to load snippet directory. %v", err)
snippetFiles = append(snippetFiles, getFiles(dir)...)
csessh marked this conversation as resolved.
Show resolved Hide resolved
}

snippetFiles = append(snippetFiles, getFiles(dir)...)
}
}

// Read files and load snippets
for _, file := range snippetFiles {
tmp := Snippets{}
f, err := os.ReadFile(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)
Expand Down Expand Up @@ -98,7 +106,13 @@ func (snippets *Snippets) Save() error {
newSnippets.Snippets = append(newSnippets.Snippets, snippet)
}
}
f, err := os.Create(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)
}
Expand Down
12 changes: 9 additions & 3 deletions sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,22 +100,28 @@ 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

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")
return nil
}

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)
}