Skip to content

Commit 20b01d5

Browse files
committed
feat: add bun bash completion
1 parent f7d9ef4 commit 20b01d5

File tree

3 files changed

+196
-2
lines changed

3 files changed

+196
-2
lines changed

.chezmoi.toml.tmpl

+3-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ sourceDir = {{ .chezmoi.sourceDir | quote }}
3131
{{ $email = promptStringOnce . "email" "Email address" -}}
3232
{{ $signingkey = promptStringOnce . "signingkey" "Signing key" -}}
3333
{{ $themes := list "gruvbox-dark" "catppuccin-mocha" "eldritch" "dracula" "dracula-pro" -}}
34-
{{ $colortheme = promptChoiceOnce . "colortheme" "Color theme" $themes -}}
35-
{{ $disable_bash_history = promptBoolOnce . "disable_bash_history" "Disable bash history" -}}
34+
{{ $defaultColorTheme := "gruvbox-dark" -}}
35+
{{ $colortheme = promptChoiceOnce . "colortheme" "Color theme" $themes $defaultColorTheme -}}
36+
{{ $disable_bash_history = promptBoolOnce . "disable_bash_history" "Disable bash history" false -}}
3637
{{- end -}}
3738

3839
{{- $osid := .chezmoi.os -}}

.pre-commit-config.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ repos:
2929
(?x)^(
3030
exact_private_dot_bashrc.d/05-complete-alias.bash|
3131
exact_private_dot_bashrc.d/10-bash-preexec.bash|
32+
exact_private_dot_bashrc.d/20-.*.bash|
3233
exact_private_dot_zprofile.d/.*|
3334
exact_private_dot_zshenv.d/.*|
3435
exact_private_dot_zshrc.d/.*
@@ -42,6 +43,7 @@ repos:
4243
(?x)^(
4344
exact_private_dot_bashrc.d/05-complete-alias.bash|
4445
exact_private_dot_bashrc.d/10-bash-preexec.bash|
46+
exact_private_dot_bashrc.d/20-.*.bash|
4547
exact_private_dot_zprofile.d/.*|
4648
exact_private_dot_zshenv.d/.*|
4749
exact_private_dot_zshrc.d/.*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#/usr/bin/env bash
2+
3+
_file_arguments() {
4+
local extensions="${1}"
5+
local reset=$(shopt -p globstar)
6+
shopt -s globstar
7+
8+
if [[ -z "${cur_word}" ]]; then
9+
COMPREPLY=( $(compgen -fG -X "${extensions}" -- "${cur_word}") );
10+
else
11+
COMPREPLY=( $(compgen -f -X "${extensions}" -- "${cur_word}") );
12+
fi
13+
14+
$reset
15+
}
16+
17+
_long_short_completion() {
18+
local wordlist="${1}";
19+
local short_options="${2}"
20+
21+
[[ -z "${cur_word}" || "${cur_word}" =~ ^- ]] && {
22+
COMPREPLY=( $(compgen -W "${wordlist}" -- "${cur_word}"));
23+
return;
24+
}
25+
[[ "${cur_word}" =~ ^-[A-Za_z]+ ]] && {
26+
COMPREPLY=( $(compgen -W "${short_options}" -- "${cur_word}"));
27+
return;
28+
}
29+
}
30+
31+
# loads the scripts block in package.json
32+
_read_scripts_in_package_json() {
33+
local package_json;
34+
local return_package_json
35+
local line=0;
36+
local working_dir="${PWD}";
37+
38+
for ((; line < ${#COMP_WORDS[@]}; line+=1)); do
39+
[[ "${COMP_WORDS[${line}]}" == "--cwd" ]] && working_dir="${COMP_WORDS[$((line + 1))]}";
40+
done
41+
42+
[[ -f "${working_dir}/package.json" ]] && package_json=$(<${working_dir}/package.json);
43+
44+
[[ "${package_json}" =~ "\"scripts\""[[:space:]]*":"[[:space:]]*\{(.*)\} ]] && {
45+
local package_json_compreply;
46+
local matched="${BASH_REMATCH[@]:1}";
47+
local scripts="${matched%%\}*}";
48+
scripts="${scripts//@(\"|\')/}";
49+
readarray -td, scripts <<<"${scripts}";
50+
for completion in "${scripts[@]}"; do
51+
package_json_compreply+=( "${completion%:*}" );
52+
done
53+
COMPREPLY+=( $(compgen -W "${package_json_compreply[*]}" -- "${cur_word}") );
54+
}
55+
56+
# when a script is passed as an option, do not show other scripts as part of the completion anymore
57+
local re_prev_script="(^| )${prev}($| )";
58+
[[
59+
( "${COMPREPLY[*]}" =~ ${re_prev_script} && -n "${COMP_WORDS[2]}" ) || \
60+
( "${COMPREPLY[*]}" =~ ${re_comp_word_script} )
61+
]] && {
62+
local re_script=$(echo ${package_json_compreply[@]} | sed 's/[^ ]*/(&)/g');
63+
local new_reply=$(echo "${COMPREPLY[@]}" | sed -E "s/$re_script//");
64+
COMPREPLY=( $(compgen -W "${new_reply}" -- "${cur_word}") );
65+
replaced_script="${prev}";
66+
}
67+
}
68+
69+
70+
_subcommand_comp_reply() {
71+
local cur_word="${1}"
72+
local sub_commands="${2}"
73+
local regexp_subcommand="^[dbcriauh]";
74+
[[ "${prev}" =~ ${regexp_subcommand} ]] && {
75+
COMPREPLY+=( $(compgen -W "${sub_commands}" -- "${cur_word}") );
76+
}
77+
}
78+
79+
80+
_bun_completions() {
81+
declare -A GLOBAL_OPTIONS;
82+
declare -A PACKAGE_OPTIONS;
83+
declare -A PM_OPTIONS;
84+
85+
local SUBCOMMANDS="dev bun create run install add remove upgrade completions discord help init pm x";
86+
87+
GLOBAL_OPTIONS[LONG_OPTIONS]="--use --cwd --bunfile --server-bunfile --config --disable-react-fast-refresh --disable-hmr --env-file --extension-order --jsx-factory --jsx-fragment --extension-order --jsx-factory --jsx-fragment --jsx-import-source --jsx-production --jsx-runtime --main-fields --no-summary --version --platform --public-dir --tsconfig-override --define --external --help --inject --loader --origin --port --dump-environment-variables --dump-limits --disable-bun-js";
88+
GLOBAL_OPTIONS[SHORT_OPTIONS]="-c -v -d -e -h -i -l -u -p";
89+
90+
PACKAGE_OPTIONS[ADD_OPTIONS_LONG]="--development --optional";
91+
PACKAGE_OPTIONS[ADD_OPTIONS_SHORT]="-d";
92+
PACKAGE_OPTIONS[REMOVE_OPTIONS_LONG]="";
93+
PACKAGE_OPTIONS[REMOVE_OPTIONS_SHORT]="";
94+
95+
PACKAGE_OPTIONS[SHARED_OPTIONS_LONG]="--config --yarn --production --frozen-lockfile --no-save --dry-run --force --cache-dir --no-cache --silent --verbose --global --cwd --backend --link-native-bins --help";
96+
PACKAGE_OPTIONS[SHARED_OPTIONS_SHORT]="-c -y -p -f -g";
97+
98+
PM_OPTIONS[LONG_OPTIONS]="--config --yarn --production --frozen-lockfile --no-save --dry-run --force --cache-dir --no-cache --silent --verbose --no-progress --no-summary --no-verify --ignore-scripts --global --cwd --backend --link-native-bins --help"
99+
PM_OPTIONS[SHORT_OPTIONS]="-c -y -p -f -g"
100+
101+
local cur_word="${COMP_WORDS[${COMP_CWORD}]}";
102+
local prev="${COMP_WORDS[$(( COMP_CWORD - 1 ))]}";
103+
104+
case "${prev}" in
105+
help|--help|-h|-v|--version) return;;
106+
-c|--config) _file_arguments "!*.toml" && return;;
107+
--bunfile) _file_arguments "!*.bun" && return;;
108+
--server-bunfile) _file_arguments "!*.server.bun" && return;;
109+
--backend)
110+
case "${COMP_WORDS[1]}" in
111+
a|add|remove|rm|install|i)
112+
COMPREPLY=( $(compgen -W "clonefile copyfile hardlink clonefile_each_dir symlink" -- "${cur_word}") );
113+
;;
114+
esac
115+
return ;;
116+
--cwd|--public-dir)
117+
COMPREPLY=( $(compgen -d -- "${cur_word}" ));
118+
return;;
119+
--jsx-runtime)
120+
COMPREPLY=( $(compgen -W "automatic classic" -- "${cur_word}") );
121+
return;;
122+
--target)
123+
COMPREPLY=( $(compgen -W "browser node bun" -- "${cur_word}") );
124+
return;;
125+
-l|--loader)
126+
[[ "${cur_word}" =~ (:) ]] && {
127+
local cut_colon_forward="${cur_word%%:*}"
128+
COMPREPLY=( $(compgen -W "${cut_colon_forward}:jsx ${cut_colon_forward}:js ${cut_colon_forward}:json ${cut_colon_forward}:tsx ${cut_colon_forward}:ts ${cut_colon_forward}:css" -- "${cut_colon_forward}:${cur_word##*:}") );
129+
}
130+
return;;
131+
esac
132+
133+
case "${COMP_WORDS[1]}" in
134+
help|completions|--help|-h|-v|--version) return;;
135+
add|a)
136+
_long_short_completion \
137+
"${PACKAGE_OPTIONS[ADD_OPTIONS_LONG]} ${PACKAGE_OPTIONS[ADD_OPTIONS_SHORT]} ${PACKAGE_OPTIONS[SHARED_OPTIONS_LONG]} ${PACKAGE_OPTIONS[SHARED_OPTIONS_SHORT]}" \
138+
"${PACKAGE_OPTIONS[ADD_OPTIONS_SHORT]} ${PACKAGE_OPTIONS[SHARED_OPTIONS_SHORT]}"
139+
return;;
140+
remove|rm|i|install|link|unlink)
141+
_long_short_completion \
142+
"${PACKAGE_OPTIONS[REMOVE_OPTIONS_LONG]} ${PACKAGE_OPTIONS[REMOVE_OPTIONS_SHORT]} ${PACKAGE_OPTIONS[SHARED_OPTIONS_LONG]} ${PACKAGE_OPTIONS[SHARED_OPTIONS_SHORT]}" \
143+
"${PACKAGE_OPTIONS[REMOVE_OPTIONS_SHORT]} ${PACKAGE_OPTIONS[SHARED_OPTIONS_SHORT]}";
144+
return;;
145+
create|c)
146+
COMPREPLY=( $(compgen -W "--force --no-install --help --no-git --verbose --no-package-json --open next react" -- "${cur_word}") );
147+
return;;
148+
upgrade)
149+
COMPREPLY=( $(compgen -W "--version --cwd --help -v -h") );
150+
return;;
151+
run)
152+
_file_arguments "!(*.@(js|ts|jsx|tsx|mjs|cjs)?($|))";
153+
COMPREPLY+=( $(compgen -W "--version --cwd --help --silent -v -h" -- "${cur_word}" ) );
154+
_read_scripts_in_package_json;
155+
return;;
156+
pm)
157+
_long_short_completion \
158+
"${PM_OPTIONS[LONG_OPTIONS]} ${PM_OPTIONS[SHORT_OPTIONS]}";
159+
COMPREPLY+=( $(compgen -W "bin ls cache hash hash-print hash-string" -- "${cur_word}") );
160+
return;;
161+
*)
162+
local replaced_script;
163+
_long_short_completion \
164+
"${GLOBAL_OPTIONS[*]}" \
165+
"${GLOBAL_OPTIONS[SHORT_OPTIONS]}"
166+
167+
_read_scripts_in_package_json;
168+
_subcommand_comp_reply "${cur_word}" "${SUBCOMMANDS}";
169+
170+
# determine if completion should be continued
171+
# when the current word is an empty string
172+
# the previous word is not part of the allowed completion
173+
# the previous word is not an argument to the last two option
174+
[[ -z "${cur_word}" ]] && {
175+
declare -A comp_reply_associative="( $(echo ${COMPREPLY[@]} | sed 's/[^ ]*/[&]=&/g') )";
176+
[[ -z "${comp_reply_associative[${prev}]}" ]] && {
177+
local re_prev_prev="(^| )${COMP_WORDS[(( COMP_CWORD - 2 ))]}($| )";
178+
local global_option_with_extra_args="--bunfile --server-bunfile --config --port --cwd --public-dir --jsx-runtime --platform --loader";
179+
[[
180+
( -n "${replaced_script}" && "${replaced_script}" == "${prev}" ) || \
181+
( "${global_option_with_extra_args}" =~ ${re_prev_prev} )
182+
]] && return;
183+
unset COMPREPLY;
184+
}
185+
}
186+
return;;
187+
esac
188+
189+
}
190+
191+
complete -F _bun_completions bun

0 commit comments

Comments
 (0)