From 8509b74f73d60e99d8de3000e8152a7905f19a73 Mon Sep 17 00:00:00 2001
From: Ilia Maslakov <il.smind@gmail.com>
Date: Fri, 21 Jan 2011 21:10:36 +0000
Subject: [PATCH 01/10] Ticket #323 (reimplimented editor macros)

Reimplemented editor macro engine:

    * added string binding "InsertChar" for action - "CK_Insert_Char"
    * added keybind_lookup_actionname - found action name by numeric constant
    * replaced struct macro to struct macro_action_t
    * added struct macros_t for describe editor scripts
    * rewritten edit_load_macro_cmd, edit_execute_macro
    * renamed edit_save_macro_cmd into edit_store_macro_cmd (WEdit * edit);
    * dropped Wedit properties: macro_i, macro_depth, macro[MAX_MACRO_LENGTH]
    * added GArray *macros_list to the store macroses of mcedit
    * added edit_get_macro

Signed-off-by: Ilia Maslakov <il.smind@gmail.com>
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
---
 lib/fileloc.h            |   2 +-
 lib/keybind.c            |  16 ++
 lib/keybind.h            |   5 +-
 lib/mcconfig/paths.c     |   2 -
 src/editor/edit-impl.h   |  11 +-
 src/editor/edit-widget.h |   6 -
 src/editor/edit.c        |  55 +----
 src/editor/editcmd.c     | 509 +++++++++++++++++++++++----------------
 src/editor/editdraw.c    |   4 +-
 src/editor/editkeys.c    |   2 +-
 src/editor/editwidget.c  |   4 +-
 src/main.c               |  18 ++
 src/main.h               |  22 +-
 13 files changed, 388 insertions(+), 268 deletions(-)

diff --git a/lib/fileloc.h b/lib/fileloc.h
index 5aeaa938d..12133aaef 100644
--- a/lib/fileloc.h
+++ b/lib/fileloc.h
@@ -29,6 +29,7 @@
 #define GLOBAL_KEYMAP_FILE      "mc.keymap"
 #define CHARSETS_LIST           "mc.charsets"
 #define MC_LIB_EXT              "mc.ext"
+#define MC_MACRO_FILE           "mc.macros"
 
 #define FISH_PREFIX             "fish"
 
@@ -67,7 +68,6 @@
 /* file names */
 #define EDIT_SYNTAX_FILE        EDIT_DIR PATH_SEP_STR "Syntax"
 #define EDIT_CLIP_FILE          EDIT_DIR PATH_SEP_STR "mcedit.clip"
-#define EDIT_MACRO_FILE         EDIT_DIR PATH_SEP_STR "mcedit.macros"
 #define EDIT_BLOCK_FILE         EDIT_DIR PATH_SEP_STR "mcedit.block"
 #define EDIT_TEMP_FILE          EDIT_DIR PATH_SEP_STR "mcedit.temp"
 
diff --git a/lib/keybind.c b/lib/keybind.c
index 822434a02..2d064e2b6 100644
--- a/lib/keybind.c
+++ b/lib/keybind.c
@@ -43,6 +43,7 @@
 /*** file scope variables ************************************************************************/
 
 static name_keymap_t command_names[] = {
+    {"InsertChar", CK_Insert_Char},
 #ifdef USE_INTERNAL_EDIT
     {"EditNoCommand", CK_Ignore_Key},
     {"EditIgnoreKey", CK_Ignore_Key},
@@ -199,6 +200,7 @@ static name_keymap_t command_names[] = {
     {"EditSaveMode", CK_Edit_Save_Mode},
     {"EditChooseSyntax", CK_Choose_Syntax},
     {"EditAbout", CK_About},
+    {"EditPipeBlock", CK_Pipe_Block (0)},
 
 #if 0
     {"EditFocusNext", CK_Focus_Next},
@@ -617,6 +619,20 @@ keybind_lookup_action (const char *name)
 
 /* --------------------------------------------------------------------------------------------- */
 
+const char *
+keybind_lookup_actionname (unsigned long action)
+{
+    size_t i;
+
+    for (i = 0; command_names[i].name != NULL; i++)
+        if (command_names[i].val == action)
+            return command_names[i].name;
+
+    return NULL;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
 const char *
 keybind_lookup_keymap_shortcut (const global_keymap_t * keymap, unsigned long action)
 {
diff --git a/lib/keybind.h b/lib/keybind.h
index 9106d4922..90b0d41f9 100644
--- a/lib/keybind.h
+++ b/lib/keybind.h
@@ -507,9 +507,9 @@
    TODO: bring up a viewer to display the error message instead of inserting
    it into the text, which is annoying.
  */
-#define CK_Pipe_Block(i) (1000+(i))
+#define CK_Pipe_Block(i) (10000+(i))
 #define SHELL_COMMANDS_i {"/edit.indent.rc", "/edit.spell.rc", /* and so on */ 0 }
-#define CK_Macro(i)      (2000+(i))
+#define CK_Macro(i)      (20000+(i))
 #define CK_Last_Macro    CK_Macro(0x7FFF)
 
 /*** enums ***************************************************************************************/
@@ -544,6 +544,7 @@ typedef struct global_keymap_t
 
 void keybind_cmd_bind (GArray * keymap, const char *keybind, unsigned long action);
 unsigned long keybind_lookup_action (const char *name);
+const char *keybind_lookup_actionname (unsigned long action);
 const char *keybind_lookup_keymap_shortcut (const global_keymap_t * keymap, unsigned long action);
 unsigned long keybind_lookup_keymap_command (const global_keymap_t * keymap, long key);
 
diff --git a/lib/mcconfig/paths.c b/lib/mcconfig/paths.c
index 3bbc6b374..dba27ee31 100644
--- a/lib/mcconfig/paths.c
+++ b/lib/mcconfig/paths.c
@@ -66,7 +66,6 @@ static const struct
     { "hotlist",                               &xdg_config, MC_HOTLIST_FILE},
     { "mc.keymap",                             &xdg_config, GLOBAL_KEYMAP_FILE},
 
-
     /* data */
     { "skins",                                 &xdg_data, MC_SKINS_SUBDIR},
     { "fish",                                  &xdg_data, FISH_PREFIX},
@@ -75,7 +74,6 @@ static const struct
     { "bashrc",                                &xdg_data, "bashrc"},
     { "inputrc",                               &xdg_data, "inputrc"},
     { "extfs.d",                               &xdg_data, MC_EXTFS_DIR},
-    { "cedit" PATH_SEP_STR "cooledit.macros",  &xdg_data, EDIT_MACRO_FILE},
     { "cedit" PATH_SEP_STR "Syntax",           &xdg_data, EDIT_SYNTAX_FILE},
     { "cedit" PATH_SEP_STR "menu",             &xdg_data, EDIT_HOME_MENU},
     { "cedit" PATH_SEP_STR "edit.indent.rc",   &xdg_data, EDIT_DIR PATH_SEP_STR "edit.indent.rc"},
diff --git a/src/editor/edit-impl.h b/src/editor/edit-impl.h
index c4cd99780..809272885 100644
--- a/src/editor/edit-impl.h
+++ b/src/editor/edit-impl.h
@@ -184,12 +184,6 @@ typedef struct edit_stack_type
     char *filename;
 } edit_stack_type;
 
-struct macro
-{
-    unsigned long command;
-    int ch;
-};
-
 struct Widget;
 struct WMenuBar;
 
@@ -311,8 +305,8 @@ int edit_sort_cmd (WEdit * edit);
 int edit_ext_cmd (WEdit * edit);
 void edit_help_cmd (WEdit * edit);
 
-int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n);
-int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k);
+int edit_store_macro_cmd (WEdit * edit);
+gboolean edit_load_macro_cmd (WEdit * edit);
 void edit_delete_macro_cmd (WEdit * edit);
 
 int edit_copy_to_X_buf_cmd (WEdit * edit);
@@ -322,6 +316,7 @@ void edit_paste_from_X_buf_cmd (WEdit * edit);
 void edit_select_codepage_cmd (WEdit * edit);
 void edit_insert_literal_cmd (WEdit * edit);
 void edit_execute_macro_cmd (WEdit * edit);
+gboolean edit_execute_macro (WEdit * edit, int hotkey);
 void edit_begin_end_macro_cmd (WEdit * edit);
 
 void edit_paste_from_history (WEdit * edit);
diff --git a/src/editor/edit-widget.h b/src/editor/edit-widget.h
index c82e05ad6..18ab9b68c 100644
--- a/src/editor/edit-widget.h
+++ b/src/editor/edit-widget.h
@@ -12,7 +12,6 @@
 
 /*** typedefs(not structures) and defined constants **********************************************/
 
-#define MAX_MACRO_LENGTH 1024
 #define N_LINE_CACHES 32
 
 /*** enums ***************************************************************************************/
@@ -132,11 +131,6 @@ struct WEdit
     GTree *defines;             /* List of defines */
     gboolean is_case_insensitive;       /* selects language case sensitivity */
 
-    /* macro stuff */
-    int macro_i;                /* index to macro[], -1 if not recording a macro */
-    int macro_depth;            /* depth of the macro recursion */
-    struct macro macro[MAX_MACRO_LENGTH];
-
     /* user map stuff */
     GIConv converter;
 
diff --git a/src/editor/edit.c b/src/editor/edit.c
index a733805c7..5d49e93f2 100644
--- a/src/editor/edit.c
+++ b/src/editor/edit.c
@@ -169,7 +169,6 @@ static const char *const shell_cmd[] = SHELL_COMMANDS_i;
 
 static void user_menu (WEdit * edit);
 static int left_of_four_spaces (WEdit * edit);
-static inline void edit_execute_macro (WEdit * edit, struct macro macro[], int n);
 
 /* --------------------------------------------------------------------------------------------- */
 
@@ -558,7 +557,6 @@ edit_purge_widget (WEdit * edit)
     size_t len = sizeof (WEdit) - sizeof (Widget);
     char *start = (char *) edit + sizeof (Widget);
     memset (start, 0, len);
-    edit->macro_i = -1;         /* not recording a macro */
 }
 
 /* --------------------------------------------------------------------------------------------- */
@@ -1662,28 +1660,6 @@ edit_goto_matching_bracket (WEdit * edit)
     }
 }
 
-/* --------------------------------------------------------------------------------------------- */
-
-static void
-edit_execute_macro (WEdit * edit, struct macro macro[], int n)
-{
-    int i = 0;
-
-    if (edit->macro_depth++ > 256)
-    {
-        edit_error_dialog (_("Error"), _("Macro recursion is too deep"));
-        edit->macro_depth--;
-        return;
-    }
-    edit->force |= REDRAW_PAGE;
-    for (; i < n; i++)
-    {
-        edit_execute_cmd (edit, macro[i].command, macro[i].ch);
-    }
-    edit_update_screen (edit);
-    edit->macro_depth--;
-}
-
 /* --------------------------------------------------------------------------------------------- */
 /** User edit menu, like user menu (F2) but only in editor. */
 
@@ -2225,7 +2201,7 @@ edit_init (WEdit * edit, int lines, int columns, const char *filename, long line
     }
 
     edit_set_keymap ();
-
+    edit_load_macro_cmd (edit);
     return edit;
 }
 
@@ -2266,7 +2242,6 @@ edit_clean (WEdit * edit)
     g_free (edit->redo_stack);
     g_free (edit->filename);
     g_free (edit->dir);
-
     mc_search_free (edit->search);
     edit->search = NULL;
 
@@ -3404,23 +3379,24 @@ edit_find_bracket (WEdit * edit)
 void
 edit_execute_key_command (WEdit * edit, unsigned long command, int char_for_insertion)
 {
-    if (command == CK_Begin_Record_Macro)
+    if (command == CK_Begin_Record_Macro || (command == CK_Begin_End_Macro && macro_index < 0))
     {
-        edit->macro_i = 0;
+        macro_index = 0;
         edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
         return;
     }
-    if (command == CK_End_Record_Macro && edit->macro_i != -1)
+    if ((command == CK_End_Record_Macro || command == CK_Begin_End_Macro) && macro_index != -1)
     {
         edit->force |= REDRAW_COMPLETELY;
-        edit_save_macro_cmd (edit, edit->macro, edit->macro_i);
-        edit->macro_i = -1;
+        edit_store_macro_cmd (edit);
+        macro_index = -1;
         return;
     }
-    if (edit->macro_i >= 0 && edit->macro_i < MAX_MACRO_LENGTH - 1)
+
+    if (macro_index >= 0 && macro_index < MAX_MACRO_LENGTH - 1)
     {
-        edit->macro[edit->macro_i].command = command;
-        edit->macro[edit->macro_i++].ch = char_for_insertion;
+        record_macro_buf[macro_index].action = command;
+        record_macro_buf[macro_index++].ch = char_for_insertion;
     }
     /* record the beginning of a set of editing actions initiated by a key press */
     if (command != CK_Undo && command != CK_Ext_Mode)
@@ -4149,15 +4125,8 @@ edit_execute_cmd (WEdit * edit, unsigned long command, int char_for_insertion)
     }
 
     /* CK_Pipe_Block */
