zsh-users
 help / color / mirror / code / Atom feed
* possibly useful zsh_directory_name implementation
@ 2011-03-11  1:06 Mikael Magnusson
  2011-03-11  1:15 ` Mikael Magnusson
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Mikael Magnusson @ 2011-03-11  1:06 UTC (permalink / raw)
  To: Zsh Users

function zsh_directory_name () {
  case $1 in
    n)
      case $2 in
        /*)
          reply=( /${(j:/:)${(s:/:)PWD}[1,(er)${2[2,-1]}]} )
        ;;
        .*)
          reply=( (../)##${2[2,-1]}([1]) )
        ;;
      esac
    ;;
    c)
      local types vals description
      types=( '.:children of parent directories' '/:pwd segment' )
      case $PREFIX in
        '')
          vals=( $types )
          _describe 'dynamic dir type' vals -V dynamic-dirs -o -S ''
        ;;
        .*)
          vals=( (../)##*~(../)##$PWD:t(/:t) )
        ;|
        /*)
          vals=( "${(@)${(s:/:)PWD}[1,-2]}" )
        ;|
        *)
          _wanted -V dynamic-dirs expl
${${types[(r)$PREFIX[1]*]}[3,-1]} compadd -P $PREFIX[1] -qQS / -d vals
${(q)^vals}\]
      esac
    ;;
  esac
}

With this, /home/mikachu/some/directory/somewhere% cd ~[/some], will
take you to /home/mikachu/some/, and cd ~[.foo] will take you to foo/
in whatever parent directory has a subdirectory foo, for example it
could be /home/foo/.

-- 
Mikael Magnusson

footnotes:
reply=( $PWD[1,(r)$2] ) of course is the more obvious solution, but it
doesn't work on directories called "[foo] something".
the fiddling with (q)^\] and -Q is because i want only / to be a
removable suffix, not the ].


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11  1:06 possibly useful zsh_directory_name implementation Mikael Magnusson
@ 2011-03-11  1:15 ` Mikael Magnusson
  2011-03-11 10:44 ` Peter Stephenson
  2011-03-11 17:44 ` Jérémie Roquet
  2 siblings, 0 replies; 11+ messages in thread
From: Mikael Magnusson @ 2011-03-11  1:15 UTC (permalink / raw)
  To: Zsh Users

