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

PATCH: zcurses querychar



On Wed, 07 Nov 2007 22:30:06 +0000
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx> wrote:
> I think the big thing missing now is to be able to query characters and
> attributes within windows.

Like so, including wide character support.  I've obsessively rewritten the
manual to refer to subcommands as such; the new bit is at the end of the
changes to the file.

There is a reason after all to have both string and char: string moves
the cursor, char doesn't.

We could probably do with some global querying of state, but otherwise I
think we're in good shape.

I tested it with this function (curses_querychar), which tests quite a
lot of the system (but only in one window).


# Move around the window.  The first line outputs information about
# the character under the cursor.  ASCII keys insert, cursor and backspace
# keys have the obvious effect.  F1 is followed by a key for attribute:
# lower case to turn on, upper case to turn off: bold, dim, reverse, standout,
# underline.  F2 is followed by two colors, for foreground and background:
# two out of (b)lack, (B)lue, (c)yan, (d)efault, (g)reen, (m)agenta,
# (r)ed, (w)hite, (y)ellow.  Any other non-character input aborts.

zmodload zsh/curses

{
  zcurses init

  integer x=0 y=1 i
  local REPLY key attr
  local -a reply color
  while true; do
    zcurses move stdscr $y $x
    zcurses querychar stdscr reply
    zcurses move stdscr 0 0
    reply=(${(qq)reply})
    zcurses string stdscr "($reply)"
    zcurses clear stdscr eol
    zcurses move stdscr $y $x
    zcurses refresh
    zcurses input stdscr REPLY key
    case $key in
      (UP)
      (( y > 1 && y-- ))
      ;;

      (DOWN)
      (( y < LINES-1 && y++ ))
      ;;

      (LEFT)
      (( x > 0 && x-- ))
      ;;

      (RIGHT)
      (( x < COLUMNS-1 && x++ ))
      ;;
      
      (BACKSPACE)
      if (( x > 0 )); then
	(( x-- ))
      elif (( y > 1 )); then
	(( y--, x = LINES-1 ))
      fi
      zcurses move stdscr $y $x
      zcurses char stdscr " "
      ;;

      (F1)
      zcurses input stdscr REPLY
      case $REPLY in
	(b)
	attr=+bold
	;;

	(B)
	attr=-bold
	;;

	(d)
	attr=+dim
	;;

	(D)
	attr=-dim
	;;

	(r)
	attr=+reverse
	;;

	(R)
	attr=-reverse
	;;

	(s)
	attr=+standout
	;;

	(S)
	attr=-standout
	;;

	(u)
	attr=+underline
	;;

	(U)
	attr=-underline
	;;

	(*)
	continue
	;;
      esac
      zcurses attr stdscr $attr
      ;;

      (F2)
      # read fg and bg color
      for (( i = 1; i <= 2; i++ )); do
	zcurses input stdscr
	case $REPLY in
	  (b) color[i]=black;;
	  (B) color[i]=blue;;
	  (c) color[i]=cyan;;
	  (d) color[i]=default;;
	  (g) color[i]=green;;
	  (m) color[i]=magenta;;
	  (r) color[i]=red;;
	  (w) color[i]=white;;
	  (y) color[i]=yellow;;
	  (*) continue 2
	esac
      done
      zcurses attr stdscr $color[1]/$color[2]
      ;;

      ("")
      zcurses char stdscr $REPLY
      if (( x == COLUMNS-1 )); then
	if (( y < LINES-1 )); then
	  (( y++, x = 0 ))
	fi
      else
	(( x++ ))
      fi
      ;;

      (*)
      break
      ;;
    esac
  done

} always {
  zcurses end
}


Index: configure.ac
===================================================================
RCS file: /cvsroot/zsh/zsh/configure.ac,v
retrieving revision 1.77
diff -u -r1.77 configure.ac
--- configure.ac	1 Nov 2007 17:57:57 -0000	1.77
+++ configure.ac	10 Nov 2007 20:19:53 -0000
@@ -1145,7 +1145,7 @@
 	       brk sbrk \
 	       pathconf sysconf \
 	       tgetent tigetflag tigetnum tigetstr setupterm initscr \
-	       setcchar waddwstr wget_wch use_default_colors \
+	       getcchar setcchar waddwstr wget_wch win_wch use_default_colors \
 	       pcre_compile pcre_study pcre_exec \
 	       nl_langinfo \
 	       erand48 open_memstream \