-    if ((command / 1000) == 1)  /* a shell command */
-        edit_block_process_cmd (edit, shell_cmd[command - 1000], 1);
-    if (command > CK_Macro (0) && command <= CK_Last_Macro)
-    {                           /* a macro command */
-        struct macro m[MAX_MACRO_LENGTH];
-        int nm;
-        if (edit_load_macro_cmd (edit, m, &nm, command - 2000))
-            edit_execute_macro (edit, m, nm);
-    }
+    if ((command / 10000) == 1)  /* a shell command */
+        edit_block_process_cmd (edit, shell_cmd[command - 10000], 1);
 
     /* keys which must set the col position, and the search vars */
     switch (command)
diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c
index f1aeca753..c7d05162e 100644
--- a/src/editor/editcmd.c
+++ b/src/editor/editcmd.c
@@ -445,126 +445,6 @@ edit_get_save_file_as (WEdit * edit)
 #undef DLG_HEIGHT
 }
 
-/* {{{ Macro stuff starts here */
-
-/* --------------------------------------------------------------------------------------------- */
-/** creates a macro file if it doesn't exist */
-
-static FILE *
-edit_open_macro_file (const char *r)
-{
-    gchar *filename;
-    FILE *fd;
-    int file;
-    filename = concat_dir_and_file (mc_config_get_data_path (), EDIT_MACRO_FILE);
-    file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-    if (file == -1)
-    {
-        g_free (filename);
-        return 0;
-    }
-    close (file);
-    fd = fopen (filename, r);
-    g_free (filename);
-    return fd;
-}
-
-#define MAX_MACROS 1024
-static int saved_macro[MAX_MACROS + 1];
-static int saved_macros_loaded = 0;
-
-/* --------------------------------------------------------------------------------------------- */
-/**
-   This is just to stop the macro file be loaded over and over for keys
-   that aren't defined to anything. On slow systems this could be annoying.
- */
-
-static int
-macro_exists (int k)
-{
-    int i;
-    for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
-        if (saved_macro[i] == k)
-            return i;
-    return -1;
-}
-
-/* --------------------------------------------------------------------------------------------- */
-/** returns 1 on error */
-
-static int
-edit_delete_macro (WEdit * edit, int k)
-{
-    gchar *tmp, *tmp2;
-    struct macro macro[MAX_MACRO_LENGTH];
-    FILE *f, *g;
-    int s, i, n, j = 0;
-
-    (void) edit;
-
-    if (saved_macros_loaded)
-    {
-        j = macro_exists (k);
-        if (j < 0)
-            return 0;
-    }
-    tmp = concat_dir_and_file (mc_config_get_cache_path (), EDIT_TEMP_FILE);
-    g = fopen (tmp, "w");
-    g_free (tmp);
-    if (!g)
-    {
-        edit_error_dialog (_("Delete macro"), get_sys_error (_("Cannot open temp file")));
-        return 1;
-    }
-    f = edit_open_macro_file ("r");
-    if (!f)
-    {
-        edit_error_dialog (_("Delete macro"), get_sys_error (_("Cannot open macro file")));
-        fclose (g);
-        return 1;
-    }
-    for (;;)
-    {
-        n = fscanf (f, ("key '%d 0': "), &s);
-        if (!n || n == EOF)
-            break;
-        n = 0;
-        while (fscanf (f, "%lu %d, ", &macro[n].command, &macro[n].ch))
-            n++;
-        {
-            int ret;
-            ret = fscanf (f, ";\n");
-        }
-        if (s != k)
-        {
-            fprintf (g, ("key '%d 0': "), s);
-            for (i = 0; i < n; i++)
-                fprintf (g, "%lu %d, ", macro[i].command, macro[i].ch);
-            fprintf (g, ";\n");
-        }
-    }
-    fclose (f);
-    fclose (g);
-    tmp = concat_dir_and_file (mc_config_get_cache_path (), EDIT_TEMP_FILE);
-    tmp2 = concat_dir_and_file (mc_config_get_data_path (), EDIT_MACRO_FILE);
-    if (rename (tmp, tmp2) == -1)
-    {
-        edit_error_dialog (_("Delete macro"), get_sys_error (_("Cannot overwrite macro file")));
-        g_free (tmp);
-        g_free (tmp2);
-        return 1;
-    }
-    g_free (tmp);
-    g_free (tmp2);
-
-    if (saved_macros_loaded)
-        memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
-    return 0;
-}
-
-/* }}} */
-
-/* --------------------------------------------------------------------------------------------- */
 /** returns 1 on success */
 
 static int
@@ -1498,117 +1378,345 @@ edit_save_as_cmd (WEdit * edit)
 
 /* {{{ Macro stuff starts here */
 
+/* --------------------------------------------------------------------------------------------- */
+
+static int
+edit_macro_comparator (gconstpointer *macro1, gconstpointer *macro2)
+{
+    const macros_t *m1 = (const macros_t *) macro1;
+    const macros_t *m2 = (const macros_t *) macro2;
+
+    return m1->hotkey - m2->hotkey;
+}
 
 /* --------------------------------------------------------------------------------------------- */
-/** returns 0 on error */
 
-int
-edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
+static void
+edit_macro_sort_by_hotkey (WEdit *edit)
 {
-    FILE *f;
-    int s, i;
-
-    edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
-    s = editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), 1);
-    edit->force |= REDRAW_COMPLETELY;
-    if (s)
-    {
-        if (edit_delete_macro (edit, s))
-            return 0;
-        f = edit_open_macro_file ("a+");
-        if (f)
-        {
-            fprintf (f, ("key '%d 0': "), s);
-            for (i = 0; i < n; i++)
-                fprintf (f, "%lu %d, ", macro[i].command, macro[i].ch);
-            fprintf (f, ";\n");
-            fclose (f);
-            if (saved_macros_loaded)
-            {
-                for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
-                saved_macro[i] = s;
-            }
-            return 1;
-        }
-        else
-            edit_error_dialog (_("Save macro"), get_sys_error (_("Cannot open macro file")));
-    }
-    return 0;
+    if (macros_list == NULL || macros_list->len == 0)
+        return;
+    g_array_sort (macros_list, (GCompareFunc) edit_macro_comparator);
 }
 
+/* --------------------------------------------------------------------------------------------- */
+
+static gboolean
+edit_get_macro (WEdit * edit, int hotkey, const macros_t **macros, guint *indx)
+{
+    const macros_t *array_start = &g_array_index (macros_list, struct macros_t, 0);
+    macros_t *result;
+    macros_t search_macro;
+    search_macro.hotkey = hotkey;
+    result = bsearch (&search_macro, macros_list->data, macros_list->len,
+                      sizeof (macros_t), (GCompareFunc) edit_macro_comparator);
+
+    if (result != NULL && result->macro != NULL)
+    {
+        *indx = (result - array_start);
+        *macros = result;
+        return TRUE;
+    }
+    *indx = 0;
+    return FALSE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/** returns FALSE on error */
+
+static gboolean
+edit_delete_macro (WEdit * edit, int hotkey)
+{
+    mc_config_t *macros_config = NULL;
+    const char *section_name = "editor";
+    gchar *macros_fname;
+    guint indx;
+    char keyname[8];
+
+    const macros_t *macros = NULL;
+
+    /* clear array of actions for current hotkey */
+    while (edit_get_macro (edit, hotkey, &macros, &indx))
+    {
+        if (macros->macro != NULL)
+            g_array_free (macros->macro, TRUE);
+        macros = NULL;
+        g_array_remove_index (macros_list, indx);
+        edit_macro_sort_by_hotkey (edit);
+    }
+
+    macros_fname = g_build_filename (mc_config_get_path (), MC_MACRO_FILE, NULL);
+    macros_config = mc_config_init (macros_fname);
+    g_free (macros_fname);
+
+    if (macros_config == NULL)
+        return FALSE;
+
+    g_snprintf (keyname, sizeof (keyname), "%i", hotkey);
+    while (mc_config_del_key (macros_config, section_name, keyname));
+    mc_config_save_file (macros_config, NULL);
+    mc_config_deinit (macros_config);
+    return TRUE;
+}
+
+
 /* --------------------------------------------------------------------------------------------- */
 
 void
 edit_delete_macro_cmd (WEdit * edit)
 {
-    int command;
+    int hotkey;
 
-    command = editcmd_dialog_raw_key_query (_("Delete macro"), _("Press macro hotkey:"), 1);
+    hotkey = editcmd_dialog_raw_key_query (_("Delete macro"), _("Press macro hotkey:"), 1);
 
-    if (command != 0)
-        edit_delete_macro (edit, command);
+    if (hotkey != 0 && !edit_delete_macro (edit, hotkey))
+        message (D_ERROR, _("Delete macro"), _("Macro not deleted"));
 }
 
 /* --------------------------------------------------------------------------------------------- */
-/** return 0 on error */
 
-int
-edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
+/** returns FALSE on error */
+gboolean
+edit_execute_macro (WEdit * edit, int hotkey)
 {
-    FILE *f;
-    int s, i = 0, found = 0;
+    gboolean res = FALSE;
+
+    if (hotkey != 0)
+    {
+        const macros_t *macros;
+        guint indx;
+
+        if (edit_get_macro (edit, hotkey, &macros, &indx) &&
+            macros->macro != NULL && macros->macro->len != 0)
+        {
+            guint i;
+
+            edit->force |= REDRAW_PAGE;
+
+            for (i = 0; i < macros->macro->len; i++)
+            {
+                const macro_action_t *m_act;
+
+                m_act = &g_array_index (macros->macro, struct macro_action_t, i);
+                edit_execute_cmd (edit, m_act->action, m_act->ch);
+                res = TRUE;
+            }
+        }
+    }
+    edit_update_screen (edit);
+    return res;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/** returns FALSE on error */
+gboolean
+edit_store_macro_cmd (WEdit * edit)
+{
+    int i;
+    int hotkey;
+    char keyname[8];
+    GString *marcros_string;
+    mc_config_t *macros_config = NULL;
+    const char *section_name = "editor";
+    gchar *macros_fname;
+    GArray *macros; /* current macro */
+    int tmp_act;
+    gboolean have_macro = FALSE;
+
+    hotkey = editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), 1);
+    if (hotkey == ESC_CHAR)
+        return FALSE;
+
+    tmp_act = keybind_lookup_keymap_command (editor_map, hotkey);
+
+    /* return FALSE if try assign macro into restricted hotkeys */
+    if (tmp_act == CK_Begin_Record_Macro
+       || tmp_act == CK_End_Record_Macro
+       || tmp_act == CK_Begin_End_Macro)
+        return FALSE;
+
+    edit_delete_macro (edit, hotkey);
+
+    macros_fname = g_build_filename (mc_config_get_path (), MC_MACRO_FILE, NULL);
+    macros_config = mc_config_init (macros_fname);
+    g_free (macros_fname);
+
+    if (macros_config == NULL)
+        return FALSE;
+
+    g_snprintf (keyname, sizeof (keyname), "%i", hotkey);
+
+    marcros_string = g_string_sized_new (250);
+
+    edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
+
+    macros = g_array_new (TRUE, FALSE, sizeof (macro_action_t));
+    for (i = 0; i < macro_index; i++)
+    {
+        macro_action_t m_act;
+        const char *action_name;
+
+        action_name = keybind_lookup_actionname (record_macro_buf[i].action);
+
+        if (action_name == NULL)
+            break;
+
+        m_act.action = record_macro_buf[i].action;
+        m_act.ch = record_macro_buf[i].ch;
+        g_array_append_val (macros, m_act);
+        have_macro = TRUE;
+        g_string_append_printf (marcros_string, "%s:%i;", action_name, (int) record_macro_buf[i].ch);
+    }
+    if (have_macro)
+    {
+        macros_t macro;
+        macro.hotkey = hotkey;
+        macro.macro = macros;
+        g_array_append_val (macros_list, macro);
+        mc_config_set_string (macros_config, section_name, keyname, marcros_string->str);
+    }
+    else
+        mc_config_del_key (macros_config, section_name, keyname);
+
+    edit_macro_sort_by_hotkey (edit);
+
+    g_string_free (marcros_string, TRUE);
+    mc_config_save_file (macros_config, NULL);
+    mc_config_deinit (macros_config);
+    return TRUE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+gboolean
+edit_repeat_macro_cmd (WEdit * edit)
+{
+    int i, j;
+    char *f;
+    long count_repeat;
+    char *error = NULL;
+
+    f = input_dialog (_("Repeat last commands"), _("Repeat times:"), NULL, "1");
+    if (f == NULL || *f == '\0')
+    {
+        g_free (f);
+        return FALSE;
+    }
+
+    count_repeat = strtol (f, &error, 0);
+
+    if (error != NULL)
+    {
+        g_free (f);
+        return FALSE;
+    }
+
+    g_free (f);
+
+    edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
+
+    edit->force |= REDRAW_PAGE;
+    for (j = 0; j < count_repeat; j++)
+        for (i = 0; i < macro_index; i++)
+            edit_execute_cmd (edit, record_macro_buf[i].action, record_macro_buf[i].ch);
+    edit_update_screen (edit);
+    return TRUE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/** return FALSE on error */
+
+gboolean
+edit_load_macro_cmd (WEdit * edit)
+{
+    mc_config_t *macros_config = NULL;
+    gchar **profile_keys, **keys;
+    gchar **values, **curr_values;
+    gsize len, values_len;
+    const char *section_name = "editor";
+    gchar *macros_fname;
+    int hotkey;
 
     (void) edit;
 
-    if (saved_macros_loaded)
-        if (macro_exists (k) < 0)
-            return 0;
+    macros_fname = g_build_filename (mc_config_get_path (), MC_MACRO_FILE, NULL);
+    macros_config = mc_config_init (macros_fname);
+    g_free (macros_fname);
 
-    f = edit_open_macro_file ("r");
-    if (f != NULL)
+    if (macros_config == NULL)
+        return FALSE;
+
+    profile_keys = keys = mc_config_get_keys (macros_config, section_name, &len);
+    while (*profile_keys != NULL)
     {
-        struct macro dummy;
-        do
+        gboolean have_macro;
+        GArray *macros;
+        macros_t macro;
+
+        macros = g_array_new (TRUE, FALSE, sizeof (macro_action_t));
+
+        curr_values = values = mc_config_get_string_list (macros_config, section_name,
+                                                          *profile_keys, &values_len);
+        hotkey = strtol (*profile_keys, NULL, 0);
+        have_macro = FALSE;
+        while (*curr_values != NULL && *curr_values[0] != '\0')
         {
-            int u;
-            u = fscanf (f, ("key '%d 0': "), &s);
-            if (!u || u == EOF)
-                break;
-            if (!saved_macros_loaded)
-                saved_macro[i++] = s;
-            if (!found)
+            char **macro_pair = NULL;
+
+            macro_pair = g_strsplit (*curr_values, ":", 2);
+
+            if (macro_pair != NULL)
             {
-                *n = 0;
-                while (*n < MAX_MACRO_LENGTH
-                       && 2 == fscanf (f, "%lu %d, ", &macro[*n].command, &macro[*n].ch))
-                    (*n)++;
+                macro_action_t m_act;
+                if (macro_pair [0] == NULL || macro_pair [0][0] == '\0')
+                    m_act.action = 0;
+                else
+                {
+                    m_act.action = keybind_lookup_action (macro_pair [0]);
+                    g_free (macro_pair[0]);
+                    macro_pair[0] = NULL;
+                }
+                if (macro_pair [1] == NULL || macro_pair [1][0] == '\0')
+                    m_act.ch = -1;
+                else
+                {
+                    m_act.ch = strtol (macro_pair [1], NULL, 0);
+                    g_free (macro_pair[1]);
+                    macro_pair[1] = NULL;
+                }
+                if (m_act.action != 0)
+                {
+                    /* a shell command */
+                    if ((m_act.action / CK_Pipe_Block (0)) == 1)
+                    {
+                        m_act.action = CK_Pipe_Block (0) + (m_act.ch > 0 ? m_act.ch : 0);
+                        m_act.ch = -1;
+                    }
+                    g_array_append_val (macros, m_act);
+                    have_macro = TRUE;
+                }
+                g_strfreev (macro_pair);
+                macro_pair = NULL;
             }
-            else
-            {
-                while (2 == fscanf (f, "%lu %d, ", &dummy.command, &dummy.ch));
-            }
-            {
-                int ret;
-                ret = fscanf (f, ";\n");
-            }
-            if (s == k)
-                found = 1;
+            curr_values++;
         }
-        while (!found || !saved_macros_loaded);
-        if (!saved_macros_loaded)
+        if (have_macro)
         {
-            saved_macro[i] = 0;
-            saved_macros_loaded = 1;
+            macro.hotkey = hotkey;
+            macro.macro = macros;
+            g_array_append_val (macros_list, macro);
         }
-        fclose (f);
-        return found;
+        profile_keys++;
+        g_strfreev (values);
     }
-    else
-        edit_error_dialog (_("Load macro"), get_sys_error (_("Cannot open macro file")));
-    return 0;
+    g_strfreev (keys);
+    mc_config_deinit (macros_config);
+    edit_macro_sort_by_hotkey (edit);
+    return TRUE;
 }
 
-/* }}} Macro stuff starts here */
+/* }}} Macro stuff end here */
 
 /* --------------------------------------------------------------------------------------------- */
 /** returns 1 on success */
@@ -1634,7 +1742,6 @@ edit_save_confirm_cmd (WEdit * edit)
     return edit_save_cmd (edit);
 }
 
-
 /* --------------------------------------------------------------------------------------------- */
 /** returns 1 on success */
 
@@ -3046,7 +3153,7 @@ edit_begin_end_macro_cmd (WEdit * edit)
     /* edit is a pointer to the widget */
     if (edit)
     {
-        unsigned long command = edit->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
+        unsigned long command = macro_index < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
         edit_execute_key_command (edit, command, -1);
     }
 }
diff --git a/src/editor/editdraw.c b/src/editor/editdraw.c
index 06d7a0f80..37eb85279 100644
--- a/src/editor/editdraw.c
+++ b/src/editor/editdraw.c
@@ -145,7 +145,7 @@ status_string (WEdit * edit, char *s, int w)
                     "%c%c%c%c %3ld %5ld/%ld %6ld/%ld %s %s",
                     edit->mark1 != edit->mark2 ? (edit->column_highlight ? 'C' : 'B') : '-',
                     edit->modified ? 'M' : '-',
-                    edit->macro_i < 0 ? '-' : 'R',
+                    macro_index < 0 ? '-' : 'R',
                     edit->overwrite == 0 ? '-' : 'O',
                     edit->curs_col + edit->over_col,
                     edit->curs_line + 1,
@@ -161,7 +161,7 @@ status_string (WEdit * edit, char *s, int w)
                     "[%c%c%c%c] %2ld L:[%3ld+%2ld %3ld/%3ld] *(%-4ld/%4ldb) %s  %s",
                     edit->mark1 != edit->mark2 ? (edit->column_highlight ? 'C' : 'B') : '-',
                     edit->modified ? 'M' : '-',
-                    edit->macro_i < 0 ? '-' : 'R',
+                    macro_index < 0 ? '-' : 'R',
                     edit->overwrite == 0 ? '-' : 'O',
                     edit->curs_col + edit->over_col,
                     edit->start_line + 1,
diff --git a/src/editor/editkeys.c b/src/editor/editkeys.c
index 81c211d40..0de8a5ce0 100644
--- a/src/editor/editkeys.c
+++ b/src/editor/editkeys.c
@@ -47,7 +47,7 @@
 #include "lib/charsets.h"       /* convert_from_input_c() */
 
 #include "edit-impl.h"
-#include "edit-widget.h"        /* edit->macro_i */
+#include "edit-widget.h"        /* WEdit */
 #include "editcmd_dialogs.h"
 
 #include "src/keybind-defaults.h"       /* keybind_lookup_keymap_command() */
diff --git a/src/editor/editwidget.c b/src/editor/editwidget.c
index 381badba3..7fdd779b0 100644
--- a/src/editor/editwidget.c
+++ b/src/editor/editwidget.c
@@ -315,7 +315,9 @@ edit_callback (Widget * w, widget_msg_t msg, int parm)
             cb_ret_t ret = MSG_NOT_HANDLED;
 
             /* The user may override the access-keys for the menu bar. */
-            if (edit_translate_key (e, parm, &cmd, &ch))
+            if (macro_index == -1 && edit_execute_macro (e, parm))
+                ret = MSG_HANDLED;
+            else if (edit_translate_key (e, parm, &cmd, &ch))
             {
                 edit_execute_key_command (e, cmd, ch);
                 edit_update_screen (e);
diff --git a/src/main.c b/src/main.c
index c54d82db0..9b3e807f3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -133,6 +133,9 @@ int print_last_revert = FALSE;
 /* If set, then print to the given file the last directory we were at */
 char *last_wd_string = NULL;
 
+/* index to record_macro_buf[], -1 if not recording a macro */
+int macro_index = -1;
+
 /*** file scope macro definitions ****************************************************************/
 
 /*** file scope type declarations ****************************************************************/
@@ -482,6 +485,8 @@ main (int argc, char *argv[])
 
     load_keymap_defs ();
 
+    macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
+
     tty_init_colors (mc_args__disable_colors, mc_args__force_colors);
 
     {
@@ -587,6 +592,19 @@ main (int argc, char *argv[])
 
     done_key ();
 
+    if (macros_list != NULL)
+    {
+        guint i;
+        macros_t *macros;
+        for (i = 0; i < macros_list->len; i++)
+        {
+            macros = &g_array_index (macros_list, struct macros_t, i);
+            if (macros != NULL && macros->macro != NULL)
+                g_array_free (macros->macro, FALSE);
+        }
+        g_array_free (macros_list, TRUE);
+    }
+
     str_uninit_strings ();
 
     g_free (mc_run_param0);
diff --git a/src/main.h b/src/main.h
index bd0cd959a..4550e9f57 100644
--- a/src/main.h
+++ b/src/main.h
@@ -9,6 +9,8 @@
 
 /*** typedefs(not structures) and defined constants **********************************************/
 
+#define MAX_MACRO_LENGTH 1024
+
 /*** enums ***************************************************************************************/
 
 /* run mode and params */
@@ -26,9 +28,23 @@ enum cd_enum
     cd_exact
 };
 
-
 /*** structures declarations (and typedefs of structures)*****************************************/
 
+typedef struct macro_action_t
+{
+    unsigned long action;
+    int ch;
+} macro_action_t;
+
+typedef struct macros_t
+{
+    int hotkey;
+    GArray *macro;
+} macros_t;
+
+/* macro stuff */
+struct macro_action_t record_macro_buf[MAX_MACRO_LENGTH];
+
 struct mc_fhl_struct;
 
 /*** global variables defined in .c file *********************************************************/
@@ -81,6 +97,10 @@ extern const char *mc_prompt;
 extern char *mc_sysconfig_dir;
 extern char *mc_share_data_dir;
 
+GArray *macros_list;
+/* index to record_macro_buf[], -1 if not recording a macro */
+extern int macro_index;
+
 /*** declarations of public functions ************************************************************/
 
 #ifdef HAVE_SUBSHELL_SUPPORT

From 8e22a16430b1fd09e2e2ff86f04c7274d414be3b Mon Sep 17 00:00:00 2001
From: Ilia Maslakov <il.smind@gmail.com>
Date: Fri, 21 Jan 2011 21:36:29 +0000
Subject: [PATCH 02/10] Added lookup_key_by_code, now parameter is string.

For example: "ctrl-w=action:code;action:code;action:code;"

Signed-off-by: Ilia Maslakov <il.smind@gmail.com>
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
---
 lib/tty/key.c        | 181 ++++++++++++++++++++++++++++++++++++-------
 lib/tty/key.h        |   2 +-
 src/editor/editcmd.c |  40 +++++-----
 3 files changed, 176 insertions(+), 47 deletions(-)

diff --git a/lib/tty/key.c b/lib/tty/key.c
index a1d9619f4..90ba5a70a 100644
--- a/lib/tty/key.c
+++ b/lib/tty/key.c
@@ -251,6 +251,13 @@ typedef struct SelectList
     struct SelectList *next;
 } SelectList;
 
+typedef enum KeySortType
+{
+    KEY_NOSORT = 0,
+    KEY_SORTBYNAME,
+    KEY_SORTBYCODE
+} KeySortType;
+
 #ifdef __QNXNTO__
 typedef int (*ph_dv_f) (void *, void *);
 typedef int (*ph_ov_f) (void *);
@@ -524,11 +531,11 @@ static Display *x11_display;
 static Window x11_window;
 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
 
-static const size_t key_name_conv_tab_size = sizeof (key_name_conv_tab) /
-    sizeof (key_name_conv_tab[0]) - 1;
+static KeySortType has_been_sorted = KEY_NOSORT;
 
-static const key_code_name_t *key_name_conv_tab_sorted[sizeof (key_name_conv_tab) /
-                                                       sizeof (key_name_conv_tab[0]) - 1];
+static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
+
+static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
 
 /*** file scope functions ************************************************************************/
 /* --------------------------------------------------------------------------------------------- */
@@ -1144,7 +1151,7 @@ s_dispose (SelectList * sel)
 /* --------------------------------------------------------------------------------------------- */
 
 static int
-key_code_name_comparator (const void *p1, const void *p2)
+key_code_comparator_by_name (const void *p1, const void *p2)
 {
     const key_code_name_t *n1 = *(const key_code_name_t **) p1;
     const key_code_name_t *n2 = *(const key_code_name_t **) p2;
@@ -1154,21 +1161,37 @@ key_code_name_comparator (const void *p1, const void *p2)
 
 /* --------------------------------------------------------------------------------------------- */
 
-static inline void
-sort_key_name_conv_tab (void)
+static int
+key_code_comparator_by_code (const void *p1, const void *p2)
 {
-    static gboolean has_been_sorted = FALSE;
+    const key_code_name_t *n1 = *(const key_code_name_t **) p1;
+    const key_code_name_t *n2 = *(const key_code_name_t **) p2;
 
-    if (!has_been_sorted)
+    return n1->code - n2->code;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+static inline void
+sort_key_conv_tab (enum KeySortType type_sort)
+{
+    if (has_been_sorted != type_sort)
     {
         size_t i;
-        for (i = 0; i < key_name_conv_tab_size; i++)
-            key_name_conv_tab_sorted[i] = &key_name_conv_tab[i];
+        for (i = 0; i < key_conv_tab_size; i++)
+            key_conv_tab_sorted[i] = &key_name_conv_tab[i];
 
-        qsort (key_name_conv_tab_sorted,
-               key_name_conv_tab_size, sizeof (key_name_conv_tab_sorted[0]),
-               &key_code_name_comparator);
-        has_been_sorted = TRUE;
+        if (type_sort == KEY_SORTBYNAME)
+        {
+            qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
+                   &key_code_comparator_by_name);
+        }
+        else if (type_sort == KEY_SORTBYCODE)
+        {
+            qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
+                   &key_code_comparator_by_code);
+        }
+        has_been_sorted = type_sort;
     }
 }
 
