zsh-workers
 help / color / mirror / code / Atom feed
* Working with the historywords special parameter
@ 2001-08-24  6:54 Felix Rosencrantz
  2001-08-24  8:16 ` Sven Wischnowsky
  0 siblings, 1 reply; 7+ messages in thread
From: Felix Rosencrantz @ 2001-08-24  6:54 UTC (permalink / raw)
  To: zsh-workers

I'm trying to create a completer that uses the previous word on the line
and the special parameter historywords to determine what values current
word should be.

It looks to me like there is no single expression that can be used to
get just the list of all the elements that match an expression from an
array.  It seems like you need to iterate over the elements of an array
via an expression like:

    #the_word is $words[CURRENT-1]
    cnt=2
    words=()
    while [[ $historywords[(in:cnt:)the_word] -lt  $#historywords  ]] ; do
       words=($words $historywords[$historywords[(in:cnt:)the_word]-1]
       let "cnt = cnt + 1" 
    done

Is there a faster way to do this?

I'd like to do this with a large historywords (currently I have
4728 elements) doing this takes between 1 and 2 seconds. If I copy
historywords to a temporary array to do the search it goes much faster.
But if the search could be done in one operation, it would be faster and
wouldn't require a temporary copy of historywords.

Would anyone object to a new special parameter (maybe historywordsnums)
that has corresponding elements to historywords saying with which
history line the word is associated?  I ask since one of the problems
with this completer is that it picks up false "matches" when the
previous word is the last word of a previous command, it gets the next command.

It would be nice to be able to determine if a word is the last word of
the line, or what the first word of the line is.

-FR.


__________________________________________________
Do You Yahoo!?
Make international calls for as low as $.04/minute with Yahoo! Messenger
http://phonecard.yahoo.com/


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

* Working with the historywords special parameter
  2001-08-24  6:54 Working with the historywords special parameter Felix Rosencrantz
@ 2001-08-24  8:16 ` Sven Wischnowsky
  2001-08-24 17:05   ` Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Sven Wischnowsky @ 2001-08-24  8:16 UTC (permalink / raw)
  To: zsh-workers


Felix Rosencrantz wrote:

> I'm trying to create a completer that uses the previous word on the line
> and the special parameter historywords to determine what values current
> word should be.
> 
> It looks to me like there is no single expression that can be used to
> get just the list of all the elements that match an expression from an
> array.  It seems like you need to iterate over the elements of an array
> via an expression like:
> 
>     #the_word is $words[CURRENT-1]
>     cnt=2
>     words=()
>     while [[ $historywords[(in:cnt:)the_word] -lt  $#historywords  ]] ; do
>        words=($words $historywords[$historywords[(in:cnt:)the_word]-1]
>        let "cnt = cnt + 1" 
>     done
> 
> Is there a faster way to do this?

I don't see anything faster than:

  local i length cnt=2 words hist
  words=()
  hist=($historywords)
  length=$#hist
  while (( ( i=$hist[(in:cnt++:)$the_word] ) <= length )); do
    words=($words $hist[i-1])
  done

Maybe ${(Mk)historywords:#$the_word} should expand to the list of
the indices of the words equal to $the_word.

> ...
> 
> Would anyone object to a new special parameter (maybe historywordsnums)
> that has corresponding elements to historywords saying with which
> history line the word is associated?  I ask since one of the problems
> with this completer is that it picks up false "matches" when the
> previous word is the last word of a previous command, it gets the next command.
> 
> It would be nice to be able to determine if a word is the last word of
> the line, or what the first word of the line is.

Or maybe give that new array another name and let it report not only
the line but also other information, e.g. the position on the line
(word number and character positions so that that could be used to
index into the values of the history assoc).


Bye
  Sven

-- 
Sven Wischnowsky                    wischnow@informatik.hu-berlin.de


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

* Re: Working with the historywords special parameter
  2001-08-24  8:16 ` Sven Wischnowsky
