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
8 changes: 8 additions & 0 deletions cmd/codecrafters/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ EXAMPLES
$ codecrafters submit -m "msg" # Commit changes & run tests with a custom commit message
$ codecrafters test # Run tests without committing changes
$ codecrafters test --previous # Run tests for all previous stages and the current stage without committing changes
$ codecrafters completion zsh # Generate shell completions for zsh

COMMANDS
submit: Commit changes & run tests
test: Run tests without committing changes
task: View current stage instructions
update-buildpack: Update language version
ping: Test the connection to a CodeCrafters repository
completion: Generate shell completions for bash, zsh, or fish
help: Show usage instructions

VERSION
Expand Down Expand Up @@ -111,6 +113,12 @@ func run() error {
return commands.UpdateBuildpackCommand()
case "ping":
return commands.PingCommand()
case "completion":
if flag.NArg() != 2 {
fmt.Print(commands.CompletionUsage())
return nil
}
return commands.CompletionCommand(flag.Arg(1))
case "help",
"": // no argument
flag.Usage()
Expand Down
230 changes: 230 additions & 0 deletions internal/commands/completions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
package commands

import (
"fmt"
"strings"
)

const (
ShellBash = "bash"
ShellZsh = "zsh"
ShellFish = "fish"
)

func CompletionCommand(shell string) (err error) {
var completionScript string
switch shell {
case ShellBash:
completionScript = bashCompletion
case ShellZsh:
completionScript = zshCompletion
case ShellFish:
completionScript = fishCompletion
case "-help":
fallthrough
case "--help":
fmt.Print(CompletionUsage())
return nil
default:
return fmt.Errorf("unsupported shell %q; supported shells: %s", shell, strings.Join(supportedShells, ", "))
}
fmt.Print(completionScript)

return nil
}

var supportedShells = []string{ShellBash, ShellZsh, ShellFish}

func CompletionUsage() string {
return fmt.Sprintf(`Generate shell completions for codecrafters.

USAGE
$ codecrafters completion <%s>

INSTALL
Bash:
$ mkdir -p ~/.local/share/bash-completion/completions
$ codecrafters completion bash > ~/.local/share/bash-completion/completions/codecrafters
$ echo "source ~/.local/share/bash-completion/completions/codecrafters" >> ~/.bashrc

Zsh:
$ mkdir -p ~/.zsh/completions/
$ codecrafters completion zsh > ~/.zsh/completions/_codecrafters
$ echo "fpath=(~/.zsh/completions $fpath)" >> ~/.zshrc
$ echo "autoload -Uz compinit && compinit" >> ~/.zshrc

Fish:
$ codecrafters completion fish > ~/.config/fish/completions/codecrafters.fish
`, strings.Join(supportedShells, "|"))
}

const bashCompletion = `# bash completion for codecrafters

_codecrafters()
{
local cur prev words cword command
COMPREPLY=()

if declare -F _init_completion >/dev/null 2>&1; then
_init_completion || return
else
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
words=("${COMP_WORDS[@]}")
cword=$COMP_CWORD
fi

local commands="submit test task update-buildpack ping completion help"
local global_flags="--help --version"
local shells="bash zsh fish"

command=""
for word in "${words[@]:1:cword-1}"; do
case "$word" in
submit|test|task|update-buildpack|ping|completion|help)
command="$word"
break
;;
esac
done

case "$prev" in
-m|--message|--stage|bash|zsh|fish)
return 0
;;
esac

if [[ -z "$command" ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=( $(compgen -W "$global_flags" -- "$cur") )
else
COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
fi
return 0
fi

case "$command" in
submit)
COMPREPLY=( $(compgen -W "-m --message --help" -- "$cur") )
;;
test)
COMPREPLY=( $(compgen -W "--previous --help" -- "$cur") )
;;
task)
COMPREPLY=( $(compgen -W "--stage --raw --help" -- "$cur") )
;;
completion)
COMPREPLY=( $(compgen -W "$shells" -- "$cur") )
;;
esac
}

complete -F _codecrafters codecrafters
`

const zshCompletion = `#compdef codecrafters

_codecrafters() {
local -a commands global_flags submit_flags test_flags test_previous_flag task_flags no_arg_command_flags shells

commands=(
'submit:Commit changes and run tests'
'test:Run tests without committing changes'
'task:View current stage instructions'
'update-buildpack:Update language version'
'ping:Test the connection to a CodeCrafters repository'
'completion:Generate shell completion script'
'help:Show usage instructions'
)
global_flags=(
'--help:show usage instructions'
'--version:print version and exit'
)

submit_flags=(
'-m:Commit changes and run tests with a custom commit message'
'--message:Commit changes and run tests with a custom commit message'
'--help:show usage instructions'
'-help:show usage instructions'
)
test_flags=(
'--help:show usage instructions'
'-help:show usage instructions'
)
task_flags=(
'--stage:view instructions for a specific stage (slug, +N, or -N)'
'--raw:print instructions without pretty-printing'
'--help:show usage instructions'
'-help:show usage instructions'
)
no_arg_command_flags=(
'--help'
'-help'
)
shells=(bash zsh fish)

if (( CURRENT == 2 )); then
if [[ "${words[CURRENT]}" == -* ]]; then
_describe -t options 'codecrafters option' global_flags
return
fi

_describe -t commands 'codecrafters command' commands
return
fi


case "${words[2]}" in
submit)
if [[ "${words[(Ie)-m]}" -ne 0 || "${words[(Ie)--message]}" -ne 0 || "${words[(Ie)-help]}" -ne 0 || "${words[(Ie)--help]}" -ne 0 ]]; then
return
fi
_describe -t options 'submit option' submit_flags
;;
test)
if [[ "${words[(Ie)--previous]}" -ne 0 || "${words[(Ie)-help]}" -ne 0 || "${words[(Ie)--help]}" -ne 0 ]]; then
return
fi
_describe -t options 'test option' test_flags
;;
task)
_describe -t options 'task option' task_flags
;;
update-buildpack|ping|help)
return
;;
completion)
if [[ "${words[(Ie)bash]}" -ne 0 || "${words[(Ie)zsh]}" -ne 0 || "${words[(Ie)fish]}" -ne 0 ]]; then
return
fi

if [[ "${words[CURRENT]}" == -* ]]; then
_describe -t options 'completion option' no_arg_command_flags
else
_describe -t shells 'shell' shells
fi
;;
esac
}

compdef _codecrafters codecrafters
`

const fishCompletion = `# fish completion for codecrafters

complete -c codecrafters -f
complete -c codecrafters -n __fish_use_subcommand -a submit -d 'Commit changes and run tests'
complete -c codecrafters -n __fish_use_subcommand -a test -d 'Run tests without committing changes'
complete -c codecrafters -n __fish_use_subcommand -a task -d 'View current stage instructions'
complete -c codecrafters -n __fish_use_subcommand -a update-buildpack -d 'Update language version'
complete -c codecrafters -n __fish_use_subcommand -a ping -d 'Test the connection to a CodeCrafters repository'
complete -c codecrafters -n __fish_use_subcommand -a completion -d 'Generate shell completion script'
complete -c codecrafters -n __fish_use_subcommand -a help -d 'Show usage instructions'
complete -c codecrafters -n __fish_use_subcommand -l help -d 'show usage instructions'
complete -c codecrafters -n __fish_use_subcommand -l version -d 'print version and exit'
complete -c codecrafters -n '__fish_seen_subcommand_from submit' -s m -l message -r -d 'Commit changes and run tests with a custom commit message'
complete -c codecrafters -n '__fish_seen_subcommand_from test; and not __fish_seen_argument -l previous' -l previous -d 'Run tests for all previous stages and the current stage without committing changes'
complete -c codecrafters -n '__fish_seen_subcommand_from task' -l stage -r -d 'view instructions for a specific stage (slug, +N, or -N)'
complete -c codecrafters -n '__fish_seen_subcommand_from task' -l raw -d 'print instructions without pretty-printing'
complete -c codecrafters -n '__fish_seen_subcommand_from completion; and not __fish_seen_argument -a bash zsh fish' -a 'bash zsh fish'
`