Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(make): fix stripped directory names with bind 'set show-all-if-ambiguous on' #546

Merged
merged 4 commits into from Jan 23, 2023

Conversation

akinomyoga
Copy link
Collaborator

Resolve #544

  • Commit 53060e3: support @pytest.mark.bashcomp(required_cmd=True) to skip all the tests in the class.
  • Commit eb12832: add failing test cases to illustrate the problems
  • Commit 0ddae4c: do not strip directory names when COMP_TYPE=37. This happens when the user presses TAB under the readline setting bind 'set show-all-if-ambiguous on' is set.
  • Commit d5181c5: complete subdirectories as far as the path is unique

Test suite problem on COMP_TYPE

The test test_github_issue_544_4 (test_make.py) currently fails because of the design of the test suite. The test suite extracts the generated completions by changing the readline settings as

@@ -22,20 +22,20 @@
 set menu-complete-display-prefix off
 set meta-flag on
 set output-meta on
-set page-completions on
+set page-completions off
 set prefer-visible-bell on
 set print-completions-horizontally off
 set revert-all-at-newline off
-set show-all-if-ambiguous off
+set show-all-if-ambiguous on
 set show-all-if-unmodified off
 set show-mode-in-prompt off
 set skip-completed-text off
 set visible-stats off
-set bell-style audible
+set bell-style none
 set comment-begin #
-set completion-display-width -1
+set completion-display-width 0
 set completion-prefix-display-length 0
-set completion-query-items 100
+set completion-query-items 0
 set editing-mode emacs
 set emacs-mode-string @
 set history-size 100000

Under these settings, the completion functions are called with COMP_TYPE=33 (!, show list), which is different from the usual COMP_TYPE=9 (TAB) or COMP_TYPE=37 (%, menu-complete). The completion for make changes the behavior depending on COMP_TYPE so that it doesn't produce the expected results in the test suite. Note that make completion is the only one that changes its behavior depending on the value of COMP_TYPE among the completions in bash-completion.

@scop Do you have any thoughts on how we should solve this problem?

  • Option 1: Use another approach to get the generated completions if any? I'm not sure if there is any.
  • Option 2: Make the completion results independent of COMP_TYPE?
  • Option 3: Add a special code in completions/make that detects the test suite and changes the behavior only in the test suite?
  • Option X: any other idea?

Possibility of using awk

sed has been used to extract the target names by make. It is difficult to use sed to test whether the filenames in subdirectories are unique and to generate the full path only when it is unambiguous. In commit d5181c5, sed scripts has been changed so as to always produce the full paths, and instead, the generated results are afterward filtered using Bash code. But, maybe another approach is to rewrite everything using awk. It should be more efficient than processing in Bash.

test/t/conftest.py Outdated Show resolved Hide resolved
test/t/test_make.py Outdated Show resolved Hide resolved
test/t/test_make.py Outdated Show resolved Hide resolved
@scop
Copy link
Owner

scop commented Jun 30, 2021

Added a few rather superficial comments. The make completion continues to terrify me -- the code is quite complex, and my make-fu isn't really up to speed to anywhere near always tell how the completion should behave. So I'm not sure how much I can be of assistance here. Let's just keep adding test cases for all changes we make, like you've done here.

* Option 2: Make the completion results independent of `COMP_TYPE`?

This sounds good to me in principle, but I can't tell offhand what it would mean to user experience.

But, maybe another approach is to rewrite everything using awk. It should be more efficient than processing in Bash.

Do we think that Makefiles can get sufficiently large to make efficiency here a issue we need to care much about? To me, code understandability and portability are more important unless there is an actual performance issue we do want to tackle, and in general bash wins over sed or awk on the understandabilty/portability front. But things can get hairy and overly verbose with bash, too, so this is something to look into case by case.

@akinomyoga
Copy link
Collaborator Author

* Option 2: Make the completion results independent of `COMP_TYPE`?

This sounds good to me in principle, but I can't tell offhand what it would mean to user experience.

Removing the dependence on COMP_TYPE means that we effectively revert the feature introduced by 39f00f9. This feature strips the directory name in the list of completions displayed in the terminal. For example, when we try to complete subdir/x and there are matching make targets subdir/x1, subdir/x2, and subdir/x3, the displayed list becomes x1 x2 x3 with this feature instead of subdir/x1 subdir/x2 subdir/x3.

But, maybe another approach is to rewrite everything using awk. It should be more efficient than processing in Bash.

Do we think that Makefiles can get sufficiently large to make efficiency here a issue we need to care much about?

I think basically a handwritten Makefile shouldn't be so large (unless the user uses fancy GNU make macros to automatically generate a bunch of rules). However, the result of Makefile generators such as autotools and cmake can be extremely large.

