Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Absolute path tab completion on Windows



On Thu, Nov 7, 2024 at 1:25 PM Ram Rachum <ram@xxxxxxxxxx> wrote:
>
> I used Claude to extend this code to apply to all drive letters, code below.

Hm. Not entirely terrible code, but could be optimized.

> One problem with this code is that it only autocompletes the paths when they are an argument to a command, and not when they are the first thing that's typed in the shell, like you might do to `cd` into a folder without typing `cd`. If anyone knows how to fix that, let me know.

I've been testing (the original formulation) by pretending that /tmp/
is a drive mount, and the big drawback for AUTO_CD seems to be that it
offers command names as well as the directories under /tmp/.  That's
difficult to fix without breaking command completion.

> get_drive_letters() {
>     mount | grep -i '^[a-z]:' | cut -d':' -f1 | tr '[:upper:]' '[:lower:]' | sort -u
> }

Clever enough to create that function but then it didn't use it where
it would make sense.  In any case that pipeline is functional but
wasteful.

  ${${(M)${(fL)"$(mount)"}:#[a-z]:*}%%:*}

I left out the "sort -u" because (a) the order shouldn't matter and
(b) if "mount" isn't already returning each drive uniquely I think
something is wrong.

> # Store the original completion function
> functions -c -- _normal _normal@original

OK, interesting if Claude figured that out itself.

> # Create completion functions for each drive

This isn't necessary.  Just re-use _normal@original every time.  You
only need a new function if you're going to change the operation, and
"functions -c" changes nothing but the name.  I just threw the drive
letter in when creating the first copy to make the suffix part after
the @ more distinctive.

> _normal () {
>     for drive in $(mount | grep -i '^[a-z]:' | cut -d':' -f1 | tr '[:upper:]' '[:lower:]' | sort -u); do

      local drive
      for drive in ${${(M)${(fL)"$(mount)"}:#[a-z]:*}%%:*}; do

>         if compset -P "/${drive}/"
>         then
>             local opwd=$PWD ret
>             cd /${drive} || return 1
>             _normal@${drive}:drive "$@"

              _normal@original "$@"

>             ret=$?
>             cd $opwd
>             return ret
>         fi
>     done
>     _normal@original "$@"
> }

I think we can fix the autocd problem in two steps:
1. Don't do the whole compset+cd dance if we already know a directory
name under the drive name
2. If we pass that hurdle and are in command position with autocd,
jump straight to _cd

"compset -P" accepts a pattern, so we can remove the loop from the
foregoing by turning the list of drive names into a pattern, which
just means joining them with (j:|:).  That puts the name matched by
the pattern into $IPREFIX, so we don't need the $drive local.

That gives (harder for me to test with no windows environment, so may
need tweaking) --

_normal () {
  if [[ $PREFIX != /*/*/* ]] && compset -P
"/(${(j:|:)${(M)${(fL)"$(mount)"}:#[a-z]:*}%%:*})/"
  then
    local opwd=$PWD ret
    cd $IPREFIX || return 1
    if [[ -o autocd && $compstate[context] = command ]]
    then
      _cd "$@"
    else
      _normal@original "$@"
    fi
    ret=$?
    cd $opwd
    return ret
  else
    _normal@original "$@"
  fi
}




Messages sorted by: Reverse Date, Date, Thread, Author