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

Fish completions #18

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
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
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,14 @@ As far as I know, [Nix](https://search.nixos.org/packages?channel=unstable&query
## Without a package manager

1. Put the `sd` script somewhere on your `PATH`.
2. Put the `_sd` completion script somewhere on your `fpath`.
2. For zsh completions, put the `_sd` completion script somewhere on your `fpath`.
3. For fish completions, put the `sd.fish` completion script into your [completions directory](https://fishshell.com/docs/current/completions.html#where-to-put-completions), probably `~/.config/fish/completions/`.

I like to symlink `sd` to `~/bin`, which is already on my path. If you've cloned this repo to `~/src/sd`, you can do that by running something like:

$ ln -s ~/src/sd/sd ~/bin/sd

There isn't really a standard place in your home directory to put completion scripts, so unless you've made your own, you'll probably want to add your clone directly to your `fpath`. You should add that to your `.zshrc` file before the line where you call `compinit`. It should look something like this:
With zsh, there isn't really a standard place in your home directory to put completion scripts, so unless you've made your own, you'll probably want to add your clone directly to your `fpath`. You should add that to your `.zshrc` file before the line where you call `compinit`. It should look something like this:

# ~/.zshrc

Expand Down Expand Up @@ -295,9 +296,7 @@ plugins+=(sd)
source "$ZSH/oh-my-zsh.sh"
```

# bash/fish autocompletion support

Patrick Jackson contributed [an unofficial fish completion script](https://gist.github.com/patricksjackson/5065e4a9d8e825dafc7824112f17a5e6), which should be usable with some modification (as written it does not respect `SD_ROOT`, but it should act as a very good starting point if you use fish).
# bash autocompletion support

Bash doesn't support the fancy completion-with-description feature that is sort of the whole point of `sd`, but there are apparently ways to hack something similar.

Expand Down
115 changes: 115 additions & 0 deletions sd.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Completions for the custom Script Directory (sd) script

# These are based on the contents of the Script Directory, so we're reading info from the files.
# The description is taken either from the first line of the file $cmd.help,
# or the first non-shebang comment in the $cmd file.

# Also note, completions are loaded at fish startup, not dynamically, so you need to reload fish for changes here to take effect.

# The '-f' on all complete commands is to disable file completions everywhere except for after the full command is written out

# Use $HOME/sd as the default location, otherwise take the value of SD_ROOT
function __sd_root_location
if set -q SD_ROOT
echo "$SD_ROOT"
else
echo "$HOME/sd"
end
end

# Create command completions for a subcommand
# Takes a list of all the subcommands seen so far
function __sd_list_subcommand
# Handles fully nested subcommands
set -l root_location (__sd_root_location)
set -l basepath (string join '/' "$root_location" $argv)

# Total subcommands
# Used so that we can ignore duplicate commands
set -l commands
for file in (ls -d "$basepath"/*)
set -l cmd (basename $file .help)
set -l helpfile $cmd.help
if [ (basename $file) != "$helpfile" ]
set commands $commands $cmd
end
end

# Setup the check for when to show these commands
# Basically you need to have seen everything in the path up to this point but not any commands in the current directory.
# This will cause problems if you have a command with the same name as a directory parent.
set -l check
for arg in $argv
set check (string join ' and ' $check "__fish_seen_subcommand_from $arg;")
end
set check (string join ' ' $check "and not __fish_seen_subcommand_from $commands")

# Loop through the files using their full path names.
for file in (ls -d "$basepath"/*)
set -l cmd (basename $file .help)
set -l helpfile $cmd.help
if [ (basename $file) = "$helpfile" ]
# This is the helpfile, use it for the help statement
set -l help (head -n1 "$file")
complete -f -c sd -a "$cmd" -d "$help" \
-n $check
else if test -d "$file"
set -l help "$cmd commands"
__sd_list_subcommand $argv $cmd
complete -f -c sd -a "$cmd" -d "$help" \
-n "$check"
else
set -l help (sed -nE -e '/^#!/d' -e '/^#/{s/^# *//; p; q;}' "$file")
if not test -e "$helpfile"
complete -f -c sd -a "$cmd" -d "$help" \
-n "$check"
end
end
end
end

function __sd_list_commands
# commands is used in the completions to know if we've seen the base commands
set -l commands

# Create a list of commands for this directory.
# The list is used to know when to not show more commands from this directory.
for file in $argv
set -l cmd (basename $file .help)
set -l helpfile $cmd.help
if [ (basename $file) != "$helpfile" ]
# Ignore the special commands that take the paths as input.
if not contains $cmd cat edit help new which
set commands $commands $cmd
end
end
end
for file in $argv
set -l cmd (basename $file .help)
set -l helpfile $cmd.help
if [ (basename $file) = "$helpfile" ]
# This is the helpfile, use it for the help statement
set -l help (head -n1 "$file")
complete -f -c sd -a "$cmd" -d "$help" \
-n "not __fish_seen_subcommand_from $commands"
else if test -d "$file"
# Directory, start recursing into subcommands
set -l help "$cmd commands"
__sd_list_subcommand $cmd
complete -f -c sd -a "$cmd" -d "$help" \
-n "not __fish_seen_subcommand_from $commands"
else
# Script
# Pull the help test from the first non-shebang commented line.
set -l help (sed -nE -e '/^#!/d' -e '/^#/{s/^# *//; p; q;}' "$file")
if not test -e "$helpfile"
complete -f -c sd -a "$cmd" -d "$help" \
-n "not __fish_seen_subcommand_from $commands"
end
end
end
end

set -l root_location (__sd_root_location)
__sd_list_commands "$root_location"/*