On 11 March 2011 02:06, Mikael Magnusson <mikachu@gmail.com> wrote:
> function zsh_directory_name () {
>  case $1 in
>    n)
>      case $2 in
>        /*)
>          reply=( /${(j:/:)${(s:/:)PWD}[1,(er)${2[2,-1]}]} )
>        ;;
>        .*)
>          reply=( (../)##${2[2,-1]}([1]) )
>        ;;
>      esac
>    ;;
>    c)
>      local types vals description
>      types=( '.:children of parent directories' '/:pwd segment' )
>      case $PREFIX in
>        '')
>          vals=( $types )
>          _describe 'dynamic dir type' vals -V dynamic-dirs -o -S ''
>        ;;
>        .*)
>          vals=( (../)##*~(../)##$PWD:t(/:t) )
>        ;|
>        /*)
>          vals=( "${(@)${(s:/:)PWD}[1,-2]}" )
>        ;|
>        *)
>          _wanted -V dynamic-dirs expl
> ${${types[(r)$PREFIX[1]*]}[3,-1]} compadd -P $PREFIX[1] -qQS / -d vals
> ${(q)^vals}\]

These three lines should be one line, silly email.

-- 
Mikael Magnusson


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11  1:06 possibly useful zsh_directory_name implementation Mikael Magnusson
  2011-03-11  1:15 ` Mikael Magnusson
@ 2011-03-11 10:44 ` Peter Stephenson
  2011-03-11 12:06   ` Mikael Magnusson
  2011-03-11 16:25   ` Peter Stephenson
  2011-03-11 17:44 ` Jérémie Roquet
  2 siblings, 2 replies; 11+ messages in thread
From: Peter Stephenson @ 2011-03-11 10:44 UTC (permalink / raw)
  To: Zsh Users

On Fri, 11 Mar 2011 02:06:45 +0100
Mikael Magnusson <mikachu@gmail.com> wrote:
> function zsh_directory_name () {
>...
> }
> 
> With this, /home/mikachu/some/directory/somewhere% cd ~[/some], will
> take you to /home/mikachu/some/, and cd ~[.foo] will take you to foo/
> in whatever parent directory has a subdirectory foo, for example it
> could be /home/foo/.

I've been meaning to add a zsh_directory_name hook, so you can have
multiple functions implementing this and the function here would
interact nicely with other functions that implemented naming without the
"/" or "." at the start.  However, I need to think about the
consequences --- it's more complicated than the existing hooks.

(Just to state the obvious, you can get a less controllable effect of
this using cdpath, although I find life's a bit too complicated to rely
on cdpath these days.  My zsh_directory_name implements a hierarchical
scheme where, for example, [p:c:p=main] specifies which Perforce client
I'm using, which project within the client, and which private branch
within the project.  It might be interesting to generalise this to
something configurable with associative arrays.)

-- 
Peter Stephenson <pws@csr.com>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11 10:44 ` Peter Stephenson
@ 2011-03-11 12:06   ` Mikael Magnusson
  2011-03-11 12:17     ` Peter Stephenson
  2011-03-11 16:25   ` Peter Stephenson
  1 sibling, 1 reply; 11+ messages in thread
From: Mikael Magnusson @ 2011-03-11 12:06 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh Users

On 11 March 2011 11:44, Peter Stephenson <Peter.Stephenson@csr.com> wrote:
> On Fri, 11 Mar 2011 02:06:45 +0100
> Mikael Magnusson <mikachu@gmail.com> wrote:
>> function zsh_directory_name () {
>>...
>> }
>>
>> With this, /home/mikachu/some/directory/somewhere% cd ~[/some], will
>> take you to /home/mikachu/some/, and cd ~[.foo] will take you to foo/
>> in whatever parent directory has a subdirectory foo, for example it
>> could be /home/foo/.
>
> I've been meaning to add a zsh_directory_name hook, so you can have
> multiple functions implementing this and the function here would
> interact nicely with other functions that implemented naming without the
> "/" or "." at the start.  However, I need to think about the
> consequences --- it's more complicated than the existing hooks.

If you don't have a prefix, how do you specify which of the functions
should handle the argument?

-- 
Mikael Magnusson


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11 12:06   ` Mikael Magnusson
@ 2011-03-11 12:17     ` Peter Stephenson
  2011-03-11 12:32       ` Mikael Magnusson
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2011-03-11 12:17 UTC (permalink / raw)
  To: Zsh Users

On Fri, 11 Mar 2011 13:06:13 +0100
Mikael Magnusson <mikachu@gmail.com> wrote:
> If you don't have a prefix, how do you specify which of the functions
> should handle the argument?

I'm not sure I understand the question, but the way it would is each
hook function is passed the same arguments in turn.  If it's not in a
form it recognises, it returns a non-zero status.  This continues until
one function handles the argument and returns a zero status.  So each
function just looks at the pattern it's got and sees if it thinks it
makes sense to handle it.  That requires a minimal amount of cooperation
but in the name -> directory direction it's simply a question of failing
gracefully with unmatched names.  In the other direction there's more of
an ordering problem --- do you want the name to pop up as a relative
directory like '.dir', or using some kind of absolute naming scheme?
But that's up to the user's preference.

-- 
Peter Stephenson <pws@csr.com>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11 12:17     ` Peter Stephenson
@ 2011-03-11 12:32       ` Mikael Magnusson
  0 siblings, 0 replies; 11+ messages in thread
From: Mikael Magnusson @ 2011-03-11 12:32 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh Users

On 11 March 2011 13:17, Peter Stephenson <Peter.Stephenson@csr.com> wrote:
> On Fri, 11 Mar 2011 13:06:13 +0100
> Mikael Magnusson <mikachu@gmail.com> wrote:
>> If you don't have a prefix, how do you specify which of the functions
>> should handle the argument?
>
> I'm not sure I understand the question, but the way it would is each
> hook function is passed the same arguments in turn.  If it's not in a
> form it recognises, it returns a non-zero status.  This continues until
> one function handles the argument and returns a zero status.  So each
> function just looks at the pattern it's got and sees if it thinks it
> makes sense to handle it.  That requires a minimal amount of cooperation
> but in the name -> directory direction it's simply a question of failing
> gracefully with unmatched names.  In the other direction there's more of
> an ordering problem --- do you want the name to pop up as a relative
> directory like '.dir', or using some kind of absolute naming scheme?
> But that's up to the user's preference.

Okay, I completely misinterpreted one of your sentences, it makes
complete sense now. I thought you meant the . and / in _my_ function
wouldn't be needed, somehow. Clearly that referred to the other
functions.
("the function here would interact nicely with other functions that
implemented naming without the "/" or "." at the start.")

-- 
Mikael Magnusson


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11 10:44 ` Peter Stephenson
  2011-03-11 12:06   ` Mikael Magnusson
@ 2011-03-11 16:25   ` Peter Stephenson
  2011-03-11 16:33     ` Peter Stephenson
  1 sibling, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2011-03-11 16:25 UTC (permalink / raw)
  To: Zsh Users

On Fri, 11 Mar 2011 10:44:02 +0000
Peter Stephenson <Peter.Stephenson@csr.com> wrote:
> I've been meaning to add a zsh_directory_name hook, so you can have
> multiple functions implementing this and the function here would
> interact nicely with other functions that implemented naming without
> the "/" or "." at the start.  However, I need to think about the
> consequences --- it's more complicated than the existing hooks.

Seems straightforward, in fact; the call sequence is different from the
other hooks just owing to the arguments and the return value but
otherwise there doesn't appear to be anything funny going on.

This has allowed me to make the example use of cdr dynamic directories
into a contributed function that just needs adding to a hook.

Index: Completion/Zsh/Context/_dynamic_directory_name
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Zsh/Context/_dynamic_directory_name,v
retrieving revision 1.2
diff -p -u -r1.2 _dynamic_directory_name
--- Completion/Zsh/Context/_dynamic_directory_name	11 Jun 2010 22:28:22 -0000	1.2
+++ Completion/Zsh/Context/_dynamic_directory_name	11 Mar 2011 16:24:24 -0000
@@ -1,7 +1,14 @@
 #autoload
 
-if [[ -n $functions[zsh_directory_name] ]]; then
-  zsh_directory_name c
+local func
+
+if [[ -n $functions[zsh_directory_name] || \
+  ${+zsh_directory_name_functions} -ne 0 ]] ; then
+  zsh_directory_name c && return 0
+  for func in $zsh_directory_name_functions; do
+    $func c && return 0
+  done
+  return 1
 else
   _message 'dynamic directory name: implemented as zsh_directory_name c'
 fi
Index: Doc/Zsh/contrib.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/contrib.yo,v
retrieving revision 1.126
diff -p -u -r1.126 contrib.yo
--- Doc/Zsh/contrib.yo	4 Mar 2011 13:25:26 -0000	1.126
+++ Doc/Zsh/contrib.yo	11 Mar 2011 16:24:25 -0000
@@ -302,10 +302,13 @@ called at the same point; these are so-c
 The shell function tt(add-zsh-hook) provides a simple way of adding or
 removing functions from the array.
 
-var(hook) is one of tt(chpwd), tt(periodic), tt(precmd) or tt(preexec),
-the special functions in question.
+var(hook) is one of tt(chpwd), tt(periodic), tt(precmd), tt(preexec),
+tt(zshaddhistory), tt(zshexit), or tt(zsh_directory_name),
+the special functions in question.  Note that tt(zsh_directory_name)
+is called in a different way from the other functions, but may
+still be manipulated as a hook.
 
-var(functions) is name of an ordinary shell function.  If no options
+var(function) is name of an ordinary shell function.  If no options
 are given this will be added to the array of functions to be executed
 in the given context.
 
@@ -315,6 +318,10 @@ the array of functions to be executed.
 If the option tt(-D) is given, the var(function) is treated as a pattern
 and any matching names of functions are removed from the array of
 functions to be executed.
+
+The options tt(-U), tt(-z) and tt(-k) are passed as arguments to
+tt(autoload) for var(function).  For functions contributed with zsh, the
+options tt(-Uz) are appropriate.
 )
 enditem()
 
@@ -544,36 +551,15 @@ enditem()
 subsect(Use with dynamic directory naming)
 
 It is possible to refer to recent directories using the dynamic directory
-name syntax that appeared in zsh version 4.3.7.  If you create and
-autoload a function tt(zsh_directory_name) containing the following code,
-tt(~[1]) will refer to the most recent directory other than $PWD, and so on.
-This also includes completion.
-
-example(if [[ $1 = n ]]; then
-  if [[ $2 = <-> ]]; then
-    # Recent directory
-    typeset -ga reply
-    autoload -Uz cdr
-    cdr -r
-    if [[ -n ${reply[$2]} ]]; then
-      reply=LPAR()${reply[$2]}RPAR()
-      return 0
-    else
-      reply=LPAR()RPAR()
-      return 1
-    fi
-  fi
-elif [[ $1 = c ]]; then
-  if [[ $PREFIX = <-> || -z $PREFIX ]]; then
-    typeset -a keys values
-    values=LPAR()${${(f)"$+LPAR()cdr -l+RPAR()"}/ ##/:}RPAR()
-    keys=LPAR()${values%%:*}RPAR()
-    _describe -t dir-index 'recent directory index' \
-      values keys -V unsorted -S']'
-    return
-  fi
-fi
-return 1)
+name syntax by using the supplied function tt(zsh_directory_name_cdr)
+a hook:
+
+example(autoload -Uz add-zsh-hook
+add-zsh-hook -Uz zsh_directory_name zsh_directory_name_cdr)
+
+When this is done, tt(~[1]) will refer to the most recent
+directory other than $PWD, and so on.  Completion after tt(~[)var(...)
+also works.
 
 subsect(Details of directory handling)
 
Index: Doc/Zsh/expn.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/expn.yo,v
retrieving revision 1.132
diff -p -u -r1.132 expn.yo
--- Doc/Zsh/expn.yo	4 Mar 2011 13:25:26 -0000	1.132
+++ Doc/Zsh/expn.yo	11 Mar 2011 16:24:25 -0000
@@ -1517,8 +1517,12 @@ cindex(directories, named, dynamic)
 cindex(named directories, dynamic)
 cindex(dynamic named directories)
 
-The feature described here is only available if the shell function
-tt(zsh_directory_name) exists.
+If the function tt(zsh_directory_name) exists, or the shell variable
+tt(zsh_directory_name_functions) exists and contains an array of
+function names, then the functions are used to implement dynamic
+directory naming.  The functions are tried in order until one returns
+status zero, so it is important that functions test whether they can
+handle the case in question and return an appropriate status.
 
 A `tt(~)' followed by a string var(namstr) in unquoted square brackets is
 treated specially as a dynamic directory name.  Note that the first
@@ -1529,11 +1533,12 @@ which is the directory corresponding to 
 (executing an assignment as the last statement is usually sufficient), or
 it should return status non-zero.  In the former case the element of reply
 is used as the directory; in the latter case the substitution is deemed to
-have failed and tt(NOMATCH) handling is applied if the option is set.
+have failed.  If all functions fail and the option tt(NOMATCH) is set,
+an error results.
 
-The function tt(zsh_directory_name) is also used to see if a directory can
+The functions defined as above are also used to see if a directory can
 be turned into a name, for example when printing the directory stack or
-when expanding tt(%~) in prompts.  In this case the function is passed two
+when expanding tt(%~) in prompts.  In this case each function is passed two
 arguments: the string tt(d) (for directory) and the candidate for dynamic
 naming.  The function should either return non-zero status, if the
 directory cannot be named by the function, or it should set the array reply
@@ -1551,7 +1556,15 @@ parts of the directory path, as describe
 length matched (16 in the example) is longer than that matched by any
 static name.
 
-The completion system calls `tt(zsh_directory_name c)' in order to
+It is not a requirement that a function implements both
+tt(n) and tt(d) calls; for example, it might be appropriate for certain
+dynamic forms of expansion not to be contracted to names.  In that case
+any call with the first argument tt(d) should cause a non-zero status to
+be returned.
+
+The completion system calls `tt(zsh_directory_name c)' followed by
+equivalent calls to elements of the array
+tt(zsh_directory_name_functions), if it exists, in order to
 complete dynamic names for directories.  The code for this should be
 as for any other completion function as described in
 ifnzman(noderef(Completion System))\
Index: Functions/Chpwd/.distfiles
===================================================================
RCS file: /cvsroot/zsh/zsh/Functions/Chpwd/.distfiles,v
retrieving revision 1.1
diff -p -u -r1.1 .distfiles
--- Functions/Chpwd/.distfiles	9 Jul 2010 14:47:48 -0000	1.1
+++ Functions/Chpwd/.distfiles	11 Mar 2011 16:24:25 -0000
@@ -5,4 +5,5 @@ _cdr
 chpwd_recent_add
 chpwd_recent_dirs
 chpwd_recent_filehandler
+zsh_directory_name_cdr
 '
Index: Functions/Chpwd/zsh_directory_name_cdr
===================================================================
RCS file: Functions/Chpwd/zsh_directory_name_cdr
diff -N Functions/Chpwd/zsh_directory_name_cdr
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Functions/Chpwd/zsh_directory_name_cdr	11 Mar 2011 16:24:25 -0000
@@ -0,0 +1,25 @@
+if [[ $1 = n ]]; then
+  if [[ $2 = <-> ]]; then
+    # Recent directory
+    typeset -ga reply
+    autoload -Uz cdr
+    cdr -r
+    if [[ -n ${reply[$2]} ]]; then
+      reply=(${reply[$2]})
+      return 0
+    else
+      reply=()
+      return 1
+    fi
+  fi
+elif [[ $1 = c ]]; then
+  if [[ $PREFIX = <-> || -z $PREFIX ]]; then
+    typeset -a keys values
+    values=(${${(f)"$(cdr -l)"}/ ##/:})
+    keys=(${values%%:*})
+    _describe -t dir-index 'recent directory index' \
+      values keys -V unsorted -S']'
+    return
+  fi
+fi
+return 1
Index: Functions/Misc/add-zsh-hook
===================================================================
RCS file: /cvsroot/zsh/zsh/Functions/Misc/add-zsh-hook,v
retrieving revision 1.5
diff -p -u -r1.5 add-zsh-hook
--- Functions/Misc/add-zsh-hook	1 Aug 2008 11:48:42 -0000	1.5
+++ Functions/Misc/add-zsh-hook	11 Mar 2011 16:24:25 -0000
@@ -1,6 +1,6 @@
 # Add to HOOK the given FUNCTION.
 # HOOK is one of chpwd, precmd, preexec, periodic, zshaddhistory,
-# zshexit (the _functions subscript is not required).
+# zshexit, zsh_directory_name (the _functions subscript is not required).
 #
 # With -d, remove the function from the hook instead; delete the hook
 # variable if it is empty.
@@ -15,7 +15,10 @@
 emulate -L zsh
 
 local -a hooktypes
-hooktypes=(chpwd precmd preexec periodic zshaddhistory zshexit)
+hooktypes=(
+  chpwd precmd preexec periodic zshaddhistory zshexit
+  zsh_directory_name
+)
 
 local opt
 local -a autoopts
Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.116
diff -p -u -r1.116 subst.c
--- Src/subst.c	18 Jan 2011 10:29:58 -0000	1.116
+++ Src/subst.c	11 Mar 2011 16:24:25 -0000
@@ -579,7 +579,6 @@ filesubstr(char **namptr, int assign)
     char *str = *namptr;
 
     if (*str == Tilde && str[1] != '=' && str[1] != Equals) {
-	Shfunc dirfunc;
 	char *ptr, *tmp, *res, *ptr2;
 	int val;
 
@@ -594,12 +593,11 @@ filesubstr(char **namptr, int assign)
 	    *namptr = dyncat((tmp = oldpwd) ? tmp : pwd, str + 2);
 	    return 1;
 	} else if (str[1] == Inbrack &&
-		   (dirfunc = getshfunc("zsh_directory_name")) &&
 		   (ptr2 = strchr(str+2, Outbrack))) {
 	    char **arr;
 	    untokenize(tmp = dupstrpfx(str+2, ptr2 - (str+2)));
 	    remnulargs(tmp);
-	    arr = subst_string_by_func(dirfunc, "n", tmp);
+	    arr = subst_string_by_hook("zsh_directory_name", "n", tmp);
 	    res = arr ? *arr : NULL;
 	    if (res) {
 		*namptr = dyncat(res, ptr2+1);
Index: Src/utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.255
diff -p -u -r1.255 utils.c
--- Src/utils.c	6 Jan 2011 21:31:06 -0000	1.255
+++ Src/utils.c	11 Mar 2011 16:24:25 -0000
@@ -890,7 +890,8 @@ finddir(char *s)
 {
     static struct nameddir homenode = { {NULL, "", 0}, NULL, 0 };
     static int ffsz;
-    Shfunc func = getshfunc("zsh_directory_name");
+    char **ares;
+    int len;
 
     /* Invalidate directory cache if argument is NULL.  This is called *
      * whenever a node is added to or removed from the hash table, and *
@@ -906,9 +907,16 @@ finddir(char *s)
 	return finddir_last = NULL;
     }
 
-    /* It's not safe to use the cache while we have function transformations.*/
-    if(!func && !strcmp(s, finddir_full) && *finddir_full)
+#if 0
+    /*
+     * It's not safe to use the cache while we have function
+     * transformations, and it's not clear it's worth the
+     * complexity of guessing here whether subst_string_by_hook
+     * is going to turn up the goods.
+     */
+    if (!strcmp(s, finddir_full) && *finddir_full)
 	return finddir_last;
