diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | Doc/Zsh/mod_curses.yo | 41 | ||||
-rw-r--r-- | Src/Modules/curses.c | 134 | ||||
-rw-r--r-- | Src/Modules/curses_keys.awk | 2 |
4 files changed, 164 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog index 0bab7396d..49ca72d62 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,12 +1,18 @@ +2007-10-28 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 24025: Doc/Zsh/mod_curses.yo, Src/Modules/curses.c, + Src/Modules/curses_keys.awk: new zcurses subcommands + "clear" and "position"; "stdscr" window; numerous other tweaks. + 2007-10-26 Peter Stephenson <p.w.stephenson@ntlworld.com> * unposted: Src/curses.c: zcurses input oops. * 24024: configure.ac, Doc/Zsh/mod_curses.yo, - Src/Modules/curses.c: add "zcurses input" for single character - raw input without echoing. Test for wget_wch for wide - character input. Add handling for keypad() mode by - scanning header. + Src/Modules/curses.c, Src/Modules/curses_keys.awk: add "zcurses + input" for single character raw input without echoing. Test for + wget_wch for wide character input. Add handling for keypad() + mode by scanning header. 2007-10-26 Clint Adams <clint@zsh.org> diff --git a/Doc/Zsh/mod_curses.yo b/Doc/Zsh/mod_curses.yo index 266cdea29..81513c5fc 100644 --- a/Doc/Zsh/mod_curses.yo +++ b/Doc/Zsh/mod_curses.yo @@ -15,6 +15,8 @@ xitem(tt(zcurses) tt(addwin) var(targetwin) var(nlines) var(ncols) var(begin_y) 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 @@ 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 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. diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c index 0ea43f1c1..92d906aee 100644 --- a/Src/Modules/curses.c +++ b/Src/Modules/curses.c @@ -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 @@ struct zcurses_subcommand { 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 @@ zcurses_strerror(int err) { 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 @@ zcurses_validate_window(char *win, int criteria) LinkNode target; if (win==NULL || strlen(win) < 1) { - zc_errno = ZCURSES_ERANGE; + zc_errno = ZCURSES_EINVALID; return NULL; } @@ -200,7 +202,7 @@ zcurses_validate_window(char *win, int criteria) 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 @@ freecolorpairnode(HashNode hn) 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 @@ zccmd_delwin(const char *nam, char **args) 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 @@ zccmd_delwin(const char *nam, char **args) return 0; } + static int zccmd_refresh(const char *nam, char **args) { @@ -441,7 +462,7 @@ zccmd_refresh(const char *nam, char **args) } else { - return (refresh() != OK) ? 1 : 0; + return (wrefresh(curscr) != OK) ? 1 : 0; } } @@ -472,6 +493,35 @@ zccmd_move(const char *nam, char **args) 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 @@ zccmd_border(const char *nam, char **args) 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 @@ zccmd_input(const char *nam, char **args) break; case KEY_CODE_YES: + *instr = '\0'; keypadnum = (int)wi; break; @@ -736,8 +789,11 @@ zccmd_input(const char *nam, char **args) } #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 @@ zccmd_input(const char *nam, char **args) 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 @@ zccmd_input(const char *nam, char **args) /* 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 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func)) {"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 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func)) 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); } diff --git a/Src/Modules/curses_keys.awk b/Src/Modules/curses_keys.awk index 55a786521..ffb182c35 100644 --- a/Src/Modules/curses_keys.awk +++ b/Src/Modules/curses_keys.awk @@ -5,7 +5,7 @@ BEGIN {nkeydefs = 0} 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 } } |