zsh-workers
 help / color / mirror / code / Atom feed
* Absolute path tab completion on Windows
@ 2024-11-04 21:06 Ram Rachum
  2024-11-05  3:15 ` Bart Schaefer
  0 siblings, 1 reply; 16+ messages in thread
From: Ram Rachum @ 2024-11-04 21:06 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 545 bytes --]

Hi,

I use zsh on Linux, and I recently started using it on Windows as well,
following this guide:
https://dev.to/pavlosisaris/windows-command-line-revolution-unleash-zsh-and-oh-my-zsh-a-simple-guide-for-developers-271o

It does work, but one issue is that there's no tab completion of absolute
paths.

For example, if I type /c/Wind and press tab it does not complete to
/c/Windows. However, if the current working directory is /c/ and I type
Wind and press tab, it does complete to Windows.

Is this a bug?


Thanks for your help,
Ram Rachum.

[-- Attachment #2: Type: text/html, Size: 742 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-04 21:06 Absolute path tab completion on Windows Ram Rachum
@ 2024-11-05  3:15 ` Bart Schaefer
  2024-11-05 13:16   ` Ram Rachum
  0 siblings, 1 reply; 16+ messages in thread
From: Bart Schaefer @ 2024-11-05  3:15 UTC (permalink / raw)
  To: Ram Rachum; +Cc: zsh-workers

On Mon, Nov 4, 2024 at 1:06 PM Ram Rachum <ram@rachum.com> wrote:
>
> For example, if I type /c/Wind and press tab it does not complete to /c/Windows.

That's because /c is not a real directory, it's a representation of
the C: drive mount point.  I'm not sure how the msys2 build of zsh was
done, but if it's based on cygwin, the directory search library is not
providing a way to enumerate files at the top level of a drive mount.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-05  3:15 ` Bart Schaefer
@ 2024-11-05 13:16   ` Ram Rachum
  2024-11-05 17:00     ` Bart Schaefer
  2024-11-05 20:21     ` Mikael Magnusson
  0 siblings, 2 replies; 16+ messages in thread
From: Ram Rachum @ 2024-11-05 13:16 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 684 bytes --]

I see. Then what would need to be changed in order to enable this
functionality? And in which project would it need to be changed?

On Tue, Nov 5, 2024 at 5:15 AM Bart Schaefer <schaefer@brasslantern.com>
wrote:

> On Mon, Nov 4, 2024 at 1:06 PM Ram Rachum <ram@rachum.com> wrote:
> >
> > For example, if I type /c/Wind and press tab it does not complete to
> /c/Windows.
>
> That's because /c is not a real directory, it's a representation of
> the C: drive mount point.  I'm not sure how the msys2 build of zsh was
> done, but if it's based on cygwin, the directory search library is not
> providing a way to enumerate files at the top level of a drive mount.
>

[-- Attachment #2: Type: text/html, Size: 1055 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-05 13:16   ` Ram Rachum
@ 2024-11-05 17:00     ` Bart Schaefer
  2024-11-05 17:01       ` Ram Rachum
  2024-11-05 20:21     ` Mikael Magnusson
  1 sibling, 1 reply; 16+ messages in thread
From: Bart Schaefer @ 2024-11-05 17:00 UTC (permalink / raw)
  To: Ram Rachum; +Cc: zsh-workers

On Tue, Nov 5, 2024 at 5:16 AM Ram Rachum <ram@rachum.com> wrote:
>
> I see. Then what would need to be changed in order to enable this functionality? And in which project would it need to be changed?

I would start by asking the msys project.  There's not a lot of active
work on cygwin on our side, but we'd be willing to fold in any
changes.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-05 17:00     ` Bart Schaefer
@ 2024-11-05 17:01       ` Ram Rachum
  0 siblings, 0 replies; 16+ messages in thread
From: Ram Rachum @ 2024-11-05 17:01 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 473 bytes --]

I see, thank you.

On Tue, Nov 5, 2024, 19:00 Bart Schaefer <schaefer@brasslantern.com> wrote:

> On Tue, Nov 5, 2024 at 5:16 AM Ram Rachum <ram@rachum.com> wrote:
> >
> > I see. Then what would need to be changed in order to enable this
> functionality? And in which project would it need to be changed?
>
> I would start by asking the msys project.  There's not a lot of active
> work on cygwin on our side, but we'd be willing to fold in any
> changes.
>

[-- Attachment #2: Type: text/html, Size: 837 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-05 13:16   ` Ram Rachum
  2024-11-05 17:00     ` Bart Schaefer
@ 2024-11-05 20:21     ` Mikael Magnusson
  2024-11-05 22:45       ` Mark J. Reed
  2024-11-06 11:01       ` Ram Rachum
  1 sibling, 2 replies; 16+ messages in thread