+#endif
 
     if ((int)strlen(s) >= ffsz) {
 	free(finddir_full);
@@ -920,18 +928,15 @@ finddir(char *s)
     finddir_scan(&homenode.node, 0);
     scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0);
 
-    if (func) {
-	char **ares = subst_string_by_func(func, "d", finddir_full);
-	int len;
-	if (ares && arrlen(ares) >= 2 &&
-	    (len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) {
-	    /* better duplicate this string since it's come from REPLY */
-	    finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir));
-	    finddir_last->node.nam = zhtricat("[", dupstring(ares[0]), "]");
-	    finddir_last->dir = dupstrpfx(finddir_full, len);
-	    finddir_last->diff = len - strlen(finddir_last->node.nam);
-	    finddir_best = len;
-	}
+    ares = subst_string_by_hook("zsh_directory_name", "d", finddir_full);
+    if (ares && arrlen(ares) >= 2 &&
+	(len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) {
+	/* better duplicate this string since it's come from REPLY */
+	finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir));
+	finddir_last->node.nam = zhtricat("[", dupstring(ares[0]), "]");
+	finddir_last->dir = dupstrpfx(finddir_full, len);
+	finddir_last->diff = len - strlen(finddir_last->node.nam);
+	finddir_best = len;
     }
 
     return finddir_last;
@@ -3212,7 +3217,7 @@ getshfunc(char *nam)
 char **
 subst_string_by_func(Shfunc func, char *arg1, char *orig)
 {
-    int osc = sfcontext;
+    int osc = sfcontext, osm = stopmsg;
     LinkList l = newlinklist();
     char **ret;
 
@@ -3228,6 +3233,47 @@ subst_string_by_func(Shfunc func, char *
 	ret = getaparam("reply");
 
     sfcontext = osc;
+    stopmsg = osm;
+    return ret;
+}
+
+/**
+ * Front end to subst_string_by_func to use hook-like logic.
+ * name can refer to a function, and name + "_hook" can refer
+ * to an array containing a list of functions.  The functions
+ * are tried in order until one returns success.
+ */
+/**/
+char **
+subst_string_by_hook(char *name, char *arg1, char *orig)
+{
+    Shfunc func;
+    char **ret = NULL;
+
+    if ((func = getshfunc(name))) {
+	ret = subst_string_by_func(func, arg1, orig);
+    }
+
+    if (!ret) {
+	char **arrptr;
+	int namlen = strlen(name);
+	VARARR(char, arrnam, namlen + HOOK_SUFFIX_LEN);
+	memcpy(arrnam, name, namlen);
+	memcpy(arrnam + namlen, HOOK_SUFFIX, HOOK_SUFFIX_LEN);
+
+	if ((arrptr = getaparam(arrnam))) {
+	    /* Guard against internal modification of the array */
+	    arrptr = arrdup(arrptr);
+	    for (; *arrptr; arrptr++) {
+		if ((func = getshfunc(*arrptr))) {
+		    ret = subst_string_by_func(func, arg1, orig);
+		    if (ret)
+			break;
+		}
+	    }
+	}
+    }
+
     return ret;
 }
 


-- 
Peter Stephenson <pws@csr.com>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11 16:25   ` Peter Stephenson
@ 2011-03-11 16:33     ` Peter Stephenson
  2011-03-11 17:09       ` Mikael Magnusson
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2011-03-11 16:33 UTC (permalink / raw)
  To: Zsh Users

On Fri, 11 Mar 2011 16:25:14 +0000
Peter Stephenson <Peter.Stephenson@csr.com> wrote:
> +local func
> +
> +if [[ -n $functions[zsh_directory_name] || \
> +  ${+zsh_directory_name_functions} -ne 0 ]] ; then
> +  zsh_directory_name c && return 0
> +  for func in $zsh_directory_name_functions; do
> +    $func c && return 0
> +  done
> +  return 1

Instantly after sending this, I realised it should try all functions and
return status 0 or 1 based on whether any were successful.  I've
submitted it in that form.

-- 
Peter Stephenson <pws@csr.com>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11 16:33     ` Peter Stephenson
@ 2011-03-11 17:09       ` Mikael Magnusson
  2011-03-11 18:24         ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Mikael Magnusson @ 2011-03-11 17:09 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh Users

On 11 March 2011 17:33, Peter Stephenson <Peter.Stephenson@csr.com> wrote:
> On Fri, 11 Mar 2011 16:25:14 +0000
> Peter Stephenson <Peter.Stephenson@csr.com> wrote:
>> +local func
>> +
>> +if [[ -n $functions[zsh_directory_name] || \
>> +  ${+zsh_directory_name_functions} -ne 0 ]] ; then
>> +  zsh_directory_name c && return 0
>> +  for func in $zsh_directory_name_functions; do
>> +    $func c && return 0
>> +  done
>> +  return 1
>
> Instantly after sending this, I realised it should try all functions and
> return status 0 or 1 based on whether any were successful.  I've
> submitted it in that form.

Can you really just call a bunch of completions in series and get a
useful result? The documentation still seems to imply running will
stop as soon as one hook returns 0 status.

More importantly, shouldn't you only run zsh_directory_name if that
function exists? As it is now, it will be run even if only the array
is defined. Also, why the mix of -n $foo and ${+foo}?

% ls ~[<tab>_dynamic_directory_name:8: command not found: zsh_directory_name

-- 
Mikael Magnusson


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11  1:06 possibly useful zsh_directory_name implementation Mikael Magnusson
  2011-03-11  1:15 ` Mikael Magnusson
  2011-03-11 10:44 ` Peter Stephenson
@ 2011-03-11 17:44 ` Jérémie Roquet
  2 siblings, 0 replies; 11+ messages in thread
From: Jérémie Roquet @ 2011-03-11 17:44 UTC (permalink / raw)
  To: Zsh Users

2011/3/11 Mikael Magnusson <mikachu@gmail.com>:
> function zsh_directory_name () {
> …
> }
>
> With this, /home/mikachu/some/directory/somewhere% cd ~[/some], will
> take you to /home/mikachu/some/, and cd ~[.foo] will take you to foo/
> in whatever parent directory has a subdirectory foo, for example it
> could be /home/foo/.

Looks useful to me :-)

