bugGNU Astronomy Utilities - Bugs: bug #60618, Fixed directory string being...


You are not allowed to post comments on this tracker with your current authentication level.

bug #60618: Fixed directory string being removed on pressing TAB

Submitter:  Mohammad Akhlaghi <makhlaghi>
Submitted:  Mon 17 May 2021 01:25:06 AM UTC
Category:  TAB completion Severity:  3 - Normal
Item Group:  Output not reasonable Status:  Confirmed
Privacy:  Public Assigned to:  pedram
Open/Closed:  Open

Jump to the original submission

Thu 05 Aug 2021 10:37:32 PM UTC, comment #6: 

That is an interesting discovery ;-)!

Try the problematic scenario we have here, to see how it deals with it. Hopefully it will teack us some good lessons that we can then inplement in our script ;-).

Mohammad Akhlaghi <makhlaghi>
Group administrator
Thu 05 Aug 2021 07:06:53 PM UTC, comment #5: 

Look what I found straight from 'info'! Just type in: 'info bash program' and then use ']' and navigate to 'A programmable completion example'. Then you can find the actual bash completion program written for 'cd' itself!

Does it give you any ideas?

     # A completion function for the cd builtin
     # based on the cd completion function from the bash_completion package
         local IFS=$' \t\n'    # normalize IFS
         local cur _skipdot _cdpath
         local i j k

         # Tilde expansion, which also expands tilde to full pathname
         case "$2" in
         \~*)    eval cur="$2" ;;
         *)      cur=$2 ;;

         # no cdpath or absolute pathname -- straight directory completion
         if [[ -z "${CDPATH:-}" ]] || [[ "$cur" == @(./*|../*|/*) ]]; then
             # compgen prints paths one per line; could also use while loop
             COMPREPLY=( $(compgen -d -- "$cur") )
             IFS=$' \t\n'
         # CDPATH+directories in the current directory if not in CDPATH
             # preprocess CDPATH to convert null directory names to .
             for i in ${_cdpath//:/$'\n'}; do
                 if [[ $i -ef . ]]; then _skipdot=true; fi
                 for j in $( compgen -d -- "$i/$cur" ); do
                     COMPREPLY[k++]=${j#$i/}        # cut off directory
             $_skipdot || COMPREPLY+=( $(compgen -d -- "$cur") )
             IFS=$' \t\n'

         # variable names if appropriate shell option set and no completions
         if shopt -q cdable_vars && [[ ${#COMPREPLY[@]} -eq 0 ]]; then
             COMPREPLY=( $(compgen -v -- "$cur") )

         return 0

Pedram Ashofteh-Ardakani <pedram>
Group Member
Sun 27 Jun 2021 06:25:34 AM UTC, comment #4: 

My pleasure :)

Not yet really, but I will try to resume working on it ASAP.

Pedram Ashofteh-Ardakani <pedram>
Group Member
Fri 25 Jun 2021 07:34:19 PM UTC, comment #3: 

Thanks for the nice review Pedram, and I am happy you liked the corrections ;-).

Indeed, I agree that it is better to set IFS locally.

I didn't know about M-? in Bash! It was interesting, thanks for bringing it up.

Where you able to try the solution to put '$prev' (when it exists) before the 'ls' command input? Did it work?

Mohammad Akhlaghi <makhlaghi>
Group administrator
Fri 25 Jun 2021 02:35:33 PM UTC, comment #2: 

Oh, I got caught in the problems so much that I forgot to tell you the new autocomplete structure is pretty neat! I could see you have really put good effort into this :) Great job.

Pedram Ashofteh-Ardakani <pedram>
Group Member
Fri 25 Jun 2021 02:25:34 PM UTC, comment #1: 

Hi Mohammad. I have been looking into this bug for quite a while now and got confused. The crazy thing is that as you said, one  can get only the file's 'basename' suggestion by default, such as using 'M-?' on your keyboard! Just try this:

# Buggy response, including the 'dirname':
$ astfits subdir/out-[TAB]
subdir/out-123.fits   subdir/out-456.fits

# Desired response, showing only the 'basename':
$ astfits subdir/out-[M-?]
out-123.fits   out-456.fits

As you know, 'M' stands for the 'alt' key on keyboard. I tried to get a grasp on how this command works, unfortunately to no avail. However, I stumbled upon a few links and commands that might be useful:

  • First, thie 'M-?' command is coming from option 'possible-completions' of the 'bind' application. Give it a try:

$ bind -P | grep possible-completions


  • Second, the bash-completion repository on github hosts many useful scripts which might be already installed on your system under the name 'bash-completion', try:

$ pacman -Q bash-completion

  • Third, these completion scripts use arcane functions starting with underscore '_', namely '_init_completion'. Out of curiosity, I found out one can view the content of these functions using the 'type' command. Give it a try:

$ type _init_completion

As far as I understood, bash-completion overwrites the '$current' word being completed as soon as finding a match in the COMPREPLY array. This is somewhat similar to our problem with long options containing the equal sign '='. We used IFS='=' to let 'complete' distinguish option name and option value before and after the equal sign.

But here, as you have already considered, we should check if user is passing in a directory name. But maybe we could do this with checking if the $current string includes a '/'. If so, we should somehow split this part. This way, 'complete' will let that part alone, and will not replace the 'already' accepted input. Hopefully, this will only replace the 'basename' of each given file or directory.

This is what I mean, if you could echo the $current and $prev variables for debugging:

$ astfits subdir/[TAB]
current: ''
prev: 'subdir/'

So, $prev is a directory name, we should add $prev as a prefix to the directory we're running 'ls' on. Like:

$ ls -d "$DIR_PREFIX/"*

Well, this is as far as I could get today. It would be nice if you could share some views and suggestions at your convenience :)

BTW, changing 'IFS' in the entire shell can have annoying side effects. To this end, some scripts just declare IFS inside bash functions only locally with a short lifespan.

Pedram Ashofteh-Ardakani <pedram>
Group Member
Mon 17 May 2021 01:25:06 AM UTC, original submission:  

When there are multiple matching files in a sub-directory, the default behavior of Bash's TAB completion is to only print the matching file names (not directories) to help the user visually identify the character to type.

However, in the current implementation of Gnuastro's TAB completion, this doesn't happen! In the scenario below (assuming you have an 'image.fits' in an empty directory), the fixed directory name 'subdir' will be deleted upon pressing TAB:

$ ls
$ mkdir subdir
$ mv image.fits subdir/ab-123.fits
$ cp subdir/ab-123.fits subdir/ab-456.fits
$ astcrop subdir/ab-[TAB]

Therefore, as a fast temporary work-around I have adopted an ugly (bug working!) solution in Commit c091578e2.

Pedram, can you have a look into this? I don't have time right now, and this is an important issue.

Its also a good chance to get familiar with the new TAB completion structure ;-).

Mohammad Akhlaghi <makhlaghi>
Group administrator


(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

No files currently attached


Depends on the following items: None found

Items that depend on this one: None found


Carbon-Copy List
  • -email is unavailable- added by pedram (Posted a comment)
  • -email is unavailable- added by makhlaghi (Submitted the item)

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.


    No changes have been made to this item

    Back to the top

    Powered by Savane 3.13-7c56.
    Corresponding source code