Skip to content

Commit 61d44e0

Browse files
committed
Add autocompletion forwarding for wrappers
1 parent 1525141 commit 61d44e0

File tree

5 files changed

+230
-6
lines changed

5 files changed

+230
-6
lines changed

commands/completion.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package commands
2+
3+
import (
4+
"embed"
5+
6+
"github.com/symfony-cli/console"
7+
)
8+
9+
// completionTemplates holds our custom shell completions templates.
10+
//
11+
//go:embed resources/completion.*
12+
var completionTemplates embed.FS
13+
14+
func init() {
15+
// override console completion templates with our custom ones
16+
console.CompletionTemplates = completionTemplates
17+
}

commands/resources/completion.bash

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright (c) 2021-present Fabien Potencier <fabien@symfony.com>
2+
#
3+
# This file is part of Symfony CLI project
4+
#
5+
# This program is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU Affero General Public License as
7+
# published by the Free Software Foundation, either version 3 of the
8+
# License, or (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU Affero General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU Affero General Public License
16+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
#
18+
# Bash completions for the CLI binary
19+
#
20+
# References:
21+
# - https://github.com/symfony/symfony/blob/6.4/src/Symfony/Component/Console/Resources/completion.bash
22+
# - https://github.com/posener/complete/blob/master/install/bash.go
23+
# - https://github.com/scop/bash-completion/blob/master/completions/sudo
24+
#
25+
26+
# this wrapper function allows us to let Symfony knows how to call the
27+
# `bin/console` using the Symfony CLI binary (to ensure the right env and PHP
28+
# versions are used)
29+
_{{ .App.HelpName }}_console() {
30+
# shellcheck disable=SC2068
31+
{{ .CurrentBinaryInvocation }} console $@
32+
}
33+
34+
_complete_{{ .App.HelpName }}() {
35+
36+
# Use the default completion for shell redirect operators.
37+
for w in '>' '>>' '&>' '<'; do
38+
if [[ $w = "${COMP_WORDS[COMP_CWORD-1]}" ]]; then
39+
compopt -o filenames
40+
COMPREPLY=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}"))
41+
return 0
42+
fi
43+
done
44+
45+
for (( i=1; i <= COMP_CWORD; i++ )); do
46+
if [[ "${COMP_WORDS[i]}" != -* ]]; then
47+
case "${COMP_WORDS[i]}" in
48+
console)
49+
_SF_CMD="_{{ .App.HelpName }}_console" _command_offset $i
50+
return
51+
;;
52+
composer{{range $name := (.App.Command "php").Names }}|{{$name}}{{end}}{{range $name := (.App.Command "run").Names }}|{{$name}}{{end}})
53+
_command_offset $i
54+
return
55+
;;
56+
esac;
57+
fi
58+
done
59+
60+
IFS=$'\n' COMPREPLY=( $(COMP_LINE="${COMP_LINE}" COMP_POINT="${COMP_POINT}" COMP_DEBUG="$COMP_DEBUG" {{ .CurrentBinaryPath }} self:autocomplete) )
61+
}
62+
63+
complete -F _complete_{{ .App.HelpName }} {{ .App.HelpName }}

commands/resources/completion.fish

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Copyright (c) 2021-present Fabien Potencier <fabien@symfony.com>
2+
#
3+
# This file is part of Symfony CLI project
4+
#
5+
# This program is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU Affero General Public License as
7+
# published by the Free Software Foundation, either version 3 of the
8+
# License, or (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU Affero General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU Affero General Public License
16+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
#
18+
# Fish completions for the CLI binary
19+
#
20+
# References:
21+
# - https://github.com/symfony/symfony/blob/6.4/src/Symfony/Component/Console/Resources/completion.fish
22+
# - https://github.com/posener/complete/blob/master/install/fish.go
23+
# - https://github.com/fish-shell/fish-shell/blob/master/share/completions/sudo.fish
24+
#
25+
26+
function __complete_{{ .App.HelpName }}
27+
set -lx COMP_LINE (commandline -cp)
28+
test -z (commandline -ct)
29+
and set COMP_LINE "$COMP_LINE "
30+
{{ .CurrentBinaryInvocation }} self:autocomplete
31+
end
32+
33+
# this wrapper function allows us to call Symfony autocompletion letting it
34+
# knows how to call the `bin/console` using the Symfony CLI binary (to ensure
35+
# the right env and PHP versions are used)
36+
function __complete_{{ .App.HelpName }}_console
37+
set -x _SF_CMD "{{ .CurrentBinaryInvocation }}" "console"
38+
__fish_complete_subcommand
39+
end
40+
41+
complete -f -c '{{ .App.HelpName }}' -n "__fish_seen_subcommand_from console" -a '(__complete_{{ .App.HelpName }}_console)' -f
42+
complete -f -c '{{ .App.HelpName }}' -n "__fish_seen_subcommand_from composer" -a '(__fish_complete_subcommand)'
43+
complete -f -c '{{ .App.HelpName }}' -n "__fish_seen_subcommand_from {{range $i, $name := (.App.Command "php").Names }}{{if $i}} {{end}}{{$name}}{{end}}" -a '(__fish_complete_subcommand)'
44+
complete -f -c '{{ .App.HelpName }}' -n "__fish_seen_subcommand_from {{range $i, $name := (.App.Command "run").Names }}{{if $i}} {{end}}{{$name}}{{end}}" -a '(__fish_complete_subcommand --fcs-skip=2)'
45+
complete -f -c '{{ .App.HelpName }}' -n "not __fish_seen_subcommand_from console composer {{range $i, $name := (.App.Command "php").Names }}{{if $i}} {{end}}{{$name}}{{end}} {{range $i, $name := (.App.Command "run").Names }}{{if $i}} {{end}}{{$name}}{{end}}" -a '(__complete_{{ .App.HelpName }})'

