Files
nethack/win/tty/getline.c
Michael Meyer 79cdcff7e4 Fix: msg_window:combination and TTY getlin() ^P
The ability to use ^P from within a TTY getlin prompt didn't work with
msg_window:combination: it's a combination (unsurprisingly) of 'full'
and 'single', but hooked_tty_getlin() was treating it like 'full': i.e.
expecting everything to be displayed at once, with doprev_message()
returning only once the user was finished reading.  I didn't even know
^P was supposed to be accessible from a getlin prompt until Pat's recent
commit 5120764, because I have always used msg_window:combination -- I
had come up with a system where I'd name a potion thrown at me "xx",
check the previous messages with ^P, and then rename it from the
discoveries list.  This will be a lot easier!
2023-11-30 01:06:28 -05:00

327 lines
9.7 KiB
C

/* NetHack 3.7 getline.c $NHDT-Date: 1701285885 2023/11/29 19:24:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.59 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2006. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#ifdef TTY_GRAPHICS
#if !defined(MAC)
#define NEWAUTOCOMP
#endif
#include "wintty.h"
#include "func_tab.h"
char morc = 0; /* tell the outside world what char you chose */
static boolean suppress_history;
static boolean ext_cmd_getlin_hook(char *);
typedef boolean (*getlin_hook_proc)(char *);
static void hooked_tty_getlin(const char *, char *, getlin_hook_proc);
extern int extcmd_via_menu(void); /* cmd.c */
extern char erase_char, kill_char; /* from appropriate tty.c file */
/*
* Read a line closed with '\n' into the array char bufp[BUFSZ].
* (The '\n' is not stored. The string is closed with a '\0'.)
* Reading can be interrupted by an escape ('\033'). If there is already
* some text, it is removed and prompting continues as if from the start.
* However, if there is no text yet (or anymore) then "\033" is returned.
*/
void
tty_getlin(const char *query, register char *bufp)
{
suppress_history = FALSE;
hooked_tty_getlin(query, bufp, (getlin_hook_proc) 0);
}
static void
hooked_tty_getlin(
const char *query,
register char *bufp,
getlin_hook_proc hook)
{
register char *obufp = bufp;
register int c;
struct WinDesc *cw = wins[WIN_MESSAGE];
boolean doprev = FALSE;
if (ttyDisplay->toplin == TOPLINE_NEED_MORE && !(cw->flags & WIN_STOP))
more();
cw->flags &= ~WIN_STOP;
ttyDisplay->toplin = TOPLINE_SPECIAL_PROMPT;
ttyDisplay->inread++;
/*
* Issue the prompt.
*
* custompline() will call vpline() which calls flush_screen() which
* calls bot(). The core now disables bot() processing while inside
* getlin, so the screen won't be modified during whatever this prompt
* is for.
*/
custompline(OVERRIDE_MSGTYPE | SUPPRESS_HISTORY, "%s ", query);
#ifdef EDIT_GETLIN
/* bufp is input/output; treat current contents (presumed to be from
previous getlin()) as default input */
addtopl(obufp);
bufp = eos(obufp);
#else
/* !EDIT_GETLIN: bufp is output only; init it to empty */
*bufp = '\0';
#endif
for (;;) {
(void) fflush(stdout);
Strcat(strcat(strcpy(gt.toplines, query), " "), obufp);
c = pgetchar();
if (c == '\033' || c == EOF) {
if (c == '\033' && obufp[0] != '\0') {
obufp[0] = '\0';
bufp = obufp;
tty_clear_nhwindow(WIN_MESSAGE);
cw->maxcol = cw->maxrow;
addtopl(query);
addtopl(" ");
addtopl(obufp);
} else {
obufp[0] = '\033';
obufp[1] = '\0';
break;
}
}
if (ttyDisplay->intr) {
ttyDisplay->intr--;
*bufp = 0;
}
if (c == C('p')) { /* ctrl-P, doesn't honor rebinding #prevmsg cmd */
int sav = ttyDisplay->inread;
ttyDisplay->inread = 0;
if (iflags.prevmsg_window == 's'
|| (iflags.prevmsg_window == 'c' && !doprev)) {
/* msg_window:single, or msg_window:combination while it's
behaving like msg_window:single */
if (!doprev)
(void) tty_doprev_message(); /* need two initially */
(void) tty_doprev_message();
ttyDisplay->inread = sav;
doprev = TRUE;
continue;
} else {
/* msg_window:full or reverse, or msg_window:combination while
it's behaving like msg_window:full */
(void) tty_doprev_message();
ttyDisplay->inread = sav;
doprev = FALSE;
tty_clear_nhwindow(WIN_MESSAGE);
cw->maxcol = cw->maxrow;
addtopl(query);
addtopl(" ");
*bufp = 0;
addtopl(obufp);
}
} else if (doprev) {
tty_clear_nhwindow(WIN_MESSAGE);
cw->maxcol = cw->maxrow;
doprev = FALSE;
addtopl(query);
addtopl(" ");
*bufp = 0;
addtopl(obufp);
}
if (c == erase_char || c == '\b') {
if (bufp != obufp) {
#ifdef NEWAUTOCOMP
char *i;
#endif /* NEWAUTOCOMP */
bufp--;
#ifndef NEWAUTOCOMP
putsyms("\b \b"); /* putsym converts \b */
#else /* NEWAUTOCOMP */
putsyms("\b");
for (i = bufp; *i; ++i)
putsyms(" ");
for (; i > bufp; --i)
putsyms("\b");
*bufp = 0;
#endif /* NEWAUTOCOMP */
} else
tty_nhbell();
} else if (c == '\n' || c == '\r') {
#ifndef NEWAUTOCOMP
*bufp = 0;
#endif /* not NEWAUTOCOMP */
break;
} else if (' ' <= (unsigned char) c && c != '\177'
/* avoid isprint() - some people don't have it
' ' is not always a printing char */
&& (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO)) {
#ifdef NEWAUTOCOMP
char *i = eos(bufp);
#endif /* NEWAUTOCOMP */
*bufp = c;
bufp[1] = 0;
putsyms(bufp);
bufp++;
if (hook && (*hook)(obufp)) {
putsyms(bufp);
#ifndef NEWAUTOCOMP
bufp = eos(bufp);
#else /* NEWAUTOCOMP */
/* pointer and cursor left where they were */
for (i = bufp; *i; ++i)
putsyms("\b");
} else if (i > bufp) {
char *s = i;
/* erase rest of prior guess */
for (; i > bufp; --i)
putsyms(" ");
for (; s > bufp; --s)
putsyms("\b");
#endif /* NEWAUTOCOMP */
}
} else if (c == kill_char || c == '\177') { /* Robert Viduya */
/* this test last - @ might be the kill_char */
#ifndef NEWAUTOCOMP
while (bufp != obufp) {
bufp--;
putsyms("\b \b");
}
#else /* NEWAUTOCOMP */
for (; *bufp; ++bufp)
putsyms(" ");
for (; bufp != obufp; --bufp)
putsyms("\b \b");
*bufp = 0;
#endif /* NEWAUTOCOMP */
} else
tty_nhbell();
}
ttyDisplay->toplin = TOPLINE_NON_EMPTY;
ttyDisplay->inread--;
clear_nhwindow(WIN_MESSAGE); /* clean up after ourselves */
if (suppress_history) {
/* prevent next message from pushing current query+answer into
tty message history */
*gt.toplines = '\0';
#ifdef DUMPLOG
} else {
/* needed because we've bypassed pline() */
dumplogmsg(gt.toplines);
#endif
}
}
void
xwaitforspace(register const char *s) /* chars allowed besides return */
{
register int c, x = ttyDisplay ? (int) ttyDisplay->dismiss_more : '\n';
morc = 0;
while (
#ifdef HANGUPHANDLING
!gp.program_state.done_hup &&
#endif
(c = tty_nhgetch()) != EOF) {
if (c == '\n' || c == '\r')
break;
if (iflags.cbreak) {
if (c == '\033') {
if (ttyDisplay)
ttyDisplay->dismiss_more = 1;
morc = '\033';
break;
}
if ((s && strchr(s, c)) || c == x || (x == '\n' && c == '\r')) {
morc = (char) c;
break;
}
tty_nhbell();
}
}
}
/*
* Implement extended command completion by using this hook into
* tty_getlin. Check the characters already typed, if they uniquely
* identify an extended command, expand the string to the whole
* command.
*
* Return TRUE if we've extended the string at base. Otherwise return FALSE.
* Assumptions:
*
* + we don't change the characters that are already in base
* + base has enough room to hold our string
*/
static boolean
ext_cmd_getlin_hook(char *base)
{
int *ecmatches;
int nmatches = extcmds_match(base, ECM_NOFLAGS, &ecmatches);
if (nmatches == 1) {
struct ext_func_tab *ec = extcmds_getentry(ecmatches[0]);
Strcpy(base, ec->ef_txt);
return TRUE;
}
return FALSE; /* didn't match anything */
}
/*
* Read in an extended command, doing command line completion. We
* stop when we have found enough characters to make a unique command.
*/
int
tty_get_ext_cmd(void)
{
char buf[BUFSZ];
int nmatches;
int *ecmatches = 0;
boolean (*no_hook)(char *base) = (boolean (*)(char *)) 0;
char extcmd_char[2];
if (iflags.extmenu)
return extcmd_via_menu();
suppress_history = TRUE;
/* maybe a runtime option?
* hooked_tty_getlin("#", buf,
* (flags.cmd_comp && !gi.in_doagain)
* ? ext_cmd_getlin_hook
* : (getlin_hook_proc) 0);
*/
extcmd_char[0] = extcmd_initiator(), extcmd_char[1] = '\0';
buf[0] = '\0';
hooked_tty_getlin(extcmd_char, buf,
!gi.in_doagain ? ext_cmd_getlin_hook : no_hook);
(void) mungspaces(buf);
nmatches = (buf[0] == '\0' || buf[0] == '\033') ? -1
: extcmds_match(buf, ECM_IGNOREAC | ECM_EXACTMATCH, &ecmatches);
if (nmatches != 1) {
if (nmatches != -1)
pline("%s%.60s: unknown extended command.",
visctrl(extcmd_char[0]), buf);
return -1;
}
return ecmatches[0];
}
#endif /* TTY_GRAPHICS */
/*getline.c*/