Skip to content

feat: support the startup{,-core} directory#1558

Open
akinomyoga wants to merge 5 commits intoscop:mainfrom
akinomyoga:sepdir-4
Open

feat: support the startup{,-core} directory#1558
akinomyoga wants to merge 5 commits intoscop:mainfrom
akinomyoga:sepdir-4

Conversation

@akinomyoga
Copy link
Collaborator

For startup scripts discussed in the separation of directories #1329.

@akinomyoga akinomyoga force-pushed the sepdir-4 branch 2 times, most recently from ff2b028 to d3c4a5b Compare January 26, 2026 12:09
Copy link
Collaborator

@yedayak yedayak left a comment

Choose a reason for hiding this comment

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

Can you explain the reason for keeping track of what we loaded to allow for overriding? Is there a specific use-case you're thinking about?

README.md Outdated
Comment on lines 144 to 147
basis. If you want to do it system wide, you can install eagerly loaded
files in `compatdir` (see a couple of questions further down for more
info. To get the path of `compatdir` for the current system, the output of
`pkg-config bash-completion --variable compatdir` can be used) and install a
files in `<startupdir>`, whose value in the current system can be retrieved
by `pkg-config bash-completion --variable=startupdir`, and install a
completion for the commands to override our completion for in them.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe this should be split up? Installing system wide doesn't necessarily imply eagerly loaded.
Perhaps How can I override... and How to load completions eagerly on startup?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thank you for your review.

Yeah, that makes much more sense. It's been mixed, so I just updated locally, but I agree to separate the question.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I reorganized related questions and answers. fc6787f

