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/doc/man/mcedit.1.in b/doc/man/mcedit.1.in index 62a991217..bb7d014fa 100644 --- a/doc/man/mcedit.1.in +++ b/doc/man/mcedit.1.in @@ -97,38 +97,116 @@ 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 +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. +.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 diff --git a/lib/fileloc.h b/lib/fileloc.h index 5aeaa938d..6f80db82b 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" @@ -65,9 +66,9 @@ #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_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..a4f409395 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}, @@ -133,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}, @@ -185,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}, @@ -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..7a7f1b80f 100644 --- a/lib/keybind.h +++ b/lib/keybind.h @@ -189,19 +189,21 @@ #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_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 @@ -498,18 +500,8 @@ #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) (1000+(i)) -#define SHELL_COMMANDS_i {"/edit.indent.rc", "/edit.spell.rc", /* and so on */ 0 } -#define CK_Macro(i) (2000+(i)) +#define CK_Pipe_Block(i) (10000+(i)) +#define CK_Macro(i) (20000+(i)) #define CK_Last_Macro CK_Macro(0x7FFF) /*** enums ***************************************************************************************/ @@ -544,6 +536,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/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); } 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/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/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 < %b + if ( ) + { + } + else + { + } + EOF + fi + if [ "$a" = "GPL" ]; then + cat >>%b < %b + typedef struct { + ; + } ?; + EOF + fi 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/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; + diff --git a/src/editor/edit-impl.h b/src/editor/edit-impl.h index c4cd99780..05019d208 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; @@ -221,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); @@ -295,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); @@ -311,9 +306,10 @@ 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); +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); @@ -321,8 +317,9 @@ 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); 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..66b2dd5e8 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,9 +165,7 @@ 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 +554,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 */ } /* --------------------------------------------------------------------------------------------- */ @@ -1663,46 +1658,30 @@ 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--; -} - +/*** 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; + 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); /* 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; @@ -1724,14 +1703,13 @@ user_menu (WEdit * edit) if (fd != NULL) fclose (fd); } + edit_cursor_move (edit, curs - edit->curs1); edit_refresh_cmd (edit); edit->force |= REDRAW_COMPLETELY; g_free (block_file); } -/* --------------------------------------------------------------------------------------------- */ -/*** public functions ****************************************************************************/ /* --------------------------------------------------------------------------------------------- */ int @@ -2225,7 +2203,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 +2244,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 +3381,35 @@ 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_Record_Repeat + || (macro_index < 0 && (command == CK_Begin_End_Macro || command == CK_Begin_End_Repeat))) { - 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 (macro_index != -1) { edit->force |= REDRAW_COMPLETELY; - edit_save_macro_cmd (edit, edit->macro, edit->macro_i); - edit->macro_i = -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 (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) @@ -4115,7 +4104,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); @@ -4135,12 +4124,12 @@ 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; + case CK_Begin_End_Repeat: + edit_begin_end_repeat_cmd (edit); + break; case CK_Ext_Mode: edit->extmod = 1; break; @@ -4149,15 +4138,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 / 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 f1aeca753..728683cd8 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, ", ¯o[n].command, ¯o[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,42 +1378,88 @@ 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 (void) { - FILE *f; - int s, i; + if (macros_list != NULL && macros_list->len != 0) + g_array_sort (macros_list, (GCompareFunc) edit_macro_comparator); +} - 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) +/* --------------------------------------------------------------------------------------------- */ + +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; + + (void) edit; + + 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) { - 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"))); + *indx = (result - array_start); + *macros = result; + return TRUE; } - return 0; + *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; + const macros_t *macros = NULL; + + /* clear array of actions for current hotkey */ + while (edit_get_macro (edit, hotkey, ¯os, &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 (); + } + + 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); + + if (macros_config == NULL) + return FALSE; + + 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; } /* --------------------------------------------------------------------------------------------- */ @@ -1541,74 +1467,260 @@ edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n) 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, ¯os, &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; + 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; + char *keyname = NULL; + + 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_data_path (), MC_MACRO_FILE, (char *) NULL); + macros_config = mc_config_init (macros_fname); + g_free (macros_fname); + + if (macros_config == NULL) + return FALSE; + + 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; + 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); + + g_free (keyname); + edit_macro_sort_by_hotkey (); + + 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:"), MC_HISTORY_EDIT_REPEAT, NULL); + if (f == NULL || *f == '\0') + { + g_free (f); + return FALSE; + } + + count_repeat = strtol (f, &error, 0); + + if (*error != '\0') + { + 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_data_path (), MC_MACRO_FILE, (char *) 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 = lookup_key (*profile_keys, NULL); + 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, ", ¯o[*n].command, ¯o[*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 (); + return TRUE; } -/* }}} Macro stuff starts here */ +/* }}} Macro stuff end here */ /* --------------------------------------------------------------------------------------------- */ /** returns 1 on success */ @@ -1634,7 +1746,6 @@ edit_save_confirm_cmd (WEdit * edit) return edit_save_cmd (edit); } - /* --------------------------------------------------------------------------------------------- */ /** returns 1 on success */ @@ -2741,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; } /* --------------------------------------------------------------------------------------------- */ @@ -3026,27 +3025,26 @@ 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) { /* edit is a pointer to the widget */ - if (edit) + if (edit != NULL) { - 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); + } +} + + /* --------------------------------------------------------------------------------------------- */ + +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); } } 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/editmenu.c b/src/editor/editmenu.c index 444bb7da2..58d8e4d6e 100644 --- a/src/editor/editmenu.c +++ b/src/editor/editmenu.c @@ -168,12 +168,9 @@ 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_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/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/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..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) +execute_menu_command (WEdit * edit_widget, const char *commands, gboolean 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 (!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; @@ -860,16 +868,27 @@ user_menu_cmd (struct WEdit *edit_widget) int selected, old_patterns; Listbox *listbox; gboolean res = FALSE; + gboolean interactive = FALSE; if (!vfs_current_is_local ()) { 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); @@ -936,6 +955,9 @@ user_menu_cmd (struct WEdit *edit_widget) { 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; } @@ -1006,25 +1028,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], interactive); 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/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" 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 */ 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