Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: PATCH: command line highlighting



On Thu, 3 Apr 2008 12:33:01 +0100
Peter Stephenson <pws@xxxxxxx> wrote:
> We need to be able to see if a key is read within the time and if it is
> unget it and return (like sit-for in Emacs).  Something like
>   read -kt 1 && zle -U $REPLY
> should work, but I haven't played around with it yet.

The bad news is the timeout didn't work, at least for me.  The good news is
that fixing it up to use zle's (relatively robust) timeout mechanism when
it's reading from zle anyway isn't hard and is more interesting than trying
to understand PPDU sounding frames for 802.11n beamforming calibration.  I
have solid evidence for the last bit, anyway.

I thought about updating the doc for read -t about this, but decided that
would just be confusing: it should "just work".  The granularity and range
for the timeout are smaller than the non-zle case but for reading a key
that should be immaterial.

For reference, the following function highlight-current-word (written as an
autoload file) highlights the current word for 1 second or until a key is
pressed (which is then handled as normal).  This now seems to be working.

##start
highlight-current-word-sub()
{
  local REPLY highlight
  local -a matched_words region_highlight
  autoload -U match-words-by-style
  match-words-by-style

  integer before after

  if (( ${#matched_words[4]} )); then
    highlight=underline
    (( before = ${#matched_words[1]} + ${#matched_words[2]} ))
    (( after = before + ${#matched_words[3]} + ${#matched_words[4]} ))
  else
    highlight=standout
    if (( ${#matched_words[3]} )); then
      (( before = ${#matched_words[1]} + ${#matched_words[2]} + \
	${#matched_words[3]} ))
      (( after = before + ${#matched_words[5]} ))
    else
      (( before = ${#matched_words[1]} ))
      (( after = before + ${#matched_words[2]} + ${#matched_words[5]} ))
    fi
  fi
  region_highlight=("$before $after $highlight")
  zle -R "current word highlighted..."
  read -k -t 1 && zle -U $REPLY
}

highlight-current-word() {
  # allow function to save and restore region_highlight
  highlight-current-word-sub "$@"
  # restore old display
  zle -R
}

highlight-current-word "$@"
##end


Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.189
diff -u -r1.189 builtin.c
--- Src/builtin.c	28 Mar 2008 09:59:09 -0000	1.189
+++ Src/builtin.c	3 Apr 2008 15:10:10 -0000
@@ -4739,6 +4739,7 @@
     int readchar = -1, val, resettty = 0;
     struct ttyinfo saveti;
     char d;
+    long izle_timeout = 0;
 #ifdef MULTIBYTE_SUPPORT
     wchar_t delim = L'\n', wc;
     mbstate_t mbs;
@@ -4900,18 +4901,32 @@
 		timeout = (zlong)mn.u.l * (zlong)1000000;
 	    }
 	}
-	if (readfd == -1 ||
-	    !read_poll(readfd, &readchar, keys && !zleactive, timeout)) {
-	    if (OPT_ISSET(ops,'k') && !zleactive && !isem)
-		settyinfo(&shttyinfo);
-	    else if (resettty && SHTTY != -1)
-	      settyinfo(&saveti);
-	    if (haso) {
-		fclose(shout);
-		shout = oshout;
-		SHTTY = -1;
+	if (izle) {
+	    /*
+	     * Timeout is in 100ths of a second rather than us.
+	     * See calc_timeout() in zle_main for format of this.
+	     */
+	    timeout = -(timeout/(zlong)10000 + 1L);
+	    izle_timeout = (long)timeout;
+#ifdef LONG_MAX
+	    /* saturate if range exceeded */
+	    if ((zlong)izle_timeout != timeout)
+		izle_timeout = LONG_MAX;
+#endif
+	} else {
+	    if (readfd == -1 ||
+		!read_poll(readfd, &readchar, keys && !zleactive, timeout)) {
+		if (OPT_ISSET(ops,'k') && !zleactive && !isem)
+		    settyinfo(&shttyinfo);
+		else if (resettty && SHTTY != -1)
+		    settyinfo(&saveti);
+		if (haso) {
+		    fclose(shout);
+		    shout = oshout;
+		    SHTTY = -1;
+		}
+		return 1;
 	    }
-	    return 1;
 	}
     }
 
@@ -4927,7 +4942,7 @@
 
 	do {
 	    if (izle) {
-		if ((val = getkeyptr(0, NULL)) < 0) {
+		if ((val = getkeyptr(izle_timeout, NULL)) < 0) {
 		    eof = 1;
 		    break;
 		}
@@ -5033,7 +5048,7 @@
 #ifdef MULTIBYTE_SUPPORT
 	    int key;
 
-	    while ((key = getkeyptr(0, NULL)) >= 0) {
+	    while ((key = getkeyptr(izle_timeout, NULL)) >= 0) {
 		char c = (char)key;
 		/*
 		 * If multibyte, it can't be y, so we don't care
@@ -5044,7 +5059,7 @@
 		    break;
 	    }
 #else
-	    int key = getkeyptr(0, NULL);
+	    int key = getkeyptr(izle_timeout, NULL);
 #endif
 
 	    readbuf[0] = (key == 'y' ? 'y' : 'n');
@@ -5087,7 +5102,7 @@
 #endif
 	/* get input, a character at a time */
 	while (!gotnl) {
-	    c = zread(izle, &readchar);
+	    c = zread(izle, &readchar, izle_timeout);
 	    /* \ at the end of a line indicates a continuation *
 	     * line, except in raw mode (-r option)            */
 #ifdef MULTIBYTE_SUPPORT
@@ -5277,7 +5292,7 @@
     if (!gotnl) {
 	sigset_t s = child_unblock();
 	for (;;) {
-	    c = zread(izle, &readchar);
+	    c = zread(izle, &readchar, izle_timeout);
 #ifdef MULTIBYTE_SUPPORT
 	    if (c == EOF) {
 		/* not waiting to be completed any more */
@@ -5418,13 +5433,13 @@
 
 /**/
 static int
-zread(int izle, int *readchar)
+zread(int izle, int *readchar, long izle_timeout)
 {
     char cc, retry = 0;
     int ret;
 
     if (izle) {
-	int c = getkeyptr(0, NULL);
+	int c = getkeyptr(izle_timeout, NULL);
 
 	return (c < 0 ? EOF : c);
     }
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.80
diff -u -r1.80 init.c
--- Src/init.c	12 Dec 2007 13:46:37 -0000	1.80
+++ Src/init.c	3 Apr 2008 15:10:11 -0000
@@ -82,7 +82,7 @@
 /* Pointer to read-key function from zle */
 
 /**/
-mod_export int (*getkeyptr) _((int, int *));
+mod_export int (*getkeyptr) _((long, int *));
 
 /* SIGCHLD mask */
 
Index: Src/Zle/zle_keymap.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_keymap.c,v
retrieving revision 1.28
diff -u -r1.28 zle_keymap.c
--- Src/Zle/zle_keymap.c	10 Sep 2006 18:10:49 -0000	1.28
+++ Src/Zle/zle_keymap.c	3 Apr 2008 15:10:11 -0000
@@ -1363,7 +1363,7 @@
 static int
 getkeybuf(int w)
 {
-    int c = getbyte(w, NULL);
+    int c = getbyte((long)w, NULL);
 
     if(c < 0)
 	return EOF;
Index: Src/Zle/zle_main.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v
retrieving revision 1.105
diff -u -r1.105 zle_main.c
--- Src/Zle/zle_main.c	3 Apr 2008 11:39:12 -0000	1.105
+++ Src/Zle/zle_main.c	3 Apr 2008 15:10:12 -0000
@@ -451,13 +451,22 @@
 /*
  * See if we need a timeout either for a key press or for a
  * timed function.
+ *
+ * do_keytmout is passed down from getbyte() here.  If it is positive,
+ * we the keytimeout value, which is in 100ths of a second (directly set
+ * from the parameter).  If it is negative, we use -(do_keytmout+1)
+ * (i.e. the one's complement, to allow a zero value to be set).  This
+ * is only used when calling into zle from outside to specify an
+ * explicit timeout.  This is also in 100ths of a second.
  */
 
 static void
-calc_timeout(struct ztmout *tmoutp, int do_keytmout)
+calc_timeout(struct ztmout *tmoutp, long do_keytmout)
 {
-    if (do_keytmout && keytimeout > 0) {
-	if (keytimeout > ZMAXTIMEOUT * 100 /* 24 days for a keypress???? */)
+    if (do_keytmout && (keytimeout > 0 || do_keytmout < 0)) {
+	if (do_keytmout < 0)
+	    tmoutp->exp100ths = (time_t)-do_keytmout;
+	else if (keytimeout > ZMAXTIMEOUT * 100 /* 24 days for a keypress???? */)
 	    tmoutp->exp100ths = ZMAXTIMEOUT * 100;
 	else
 	    tmoutp->exp100ths = keytimeout;
@@ -501,8 +510,10 @@
     }
 }
 
+/* see calc_timeout for use of do_keytmout */
+
 static int
-raw_getbyte(int do_keytmout, char *cptr)
+raw_getbyte(long do_keytmout, char *cptr)
 {
     int ret;
     struct ztmout tmout;
@@ -785,9 +796,11 @@
     return ret;
 }
 
+/* see calc_timeout for use of do_keytmout */
+
 /**/
 mod_export int
-getbyte(int do_keytmout, int *timeout)
+getbyte(long do_keytmout, int *timeout)
 {
     char cc;
     unsigned int ret;
@@ -899,7 +912,7 @@
 mod_export ZLE_INT_T
 getfullchar(int do_keytmout)
 {
-    int inchar = getbyte(do_keytmout, NULL);
+    int inchar = getbyte((long)do_keytmout, NULL);
 
 #ifdef MULTIBYTE_SUPPORT
     return getrestchar(inchar);
@@ -962,7 +975,7 @@
 	 * arrive together.  If we don't do this the input can
 	 * get stuck if an invalid byte sequence arrives.
 	 */
-	inchar = getbyte(1, &timeout);
+	inchar = getbyte(1L, &timeout);
 	/* getbyte deliberately resets lastchar_wide_valid */
 	lastchar_wide_valid = 1;
 	if (inchar == EOF) {
Index: Src/Zle/zle_misc.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_misc.c,v
retrieving revision 1.43
diff -u -r1.43 zle_misc.c
--- Src/Zle/zle_misc.c	30 Aug 2007 14:38:27 -0000	1.43
+++ Src/Zle/zle_misc.c	3 Apr 2008 15:10:12 -0000
@@ -619,7 +619,7 @@
      *
      * Hence for now this remains byte-by-byte.
      */
-    while ((gotk = getbyte(0, NULL)) != EOF) {
+    while ((gotk = getbyte(0L, NULL)) != EOF) {
 	if (gotk == '-' && !digcnt) {
 	    minus = -1;
 	    digcnt++;
Index: Src/Zle/zle_vi.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_vi.c,v
retrieving revision 1.14
diff -u -r1.14 zle_vi.c
--- Src/Zle/zle_vi.c	25 Apr 2006 15:00:27 -0000	1.14
+++ Src/Zle/zle_vi.c	3 Apr 2008 15:10:12 -0000
@@ -108,7 +108,7 @@
     char m[3], *str;
     Thingy cmd;
 
-    if (getbyte(0, NULL) == EOF)
+    if (getbyte(0L, NULL) == EOF)
 	return ZLEEOF;
 
     m[0] = lastchar;

-- 
Peter Stephenson <pws@xxxxxxx>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070



Messages sorted by: Reverse Date, Date, Thread, Author