@ 2001-08-24 17:05   ` Bart Schaefer
  2001-08-28  6:19     ` Felix Rosencrantz
  2001-08-28  6:24     ` Seg Fault in paramsubst() Felix Rosencrantz
  0 siblings, 2 replies; 7+ messages in thread
From: Bart Schaefer @ 2001-08-24 17:05 UTC (permalink / raw)
  To: Felix Rosencrantz, zsh-workers

On Aug 23, 11:54pm, Felix Rosencrantz wrote:
}
} I'm trying to create a completer that uses the previous word on the line
} and the special parameter historywords to determine what values current
} word should be.

Have you tried using $history instead of $historywords?  You want the
word that comes immediately after $words[CURRENT-1] in every history line
that contains $word[CURRENT-1], right?

    local w p h r
    w=${(q)words[CURRENT-1]}
    p=$'\0'$w$'\0'
    h=$'\0'${(pj:\0:)${(z)history[(R)*$w*]}}
    r=( ${${(ps:\1:)h//$~p/$'\1'}%%$'\0'*} )
    compadd -a r

This assumes there are no literal NUL or ctrl-A characters in the history,
but that seems a pretty safe assumption.

} It looks to me like there is no single expression that can be used to
} get just the list of all the elements that match an expression from an
} array.

That's a different question.  You want a list of the indices of all the
elements that match $words[CURRENT-1]?

    integer n=0
    local ixs p="(#b)((#s)(${(q)words[CURRENT-1]})(#e)|*)"
    ixs=( ${${(M)${historywords//$~p/$((++n))=$match[2]}:#<->\=?##}%\=*} )

This takes advantage of the fact that alternate matches with `|' are tried
left to right; it wouldn't work with (*|...).

To get the nth element after the element that matches the word, just
start n at a larger number, e.g. n=1 for your specific example.

} Would anyone object to a new special parameter (maybe historywordsnums)
} that has corresponding elements to historywords saying with which
} history line the word is associated?

I won't object, but it's not really necessary, is it?  You can get it
from ${(k)history[(R)word]}.

On Aug 24, 10:16am, Sven Wischnowsky wrote:
}
} Maybe ${(Mk)historywords:#$the_word} should expand to the list of
} the indices of the words equal to $the_word.

That's an interesting thought.  It's equivalent to what I invented above
but not quite as flexible.


-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* Re: Working with the historywords special parameter
  2001-08-24 17:05   ` Bart Schaefer
@ 2001-08-28  6:19     ` Felix Rosencrantz
  2001-08-28 15:16       ` Bart Schaefer
  2001-08-28  6:24     ` Seg Fault in paramsubst() Felix Rosencrantz
  1 sibling, 1 reply; 7+ messages in thread
From: Felix Rosencrantz @ 2001-08-28  6:19 UTC (permalink / raw)
  To: zsh-workers


