8000 Merge pull request #488 from tucksaun/feat/wrappers-autocomplete · symfony-cli/symfony-cli@7c0b22e · GitHub
[go: up one dir, main page]

Skip to content

Commit 7c0b22e

Browse files
authored
Merge pull request #488 from tucksaun/feat/wrappers-autocomplete
Add autocompletion forwarding for wrappers
2 parents 1525141 + 684d348 commit 7c0b22e

File tree

5 files changed

+240
-8
lines changed

5 files changed

+240
-8
lines changed

commands/completion.go

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

commands/resources/completion.bash

Lines changed: 63 additions & 0 deletions
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

Lines changed: 45 additions & 0 deletions
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

Lines changed: 95 additions & 0 deletions
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 }} {{ . 10000 App.HelpName }}

commands/wrappers.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,32 +27,42 @@ import (
2727

2828
var (
2929
composerWrapper = &console.Command{
30-
Name: "composer",
3130
Usage: "Runs Composer without memory limit",
3231
Hidden: console.Hide,
32+
// we use an alias to avoid the command being shown in the help but
33+
// still be available for completion
34+
Aliases: []*console.Alias{{Name: "composer"}},
3335
Action: func(c *console.Context) error {
3436
return console.IncorrectUsageError{ParentError: errors.New(`This command can only be run as "symfony composer"`)}
3537
},
3638
}
3739
binConsoleWrapper = &console.Command{
38-
Name: "console",
3940
Usage: "Runs the Symfony Console (bin/console) for current project",
4041
Hidden: console.Hide,
42+
// we use an alias to avoid the command being shown in the help but
43+
// still be available for completion
44+
Aliases: []*console.Alias{{Name: "console"}},
4145
Action: func(c *console.Context) error {
4246
return console.IncorrectUsageError{ParentError: errors.New(`This command can only be run as "symfony console"`)}
4347
},
4448
}
4549
phpWrapper = &console.Command{
4650
Usage: "Runs the named binary using the configured PHP version",
4751
Hidden: console.Hide,
52+
// we use aliases to avoid the command being shown in the help but
53+
// still be available for completion
54+
Aliases: func() []*console.Alias {
55+
binNames := php.GetBinaryNames()
56+
aliases := make([]*console.Alias, 0, len(binNames))
57+
58+
for _, name := range php.GetBinaryNames() {
59+
aliases = append(aliases, &console.Alias{Name: name})
60+
}
61+
62+
return aliases
63+
}(),
4864
Action: func(c *console.Context) error {
4965
return console.IncorrectUsageError{ParentError: errors.New(`This command can only be run as "symfony php*"`)}
5066
},
5167
}
5268
)
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)
0