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
33 changes: 30 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

![demo3 1](https://github.com/user-attachments/assets/e6f4be6e-788e-453e-9f27-2b61b76755aa)

For now, `fish` and `zsh` are fully supported and testing is done on Linux only. MacOS might just work too.
`fish` and `zsh` are fully supported on Linux and macOS.

Perhaps unsurprisingly, xkcd [has](https://xkcd.com/1168/) elucidated the core situation inspiring this software:

Expand All @@ -14,7 +14,23 @@ Perhaps unsurprisingly, xkcd [has](https://xkcd.com/1168/) elucidated the core s

## Quickstart

It's a single binary that you can just download into any location on your `$PATH`:
It's a single binary that you can download into any location on your `$PATH`:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

We can standardize on curl here too (see comment below). But why do we have a different curl invocation in the update command versus here on the README?

Also, let's put Linux at the top of the list :)


macOS (Apple Silicon):

```sh
curl -L https://github.com/scottyeager/Pal/releases/latest/download/pal-darwin-arm64 -o /usr/local/bin/pal
chmod +x /usr/local/bin/pal
```

macOS (Intel):

```sh
curl -L https://github.com/scottyeager/Pal/releases/latest/download/pal-darwin-amd64 -o /usr/local/bin/pal
chmod +x /usr/local/bin/pal
```

Linux (x86_64):

```sh
wget https://github.com/scottyeager/Pal/releases/latest/download/pal-linux-amd64 -O /usr/local/bin/pal
Expand Down Expand Up @@ -58,7 +74,7 @@ For interactive configuration, run:

```sh
pal /config
# Config saved successfully at ~/.config/pal_helper/config.yaml
# The command will print where your config was saved (varies by OS)
```

## Abbreviations
Expand All @@ -72,6 +88,17 @@ pal2 # Etc

Both `fish` and `zsh` are supported for abbreviations. If you followed the quickstart, abbreviations will be available in every new shell or after sourcing the shell config file. For more info, see [abbreviations](https://github.com/scottyeager/Pal/blob/main/docs/abbreviations.md).

### Paths

`pal` uses standard OS-specific paths:

- Config file:
- macOS: `~/Library/Application Support/pal_helper/config.yaml`
- Linux: `~/.config/pal_helper/config.yaml`
- Abbreviations file (stores suggestions for pal1, pal2, ...):
- macOS: `~/Library/Application Support/pal_helper/expansions.txt`
- Linux: `~/.local/share/pal_helper/expansions.txt`

## Autocompletion

Since `pal` is built with [Cobra](https://github.com/spf13/cobra), it's able to generate autocompletions for a variety of shells automatically. Currently only the `fish` and `zsh` completions are exposed.
Expand Down
7 changes: 6 additions & 1 deletion abbr/abbr.fish
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ if not set -q pal_prefix
end

function _pal_get_completion
set completions_file ~/.local/share/pal_helper/expansions.txt
# Use configured path if provided, otherwise default to XDG path
if set -q pal_abbr_file
set completions_file $pal_abbr_file
else
set completions_file ~/.local/share/pal_helper/expansions.txt
end
set suffix (string match -r "$pal_prefix(\d+)" $argv[1] | tail -n1)

# Handle prefix0 specially
Expand Down
2 changes: 1 addition & 1 deletion abbr/abbr.zsh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# File containing the command lines to expand to
local PAL_ABBR_FILE=~/.local/share/pal_helper/expansions.txt
local PAL_ABBR_FILE=${PAL_ABBR_FILE:-~/.local/share/pal_helper/expansions.txt}
# Default prefix value if not set
local pal_prefix=${pal_prefix:-pal}

Expand Down
11 changes: 10 additions & 1 deletion abbr/fish.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@ package abbr

import (
_ "embed"
"fmt"
"github.com/scottyeager/pal/inout"
)

//go:embed abbr.fish
var FishAbbrEmbed string

func GetFishAbbrScript(abbreviationPrefix string) string {
return `set -l pal_prefix "` + abbreviationPrefix + `"` + "\n" + FishAbbrEmbed + "\n"
path, err := inout.GetAbbrFilePath()
if err != nil {
// Fallback to Linux default if something goes wrong
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Let's not blindly continue on error. Same for zsh.

path = fmt.Sprintf("%s", "~/.local/share/pal_helper/expansions.txt")
}
return `set -g pal_prefix "` + abbreviationPrefix + `"` + "\n" +
`set -g pal_abbr_file "` + path + `"` + "\n" +
FishAbbrEmbed + "\n"
}
11 changes: 10 additions & 1 deletion abbr/zsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@ package abbr

import (
_ "embed"
"fmt"
"github.com/scottyeager/pal/inout"
)

//go:embed abbr.zsh
var ZshAbbrEmbed string

func GetZshAbbrScript(abbreviationPrefix string) string {
return `local pal_prefix="` + abbreviationPrefix + `"` + "\n" + ZshAbbrEmbed + "\n"
path, err := inout.GetAbbrFilePath()
if err != nil {
// Fallback to Linux default if something goes wrong
path = fmt.Sprintf("%s", "~/.local/share/pal_helper/expansions.txt")
}
return `local pal_prefix="` + abbreviationPrefix + `"` + "\n" +
`export PAL_ABBR_FILE="` + path + `"` + "\n" +
ZshAbbrEmbed + "\n"
}
8 changes: 7 additions & 1 deletion cmd/update.go
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Let's just use curl. It should always be there on Linux too, so we can keep it simple.

Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,13 @@ var updateCmd = &cobra.Command{
default:
return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
}
updateCmd := fmt.Sprintf(`wget -q https://github.com/scottyeager/Pal/releases/latest/download/%s -O %s && chmod +x %s`, binaryName, execPath, execPath)
// macOS typically doesn't ship with wget, so prefer curl there
var updateCmd string
if runtime.GOOS == "darwin" {
updateCmd = fmt.Sprintf(`curl -fsSL https://github.com/scottyeager/Pal/releases/latest/download/%s -o %s && chmod +x %s`, binaryName, execPath, execPath)
} else {
updateCmd = fmt.Sprintf(`wget -q https://github.com/scottyeager/Pal/releases/latest/download/%s -O %s && chmod +x %s`, binaryName, execPath, execPath)
}
err = inout.StorePrefix0Command(updateCmd)
if err != nil {
return fmt.Errorf("error storing update command: %w", err)
Expand Down
30 changes: 30 additions & 0 deletions docs/abbreviations.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ $ pal3 # Expands to `dir`
# Multiple lines can also be expanded together, such as with pal123
```

Note for zsh users: type the abbreviation (e.g. `pal1`) and press Space to expand. Press Enter afterwards to execute the expanded command.

This eliminates the need to copy and paste command suggestions. The abbreviations will always dynamically expand into the commands suggested by the last bare `pal` command or the equivalent `/cmd` command.

The stored commands that will expand when using the abbreviations can be printed with `/show`:
Expand Down Expand Up @@ -69,6 +71,34 @@ Bring this change into open shell sessions by sourcing your config file again:
source ~/.zshrc
```

#### Using abbreviations in zsh

- Type `pal1` then press Space to expand to the first suggestion. Press Enter to run it.
- Use `pal2`, `pal3`, etc. For multiple lines, `pal123` expands the first three suggestions.
- Show the stored suggestions at any time with:
```sh
pal /show
```

#### Troubleshooting (zsh)

- Enable for the current shell immediately:
```sh
source <(pal --zsh)
```
- Verify Space is bound to the expansion widget:
```sh
bindkey ' ' | grep pal-expand-abbr
```
If there’s no output, re-run the `source <(pal --zsh)` command above.

#### Paths

The file that stores suggestions (used by `pal1`, `pal2`, …):

- macOS: `~/Library/Application Support/pal_helper/expansions.txt`
- Linux: `~/.local/share/pal_helper/expansions.txt`

## Disabling abbreviations

To disable the abbreviation feature, just remove the line from your shell config file. No permanent changes have been made to your shell, but this change will also only apply to new shells.
Expand Down
32 changes: 24 additions & 8 deletions inout/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,34 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
)

const commandFileName = "expansions.txt"

func GetStoredCommands() (string, error) {
// GetAbbrFilePath returns the full path to the abbreviations storage file.
// On macOS it uses: ~/Library/Application Support/pal_helper/expansions.txt
// On Linux it uses: ~/.local/share/pal_helper/expansions.txt
func GetAbbrFilePath() (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("failed to get home directory: %w", err)
}
storagePath := filepath.Join(homeDir, ".local", "share", "pal_helper", commandFileName)
var storageDir string
if runtime.GOOS == "darwin" {
storageDir = filepath.Join(homeDir, "Library", "Application Support", "pal_helper")
} else {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Technically on the off chance that someone tries pal on FreeBSD, etc, they will also fall under this branch. As far as I can tell, using the XDG standard on these systems is okay. Maybe we can just mention this possibility in the comment, so it doesn't look like we are using a catchall else to mean linux.

storageDir = filepath.Join(homeDir, ".local", "share", "pal_helper")
}
return filepath.Join(storageDir, commandFileName), nil
}

func GetStoredCommands() (string, error) {
storagePath, err := GetAbbrFilePath()
if err != nil {
return "", err
}

// Ensure directory exists
storageDir := filepath.Dir(storagePath)
Expand All @@ -41,11 +58,10 @@ func GetStoredCommands() (string, error) {
}

func StorePrefix0Command(command string) error {
homeDir, err := os.UserHomeDir()
storagePath, err := GetAbbrFilePath()
if err != nil {
return fmt.Errorf("failed to get home directory: %w", err)
return err
}
storagePath := filepath.Join(homeDir, ".local", "share", "pal_helper", commandFileName)

// Ensure directory exists
storageDir := filepath.Dir(storagePath)
Expand Down Expand Up @@ -79,11 +95,10 @@ func StorePrefix0Command(command string) error {
}

func StoreCommands(completion string) error {
homeDir, err := os.UserHomeDir()
storagePath, err := GetAbbrFilePath()
if err != nil {
return fmt.Errorf("failed to get home directory: %w", err)
return err
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Let's also wrap this error to provide context. Not sure if we are doing that totally consistently, but it seems like a good idea.

}
storagePath := filepath.Join(homeDir, ".local", "share", "pal_helper", commandFileName)

// Ensure directory exists
storageDir := filepath.Dir(storagePath)
Expand Down Expand Up @@ -116,6 +131,7 @@ func StoreCommands(completion string) error {

// Clean up the old file if it exists. This shouldn't slow us down if the
// file no longer exists, since stat hits cached data
homeDir, _ := os.UserHomeDir()
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

We should not be silently dropping the possible err here, I think. Better to keep what we had I think:

	if err != nil {
		return fmt.Errorf("failed to get home directory: %w", err)

oldPath := filepath.Join(homeDir, ".local", "share", "pal_helper", "completions.txt")
if _, err := os.Stat(oldPath); !os.IsNotExist(err) {
// If both exist, remove the old one
Expand Down