--- Bart Schaefer <schaefer@brasslantern.com> wrote:
>Have you tried using $history instead of $historywords?  You want the
>word that comes immediately after $words[CURRENT-1] in every history
>line that contains $word[CURRENT-1], right?
>
>    local w p h r
>    w=${(q)words[CURRENT-1]}
>    p=$'\0'$w$'\0'
>    h=$'\0'${(pj:\0:)${(z)history[(R)*$w*]}}
>    r=( ${${(ps:\1:)h//$~p/$'\1'}%%$'\0'*} )
>    compadd -a r
>
>This assumes there are no literal NUL or ctrl-A characters in the
>history, but that seems a pretty safe assumption.

I tried Sven's suggestion and that worked fine. I then tried Bart's
suggestion, and that worked really fast.  However, there were two
problems.  One a seg fault in the shell when completing for a word that
had either one or no matches  (stack in a separate post).  The other problem
is that it didn't know about line boundaries.  So if the searched for word was
at the end of the line, then it would return a match for the previous
command, which is wrong.

I didn't try Bart's other suggestion for getting indexes.  So don't have
anything to say about that versus a new "M" modifier.

Also, I was wondering if the (z) modifier applied to the elements of history
would always return the same results as found by historywords?

-FR


__________________________________________________
Do You Yahoo!?
Make international calls for as low as $.04/minute with Yahoo! Messenger
http://phonecard.yahoo.com/


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

* Seg Fault in paramsubst()
  2001-08-24 17:05   ` Bart Schaefer
  2001-08-28  6:19     ` Felix Rosencrantz
@ 2001-08-28  6:24     ` Felix Rosencrantz
  2001-08-28  8:35       ` PATCH: " Sven Wischnowsky
  1 sibling, 1 reply; 7+ messages in thread
From: Felix Rosencrantz @ 2001-08-28  6:24 UTC (permalink / raw)
  To: zsh-workers

When using this in my completer I would sometimes get seg faults.  Below
is a stack trace from gdb.  I think this stack trace would only occur if there
were either no matches or just one.  Though it might just happen in one of
those situations.

>    local w p h r
>    w=${(q)words[CURRENT-1]}
>    p=$'\0'$w$'\0'
>    h=$'\0'${(pj:\0:)${(z)history[(R)*$w*]}}
>    r=( ${${(ps:\1:)h//$~p/$'\1'}%%$'\0'*} )
>    compadd -a r
>
-FR

#0  0x80b472e in paramsubst (l=0xbfffbe88, n=0xbfffbe70, str=0xbfffbc58, qt=0, 
    ssub=0) at subst.c:1836
#1  0x80af2ec in stringsubst (list=0xbfffbe88, node=0xbfffbe70, ssub=0, 
    asssub=0) at subst.c:130
#2  0x80aec7f in prefork (list=0xbfffbe88, flags=0) at subst.c:74
#3  0x80af82f in multsub (s=0xbfffc108, a=0xbfffc104, isarr=0xbfffc12c, 
    sep=0x0) at subst.c:282
#4  0x80b216d in paramsubst (l=0xbfffc3f0, n=0xbfffc3e0, str=0xbfffc1b8, qt=0, 
    ssub=4) at subst.c:1065
#5  0x80af2ec in stringsubst (list=0xbfffc3f0, node=0xbfffc3e0, ssub=4, 
    asssub=0) at subst.c:130
#6  0x80aec7f in prefork (list=0xbfffc3f0, flags=6) at subst.c:74
#7  0x8065b6e in addvars (state=0xbfffc4d0, pc=0x8139d5c, export=0)
    at exec.c:1516
#8  0x8063a5e in execsimple (state=0xbfffc4d0) at exec.c:753
#9  0x8063bc8 in execlist (state=0xbfffc4d0, dont_change_job=1, exiting=0)
    at exec.c:806
#10 0x80639c8 in execode (p=0x8139a68, dont_change_job=1, exiting=0)
    at exec.c:729
#11 0x806b388 in runshfunc (prog=0x8139a68, wrap=0x0, 
    name=0x40249b40 "_history_prev_word") at exec.c:3461
#12 0x401cd80f in comp_wrapper (prog=0x8139a68, w=0x0, 
    name=0x40249b40 "_history_prev_word") at complete.c:1271


__________________________________________________
Do You Yahoo!?
Make international calls for as low as $.04/minute with Yahoo! Messenger
http://phonecard.yahoo.com/


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

* PATCH: Re: Seg Fault in paramsubst()
  2001-08-28  6:24     ` Seg Fault in paramsubst() Felix Rosencrantz
@ 2001-08-28  8:35       ` Sven Wischnowsky
  0 siblings, 0 replies; 7+ messages in thread
From: Sven Wischnowsky @ 2001-08-28  8:35 UTC (permalink / raw)
  To: zsh-workers


Felix Rosencrantz wrote:

> When using this in my completer I would sometimes get seg faults.  Below
> is a stack trace from gdb.  I think this stack trace would only occur if there
> were either no matches or just one.  Though it might just happen in one of
> those situations.

bufferwords() might return a NULL pointer, so we should check if it did.
Everywhere.


Bye
  Sven

Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.21
diff -u -r1.21 subst.c
--- Src/subst.c	2001/08/07 10:18:32	1.21
+++ Src/subst.c	2001/08/28 08:32:38
@@ -1833,7 +1833,7 @@
 	} else
 	    list = bufferwords(NULL, val, NULL);
 
-	if (!firstnode(list))
+	if (!list || !firstnode(list))
 	    val = dupstring("");
 	else if (!nextnode(firstnode(list)))
 	    val = getdata(firstnode(list));
Index: Src/Modules/parameter.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/parameter.c,v
retrieving revision 1.21
diff -u -r1.21 parameter.c
--- Src/Modules/parameter.c	2001/07/09 16:05:14	1.21
+++ Src/Modules/parameter.c	2001/08/28 08:32:38
@@ -1105,9 +1105,9 @@
     int i = addhistnum(curhist, -1, HIST_FOREIGN), iw;
     Histent he = gethistent(i, GETHIST_UPWARD);
 