Thanks for sharing!

-- 
Jérémie


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

* Re: possibly useful zsh_directory_name implementation
  2011-03-11 17:09       ` Mikael Magnusson
@ 2011-03-11 18:24         ` Peter Stephenson
  0 siblings, 0 replies; 11+ messages in thread
From: Peter Stephenson @ 2011-03-11 18:24 UTC (permalink / raw)
  To: Zsh Users

On Fri, 11 Mar 2011 18:09:57 +0100
Mikael Magnusson <mikachu@gmail.com> wrote:
> Can you really just call a bunch of completions in series and get a
> useful result? The documentation still seems to imply running will
> stop as soon as one hook returns 0 status.

Completion of a set of possibilities is a completely different operation
from turning one, unique, name into one, unique, directory.  You don't
know the first function to be called is the one that will produce the
completion you want.  If the user typed "p", does the user want
"pigbreeder-ahab" from zsh_directory_name_farmers, or "proj:monty" from
zsh_directory_name_projects?  The order of the functions doesn't tell
you.

> More importantly, shouldn't you only run zsh_directory_name if that
> function exists? As it is now, it will be run even if only the array
> is defined.

Yes, I'll fix that.

> Also, why the mix of -n $foo and ${+foo}?

Your $foo is looking for the presence of a function.  I think
${+functions[...]} does work, it just happened not to be done that way
and I didn't change it.  Your ${+foo} is looking for a variable being
set; that's not what -n $foo does, and although -n $foo does the right
thing as far as completion is concerned, testing the presense of the
variable is the right thing to avoid triggering the error message which
should only pop up if there is no defined mechanism for expanding ~[...].

-- 
Peter Stephenson <pws@csr.com>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom


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

end of thread, other threads:[~2011-03-11 18:24 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-11  1:06 possibly useful zsh_directory_name implementation Mikael Magnusson
2011-03-11  1:15 ` Mikael Magnusson
2011-03-11 10:44 ` Peter Stephenson
2011-03-11 12:06   ` Mikael Magnusson
2011-03-11 12:17     ` Peter Stephenson
2011-03-11 12:32       ` Mikael Magnusson
2011-03-11 16:25   ` Peter Stephenson
2011-03-11 16:33     ` Peter Stephenson
2011-03-11 17:09       ` Mikael Magnusson
2011-03-11 18:24         ` Peter Stephenson
2011-03-11 17:44 ` Jérémie Roquet

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