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

PATCH: yet more curses



- "stdscr" is now addressable as a window (as suggested by Clint); it
can't be deleted normally.
- New "location" subcommand: output cursor position and window start and
end into an array.
- New "clear" subcommand.  This covers the curses clear, erase, clrtoeol
and clrtobot functions.  The default is really erase rather than
clear but again I didn't feel the need to follow curses' not very
helpful nomenclature.
- Fix for refresh: refresh() simply refreshes stdscr, equivalent
to "zcurses refresh stdscr" and it's inconsistent to special-case it
since elsewhere we expect stdscr to be specified.  It is
possible to refresh curscr, and that appears to be the only useful thing
to do with curscr, so "zcurses refresh" does that.  (The link given
below explains about curscr, but I suggest you don't really want to know.)
- Add a test for all subcommands except init and end that init has been
called.  I excepted end since as written "zcurses end" is a no-op
when curses is uninitialised, but other ways of doing it are obviously
conceivable.
- Add missing error message for undefined window.  "out of range" isn't
really an appropriate error now we have strings so I've changed it
to "name invalid".
- Slight sanity fixes for "zcurses input".  I've a feeling there's
something I need to do that occurred to me last night and that
I've forgotten.
- KEY_CODE_YES isn't a proper keypad code.

One fairly authoritative looking description
http://www.linuxfocus.org/English/March2002/article233.shtml
says after endwin() you need to run initscr() again, which we don't,
and apparently we get away with it, so I'm confused.  However, it's
not the only confusing thing about curses by a long chalk.

Index: Doc/Zsh/mod_curses.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_curses.yo,v
retrieving revision 1.11
diff -u -r1.11 mod_curses.yo
--- Doc/Zsh/mod_curses.yo	26 Oct 2007 21:59:56 -0000	1.11
+++ Doc/Zsh/mod_curses.yo	27 Oct 2007 23:35:36 -0000
@@ -15,6 +15,8 @@
 xitem(tt(zcurses) tt(delwin) var(targetwin) )
 xitem(tt(zcurses) tt(refresh) [ var(targetwin) ] )
 xitem(tt(zcurses) tt(move) var(targetwin) var(new_y) var(new_x) )
+xitem(tt(zcurses) tt(clear) var(targetwin) [ tt(redraw) | tt(eol) | tt(bot) ])
+xitem(tt(location) var(targetwin) var(array))
 xitem(tt(zcurses) tt(char) var(targetwin) var(character) )
 xitem(tt(zcurses) tt(string) var(targetwin) var(string) )
 xitem(tt(zcurses) tt(border) var(targetwin) var(border) )(
@@ -29,19 +31,46 @@
 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
 var(begin_x) of the screen.  var(targetwin) is a string and refers
-to the name of a window that is not currently assigned.
+to the name of a window that is not currently assigned.  Note
+in particular the curses convention that vertical values appear
+before horizontal values.
 
 Use tt(delwin) to delete a window created with tt(addwin).  Note
-that tt(end) does em(not) implicitly delete windows.
+that tt(end) does em(not) implicitly delete windows, and that
+tt(delwin) does not erase the screen image of the window.
 
-The tt(refresh) command 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.  If no argument is given,
-all windows are refreshed; this is necessary after deleting a 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
+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.
 
 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
+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).
+These are, in order:
+startsitem()
+sitem()(The y and x coordinates of the cursor relative to the top left
+of var(targetwin))
+sitem()(The y and x coordinates of the top left of var(targetwin) on the
+screen)
+sitem()(The y and x coordinates of the bottom right of var(targetwin)
+on the screen.)
+endsitem()
+
 Outputting characters and strings are achieved by tt(char) and tt(string)
 respectively.
 
Index: Src/Modules/curses.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/curses.c,v
retrieving revision 1.24
diff -u -r1.24 curses.c
--- Src/Modules/curses.c	26 Oct 2007 22:04:51 -0000	1.24
+++ Src/Modules/curses.c	27 Oct 2007 23:35:36 -0000
@@ -53,8 +53,10 @@
 #include <stdio.h>
 
 enum zc_win_flags {
+    /* Window is permanent (probably "stdscr") */
+    ZCWF_PERMANENT = 0x0001,
     /* Scrolling enabled */
-    ZCWF_SCROLL = 0x0001
+    ZCWF_SCROLL = 0x0002
 };
 
 typedef struct zc_win {
@@ -82,13 +84,12 @@
     int maxargs;
 };
 
-static WINDOW *win_zero;
 static struct ttyinfo saved_tty_state;
 static struct ttyinfo curses_tty_state;
 static LinkList zcurses_windows;
 static HashTable zcurses_colorpairs = NULL;
 
-#define ZCURSES_ERANGE 1
+#define ZCURSES_EINVALID 1
 #define ZCURSES_EDEFINED 2
 #define ZCURSES_EUNDEFINED 3
 
@@ -151,11 +152,12 @@
 {
     static const char *errs[] = {
 	"unknown error",
-	"window number out of range",
+	"window name invalid",
 	"window already defined",
+	"window undefined",
 	NULL };
 
-    return errs[(err < 1 || err > 2) ? 0 : err];
+    return errs[(err < 1 || err > 3) ? 0 : err];
 }
 
 static LinkNode
@@ -177,7 +179,7 @@
     LinkNode target;
 
     if (win==NULL || strlen(win) < 1) {
-	zc_errno = ZCURSES_ERANGE;
+	zc_errno = ZCURSES_EINVALID;
 	return NULL;
     }
 
@@ -200,7 +202,7 @@
 static int
 zcurses_free_window(ZCWin w)
 {
-    if (delwin(w->win)!=OK)
+    if (!(w->flags & ZCWF_PERMANENT) && delwin(w->win)!=OK)
 	return 1;
 
     if (w->name)
@@ -317,9 +319,23 @@
 static int
 zccmd_init(const char *nam, char **args)
 {
-    if (!win_zero) {
+    LinkNode stdscr_win = zcurses_getwindowbyname("stdscr");
+
+    if (!stdscr_win) {
+	ZCWin w = (ZCWin)zshcalloc(sizeof(struct zc_win));
+	if (!w)
+	    return 1;
+
 	gettyinfo(&saved_tty_state);
-	win_zero = initscr();
+	w->name = ztrdup("stdscr");
+	w->win = initscr();
+	if (w->win == NULL) {
+	    zsfree(w->name);
+	    zfree(w, sizeof(struct zc_win));
+	    return 1;
+	}
+	w->flags = ZCWF_PERMANENT;
+	zinsertlinknode(zcurses_windows, lastnode(zcurses_windows), (void *)w);
 	if (start_color() != ERR) {
 	    if(!zc_color_phase)
 		zc_color_phase = 1;
@@ -410,6 +426,10 @@
 	zwarnnam(nam, "record for window `%s' is corrupt", args[0]);
 	return 1;
     }
+    if (w->flags & ZCWF_PERMANENT) {
+	zwarnnam(nam, "window `%s' can't be deleted", args[0]);
+	return 1;
+    }
     if (delwin(w->win)!=OK)
 	return 1;
 
@@ -421,6 +441,7 @@
     return 0;
 }
 
+
 static int
 zccmd_refresh(const char *nam, char **args)
 {
@@ -441,7 +462,7 @@
     }
     else
     {
-	return (refresh() != OK) ? 1 : 0;
+	return (wrefresh(curscr) != OK) ? 1 : 0;
     }
 }
 
@@ -472,6 +493,35 @@
 
 
 static int
+zccmd_clear(const char *nam, char **args)
+{
+    LinkNode node;
+    ZCWin w;
+
+    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 (!args[1]) {
+	return werase(w->win) != OK;
+    } else if (!strcmp(args[1], "redraw")) {
+	return wclear(w->win) != OK;
+    } else if (!strcmp(args[1], "eol")) {
+	return wclrtoeol(w->win) != OK;
+    } else if (!strmp(args[1], "bot")) {
+	return wclrtobot(w->win) != OK;
+    } else {
+	zwarnnam(nam, "`clear' expects `redraw', `eol' or `bot'");
+	return 1;
+    }
+}
+
+
+static int
 zccmd_char(const char *nam, char **args)
 {
     LinkNode node;
@@ -574,7 +624,9 @@
 static int
 zccmd_endwin(const char *nam, char **args)
 {
-    if (win_zero) {
+    LinkNode stdscr_win = zcurses_getwindowbyname("stdscr");
+
+    if (stdscr_win) {
 	endwin();
 	/* Restore TTY as it was before zcurses -i */
 	settyinfo(&saved_tty_state);
@@ -727,6 +779,7 @@
 	break;
 
     case KEY_CODE_YES:
+	*instr = '\0';
 	keypadnum = (int)wi;
 	break;
 
@@ -736,8 +789,11 @@
     }
 #else
     ci = wgetch(w->win);
+    if (ci == ERR)
+	return 1;
     if (ci >= 256) {
 	keypadnum = ci;
+	*instr = '\0';
     } else {
 	if (imeta(ci)) {
 	    instr[0] = Meta;
@@ -753,16 +809,17 @@
 	var = args[1];
     else
 	var = "REPLY";
-    if (!setsparam(var, ztrdup(keypadnum > 0 ? "" : instr)))
+    if (!setsparam(var, ztrdup(instr)))
 	return 1;
-    if (args[2]) {
+    if (args[1] && args[2]) {
 	if (keypadnum > 0) {
 	    const struct zcurses_namenumberpair *nnptr;
 	    char fbuf[DIGBUFSIZE+1];
 
 	    for (nnptr = keypad_names; nnptr->name; nnptr++) {
 		if (keypadnum == nnptr->number) {
-		    setsparam(args[2], ztrdup(nnptr->name));
+		    if (!setsparam(args[2], ztrdup(nnptr->name)))
+			return 1;
 		    return 0;
 		}
 	    }
@@ -773,15 +830,51 @@
 		/* print raw number */
 		sprintf(fbuf, "%d", keypadnum);
 	    }
-	    setsparam(args[2], ztrdup(fbuf));
+	    if (!setsparam(args[2], ztrdup(fbuf)))
+		return 1;
 	} else {
-	    setsparam(args[2], ztrdup(""));
+	    if (!setsparam(args[2], ztrdup("")))
+		return 1;
 	}
     }
     return 0;
 }
 
 
+static int
+zccmd_position(const char *nam, char **args)
+{
+    LinkNode node;
+    ZCWin w;
+    int i, intarr[6];
+    char **array, dbuf[DIGBUFSIZE];
+
+    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);
+
+    /* Look no pointers:  these are macros. */
+    if (getyx(w->win, intarr[0], intarr[1]) == ERR ||
+	getbegyx(w->win, intarr[2], intarr[3]) == ERR ||
+	getmaxyx(w->win, intarr[4], intarr[5]) == ERR)
+	return 1;
+
+    array = (char **)zalloc(7*sizeof(char *));
+    for (i = 0; i < 6; i++) {
+	sprintf(dbuf, "%d", intarr[i]);
+	array[i] = ztrdup(dbuf);
+    }
+    array[6] = NULL;
+
+    setaparam(args[1], array);
+    return 0;
+}
+
+
 /*********************
   Main builtin handler
  *********************/
@@ -800,6 +893,8 @@
 	{"delwin", zccmd_delwin, 1, 1},
 	{"refresh", zccmd_refresh, 0, 1},
 	{"move", zccmd_move, 3, 3},
+	{"clear", zccmd_clear, 1, 2},
+	{"position", zccmd_position, 2, 2},
 	{"char", zccmd_char, 2, 2},
 	{"string", zccmd_string, 2, 2},
 	{"border", zccmd_border, 1, 1},
@@ -832,6 +927,13 @@
 	return 1;
     }
 
+    if (zcsc->cmd != zccmd_init && zcsc->cmd != zccmd_endwin &&
+	!zcurses_getwindowbyname("stdscr")) {
+	zwarnnam(nam, "command `%s' can't be used before `zcurses init'",
+		 zcsc->name);
+	return 1;
+    }
+
     return zcsc->cmd(nam, args+1);
 }
 
Index: Src/Modules/curses_keys.awk
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/curses_keys.awk,v
retrieving revision 1.1
diff -u -r1.1 curses_keys.awk
--- Src/Modules/curses_keys.awk	26 Oct 2007 21:59:56 -0000	1.1
+++ Src/Modules/curses_keys.awk	27 Oct 2007 23:35:36 -0000
@@ -5,7 +5,7 @@
     keytail = substr($0, keyindex, 80)
     split(keytail, tmp)
     keynam = substr(tmp[1], 5, 30)
-    if (keynam != "MIN" && keynam != "MAX") {
+    if (keynam != "MIN" && keynam != "MAX" && keynam != "CODE_YES") {
 	name[nkeydefs++] = keynam
     }
 }

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