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

Re: Absolute path tab completion on Windows





On Fri, Nov 8, 2024 at 2:18 AM Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:

> 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.

On my system this results in `c c c c g j l m p` so I'll keep the implementation with `sort -u`.
 

> # 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
}

This works for /c/ but not for my other drives. I changed it around and now it works great:

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

# Store the original completion function
functions -c -- _normal _normal@original
   
# This autocompletes stuff like `/c/Windows`
_normal () {
  if [[ $PREFIX != /*/*/* ]] && compset -P "/([$(get_drive_letters | tr -d '\n' | tr -d ' ')])/"
  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