Index: Doc/Zsh/mod_curses.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_curses.yo,v
retrieving revision 1.20
diff -u -r1.20 mod_curses.yo
--- Doc/Zsh/mod_curses.yo	7 Nov 2007 22:35:15 -0000	1.20
+++ Doc/Zsh/mod_curses.yo	10 Nov 2007 20:19:54 -0000
@@ -26,14 +26,16 @@
 xitem(tt(zcurses) tt(scroll) var(targetwin) [ tt(on) | tt(off) | {+/-}var(lines) ])
 xitem(tt(zcurses) tt(input) var(targetwin) [ var(param) [ var(kparam) [ var(mparam) ] ] ])
 xitem(tt(zcurses) tt(mouse) [ tt(delay) var(num) | {+/-}tt(motion) ])
-item(tt(zcurses) tt(timeout) var(targetwin) var(intval))(
+xitem(tt(zcurses) tt(timeout) var(targetwin) var(intval))
+item(tt(zcurses) tt(querychar) var(targetwin) [ var(param) ])(
 Manipulate curses windows.  All uses of this command should be
 bracketed by `tt(zcurses init)' to initialise use of curses, and
 `tt(zcurses end)' to end it; omitting `tt(zcurses end)' can cause
 the terminal to be in an unwanted state.
 
-With tt(addwin), create a window with var(nlines) lines and var(ncols) columns.
-Its upper left corner will be placed at row var(begin_y) and column
+The subcommand tt(addwin) creates a window with var(nlines) lines and
+var(ncols) columns.  Its upper left corner will be placed at row
+var(begin_y) and column
 var(begin_x) of the screen.  var(targetwin) is a string and refers
 to the name of a window that is not currently assigned.  Note
 in particular the curses convention that vertical values appear
@@ -46,37 +48,40 @@
 Note that the coordinates of subwindows are relative to the screen, not
 the parent, as with other windows.
 
-Use tt(delwin) to delete a window created with tt(addwin).  Note
-that tt(end) does em(not) implicitly delete windows, and that
-tt(delwin) does not erase the screen image of the window.
+Use the subcommand tt(delwin) to delete a window created with
+tt(addwin).  Note that tt(end) does em(not) implicitly delete windows,
+and that tt(delwin) does not erase the screen image of the window.
 
 The window corresponding to the full visible screen is called
 tt(stdscr); it always exists after `tt(zcurses init)' and cannot
 be delete with tt(delwin).
 
-The tt(refresh) command will refresh window var(targetwin); this is
+The subcommand tt(refresh) will refresh window var(targetwin); this is
 necessary to make any pending changes (such as characters you have
 prepared for output with tt(char)) visible on the screen.  tt(refresh)
 without an argument causes the screen to be cleared and redrawn.
 If multiple windows are given, the screen is updated once at the end.
 
-The tt(touch) command marks the var(targetwin)s listed as changed.
+The subcommand tt(touch) marks the var(targetwin)s listed as changed.
 This is necessary before tt(refresh)ing windows if a window that
 was in front of another window (which may be tt(stdscr)) is deleted.
 
-tt(move) moves the cursor position in var(targetwin) to new coordinates
-var(new_y) and var(new_x).
-
-tt(clear) erases the contents of var(targetwin).  One (and no more than one)
-of three options may be specified.  With the option tt(redraw),
-in addition the next tt(refresh) of var(targetwin) will cause the screen to be
-cleared and repainted.  With the option tt(eol), var(targetwin) is only
-cleared to the end of the current cursor line.  With the option
+The subcommand tt(move) moves the cursor position in var(targetwin) to
+new coordinates var(new_y) and var(new_x).  Note that the 
+subcommand tt(string) (but not the subcommand tt(char)) advances the
+cursor position over the characters added.
+
+The subcommand tt(clear) erases the contents of var(targetwin).  One
+(and no more than one) of three options may be specified.  With the
+option tt(redraw), in addition the next tt(refresh) of var(targetwin)
+will cause the screen to be cleared and repainted.  With the option
+tt(eol), var(targetwin) is only cleared to the end of the current cursor
+line.  With the option
 tt(bot), var(targetwin) is cleared to the end of the window, i.e
 everything to the right and below the cursor is cleared.
 
-tt(location) writes various positions associated with var(targetwin)
-into the array named var(array).
+The subcommand tt(location) writes various positions associated with
+var(targetwin) into the array named var(array).
 These are, in order:
 startsitem()
 sitem()(The y and x coordinates of the cursor relative to the top left
@@ -94,12 +99,12 @@
 the border is simply a set of characters output at the edge of the
 window.  Hence it can be overwritten, can scroll off the window, etc.
 
-tt(attr) will set var(targetwin)'s attributes or foreground/background
-color pair for any successive character output.  Each var(attribute)
-given on the line may be prepended by a tt(+) to set or a tt(-) to
-unset that attribute; tt(+) is assumed if absent.  The attributes
-supported are tt(blink), tt(bold), tt(dim), tt(reverse), tt(standout),
-and tt(underline).
+The subcommand tt(attr) will set var(targetwin)'s attributes or
+foreground/background color pair for any successive character output.
+Each var(attribute) given on the line may be prepended by a tt(+) to set
+or a tt(-) to unset that attribute; tt(+) is assumed if absent.  The
+attributes supported are tt(blink), tt(bold), tt(dim), tt(reverse),
+tt(standout), and tt(underline).
 
 Each var(fg_col)tt(/)var(bg_col) attribute (to be read as
 `var(fg_col) on var(bg_col)') sets the foreground and background color
@@ -118,18 +123,19 @@
 of attributes override the existing background, turning attributes
 off in the arguments is not useful, though this does not cause an error.
 
-tt(scroll) can be used with tt(on) or tt(off) to enabled or disable
-scrolling of a window when the cursor would otherwise move below the
-window due to typing or output.  It can also be used with a positive
-or negative integer to scroll the window up or down the given number
-of lines without changing the current cursor position (which therefore
-appears to move in the opposite direction relative to the window).
-In the second case, if scrolling is tt(off) it is temporarily turned tt(on)
-to allow the window to be scrolled.
-
-tt(input) reads a single character from the window without echoing
-it back.  If var(param) is supplied the character is assigned to the
-parameter var(param), else it is assigned to the parameter var(REPLY).
+The subcommand tt(scroll) can be used with tt(on) or tt(off) to enabled
+or disable scrolling of a window when the cursor would otherwise move
+below the window due to typing or output.  It can also be used with a
+positive or negative integer to scroll the window up or down the given
+number of lines without changing the current cursor position (which
+therefore appears to move in the opposite direction relative to the
+window).  In the second case, if scrolling is tt(off) it is temporarily
+turned tt(on) to allow the window to be scrolled.
+
+The subcommand tt(input) reads a single character from the window
+without echoing it back.  If var(param) is supplied the character is
+assigned to the parameter var(param), else it is assigned to the
+parameter var(REPLY).
 
 If both var(param) and var(kparam) are supplied, the key is read in
 `keypad' mode.  In this mode special keys such as function keys and
@@ -184,13 +190,22 @@
 which are always reported.  However, it appears reports for mouse
 motion are not currently implemented.
 
-tt(timeout) specifies a timeout value for input from var(targetwin).
-If var(intval) is negative, `tt(zcurses input)' waits indefinitely for
-a character to be typed; this is the default.  If var(intval) is zero,
-`tt(zcurses input)' returns immediately; if there is typeahead it is
-returned, else no input is done and status 1 is returned.  If var(intval)
-is positive, `tt(zcurses input)' waits var(intval) milliseconds for
-input and if there is none at the end of that period returns status 1.
+The subcommand tt(timeout) specifies a timeout value for input from
+var(targetwin).  If var(intval) is negative, `tt(zcurses input)' waits
+indefinitely for a character to be typed; this is the default.  If
+var(intval) is zero, `tt(zcurses input)' returns immediately; if there
+is typeahead it is returned, else no input is done and status 1 is
+returned.  If var(intval) is positive, `tt(zcurses input)' waits
+var(intval) milliseconds for input and if there is none at the end of
+that period returns status 1.
+
+The subcommand tt(querychar) queries the character at the current cursor
+position.  The return values are stored in the array named var(param) if
+supplied, else in the array tt(reply).  The first value is the character
+(which may be a multibyte character if the system supports them); the
+second is the color pair in the usual var(fg_col)tt(/)var(bg_col)
+notation.  Any attributes other than color that apply to the character,
+as set with the subcommand tt(attr), appear as additional elements.
 )
 enditem()
 
Index: Src/Modules/curses.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/curses.c,v
retrieving revision 1.37
diff -u -r1.37 curses.c
--- Src/Modules/curses.c	8 Nov 2007 12:13:20 -0000	1.37
+++ Src/Modules/curses.c	10 Nov 2007 20:19:54 -0000
@@ -41,9 +41,11 @@
 #endif
 
 #ifndef MULTIBYTE_SUPPORT
+# undef HAVE_GETCCHAR
 # undef HAVE_SETCCHAR
 # undef HAVE_WADDWSTR
 # undef HAVE_WGET_WCH
+# undef HAVE_WIN_WCH
 #endif
 
 #ifdef HAVE_SETCCHAR
@@ -379,6 +381,25 @@
     return cpn;
 }
 
+static Colorpairnode cpn_match;
+
+static void
+zcurses_colornode(HashNode hn, int cp)
+{
+    Colorpairnode cpn = (Colorpairnode)hn;
+    if (cpn->colorpair == (short)cp)
+	cpn_match = cpn;
+}
+
+static Colorpairnode
+zcurses_colorget_reverse(short cp)
+{
+    cpn_match = NULL;
+    scanhashtable(zcurses_colorpairs, 0, 0, 0,
+		  zcurses_colornode, cp);
+    return cpn_match;
+}
+
 static void
 freecolorpairnode(HashNode hn)
 {
@@ -1302,6 +1323,100 @@
 
 
 static int
+zccmd_querychar(const char *nam, char **args)
+{
+    LinkNode node;
+    ZCWin w;
+    short cp;
+    Colorpairnode cpn;
+    const struct zcurses_namenumberpair *zattrp;
+    LinkList clist;
+#if defined(HAVE_WIN_WCH) && defined(HAVE_GETCCHAR)
+    wchar_t c;
+    cchar_t cc;
+    attr_t attrs;
+    int count;
+    VARARR(char, instr, 2*MB_CUR_MAX+1);
+#else
+    chtype inc;
+    char instr[3];
+#endif
+
+    node = zcurses_validate_window(args[0], ZCURSES_USED);
+    if (node == NULL) {
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
+	return 1;
+    }
+
+    w = (ZCWin)getdata(node);
+
+#if defined(HAVE_WIN_WCH) && defined(HAVE_GETCCHAR)
+    if (win_wch(w->win, &cc) == ERR)
+	return 1;
+
+    if (getcchar(&cc, &c, &attrs, &cp, NULL) == ERR)
+	return 1;
+    /* Hmmm... I always get 0 for cp, whereas the following works... */
+    cp = PAIR_NUMBER(winch(w->win));
+
+    count = wctomb(instr, c);
+    if (count == -1)
+	return 1;
+    (void)metafy(instr, count, META_NOALLOC);
+#else
+    inc = winch(w->win);
+    /* I think the following is correct, the manual is a little terse */
+    cp = PAIR_NUMBER(inc);
+    inc &= A_CHARTEXT;
+    if (imeta(inc)) {
+	instr[0] = Meta;
+	instr[1] = STOUC(inc ^ 32);
+	instr[2] = '\0';
+    } else {
+	instr[0] = STOUC(inc);
+	instr[1] = '\0';
+    }
+    /*
+     * I'm guessing this is OK... header says attr_t must be at
+     * least as wide as chtype.
+     */
+    attrs = (attr_t)inc;
+#endif
+
+    /*
+     * Attribute numbers vary, so make a linked list.
+     * This also saves us from doing the permanent allocation till
+     * the end.
+     */
+    clist = newlinklist();
+    /* First the (possibly multibyte) character itself. */
+    addlinknode(clist, instr);
+    /*
+     * Next the colo[u]r.
+     * We should be able to match it in the colorpair list, but
+     * if some reason we can't, fail safe and output the number.
+     */
+    cpn = zcurses_colorget_reverse(cp);
+    if (cpn) {
+	addlinknode(clist, cpn->node.nam);
+    } else {
+	/* report color pair number */
+	char digits[DIGBUFSIZE];
+	sprintf(digits, "%d", (int)cp);
+	addlinknode(clist, digits);
+    }
+    /* Now see what attributes are present. */
+    for (zattrp = zcurses_attributes; zattrp->name; zattrp++) {
+	if (attrs & zattrp->number)
+	    addlinknode(clist, zattrp->name);
+    }
+
+    /* Turn this into an array and store it. */
+    return !setaparam(args[1] ? args[1] : "reply", zlinklist2array(clist));
+}
+
+
+static int
 zccmd_touch(const char *nam, char **args)
 {
     LinkNode node;
@@ -1354,6 +1469,7 @@
 	{"input", zccmd_input, 1, 4},
 	{"timeout", zccmd_timeout, 2, 2},
 	{"mouse", zccmd_mouse, 0, -1},
+	{"querychar", zccmd_querychar, 1, 2},
 	{"touch", zccmd_touch, 1, -1},
 	{NULL, (zccmd_t)0, 0, 0}
     };


-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



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