@@ -1189,15 +1212,14 @@ lookup_keyname (const char *name, int *idx)
             return (int) name[0];
         }
 
-        sort_key_name_conv_tab ();
+        sort_key_conv_tab (KEY_SORTBYNAME);
 
-        res = bsearch (&keyp, key_name_conv_tab_sorted,
-                       key_name_conv_tab_size,
-                       sizeof (key_name_conv_tab_sorted[0]), key_code_name_comparator);
+        res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
+                       sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
 
         if (res != NULL)
         {
-            *idx = (int) (res - (key_code_name_t **) key_name_conv_tab_sorted);
+            *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
             return (*res)->code;
         }
     }
@@ -1206,6 +1228,33 @@ lookup_keyname (const char *name, int *idx)
     return 0;
 }
 
+/* --------------------------------------------------------------------------------------------- */
+
+static gboolean
+lookup_keycode (const long code, int *idx)
+{
+    if (code != 0)
+    {
+        const key_code_name_t key = { code, NULL, NULL, NULL };
+        const key_code_name_t *keyp = &key;
+        key_code_name_t **res;
+
+        sort_key_conv_tab (KEY_SORTBYCODE);
+
+        res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
+                       sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
+
+        if (res != NULL)
+        {
+            *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
+            return TRUE;
+        }
+    }
+
+    *idx = -1;
+    return FALSE;
+}
+
 /* --------------------------------------------------------------------------------------------- */
 /*** public functions ****************************************************************************/
 /* --------------------------------------------------------------------------------------------- */
@@ -1413,12 +1462,12 @@ lookup_key (const char *name, char **label)
 
         if (use_meta != -1)
         {
-            g_string_append (s, key_name_conv_tab_sorted[use_meta]->shortcut);
+            g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
             g_string_append_c (s, '-');
         }
         if (use_ctrl != -1)
         {
-            g_string_append (s, key_name_conv_tab_sorted[use_ctrl]->shortcut);
+            g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
             g_string_append_c (s, '-');
         }
         if (use_shift != -1)
@@ -1427,21 +1476,21 @@ lookup_key (const char *name, char **label)
                 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
             else
             {
-                g_string_append (s, key_name_conv_tab_sorted[use_shift]->shortcut);
+                g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
                 g_string_append_c (s, '-');
-                g_string_append (s, key_name_conv_tab_sorted[lc_index]->shortcut);
+                g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
             }
         }
         else if (k < 128)
         {
             if ((k >= 'A') || (lc_index < 0)
-                || (key_name_conv_tab_sorted[lc_index]->shortcut == NULL))
+                || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
                 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
             else
-                g_string_append (s, key_name_conv_tab_sorted[lc_index]->shortcut);
+                g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
         }
-        else if ((lc_index != -1) && (key_name_conv_tab_sorted[lc_index]->shortcut != NULL))
-            g_string_append (s, key_name_conv_tab_sorted[lc_index]->shortcut);
+        else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
+            g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
         else
             g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
 
@@ -1470,6 +1519,82 @@ lookup_key (const char *name, char **label)
     return (long) k;
 }
 
+/* --------------------------------------------------------------------------------------------- */
+
+char *
+lookup_key_by_code (const int keycode)
+{
+    /* code without modifier */
+    unsigned int k = keycode & ~KEY_M_MASK;
+    /* modifier */
+    unsigned int mod = keycode & KEY_M_MASK;
+
+    int use_meta = -1;
+    int use_ctrl = -1;
+    int use_shift = -1;
+    int key_idx = -1;
+
+    GString *s;
+    int idx;
+
+    s = g_string_sized_new (8);
+
+    if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
+    {
+        if (mod & KEY_M_ALT)
+        {
+            if (lookup_keycode (KEY_M_ALT, &idx))
+            {
+                use_meta = idx;
+                g_string_append (s, key_conv_tab_sorted[use_meta]->name);
+                g_string_append_c (s, '-');
+            }
+        }
+        if (mod & KEY_M_CTRL)
+        {
+            /* non printeble chars like a CTRL-[A..Z] */
+            if (k < 32)
+                k += 64;
+
+            if (lookup_keycode (KEY_M_CTRL, &idx))
+            {
+                use_ctrl = idx;
+                g_string_append (s, key_conv_tab_sorted[use_ctrl]->name);
+                g_string_append_c (s, '-');
+            }
+        }
+        if (mod & KEY_M_SHIFT)
+        {
+            if (lookup_keycode (KEY_M_ALT, &idx))
+            {
+                use_shift = idx;
+                if (k < 127)
+                    g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
+                else
+                {
+                    g_string_append (s, key_conv_tab_sorted[use_shift]->name);
+                    g_string_append_c (s, '-');
+                    g_string_append (s, key_conv_tab_sorted[key_idx]->name);
+                }
+            }
+        }
+        else if (k < 128)
+        {
+            if ((k >= 'A') || (key_idx < 0)
+                || (key_conv_tab_sorted[key_idx]->name == NULL))
+                g_string_append_c (s, (gchar) k);
+            else
+                g_string_append (s, key_conv_tab_sorted[key_idx]->name);
+        }
+        else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
+            g_string_append (s, key_conv_tab_sorted[key_idx]->name);
+        else
+            g_string_append_c (s, (gchar) keycode);
+    }
+
+    return g_string_free (s, s->len == 0);
+}
+
 /* --------------------------------------------------------------------------------------------- */
 /**
  * Return TRUE on success, FALSE on error.
diff --git a/lib/tty/key.h b/lib/tty/key.h
index 91b8290da..d1d4ab4cd 100644
--- a/lib/tty/key.h
+++ b/lib/tty/key.h
@@ -68,7 +68,7 @@ void init_key_input_fd (void);
 void done_key (void);
 
 long lookup_key (const char *name, char **label);
-
+char *lookup_key_by_code (const int keycode);
 /* mouse support */
 int tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block);
 gboolean is_idle (void);
diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c
index c7d05162e..14c9af622 100644
--- a/src/editor/editcmd.c
+++ b/src/editor/editcmd.c
@@ -1392,11 +1392,10 @@ edit_macro_comparator (gconstpointer *macro1, gconstpointer *macro2)
 /* --------------------------------------------------------------------------------------------- */
 
 static void
-edit_macro_sort_by_hotkey (WEdit *edit)
+edit_macro_sort_by_hotkey (void)
 {
-    if (macros_list == NULL || macros_list->len == 0)
-        return;
-    g_array_sort (macros_list, (GCompareFunc) edit_macro_comparator);
+    if (macros_list != NULL && macros_list->len != 0)
+        g_array_sort (macros_list, (GCompareFunc) edit_macro_comparator);
 }
 
 /* --------------------------------------------------------------------------------------------- */
@@ -1407,6 +1406,9 @@ edit_get_macro (WEdit * edit, int hotkey, const macros_t **macros, guint *indx)
     const macros_t *array_start = &g_array_index (macros_list, struct macros_t, 0);
     macros_t *result;
     macros_t search_macro;
+
+    (void) edit;
+
     search_macro.hotkey = hotkey;
     result = bsearch (&search_macro, macros_list->data, macros_list->len,
                       sizeof (macros_t), (GCompareFunc) edit_macro_comparator);
@@ -1431,8 +1433,7 @@ edit_delete_macro (WEdit * edit, int hotkey)
     const char *section_name = "editor";
     gchar *macros_fname;
     guint indx;
-    char keyname[8];
-
+    char *keyname;
     const macros_t *macros = NULL;
 
     /* clear array of actions for current hotkey */
@@ -1442,7 +1443,7 @@ edit_delete_macro (WEdit * edit, int hotkey)
             g_array_free (macros->macro, TRUE);
         macros = NULL;
         g_array_remove_index (macros_list, indx);
-        edit_macro_sort_by_hotkey (edit);
+        edit_macro_sort_by_hotkey ();
     }
 
     macros_fname = g_build_filename (mc_config_get_path (), MC_MACRO_FILE, NULL);
@@ -1452,14 +1453,15 @@ edit_delete_macro (WEdit * edit, int hotkey)
     if (macros_config == NULL)
         return FALSE;
 
-    g_snprintf (keyname, sizeof (keyname), "%i", hotkey);
-    while (mc_config_del_key (macros_config, section_name, keyname));
+    keyname = lookup_key_by_code (hotkey);
+    while (mc_config_del_key (macros_config, section_name, keyname))
+        ;
+    g_free (keyname);
     mc_config_save_file (macros_config, NULL);
     mc_config_deinit (macros_config);
     return TRUE;
 }
 
-
 /* --------------------------------------------------------------------------------------------- */
 
 void
@@ -1515,7 +1517,6 @@ edit_store_macro_cmd (WEdit * edit)
 {
     int i;
     int hotkey;
-    char keyname[8];
     GString *marcros_string;
     mc_config_t *macros_config = NULL;
     const char *section_name = "editor";
@@ -1523,6 +1524,7 @@ edit_store_macro_cmd (WEdit * edit)
     GArray *macros; /* current macro */
     int tmp_act;
     gboolean have_macro = FALSE;
+    char *keyname = NULL;
 
     hotkey = editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), 1);
     if (hotkey == ESC_CHAR)
@@ -1545,13 +1547,13 @@ edit_store_macro_cmd (WEdit * edit)
     if (macros_config == NULL)
         return FALSE;
 
-    g_snprintf (keyname, sizeof (keyname), "%i", hotkey);
-
-    marcros_string = g_string_sized_new (250);
-
     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
 
+    marcros_string = g_string_sized_new (250);
     macros = g_array_new (TRUE, FALSE, sizeof (macro_action_t));
+
+    keyname = lookup_key_by_code (hotkey);
+
     for (i = 0; i < macro_index; i++)
     {
         macro_action_t m_act;
@@ -1579,7 +1581,8 @@ edit_store_macro_cmd (WEdit * edit)
     else
         mc_config_del_key (macros_config, section_name, keyname);
 
-    edit_macro_sort_by_hotkey (edit);
+    g_free (keyname);
+    edit_macro_sort_by_hotkey ();
 
     g_string_free (marcros_string, TRUE);
     mc_config_save_file (macros_config, NULL);
@@ -1658,8 +1661,9 @@ edit_load_macro_cmd (WEdit * edit)
 
         curr_values = values = mc_config_get_string_list (macros_config, section_name,
                                                           *profile_keys, &values_len);
-        hotkey = strtol (*profile_keys, NULL, 0);
+        hotkey = lookup_key (*profile_keys, NULL);
         have_macro = FALSE;
+
         while (*curr_values != NULL && *curr_values[0] != '\0')
         {
             char **macro_pair = NULL;
@@ -1712,7 +1716,7 @@ edit_load_macro_cmd (WEdit * edit)
     }
     g_strfreev (keys);
     mc_config_deinit (macros_config);
-    edit_macro_sort_by_hotkey (edit);
+    edit_macro_sort_by_hotkey ();
     return TRUE;
 }
 

From 6066713f779080d143463bb52fe9f99c05e5ead8 Mon Sep 17 00:00:00 2001
From: Ilia Maslakov <il.smind@gmail.com>
Date: Fri, 21 Jan 2011 21:41:42 +0000
Subject: [PATCH 03/10] Removed unneeded menu entries.

Signed-off-by: Ilia Maslakov <il.smind@gmail.com>
---
 src/editor/editmenu.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/src/editor/editmenu.c b/src/editor/editmenu.c
index 444bb7da2..bc2c4aa25 100644
--- a/src/editor/editmenu.c
+++ b/src/editor/editmenu.c
@@ -168,11 +168,7 @@ create_command_menu (void)
     entries = g_list_append (entries, menu_separator_create ());
     entries =
         g_list_append (entries,
-                       menu_entry_create (_("&Start record macro"), CK_Begin_Record_Macro));
-    entries =
-        g_list_append (entries,
-                       menu_entry_create (_("Finis&h record macro..."), CK_End_Record_Macro));
-    entries = g_list_append (entries, menu_entry_create (_("&Execute macro..."), CK_Execute_Macro));
+                       menu_entry_create (_("&Start/Stop record macro"), CK_Begin_End_Macro));
     entries = g_list_append (entries, menu_entry_create (_("Delete macr&o..."), CK_Delete_Macro));
     entries = g_list_append (entries, menu_separator_create ());
     entries =

From 83177cfc16855aab6de144cdeba42b34266e7bcc Mon Sep 17 00:00:00 2001
From: Ilia Maslakov <il.smind@gmail.com>
Date: Mon, 24 Jan 2011 18:55:00 +0300
Subject: [PATCH 04/10]     added a new action "Record and Repeat commands",
 added menu entry (Record/Repeat actions) for this.

Signed-off-by: Ilia Maslakov <il.smind@gmail.com>

some fixes

Signed-off-by: Slava Zanko <slavazanko@gmail.com>

and one more fix

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
---
 lib/keybind.c          |  1 +
 lib/keybind.h          | 21 ++++++++++++---------
 misc/mc.keymap.default |  2 ++
 misc/mc.keymap.emacs   |  2 ++
 src/editor/edit-impl.h |  2 ++
 src/editor/edit.c      | 24 +++++++++++++++++++-----
 src/editor/editcmd.c   | 23 ++++++++++++++++++-----
 src/editor/editmenu.c  |  1 +
 src/history.h          |  1 +
 9 files changed, 58 insertions(+), 19 deletions(-)

diff --git a/lib/keybind.c b/lib/keybind.c
index 2d064e2b6..5b7c6a5b5 100644
--- a/lib/keybind.c
+++ b/lib/keybind.c
@@ -134,6 +134,7 @@ static name_keymap_t command_names[] = {
     {"EditUserMenu", CK_User_Menu},
     {"EditBeginRecordMacro", CK_Begin_Record_Macro},
     {"EditEndRecordMacro", CK_End_Record_Macro},
+    {"EditBeginEndRepeat", CK_Begin_End_Repeat},
     {"EditDeleteMacro", CK_Delete_Macro},
     {"EditToggleBookmark", CK_Toggle_Bookmark},
     {"EditFlushBookmarks", CK_Flush_Bookmarks},
diff --git a/lib/keybind.h b/lib/keybind.h
index 90b0d41f9..20bf4244a 100644
--- a/lib/keybind.h
+++ b/lib/keybind.h
@@ -189,19 +189,22 @@
 #define CK_Paragraph_Down_Alt_Highlight    671
 
 /* X clipboard operations */
-#define CK_XStore            701
-#define CK_XCut              702
-#define CK_XPaste            703
-#define CK_Selection_History 704
+#define CK_XStore                        701
+#define CK_XCut                          702
+#define CK_XPaste                        703
+#define CK_Selection_History             704
 
-#define CK_Shell           801
+#define CK_Shell                         801
 
 /* C-x or similar */
-#define CK_Ext_Mode        820
+#define CK_Ext_Mode                      820
 
-#define CK_Insert_Literal  851
-#define CK_Execute_Macro   852
-#define CK_Begin_End_Macro 853
+#define CK_Insert_Literal                851
+#define CK_Execute_Macro                 852
+#define CK_Begin_End_Macro               853
+#define CK_Begin_End_Repeat              854
+#define CK_Begin_Record_Repeat           855
+#define CK_End_Record_Repeat             856
 
 /* help */
 #define CK_HelpHelp                     1001
diff --git a/misc/mc.keymap.default b/misc/mc.keymap.default
index 356fa5cda..e0f3374ab 100644
--- a/misc/mc.keymap.default
+++ b/misc/mc.keymap.default
@@ -160,6 +160,8 @@ EditFindDefinition = alt-enter
 EditLoadPrevFile = alt-minus
 EditLoadNextFile = alt-plus
 
+EditBeginEndRepeat =
+
 SelectCodepage = alt-e
 
 [viewer]
diff --git a/misc/mc.keymap.emacs b/misc/mc.keymap.emacs
index 0d357ce3e..53c1d231a 100644
--- a/misc/mc.keymap.emacs
+++ b/misc/mc.keymap.emacs
@@ -157,6 +157,8 @@ EditFindDefinition = alt-enter
 EditLoadPrevFile = alt-minus
 EditLoadNextFile = alt-plus
 
+EditBeginEndRepeat =
+
 SelectCodepage = alt-e
 
 EditExtMode = ctrl-x
diff --git a/src/editor/edit-impl.h b/src/editor/edit-impl.h
index 809272885..5b49e316c 100644
--- a/src/editor/edit-impl.h
+++ b/src/editor/edit-impl.h
@@ -308,6 +308,7 @@ void edit_help_cmd (WEdit * edit);
 int edit_store_macro_cmd (WEdit * edit);
 gboolean edit_load_macro_cmd (WEdit * edit);
 void edit_delete_macro_cmd (WEdit * edit);
+gboolean edit_repeat_macro_cmd (WEdit * edit);
 
 int edit_copy_to_X_buf_cmd (WEdit * edit);
 int edit_cut_to_X_buf_cmd (WEdit * edit);
@@ -318,6 +319,7 @@ void edit_insert_literal_cmd (WEdit * edit);
 void edit_execute_macro_cmd (WEdit * edit);
 gboolean edit_execute_macro (WEdit * edit, int hotkey);
 void edit_begin_end_macro_cmd (WEdit * edit);
+void edit_begin_end_repeat_cmd (WEdit * edit);
 
 void edit_paste_from_history (WEdit * edit);
 
diff --git a/src/editor/edit.c b/src/editor/edit.c
index 5d49e93f2..84b1e3813 100644
--- a/src/editor/edit.c
+++ b/src/editor/edit.c
@@ -3379,18 +3379,29 @@ edit_find_bracket (WEdit * edit)
 void
 edit_execute_key_command (WEdit * edit, unsigned long command, int char_for_insertion)
 {
-    if (command == CK_Begin_Record_Macro || (command == CK_Begin_End_Macro && macro_index < 0))
+    if (command == CK_Begin_Record_Macro || command == CK_Begin_Record_Repeat
+        || (macro_index < 0 && (command == CK_Begin_End_Macro || command == CK_Begin_End_Repeat)))
     {
         macro_index = 0;
         edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
         return;
     }
-    if ((command == CK_End_Record_Macro || command == CK_Begin_End_Macro) && macro_index != -1)
+    if (macro_index != -1)
     {
         edit->force |= REDRAW_COMPLETELY;
-        edit_store_macro_cmd (edit);
-        macro_index = -1;
-        return;
+        if (command == CK_End_Record_Macro || command == CK_Begin_End_Macro)
+        {
+            edit_store_macro_cmd (edit);
+            macro_index = -1;
+            return;
+        }
+        else if (command == CK_End_Record_Repeat || command == CK_Begin_End_Repeat)
+        {
+            edit_repeat_macro_cmd (edit);
+            macro_index = -1;
+            return;
+        }
+
     }
 
     if (macro_index >= 0 && macro_index < MAX_MACRO_LENGTH - 1)
@@ -4117,6 +4128,9 @@ edit_execute_cmd (WEdit * edit, unsigned long command, int char_for_insertion)
     case CK_Begin_End_Macro:
         edit_begin_end_macro_cmd (edit);
         break;
+    case CK_Begin_End_Repeat:
+        edit_begin_end_repeat_cmd (edit);
+        break;
     case CK_Ext_Mode:
         edit->extmod = 1;
         break;
diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c
index 14c9af622..e763b4b40 100644
--- a/src/editor/editcmd.c
+++ b/src/editor/editcmd.c
@@ -1590,7 +1590,7 @@ edit_store_macro_cmd (WEdit * edit)
     return TRUE;
 }
 
-/* --------------------------------------------------------------------------------------------- */
+ /* --------------------------------------------------------------------------------------------- */
 
 gboolean
 edit_repeat_macro_cmd (WEdit * edit)
@@ -1600,7 +1600,7 @@ edit_repeat_macro_cmd (WEdit * edit)
     long count_repeat;
     char *error = NULL;
 
-    f = input_dialog (_("Repeat last commands"), _("Repeat times:"), NULL, "1");
+    f = input_dialog (_("Repeat last commands"), _("Repeat times:"), MC_HISTORY_EDIT_REPEAT, NULL);
     if (f == NULL || *f == '\0')
     {
         g_free (f);
@@ -1609,7 +1609,7 @@ edit_repeat_macro_cmd (WEdit * edit)
 
     count_repeat = strtol (f, &error, 0);
 
-    if (error != NULL)
+    if (*error != '\0')
     {
         g_free (f);
         return FALSE;
@@ -1618,8 +1618,8 @@ edit_repeat_macro_cmd (WEdit * edit)
     g_free (f);
 
     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
-
     edit->force |= REDRAW_PAGE;
+
     for (j = 0; j < count_repeat; j++)
         for (i = 0; i < macro_index; i++)
             edit_execute_cmd (edit, record_macro_buf[i].action, record_macro_buf[i].ch);
@@ -3155,13 +3155,26 @@ void
 edit_begin_end_macro_cmd (WEdit * edit)
 {
     /* edit is a pointer to the widget */
-    if (edit)
+    if (edit != NULL)
     {
         unsigned long command = macro_index < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
         edit_execute_key_command (edit, command, -1);
     }
 }
 
+ /* --------------------------------------------------------------------------------------------- */
+
+void
+edit_begin_end_repeat_cmd (WEdit * edit)
+{
+    /* edit is a pointer to the widget */
+    if (edit != NULL)
+    {
+        unsigned long command = macro_index < 0 ? CK_Begin_Record_Repeat : CK_End_Record_Repeat;
+        edit_execute_key_command (edit, command, -1);
+    }
+}
+
 /* --------------------------------------------------------------------------------------------- */
 
 int
diff --git a/src/editor/editmenu.c b/src/editor/editmenu.c
index bc2c4aa25..58d8e4d6e 100644
--- a/src/editor/editmenu.c
+++ b/src/editor/editmenu.c
@@ -170,6 +170,7 @@ create_command_menu (void)
         g_list_append (entries,
                        menu_entry_create (_("&Start/Stop record macro"), CK_Begin_End_Macro));
     entries = g_list_append (entries, menu_entry_create (_("Delete macr&o..."), CK_Delete_Macro));
+    entries = g_list_append (entries, menu_entry_create (_("Record/Repeat &actions"), CK_Begin_End_Repeat));
     entries = g_list_append (entries, menu_separator_create ());
     entries =
         g_list_append (entries, menu_entry_create (_("'ispell' s&pell check"), CK_Pipe_Block (1)));
diff --git a/src/history.h b/src/history.h
index 370ce925e..d032942cc 100644
--- a/src/history.h
+++ b/src/history.h
@@ -16,6 +16,7 @@
 #define MC_HISTORY_EDIT_GOTO_LINE     "mc.edit.goto-line"
 #define MC_HISTORY_EDIT_SORT          "mc.edit.sort"
 #define MC_HISTORY_EDIT_PASTE_EXTCMD  "mc.edit.paste-extcmd"
+#define MC_HISTORY_EDIT_REPEAT        "mc.edit.repeat-action"
 
 #define MC_HISTORY_FM_VIEW_FILE       "mc.fm.view-file"
 #define MC_HISTORY_FM_MKDIR           "mc.fm.mkdir"

From d31116328a7359396325de466124f0b9462190f1 Mon Sep 17 00:00:00 2001
From: Ilia Maslakov <il.smind@gmail.com>
Date: Wed, 26 Jan 2011 00:12:30 +0000
Subject: [PATCH 05/10] Changed engine of external macros execution

Now "EditPipeBlock (X)" action tries execute the
~/.local/share/mc/mcedit/macros.d/macro.X.sh script.
To bind action EditPipeBlock (X) to the any hotkey you need add this binding
into ~/.local/share/mc/mc.macros file like following:

[editor]
ctrl-Q=EditWordLeft:-1;EditWordRightHighlight:-1;EditPipeBlock:3;
ctrl-W=EditPipeBlock:1;

This means that "ctrl-W" hotkey initiates the EditPipeBlock (1) action,
editor handler translates this into execution of
~/.local/share/mc/mcedit/macros.d/macro.1.sh shell script.

Signed-off-by: Ilia Maslakov <il.smind@gmail.com>
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
---
 lib/fileloc.h              |   1 +
 lib/keybind.c              |   1 -
 lib/keybind.h              |  11 ---
 src/editor/edit-impl.h     |   4 +-
 src/editor/edit.c          |  25 +++---
 src/editor/editcmd.c       | 158 ++++---------------------------------
 src/filemanager/cmd.c      |   2 +-
 src/filemanager/usermenu.c |  63 ++++++++++-----
 src/filemanager/usermenu.h |   2 +-
 src/keybind-defaults.c     |   2 -
 10 files changed, 75 insertions(+), 194 deletions(-)

diff --git a/lib/fileloc.h b/lib/fileloc.h
index 12133aaef..6f80db82b 100644
--- a/lib/fileloc.h
+++ b/lib/fileloc.h
@@ -66,6 +66,7 @@
 #define EDIT_DIR                "mcedit"
 
 /* file names */
+#define MC_EXTMACRO_FILE        EDIT_DIR PATH_SEP_STR "macros.d" PATH_SEP_STR "macro"
 #define EDIT_SYNTAX_FILE        EDIT_DIR PATH_SEP_STR "Syntax"
 #define EDIT_CLIP_FILE          EDIT_DIR PATH_SEP_STR "mcedit.clip"
 #define EDIT_BLOCK_FILE         EDIT_DIR PATH_SEP_STR "mcedit.block"
diff --git a/lib/keybind.c b/lib/keybind.c
index 5b7c6a5b5..a4f409395 100644
--- a/lib/keybind.c
+++ b/lib/keybind.c
@@ -187,7 +187,6 @@ static name_keymap_t command_names[] = {
     {"EditSelectionHistory", CK_Selection_History},
     {"EditShell", CK_Shell},
     {"EditInsertLiteral", CK_Insert_Literal},
-    {"EditExecuteMacro", CK_Execute_Macro},
     {"EditBeginOrEndMacro", CK_Begin_End_Macro},
     {"EditExtMode", CK_Ext_Mode},
     {"EditToggleLineState", CK_Toggle_Line_State},
diff --git a/lib/keybind.h b/lib/keybind.h
index 20bf4244a..7a7f1b80f 100644
--- a/lib/keybind.h
+++ b/lib/keybind.h
@@ -200,7 +200,6 @@
 #define CK_Ext_Mode                      820
 
 #define CK_Insert_Literal                851
-#define CK_Execute_Macro                 852
 #define CK_Begin_End_Macro               853
 #define CK_Begin_End_Repeat              854
 #define CK_Begin_Record_Repeat           855
@@ -501,17 +500,7 @@
 #define CK_DiffContinueSearch           9037
 #define CK_DiffOptions                  9038
 
-/*
-   Process a block through a shell command: CK_Pipe_Block(i) executes shell_cmd[i].
-   shell_cmd[i] must process the file ~/cooledit.block and output ~/cooledit.block
-   which is then inserted into the text in place of the original block. shell_cmd[i] must
-   also produce a file homedir/cooledit.error . If this file is not empty an error will
-   have been assumed to have occured, and the block will not be replaced.
-   TODO: bring up a viewer to display the error message instead of inserting
-   it into the text, which is annoying.
- */
 #define CK_Pipe_Block(i) (10000+(i))
-#define SHELL_COMMANDS_i {"/edit.indent.rc", "/edit.spell.rc", /* and so on */ 0 }
 #define CK_Macro(i)      (20000+(i))
 #define CK_Last_Macro    CK_Macro(0x7FFF)
 
diff --git a/src/editor/edit-impl.h b/src/editor/edit-impl.h
index 5b49e316c..05019d208 100644
--- a/src/editor/edit-impl.h
+++ b/src/editor/edit-impl.h
@@ -215,6 +215,7 @@ extern gboolean search_create_bookmark;
 
 int edit_drop_hotkey_menu (WEdit * e, int key);
 void edit_menu_cmd (WEdit * e);
+void user_menu (WEdit * edit, const char *menu_file, int selected_entry);
 void edit_init_menu (struct WMenuBar *menubar);
 void menu_save_mode_cmd (void);
 int edit_translate_key (WEdit * edit, long x_key, int *cmd, int *ch);
@@ -289,7 +290,7 @@ int edit_insert_column_of_text_from_file (WEdit * edit, int file);
 long edit_insert_file (WEdit * edit, const char *filename);
 int edit_load_back_cmd (WEdit * edit);
 int edit_load_forward_cmd (WEdit * edit);
-void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block);
+void edit_block_process_cmd (WEdit * edit, int macro_number);
 void edit_refresh_cmd (WEdit * edit);
 void edit_date_cmd (WEdit * edit);
 void edit_goto_cmd (WEdit * edit);
@@ -316,7 +317,6 @@ void edit_paste_from_X_buf_cmd (WEdit * edit);
 
 void edit_select_codepage_cmd (WEdit * edit);
 void edit_insert_literal_cmd (WEdit * edit);
-void edit_execute_macro_cmd (WEdit * edit);
 gboolean edit_execute_macro (WEdit * edit, int hotkey);
 void edit_begin_end_macro_cmd (WEdit * edit);
 void edit_begin_end_repeat_cmd (WEdit * edit);
diff --git a/src/editor/edit.c b/src/editor/edit.c
index 84b1e3813..90dfa63cb 100644
--- a/src/editor/edit.c
+++ b/src/editor/edit.c
@@ -132,8 +132,6 @@ static const struct edit_filters
 
 static long last_bracket = -1;
 
-static const char *const shell_cmd[] = SHELL_COMMANDS_i;
-
 /*** file scope functions ************************************************************************/
 /* --------------------------------------------------------------------------------------------- */
 
@@ -167,7 +165,6 @@ static const char *const shell_cmd[] = SHELL_COMMANDS_i;
 
 /* --------------------------------------------------------------------------------------------- */
 
-static void user_menu (WEdit * edit);
 static int left_of_four_spaces (WEdit * edit);
 
 /* --------------------------------------------------------------------------------------------- */
@@ -1661,10 +1658,13 @@ edit_goto_matching_bracket (WEdit * edit)
 }
 
 /* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
 /** User edit menu, like user menu (F2) but only in editor. */
 
-static void
-user_menu (WEdit * edit)
+void
+user_menu (WEdit * edit, const char *menu_file, int selected_entry)
 {
     char *block_file;
     int nomark;
@@ -1678,7 +1678,9 @@ user_menu (WEdit * edit)
         edit_save_block (edit, block_file, start_mark, end_mark);
 
     /* run shell scripts from menu */
-    if (user_menu_cmd (edit) && (mc_stat (block_file, &status) == 0) && (status.st_size != 0))
+    if (user_menu_cmd (edit, menu_file, selected_entry)
+        && (mc_stat (block_file, &status) == 0)
+        && (status.st_size != 0))
     {
         int rc = 0;
         FILE *fd;
@@ -1706,8 +1708,6 @@ user_menu (WEdit * edit)
     g_free (block_file);
 }
 
-/* --------------------------------------------------------------------------------------------- */
-/*** public functions ****************************************************************************/
 /* --------------------------------------------------------------------------------------------- */
 
 int
@@ -4102,7 +4102,7 @@ edit_execute_cmd (WEdit * edit, unsigned long command, int char_for_insertion)
         edit_goto_matching_bracket (edit);
         break;
     case CK_User_Menu:
-        user_menu (edit);
+        user_menu (edit, NULL, -1);
         break;
     case CK_Sort:
         edit_sort_cmd (edit);
@@ -4122,9 +4122,6 @@ edit_execute_cmd (WEdit * edit, unsigned long command, int char_for_insertion)
     case CK_Insert_Literal:
         edit_insert_literal_cmd (edit);
         break;
-    case CK_Execute_Macro:
-        edit_execute_macro_cmd (edit);
-        break;
     case CK_Begin_End_Macro:
         edit_begin_end_macro_cmd (edit);
         break;
@@ -4139,8 +4136,8 @@ edit_execute_cmd (WEdit * edit, unsigned long command, int char_for_insertion)
     }
 
     /* CK_Pipe_Block */
-    if ((command / 10000) == 1)  /* a shell command */
-        edit_block_process_cmd (edit, shell_cmd[command - 10000], 1);
+    if ((command / CK_Pipe_Block (0)) == 1)
+        edit_block_process_cmd (edit, command - CK_Pipe_Block (0));
 
     /* keys which must set the col position, and the search vars */
     switch (command)
diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c
index e763b4b40..728683cd8 100644
--- a/src/editor/editcmd.c
+++ b/src/editor/editcmd.c
@@ -1446,7 +1446,7 @@ edit_delete_macro (WEdit * edit, int hotkey)
         edit_macro_sort_by_hotkey ();
     }
 
-    macros_fname = g_build_filename (mc_config_get_path (), MC_MACRO_FILE, NULL);
+    macros_fname = g_build_filename (mc_config_get_data_path (), MC_MACRO_FILE, (char *) NULL);
     macros_config = mc_config_init (macros_fname);
     g_free (macros_fname);
 
@@ -1540,7 +1540,7 @@ edit_store_macro_cmd (WEdit * edit)
 
     edit_delete_macro (edit, hotkey);
 
-    macros_fname = g_build_filename (mc_config_get_path (), MC_MACRO_FILE, NULL);
+    macros_fname = g_build_filename (mc_config_get_data_path (), MC_MACRO_FILE, (char *) NULL);
     macros_config = mc_config_init (macros_fname);
     g_free (macros_fname);
 
@@ -1643,7 +1643,7 @@ edit_load_macro_cmd (WEdit * edit)
 
     (void) edit;
 
-    macros_fname = g_build_filename (mc_config_get_path (), MC_MACRO_FILE, NULL);
+    macros_fname = g_build_filename (mc_config_get_data_path (), MC_MACRO_FILE, (char *) NULL);
     macros_config = mc_config_init (macros_fname);
     g_free (macros_fname);
 
@@ -1673,19 +1673,19 @@ edit_load_macro_cmd (WEdit * edit)
             if (macro_pair != NULL)
             {
                 macro_action_t m_act;
-                if (macro_pair [0] == NULL || macro_pair [0][0] == '\0')
+                if (macro_pair[0] == NULL || macro_pair[0][0] == '\0')
                     m_act.action = 0;
                 else
                 {
-                    m_act.action = keybind_lookup_action (macro_pair [0]);
+                    m_act.action = keybind_lookup_action (macro_pair[0]);
                     g_free (macro_pair[0]);
                     macro_pair[0] = NULL;
                 }
-                if (macro_pair [1] == NULL || macro_pair [1][0] == '\0')
+                if (macro_pair[1] == NULL || macro_pair[1][0] == '\0')
                     m_act.ch = -1;
                 else
                 {
-                    m_act.ch = strtol (macro_pair [1], NULL, 0);
+                    m_act.ch = strtol (macro_pair[1], NULL, 0);
                     g_free (macro_pair[1]);
                     macro_pair[1] = NULL;
                 }
@@ -2852,129 +2852,17 @@ edit_ext_cmd (WEdit * edit)
    command, that just produces some output which is to be inserted */
 
 void
-edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
+edit_block_process_cmd (WEdit * edit, int macro_number)
 {
-    long start_mark, end_mark;
-    char buf[BUFSIZ];
-    FILE *script_home = NULL;
-    FILE *block_file = NULL;
-    gchar *o, *h, *b, *tmp;
-    char *quoted_name = NULL;
+    char *fname;
+    char *macros_fname = NULL;
 
-    o = g_strconcat (mc_sysconfig_dir, shell_cmd, (char *) NULL);        /* original source script */
-    h = g_strconcat (mc_config_get_data_path (), PATH_SEP_STR EDIT_DIR, shell_cmd, (char *) NULL);     /* home script */
-    b = concat_dir_and_file (mc_config_get_cache_path (), EDIT_BLOCK_FILE);     /* block file */
-
-    script_home = fopen (h, "r");
-    if (script_home == NULL)
-    {
-        FILE *script_src = NULL;
-
-        script_home = fopen (h, "w");
-        if (script_home == NULL)
-        {
-            tmp = g_strconcat (_("Error creating script:"), h, (char *) NULL);
-            edit_error_dialog ("", get_sys_error (tmp));
-            g_free (tmp);
-            goto edit_block_process_cmd__EXIT;
-        }
-
-        script_src = fopen (o, "r");
-        if (script_src == NULL)
-        {
-            o = g_strconcat (mc_share_data_dir, shell_cmd, (char *) NULL);
-            script_src = fopen (o, "r");
-            if (script_src == NULL)
-            {
-                fclose (script_home);
-                unlink (h);
-                tmp = g_strconcat (_("Error reading script:"), o, (char *) NULL);
-                edit_error_dialog ("", get_sys_error (tmp));
-                g_free (tmp);
-                goto edit_block_process_cmd__EXIT;
-            }
-        }
-        while (fgets (buf, sizeof (buf), script_src))
-            fputs (buf, script_home);
-        fclose (script_src);
-
-        if (fclose (script_home))
-        {
-            tmp = g_strconcat (_("Error closing script:"), h, (char *) NULL);
-            edit_error_dialog ("", get_sys_error (tmp));
-            g_free (tmp);
-            goto edit_block_process_cmd__EXIT;
-        }
-        chmod (h, 0700);
-        tmp = g_strconcat (_("Script created:"), h, (char *) NULL);
-        edit_error_dialog ("", get_sys_error (tmp));
-        g_free (tmp);
-    }
-
-    open_error_pipe ();
-
-    if (block)
-    {                           /* for marked block run indent formatter */
-        if (eval_marks (edit, &start_mark, &end_mark))
-        {
-            edit_error_dialog (_("Process block"), _("You must first highlight a block of text"));
-            goto edit_block_process_cmd__EXIT;
-        }
-        edit_save_block (edit, b, start_mark, end_mark);
-        quoted_name = name_quote (edit->filename, 0);
-        /*
-         * Run script.
-         * Initial space is to avoid polluting bash history.
-         * Arguments:
-         *   $1 - name of the edited file (to check its extension etc).
-         *   $2 - file containing the current block.
-         *   $3 - file where error messages should be put
-         *        (for compatibility with old scripts).
-         */
-        tmp =
-            g_strconcat (" ", mc_config_get_cache_path (), PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
-                         quoted_name, " ", mc_config_get_cache_path (),
-                         PATH_SEP_STR EDIT_BLOCK_FILE " /dev/null", (char *) NULL);
-    }
-    else
-    {
-        /*
-         * No block selected, just execute the command for the file.
-         * Arguments:
-         *   $1 - name of the edited file.
-         */
-        tmp = g_strconcat (" ", mc_config_get_cache_path (), PATH_SEP_STR EDIT_DIR, shell_cmd, " ",
-                           quoted_name, (char *) NULL);
-    }
-
-    if (system (tmp) == -1)
-    {
-        edit_error_dialog (_("Process block"), _("Error calling program"));
-    }
-    else
-    {
-
-        g_free (quoted_name);
-        close_error_pipe (D_NORMAL, NULL);
-
-        edit_refresh_cmd (edit);
-        edit->force |= REDRAW_COMPLETELY;
-
-        /* insert result block */
-        if (block && !edit_block_delete_cmd (edit))
-        {
-            edit_insert_file (edit, b);
-            block_file = fopen (b, "w");
-            if (block_file != NULL)
-                fclose (block_file);
-        }
-    }
-    g_free (tmp);
-
-  edit_block_process_cmd__EXIT:
-    g_free (b);
-    g_free (h);
-    g_free (o);
+    fname = g_strdup_printf ("%s.%i.sh", MC_EXTMACRO_FILE, macro_number);
+    macros_fname = g_build_filename (mc_config_get_data_path (), fname, (char *) NULL);
+    user_menu (edit, macros_fname, 0);
+    g_free (fname);
+    g_free (macros_fname);
+    edit->force |= REDRAW_COMPLETELY;
 }
 
 /* --------------------------------------------------------------------------------------------- */
@@ -3137,20 +3025,6 @@ edit_insert_literal_cmd (WEdit * edit)
 
 /* --------------------------------------------------------------------------------------------- */
 
-void
-edit_execute_macro_cmd (WEdit * edit)
-{
-    int command =
-        CK_Macro (editcmd_dialog_raw_key_query (_("Execute macro"), _("Press macro hotkey:"),
-                                                1));
-    if (command == CK_Macro (0))
-        command = CK_Insert_Char;
-
-    edit_execute_key_command (edit, command, -1);
-}
-
-/* --------------------------------------------------------------------------------------------- */
-
 void
 edit_begin_end_macro_cmd (WEdit * edit)
 {
diff --git a/src/filemanager/cmd.c b/src/filemanager/cmd.c
index a5d504e7f..42d58e910 100644
--- a/src/filemanager/cmd.c
+++ b/src/filemanager/cmd.c
@@ -1340,7 +1340,7 @@ help_cmd (void)
 void
 user_file_menu_cmd (void)
 {
-    (void) user_menu_cmd (NULL);
+    (void) user_menu_cmd (NULL, NULL, -1);
 }
 
 /* --------------------------------------------------------------------------------------------- */
diff --git a/src/filemanager/usermenu.c b/src/filemanager/usermenu.c
index 67b89f444..36c404da6 100644
--- a/src/filemanager/usermenu.c
+++ b/src/filemanager/usermenu.c
@@ -404,7 +404,7 @@ test_line (WEdit * edit_widget, char *p, int *result)
 /** FIXME: recode this routine on version 3.0, it could be cleaner */
 
 static void
-execute_menu_command (WEdit * edit_widget, const char *commands)
+execute_menu_command (WEdit * edit_widget, const char *commands, gboolean dont_show_prompt)
 {
     FILE *cmd_file;
     int cmd_file_fd;
@@ -534,7 +534,15 @@ execute_menu_command (WEdit * edit_widget, const char *commands)
         /* execute the command indirectly to allow execution even
          * on no-exec filesystems. */
         char *cmd = g_strconcat ("/bin/sh ", file_name, (char *) NULL);
-        shell_execute (cmd, EXECUTE_HIDE);
+        if (dont_show_prompt)
+        {
+            if (system (cmd) == -1)
+                message (D_ERROR, MSG_ERROR, "%s", _("Error calling program"));
+        }
+        else
+        {
+            shell_execute (cmd, EXECUTE_HIDE);
+        }
         g_free (cmd);
     }
     unlink (file_name);
@@ -851,7 +859,7 @@ expand_format (struct WEdit *edit_widget, char c, gboolean do_quote)
  */
 
 gboolean
-user_menu_cmd (struct WEdit *edit_widget)
+user_menu_cmd (struct WEdit *edit_widget, const char *menu_file, int selected_entry)
 {
     char *p;
     char *data, **entries;
@@ -866,10 +874,20 @@ user_menu_cmd (struct WEdit *edit_widget)
         message (D_ERROR, MSG_ERROR, "%s", _("Cannot execute commands on non-local filesystems"));
         return FALSE;
     }
-
-    menu = g_strdup (edit_widget ? EDIT_LOCAL_MENU : MC_LOCAL_MENU);
+    if (menu_file != NULL)
+        menu = g_strdup (menu_file);
+    else
+        menu = g_strdup (edit_widget ? EDIT_LOCAL_MENU : MC_LOCAL_MENU);
     if (!exist_file (menu) || !menu_file_own (menu))
     {
+        if (menu_file != NULL)
+        {
+            message (D_ERROR, MSG_ERROR, _("Cannot open file%s\n%s"), menu, unix_error_string (errno));
+            g_free (menu);
+            menu = NULL;
+            return FALSE;
+        }
+
         g_free (menu);
         if (edit_widget)
             menu = concat_dir_and_file (mc_config_get_data_path (), EDIT_HOME_MENU);
@@ -1006,25 +1024,30 @@ user_menu_cmd (struct WEdit *edit_widget)
     }
     else
     {
-        max_cols = min (max (max_cols, col), MAX_ENTRY_LEN);
-
-        /* Create listbox */
-        listbox = create_listbox_window (menu_lines, max_cols + 2, _("User menu"),
-                                         "[Menu File Edit]");
-        /* insert all the items found */
-        for (i = 0; i < menu_lines; i++)
+        if (selected_entry >= 0)
+            selected = selected_entry;
+        else
         {
-            p = entries[i];
-            LISTBOX_APPEND_TEXT (listbox, (unsigned char) p[0],
-                                 extract_line (p, p + MAX_ENTRY_LEN), p);
-        }
-        /* Select the default entry */
-        listbox_select_entry (listbox->list, selected);
+            max_cols = min (max (max_cols, col), MAX_ENTRY_LEN);
 
-        selected = run_listbox (listbox);
+            /* Create listbox */
+            listbox = create_listbox_window (menu_lines, max_cols + 2, _("User menu"),
+                                             "[Menu File Edit]");
+            /* insert all the items found */
+            for (i = 0; i < menu_lines; i++)
+            {
+                p = entries[i];
+                LISTBOX_APPEND_TEXT (listbox, (unsigned char) p[0],
+                                     extract_line (p, p + MAX_ENTRY_LEN), p);
+            }
+            /* Select the default entry */
+            listbox_select_entry (listbox->list, selected);
+
+            selected = run_listbox (listbox);
+        }
         if (selected >= 0)
         {
-            execute_menu_command (edit_widget, entries[selected]);
+            execute_menu_command (edit_widget, entries[selected], (selected_entry >= 0));
             res = TRUE;
         }
 
diff --git a/src/filemanager/usermenu.h b/src/filemanager/usermenu.h
index 9cbefccb2..9596d788a 100644
--- a/src/filemanager/usermenu.h
+++ b/src/filemanager/usermenu.h
@@ -19,7 +19,7 @@ struct WEdit;
 
 /*** declarations of public functions ************************************************************/
 
-gboolean user_menu_cmd (struct WEdit *edit_widget);
+gboolean user_menu_cmd (struct WEdit *edit_widget, const char * menu_file, int selected_entry);
 char *expand_format (struct WEdit *edit_widget, char c, gboolean do_quote);
 int check_format_view (const char *);
 int check_format_var (const char *, char **);
diff --git a/src/keybind-defaults.c b/src/keybind-defaults.c
index 381e44e5b..2b2626261 100644
--- a/src/keybind-defaults.c
+++ b/src/keybind-defaults.c
@@ -293,7 +293,6 @@ const global_keymap_t default_editor_keymap[] = {
     {XCTRL ('r'), CK_Begin_End_Macro, "C-r"},
     {XCTRL ('r'), CK_Begin_Record_Macro, "C-r"},
     {XCTRL ('r'), CK_End_Record_Macro, "C-r"},
-    {XCTRL ('a'), CK_Execute_Macro, "C-a"},
     {XCTRL ('f'), CK_Save_Block, "C-f"},
     /* Spell check */
     {XCTRL ('p'), CK_Pipe_Block (1), "C-p"},
@@ -361,7 +360,6 @@ const global_keymap_t default_editor_keymap[] = {
 /* emacs keyboard layout emulation */
 const global_keymap_t default_editor_x_keymap[] = {
     {'k', CK_New, "k"},
-    {'e', CK_Execute_Macro, "e"},
     {0, CK_Ignore_Key, ""}
 };
 #endif /* USE_INTERNAL_EDIT */

From b58e7e64fc2e630fe818cf79910db5601e37fe43 Mon Sep 17 00:00:00 2001
From: Ilia Maslakov <il.smind@gmail.com>
Date: Wed, 26 Jan 2011 22:35:41 +0000
Subject: [PATCH 06/10] Fix cursor position after execution of external script.

Signed-off-by: Ilia Maslakov <il.smind@gmail.com>
---
 src/editor/edit.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/editor/edit.c b/src/editor/edit.c
index 90dfa63cb..66b2dd5e8 100644
--- a/src/editor/edit.c
+++ b/src/editor/edit.c
@@ -1668,11 +1668,12 @@ user_menu (WEdit * edit, const char *menu_file, int selected_entry)
 {
     char *block_file;
     int nomark;
+    long curs;
     long start_mark, end_mark;
     struct stat status;
 
     block_file = concat_dir_and_file (mc_config_get_cache_path (), EDIT_BLOCK_FILE);
-
+    curs = edit->curs1;
     nomark = eval_marks (edit, &start_mark, &end_mark);
     if (nomark == 0)
         edit_save_block (edit, block_file, start_mark, end_mark);
@@ -1702,6 +1703,7 @@ user_menu (WEdit * edit, const char *menu_file, int selected_entry)
         if (fd != NULL)
             fclose (fd);
     }
+    edit_cursor_move (edit, curs - edit->curs1);
     edit_refresh_cmd (edit);
     edit->force |= REDRAW_COMPLETELY;
 

From 44381176288717803ee1c5a58774a511a46e5d93 Mon Sep 17 00:00:00 2001
From: Ilia Maslakov <il.smind@gmail.com>
Date: Fri, 28 Jan 2011 11:59:18 +0300
Subject: [PATCH 07/10] changed mcedit.1.in

Signed-off-by: Ilia Maslakov <il.smind@gmail.com>
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
---
 doc/man/mcedit.1.in | 127 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 101 insertions(+), 26 deletions(-)

diff --git a/doc/man/mcedit.1.in b/doc/man/mcedit.1.in
index 62a991217..11a607883 100644
--- a/doc/man/mcedit.1.in
+++ b/doc/man/mcedit.1.in
@@ -97,38 +97,113 @@ or
 .BR "Escape Tab" )
 completes the word under the cursor using the words used earlier in the
 file.
+.SH MACRO
 .PP
 To define a macro, press
 .B Ctrl\-R
 and then type out the keys you want to be executed.  Press
 .B Ctrl\-R
-again when finished.  You can then assign the macro to any key you like
-by pressing that key.  The macro is executed when you press
-.B Ctrl\-A
-and then the assigned key.  The macro is also executed if you press
-Meta, Ctrl, or Esc and the assigned key, provided that the key is not
-used for any other function.  The macro commands are stored in the file
-.BR ~/.local/share/mc/mcedit/mcedit.macros .
-Do NOT edit this file if you are going to use macros again in the same
-editing session, because
-.B mcedit
-caches macro key defines in memory.
-.B mcedit
-now overwrites a macro if a macro with the same key already exists,
-so you won't have to edit this file. You will also have to restart
-other running editors for macros to take effect.
-.P
-.B F19
-will format C, C++, Java or HTML code when it is highlighted.  An executable
-file called
-.B ~/.local/share/mc/mcedit/edit.indent.rc
-will be created for you from the default template.  Feel free to edit it
-if you need.
+again when finished.  The macro can be assigned to any key by pressing that key.
+The macro is executed when you press the assigned key.
 .PP
-.B C\-p
-will run ispell on a block of text in a similar way.  The script file
-will be called
-.BR ~/.local/share/mc/mcedit/edit.spell.rc .
+The macro commands are stored in section
+.B [editor]
+it the file
+.BR ~/.local/share/mc/mc.macros .
+.PP
+External scripts (filters) can be assigned into the any hotkey by edit
+.B mc.macros
+like following:
+.PP
+.nf
+[editor]
+ctrl\-W=EditPipeBlock:25;
+.fi
+.PP
+This means that ctrl\-W hotkey initiates the
+.I EditPipeBlock(25)
+action, next the editor handler translates this into execution of
+.B ~/.local/share/mc/mcedit/macros.d/macro.25.sh
+shell script.
+.PP
+External scripts stored into
+.B ~/.local/share/mc/mcedit/macros.d/
+directory and must named
+.B macro.XXXX.sh
+where
+.B XXXX
+is the number from 0 to 9999.
+See
+.B Menu File Edit
+for more detail about format of the script.
+.PP
+Next macro definition can be used:
+.TP
+.I %c
+The cursor column position number.
+.TP
+.I %i
+The indent of blank space, equal the cursor column.
+.TP
+.I %y
+The syntax type of current file.
+.TP
+.I %b
+The block file name.
+.TP
+.I %f
+The current file name.
+.TP
+.I %n
+Only the current file name without extension.
+.TP
+.I %x
+The extension of current file name.
+.TP
+.I %d
+The current directory name.
+.TP
+.I %F
+The current file in the unselected panel.
+.TP
+.I %D
+The directory name of the unselected panel.
+.TP
+.I %t
+The currently tagged files.
+.TP
+.I %T
+The tagged files in the unselected panel.
+.TP
+.I %u
+and
+.I %U
+Similar to the
+.I %t
+and
+.I %T
+macros, but in addition the files are untagged. You can use this macro
+only once per menu file entry or extension file entry, because next time
+there will be no tagged files.
+.TP
+.I %s
+and
+.I %S
+The selected files: The tagged files if there are any. Otherwise the
+current file.
+.PP
+Feel free to edit this files, if you need.
+Here is a sample external script:
+.PP
+.nf
+l       comment selection
+	TMPFILE=`mktemp ${MC_TMPDIR:\-/tmp}/up.XXXXXX` || exit 1
+	echo #if 0 > $TMPFILE
+	cat %b >> $TMPFILE
+	echo #endif >> $TMPFILE
+	cat $TMPFILE > %b
+	rm \-f $TMPFILE
+.fi
 .PP
 If some keys don't work, you can use
 .B Learn Keys

From b642e2e1e1732d16103bb5d9694cdc9d4536449c Mon Sep 17 00:00:00 2001
From: Ilia Maslakov <il.smind@gmail.com>
Date: Mon, 31 Jan 2011 22:08:15 +0000
Subject: [PATCH 08/10] added check for instruction "#interactive" in the
 script. if the external script contain #interactive then do show prompt.

Signed-off-by: Ilia Maslakov <il.smind@gmail.com>
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
---
 doc/man/mcedit.1.in        |  5 ++++-
 src/filemanager/usermenu.c | 10 +++++++---
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/doc/man/mcedit.1.in b/doc/man/mcedit.1.in
index 11a607883..bb7d014fa 100644
--- a/doc/man/mcedit.1.in
+++ b/doc/man/mcedit.1.in
@@ -137,7 +137,10 @@ See
 .B Menu File Edit
 for more detail about format of the script.
 .PP
-Next macro definition can be used:
+Following macro definition and directives can be used:
+.TP
+.I #interactive
+If this directive is set, then script starts in subshell.
 .TP
 .I %c
 The cursor column position number.
diff --git a/src/filemanager/usermenu.c b/src/filemanager/usermenu.c
index 36c404da6..c093776a9 100644
--- a/src/filemanager/usermenu.c
+++ b/src/filemanager/usermenu.c
@@ -404,7 +404,7 @@ test_line (WEdit * edit_widget, char *p, int *result)
 /** FIXME: recode this routine on version 3.0, it could be cleaner */
 
 static void
-execute_menu_command (WEdit * edit_widget, const char *commands, gboolean dont_show_prompt)
+execute_menu_command (WEdit * edit_widget, const char *commands, gboolean show_prompt)
 {
     FILE *cmd_file;
     int cmd_file_fd;
@@ -534,7 +534,7 @@ execute_menu_command (WEdit * edit_widget, const char *commands, gboolean dont_s
         /* execute the command indirectly to allow execution even
          * on no-exec filesystems. */
         char *cmd = g_strconcat ("/bin/sh ", file_name, (char *) NULL);
-        if (dont_show_prompt)
+        if (!show_prompt)
         {
             if (system (cmd) == -1)
                 message (D_ERROR, MSG_ERROR, "%s", _("Error calling program"));
@@ -868,6 +868,7 @@ user_menu_cmd (struct WEdit *edit_widget, const char *menu_file, int selected_en
     int selected, old_patterns;
     Listbox *listbox;
     gboolean res = FALSE;
+    gboolean interactive = FALSE;
 
     if (!vfs_current_is_local ())
     {
@@ -954,6 +955,9 @@ user_menu_cmd (struct WEdit *edit_widget, const char *menu_file, int selected_en
         {
             if (*p == '#')
             {
+                /* show prompt if first line of external script is #interactive */
+                if (selected_entry >= 0 && strncmp (p, "#interactive", 12) == 0)
+                    interactive = TRUE;
                 /* A commented menu entry */
                 accept_entry = 1;
             }
@@ -1047,7 +1051,7 @@ user_menu_cmd (struct WEdit *edit_widget, const char *menu_file, int selected_en
         }
         if (selected >= 0)
         {
-            execute_menu_command (edit_widget, entries[selected], (selected_entry >= 0));
+            execute_menu_command (edit_widget, entries[selected], interactive);
             res = TRUE;
         }
 

From 04d54931d0d078fcdc771dbba316d2ecb43803ee Mon Sep 17 00:00:00 2001
From: Ilia Maslakov <il.smind@gmail.com>
Date: Fri, 4 Feb 2011 13:15:43 +0300
Subject: [PATCH 09/10]     added examples     added rules for misc/macros.d/*.
 in the process of installation, example scripts will be copied into
 share/mc/examples/macros.d

Signed-off-by: Ilia Maslakov <il.smind@gmail.com>
---
 configure.ac              |  1 +
 misc/Makefile.am          |  3 +--
 misc/macros.d/Makefile.am | 11 +++++++++++
 misc/macros.d/macro.0.sh  |  6 ++++++
 misc/macros.d/macro.1.sh  |  5 +++++
 misc/macros.d/macro.2.sh  |  5 +++++
 misc/macros.d/macro.3.sh  |  5 +++++
 misc/macros.d/macro.4.sh  |  2 ++
 misc/macros.d/macro.5.sh  | 41 +++++++++++++++++++++++++++++++++++++++
 misc/mc.macros            |  9 +++++++++
 10 files changed, 86 insertions(+), 2 deletions(-)
 create mode 100644 misc/macros.d/Makefile.am
 create mode 100644 misc/macros.d/macro.0.sh
 create mode 100644 misc/macros.d/macro.1.sh
 create mode 100644 misc/macros.d/macro.2.sh
 create mode 100644 misc/macros.d/macro.3.sh
 create mode 100644 misc/macros.d/macro.4.sh
 create mode 100644 misc/macros.d/macro.5.sh
 create mode 100644 misc/mc.macros

diff --git a/configure.ac b/configure.ac
index 02c004213..ec77113d5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -529,6 +529,7 @@ contrib/dist/prototype
 
 misc/Makefile
 misc/skins/Makefile
+misc/macros.d/Makefile
 misc/mc.ext
 
 src/Makefile
diff --git a/misc/Makefile.am b/misc/Makefile.am
index c813eb903..4ed4e7a57 100644
--- a/misc/Makefile.am
+++ b/misc/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to create Makefile.in.
 
-SUBDIRS = skins syntax
+SUBDIRS = macros.d skins syntax
 
 LIBFILES_OUT = mc.ext
 
@@ -23,7 +23,6 @@ LIBFILES_CONST = \
 	mc.menu \
 	mc.menu.sr
 
-
 CLEANFILES = $(SCRIPTS_OUT)
 
 cfgdir = $(sysconfdir)/@PACKAGE@
diff --git a/misc/macros.d/Makefile.am b/misc/macros.d/Makefile.am
new file mode 100644
index 000000000..18594b7dd
--- /dev/null
+++ b/misc/macros.d/Makefile.am
@@ -0,0 +1,11 @@
+macrodir = $(pkgdatadir)/examples/macros.d
+
+macro_DATA = \
+	macro.0.sh \
+	macro.1.sh \
+	macro.3.sh \
+	macro.4.sh \
+	macro.5.sh
+
+EXTRA_DIST = \
+    $(macro_DATA)
diff --git a/misc/macros.d/macro.0.sh b/misc/macros.d/macro.0.sh
new file mode 100644
index 000000000..983b90715
--- /dev/null
+++ b/misc/macros.d/macro.0.sh
@@ -0,0 +1,6 @@
+#interactive
+m       make
+        TMPFILE=`mktemp ${MC_TMPDIR:-/tmp}/up.XXXXXX` || exit 1
+        make 2> $TMPFILE
+        mcedit $TMPFILE
+        rm $TMPFILE
diff --git a/misc/macros.d/macro.1.sh b/misc/macros.d/macro.1.sh
new file mode 100644
index 000000000..0a881ba15
--- /dev/null
+++ b/misc/macros.d/macro.1.sh
@@ -0,0 +1,5 @@
+u       Upper case selection
+        TMPFILE=`mktemp ${MC_TMPDIR:-/tmp}/up.XXXXXX` || exit 1
+        cat %b > $TMPFILE
+        cat $TMPFILE| sed 's/\(.*\)/\U\1/' >%b
+        rm -f $TMPFILE
diff --git a/misc/macros.d/macro.2.sh b/misc/macros.d/macro.2.sh
new file mode 100644
index 000000000..7e3b8026d
--- /dev/null
+++ b/misc/macros.d/macro.2.sh
@@ -0,0 +1,5 @@
+l       Lower case selection
+        TMPFILE=`mktemp ${MC_TMPDIR:-/tmp}/up.XXXXXX` || exit 1
+        cat %b > $TMPFILE
+        cat $TMPFILE| sed 's/\(.*\)/\L\1/' >%b
+        rm -f $TMPFILE
diff --git a/misc/macros.d/macro.3.sh b/misc/macros.d/macro.3.sh
new file mode 100644
index 000000000..db77f3da6
--- /dev/null
+++ b/misc/macros.d/macro.3.sh
@@ -0,0 +1,5 @@
+S       Sort selection
+        TMPFILE=`mktemp ${MC_TMPDIR:-/tmp}/up.XXXXXX` || exit 1
+        cat %b > $TMPFILE
+        cat $TMPFILE| sort >%b
+        rm -f $TMPFILE
diff --git a/misc/macros.d/macro.4.sh b/misc/macros.d/macro.4.sh
new file mode 100644
index 000000000..ee53a8cce
--- /dev/null
+++ b/misc/macros.d/macro.4.sh
@@ -0,0 +1,2 @@
+t       Indent `C' formatter
+        indent -gnu -fc1 -i4 -bli0 -nut -bap -l100 %b 1>/dev/null 2> %e
diff --git a/misc/macros.d/macro.5.sh b/misc/macros.d/macro.5.sh
new file mode 100644
index 000000000..a64dfc95a
--- /dev/null
+++ b/misc/macros.d/macro.5.sh
@@ -0,0 +1,41 @@
+s       snippets
+        a=`cat %b`
+        if [ "$a" = "fori" ]; then
+        echo "for (i = 0; i _; i++)" > %b
+        fi
+        if [ "$a" = "ife" ]; then
+        cat <<EOF > %b
+        if ( )
+        {
+        }
+        else
+        {
+        }
+        EOF
+        fi
+        if [ "$a" = "GPL" ]; then
+        cat >>%b <<EOF
+        /*
+        * This program is free software; you can redistribute it and/or modify
+        * it under the terms of the GNU General Public License as published by
+        * the Free Software Foundation; either version 2 of the License, or
+        * (at your option) any later version.
+        *
+        * This program is distributed in the hope that it will be useful,
+        * but WITHOUT ANY WARRANTY; without even the implied warranty of
+        * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        * GNU General Public License for more details.
+        *
+        * You should have received a copy of the GNU General Public License
+        * along with this program; if not, write to the Free Software
+        * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+        */
+        EOF
+        fi
+        if [ "$a" = "type" ]; then
+        cat <<EOF > %b
+        typedef struct {
+        ;
+        } ?;
+        EOF
+        fi
diff --git a/misc/mc.macros b/misc/mc.macros
new file mode 100644
index 000000000..bcf9d2834
--- /dev/null
+++ b/misc/mc.macros
@@ -0,0 +1,9 @@
+#see ./macros.d/*
+[editor]
+#autocomplete "ife", "GPL", "fori"
+ctrl-space=EditWordLeftHighlight:-1;EditPipeBlock:5;EditUnmark:-1;
+#run make
+ctrl-f9=EditPipeBlock:0;
+#indent current selection
+meta-ctrl-F=EditPipeBlock:4;
+

From f28ec51c77bb165a89c8e14abf5deb454e8233bb Mon Sep 17 00:00:00 2001
From: Andrew Borodin <aborodin@vmail.ru>
Date: Mon, 14 Feb 2011 14:10:33 +0300
Subject: [PATCH 10/10] (mc_config_init): don't drop file name if file is not
 exist.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
---
 lib/mcconfig/common.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/lib/mcconfig/common.c b/lib/mcconfig/common.c
index fee93cafc..a4c97318a 100644
--- a/lib/mcconfig/common.c
+++ b/lib/mcconfig/common.c
@@ -112,14 +112,12 @@ mc_config_init (const gchar * ini_path)
         g_free (mc_config);
         return NULL;
     }
-    if (!ini_path || !exist_file (ini_path))
-    {
+    if (ini_path == NULL)
         return mc_config;
-    }
 
-    if (!mc_stat (ini_path, &st) && st.st_size)
+    if (exist_file (ini_path) && mc_stat (ini_path, &st) == 0 && st.st_size != 0)
     {
-        /* file present and not empty */
+        /* file exists and not empty */
         g_key_file_load_from_file (mc_config->handle, ini_path, G_KEY_FILE_KEEP_COMMENTS, NULL);
     }