zsh-users
 help / color / mirror / code / Atom feed
From: Mikael Magnusson <mikachu@gmail.com>
To: Zsh Users <zsh-users@zsh.org>
Subject: Re: Neat hash -d trick
Date: Fri, 22 Oct 2010 09:28:04 +0200	[thread overview]
Message-ID: <AANLkTimewqEvxBaQwqv1Sp=+OOjwmK_cgghM=VVC-Db2@mail.gmail.com> (raw)
In-Reply-To: <101021210513.ZM30802@torch.brasslantern.com>

On 22 October 2010 06:05, Bart Schaefer <schaefer@brasslantern.com> wrote:
> [Aside to -workers:  This reminds me about Mikael Magnusson's thread
> for his proposed HASH_LOOKUP option, which sort of died out without
> resolution after a discussion of findcmd() behaving oddly.]

[I'm still meaning to look into that, it's just that hacking on zsh C
code requires a pretty rare set of circumstances, being both pretty
bored, but also in a very optimistic mood. :)]

> On Oct 22, 12:34am, Nikolai Weibull wrote:
> }
> } for ((i = 1; i < 9; i++)); do
>
> You probably mean <= 9 there?  Or just
>
>  for i in {1..9}
>
> }   hash -d .$i=${(j:/:)${(l:2::.:)${(s::)${(l:i::.:)}}}}
>
>    hash -d .$i=${${(l:i*3::../:)}%/}
>
> } done
> }
> } cd ~.4/dir
>
> A generic word of caution about using "hash -d": if you for any reason
> change the value of $PATH or $path after this, all your custom hash
> entries are lost when the table is rebuilt for the new searchpath.

Hmm? Doesn't seem to happen for me.

> A similar trick:
>
>    dotdot() {
>      if (( NUMERIC > 0 ))
>      then LBUFFER+=..; repeat $((NUMERIC-1)) LBUFFER+=/..
>      else LBUFFER+=.
>      fi
>    }
>    zle -N dotdot
>    bindkey . dotdot
>
> Now you can type ESC 4 . to insert ../../../.. (or ESC 9 ESC 9 . to
> insert 99 levels, if for some insane reason you need that many).

Doing this actually causes you to be unable to type dots in an isearch
widget, since it aborts on custom bindings. I think pws is partly
responsible for this
# just type '...' to get '../..'
rationalise-dot() {
local MATCH
if [[ $LBUFFER =~ '(^|/| |	|'$'\n''|\||;|&)\.\.$' ]]; then
  LBUFFER+=/
  zle self-insert
  zle self-insert
else
  zle self-insert
fi
}
zle -N rationalise-dot
bindkey . rationalise-dot
# without this, typing a . aborts incremental history search
bindkey -M isearch . self-insert

You only need the last line to avoid the problem of course.

> } What would be even sweeter is if someone would come up with a way to
> } do this with only one call to hash -d without writing out all the
> } expansions
>
> Because the counter has to be referenced twice in the expansion, I
> don't think there's any way of avoiding the "for" loop that's worth
> the effort to figure out.  However,
>
>    for i in {1..9}; h+=(.$i=${${(l:i*3::../:)}%/}); hash -d $h
>
> Or to avoid leaving $i and $h with a value at the end,
>
>    hash -d $( for i in {1..9}; print .$i=${${(l:i*3::../:)}%/} )

To avoid leaving $i and $h with a value and a fork ;)
% () {local i h; for i in {1..9}; h+=(.$i=${${(l:i*3::../:)}%/}); hash -d $h}
% path+=/tmp
% path[2]=()
% hash -d|head -1
.1=..

I also have a vaguely related custom widget, in case you're unsure
just how many dotdots you need.

function _showcurrargrealpath() {
  setopt localoptions nonomatch
  local REPLY REALPATH
  _split_shell_arguments_under
  #zle -M "$(realpath ${(Q)${~REPLY}} 2> /dev/null | head -n1 || echo
1>&2 "No such path")"
  REALPATH=( ${(Q)${~REPLY}}(N:A) )
  zle -M "${REALPATH:-Path not found: $REPLY}"
}
zle -N _showcurrargrealpath
bindkey "^X." _showcurrargrealpath

# which i now notice in turn relies on this bit:
autoload -U modify-current-argument
autoload -U split-shell-arguments

function _split_shell_arguments_under()
{
  local -a reply
  integer REPLY2
  split-shell-arguments
  #have to duplicate some of modify-current-argument to get the word
  #_under_ the cursor, not after.
  setopt localoptions noksharrays multibyte
  if (( REPLY > 1 )); then
    if (( REPLY & 1 )); then
      (( REPLY-- ))
    fi
  fi
  REPLY=${reply[$REPLY]}
}

I also noticed now that if you mistype a named dir and run that
widget, the whole command line aborted due to the failed $~ expansion,
not sure why it would do that. That's why I added the setopt nonomatch
just now, it'll print the original path with (:A) appended as if it
succeeds but at least better than eating the command line.

[aside to -workers: would it make sense if ~ also checked for
nullglob? i noticed in the code that it checks for nomatch only
(merely looking at zsh C code is possible more often than editing it).
not sure how many different bits use that same function to expand
stuff though.]

-- 
Mikael Magnusson


  reply	other threads:[~2010-10-22  7:28 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-10-21 22:34 Nikolai Weibull
2010-10-22  4:05 ` Bart Schaefer
2010-10-22  7:28   ` Mikael Magnusson [this message]
2010-10-22  8:09     ` Julien Nicoulaud
2010-10-22  8:39     ` Jérémie Roquet
2010-10-22 10:29   ` Nikolai Weibull
2010-10-22 14:24   ` Oliver Kiddle
2010-10-27 15:45 ` Jean-Rene David

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='AANLkTimewqEvxBaQwqv1Sp=+OOjwmK_cgghM=VVC-Db2@mail.gmail.com' \
    --to=mikachu@gmail.com \
    --cc=zsh-users@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).