# selected startup files. This allows users to override a startup
# file with another file with the same name placed in an earlier
# directory in "${startup_files[@]}".
local name=${startup_file##*/?([0-9][0-9][0-9]_)}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this processing needed?

Copy link
Collaborator Author

@akinomyoga akinomyoga Jan 26, 2026

Choose a reason for hiding this comment

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

I think this comment discusses the same thing as the following cover comment, so let me answer together in this sub-thread.

Can you explain the reason for keeping track of what we loaded to allow for overriding? Is there a specific use-case you're thinking about?

The original motivation that I thought of this mechanism is #1399. Although the OP of #1399 didn't explain or show a reference to any technical details that they tried to use to reason the PR, I found the UAPI spec and other materials myself. They explain the usage of /etc/<app> and /usr/etc/<app> (or /usr/lib/<app>, /usr/share/<app>, or whatever). I'm neutral on whether to adopt their specific use of the specific directories, /etc and /usr/etc, but I found the underlying idea useful.

Meanwhile, I've been thinking it is very annoying that some distribution packages put in /etc/bash_completion.d completion settings that affect the global behavior of completion, such as fzf and _python-argcomplete. For example, even if I don't intend to use fzf for Bash completion, when some application packages require the fzf package as a dependency in order to provide a menu for their UI, the fzf completion is unintentionally turned on through /etc/bash_completion.d/fzf installed by dependency. I believe the fzf package and the package for the fzf-bash integration should be separated ideally, but I guess the package maintainers of fzf consider fzf a tool for shell completion (rather than a general selector).

This also becomes an issue in a shared system, for which I do not have the administrator privilege. If there are any files in /etc/bash_completion.d/*, they are all forcibly loaded. Even if I want to disable any of them partially, there is no way to realize that. Actually, I ended up doing a very ugly hack of overriding the source builtin and the dot (.) builtin, but I would rather avoid such a hack if possible. Then, if those system-wide startup completion settings are moved to /usr/share/bash-completion/startup/<xxx>.bash, and if bash-completion provides a way to disable each setting by putting an empty file at e.g. ~/.local/share/bash-completion/startup/<xxx>.bash (or a way to override the behavior by putting a non-empty file), it will be useful.

Even if we forget about those arguments, when different versions of the same application install the same name of startup completion files at different paths, such as /usr/share/bash-completion/startup/xyz.bash, /usr/local/share/bash-completion/startup/xyz.bash, and ~/.local/share/bash-completion/startup/xyz.bash, I doubt we should source all of them. I think it would make more sense to pick up one of them, particularly the one installed by the current user.

Why is this processing needed?

If you mean by "this" the entire processing described by the code comment, I think I answered it above.

If you mean by "this" particularly the stripping of ?([0-9][0-9][0-9]_), it is to remove the prefix used to control the loading order. We already have 000_ prefixed to our 000_bash_completion_compat.bash, so other startup settings may also be prefixed by numbers. However, such a prefix number isn't controlled by the upstream project of the application, but the package distributions, or the system administrator may also change the number. Thus, when multiple startup completions of the same application are installed to different paths, they are not guaranteed to have the matching prefix numbers (if any). Then, the prefix numbers used to control the loading order should be ignored in identifying the initialization of the same application.

Copy link
Collaborator Author

@akinomyoga akinomyoga Jan 26, 2026

Choose a reason for hiding this comment

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

Maybe the name "eagerly loaded settings" is not a good description for startup files that can be overridden by users?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I realized I haven't considered users' directories in looking up the users' startup files. I added the support for it in commit a45e2ab. I'll squash this commit into the first commit later.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I also included the description of this behavior in fc6787f.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thank you for pointing out the existence of the configuration variable, BASH_COMPLETION_COMPAT_IGNORE! I haven't thought about using it to select valid startup files rather than buggy ones, (though it's not sufficient to process the UAPI-type overriding and selection from multiple versions of the same startup file).

@akinomyoga akinomyoga force-pushed the sepdir-4 branch 3 times, most recently from fc6787f to 59074b3 Compare January 30, 2026 04:08
Copy link
Collaborator Author

@akinomyoga akinomyoga left a comment

Choose a reason for hiding this comment

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

I probably need to add tests.

@akinomyoga akinomyoga force-pushed the sepdir-4 branch 2 times, most recently from 31b52ee to 011affa Compare January 31, 2026 09:49
@akinomyoga
Copy link
Collaborator Author

I probably need to add tests.

I added tests in 4990f89. I also adjusted the loading order of startup files from different directories in commit 011affa.

bash_completion Outdated
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this isn't needed anymore since we don't ship bash_completion.d in the repo itself anymore

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thank you. I've fixed this in push d89b679..5a1f187.

Comment on lines 6 to +8
# Empty, but here just to get the compat dir created with install
compatdir = $(sysconfdir)/bash_completion.d
compat_DATA = bash_completion.d/000_bash_completion_compat.bash
compat_DATA =
Copy link
Collaborator

Choose a reason for hiding this comment

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

We still need to create ${sysconfdir}/bash_completion.d

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do we? #1399 seemed to want us not to create anything in /etc. I thought the projects that want to put any file in /etc/bash-completion.d can create a directory themselves, but does it actually fail in a typical setup of autoconf? I thought it would automatically create a directory. Is there another reason that we need to create it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I thought the projects that want to put any file in /etc/bash-completion.d can create a directory themselves, but does it actually fail in a typical setup of autoconf? I thought it would automatically create a directory.

When creating a package, one would do make install into a clean directory. So I guess make install is rather required to work without any existing directory structures.

Copy link
Collaborator

@yedayak yedayak Feb 4, 2026

Choose a reason for hiding this comment

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

Yeah that's a good point, any other packages that install there will create the directory there themselves, especially since they can be installed even if bash-completion isn't.
My only worry is for users following guides that tell them to put the completions in /etc/bash-completion.d/. Maybe this calls for another README 🙃
I think creating the directory will be fine from the perspective of the UAPI concerns, since we're not dependent anymore on any files in that directory for a fully working system. Maybe someone from the original PR wants to chime in? @septatrix @bluca

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

My only worry is for users following guides that tell them to put the completions in /etc/bash-completion.d/. Maybe this calls for another README 🙃

I think I already removed that part with 6a78aa3. Is there still a place to modify?

Copy link
Collaborator

Choose a reason for hiding this comment

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

My only worry is for users following guides that tell them to put the completions in /etc/bash-completion.d/. Maybe this calls for another README 🙃

I think I already removed that part with 6a78aa3. Is there still a place to modify?

I mean guides outside of the repo, for example this stack overflow question: https://askubuntu.com/questions/68175/how-to-create-script-with-auto-complete, or the cobra13 docs. Maybe adding a bit more friction for doing the "wrong thing" does make sense though.

Copy link
Collaborator Author

@akinomyoga akinomyoga Feb 4, 2026

Choose a reason for hiding this comment

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

I see. It can sometimes take a long time to update the community's knowledge. Until recently, there have been many articles recommending the use of the old-style command substitutions `...` that were deprecateddiscouraged by the standard about 30 years ago.

# system startup files earlier.
_comp__init_startup_configs=(
"${selected_startup_files[@]}"
${_comp__init_startup_configs[@]+"${_comp__init_startup_configs[@]}"}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Side note: I see we have this pattern in other places, but I don't understand why it's needed, doesn't just doing

_comp__init_startup_configs=( "${selected_startup_files[@]}" ${_comp__init_startup_configs[@]} )

work?

Copy link
Collaborator Author

@akinomyoga akinomyoga Feb 4, 2026

Choose a reason for hiding this comment

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

Bash 4.2 has a bug that "${arr[@]}" fails with set -u for arr=().

Copy link
Owner

Choose a reason for hiding this comment

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

Just a random off-context comment, as I haven't been following this MR yet, ref #1479 (reply in thread): I think we should drop support for bash < 5.0 (or at least < 4.3) for the next release.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So they can finally be removed, but I believe it should be done in a separate PR for consistency (and for later research in case something happens). In the first place, the code doesn't pass the CI tests without the workaround in the current setup of the test environment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I added a clarification in 71ae643..6c1af0e.

I also considered adding the same comments to other cases, but I gave it up because there seem to be many, and I didn't feel that we needed to bother with what would soon be removed for the version requirement change. There have been 13 cases, and none of them had comments:

./bash_completion:975:    _comp_compgen -F "$_ifs" -U input -- ${_compgen_options[@]+"${_compgen_options[@]}"} -W '$input'
./bash_completion:1101:    local "$2" "$3" "$4" && _comp_upvars -a"${#words[@]}" "$2" ${words[@]+"${words[@]}"} \
./bash_completion:1379:    _comp_compgen -U toks set ${toks[@]+"${toks[@]}"}
./bash_completion:2657:    _comp_compgen_known_hosts ${options[@]+"${options[@]}"} -- "$cur"
./bash_completion:3413:    elif . "$compfile" "$cmd" ${source_args[@]+"${source_args[@]}"}; then
./completions-core/gdb.bash:32:                find ${path_array[@]+"${path_array[@]}"} . -name . -o \
./completions-core/ri.bash:23:            "$(ri ${classes[@]+"${classes[@]}"} 2>/dev/null | ruby -ane \
./completions-core/ri.bash:31:            "$(ruby -W0 "$ri_path" ${classes[@]+"${classes[@]}"} 2>/dev/null | ruby -ane \
./completions-core/strace.bash:60:                                '${syscalls[@]+"${!syscalls[@]}"} file process
./completions-core/update-rc.d.bash:20:        _comp_compgen -- -W '"${options[@]}" ${services[@]+"${services[@]}"}' \
./startup-core/000_bash_completion_compat.bash:338:        args=(-c "$REPLY" ${opt[@]+"${opt[@]}"})
./startup-core/000_bash_completion_compat.bash:362:        args=(-c "$REPLY" ${opt[@]+"${opt[@]}"})
./test/t/unit/test_unit_compgen.py:22:            '_comp__test_words() { local -a input=("${@:1:$#-1}"); _comp__test_compgen -c "${@:$#}" -- -W \'${input[@]+"${input[@]}"}\'; }',

akinomyoga and others added 5 commits February 5, 2026 15:42
* chore(pkg-config): expose the "startupdir" pkg-config variable

Co-authored-by: Yedaya Katsman <yedaya.ka@gmail.com>
This patch reorganizes the descriptions for installing/overriding
completion settings to solve multiple issues.

* First, the systemwide settings and eagerly loaded settings were
  conflated.  The systemwide settings are not necessarily eagerly
  loaded completions.
* The paths obtained by "pkg-config" usually point to the directory
  under `/usr/share`, which are the places for system packages
  provided by the distributions.  User startup files and systemwide
  local settings should not be placed under the tree `/usr/local` in
  typical distributions or with typical package managers.  The user
  startup files should be installed into the user's directory, and
  systemwide local settings should be installed in `/usr/local/share`.
* We also distinguish the new startup files from the traditional
  eagerly loaded files
@akinomyoga akinomyoga force-pushed the sepdir-4 branch 2 times, most recently from 71ae643 to 6c1af0e Compare February 5, 2026 07:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants