Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dbf42ec
Changed bash completions for nested commands
jeffreyroberts Apr 22, 2013
24c5845
Combined sub commands and completions
jeffreyroberts Apr 22, 2013
d64d43a
Modified sub-help for nested commands
jeffreyroberts Apr 22, 2013
560c636
Modified sub for nested commands
jeffreyroberts Apr 22, 2013
b7b7a6a
Modified prepare script for sub sub commands
jeffreyroberts Apr 22, 2013
fd5792d
Adding sub-sub-command examples
jeffreyroberts Apr 22, 2013
fbc39c1
Quick change to sub-help
jeffreyroberts Apr 22, 2013
019c1ac
Got sub-commands auto-complete working
jeffreyroberts Apr 22, 2013
4278c6f
Sub commands working with both bash and zsh
jeffreyroberts Apr 22, 2013
72b8d87
Added zsh completions for nested sub sub commands
jeffreyroberts Apr 22, 2013
dd458b1
Replaced seq with triple expression
jeffreyroberts Apr 23, 2013
79a12ab
Renamed example variable
jeffreyroberts Apr 23, 2013
dc4ee37
Added example for auto file completions
jeffreyroberts Apr 23, 2013
e134574
Fixes #7 - Example script
jeffreyroberts Apr 23, 2013
254a7f7
Refactoring
jeffreyroberts Apr 23, 2013
34a4bb9
Refactoring
jeffreyroberts Apr 23, 2013
1da72da
Fixes Auto File Completion
jeffreyroberts Apr 23, 2013
8764cfc
Minor README.md update
jeffreyroberts Apr 24, 2013
2bf26a9
small typo in bash completions
jeffreyroberts Apr 25, 2013
95a123e
Added ability to have help on root sub-sub-command
jeffreyroberts Apr 28, 2013
13797c3
Removed auto complete from sub commands, it was breaking help
jeffreyroberts Apr 28, 2013
138b124
Minor edit
jeffreyroberts Apr 28, 2013
d1d4108
Did some debugging
jeffreyroberts Apr 28, 2013
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
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Sub is a model for setting up shell programs that use subcommands, like `git` or
A sub program is run at the command line using this style:

$ [name of program] [subcommand] [(args)]
$ [name of program] [subcommand] [subcommand] [(args)]

Here's some quick examples:

Expand All @@ -15,10 +16,13 @@ Here's some quick examples:
Each subcommand maps to a separate, standalone executable program. Sub programs are laid out like so:

.
├── bin # contains the main executable for your program
├── completions # (optional) bash/zsh completions
├── libexec # where the subcommand executables are
└── share # static data storage
├── bin # contains the main executable for your program
├── completions # (optional) bash/zsh completions
├── libexec # where the subcommand executables are
├───> sub-command # sub command (Displays summary for b & c)
| ├────∎ sub-command-b # sub command command-b <args>
| └────∎ sub-command-c # sub command command-c <args>
└── share # static data storage

## Subcommands

Expand Down Expand Up @@ -49,8 +53,7 @@ You can run *any* executable in the `libexec` directly, as long as it follows th

You get a few commands that come with your sub:

* `commands`: Prints out every subcommand available
* `completions`: Helps kick off subcommand autocompletion.
* `commands`: Prints out every subcommand available and kicks off autocompletion
* `help`: Document how to use each subcommand
* `init`: Shows how to load your sub with autocompletions, based on your shell.
* `shell`: Helps with calling subcommands that might be named the same as builtin/executables.
Expand Down
13 changes: 8 additions & 5 deletions completions/sub.bash
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ _sub() {

if [ "$COMP_CWORD" -eq 1 ]; then
COMPREPLY=( $(compgen -W "$(sub commands)" -- "$word") )
else
local command="${COMP_WORDS[1]}"
local completions="$(sub completions "$command")"
COMPREPLY=( $(compgen -W "$completions" -- "$word") )
elif [ "$COMP_CWORD" -gt 1 ]; then
commands="$(sub commands ${COMP_WORDS[@]})"
if [ "$commands" ]; then
COMPREPLY=( $(compgen -W "$commands" -- "$word") )
else
return 1
fi
fi
}

