root/src/editor/editmacros.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. edit_macro_comparator
  2. edit_macro_sort_by_hotkey
  3. edit_get_macro
  4. edit_delete_macro
  5. edit_store_macro_cmd
  6. edit_load_macro_cmd
  7. edit_delete_macro_cmd
  8. edit_repeat_macro_cmd
  9. edit_execute_macro
  10. edit_begin_end_macro_cmd
  11. edit_begin_end_repeat_cmd

   1 /*
   2    Editor macros engine
   3 
   4    Copyright (C) 2001-2022
   5    Free Software Foundation, Inc.
   6 
   7    This file is part of the Midnight Commander.
   8 
   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.
  13 
  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.
  18 
  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/>.
  21  */
  22 
  23 #include <config.h>
  24 
  25 #include <stdlib.h>
  26 
  27 #include "lib/global.h"
  28 #include "lib/mcconfig.h"
  29 #include "lib/tty/key.h"        /* lookup_key*() */
  30 #include "lib/keybind.h"        /* keybind_lookup_actionname() */
  31 #include "lib/fileloc.h"
  32 
  33 #include "src/setup.h"          /* macro_action_t */
  34 #include "src/history.h"        /* MC_HISTORY_EDIT_REPEAT */
  35 
  36 #include "editwidget.h"
  37 
  38 #include "editmacros.h"
  39 
  40 /*** global variables ****************************************************************************/
  41 
  42 /*** file scope macro definitions ****************************************************************/
  43 
  44 /*** file scope type declarations ****************************************************************/
  45 
  46 /*** file scope variables ************************************************************************/
  47 
  48 /* --------------------------------------------------------------------------------------------- */
  49 /*** file scope functions ************************************************************************/
  50 /* --------------------------------------------------------------------------------------------- */
  51 
  52 static int
  53 edit_macro_comparator (gconstpointer * macro1, gconstpointer * macro2)
     /* [previous][next][first][last][top][bottom][index][help]  */
  54 {
  55     const macros_t *m1 = (const macros_t *) macro1;
  56     const macros_t *m2 = (const macros_t *) macro2;
  57 
  58     return m1->hotkey - m2->hotkey;
  59 }
  60 
  61 /* --------------------------------------------------------------------------------------------- */
  62 
  63 static void
  64 edit_macro_sort_by_hotkey (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  65 {
  66     if (macros_list != NULL && macros_list->len != 0)
  67         g_array_sort (macros_list, (GCompareFunc) edit_macro_comparator);
  68 }
  69 
  70 /* --------------------------------------------------------------------------------------------- */
  71 
  72 static int
  73 edit_get_macro (WEdit * edit, int hotkey)
     /* [previous][next][first][last][top][bottom][index][help]  */
  74 {
  75     macros_t *array_start;
  76     macros_t *result;
  77     macros_t search_macro = {
  78         .hotkey = hotkey
  79     };
  80 
  81     (void) edit;
  82 
  83     result = bsearch (&search_macro, macros_list->data, macros_list->len,
  84                       sizeof (macros_t), (GCompareFunc) edit_macro_comparator);
  85 
  86     if (result == NULL || result->macro == NULL)
  87         return (-1);
  88 
  89     array_start = &g_array_index (macros_list, struct macros_t, 0);
  90 
  91     return (int) (result - array_start);
  92 }
  93 
  94 /* --------------------------------------------------------------------------------------------- */
  95 
  96 /** returns FALSE on error */
  97 static gboolean
  98 edit_delete_macro (WEdit * edit, int hotkey)
     /* [previous][next][first][last][top][bottom][index][help]  */
  99 {
 100     mc_config_t *macros_config = NULL;
 101     const char *section_name = "editor";
 102     gchar *macros_fname;
 103     int indx;
 104     char *skeyname;
 105 
 106     /* clear array of actions for current hotkey */
 107     while ((indx = edit_get_macro (edit, hotkey)) != -1)
 108     {
 109         macros_t *macros;
 110 
 111         macros = &g_array_index (macros_list, struct macros_t, indx);
 112         g_array_free (macros->macro, TRUE);
 113         g_array_remove_index (macros_list, indx);
 114     }
 115 
 116     macros_fname = mc_config_get_full_path (MC_MACRO_FILE);
 117     macros_config = mc_config_init (macros_fname, FALSE);
 118     g_free (macros_fname);
 119 
 120     if (macros_config == NULL)
 121         return FALSE;
 122 
 123     skeyname = lookup_key_by_code (hotkey);
 124     while (mc_config_del_key (macros_config, section_name, skeyname))
 125         ;
 126     g_free (skeyname);
 127     mc_config_save_file (macros_config, NULL);
 128     mc_config_deinit (macros_config);
 129     return TRUE;
 130 }
 131 
 132 /* --------------------------------------------------------------------------------------------- */
 133 /*** public functions ****************************************************************************/
 134 /* --------------------------------------------------------------------------------------------- */
 135 
 136 /** returns FALSE on error */
 137 gboolean
 138 edit_store_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 139 {
 140     int i;
 141     int hotkey;
 142     GString *macros_string = NULL;
 143     const char *section_name = "editor";
 144     gchar *macros_fname;
 145     GArray *macros = NULL;
 146     int tmp_act;
 147     mc_config_t *macros_config;
 148     char *skeyname;
 149 
 150     hotkey =
 151         editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), TRUE);
 152     if (hotkey == ESC_CHAR)
 153         return FALSE;
 154 
 155     tmp_act = keybind_lookup_keymap_command (WIDGET (edit)->keymap, hotkey);
 156     /* return FALSE if try assign macro into restricted hotkeys */
 157     if (tmp_act == CK_MacroStartRecord
 158         || tmp_act == CK_MacroStopRecord || tmp_act == CK_MacroStartStopRecord)
 159         return FALSE;
 160 
 161     edit_delete_macro (edit, hotkey);
 162 
 163     macros_fname = mc_config_get_full_path (MC_MACRO_FILE);
 164     macros_config = mc_config_init (macros_fname, FALSE);
 165     g_free (macros_fname);
 166 
 167     if (macros_config == NULL)
 168         return FALSE;
 169 
 170     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
 171 
 172     skeyname = lookup_key_by_code (hotkey);
 173 
 174     for (i = 0; i < macro_index; i++)
 175     {
 176         macro_action_t m_act;
 177         const char *action_name;
 178 
 179         action_name = keybind_lookup_actionname (record_macro_buf[i].action);
 180         if (action_name == NULL)
 181             break;
 182 
 183         if (macros == NULL)
 184         {
 185             macros = g_array_new (TRUE, FALSE, sizeof (macro_action_t));
 186             macros_string = g_string_sized_new (250);
 187         }
 188 
 189         m_act.action = record_macro_buf[i].action;
 190         m_act.ch = record_macro_buf[i].ch;
 191         g_array_append_val (macros, m_act);
 192         g_string_append_printf (macros_string, "%s:%i;", action_name, (int) record_macro_buf[i].ch);
 193     }
 194 
 195     if (macros == NULL)
 196         mc_config_del_key (macros_config, section_name, skeyname);
 197     else
 198     {
 199         macros_t macro;
 200 
 201         macro.hotkey = hotkey;
 202         macro.macro = macros;
 203         g_array_append_val (macros_list, macro);
 204         mc_config_set_string (macros_config, section_name, skeyname, macros_string->str);
 205     }
 206 
 207     g_free (skeyname);
 208 
 209     edit_macro_sort_by_hotkey ();
 210 
 211     if (macros_string != NULL)
 212         g_string_free (macros_string, TRUE);
 213     mc_config_save_file (macros_config, NULL);
 214     mc_config_deinit (macros_config);
 215 
 216     return TRUE;
 217 }
 218 
 219 /* --------------------------------------------------------------------------------------------- */
 220 
 221 /** return FALSE on error */
 222 
 223 gboolean
 224 edit_load_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 225 {
 226     mc_config_t *macros_config = NULL;
 227     gchar **profile_keys, **keys;
 228     gchar **values, **curr_values;
 229     const char *section_name = "editor";
 230     gchar *macros_fname;
 231 
 232     (void) edit;
 233 
 234     if (macros_list == NULL || macros_list->len != 0)
 235         return FALSE;
 236 
 237     macros_fname = mc_config_get_full_path (MC_MACRO_FILE);
 238     macros_config = mc_config_init (macros_fname, TRUE);
 239     g_free (macros_fname);
 240 
 241     if (macros_config == NULL)
 242         return FALSE;
 243 
 244     keys = mc_config_get_keys (macros_config, section_name, NULL);
 245 
 246     for (profile_keys = keys; *profile_keys != NULL; profile_keys++)
 247     {
 248         int hotkey;
 249         GArray *macros = NULL;
 250         macros_t macro;
 251 
 252         values = mc_config_get_string_list (macros_config, section_name, *profile_keys, NULL);
 253         hotkey = lookup_key (*profile_keys, NULL);
 254 
 255         for (curr_values = values; *curr_values != NULL && *curr_values[0] != '\0'; curr_values++)
 256         {
 257             char **macro_pair;
 258 
 259             macro_pair = g_strsplit (*curr_values, ":", 2);
 260 
 261             if (macro_pair != NULL)
 262             {
 263                 macro_action_t m_act = {
 264                     .action = 0,
 265                     .ch = -1
 266                 };
 267 
 268                 if (macro_pair[0] != NULL && macro_pair[0][0] != '\0')
 269                     m_act.action = keybind_lookup_action (macro_pair[0]);
 270 
 271                 if (macro_pair[1] != NULL && macro_pair[1][0] != '\0')
 272                     m_act.ch = strtol (macro_pair[1], NULL, 0);
 273 
 274                 if (m_act.action != 0)
 275                 {
 276                     /* a shell command */
 277                     if ((m_act.action / CK_PipeBlock (0)) == 1)
 278                     {
 279                         m_act.action = CK_PipeBlock (0);
 280                         if (m_act.ch > 0)
 281                             m_act.action += m_act.ch;
 282                         m_act.ch = -1;
 283                     }
 284 
 285                     if (macros == NULL)
 286                         macros = g_array_new (TRUE, FALSE, sizeof (m_act));
 287 
 288                     g_array_append_val (macros, m_act);
 289                 }
 290 
 291                 g_strfreev (macro_pair);
 292             }
 293         }
 294 
 295         if (macros != NULL)
 296         {
 297             macro.hotkey = hotkey;
 298             macro.macro = macros;
 299             g_array_append_val (macros_list, macro);
 300         }
 301 
 302         g_strfreev (values);
 303     }
 304 
 305     g_strfreev (keys);
 306     mc_config_deinit (macros_config);
 307     edit_macro_sort_by_hotkey ();
 308 
 309     return TRUE;
 310 }
 311 
 312 /* --------------------------------------------------------------------------------------------- */
 313 
 314 void
 315 edit_delete_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 316 {
 317     int hotkey;
 318 
 319     hotkey = editcmd_dialog_raw_key_query (_("Delete macro"), _("Press macro hotkey:"), TRUE);
 320 
 321     if (hotkey != 0 && !edit_delete_macro (edit, hotkey))
 322         message (D_ERROR, _("Delete macro"), _("Macro not deleted"));
 323 }
 324 
 325 /* --------------------------------------------------------------------------------------------- */
 326 
 327 gboolean
 328 edit_repeat_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 329 {
 330     gboolean ok;
 331     char *f;
 332     long count_repeat = 0;
 333 
 334     f = input_dialog (_("Repeat last commands"), _("Repeat times:"), MC_HISTORY_EDIT_REPEAT, NULL,
 335                       INPUT_COMPLETE_NONE);
 336     ok = (f != NULL && *f != '\0');
 337 
 338     if (ok)
 339     {
 340         char *error = NULL;
 341 
 342         count_repeat = strtol (f, &error, 0);
 343 
 344         ok = (*error == '\0');
 345     }
 346 
 347     g_free (f);
 348 
 349     if (ok)
 350     {
 351         int i, j;
 352 
 353         edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
 354         edit->force |= REDRAW_PAGE;
 355 
 356         for (j = 0; j < count_repeat; j++)
 357             for (i = 0; i < macro_index; i++)
 358                 edit_execute_cmd (edit, record_macro_buf[i].action, record_macro_buf[i].ch);
 359 
 360         edit_update_screen (edit);
 361     }
 362 
 363     return ok;
 364 }
 365 
 366 /* --------------------------------------------------------------------------------------------- */
 367 
 368 /** returns FALSE on error */
 369 gboolean
 370 edit_execute_macro (WEdit * edit, int hotkey)
     /* [previous][next][first][last][top][bottom][index][help]  */
 371 {
 372     gboolean res = FALSE;
 373 
 374     if (hotkey != 0)
 375     {
 376         int indx;
 377 
 378         indx = edit_get_macro (edit, hotkey);
 379         if (indx != -1)
 380         {
 381             const macros_t *macros;
 382 
 383             macros = &g_array_index (macros_list, struct macros_t, indx);
 384             if (macros->macro->len != 0)
 385             {
 386                 guint i;
 387 
 388                 edit->force |= REDRAW_PAGE;
 389 
 390                 for (i = 0; i < macros->macro->len; i++)
 391                 {
 392                     const macro_action_t *m_act;
 393 
 394                     m_act = &g_array_index (macros->macro, struct macro_action_t, i);
 395                     edit_execute_cmd (edit, m_act->action, m_act->ch);
 396                     res = TRUE;
 397                 }
 398             }
 399         }
 400     }
 401 
 402     return res;
 403 }
 404 
 405 /* --------------------------------------------------------------------------------------------- */
 406 
 407 void
 408 edit_begin_end_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 409 {
 410     /* edit is a pointer to the widget */
 411     if (edit != NULL)
 412     {
 413         long command = macro_index < 0 ? CK_MacroStartRecord : CK_MacroStopRecord;
 414 
 415         edit_execute_key_command (edit, command, -1);
 416     }
 417 }
 418 
 419  /* --------------------------------------------------------------------------------------------- */
 420 
 421 void
 422 edit_begin_end_repeat_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 423 {
 424     /* edit is a pointer to the widget */
 425     if (edit != NULL)
 426     {
 427         long command = macro_index < 0 ? CK_RepeatStartRecord : CK_RepeatStopRecord;
 428 
 429         edit_execute_key_command (edit, command, -1);
 430     }
 431 }
 432 
 433 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */