summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--Doc/Zsh/mod_curses.yo41
-rw-r--r--Src/Modules/curses.c134
-rw-r--r--Src/Modules/curses_keys.awk2
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
}
}