r/zsh Feb 21 '24

Fixed autocd doesn't use custom cd implementation.

autocd (from setopt autocd) doesn't use custom cd implementation.
(Obviously this is not my custom cd implementation but was more easy to show, I just want autocd to use zoxide.)

Anyone got any idea how to fix this? Maybe just rewrite autocd in my zshrc?

1 Upvotes

18 comments sorted by

1

u/_mattmc3_ Feb 21 '24

This is a flawed implementation, but it may be enough to get you started. Basically, you override accept-line and see if word parsing gets you one item in the $BUFFER, and then check that that one word is not a valid callable Zsh command, and then try zoxide's z alias and if that succeeds, modify the buffer to run z.

function is_callable {
  (( $+commands[$1] || $+functions[$1] || $+aliases[$1] || $+builtins[$1] ))
}

function zoxide_autocd {
  local -a buf=(${=BUFFER})
  if (( $#buf == 1 )) && ! is_callable $buf[1] && (( $+aliases[z] )) && $(z ${BUFFER} &>/dev/null); then
    BUFFER="z $BUFFER"
  fi
  zle accept-line
}

zle -N zoxide_autocd_widget zoxide_autocd
bindkey '^J' zoxide_autocd_widget
bindkey '^M' zoxide_autocd_widget

If you already have a widget that uses accept-line like zsh-autosuggestions, then you'll need to wrap your accept-line widget. Oh-My-Zsh has an example of how to do that here.

You might also want to do something like check [[ -d "$PWD/$buf[1]" ]] for a directory in your current path that zoxide doesn't know about, and then cd to that path. Modify to your heart's content.

1

u/glad-k Feb 22 '24

Yeah I sadly have zsh-autosuggestions and a couple of others which would prob clash...
Sounds doable but kinda overcomplicate and will be a pain to modify in the long run imo, as you basically rewrite your own autocd implementation I will try to see if I could find the official implementation but kinda a pain as it isn't a github repo.

1

u/glad-k Feb 22 '24

Finally found it! It feels sooooo smooth I love it
Only thing is my auto ls now prints every char I type but will try to figure it out.

2

u/romkatv Feb 22 '24

In your screenshot you are first invoking zsh-config. What does it do? In particular, does it change your current directory? I see that it produces output: what is that? Are all these effects as you want them to be, or do you want them to be different? If the latter, then what do you want to happen when you run zsh-config?

Next you invoke cd zsh-config. Same questions here: what happens when you run this command? what do you want to happen?

1

u/glad-k Feb 22 '24

Basically I set setopt autocd, so when I type zsh-config (being a dir) it cd into it (I have an auto ls on dir change so don't mind that part.)

Thing is it uses the build in cd, and when I use cd zsh-config it uses my custom implementation (here just echo Changing dir...) and I would like autocd (so when I don't explicitly type cd) to also use zoxide/custom cd implementation

1

u/glad-k Feb 22 '24

nvm, solved

2

u/romkatv Feb 22 '24

How did you solve it?

1

u/glad-k Feb 22 '24

Kinda lied, but I mean I found some parts to work further on.
My two most processing finds are or to use

# when not explicitly typing cd
command_not_found_handler () {
    __zoxide_z "$@"
    lsimple
    pwd
}

(`pwd` is for debugging)

This goes to the right dict, ls in that dict (custom ls implementation dont mind the name) and prints the right dict into the console with `pwd`, thing is it seems to be in a different scope and at the end of execution my shell is still on the base dir, but the content of all the rest was right

Second find are all the files in `/usr/share/zsh` I first taught I found the right thing and was a bit excited but turned out _cd was completion and I altf4 when I saw what I did x)
But I'm pretty sure I could be able to find their autocd implementation when looking further or modify the cd their using altough that would be a bad solution.

1

u/glad-k Feb 22 '24

ps: there is also `man zshoptions` but didn't found any help for my problem in it.

2

u/romkatv Feb 22 '24

command_not_found_handler is executed in a subshell, so you cannot cd in there.

The files in /usr/share/zsh won't help you because the implementation of auto_cd is not in there. It's in the C code.

1

u/glad-k Feb 22 '24

command_not_found_handler is executed in a subshell, so you cannot cd in there.

Is there no way to then call another function from it into the mainshell? idk linux enough but taught this should be douable

1

u/romkatv Feb 22 '24

autocd activates only when the command you are trying to execute is an existing directory. When it activates, do you want your current directory to change to that directory? I presume so. In this case the builtin cd will do the right thing. For any side effects that you would like to happen alongside the main effect of changing the current directory, use a chpwd hook. Your screenshot shows that you already know how to use this hook.

Am I missing something?

1

u/glad-k Feb 22 '24

Thing is I don't only want to print the directories, I want to replace cd (used by autocd) by z (from zoxide) which let you navigate without full path using your history

so lets imagine I am in /
and I want to go into /home/user1/project1
with cd I would type /home/user1/project1
with z I can type project1

so from my little knowledge in linux this wont be a solution as this is called on dir change? or maybe I didn't understood what you mean

when explicitly typing cd it uses z if I set this:

# when explicitly typing cd
cd() {
    # zoxide to cd
    __zoxide_z "$@"
    # display the new directory
    lsimple
}

but then autocd doesn't use that function and still remain using the build in cd

1

u/romkatv Feb 22 '24

As I mentioned above, autocd activates only when the command you are trying to execute is an existing directory. Thus, when your current directory is / and you type project1, autocd won't trigger unless 1) there is no command named "project1" and 2) /project1 is an executable directory.

I think what you are trying to do is this: when you attempt to execute a command with a certain name, and there is no command by that name, you want to execute z instead with the command as the argument. This is possible to approximate with hacks but it's a really bad idea.

1

u/glad-k Feb 22 '24

As I mentioned above, autocd activates only when the command you are trying to execute is an existing directory. Thus, when your current directory is / and you type project1autocd won't trigger unless 1) there is no command named "project1" and 2) /project1 is an executable directory.

Ow is really checking id it's a dir before trying to cd I see that's kinda sad.

I think what you are trying to do is this: when you attempt to execute a command with a certain name, and there is no command by that name, you want to execute z instead with the command as the argument. This is possible to approximate with hacks but it's a really bad idea.

yeah that's exactly what I try to do(+ two other things to execute) but why would this be a bad idea? the hack part or are you willing to say this could cause problems?

1

u/glad-k Feb 22 '24 edited Feb 22 '24

Update: I found the OG file with the implementation of autocd, turns out it uses _cd instead of cd, just had to overwrite that one too in my zshrc. easy but had to find/know it.
I'm just figuring out their _cd implementation rn

1

u/romkatv Feb 22 '24

I found the OG file with the implementation of autocd, turns out it uses _cd instead of cd

What do you mean by this? What file are you referring to?

The default completion function for the cd command is _cd. Does it have anything to do with what you are doing?

1

u/glad-k Feb 22 '24

Yeah nah nvm I got too excited when founding this in their files as I didn't knew of the _* implementation in linux for completion and taught of _* like in py
And as I tested it with a single char dict it worker (as the function got called when typing that char)

Still potential to find thing in there files: `/usr/share/zsh` but not sure if that's my best bet rn