So, mika started a little pet project called zsh-pony, which aims at telling zsh-newcomers about how to facilitate many of zsh's advanced features in their own setups (which by the way, I'm considering to be a way better approach of getting starters into zsh than telling them "Here, clone this github-repo and be happy" - which only helps until the zsh-padawan hits the first issue in that repo - at which point, he/she is screwed).
One of the things mika lists is `auto_cd' as "switching directories for lazy people". I don't agree. Never liked that option. It makes stuff at the command position even more ambiguous than it already is. Sure, it may sound nice to be able to type "foo<RET>" to go a directory "foo" in the current directory. But what if the directory is called "git"? "git<RET>", huh? Yeah, well. That'll execute `git' the version control's main command. Of course, you'll scream at me, that you'll just "./git<RET>". Because that's so much simpler than "cd git<RET>". Especially on - say - german keyboards, where `/' is "Shift-7".
Also, you don't get the special completion for the `cd' builtin. It's nice to have it not complete stuff like files or "lost+found/" or "CVS/".
The one and only thing in `auto_cd', that seems worthwhile to me, is "..<RET>" to go up a directory level. But then, what to do to go up two levels? "../..<RET>"? I think not.
A friend of mine (hey Fabian!) asked me a while back if I could come up with a feature that would let him go up levels like he did in his amiga shell. Apparently, you could enter a forward-slash to go up a level. That is useful. So, what my setup does is if upon hitting "<RET>" and the command buffer is made up of just dots, it will convert that into "cd ../..". One ".."-level for each dot in the buffer.
So, ".<RET>" gets me up one directory. "..<RET>" two levels. And so on. There is no arbitrary limit, so if I input a hundert dots my shell will try to go up a hundert levels.
How to do that, well here's how:
function ft_accept_line_cd_up() {
setopt local_options extended_glob
local -a cmdline
cmdline=( ${(z)BUFFER} )
if (( ${#cmdline} == 1 )) && [[ ${cmdline[1]} == .# ]] ; then
BUFFER='cd '
for (( i = 1; i <= ${#${cmdline[1]}}; i++ )); do
BUFFER="${BUFFER}../"
done
BUFFER=${BUFFER%/}
fi
zle ".$WIDGET"
}
zle -N accept-line ft_accept_line_cd_up
After that the following
% ...<RET>
will turn into
% cd ../../..<RET>
But what about "../../<TAB>"? I hear you ask. Well, my setup does that too. I can just do this:
% ..<TAB>
...and that will behave as if I did this:
% cd ../../<TAB>
Here's a simple way to get that going:
function ft_complete_with_dots() {
setopt local_options extended_glob
local -a cmdline
cmdline=( ${(z)BUFFER} )
if (( ${#cmdline} == 1 )) && [[ ${cmdline[1]} == .# ]] ; then
BUFFER='cd '
for (( i = 1; i <= ${#${cmdline[1]}}; i++ )); do
BUFFER="${BUFFER}../"
done
CURSOR=${#BUFFER}
fi
zle ".$WIDGET"
}
zle -N complete-word ft_complete_with_dots
# if you don't do this already...
bindkey '^I' complete-word
You could factor the turn-dots-into-cd code into its own function to avoid the code duplication with the previous snippet, but that's basically it.
Take that for laziness.
(Oh yeah. If you're a big big fan of `auto_cd', use it by all means. The above snippets also work if that option is enabled, so you can have both.)