From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15990 invoked from network); 27 Oct 2007 23:40:15 -0000 X-Spam-Checker-Version: SpamAssassin 3.2.3 (2007-08-08) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-2.5 required=5.0 tests=AWL,BAYES_00 autolearn=ham version=3.2.3 Received: from news.dotsrc.org (HELO a.mx.sunsite.dk) (130.225.247.88) by ns1.primenet.com.au with SMTP; 27 Oct 2007 23:40:15 -0000 Received-SPF: none (ns1.primenet.com.au: domain at sunsite.dk does not designate permitted sender hosts) Received: (qmail 10318 invoked from network); 27 Oct 2007 23:40:09 -0000 Received: from sunsite.dk (130.225.247.90) by a.mx.sunsite.dk with SMTP; 27 Oct 2007 23:40:09 -0000 Received: (qmail 21867 invoked by alias); 27 Oct 2007 23:40:05 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 24025 Received: (qmail 21820 invoked from network); 27 Oct 2007 23:40:02 -0000 Received: from news.dotsrc.org (HELO a.mx.sunsite.dk) (130.225.247.88) by sunsite.dk with SMTP; 27 Oct 2007 23:40:02 -0000 Received: (qmail 9680 invoked from network); 27 Oct 2007 23:40:02 -0000 Received: from mtaout01-winn.ispmail.ntl.com (81.103.221.47) by a.mx.sunsite.dk with SMTP; 27 Oct 2007 23:39:56 -0000 Received: from aamtaout01-winn.ispmail.ntl.com ([81.103.221.35]) by mtaout01-winn.ispmail.ntl.com with ESMTP id <20071027233953.WLXB1783.mtaout01-winn.ispmail.ntl.com@aamtaout01-winn.ispmail.ntl.com> for ; Sun, 28 Oct 2007 00:39:53 +0100 Received: from pws-pc.ntlworld.com ([81.107.45.67]) by aamtaout01-winn.ispmail.ntl.com with ESMTP id <20071027233951.UIVZ219.aamtaout01-winn.ispmail.ntl.com@pws-pc.ntlworld.com> for ; Sun, 28 Oct 2007 00:39:51 +0100 Received: from pws-pc.ntlworld.com (pws-pc.ntlworld.com [127.0.0.1]) by pws-pc.ntlworld.com (8.14.1/8.13.8) with ESMTP id l9RNcq30009273 for ; Sun, 28 Oct 2007 00:38:53 +0100 From: Peter Stephenson To: zsh-workers@sunsite.dk (Zsh hackers list) Subject: PATCH: yet more curses X-Mailers: MH-E 8.0.3; nmh 1.2-20070115cvs; GNU Emacs 22.1.1 Date: Sun, 28 Oct 2007 00:38:52 +0100 Message-ID: <9272.1193528332@pws-pc.ntlworld.com> - "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 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 Web page now at http://homepage.ntlworld.com/p.w.stephenson/