To me, code understandability and portability are more important unless there is an actual performance issue we do want to tackle, and in general bash wins over sed or awk on the understandabilty/portability front.

For understandability, I believe awk is better than the current sed or a Bash implementation. For the portability, awk may be harder than sed but is still manageable if we carefully write the awk script. I think the most challenging implementations for awk/sed among contemporary systems are Solaris awk and Solaris sed. At least, Solaris awk lacks many important features of POSIX awk. I actually have no experience with Solaris sed so am not even sure whether the POSIX sed scripts work as expected.

But things can get hairy and overly verbose with bash, too, so this is something to look into case by case.

Maybe I should make a sample implementation by awk and we compare it with the current implementation?

@scop
Copy link
Owner

scop commented Jun 30, 2021

Maybe I should make a sample implementation by awk and we compare it with the current implementation?

Sure, if you're interested.

While at it, no matter the language, I think it would be cool if we could extract the whole implementation to a separately invoked static script in helpers/ instead of generating it from bash code on the fly. That'd help with editor syntax highlighting and formatting, avoid some potentially hairy escaping issues, and likely make it easier to test.

@akinomyoga
Copy link
Collaborator Author

I'm going to update this PR after another PR #548, which the new commits for this PR would depend on, is processed.

  • Option 2: Make the completion results independent of COMP_TYPE? (comment by @akinomyoga)

This sounds good to me in principle, but I can't tell offhand what it would mean to user experience. (comment by @scop)

Removing the dependence on COMP_TYPE means that we effectively revert the feature introduced by 39f00f9. (comment by @akinomyoga)

If you are fine with removing the COMP_TYPE-dependent feature 39f00f9, I can remove it. What do you think?

Maybe I should make a sample implementation by awk and we compare it with the current implementation?

Sure, if you're interested.

I would do it in another PR if I have time after this PR is settled.

