4 Copyright (C) 2001-2024
5 Free Software Foundation, Inc.
7 This file is part of the Midnight Commander.
9 The Midnight Commander is free software: you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation, either version 3 of the License,
12 or (at your option) any later version.
14 The Midnight Commander is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "lib/global.h"
28 #include "lib/mcconfig.h"
29 #include "lib/tty/key.h" /* tty_keyname_to_keycode*() */
30 #include "lib/keybind.h" /* keybind_lookup_actionname() */
31 #include "lib/fileloc.h"
33 #include "src/setup.h" /* macro_action_t */
34 #include "src/history.h" /* MC_HISTORY_EDIT_REPEAT */
36 #include "editwidget.h"
38 #include "editmacros.h"
40 /*** global variables ****************************************************************************/
42 /*** file scope macro definitions ****************************************************************/
44 /*** file scope type declarations ****************************************************************/
46 /*** forward declarations (file scope functions) *************************************************/
48 /*** file scope variables ************************************************************************/
50 /* --------------------------------------------------------------------------------------------- */
51 /*** file scope functions ************************************************************************/
52 /* --------------------------------------------------------------------------------------------- */
55 edit_macro_comparator (gconstpointer
*macro1
, gconstpointer
*macro2
)
57 const macros_t
*m1
= (const macros_t
*) macro1
;
58 const macros_t
*m2
= (const macros_t
*) macro2
;
60 return m1
->hotkey
- m2
->hotkey
;
63 /* --------------------------------------------------------------------------------------------- */
66 edit_macro_sort_by_hotkey (void)
68 if (macros_list
!= NULL
&& macros_list
->len
!= 0)
69 g_array_sort (macros_list
, (GCompareFunc
) edit_macro_comparator
);
72 /* --------------------------------------------------------------------------------------------- */
75 edit_get_macro (WEdit
*edit
, int hotkey
)
77 macros_t
*array_start
;
79 macros_t search_macro
= {
85 result
= bsearch (&search_macro
, macros_list
->data
, macros_list
->len
,
86 sizeof (macros_t
), (GCompareFunc
) edit_macro_comparator
);
88 if (result
== NULL
|| result
->macro
== NULL
)
91 array_start
= &g_array_index (macros_list
, struct macros_t
, 0);
93 return (int) (result
- array_start
);
96 /* --------------------------------------------------------------------------------------------- */
98 /** returns FALSE on error */
100 edit_delete_macro (WEdit
*edit
, int hotkey
)
102 mc_config_t
*macros_config
= NULL
;
103 const char *section_name
= "editor";
108 /* clear array of actions for current hotkey */
109 while ((indx
= edit_get_macro (edit
, hotkey
)) != -1)
113 macros
= &g_array_index (macros_list
, struct macros_t
, indx
);
114 g_array_free (macros
->macro
, TRUE
);
115 g_array_remove_index (macros_list
, indx
);
118 macros_fname
= mc_config_get_full_path (MC_MACRO_FILE
);
119 macros_config
= mc_config_init (macros_fname
, FALSE
);
120 g_free (macros_fname
);
122 if (macros_config
== NULL
)
125 skeyname
= tty_keycode_to_keyname (hotkey
);
126 while (mc_config_del_key (macros_config
, section_name
, skeyname
))
129 mc_config_save_file (macros_config
, NULL
);
130 mc_config_deinit (macros_config
);
134 /* --------------------------------------------------------------------------------------------- */
135 /*** public functions ****************************************************************************/
136 /* --------------------------------------------------------------------------------------------- */
138 /** returns FALSE on error */
140 edit_store_macro_cmd (WEdit
*edit
)
144 GString
*macros_string
= NULL
;
145 const char *section_name
= "editor";
147 GArray
*macros
= NULL
;
149 mc_config_t
*macros_config
;
153 editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), TRUE
);
154 if (hotkey
== ESC_CHAR
)
157 tmp_act
= keybind_lookup_keymap_command (WIDGET (edit
)->keymap
, hotkey
);
158 /* return FALSE if try assign macro into restricted hotkeys */
159 if (tmp_act
== CK_MacroStartRecord
160 || tmp_act
== CK_MacroStopRecord
|| tmp_act
== CK_MacroStartStopRecord
)
163 edit_delete_macro (edit
, hotkey
);
165 macros_fname
= mc_config_get_full_path (MC_MACRO_FILE
);
166 macros_config
= mc_config_init (macros_fname
, FALSE
);
167 g_free (macros_fname
);
169 if (macros_config
== NULL
)
172 edit_push_undo_action (edit
, KEY_PRESS
+ edit
->start_display
);
174 skeyname
= tty_keycode_to_keyname (hotkey
);
176 for (i
= 0; i
< macro_index
; i
++)
178 macro_action_t m_act
;
179 const char *action_name
;
181 action_name
= keybind_lookup_actionname (record_macro_buf
[i
].action
);
182 if (action_name
== NULL
)
187 macros
= g_array_new (TRUE
, FALSE
, sizeof (macro_action_t
));
188 macros_string
= g_string_sized_new (250);
191 m_act
.action
= record_macro_buf
[i
].action
;
192 m_act
.ch
= record_macro_buf
[i
].ch
;
193 g_array_append_val (macros
, m_act
);
194 g_string_append_printf (macros_string
, "%s:%i;", action_name
, (int) record_macro_buf
[i
].ch
);
198 mc_config_del_key (macros_config
, section_name
, skeyname
);
203 macro
.hotkey
= hotkey
;
204 macro
.macro
= macros
;
205 g_array_append_val (macros_list
, macro
);
206 mc_config_set_string (macros_config
, section_name
, skeyname
, macros_string
->str
);
211 edit_macro_sort_by_hotkey ();
213 if (macros_string
!= NULL
)
214 g_string_free (macros_string
, TRUE
);
215 mc_config_save_file (macros_config
, NULL
);
216 mc_config_deinit (macros_config
);
221 /* --------------------------------------------------------------------------------------------- */
223 /** return FALSE on error */
226 edit_load_macro_cmd (WEdit
*edit
)
228 mc_config_t
*macros_config
= NULL
;
229 gchar
**profile_keys
, **keys
;
230 gchar
**values
, **curr_values
;
231 const char *section_name
= "editor";
236 if (macros_list
== NULL
|| macros_list
->len
!= 0)
239 macros_fname
= mc_config_get_full_path (MC_MACRO_FILE
);
240 macros_config
= mc_config_init (macros_fname
, TRUE
);
241 g_free (macros_fname
);
243 if (macros_config
== NULL
)
246 keys
= mc_config_get_keys (macros_config
, section_name
, NULL
);
248 for (profile_keys
= keys
; *profile_keys
!= NULL
; profile_keys
++)
251 GArray
*macros
= NULL
;
253 values
= mc_config_get_string_list (macros_config
, section_name
, *profile_keys
, NULL
);
254 hotkey
= tty_keyname_to_keycode (*profile_keys
, NULL
);
256 for (curr_values
= values
; *curr_values
!= NULL
&& *curr_values
[0] != '\0'; curr_values
++)
260 macro_pair
= g_strsplit (*curr_values
, ":", 2);
262 if (macro_pair
!= NULL
)
264 macro_action_t m_act
= {
269 if (macro_pair
[0] != NULL
&& macro_pair
[0][0] != '\0')
270 m_act
.action
= keybind_lookup_action (macro_pair
[0]);
272 if (macro_pair
[1] != NULL
&& macro_pair
[1][0] != '\0')
273 m_act
.ch
= strtol (macro_pair
[1], NULL
, 0);
275 if (m_act
.action
!= 0)
277 /* a shell command */
278 if ((m_act
.action
/ CK_PipeBlock (0)) == 1)
280 m_act
.action
= CK_PipeBlock (0);
282 m_act
.action
+= m_act
.ch
;
287 macros
= g_array_new (TRUE
, FALSE
, sizeof (m_act
));
289 g_array_append_val (macros
, m_act
);
292 g_strfreev (macro_pair
);
303 g_array_append_val (macros_list
, macro
);
310 mc_config_deinit (macros_config
);
311 edit_macro_sort_by_hotkey ();
316 /* --------------------------------------------------------------------------------------------- */
319 edit_delete_macro_cmd (WEdit
*edit
)
323 hotkey
= editcmd_dialog_raw_key_query (_("Delete macro"), _("Press macro hotkey:"), TRUE
);
325 if (hotkey
!= 0 && !edit_delete_macro (edit
, hotkey
))
326 message (D_ERROR
, _("Delete macro"), _("Macro not deleted"));
329 /* --------------------------------------------------------------------------------------------- */
332 edit_repeat_macro_cmd (WEdit
*edit
)
336 long count_repeat
= 0;
338 f
= input_dialog (_("Repeat last commands"), _("Repeat times:"), MC_HISTORY_EDIT_REPEAT
, NULL
,
339 INPUT_COMPLETE_NONE
);
340 ok
= (f
!= NULL
&& *f
!= '\0');
346 count_repeat
= strtol (f
, &error
, 0);
348 ok
= (*error
== '\0');
357 edit_push_undo_action (edit
, KEY_PRESS
+ edit
->start_display
);
358 edit
->force
|= REDRAW_PAGE
;
360 for (j
= 0; j
< count_repeat
; j
++)
361 for (i
= 0; i
< macro_index
; i
++)
362 edit_execute_cmd (edit
, record_macro_buf
[i
].action
, record_macro_buf
[i
].ch
);
364 edit_update_screen (edit
);
370 /* --------------------------------------------------------------------------------------------- */
372 /** returns FALSE on error */
374 edit_execute_macro (WEdit
*edit
, int hotkey
)
376 gboolean res
= FALSE
;
382 indx
= edit_get_macro (edit
, hotkey
);
385 const macros_t
*macros
;
387 macros
= &g_array_index (macros_list
, struct macros_t
, indx
);
388 if (macros
->macro
->len
!= 0)
392 edit
->force
|= REDRAW_PAGE
;
394 for (i
= 0; i
< macros
->macro
->len
; i
++)
396 const macro_action_t
*m_act
;
398 m_act
= &g_array_index (macros
->macro
, struct macro_action_t
, i
);
399 edit_execute_cmd (edit
, m_act
->action
, m_act
->ch
);
409 /* --------------------------------------------------------------------------------------------- */
412 edit_begin_end_macro_cmd (WEdit
*edit
)
414 /* edit is a pointer to the widget */
417 long command
= macro_index
< 0 ? CK_MacroStartRecord
: CK_MacroStopRecord
;
419 edit_execute_key_command (edit
, command
, -1);
423 /* --------------------------------------------------------------------------------------------- */
426 edit_begin_end_repeat_cmd (WEdit
*edit
)
428 /* edit is a pointer to the widget */
431 long command
= macro_index
< 0 ? CK_RepeatStartRecord
: CK_RepeatStopRecord
;
433 edit_execute_key_command (edit
, command
, -1);
437 /* --------------------------------------------------------------------------------------------- */