-    ll = bufferwords(NULL, NULL, NULL);
-    for (n = firstnode(ll); n; incnode(n))
-	pushnode(l, getdata(n));
+    if ((ll = bufferwords(NULL, NULL, NULL)))
+        for (n = firstnode(ll); n; incnode(n))
+            pushnode(l, getdata(n));
 
     while (he) {
 	for (iw = he->nwords - 1; iw >= 0; iw--) {
Index: Src/Zle/zle_misc.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_misc.c,v
retrieving revision 1.4
diff -u -r1.4 zle_misc.c
--- Src/Zle/zle_misc.c	2000/05/10 15:01:19	1.4
+++ Src/Zle/zle_misc.c	2001/08/28 08:32:39
@@ -549,13 +549,13 @@
     int i;
     char *p = NULL;
 
-    l = bufferwords(NULL, NULL, &i);
+    if ((l = bufferwords(NULL, NULL, &i)))
+        for (n = firstnode(l); n; incnode(n))
+            if (!i--) {
+                p = getdata(n);
+                break;
+            }
 
-    for (n = firstnode(l); n; incnode(n))
-	if (!i--) {
-	    p = getdata(n);
-	    break;
-	}
     if (p) {
 	int len = strlen(p);
 

-- 
Sven Wischnowsky                    wischnow@informatik.hu-berlin.de


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

* Re: Working with the historywords special parameter
  2001-08-28  6:19     ` Felix Rosencrantz
@ 2001-08-28 15:16       ` Bart Schaefer
  0 siblings, 0 replies; 7+ messages in thread
From: Bart Schaefer @ 2001-08-28 15:16 UTC (permalink / raw)
  To: Felix Rosencrantz, zsh-workers

On Aug 27, 11:19pm, Felix Rosencrantz wrote:
}
} --- Bart Schaefer <schaefer@brasslantern.com> wrote:
} >Have you tried using $history instead of $historywords?  You want the
} >word that comes immediately after $words[CURRENT-1] in every history
} >line that contains $word[CURRENT-1], right?
} >
} >    local w p h r
} >    w=${(q)words[CURRENT-1]}
} >    p=$'\0'$w$'\0'
} >    h=$'\0'${(pj:\0:)${(z)history[(R)*$w*]}}
} >    r=( ${${(ps:\1:)h//$~p/$'\1'}%%$'\0'*} )
} >    compadd -a r
} >
} >This assumes there are no literal NUL or ctrl-A characters in the
} >history, but that seems a pretty safe assumption.
} 
} The other problem is that it didn't know about line boundaries. So if
} the searched for word was at the end of the line, then it would return
} a match for the previous command, which is wrong.

Stick a $'\1' on the end of each line so that $'\0'$w$'\0' won't match
the last word:

    local w p h r
    w=${(q)words[CURRENT-1]}
    p=$'\0'$w$'\0'
    #
    h=( ${^history[(R)*$w*]}$'\1' )
    h=$'\0'${(pj:\0:)${(z)h}}
    r=( ${${(ps:\1:)h//$~p/$'\1'}%%$'\0'*} )
    #
    compadd -a r

To see which is faster, you can replace the three lines between the `#'
with:

    r=()
    for h in $history[(R)*$w*]
    do
	h=$'\0'${(pj:\0:)${(z)h}}
	r[$#r+1]=( ${${(ps:\1:)h//$~p/$'\1'}%%$'\0'*} )
    done

I suspect the first way is faster because it does fewer, though larger,
memory allocations.

The loop body could be one line if not for the need to prepend $'\0' to
the join.

} Also, I was wondering if the (z) modifier applied to the elements of
} history would always return the same results as found by historywords?

No, it won't.  $historywords is more like $=history, but it isn't quite
that either -- the rules for what is a "word" in $historywords are a bit
odd.  E.g., quoted strings are broken up at whitespace, but =(...) are
kept as single words.  Also, it appears that $historywords has the words
from the current input line, whereas $history doesn't get that line added
until after the command has been parsed -- but I'm not sure about that.

I think ${(z)history} is more accurate for purposes of completion.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

end of thread, other threads:[~2001-08-28 15:20 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-08-24  6:54 Working with the historywords special parameter Felix Rosencrantz
2001-08-24  8:16 ` Sven Wischnowsky
2001-08-24 17:05   ` Bart Schaefer
2001-08-28  6:19     ` Felix Rosencrantz
2001-08-28 15:16       ` Bart Schaefer
2001-08-28  6:24     ` Seg Fault in paramsubst() Felix Rosencrantz
2001-08-28  8:35       ` PATCH: " Sven Wischnowsky

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