@akinomyoga akinomyoga changed the title fix(make): fix stripped directory names with bind 'set show-all-if-ambiguous on' [WIP waiting #548] fix(make): fix stripped directory names with bind 'set show-all-if-ambiguous on' Jul 5, 2021
@akinomyoga akinomyoga changed the title [WIP waiting #548] fix(make): fix stripped directory names with bind 'set show-all-if-ambiguous on' [WIP waiting for #548] fix(make): fix stripped directory names with bind 'set show-all-if-ambiguous on' Jul 7, 2021
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch 3 times, most recently from 2d0f691 to 49ba02e Compare August 24, 2021 06:20
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from 49ba02e to 89cfbaf Compare September 3, 2021 02:46
@akinomyoga
Copy link
Collaborator Author

akinomyoga commented Sep 7, 2021

Under these settings, the completion functions are called with COMP_TYPE=33 (!, show list), which is different from the usual COMP_TYPE=9 (TAB) or COMP_TYPE=37 (%, menu-complete). The completion for make changes the behavior depending on COMP_TYPE so that it doesn't produce the expected results in the test suite. Note that make completion is the only one that changes its behavior depending on the value of COMP_TYPE among the completions in bash-completion.

@scop Do you have any thoughts on how we should solve this problem?

  • Option 1: Use another approach to get the generated completions if any? I'm not sure if there is any.
  • Option 2: Make the completion results independent of COMP_TYPE?
  • Option 3: Add a special code in completions/make that detects the test suite and changes the behavior only in the test suite?
  • Option X: any other idea?
* Option 2: Make the completion results independent of `COMP_TYPE`?

This sounds good to me in principle, but I can't tell offhand what it would mean to user experience.

I still hesitate to choose the solution for this issue. In the current test framework, the completions are extracted with COMP_TYPE=33 (display candidates) which is different from the usual COMP_TYPE=9 (tab-completion) and COMP_TYPE=37 (menu-completion). Considering the reason that Bash provides the variable COMP_TYPE, I feel it is a too strong restriction to require not using COMP_TYPE in completion functions.

Isn't there any way to update the test framework so that it can handle different cases of COMP_TYPE?

[Edit: Sorry there were many typos of COMP_TYPE being wrongly COMP_REPLY. I fixed them. ]

@scop
Copy link
Owner

scop commented Sep 8, 2021

This is an area in which I have little experience, so unsure how much I can be of assistance. A couple of (likely stupid) comments/questions though:

In the current test framework, the completions are extracted with COMP_TYPE=33

Not sure I follow -- the only git grep hit for that I find is the one in the current make completion that test it's not equal to 9...?

Isn't there any way to update the test framework so that it can handle different cases of COMP_REPLY?

Doesn't strike me as impossible off the bat, but nothing concrete to offer right now either.

@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from 89cfbaf to 5bc3823 Compare December 26, 2021 01:58
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from 5bc3823 to edc0bbd Compare January 6, 2022 06:51
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from edc0bbd to 5b23b5f Compare February 24, 2022 02:38
@akinomyoga
Copy link
Collaborator Author

We might also need to exclude the case COMP_TYPE == 42 (cf spf13/cobra#1509)

@akinomyoga akinomyoga changed the title [WIP waiting for #548] fix(make): fix stripped directory names with bind 'set show-all-if-ambiguous on' fix(make): fix stripped directory names with bind 'set show-all-if-ambiguous on' Apr 7, 2022
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from 5b23b5f to 9f03119 Compare August 28, 2022 02:06
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from 9f03119 to e204c78 Compare December 17, 2022 17:57
akinomyoga added a commit to akinomyoga/bash-completion that referenced this pull request Dec 17, 2022
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from 85ffc5b to d21ebba Compare December 17, 2022 18:08
@akinomyoga akinomyoga marked this pull request as ready for review December 17, 2022 18:09
@akinomyoga
Copy link
Collaborator Author

The issue is reported again in #858. I think there is no reason to block the fixes just for the test suite problem. Here, I have rebased it on top of the latest master and, in commit d21ebba, deactivated the display-only mode (39f00f9) causing the test-suite issue. If we would like to still use the "display-only mode", we can discuss how to make it work with the test framework in a separate issue, but I'm currently not sure if the "display-only mode" is worth re-enabling.

scop
scop previously requested changes Dec 18, 2022
completions/make Outdated Show resolved Hide resolved
completions/make Outdated Show resolved Hide resolved
akinomyoga added a commit to akinomyoga/bash-completion that referenced this pull request Dec 19, 2022
In the display-only mode where COMP_TYPE=9, 37, or 42, only a part of
the completion is stored in COMPREPLY for displaying purposes.  For
example, "xyz" is stored in COMPREPLY when "abc/xyz" is the candidate
and "abc/" is already inserted.

However, the test framework extracts generated completions using
COMP_TYPE=37 by setting "set show-all-if-ambiguous off", which would
be broken by the display-only mode.  There is no simple way to make it
work with the test framework, and the display-only mode does not seem
to be essential.  For the time being, we deactivate the display-only
mode.  See also discussions in the following links:

scop#544
scop#546
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from d21ebba to 5df3eef Compare December 19, 2022 12:28
akinomyoga added a commit to akinomyoga/bash-completion that referenced this pull request Dec 19, 2022
In the display-only mode where COMP_TYPE=9, 37, or 42, only a part of
the completion is stored in COMPREPLY for displaying purposes.  For
example, "xyz" is stored in COMPREPLY when "abc/xyz" is the candidate
and "abc/" is already inserted.

However, the test framework extracts generated completions using
COMP_TYPE=37 by setting "set show-all-if-ambiguous off", which would
be broken by the display-only mode.  There is no simple way to make it
work with the test framework, and the display-only mode does not seem
to be essential.  For the time being, we deactivate the display-only
mode.  See also discussions in the following links:

scop#544
scop#546
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from 5df3eef to 3d8811b Compare December 19, 2022 12:31
@ncfavier
Copy link

Can confirm this works fine. Not sure why we need all that code though, bash should be able to do the right thing with paths (complete -o filenames?)

@akinomyoga
Copy link
Collaborator Author

Can confirm this works fine.

Thank you for checking!

Not sure why we need all that code though, bash should be able to do the right thing with paths (complete -o filenames?)

I guess you mean complete -f (because -o filenames specifies that the completions generated by other means should be post-processed for quoting, suffixing with /, etc.)?

The reason for not using Bash's filename generation is that we would like to generate the target names defined in Makefile (or GNUmakefile, etc.). The target names are not necessarily filenames, and filenames are not necessarily targets, and Bash doesn't know which are the make targets and which are not. This is the reason that the generation is implemented in the script.

@ncfavier
Copy link

I am talking about processing, not generation. I guess what we're doing isn't even specific to paths. complete -W 'test/abc test/xyz' foo already seems to do the right thing, why do we need to reinvent anything?

@akinomyoga
Copy link
Collaborator Author

akinomyoga commented Dec 19, 2022

OK, I see. Thank you for your clarification!

What we are doing here is not equivalent to compgen -W 'test/abc test/xyz' -o filenames. We reduce the list test/abc test/xyz to test/, which is not available by -o filenames. This is the behavior in the current master, though I'm not sure for the background of this behavior. This PR partially suppresses this reduction only in the unambiguous cases as requested in #544. If there is anything built in Bash that can be used to implement this conditional reduction in a simple way, I'm not reluctant to switch to it. Do you have any idea?

P.S.

though I'm not sure for the background of this behavior.

It seems the reduction is introduced in commit b28d710. This seems to predate the time we moved to GitHub, so I don't know where to find the corresponding discussion.

@ncfavier
Copy link

ncfavier commented Dec 19, 2022

If there is anything built in Bash that can be used to implement this conditional reduction in a simple way, I'm not reluctant to switch to it.

I mean, leaving aside -o filenames, if I just run complete -W 'test/abc test/xyz' foo then foo <Tab> completes to foo test/, and if I remove test/abc then it completes to test/xyz. Why do we need to do anything?

In other words this "reduction" behaviour you're talking about is just... how completion works, why would we need to reimplement it ourselves for make?

@akinomyoga
Copy link
Collaborator Author

akinomyoga commented Dec 19, 2022

Ah, I see what you mean now. I have been considering the case where there are multiple directories and multiple files therein and we do not want to list the entire file tree by show-all-if-ambiguous or by two consecutive TABs. For the normal completion with complete -f, we just obtain the list of filenames in the current directory or in the subdirectory already input, which the current implementation in the master and also this PR mimics.

But maybe the behavior you suggest makes sense.

@ncfavier
Copy link

Ah, I see what you mean, we're reducing the list of options shown. That makes sense.

@akinomyoga
Copy link
Collaborator Author

It's hard to decide for me. This is related to the background that introduced this line ten years ago. This is just my guess, but people might have wanted to mimic the behavior of Bash for normal paths.

akinomyoga added a commit to akinomyoga/bash-completion that referenced this pull request Dec 22, 2022
In the display-only mode where COMP_TYPE=9, 37, or 42, only a part of
the completion is stored in COMPREPLY for displaying purposes.  For
example, "xyz" is stored in COMPREPLY when "abc/xyz" is the candidate
and "abc/" is already inserted.

However, the test framework extracts generated completions using
COMP_TYPE=37 by setting "set show-all-if-ambiguous off", which would
be broken by the display-only mode.  There is no simple way to make it
work with the test framework, and the display-only mode does not seem
to be essential.  For the time being, we deactivate the display-only
mode.  See also discussions in the following links:

scop#544
scop#546
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from e445428 to a16a6b5 Compare December 22, 2022 08:18
Copy link

@ncfavier ncfavier left a comment

Choose a reason for hiding this comment

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

Let's not delay this any longer

@scop
Copy link
Owner

scop commented Jan 9, 2023

As noted, the make completion is already too complex for my taste and this makes it even more complex. Then again, we have the test cases here which appear to make sense as well as good amount of commentary, and no alternative implementations for taking care of the issue, so leaving it up to @akinomyoga to merge if he's comfortable with what we have here.

akinomyoga added a commit to akinomyoga/bash-completion that referenced this pull request Jan 10, 2023
In the display-only mode where COMP_TYPE=9, 37, or 42, only a part of
the completion is stored in COMPREPLY for displaying purposes.  For
example, "xyz" is stored in COMPREPLY when "abc/xyz" is the candidate
and "abc/" is already inserted.

However, the test framework extracts generated completions using
COMP_TYPE=37 by setting "set show-all-if-ambiguous off", which would
be broken by the display-only mode.  There is no simple way to make it
work with the test framework, and the display-only mode does not seem
to be essential.  For the time being, we deactivate the display-only
mode.  See also discussions in the following links:

scop#544
scop#546
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from a16a6b5 to 36fb9bb Compare January 10, 2023 05:21
When many targets in subdirectories are defined in Makefile, we
typically want to list the files or subdirectories in the current
directory.  However, when the file in the subdirectory is unique, we
may generate the full path.  See also the discussion on GitHub:

scop#544
scop#546 (comment)
In the display-only mode where COMP_TYPE=9, 37, or 42, only a part of
the completion is stored in COMPREPLY for displaying purposes.  For
example, "xyz" is stored in COMPREPLY when "abc/xyz" is the candidate
and "abc/" is already inserted.

However, the test framework extracts generated completions using
COMP_TYPE=37 by setting "set show-all-if-ambiguous off", which would
be broken by the display-only mode.  There is no simple way to make it
work with the test framework, and the display-only mode does not seem
to be essential.  For the time being, we deactivate the display-only
mode.  See also discussions in the following links:

scop#544
scop#546
@akinomyoga akinomyoga force-pushed the fix-make-for-show-all-if-ambiguous branch from 36fb9bb to 5eb1042 Compare January 10, 2023 05:39
@akinomyoga
Copy link
Collaborator Author

@ncfavier @scop Thank you for your comments. After another look, I decided to separate the corresponding code in a new function (1ea3326 is the updated patch). I think I will merge this version after waiting for a week.

@akinomyoga akinomyoga merged commit 5927d57 into scop:master Jan 23, 2023
@akinomyoga akinomyoga deleted the fix-make-for-show-all-if-ambiguous branch January 23, 2023 23:46
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.

Make target completion doesn't work with subdirectories
3 participants