Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ You can use also use variables in snippets, these are called parameters. More in
You can also *tag* snippets to search for them faster. More information on that in the tag section.



# Parameters
There are `<n_ways>` ways of entering parameters.

They can contain default values: Hello `<subject=world>`
defined by the equal sign.
defined by the equal sign.

They can even contain `<content=spaces & = signs>` where the default value would be \<content=<mark>spaces & = signs</mark>\>.

Expand All @@ -105,6 +106,9 @@ Hello `<subject=|_John_||_Sam_||_Jane Doe = special #chars_|>`

The values in this case would be :Hello \<subject=\|\_<mark>John</mark>\_\|\|\_<mark>Sam</mark>\_\|\|\_<mark>Jane Doe = special #chars</mark>\_\|\>

If you want to disable parameter expansion (i.e. treat `<...>` as literal text), you can use the `-s` or `--static` flag when creating a new snippet with `pet new`, or you can add the field `Static = true` in the snippet's definition table.


# Examples
Some examples are shown below.

Expand All @@ -131,7 +135,7 @@ function prev() {
```

### fish
See below for details.
See below for details.
https://github.com/otms61/fish-pet

<img src="doc/pet02.gif" width="700">
Expand Down Expand Up @@ -170,7 +174,7 @@ bindkey '^s' pet-select
```

### fish
See below for details.
See below for details.
https://github.com/otms61/fish-pet

<img src="doc/pet03.gif" width="700">
Expand Down Expand Up @@ -253,7 +257,7 @@ export FZF_CTRL_R_OPTS="
--info=right
--color header:italic
--header 'alt+s (pet new)'
--preview 'echo {}' --preview-window down:3:hidden:wrap
--preview 'echo {}' --preview-window down:3:hidden:wrap
--bind '?:toggle-preview'
--bind 'alt-s:execute(pet new --tag {2..})+abort'"
```
Expand Down Expand Up @@ -298,7 +302,7 @@ Use "pet [command] --help" for more information about a command.
```

# Snippet
Run `pet edit`
Run `pet edit`
You can also register the output of command (but cannot search).

```
Expand Down Expand Up @@ -452,7 +456,7 @@ You must obtain access token.
Go https://github.com/settings/tokens/new and create access token (only need "gist" scope).
Set that to `access_token` in `[Gist]` or use an environment variable with the name `$PET_GITHUB_ACCESS_TOKEN`.

After setting, you can upload snippets to Gist.
After setting, you can upload snippets to Gist.
If `gist_id` is not set, new gist will be created.
```
pet sync
Expand Down Expand Up @@ -541,14 +545,14 @@ Upload success
```

# Installation
You need to install selector command ([fzf](https://github.com/junegunn/fzf) or [peco](https://github.com/peco/peco)).
You need to install selector command ([fzf](https://github.com/junegunn/fzf) or [peco](https://github.com/peco/peco)).
`homebrew` install `fzf` automatically.

After you install Pet, it's HIGHLY recommended to install the shortcuts mentioned in the section on [ZSH Prev](#zsh-prev-function)


## Binary
Go to [the releases page](https://github.com/knqyf263/pet/releases), find the version you want, and download the zip file. Unpack the zip file, and put the binary to somewhere you want (on UNIX-y systems, /usr/local/bin or the like). Make sure it has execution bits turned on.
Go to [the releases page](https://github.com/knqyf263/pet/releases), find the version you want, and download the zip file. Unpack the zip file, and put the binary to somewhere you want (on UNIX-y systems, /usr/local/bin or the like). Make sure it has execution bits turned on.

## macOS / Homebrew

Expand Down
16 changes: 16 additions & 0 deletions cmd/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ func CanceledError() error {
return errors.New("canceled")
}

// setStaticField sets the static field on a snippet if the static flag is enabled
func setStaticField(snippetInfo *snippet.SnippetInfo) {
if config.Flag.Static {
static := true
snippetInfo.Static = &static
}
}

func scan(prompt string, out io.Writer, in io.ReadCloser, allowEmpty bool) (string, error) {
f, err := os.CreateTemp("", "pet-")
if err != nil {
Expand Down Expand Up @@ -232,6 +240,9 @@ func _new(in io.ReadCloser, out io.Writer, args []string) (err error) {
Tag: tags,
}

// Set static field if static flag is used
setStaticField(&newSnippet)

return createAndEditSnippet(newSnippet, snippets, lineCount+3)
} else {
command, err = scan(color.HiYellowString("Command> "), out, in, false)
Expand Down Expand Up @@ -274,6 +285,9 @@ func _new(in io.ReadCloser, out io.Writer, args []string) (err error) {
Tag: tags,
}

// Set static field if static flag is used
setStaticField(&newSnippet)

snippets.Snippets = append(snippets.Snippets, newSnippet)
if err = snippets.Save(); err != nil {
return err
Expand All @@ -298,4 +312,6 @@ func init() {
`Can enter multiline snippet (Double \n to quit)`)
newCmd.Flags().BoolVarP(&config.Flag.UseEditor, "editor", "e", false,
`Use editor to create snippet`)
newCmd.Flags().BoolVarP(&config.Flag.Static, "static", "s", false,
`Create snippet without parameter expansion (static = true)`)
}
176 changes: 176 additions & 0 deletions cmd/new_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,179 @@ func compareSnippets(a, b snippet.Snippets) bool {
}
return true
}

func TestNew_WithStaticFlag(t *testing.T) {
// Setup temporary directory for config
tempDir, _ := os.MkdirTemp("", "testdata")
tempSnippetFile := filepath.Join(tempDir, "snippet.toml")

// Clean up temp dirs
defer os.RemoveAll(tempDir)

// Create empty snippet file
_, err := os.Create(tempSnippetFile)
if err != nil {
t.Fatalf("Failed to create temp snippet file: %v", err)
}

// Mock configuration
config.Conf.General.SnippetFile = tempSnippetFile
config.Conf.General.SnippetDirs = []string{}

// Set the static flag to true
originalStatic := config.Flag.Static
config.Flag.Static = true
defer func() { config.Flag.Static = originalStatic }()

// Simulate creating a new snippet with static flag
args := []string{"echo hello <name>"}

// Create a buffer for output
var outputBuffer bytes.Buffer
// Create a mock ReadCloser for input (description)
inputReader := &MockReadCloser{strings.NewReader("test description\n")}

err = _new(inputReader, &outputBuffer, args)
if err != nil {
t.Fatalf("Failed to create new snippet: %v", err)
}

// Load the snippet file and check if static field is set
var snippets snippet.Snippets
loadSnippetsFromFile(t, tempSnippetFile, &snippets)

if len(snippets.Snippets) != 1 {
t.Fatalf("Expected 1 snippet, got %d", len(snippets.Snippets))
}

createdSnippet := snippets.Snippets[0]
if createdSnippet.Command != "echo hello <name>" {
t.Errorf("Expected command to be 'echo hello <name>', got '%s'", createdSnippet.Command)
}

if createdSnippet.Description != "test description" {
t.Errorf("Expected description to be 'test description', got '%s'", createdSnippet.Description)
}

// Check that static field is set to true
if createdSnippet.Static == nil {
t.Error("Expected Static field to be set, got nil")
} else if !*createdSnippet.Static {
t.Error("Expected Static field to be true, got false")
}
}

func TestNew_WithoutStaticFlag(t *testing.T) {
// Setup temporary directory for config
tempDir, _ := os.MkdirTemp("", "testdata")
tempSnippetFile := filepath.Join(tempDir, "snippet.toml")

// Clean up temp dirs
defer os.RemoveAll(tempDir)

// Create empty snippet file
_, err := os.Create(tempSnippetFile)
if err != nil {
t.Fatalf("Failed to create temp snippet file: %v", err)
}

// Mock configuration
config.Conf.General.SnippetFile = tempSnippetFile
config.Conf.General.SnippetDirs = []string{}

// Ensure the static flag is false
originalStatic := config.Flag.Static
config.Flag.Static = false
defer func() { config.Flag.Static = originalStatic }()

// Simulate creating a new snippet without static flag
args := []string{"echo hello <name>"}

// Create a buffer for output
var outputBuffer bytes.Buffer
// Create a mock ReadCloser for input (description)
inputReader := &MockReadCloser{strings.NewReader("test description\n")}

err = _new(inputReader, &outputBuffer, args)
if err != nil {
t.Fatalf("Failed to create new snippet: %v", err)
}

// Load the snippet file and check if static field is not set
var snippets snippet.Snippets
loadSnippetsFromFile(t, tempSnippetFile, &snippets)

if len(snippets.Snippets) != 1 {
t.Fatalf("Expected 1 snippet, got %d", len(snippets.Snippets))
}

createdSnippet := snippets.Snippets[0]
if createdSnippet.Command != "echo hello <name>" {
t.Errorf("Expected command to be 'echo hello <name>', got '%s'", createdSnippet.Command)
}

// Check that static field is nil (not set) when flag is false
if createdSnippet.Static != nil {
t.Errorf("Expected Static field to be nil when flag is false, got %v", *createdSnippet.Static)
}
}

func TestNew_WithStaticFlagAndEditor(t *testing.T) {
// Setup temporary directory for config
tempDir, _ := os.MkdirTemp("", "testdata")
tempSnippetFile := filepath.Join(tempDir, "snippet.toml")

// Clean up temp dirs
defer os.RemoveAll(tempDir)

// Create empty snippet file
_, err := os.Create(tempSnippetFile)
if err != nil {
t.Fatalf("Failed to create temp snippet file: %v", err)
}

// Mock configuration
config.Conf.General.SnippetFile = tempSnippetFile
config.Conf.General.SnippetDirs = []string{}
config.Conf.General.Editor = "echo" // Use echo as a mock editor that won't actually open

// Set flags
originalStatic := config.Flag.Static
originalUseEditor := config.Flag.UseEditor
config.Flag.Static = true
config.Flag.UseEditor = true
defer func() {
config.Flag.Static = originalStatic
config.Flag.UseEditor = originalUseEditor
}()

// Simulate creating a new snippet with static flag and editor
args := []string{} // No command args when using editor

// Create a buffer for output
var outputBuffer bytes.Buffer
// Create a mock ReadCloser for input
inputReader := &MockReadCloser{strings.NewReader("")}

err = _new(inputReader, &outputBuffer, args)
if err != nil {
t.Fatalf("Failed to create new snippet: %v", err)
}

// Load the snippet file and check if static field is set
var snippets snippet.Snippets
loadSnippetsFromFile(t, tempSnippetFile, &snippets)

if len(snippets.Snippets) != 1 {
t.Fatalf("Expected 1 snippet, got %d", len(snippets.Snippets))
}

createdSnippet := snippets.Snippets[0]

// Check that static field is set to true even when using editor
if createdSnippet.Static == nil {
t.Error("Expected Static field to be set, got nil")
} else if !*createdSnippet.Static {
t.Error("Expected Static field to be true, got false")
}
}
12 changes: 11 additions & 1 deletion cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,17 @@ func filter(options []string, tag string, raw bool) (commands []string, err erro
// If only one line is selected, search for params in the command
if len(lines) == 1 && !raw {
snippetInfo := snippetTexts[lines[0]]
params = dialog.SearchForParams(snippetInfo.Command)
// Check if snippet is static (parameter expansion disabled)
isStatic := false
if snippetInfo.Static != nil {
isStatic = *snippetInfo.Static
}

if !isStatic {
params = dialog.SearchForParams(snippetInfo.Command)
} else {
params = nil
}
} else {
params = nil
}
Expand Down
Loading