diff --git a/include/decl.h b/include/decl.h index 1d6882214..745a00ff0 100644 --- a/include/decl.h +++ b/include/decl.h @@ -499,6 +499,7 @@ struct cmd { const char *alphadirchars; /* same as dirchars if !numpad */ const struct ext_func_tab *commands[256]; /* indexed by input character */ char spkeys[NUM_NHKF]; + char extcmd_char; /* key that starts an extended command ('#') */ }; diff --git a/include/extern.h b/include/extern.h index 46d5a326b..e6786e8ea 100644 --- a/include/extern.h +++ b/include/extern.h @@ -260,6 +260,8 @@ extern void cmdq_clear(void); extern char pgetchar(void); extern void pushch(char); extern void savech(char); +extern void savech_extcmd(const char *, boolean); +extern char extcmd_initiator(void); extern int doextcmd(void); extern struct ext_func_tab *extcmds_getentry(int); extern int extcmds_match(const char *, int, int **); diff --git a/src/cmd.c b/src/cmd.c index d796ebc36..f1911c449 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -400,6 +400,43 @@ savech(char ch) return; } +/* perform savech() for the characters of an extended command name; + inserts the '#' first because rhack() no longer does that one + while processing do_extcmd(); + 'str' might be the full command name or maybe just enough to be + unambiguous depending on how the interface handles that--we don't + care as long as ^A feeds back what the interface expects to see */ +void +savech_extcmd(const char *str, boolean addnewline) +{ + int j; + + /* this debuging line might be immediately erased and need ^P to read */ + debugpline1("savech_extcmd(\"%s\")", str); + + if (!g.in_doagain && strcmp(str, "repeat")) { + uchar c = (g.shead > 0) ? (uchar) (g.saveq[g.shead - 1] & 0xff) : 0; + + /* reset saveq unless it holds a prefix */ + if (!c || !g.Cmd.commands[c] + || (g.Cmd.commands[c]->flags & PREFIXCMD) == 0) + savech(0); + + savech(g.Cmd.extcmd_char); + for (j = 0; str[j]; j++) + savech(str[j]); + if (addnewline) + savech('\n'); + } +} + +/* '#' or whatever has been bound to do_extcmd() in its place */ +char +extcmd_initiator(void) +{ + return g.Cmd.extcmd_char; +} + static boolean can_do_extcmd(const struct ext_func_tab *extcmd) { @@ -3683,7 +3720,8 @@ reset_commands(boolean initial) if (backed_dir_cmd) { for (dir = 0; dir < N_DIRS; dir++) { for (mode = 0; mode < N_MOVEMODES; mode++) { - g.Cmd.commands[back_dir_key[dir][mode]] = back_dir_cmd[dir][mode]; + g.Cmd.commands[back_dir_key[dir][mode]] + = back_dir_cmd[dir][mode]; } } } @@ -3766,7 +3804,8 @@ reset_commands(boolean initial) else if (mode == MV_RUSH) di = M(di); } back_dir_key[dir][mode] = di; - back_dir_cmd[dir][mode] = (struct ext_func_tab *) g.Cmd.commands[di]; + back_dir_cmd[dir][mode] + = (struct ext_func_tab *) g.Cmd.commands[di]; g.Cmd.commands[di] = (struct ext_func_tab *) 0; } } @@ -3776,15 +3815,17 @@ reset_commands(boolean initial) for (i = 0; i < N_DIRS; i++) { (void) bind_key_fn(g.Cmd.dirchars[i], move_funcs[i][MV_WALK]); if (!g.Cmd.num_pad) { - (void) bind_key_fn(highc(g.Cmd.dirchars[i]), move_funcs[i][MV_RUN]); + (void) bind_key_fn(highc(g.Cmd.dirchars[i]), + move_funcs[i][MV_RUN]); (void) bind_key_fn(C(g.Cmd.dirchars[i]), move_funcs[i][MV_RUSH]); } else { /* M(number) works when altmeta is on */ (void) bind_key_fn(M(g.Cmd.dirchars[i]), move_funcs[i][MV_RUN]); - /* can't bind highc() or C() of numbers. just use the 5 prefix. */ + /* can't bind highc() or C() of digits. just use the 5 prefix. */ } } update_rest_on_space(); + g.Cmd.extcmd_char = cmd_from_func(doextcmd); } /* called when 'rest_on_space' is toggled, also called by reset_commands() @@ -5170,7 +5211,12 @@ parse(void) } else if (g.in_doagain) { g.command_count = g.last_command_count; } else if (foo && g.Cmd.commands[foo & 0xff] - && g.Cmd.commands[foo & 0xff]->ef_funct == do_repeat) { + /* these shouldn't go into the do-again buffer */ + && (g.Cmd.commands[foo & 0xff]->ef_funct == do_repeat + || g.Cmd.commands[foo & 0xff]->ef_funct == doprev_message + /* this one might get put into the do-again buffer but + only if the interface code tells the core to do it */ + || g.Cmd.commands[foo & 0xff]->ef_funct == doextcmd)) { /* g.command_count will be set again when we re-enter with g.in_doagain set true */ g.command_count = g.last_command_count; diff --git a/win/Qt/qt_xcmd.cpp b/win/Qt/qt_xcmd.cpp index 8755897a6..fff29e649 100644 --- a/win/Qt/qt_xcmd.cpp +++ b/win/Qt/qt_xcmd.cpp @@ -581,7 +581,15 @@ int NetHackQtExtCmdRequestor::get() } if (result() == xcmdNone) exec(); - return result() - 1; + + int ret = result() - 1; + if (!::g.in_doagain) { + if (ret >= 0) + savech_extcmd(::extcmdlist[ret].ef_txt, FALSE); + else + savech(0); + } + return ret; } // Enable only buttons that match the current prompt string diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 644d1cd3f..2a027b094 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -1556,8 +1556,13 @@ X11_get_ext_cmd(void) /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); - if (extended_cmd_selected < 0) + if (extended_cmd_selected < 0) { + if (!g.in_doagain) + savech(0); return -1; + } + if (!g.in_doagain) + savech_extcmd(command_list[extended_cmd_selected], TRUE); return command_indx[extended_cmd_selected]; } diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index b448fc771..f380fc5d4 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -437,7 +437,7 @@ curses_ext_cmd(void) curs_set(1); wrefresh(extwin); - letter = getch(); + letter = pgetchar(); /* pgetchar(cmd.c) implements do-again */ curs_set(0); prompt_width = (int) strlen(cur_choice); matches = 0; @@ -494,8 +494,23 @@ curses_ext_cmd(void) curses_destroy_win(extwin); if (extwin2) curses_destroy_win(extwin2); - if (ret == -1 && *cur_choice) - pline("%s: unknown extended command.", cur_choice); + + if (ret != -1) { + if (!g.in_doagain) + savech_extcmd(cur_choice, TRUE); + } else { + char extcmd_char = extcmd_initiator(); + + if (*cur_choice) + pline("%s%s: unknown extended command.", + visctrl(extcmd_char), cur_choice); + + if (!g.in_doagain) { + savech(0); /* reset do-again buffer */ + if (letter != '\033') + savech(extcmd_char); + } + } return ret; } diff --git a/win/tty/getline.c b/win/tty/getline.c index f94359bdc..98d1461d2 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -271,6 +271,8 @@ tty_get_ext_cmd(void) char buf[BUFSZ]; int nmatches; int *ecmatches; + boolean (*no_hook)(char *base) = (boolean (*)(char *)) 0; + char extcmd_char[2]; if (iflags.extmenu) return extcmd_via_menu(); @@ -282,27 +284,24 @@ tty_get_ext_cmd(void) * ? ext_cmd_getlin_hook * : (getlin_hook_proc) 0); */ + extcmd_char[0] = extcmd_initiator(), extcmd_char[1] = '\0'; buf[0] = '\0'; - hooked_tty_getlin("#", buf, g.in_doagain ? (getlin_hook_proc) 0 - : ext_cmd_getlin_hook); + hooked_tty_getlin(extcmd_char, buf, + !g.in_doagain ? ext_cmd_getlin_hook : no_hook); (void) mungspaces(buf); - if (buf[0] == 0 || buf[0] == '\033') - return -1; - - nmatches = extcmds_match(buf, ECM_IGNOREAC|ECM_EXACTMATCH, &ecmatches); - - if (!g.in_doagain) { - int j; - for (j = 0; buf[j]; j++) - savech(buf[j]); - savech('\n'); - } + nmatches = (buf[0] == '\0' || buf[0] == '\033') ? -1 + : extcmds_match(buf, ECM_IGNOREAC | ECM_EXACTMATCH, &ecmatches); if (nmatches != 1) { - pline("%s: unknown extended command.", buf); + if (nmatches != -1) + pline("%s%.60s: unknown extended command.", + visctrl(extcmd_char[0]), buf); + savech(0); /* reset do-again buffer */ + savech(extcmd_char[0]); return -1; } + savech_extcmd(buf, TRUE); /* savech() for extcmd_char+buf[...]+'\n' */ return ecmatches[0]; } diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 912078033..ba9bb97d8 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1750,12 +1750,12 @@ int get_ext_cmd(void) int mswin_get_ext_cmd(void) { + char cmd[BUFSZ]; int ret; logDebug("mswin_get_ext_cmd()\n"); if (!iflags.wc_popup_dialog) { char c; - char cmd[BUFSZ]; int i, len; int createcaret; @@ -1784,7 +1784,8 @@ mswin_get_ext_cmd(void) break; if (extcmdlist[i].ef_txt == (char *) 0) { - pline("%s: unknown extended command.", cmd); + pline("%s%s: unknown extended command.", + visctrl(extcmd_initiator()), cmd); i = -1; } break; @@ -1825,13 +1826,22 @@ mswin_get_ext_cmd(void) createcaret = 0; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret); - return i; + ret = i; } else { - if (mswin_ext_cmd_window(&ret) == IDCANCEL) - return -1; + cmd[0] = '\0'; + if (mswin_ext_cmd_window(&ret) != IDCANCEL) + Strcpy(cmd, extcmdlist[ret].ef_txt); else - return ret; + ret = -1; } + + if (!g.in_doagain) { + if (ret >= 0) + savech_extcmd(cmd, TRUE); + else + savech(0); + } + return ret; } /*