diff --git a/README.md b/README.md index a335f24..1363204 100644 --- a/README.md +++ b/README.md @@ -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: @@ -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`: + +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 @@ -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 @@ -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. diff --git a/abbr/abbr.fish b/abbr/abbr.fish index c1a2132..758c616 100644 --- a/abbr/abbr.fish +++ b/abbr/abbr.fish @@ -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 diff --git a/abbr/abbr.zsh b/abbr/abbr.zsh index 83cb611..4c67b22 100644 --- a/abbr/abbr.zsh +++ b/abbr/abbr.zsh @@ -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} diff --git a/abbr/fish.go b/abbr/fish.go index 60799ad..4c65464 100644 --- a/abbr/fish.go +++ b/abbr/fish.go @@ -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 + 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" } diff --git a/abbr/zsh.go b/abbr/zsh.go index dc5ceed..3230065 100644 --- a/abbr/zsh.go +++ b/abbr/zsh.go @@ -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" } diff --git a/cmd/update.go b/cmd/update.go index 1cb5900..5eb4d62 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -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) diff --git a/docs/abbreviations.md b/docs/abbreviations.md index 6c1c2c0..b6a62b5 100644 --- a/docs/abbreviations.md +++ b/docs/abbreviations.md @@ -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`: @@ -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. diff --git a/inout/disk.go b/inout/disk.go index 8d5f6b2..2c878eb 100644 --- a/inout/disk.go +++ b/inout/disk.go @@ -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 { + 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) @@ -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) @@ -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 } - storagePath := filepath.Join(homeDir, ".local", "share", "pal_helper", commandFileName) // Ensure directory exists storageDir := filepath.Dir(storagePath) @@ -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() 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