complete -F _sub sub
complete -o default -F _sub sub
5 changes: 2 additions & 3 deletions completions/sub.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ compctl -K _sub sub
_sub() {
local word words completions
read -cA words
word="${words[2]}"

if [ "${#words}" -eq 2 ]; then
completions="$(sub commands)"
else
completions="$(sub completions "${word}")"
elif [ "${#words}" -gt 2 ]; then
completions="$(sub commands "$words")"
fi

reply=("${(ps:\n:)completions}")
Expand Down
76 changes: 64 additions & 12 deletions libexec/sub
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,73 @@ abs_dirname() {

libexec_path="$(abs_dirname "$0")"
export _SUB_ROOT="$(abs_dirname "$libexec_path")"
export PATH="${libexec_path}:$PATH"

commands=($@)

path_builder="$_SUB_ROOT/libexec"
command_builder=""
_SUB_COMMAND_IS="false"
prev_command=""

for (( i=0; i<=${#commands[@]}; i++ ))
do
if [ "${commands[$i]}" != "" ] && [[ "${commands[$i]}" != -* ]]; then
if [ -d "$path_builder/sub-${commands[$i]}" ]; then
path_builder="$path_builder/sub-${commands[$i]}"
fi
if [ -f "$path_builder/sub-${commands[$i]}" ]; then
prev_command=$command_builder
command_builder="${commands[$i]}"
_SUB_COMMAND_IS="true"
else
_SUB_COMMAND_IS="false"
fi
fi

if [[ "${commands[$i]}" == -* ]]; then
break
fi
done

flags=""
flags_on="false"
for (( i=0; i<=${#commands[@]}; i++ ))
do
if [[ "${commands[$i]}" == -* ]] || [ "$flags_on" == "true" ]; then
flags="$flags${commands[$i]} "
flags_on="true"
fi
done

export _SUB_COMMAND_ROOT="$path_builder"
export _SUB_COMMAND_FILE="$command_builder"
export _SUB_COMMAND_VARS="$@"
export _SUB_COMMAND_IS="$_SUB_COMMAND_IS"

if [ -d "$_SUB_COMMAND_ROOT" ]; then
export PATH="${libexec_path}:$_SUB_COMMAND_ROOT:$PATH"
else
export PATH="${libexec_path}:$PATH"
fi

command="$1"
case "$command" in
"" | "-h" | "--help" )
if [ "$command" == "" ] || [ "$command" == "-h" ] || [ "$command" == "-help" ]; then
exec sub-help
;;
* )
exit
elif [ "$command" == "help" ] || [ "$command" == "commands" ]; then
command_path="$(command -v "sub-$command" || true)"
if [ ! -x "$command_path" ]; then
echo "sub: no such command \`$command'" >&2
exit 1
fi
else
command_path="$(command -v "sub-$command_builder" || true)"
fi

if [ ! -x "$command_path" ]; then
echo "sub: no such command \`$command'" >&2
exit 1
fi

shift
shift
if [ "$flags" == "" ]; then
exec "$command_path" "$@"
;;
esac
else
exec "$command_path" $flags
fi
46 changes: 31 additions & 15 deletions libexec/sub-commands
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@

set -e

# Provide sub completions
if [ "$1" = "--complete" ]; then
echo --sh
echo --no-sh
exit
fi

if [ "$1" = "--sh" ]; then
sh=1
shift
Expand All @@ -23,19 +16,42 @@ fi

shopt -s nullglob

if grep -i "^# provide sub completions" "$_SUB_COMMAND_ROOT/sub-$_SUB_COMMAND_FILE" >/dev/null; then
completions=`exec "$_SUB_COMMAND_ROOT/sub-$_SUB_COMMAND_FILE" --complete "$@"`
if [ "$completions" ]; then
echo $completions
fi
exit
fi

{ for path in ${PATH//:/$'\n'}; do
for command in "${path}/sub-"*; do
Copy link

Choose a reason for hiding this comment

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

I don't fully understand what is being achieved here, perhaps add some comments explaining what's going on? Something like what are the cases where we want to show the commands and where we don't.

Copy link
Author

Choose a reason for hiding this comment

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

I will def add some comments, I am going to work on this for a couple of hours now

command="${command##*sub-}"
if [ -n "$sh" ]; then
if [ ${command:0:3} = "sh-" ]; then
echo ${command##sh-}
if [ ! "$command" == "$_SUB_COMMAND_ROOT/sub-$_SUB_COMMAND_FILE" ] || [ "$_SUB_COMMAND_FILE" == "commands" ]; then
if [ -d "$_SUB_COMMAND_ROOT" ] && [ "$_SUB_COMMAND_ROOT" == "$path" ]; then
do_commands="true"
elif [ ! -d "$_SUB_COMMAND_ROOT" ] || [ "$_SUB_COMMAND_ROOT" == "$_SUB_ROOT/libexec" ]; then
do_commands="true"
else
do_commands="false"
fi
elif [ -n "$nosh" ]; then
if [ ${command:0:3} != "sh-" ]; then
elif [ "$command" == "commands" ] && [ "$command" == "$_SUB_COMMAND_FILE" ]; then
Copy link

Choose a reason for hiding this comment

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

[ "$command" == "commands" ]

That condition can now never be true, since $command is always going to be a path with "/sub-" in it.

Copy link
Author

Choose a reason for hiding this comment

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

Very good call =]

do_commands="true"
else
do_commands="false"
fi
if [ "$do_commands" == "true" ]; then
command="${command##*sub-}"
if [ -n "$sh" ]; then
if [ ${command:0:3} = "sh-" ]; then
echo ${command##sh-}
fi
elif [ -n "$nosh" ]; then
if [ ${command:0:3} != "sh-" ]; then
echo ${command##sh-}
fi
else
echo ${command##sh-}
fi
else
echo ${command##sh-}
fi
done
done
Expand Down
14 changes: 0 additions & 14 deletions libexec/sub-completions

This file was deleted.

8 changes: 8 additions & 0 deletions libexec/sub-example/sub-advanced/sub-advanced
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Usage: sub example advanced
# Summary: List all Advanced sub Example Scripts
# Help: This command lists all of the Advanced sub Example Scripts

set -e

sub help example bash advanced
54 changes: 54 additions & 0 deletions libexec/sub-example/sub-advanced/sub-expert/sub-case-select
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# Usage: sub example advanced expert case-select
# Summary: BASH Case Select Example
# Help: This is an example of a BASH Case Select

set -e

# Provide sub completions
if [ "$1" = "--complete" ]; then
echo --name
echo --break
exit
fi

what="counter"
break_on=6
while [ ! "$1" == "" ]; do
case "$1" in
--name)
if [[ ! "$2" == -* ]]; then
name=$2
shift
else
name="default"
fi
;;
--break)
if [[ ! "$2" == -* ]]; then
break_on=$2
shift
else
break_on=3
fi
;;
esac

shift
done

echo "-=> Executing Case Select Example"
echo "----> Breaking on $break_on"
echo "----> Counter is called $name"

COUNTER=0
while [ $COUNTER -lt 5 ]; do
echo "------> The $name is $COUNTER"
COUNTER=`expr $COUNTER + 1`

if [ "$break_on" == "$COUNTER" ]; then
break
fi
done

echo "- Finished..."
6 changes: 6 additions & 0 deletions libexec/sub-example/sub-advanced/sub-expert/sub-expert
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Usage: sub example advanced expert
# Summary: Collection of expert scripts
# Help: Collection of advanced expert sub scripts

sub help example advanced expert
21 changes: 21 additions & 0 deletions libexec/sub-example/sub-advanced/sub-fix-7
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Usage: sub example advanced fix-7
# Summary: Fixes Issue #7
# Help: Fixes Issue #7: https://github.com/37signals/sub/issues/7

set -e

# Provide sub completions
if [ "$1" = "--complete" ]; then
while [ ! "$1" == "" ]; do
if [ "$1" = "foo" ] || [ "$1" = "bar" ]; then
{ echo baz; echo bla; } | sort | uniq
exit
fi

shift
done

{ echo foo; echo bar; } | sort | uniq
exit;
fi
8 changes: 8 additions & 0 deletions libexec/sub-example/sub-basic/sub-basic
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Usage: sub example bash basic
# Summary: List all basic sub Example Scripts
# Help: This command lists all of the basic sub Example Scripts

set -e

sub help example bash basic
4 changes: 4 additions & 0 deletions libexec/sub-example/sub-basic/sub-files
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
# Usage: sub example basic filecomplete
# Summary: Example of auto completion for files
# Help: This is an example of auto completion for files
39 changes: 39 additions & 0 deletions libexec/sub-example/sub-basic/sub-foreach
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# Usage: sub example basic foreach [--break]
# Summary: BASH For Each Example w/ break loop option
# Help: This command is an example of a BASH For Each Loop with an example of how to break the loop based on an argument parameter

set -e

# Provide sub completions
if [ "$1" = "--complete" ]; then
echo --break
exit
fi

if [ "$1" = "--break" ] && [ ! "$2" == "" ] && [[ ! "$2" == -* ]]; then
break_on=$2
shift
shift
elif [ "$1" = "--break" ] && [ "$2" == "" ]; then
echo "Defaulting Break On Three"
break_on=3
shift
else
break_on=6
fi

foreach_array=("one" "two" "three" "four" "five")
count=0

for array_value in ${foreach_array[@]}
do
if [ "$break_on" == "$count" ]; then
break
else
echo $array_value
fi
count=`expr $count + 1`
done

echo "done"
8 changes: 8 additions & 0 deletions libexec/sub-example/sub-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Usage: sub example [command]
# Summary: Collection of BASH Sub Example Scripts
# Help: These commands are mostly used as examples and for testing sub modifications

set -e

sub help example
Loading