Commit f9fb4533 authored by Thomas Roessler's avatar Thomas Roessler

Vikas' macro_function patch.

parent ee4d0e31
......@@ -182,11 +182,8 @@ AC_DEFUN(AM_WITH_NLS,
if test "$gt_cv_func_gettext_libc" != "yes"; then
AC_CHECK_LIB(intl, bindtextdomain,
[AC_CACHE_CHECK([for gettext in libintl],
gt_cv_func_gettext_libintl,
[AC_CHECK_LIB(intl, gettext,
gt_cv_func_gettext_libintl=yes,
gt_cv_func_gettext_libintl=no)],
[AC_CHECK_LIB(intl, gettext,
gt_cv_func_gettext_libintl=yes,
gt_cv_func_gettext_libintl=no)])
fi
......
......@@ -125,6 +125,7 @@ void mutt_alias_menu (char *buf, size_t buflen, ALIAS *aliases)
int t = -1;
int i, done = 0;
char helpstr[SHORT_STRING];
int savedmenu = CurrentMenu;
if (!aliases)
{
......@@ -139,7 +140,7 @@ void mutt_alias_menu (char *buf, size_t buflen, ALIAS *aliases)
menu->make_entry = alias_entry;
menu->search = alias_search;
menu->tag = alias_tag;
menu->menu = MENU_ALIAS;
menu->menu = CurrentMenu = MENU_ALIAS;
menu->title = _("Aliases");
menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_ALIAS, AliasHelp);
......@@ -188,5 +189,6 @@ void mutt_alias_menu (char *buf, size_t buflen, ALIAS *aliases)
rfc822_write_address (buf, buflen, AliasTable[t]->addr);
mutt_menuDestroy (&menu);
CurrentMenu = savedmenu;
safe_free ((void **) &AliasTable);
}
......@@ -465,6 +465,7 @@ void mutt_select_file (char *f, size_t flen, int buffy)
MUTTMENU *menu;
struct stat st;
int i, killPrefix = 0;
int savedmenu = CurrentMenu;
memset (&state, 0, sizeof (struct browser_state));
......@@ -515,7 +516,7 @@ void mutt_select_file (char *f, size_t flen, int buffy)
return;
menu = mutt_new_menu ();
menu->menu = MENU_FOLDER;
menu->menu = CurrentMenu = MENU_FOLDER;
menu->make_entry = folder_entry;
menu->search = select_file_search;
menu->title = title;
......@@ -624,6 +625,7 @@ void mutt_select_file (char *f, size_t flen, int buffy)
destroy_state (&state);
mutt_menuDestroy (&menu);
CurrentMenu = savedmenu;
return;
case OP_BROWSER_TELL:
......@@ -662,6 +664,7 @@ void mutt_select_file (char *f, size_t flen, int buffy)
mutt_error _("Error scanning directory.");
destroy_state (&state);
mutt_menuDestroy (&menu);
CurrentMenu = savedmenu;
return;
}
}
......@@ -718,6 +721,7 @@ void mutt_select_file (char *f, size_t flen, int buffy)
{
mutt_error _("Error scanning directory.");
mutt_menuDestroy (&menu);
CurrentMenu = savedmenu;
return;
}
killPrefix = 0;
......@@ -736,6 +740,7 @@ void mutt_select_file (char *f, size_t flen, int buffy)
{
int reverse = 0;
event_t ch;
move (LINES - 1, 0);
if (i == OP_SORT_REVERSE)
......@@ -747,18 +752,21 @@ void mutt_select_file (char *f, size_t flen, int buffy)
}
clrtoeol ();
while ((i = mutt_getch ()) != EOF && i != 'a' && i != 'd' && i != 'z'
&& i != 'n')
FOREVER
{
if (i == ERR || CI_is_return (i))
ch = mutt_getch();
if (ch.ch == EOF || ch.ch == 'a' || ch.ch == 'd' || ch.ch == 'z' || ch.ch == 'n')
break;
if (ch.ch == ERR || CI_is_return (ch.ch))
break;
else
BEEP ();
}
if (i != EOF)
if (ch.ch != EOF)
{
switch (i)
switch (ch.ch)
{
case 'a':
BrowserSort = reverse | SORT_SUBJECT;
......@@ -805,6 +813,7 @@ void mutt_select_file (char *f, size_t flen, int buffy)
strfcpy (f, buf, flen);
destroy_state (&state);
mutt_menuDestroy (&menu);
CurrentMenu = savedmenu;
return;
}
MAYBE_REDRAW (menu->redraw);
......
......@@ -221,7 +221,7 @@ int mutt_display_message (HEADER *cur)
mutt_set_flag (Context, cur, M_READ, 1);
if (option (OPTPROMPTAFTER))
{
mutt_ungetch (mutt_any_key_to_continue _("Command: "));
mutt_ungetch (mutt_any_key_to_continue _("Command: "), 0);
rc = km_dokey (MENU_PAGER);
}
else
......@@ -393,7 +393,7 @@ int mutt_pipe_message (HEADER *h)
int mutt_select_sort (int reverse)
{
int method = Sort; /* save the current method in case of abort */
int ch;
event_t ch;
Sort = 0;
while (!Sort)
......@@ -403,13 +403,13 @@ int mutt_select_sort (int reverse)
_("Rev-Sort (d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore?: ") :
_("Sort (d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore?: "));
ch = mutt_getch ();
if (ch == ERR || CI_is_return (ch))
if (ch.ch == -1 || CI_is_return (ch.ch))
{
Sort = method;
CLEARLINE (LINES-1);
return (-1);
}
switch (ch)
switch (ch.ch)
{
case 'c':
Sort = SORT_SCORE;
......
......@@ -435,11 +435,12 @@ int mutt_compose_menu (HEADER *msg, /* structure for new message */
/* Sort, SortAux could be changed in mutt_index_menu() */
int oldSort = Sort, oldSortAux = SortAux;
struct stat st;
int savedmenu = CurrentMenu;
idx = mutt_gen_attach_list (msg->content, idx, &idxlen, &idxmax, 0, 1);
menu = mutt_new_menu ();
menu->menu = MENU_COMPOSE;
menu->menu = CurrentMenu = MENU_COMPOSE;
menu->offset = HDR_ATTACH;
menu->max = idxlen;
menu->make_entry = snd_entry;
......@@ -1105,6 +1106,7 @@ int mutt_compose_menu (HEADER *msg, /* structure for new message */
}
mutt_menuDestroy (&menu);
CurrentMenu = savedmenu;
if (idxlen)
{
......
This diff is collapsed.
......@@ -3,7 +3,7 @@ AC_INIT(mutt.h)
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(mutt, 0.94.10)
ALL_LINGUAS="de"
ALL_LINGUAS="de ru"
AC_CANONICAL_HOST
......
......@@ -35,9 +35,8 @@
* buffering routines.
*/
static short UngetCount = 0;
#define UngetBufLen 128
static int UngetBuf[UngetBufLen];
static event_t KeyEvent[UngetBufLen] = { {0,0} };
void mutt_refresh (void)
{
......@@ -46,12 +45,13 @@ void mutt_refresh (void)
refresh ();
}
int mutt_getch (void)
event_t mutt_getch (void)
{
int ch;
event_t err = {-1,0}, ret;
if (UngetCount)
return (UngetBuf[--UngetCount]);
return (KeyEvent[--UngetCount]);
Signals &= ~S_INTERRUPT;
......@@ -66,17 +66,21 @@ int mutt_getch (void)
mutt_query_exit ();
if(ch == -1)
return ch;
return err;
if ((ch & 0x80) && option (OPTMETAKEY))
{
/* send ALT-x as ESC-x */
ch &= ~0x80;
mutt_ungetch (ch);
return ('\033');
mutt_ungetch (ch, 0);
ret.ch = '\033';
ret.op = 0;
return ret;
}
return (ch == ctrl ('G') ? ERR : ch);
ret.ch = ch;
ret.op = 0;
return (ch == ctrl ('G') ? err : ret);
}
int mutt_get_field (/* const */ char *field, char *buf, size_t buflen, int complete)
......@@ -126,7 +130,7 @@ void mutt_edit_file (const char *editor, const char *data)
int mutt_yesorno (const char *msg, int def)
{
int ch;
event_t ch;
const char *yes = _("yes");
const char *no = _("no");
......@@ -137,15 +141,15 @@ int mutt_yesorno (const char *msg, int def)
{
mutt_refresh ();
ch = mutt_getch ();
if (ch == ERR) return(-1);
if (CI_is_return (ch))
if (ch.ch == ERR) return(-1);
if (CI_is_return (ch.ch))
break;
else if (tolower(ch) == tolower(*yes))
else if (tolower(ch.ch) == tolower(*yes))
{
def = 1;
break;
}
else if (tolower(ch) == tolower(*no))
else if (tolower(ch.ch) == tolower(*no))
{
def = 0;
break;
......@@ -297,7 +301,7 @@ int mutt_do_pager (const char *banner,
int mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw, int buffy)
{
int i;
event_t ch;
mvaddstr (LINES-1, 0, (char *) prompt);
addstr (_(" ('?' for list): "));
......@@ -306,12 +310,13 @@ int mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw, i
clrtoeol ();
mutt_refresh ();
if ((i = mutt_getch ()) == ERR)
ch = mutt_getch();
if (ch.ch == -1)
{
CLEARLINE (LINES-1);
return (-1);
}
else if (i == '?')
else if (ch.ch == '?')
{
mutt_refresh ();
buf[0] = 0;
......@@ -323,7 +328,7 @@ int mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw, i
char *pc = safe_malloc (strlen (prompt) + 3);
sprintf (pc, "%s: ", prompt);
mutt_ungetch (i);
mutt_ungetch (ch.ch, 0);
if (mutt_get_field (pc, buf, blen, (buffy ? M_EFILE : M_FILE) | M_CLEAR)
!= 0)
buf[0] = 0;
......@@ -337,10 +342,15 @@ int mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw, i
/* FOO - this could be made more efficient by allocating/deallocating memory
* instead of using a fixed array
*/
void mutt_ungetch (int ch)
void mutt_ungetch (int ch, int op)
{
event_t tmp;
tmp.ch = ch;
tmp.op = op;
if (UngetCount < UngetBufLen) /* make sure not to overflow */
UngetBuf[UngetCount++] = ch;
KeyEvent[UngetCount++] = tmp;
}
void mutt_flushinp (void)
......
......@@ -241,7 +241,8 @@ struct mapping_t IndexHelp[] = {
int mutt_index_menu (void)
{
char buf[LONG_STRING], helpstr[SHORT_STRING];
int op = OP_NULL; /* function to execute */
int op = OP_NULL;
event_t event = {OP_NULL, 0};
int done = 0; /* controls when to exit the "event" loop */
int i = 0, j;
int tag = 0; /* has the tag-prefix command been pressed? */
......@@ -254,9 +255,10 @@ int mutt_index_menu (void)
int do_buffy_notify = 1;
int close = 0; /* did we OP_QUIT or OP_EXIT out of this menu? */
int attach_msg = option(OPTATTACHMSG);
int savedmenu = CurrentMenu;
menu = mutt_new_menu ();
menu->menu = MENU_MAIN;
menu->menu = CurrentMenu = MENU_MAIN;
menu->offset = 1;
menu->pagelen = LINES - 3;
menu->make_entry = index_make_entry;
......@@ -474,25 +476,26 @@ int mutt_index_menu (void)
if (Timeout > 0)
{
timeout (Timeout * 1000); /* milliseconds */
op = mutt_getch ();
event = mutt_getch ();
timeout (-1); /* restore blocking operation */
if (op != -1)
if (event.ch != -1)
{
mutt_ungetch (op);
mutt_ungetch (event.ch, event.op);
op = km_dokey (MENU_MAIN);
}
}
else
op = km_dokey (MENU_MAIN);
mutt_curs_set (1);
mutt_curs_set (1);
#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
if (Signals & S_SIGWINCH)
{
mutt_flushinp ();
mutt_resize_screen ();
menu->redraw = REDRAW_FULL;
menu->menu = MENU_MAIN;
menu->menu = CurrentMenu = MENU_MAIN;
Signals &= ~S_SIGWINCH;
menu->top = 0; /* so we scroll the right amount */
continue;
......@@ -591,7 +594,7 @@ int mutt_index_menu (void)
case OP_JUMP:
CHECK_MSGCOUNT;
mutt_ungetch (LastKey);
mutt_ungetch (LastKey, 0);
buf[0] = 0;
if (mutt_get_field (_("Jump to message: "), buf, sizeof (buf), 0) != 0
|| !buf[0])
......@@ -957,7 +960,7 @@ int mutt_index_menu (void)
menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
}
menu->menu = MENU_PAGER;
menu->menu = CurrentMenu = MENU_PAGER;
menu->oldcurrent = menu->current;
continue;
......@@ -1461,6 +1464,7 @@ int mutt_index_menu (void)
case OP_ENTER_COMMAND:
CurrentMenu = MENU_MAIN;
mutt_enter_command ();
mutt_check_rescore (Context);
if (option (OPTNEEDRESORT) && Context && Context->msgcount)
......@@ -1706,7 +1710,7 @@ int mutt_index_menu (void)
if (menu->menu == MENU_PAGER)
{
menu->menu = MENU_MAIN;
menu->menu = CurrentMenu = MENU_MAIN;
menu->redraw = REDRAW_FULL;
set_option (OPTWEED); /* turn header weeding back on. */
}
......@@ -1715,6 +1719,7 @@ int mutt_index_menu (void)
}
mutt_menuDestroy (&menu);
CurrentMenu = savedmenu;
return (close);
}
......
......@@ -53,6 +53,7 @@ enum
int mutt_enter_string (unsigned char *buf, size_t buflen, int y, int x,
int flags)
{
event_t event;
int curpos = 0; /* the location of the cursor */
int lastchar = 0; /* offset of the last char in the string */
int begin = 0; /* first character displayed on the line */
......@@ -122,7 +123,7 @@ int mutt_enter_string (unsigned char *buf, size_t buflen, int y, int x,
return (-1);
}
if (ch != 0)
if (ch != OP_NULL)
{
first = 0; /* make sure not to clear the buffer */
if (ch != OP_EDITOR_COMPLETE)
......@@ -414,7 +415,8 @@ int mutt_enter_string (unsigned char *buf, size_t buflen, int y, int x,
case OP_EDITOR_QUOTE_CHAR:
ADDCH (LastKey);
LastKey = mutt_getch ();
event = mutt_getch ();
LastKey = event.ch;
move (y, x + curpos - begin);
goto self_insert;
......@@ -436,7 +438,7 @@ self_insert:
first = 0;
if (IsPrint (ch))
{
mutt_ungetch (ch);
mutt_ungetch (ch, 0);
buf[0] = 0;
redraw = M_REDRAW_INIT;
continue;
......
......@@ -250,12 +250,14 @@ int mutt_thread_set_flag (HEADER *cur, int flag, int bf, int subthread)
int mutt_change_flag (HEADER *h, int bf)
{
int i, flag;
event_t event;
mvprintw (LINES - 1, 0, "? (D/N/O/r/*/!): ", bf ? _("Set %s flag") :
_("Clear %s flag"));
mvprintw (LINES - 1, 0, "%s flag? (D/N/O/r/*/!): ", bf ? _("Set") : _("Clear"));
clrtoeol ();
if ((i = mutt_getch ()) == ERR)
event = mutt_getch();
i = event.ch;
if (i == -1)
{
CLEARLINE (LINES-1);
return (-1);
......
......@@ -114,6 +114,8 @@ WHERE short WriteInc;
/* vector to store received signals */
WHERE short Signals INITVAL (0);
WHERE int CurrentMenu;
WHERE ALIAS *Aliases INITVAL (0);
WHERE LIST *UserHeader INITVAL (0);
......
......@@ -21,6 +21,7 @@
#include "mutt_curses.h"
#include "mutt_regex.h"
#include "history.h"
#include "keymap.h"
#ifdef _PGPPATH
......@@ -1306,6 +1307,52 @@ int mutt_command_complete (char *buffer, size_t len, int pos, int numtabs)
strncpy (pt, Completed, buffer + len - pt - spaces);
}
else if (!strncmp (buffer, "exec", 4))
{
struct binding_t *menu = km_get_table (CurrentMenu);
if (!menu && CurrentMenu != MENU_PAGER)
menu = OpGeneric;
pt++;
/* first TAB. Collect all the matches */
if (numtabs == 1)
{
Num_matched = 0;
strfcpy (User_typed, pt, sizeof (User_typed));
memset (Matches, 0, sizeof (Matches));
memset (Completed, 0, sizeof (Completed));
for (num = 0; menu[num].name; num++)
candidate (Completed, User_typed, menu[num].name, sizeof (Completed));
/* try the generic menu */
if (Completed[0] == 0 && CurrentMenu != MENU_PAGER)
{
menu = OpGeneric;
for (num = 0; menu[num].name; num++)
candidate (Completed, User_typed, menu[num].name, sizeof (Completed));
}
Matches[Num_matched++] = User_typed;
/* All matches are stored. Longest non-ambiguous string is ""
* i.e. dont change 'buffer'. Fake successful return this time */
if (User_typed[0] == 0)
return 1;
}
if (Completed[0] == 0 && User_typed[0])
return 0;
/* Num_matched will _always_ be atleast 1 since the initial
* user-typed string is always stored */
if (numtabs == 1 && Num_matched == 2)
snprintf(Completed, sizeof(Completed),"%s", Matches[0]);
else if (numtabs > 1 && Num_matched > 2)
/* cycle thru all the matches */
snprintf(Completed, sizeof(Completed), "%s",
Matches[(numtabs - 2) % Num_matched]);
strncpy (pt, Completed, buffer + len - pt - spaces);
}
else
return 0;
......@@ -1600,6 +1647,8 @@ void mutt_init (int skip_sys_rc, LIST *commands)
for (i = 0; MuttVars[i].option; i++)
mutt_restore_default (&MuttVars[i]);
CurrentMenu = MENU_MAIN;
#ifndef LOCALES_HACK
/* Do we have a locale definition? */
if (((p = getenv ("LC_ALL")) != NULL && p[0]) ||
......
......@@ -332,6 +332,7 @@ struct command_t Commands[] = {
{ "color", mutt_parse_color, 0 },
{ "uncolor", mutt_parse_uncolor, 0 },
#endif
{ "exec", mutt_parse_exec, 0 },
{ "fcc-hook", mutt_parse_hook, M_FCCHOOK },
{ "fcc-save-hook", mutt_parse_hook, M_FCCHOOK | M_SAVEHOOK },
{ "folder-hook", mutt_parse_hook, M_FOLDERHOOK },
......
......@@ -219,11 +219,37 @@ void km_bindkey (char *s, int menu, int op)
km_bind (s, menu, op, NULL, NULL);
}
static int get_op (struct binding_t *bindings, const char *start, size_t len)
{
int i;
for (i = 0; bindings[i].name; i++)
{
if (!strncasecmp (start, bindings[i].name, len))
return bindings[i].op;
}
return OP_NULL;
}
static char *get_func (struct binding_t *bindings, int op)
{
int i;
for (i = 0; bindings[i].name; i++)
{
if (bindings[i].op == op)
return bindings[i].name;
}
return NULL;
}
static void push_string (char *s)
{
char *pp, *p = s + strlen (s) - 1;
size_t l;
int i;
int i, op = OP_NULL;
while (p >= s)
{
......@@ -244,13 +270,33 @@ static void push_string (char *s)
if (KeyNames[i].name)
{
/* found a match */
mutt_ungetch (KeyNames[i].value);
mutt_ungetch (KeyNames[i].value, 0);
p = pp - 1;
continue;
}
/* See if it is a valid command
* skip the '<' and the '>' when comparing */
for (i = 0; Menus[i].name; i++)
{
struct binding_t *binding = km_get_table (Menus[i].value);
if (binding)
{
op = get_op (binding, pp + 1, l - 2);
if (op != OP_NULL)
break;
}
}
if (op != OP_NULL)
{
mutt_ungetch (0, op);
p = pp - 1;
continue;
}
}
}
mutt_ungetch (*p--);
mutt_ungetch (*p--, 0);
}
}
......@@ -259,9 +305,9 @@ static int retry_generic (int menu, keycode_t *keys, int keyslen, int lastkey)
if (menu != MENU_EDITOR && menu != MENU_GENERIC && menu != MENU_PAGER)
{
if (lastkey)
mutt_ungetch (lastkey);
mutt_ungetch (lastkey, 0);
for (; keyslen; keyslen--)
mutt_ungetch (keys[keyslen - 1]);
mutt_ungetch (keys[keyslen - 1], 0);
return (km_dokey (MENU_GENERIC));
}
if (menu != MENU_EDITOR)
......@@ -279,18 +325,65 @@ static int retry_generic (int menu, keycode_t *keys, int keyslen, int lastkey)
*/
int km_dokey (int menu)
{
event_t tmp;
struct keymap_t *map = Keymaps[menu];
int pos = 0;
int n = 0;
int i;
if (!map)
return (retry_generic (menu, NULL, 0, 0));
FOREVER
{
if ((LastKey = mutt_getch ()) == ERR)
return (-1);
tmp = mutt_getch();
LastKey = tmp.ch;
if (LastKey == -1)
return -1;
/* do we have an op already? */
if (tmp.op)
{
char *func = NULL;
struct binding_t *bindings;
/* is this a valid op for the current menu? */
bindings = km_get_table (CurrentMenu);
if ((func = get_func (bindings, tmp.op)))
return tmp.op;
if (CurrentMenu != MENU_PAGER)
{
/* check generic menu */
bindings = OpGeneric;
if ((func = get_func (bindings, tmp.op)))
return tmp.op;
}
/* Sigh. Valid function but not in this context.
* Find the literal string and push it back */
for (i = 0; Menus[i].name; i++)
{
bindings = km_get_table (Menus[i].value);
if (bindings)
{
func = get_func (bindings, tmp.op);
if (func)
{
/* careful not to feed the <..> as one token. otherwise
* push_string() will push the bogus op right back! */
mutt_ungetch ('>', 0);
push_string (func);
mutt_ungetch ('<', 0);
break;
}
}
}
/* continue to chew */
if (func)
continue;
}
/* Nope. Business as usual */
while (LastKey > map->keys[pos])
{
if (pos > map->eq || !map->next)
......@@ -303,14 +396,15 @@ int km_dokey (int menu)
if (++pos == map->len)
{
if (map->op != OP_MACRO)
return (map->op);
return map->op;
if (n++ == 10)
{
mutt_flushinp ();
mutt_error _("Macro loop detected.");
return (-1);
return -1;
}
push_string (map->macro);
......@@ -692,3 +786,45 @@ int mutt_parse_macro (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
FREE (&key);
return (r);
}
/* exec command-name */
int mutt_parse_exec (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
int op = OP_NULL;
char *command = NULL;
struct binding_t *bindings = NULL;
if (!MoreArgs (s))
{
strfcpy (err->data, _("exec: too few arguments"), err->dsize);
return (-1);
}
mutt_extract_token (buf, s, 0);
command = safe_strdup (buf->data);
if (MoreArgs (s))
{
strfcpy (err->data, _("too many arguments"), err->dsize);
return (-1);
}
if ((<