commands/resources/completion.zsh

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#compdef {{ .App.HelpName }}
2+
3+
# Copyright (c) 2021-present Fabien Potencier <fabien@symfony.com>
4+
#
5+
# This file is part of Symfony CLI project
6+
#
7+
# This program is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU Affero General Public License as
9+
# published by the Free Software Foundation, either version 3 of the
10+
# License, or (at your option) any later version.
11+
#
12+
# This program is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU Affero General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU Affero General Public License
18+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
20+
#
21+
# zsh completions for {{ .App.HelpName }}
22+
#
23+
# References:
24+
# - https://github.com/symfony/symfony/blob/6.4/src/Symfony/Component/Console/Resources/completion.zsh
25+
# - https://github.com/posener/complete/blob/master/install/zsh.go
26+
# - https://stackoverflow.com/a/13547531
27+
#
28+
29+
# this wrapper function allows us to let Symfony knows how to call the
30+
# `bin/console` using the Symfony CLI binary (to ensure the right env and PHP
31+
# versions are used)
32+
_{{ .App.HelpName }}_console() {
33+
# shellcheck disable=SC2068
34+
{{ .CurrentBinaryInvocation }} console $@
35+
}
36+
37+
_complete_{{ .App.HelpName }}() {
38+
local lastParam flagPrefix requestComp out comp
39+
local -a completions
40+
41+
# The user could have moved the cursor backwards on the command-line.
42+
# We need to trigger completion from the $CURRENT location, so we need
43+
# to truncate the command-line ($words) up to the $CURRENT location.
44+
# (We cannot use $CURSOR as its value does not work when a command is an alias.)
45+
words=("${=words[1,CURRENT]}") lastParam=${words[-1]}
46+
47+
# For zsh, when completing a flag with an = (e.g., {{ .App.HelpName }} -n=<TAB>)
48+
# completions must be prefixed with the flag
49+
setopt local_options BASH_REMATCH
50+
if [[ "${lastParam}" =~ '-.*=' ]]; then
51+
# We are dealing with a flag with an =
52+
flagPrefix="-P ${BASH_REMATCH}"
53+
fi
54+
55+
# detect if we are in a wrapper command and need to "forward" completion to it
56+
for ((i = 1; i <= $#words; i++)); do
57+
if [[ "${words[i]}" != -* ]]; then
58+
case "${words[i]}" in
59+
console)
60+
shift words
61+
(( CURRENT-- ))
62+
_SF_CMD="_{{ .App.HelpName }}_console" _normal
63+
return
64+
;;
65+
composer{{range $name := (.App.Command "php").Names }}|{{$name}}{{end}})
66+
shift words
67+
(( CURRENT-- ))
68+
_normal
69+
return
70+
;;
71+
{{range $i, $name := (.App.Command "local:run").Names }}{{if $i}}|{{end}}{{$name}}{{end}})
72+
shift words
73+
(( CURRENT-- ))
74+
shift words
75+
(( CURRENT-- ))
76+
_normal
77+
return
78+
;;
79+
esac;
80+
fi
81+
done
82+
83+
while IFS='\n' read -r comp; do
84+
if [ -n "$comp" ]; then
85+
# We first need to escape any : as part of the completion itself.
86+
comp=${comp//:/\\:}
87+
completions+=${comp}
88+
fi
89+
done < <(COMP_LINE="$words" ${words[0]} ${_SF_CMD:-${words[1]}} self:autocomplete)
90+
91+
# Let inbuilt _describe handle completions
92+
eval _describe "completions" completions $flagPrefix
93+
}
94+
95+
compdef _complete_{{ .App.HelpName }} {{ .App.HelpName }}

commands/wrappers.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,18 @@ var (
4545
phpWrapper = &console.Command{
4646
Usage: "Runs the named binary using the configured PHP version",
4747
Hidden: console.Hide,
48+
Aliases: func() []*console.Alias {
49+
binNames := php.GetBinaryNames()
50+
aliases := make([]*console.Alias, 0, len(binNames))
51+
52+
for _, name := range php.GetBinaryNames() {
53+
aliases = append(aliases, &console.Alias{Name: name})
54+
}
55+
56+
return aliases
57+
}(),
4858
Action: func(c *console.Context) error {
4959
return console.IncorrectUsageError{ParentError: errors.New(`This command can only be run as "symfony php*"`)}
5060
},
5161
}
5262
)
53-
54-
func init() {
55-
for _, name := range php.GetBinaryNames() {
56-
phpWrapper.Aliases = append(phpWrapper.Aliases, &console.Alias{Name: name, Hidden: console.Hide()})
57-
}
58-
}

0 commit comments

Comments
 (0)