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-2021
   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         edit_macro_sort_by_hotkey ();
 115     }
 116 
 117     macros_fname = mc_config_get_full_path (MC_MACRO_FILE);
 118     macros_config = mc_config_init (macros_fname, FALSE);
 119     g_free (macros_fname);
 120 
 121     if (macros_config == NULL)
 122         return FALSE;
 123 
 124     skeyname = lookup_key_by_code (hotkey);
 125     while (mc_config_del_key (macros_config, section_name, skeyname))
 126         ;
 127     g_free (skeyname);
 128     mc_config_save_file (macros_config, NULL);
 129     mc_config_deinit (macros_config);
 130     return TRUE;
 131 }
 132 
 133 /* --------------------------------------------------------------------------------------------- */
 134 /*** public functions ****************************************************************************/
 135 /* --------------------------------------------------------------------------------------------- */
 136 
 137 /** returns FALSE on error */
 138 gboolean
 139 edit_store_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 140 {
 141     int i;
 142     int hotkey;
 143     GString *macros_string = NULL;
 144     const char *section_name = "editor";
 145     gchar *macros_fname;
 146     GArray *macros = NULL;
 147     int tmp_act;
 148     mc_config_t *macros_config;
 149     char *skeyname;
 150 
 151     hotkey =
 152         editcmd_dialog_raw_key_query (_("Save macro"), _("Press the macro's new hotkey:"), TRUE);
 153     if (hotkey == ESC_CHAR)
 154         return FALSE;
 155 
 156     tmp_act = keybind_lookup_keymap_command (WIDGET (edit)->keymap, hotkey);
 157     /* return FALSE if try assign macro into restricted hotkeys */
 158     if (tmp_act == CK_MacroStartRecord
 159         || tmp_act == CK_MacroStopRecord || tmp_act == CK_MacroStartStopRecord)
 160         return FALSE;
 161 
 162     edit_delete_macro (edit, hotkey);
 163 
 164     macros_fname = mc_config_get_full_path (MC_MACRO_FILE);
 165     macros_config = mc_config_init (macros_fname, FALSE);
 166     g_free (macros_fname);
 167 
 168     if (macros_config == NULL)
 169         return FALSE;
 170 
 171     edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
 172 
 173     skeyname = lookup_key_by_code (hotkey);
 174 
 175     for (i = 0; i < macro_index; i++)
 176     {
 177         macro_action_t m_act;
 178         const char *action_name;
 179 
 180         action_name = keybind_lookup_actionname (record_macro_buf[i].action);
 181         if (action_name == NULL)
 182             break;
 183 
 184         if (macros == NULL)
 185         {
 186             macros = g_array_new (TRUE, FALSE, sizeof (macro_action_t));
 187             macros_string = g_string_sized_new (250);
 188         }
 189 
 190         m_act.action = record_macro_buf[i].action;
 191         m_act.ch = record_macro_buf[i].ch;
 192         g_array_append_val (macros, m_act);
 193         g_string_append_printf (macros_string, "%s:%i;", action_name, (int) record_macro_buf[i].ch);
 194     }
 195 
 196     if (macros == NULL)
 197         mc_config_del_key (macros_config, section_name, skeyname);
 198     else
 199     {
 200         macros_t macro;
 201 
 202         macro.hotkey = hotkey;
 203         macro.macro = macros;
 204         g_array_append_val (macros_list, macro);
 205         mc_config_set_string (macros_config, section_name, skeyname, macros_string->str);
 206     }
 207 
 208     g_free (skeyname);
 209 
 210     edit_macro_sort_by_hotkey ();
 211 
 212     if (macros_string != NULL)
 213         g_string_free (macros_string, TRUE);
 214     mc_config_save_file (macros_config, NULL);
 215     mc_config_deinit (macros_config);
 216 
 217     return TRUE;
 218 }
 219 
 220 /* --------------------------------------------------------------------------------------------- */
 221 
 222 /** return FALSE on error */
 223 
 224 gboolean
 225 edit_load_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 226 {
 227     mc_config_t *macros_config = NULL;
 228     gchar **profile_keys, **keys;
 229     gchar **values, **curr_values;
 230     const char *section_name = "editor";
 231     gchar *macros_fname;
 232 
 233     (void) edit;
 234 
 235     if (macros_list == NULL || macros_list->len != 0)
 236         return FALSE;
 237 
 238     macros_fname = mc_config_get_full_path (MC_MACRO_FILE);
 239     macros_config = mc_config_init (macros_fname, TRUE);
 240     g_free (macros_fname);
 241 
 242     if (macros_config == NULL)
 243         return FALSE;
 244 
 245     keys = mc_config_get_keys (macros_config, section_name, NULL);
 246 
 247     for (profile_keys = keys; *profile_keys != NULL; profile_keys++)
 248     {
 249         int hotkey;
 250         GArray *macros = NULL;
 251         macros_t macro;
 252 
 253         values = mc_config_get_string_list (macros_config, section_name, *profile_keys, NULL);
 254         hotkey = lookup_key (*profile_keys, NULL);
 255 
 256         for (curr_values = values; *curr_values != NULL && *curr_values[0] != '\0'; curr_values++)
 257         {
 258             char **macro_pair;
 259 
 260             macro_pair = g_strsplit (*curr_values, ":", 2);
 261 
 262             if (macro_pair != NULL)
 263             {
 264                 macro_action_t m_act = {
 265                     .action = 0,
 266                     .ch = -1
 267                 };
 268 
 269                 if (macro_pair[0] != NULL && macro_pair[0][0] != '\0')
 270                     m_act.action = keybind_lookup_action (macro_pair[0]);
 271 
 272                 if (macro_pair[1] != NULL && macro_pair[1][0] != '\0')
 273                     m_act.ch = strtol (macro_pair[1], NULL, 0);
 274 
 275                 if (m_act.action != 0)
 276                 {
 277                     /* a shell command */
 278                     if ((m_act.action / CK_PipeBlock (0)) == 1)
 279                     {
 280                         m_act.action = CK_PipeBlock (0);
 281                         if (m_act.ch > 0)
 282                             m_act.action += m_act.ch;
 283                         m_act.ch = -1;
 284                     }
 285 
 286                     if (macros == NULL)
 287                         macros = g_array_new (TRUE, FALSE, sizeof (m_act));
 288 
 289                     g_array_append_val (macros, m_act);
 290                 }
 291 
 292                 g_strfreev (macro_pair);
 293             }
 294         }
 295 
 296         if (macros != NULL)
 297         {
 298             macro.hotkey = hotkey;
 299             macro.macro = macros;
 300             g_array_append_val (macros_list, macro);
 301         }
 302 
 303         g_strfreev (values);
 304     }
 305 
 306     g_strfreev (keys);
 307     mc_config_deinit (macros_config);
 308     edit_macro_sort_by_hotkey ();
 309 
 310     return TRUE;
 311 }
 312 
 313 /* --------------------------------------------------------------------------------------------- */
 314 
 315 void
 316 edit_delete_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 317 {
 318     int hotkey;
 319 
 320     hotkey = editcmd_dialog_raw_key_query (_("Delete macro"), _("Press macro hotkey:"), TRUE);
 321 
 322     if (hotkey != 0 && !edit_delete_macro (edit, hotkey))
 323         message (D_ERROR, _("Delete macro"), _("Macro not deleted"));
 324 }
 325 
 326 /* --------------------------------------------------------------------------------------------- */
 327 
 328 gboolean
 329 edit_repeat_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 330 {
 331     gboolean ok;
 332     char *f;
 333     long count_repeat = 0;
 334 
 335     f = input_dialog (_("Repeat last commands"), _("Repeat times:"), MC_HISTORY_EDIT_REPEAT, NULL,
 336                       INPUT_COMPLETE_NONE);
 337     ok = (f != NULL && *f != '\0');
 338 
 339     if (ok)
 340     {
 341         char *error = NULL;
 342 
 343         count_repeat = strtol (f, &error, 0);
 344 
 345         ok = (*error == '\0');
 346     }
 347 
 348     g_free (f);
 349 
 350     if (ok)
 351     {
 352         int i, j;
 353 
 354         edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
 355         edit->force |= REDRAW_PAGE;
 356 
 357         for (j = 0; j < count_repeat; j++)
 358             for (i = 0; i < macro_index; i++)
 359                 edit_execute_cmd (edit, record_macro_buf[i].action, record_macro_buf[i].ch);
 360 
 361         edit_update_screen (edit);
 362     }
 363 
 364     return ok;
 365 }
 366 
 367 /* --------------------------------------------------------------------------------------------- */
 368 
 369 /** returns FALSE on error */
 370 gboolean
 371 edit_execute_macro (WEdit * edit, int hotkey)
     /* [previous][next][first][last][top][bottom][index][help]  */
 372 {
 373     gboolean res = FALSE;
 374 
 375     if (hotkey != 0)
 376     {
 377         int indx;
 378 
 379         indx = edit_get_macro (edit, hotkey);
 380         if (indx != -1)
 381         {
 382             const macros_t *macros;
 383 
 384             macros = &g_array_index (macros_list, struct macros_t, indx);
 385             if (macros->macro->len != 0)
 386             {
 387                 guint i;
 388 
 389                 edit->force |= REDRAW_PAGE;
 390 
 391                 for (i = 0; i < macros->macro->len; i++)
 392                 {
 393                     const macro_action_t *m_act;
 394 
 395                     m_act = &g_array_index (macros->macro, struct macro_action_t, i);
 396                     edit_execute_cmd (edit, m_act->action, m_act->ch);
 397                     res = TRUE;
 398                 }
 399             }
 400         }
 401     }
 402 
 403     return res;
 404 }
 405 
 406 /* --------------------------------------------------------------------------------------------- */
 407 
 408 void
 409 edit_begin_end_macro_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 410 {
 411     /* edit is a pointer to the widget */
 412     if (edit != NULL)
 413     {
 414         long command = macro_index < 0 ? CK_MacroStartRecord : CK_MacroStopRecord;
 415 
 416         edit_execute_key_command (edit, command, -1);
 417     }
 418 }
 419 
 420  /* --------------------------------------------------------------------------------------------- */
 421 
 422 void
 423 edit_begin_end_repeat_cmd (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 424 {
 425     /* edit is a pointer to the widget */
 426     if (edit != NULL)
 427     {
 428         long command = macro_index < 0 ? CK_RepeatStartRecord : CK_RepeatStopRecord;
 429 
 430         edit_execute_key_command (edit, command, -1);
 431     }
 432 }
 433 
 434 /* --------------------------------------------------------------------------------------------- */

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