From: Mikael Magnusson @ 2024-11-05 20:21 UTC (permalink / raw)
  To: Ram Rachum; +Cc: zsh workers

please don't top post
On Tue, Nov 5, 2024 at 2:17 PM Ram Rachum <ram@rachum.com> wrote:
> On Tue, Nov 5, 2024 at 5:15 AM Bart Schaefer <schaefer@brasslantern.com> wrote:
>>
>> On Mon, Nov 4, 2024 at 1:06 PM Ram Rachum <ram@rachum.com> wrote:
>> >
>> > For example, if I type /c/Wind and press tab it does not complete to /c/Windows.
>>
>> That's because /c is not a real directory, it's a representation of
>> the C: drive mount point.  I'm not sure how the msys2 build of zsh was
>> done, but if it's based on cygwin, the directory search library is not
>> providing a way to enumerate files at the top level of a drive mount.
>
> I see. Then what would need to be changed in order to enable this functionality? And in which project would it need to be changed?

Something you can try is make a directory anywhere, i use ~/.cdpath,
and symlink everything in /c/* that you want to access easily, and set
cdpath=( ~/.cdpath ) in your startup files, then you should be able to
just cd Wind<tab> from anywhere. (If you can make symlinks in your
environment, a quick search suggests maybe).

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-05 20:21     ` Mikael Magnusson
@ 2024-11-05 22:45       ` Mark J. Reed
  2024-11-06 11:01       ` Ram Rachum
  1 sibling, 0 replies; 16+ messages in thread
From: Mark J. Reed @ 2024-11-05 22:45 UTC (permalink / raw)
  To: Mikael Magnusson; +Cc: Ram Rachum, zsh workers

[-- Attachment #1: Type: text/plain, Size: 1582 bytes --]

You can make symlinks under msys on Windows but it requires some setup. You
need to either enable developer mode at the OS level or be running as an
administrator, and you have to set the environment variable *MSYS* to the
value *winsymlinks:nativestrict.*

On Tue, Nov 5, 2024 at 3:22 PM Mikael Magnusson <mikachu@gmail.com> wrote:

> please don't top post
> On Tue, Nov 5, 2024 at 2:17 PM Ram Rachum <ram@rachum.com> wrote:
> > On Tue, Nov 5, 2024 at 5:15 AM Bart Schaefer <schaefer@brasslantern.com>
> wrote:
> >>
> >> On Mon, Nov 4, 2024 at 1:06 PM Ram Rachum <ram@rachum.com> wrote:
> >> >
> >> > For example, if I type /c/Wind and press tab it does not complete to
> /c/Windows.
> >>
> >> That's because /c is not a real directory, it's a representation of
> >> the C: drive mount point.  I'm not sure how the msys2 build of zsh was
> >> done, but if it's based on cygwin, the directory search library is not
> >> providing a way to enumerate files at the top level of a drive mount.
> >
> > I see. Then what would need to be changed in order to enable this
> functionality? And in which project would it need to be changed?
>
> Something you can try is make a directory anywhere, i use ~/.cdpath,
> and symlink everything in /c/* that you want to access easily, and set
> cdpath=( ~/.cdpath ) in your startup files, then you should be able to
> just cd Wind<tab> from anywhere. (If you can make symlinks in your
> environment, a quick search suggests maybe).
>
> --
> Mikael Magnusson
>
>

-- 
Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 2430 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-05 20:21     ` Mikael Magnusson
  2024-11-05 22:45       ` Mark J. Reed
@ 2024-11-06 11:01       ` Ram Rachum
  2024-11-07 19:49         ` Bart Schaefer
  1 sibling, 1 reply; 16+ messages in thread
From: Ram Rachum @ 2024-11-06 11:01 UTC (permalink / raw)
  To: Mikael Magnusson; +Cc: zsh workers

[-- Attachment #1: Type: text/plain, Size: 1259 bytes --]

On Tue, Nov 5, 2024 at 10:22 PM Mikael Magnusson <mikachu@gmail.com> wrote:

> please don't top post
> On Tue, Nov 5, 2024 at 2:17 PM Ram Rachum <ram@rachum.com> wrote:
> > On Tue, Nov 5, 2024 at 5:15 AM Bart Schaefer <schaefer@brasslantern.com>
> wrote:
> >>
> >> On Mon, Nov 4, 2024 at 1:06 PM Ram Rachum <ram@rachum.com> wrote:
> >> >
> >> > For example, if I type /c/Wind and press tab it does not complete to
> /c/Windows.
> >>
> >> That's because /c is not a real directory, it's a representation of
> >> the C: drive mount point.  I'm not sure how the msys2 build of zsh was
> >> done, but if it's based on cygwin, the directory search library is not
> >> providing a way to enumerate files at the top level of a drive mount.
> >
> > I see. Then what would need to be changed in order to enable this
> functionality? And in which project would it need to be changed?
>
> Something you can try is make a directory anywhere, i use ~/.cdpath,
> and symlink everything in /c/* that you want to access easily, and set
> cdpath=( ~/.cdpath ) in your startup files, then you should be able to
> just cd Wind<tab> from anywhere. (If you can make symlinks in your
> environment, a quick search suggests maybe).
>

Thank you.

[-- Attachment #2: Type: text/html, Size: 1891 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-06 11:01       ` Ram Rachum
@ 2024-11-07 19:49         ` Bart Schaefer
  2024-11-07 21:24           ` Ram Rachum
  0 siblings, 1 reply; 16+ messages in thread
From: Bart Schaefer @ 2024-11-07 19:49 UTC (permalink / raw)
  To: Ram Rachum; +Cc: zsh workers

Here's a .zshrc-level workaround to try:

functions -c -- _normal _normal@c:drive
_normal () {
  if compset -P /c/
  then
    local opwd=$PWD ret
    cd /c || return 1
    _normal@c:drive "$@"
    ret=$?
    cd $opwd
    return ret
  else
    _normal@c:drive "$@"
  fi
}


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-07 19:49         ` Bart Schaefer
@ 2024-11-07 21:24           ` Ram Rachum
  2024-11-08  0:18             ` Bart Schaefer
  0 siblings, 1 reply; 16+ messages in thread
From: Ram Rachum @ 2024-11-07 21:24 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh workers

[-- Attachment #1: Type: text/plain, Size: 1686 bytes --]

On Thu, Nov 7, 2024 at 9:49 PM Bart Schaefer <schaefer@brasslantern.com>
wrote:

> Here's a .zshrc-level workaround to try:
>
> functions -c -- _normal _normal@c:drive
> _normal () {
>   if compset -P /c/
>   then
>     local opwd=$PWD ret
>     cd /c || return 1
>     _normal@c:drive "$@"
>     ret=$?
>     cd $opwd
>     return ret
>   else
>     _normal@c:drive "$@"
>   fi
> }
>

Works, thank you Bart!

I used Claude to extend this code to apply to all drive letters, code
below. 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. The code:

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

# Create completion functions for each drive
for drive in $(mount | grep -i '^[a-z]:' | cut -d':' -f1 | tr '[:upper:]'
'[:lower:]' | sort -u); do
    # Create a drive-specific completion function
    eval "functions -c -- _normal@original _normal@${drive}:drive"
done

_normal () {
    for drive in $(mount | grep -i '^[a-z]:' | cut -d':' -f1 | tr
'[:upper:]' '[:lower:]' | sort -u); do
        if compset -P "/${drive}/"
        then
            local opwd=$PWD ret
            cd /${drive} || return 1
            _normal@${drive}:drive "$@"
            ret=$?
            cd $opwd
            return ret
        fi
    done
    _normal@original "$@"
}

[-- Attachment #2: Type: text/html, Size: 2606 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-07 21:24           ` Ram Rachum
@ 2024-11-08  0:18             ` Bart Schaefer
  2024-11-08  8:03               ` Ram Rachum
  0 siblings, 1 reply; 16+ messages in thread
From: Bart Schaefer @ 2024-11-08  0:18 UTC (permalink / raw)
  To: Ram Rachum; +Cc: zsh workers

On Thu, Nov 7, 2024 at 1:25 PM Ram Rachum <ram@rachum.com> 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
}


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-08  0:18             ` Bart Schaefer
@ 2024-11-08  8:03               ` Ram Rachum
  2024-11-08  8:06                 ` Ram Rachum
  2024-11-09  4:45                 ` Bart Schaefer
  0 siblings, 2 replies; 16+ messages in thread
From: Ram Rachum @ 2024-11-08  8:03 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh workers

[-- Attachment #1: Type: text/plain, Size: 3620 bytes --]

On Fri, Nov 8, 2024 at 2:18 AM Bart Schaefer <schaefer@brasslantern.com>
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
}

[-- Attachment #2: Type: text/html, Size: 4969 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-08  8:03               ` Ram Rachum
@ 2024-11-08  8:06                 ` Ram Rachum
  2024-11-09  4:45                 ` Bart Schaefer
  1 sibling, 0 replies; 16+ messages in thread
From: Ram Rachum @ 2024-11-08  8:06 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh workers

[-- Attachment #1: Type: text/plain, Size: 4064 bytes --]

On Fri, Nov 8, 2024 at 10:03 AM Ram Rachum <ram@rachum.com> wrote:

> On Fri, Nov 8, 2024 at 2:18 AM Bart Schaefer <schaefer@brasslantern.com>
> 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
> }
>


Oh, now I find that it only works when autocompleting the first folder and
not any subsequent folders... So it'll complete /c/win to /c/Windows but it
won't complete /c/Windows/sys to /c/Windows/System.

[-- Attachment #2: Type: text/html, Size: 5564 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-08  8:03               ` Ram Rachum
  2024-11-08  8:06                 ` Ram Rachum
@ 2024-11-09  4:45                 ` Bart Schaefer
  2024-11-09 15:40                   ` Ram Rachum
  1 sibling, 1 reply; 16+ messages in thread
From: Bart Schaefer @ 2024-11-09  4:45 UTC (permalink / raw)
  To: Ram Rachum; +Cc: zsh workers

On Fri, Nov 8, 2024 at 12:03 AM Ram Rachum <ram@rachum.com> wrote:
>
> On Fri, Nov 8, 2024 at 2:18 AM Bart Schaefer <schaefer@brasslantern.com> wrote:
>>
>>   ${${(M)${(fL)"$(mount)"}:#[a-z]:*}%%:*}
>>
>> I left out the "sort -u" because (a) the order shouldn't matter
>
> On my system this results in `c c c c g j l m p` so I'll keep the implementation with `sort -u`.

I'm surprised by the multiple c: references, but just add (u) to make
them unique.

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

>> _normal () {
>>   if [[ $PREFIX != /*/*/* ]] && compset -P
>> "/(${(j:|:)${(M)${(fL)"$(mount)"}:#[a-z]:*}%%:*})/"
>
> This works for /c/ but not for my other drives.

Ah, as I said, tweaking.  Need a couple of "preserve array-ness"
operations because of the outer double-quotes:

  "/(${(j:|:)${(@u)${(@M)${(fL)"$(mount)"}:#[a-z]:*}%%:*}})/"

But you're right, since every drive is just a single letter you can do
it with a character class instead of with alternation.  I couldn't do
that because I was testing with (lib|tmp|usr).

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

However, I think even that is overkill -- there isn't anything that
matches the pattern /?/ yet is not a drive letter, is there?  So just

  if [[ $PREFIX != /*/*/* ]] && compset -P /?/

should set $IPREFIX to the drive path.

On Fri, Nov 8, 2024 at 12:06 AM Ram Rachum <ram@rachum.com> wrote:
>
> Oh, now I find that it only works when autocompleting the first folder and not any subsequent folders... So it'll complete /c/win to /c/Windows but it won't complete /c/Windows/sys to /c/Windows/System.

Hm, I'd like to see ^X? (completion debugging) output for that,
because it might be related to the attempt to match
case-insensitively.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-09  4:45                 ` Bart Schaefer
@ 2024-11-09 15:40                   ` Ram Rachum
  2024-11-09 19:34                     ` Bart Schaefer
  0 siblings, 1 reply; 16+ messages in thread
From: Ram Rachum @ 2024-11-09 15:40 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh workers

[-- Attachment #1: Type: text/plain, Size: 1033 bytes --]

On Sat, Nov 9, 2024 at 6:46 AM Bart Schaefer <schaefer@brasslantern.com>
wrote:

>
> However, I think even that is overkill -- there isn't anything that
> matches the pattern /?/ yet is not a drive letter, is there?  So just
>
>   if [[ $PREFIX != /*/*/* ]] && compset -P /?/
>
> should set $IPREFIX to the drive path.
>

Works, thank you!



> On Fri, Nov 8, 2024 at 12:06 AM Ram Rachum <ram@rachum.com> wrote:
> >
> > Oh, now I find that it only works when autocompleting the first folder
> and not any subsequent folders... So it'll complete /c/win to /c/Windows
> but it won't complete /c/Windows/sys to /c/Windows/System.
>
> Hm, I'd like to see ^X? (completion debugging) output for that,
> because it might be related to the attempt to match
> case-insensitively.
>

Here's the output for /c/Win which works:
https://gist.github.com/cool-RR/fdd1425e36552868b2424fb86ab132f4

Here's the output for /c/Windows/Sys which fails:
https://gist.github.com/cool-RR/ad525df593f60ab11024fcb33fbed127

[-- Attachment #2: Type: text/html, Size: 1843 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Absolute path tab completion on Windows
  2024-11-09 15:40                   ` Ram Rachum
@ 2024-11-09 19:34                     ` Bart Schaefer
  0 siblings, 0 replies; 16+ messages in thread
From: Bart Schaefer @ 2024-11-09 19:34 UTC (permalink / raw)
  To: Ram Rachum; +Cc: zsh workers

On Sat, Nov 9, 2024 at 7:40 AM Ram Rachum <ram@rachum.com> wrote:
>
> Here's the output for /c/Windows/Sys which fails: https://gist.github.com/cool-RR/ad525df593f60ab11024fcb33fbed127

Aha.  Let's try it this way.  I threw in an "always" block to make
sure the "cd" gets undone even on interrupt or something.

_normal () {
  case $PREFIX in
    (/?/*/*) _normal@original "$@";;
    (/?/*)
      local opwd=$PWD ret=1
      compset -P /?/    # Must succeed if /?/* matched
      {
        cd $IPREFIX
        if [[ -o autocd && $compstate[context] = command ]]
        then
          _cd "$@"
        else
          _normal@original "$@"
        fi
        ret=$?
      } always {
        cd $opwd
      }
      return ret
      ;;
    (*) _normal@original "$@";;
  esac
}

If that still doesn't work, something else fishy is going on.


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2024-11-09 19:35 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-11-04 21:06 Absolute path tab completion on Windows Ram Rachum
2024-11-05  3:15 ` Bart Schaefer
2024-11-05 13:16   ` Ram Rachum
2024-11-05 17:00     ` Bart Schaefer
2024-11-05 17:01       ` Ram Rachum
2024-11-05 20:21     ` Mikael Magnusson
2024-11-05 22:45       ` Mark J. Reed
2024-11-06 11:01       ` Ram Rachum
2024-11-07 19:49         ` Bart Schaefer
2024-11-07 21:24           ` Ram Rachum
2024-11-08  0:18             ` Bart Schaefer
2024-11-08  8:03               ` Ram Rachum
2024-11-08  8:06                 ` Ram Rachum
2024-11-09  4:45                 ` Bart Schaefer
2024-11-09 15:40                   ` Ram Rachum
2024-11-09 19:34                     ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).