root/src/editor/editcmd_dialogs.c

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

DEFINITIONS

This source file includes following definitions.
  1. editcmd_dialog_raw_key_query_cb
  2. editcmd_dialog_search_show
  3. editcmd_dialog_replace_show
  4. editcmd_dialog_replace_prompt_show
  5. editcmd_dialog_raw_key_query
  6. editcmd_dialog_completion_show
  7. editcmd_dialog_select_definition_show

   1 /*
   2    Editor dialogs for high level editing commands
   3 
   4    Copyright (C) 2009-2019
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Slava Zanko <slavazanko@gmail.com>, 2009
   9    Andrew Borodin, <aborodin@vmail.ru>, 2012, 2013
  10 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  25  */
  26 
  27 #include <config.h>
  28 
  29 #include "lib/global.h"
  30 #include "lib/tty/tty.h"
  31 #include "lib/skin.h"           /* INPUT_COLOR */
  32 #include "lib/tty/key.h"
  33 #include "lib/search.h"
  34 #include "lib/strutil.h"
  35 #include "lib/widget.h"
  36 #ifdef HAVE_CHARSET
  37 #include "lib/charsets.h"
  38 #endif
  39 
  40 #include "src/history.h"
  41 
  42 #include "src/editor/editwidget.h"
  43 #include "src/editor/etags.h"
  44 #include "src/editor/editcmd_dialogs.h"
  45 
  46 #ifdef HAVE_ASPELL
  47 #include "src/editor/spell.h"
  48 #endif
  49 
  50 /*** global variables ****************************************************************************/
  51 
  52 edit_search_options_t edit_search_options = {
  53     .type = MC_SEARCH_T_NORMAL,
  54     .case_sens = FALSE,
  55     .backwards = FALSE,
  56     .only_in_selection = FALSE,
  57     .whole_words = FALSE,
  58     .all_codepages = FALSE
  59 };
  60 
  61 /*** file scope macro definitions ****************************************************************/
  62 
  63 /*** file scope type declarations ****************************************************************/
  64 
  65 /*** file scope variables ************************************************************************/
  66 
  67 /*** file scope functions ************************************************************************/
  68 /* --------------------------------------------------------------------------------------------- */
  69 
  70 static cb_ret_t
  71 editcmd_dialog_raw_key_query_cb (Widget * w, Widget * sender, widget_msg_t msg, int parm,
     /* [previous][next][first][last][top][bottom][index][help]  */
  72                                  void *data)
  73 {
  74     WDialog *h = DIALOG (w);
  75 
  76     switch (msg)
  77     {
  78     case MSG_KEY:
  79         h->ret_value = parm;
  80         dlg_stop (h);
  81         return MSG_HANDLED;
  82     default:
  83         return dlg_default_callback (w, sender, msg, parm, data);
  84     }
  85 }
  86 
  87 /* --------------------------------------------------------------------------------------------- */
  88 /*** public functions ****************************************************************************/
  89 /* --------------------------------------------------------------------------------------------- */
  90 
  91 gboolean
  92 editcmd_dialog_search_show (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
  93 {
  94     char *search_text;
  95     size_t num_of_types = 0;
  96     gchar **list_of_types;
  97     int dialog_result;
  98 
  99     list_of_types = mc_search_get_types_strings_array (&num_of_types);
 100 
 101     {
 102         quick_widget_t quick_widgets[] = {
 103             /* *INDENT-OFF* */
 104             QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above, INPUT_LAST_TEXT, 
 105                                  MC_HISTORY_SHARED_SEARCH, &search_text, NULL, FALSE, FALSE,
 106                                  INPUT_COMPLETE_NONE),
 107             QUICK_SEPARATOR (TRUE),
 108             QUICK_START_COLUMNS,
 109                 QUICK_RADIO (num_of_types, (const char **) list_of_types,
 110                              (int *) &edit_search_options.type, NULL),
 111             QUICK_NEXT_COLUMN,
 112                 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options.case_sens, NULL),
 113                 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options.backwards, NULL),
 114                 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options.only_in_selection, NULL),
 115                 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options.whole_words, NULL),
 116 #ifdef HAVE_CHARSET
 117                 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options.all_codepages, NULL),
 118 #endif
 119             QUICK_STOP_COLUMNS,
 120             QUICK_START_BUTTONS (TRUE, TRUE),
 121                 QUICK_BUTTON (N_("&OK"), B_ENTER, NULL, NULL),
 122                 QUICK_BUTTON (N_("&Find all"), B_USER, NULL, NULL),
 123                 QUICK_BUTTON (N_("&Cancel"), B_CANCEL, NULL, NULL),
 124             QUICK_END
 125             /* *INDENT-ON* */
 126         };
 127 
 128         quick_dialog_t qdlg = {
 129             -1, -1, 58,
 130             N_("Search"), "[Input Line Keys]",
 131             quick_widgets, NULL, NULL
 132         };
 133 
 134         dialog_result = quick_dialog (&qdlg);
 135     }
 136 
 137     g_strfreev (list_of_types);
 138 
 139     if ((dialog_result == B_CANCEL) || (search_text == NULL) || (search_text[0] == '\0'))
 140     {
 141         g_free (search_text);
 142         return FALSE;
 143     }
 144 
 145     if (dialog_result == B_USER)
 146         search_create_bookmark = TRUE;
 147 
 148 #ifdef HAVE_CHARSET
 149     {
 150         GString *tmp;
 151 
 152         tmp = str_convert_to_input (search_text);
 153         g_free (search_text);
 154         search_text = g_string_free (tmp, FALSE);
 155     }
 156 #endif
 157 
 158     g_free (edit->last_search_string);
 159     edit->last_search_string = search_text;
 160     mc_search_free (edit->search);
 161 
 162 #ifdef HAVE_CHARSET
 163     edit->search = mc_search_new (edit->last_search_string, cp_source);
 164 #else
 165     edit->search = mc_search_new (edit->last_search_string, NULL);
 166 #endif
 167     if (edit->search != NULL)
 168     {
 169         edit->search->search_type = edit_search_options.type;
 170 #ifdef HAVE_CHARSET
 171         edit->search->is_all_charsets = edit_search_options.all_codepages;
 172 #endif
 173         edit->search->is_case_sensitive = edit_search_options.case_sens;
 174         edit->search->whole_words = edit_search_options.whole_words;
 175         edit->search->search_fn = edit_search_cmd_callback;
 176         edit->search->update_fn = edit_search_update_callback;
 177     }
 178 
 179     return (edit->search != NULL);
 180 }
 181 
 182 /* --------------------------------------------------------------------------------------------- */
 183 
 184 void
 185 editcmd_dialog_replace_show (WEdit * edit, const char *search_default, const char *replace_default,
     /* [previous][next][first][last][top][bottom][index][help]  */
 186                              /*@out@ */ char **search_text, /*@out@ */ char **replace_text)
 187 {
 188     size_t num_of_types = 0;
 189     gchar **list_of_types;
 190 
 191     if ((search_default == NULL) || (*search_default == '\0'))
 192         search_default = INPUT_LAST_TEXT;
 193 
 194     list_of_types = mc_search_get_types_strings_array (&num_of_types);
 195 
 196     {
 197         quick_widget_t quick_widgets[] = {
 198             /* *INDENT-OFF* */
 199             QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above, search_default,
 200                                  MC_HISTORY_SHARED_SEARCH, search_text, NULL, FALSE, FALSE,
 201                                  INPUT_COMPLETE_NONE),
 202             QUICK_LABELED_INPUT (N_("Enter replacement string:"), input_label_above, replace_default,
 203                                  "replace", replace_text, NULL, FALSE, FALSE, INPUT_COMPLETE_NONE),
 204             QUICK_SEPARATOR (TRUE),
 205             QUICK_START_COLUMNS,
 206                 QUICK_RADIO (num_of_types, (const char **) list_of_types,
 207                              (int *) &edit_search_options.type, NULL),
 208             QUICK_NEXT_COLUMN,
 209                 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options.case_sens, NULL),
 210                 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options.backwards, NULL),
 211                 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options.only_in_selection, NULL),
 212                 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options.whole_words, NULL),
 213 #ifdef HAVE_CHARSET
 214                 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options.all_codepages, NULL),
 215 #endif
 216             QUICK_STOP_COLUMNS,
 217             QUICK_BUTTONS_OK_CANCEL,
 218             QUICK_END
 219             /* *INDENT-ON* */
 220         };
 221 
 222         quick_dialog_t qdlg = {
 223             -1, -1, 58,
 224             N_("Replace"), "[Input Line Keys]",
 225             quick_widgets, NULL, NULL
 226         };
 227 
 228         if (quick_dialog (&qdlg) != B_CANCEL)
 229             edit->replace_mode = 0;
 230         else
 231         {
 232             *replace_text = NULL;
 233             *search_text = NULL;
 234         }
 235     }
 236 
 237     g_strfreev (list_of_types);
 238 }
 239 
 240 /* --------------------------------------------------------------------------------------------- */
 241 
 242 int
 243 editcmd_dialog_replace_prompt_show (WEdit * edit, char *from_text, char *to_text, int xpos,
     /* [previous][next][first][last][top][bottom][index][help]  */
 244                                     int ypos)
 245 {
 246     Widget *w = WIDGET (edit);
 247 
 248     /* dialog size */
 249     int dlg_height = 10;
 250     int dlg_width;
 251 
 252     char tmp[BUF_MEDIUM];
 253     char *repl_from, *repl_to;
 254     int retval;
 255 
 256     if (xpos == -1)
 257         xpos = w->x + option_line_state_width + 1;
 258     if (ypos == -1)
 259         ypos = w->y + w->lines / 2;
 260     /* Sometimes menu can hide replaced text. I don't like it */
 261     if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + dlg_height - 1))
 262         ypos -= dlg_height;
 263 
 264     dlg_width = WIDGET (w->owner)->cols - xpos - 1;
 265 
 266     g_snprintf (tmp, sizeof (tmp), "\"%s\"", from_text);
 267     repl_from = g_strdup (str_trunc (tmp, dlg_width - 7));
 268 
 269     g_snprintf (tmp, sizeof (tmp), "\"%s\"", to_text);
 270     repl_to = g_strdup (str_trunc (tmp, dlg_width - 7));
 271 
 272     {
 273         quick_widget_t quick_widgets[] = {
 274             /* *INDENT-OFF* */
 275             QUICK_LABEL (repl_from, NULL),
 276             QUICK_LABEL (N_("Replace with:"), NULL),
 277             QUICK_LABEL (repl_to, NULL),
 278             QUICK_START_BUTTONS (TRUE, TRUE),
 279                 QUICK_BUTTON (N_("&Replace"), B_ENTER, NULL, NULL),
 280                 QUICK_BUTTON (N_("A&ll"), B_REPLACE_ALL, NULL, NULL),
 281                 QUICK_BUTTON (N_("&Skip"), B_SKIP_REPLACE, NULL, NULL),
 282                 QUICK_BUTTON (N_("&Cancel"), B_CANCEL, NULL, NULL),
 283             QUICK_END
 284             /* *INDENT-ON* */
 285         };
 286 
 287         quick_dialog_t qdlg = {
 288             ypos, xpos, -1,
 289             N_("Confirm replace"), NULL,
 290             quick_widgets, NULL, NULL
 291         };
 292 
 293         retval = quick_dialog (&qdlg);
 294     }
 295 
 296     g_free (repl_from);
 297     g_free (repl_to);
 298 
 299     return retval;
 300 }
 301 
 302 /* --------------------------------------------------------------------------------------------- */
 303 /* gets a raw key from the keyboard. Passing cancel = 1 draws
 304    a cancel button thus allowing c-c etc.  Alternatively, cancel = 0
 305    will return the next key pressed.  ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
 306    and Esc are cannot returned */
 307 
 308 int
 309 editcmd_dialog_raw_key_query (const char *heading, const char *query, gboolean cancel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 310 {
 311     int w, wq;
 312     int y = 2;
 313     WDialog *raw_dlg;
 314 
 315     w = str_term_width1 (heading) + 6;
 316     wq = str_term_width1 (query);
 317     w = MAX (w, wq + 3 * 2 + 1 + 2);
 318 
 319     raw_dlg =
 320         dlg_create (TRUE, 0, 0, cancel ? 7 : 5, w, WPOS_CENTER | WPOS_TRYUP, FALSE, dialog_colors,
 321                     editcmd_dialog_raw_key_query_cb, NULL, NULL, heading);
 322     widget_want_tab (WIDGET (raw_dlg), TRUE);
 323 
 324     add_widget (raw_dlg, label_new (y, 3, query));
 325     add_widget (raw_dlg, input_new (y++, 3 + wq + 1, input_colors,
 326                                     w - (6 + wq + 1), "", 0, INPUT_COMPLETE_NONE));
 327     if (cancel)
 328     {
 329         add_widget (raw_dlg, hline_new (y++, -1, -1));
 330         /* Button w/o hotkey to allow use any key as raw or macro one */
 331         add_widget_autopos (raw_dlg, button_new (y, 1, B_CANCEL, NORMAL_BUTTON, _("Cancel"), NULL),
 332                             WPOS_KEEP_TOP | WPOS_CENTER_HORZ, NULL);
 333     }
 334 
 335     w = dlg_run (raw_dlg);
 336     dlg_destroy (raw_dlg);
 337 
 338     return (cancel && (w == ESC_CHAR || w == B_CANCEL)) ? 0 : w;
 339 }
 340 
 341 /* --------------------------------------------------------------------------------------------- */
 342 /* let the user select its preferred completion */
 343 
 344 char *
 345 editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** compl, int num_compl)
     /* [previous][next][first][last][top][bottom][index][help]  */
 346 {
 347     const Widget *we = CONST_WIDGET (edit);
 348     int start_x, start_y, offset, i;
 349     char *curr = NULL;
 350     WDialog *compl_dlg;
 351     WListbox *compl_list;
 352     int compl_dlg_h;            /* completion dialog height */
 353     int compl_dlg_w;            /* completion dialog width */
 354 
 355     /* calculate the dialog metrics */
 356     compl_dlg_h = num_compl + 2;
 357     compl_dlg_w = max_len + 4;
 358     start_x = we->x + edit->curs_col + edit->start_col + EDIT_TEXT_HORIZONTAL_OFFSET +
 359         (edit->fullscreen ? 0 : 1) + option_line_state_width;
 360     start_y = we->y + edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen ? 0 : 1) + 1;
 361 
 362     if (start_x < 0)
 363         start_x = 0;
 364     if (start_x < we->x + 1)
 365         start_x = we->x + 1 + option_line_state_width;
 366     if (compl_dlg_w > COLS)
 367         compl_dlg_w = COLS;
 368     if (compl_dlg_h > LINES - 2)
 369         compl_dlg_h = LINES - 2;
 370 
 371     offset = start_x + compl_dlg_w - COLS;
 372     if (offset > 0)
 373         start_x -= offset;
 374     offset = start_y + compl_dlg_h - LINES;
 375     if (offset > 0)
 376         start_y -= offset;
 377 
 378     /* create the dialog */
 379     compl_dlg =
 380         dlg_create (TRUE, start_y, start_x, compl_dlg_h, compl_dlg_w, WPOS_KEEP_DEFAULT, TRUE,
 381                     dialog_colors, NULL, NULL, "[Completion]", NULL);
 382 
 383     /* create the listbox */
 384     compl_list = listbox_new (1, 1, compl_dlg_h - 2, compl_dlg_w - 2, FALSE, NULL);
 385 
 386     /* add the dialog */
 387     add_widget (compl_dlg, compl_list);
 388 
 389     /* fill the listbox with the completions */
 390     for (i = num_compl - 1; i >= 0; i--)        /* reverse order */
 391         listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0, (char *) compl[i]->str, NULL,
 392                           FALSE);
 393 
 394     /* pop up the dialog and apply the chosen completion */
 395     if (dlg_run (compl_dlg) == B_ENTER)
 396     {
 397         listbox_get_current (compl_list, &curr, NULL);
 398         curr = g_strdup (curr);
 399     }
 400 
 401     /* destroy dialog before return */
 402     dlg_destroy (compl_dlg);
 403 
 404     return curr;
 405 }
 406 
 407 /* --------------------------------------------------------------------------------------------- */
 408 /* let the user select where function definition */
 409 
 410 void
 411 editcmd_dialog_select_definition_show (WEdit * edit, char *match_expr, int max_len, int word_len,
     /* [previous][next][first][last][top][bottom][index][help]  */
 412                                        etags_hash_t * def_hash, int num_lines)
 413 {
 414     int start_x, start_y, offset, i;
 415     char *curr = NULL;
 416     WDialog *def_dlg;
 417     WListbox *def_list;
 418     int def_dlg_h;              /* dialog height */
 419     int def_dlg_w;              /* dialog width */
 420 
 421     (void) word_len;
 422     /* calculate the dialog metrics */
 423     def_dlg_h = num_lines + 2;
 424     def_dlg_w = max_len + 4;
 425     start_x = edit->curs_col + edit->start_col - (def_dlg_w / 2) +
 426         EDIT_TEXT_HORIZONTAL_OFFSET + (edit->fullscreen ? 0 : 1) + option_line_state_width;
 427     start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen ? 0 : 1) + 1;
 428 
 429     if (start_x < 0)
 430         start_x = 0;
 431     if (def_dlg_w > COLS)
 432         def_dlg_w = COLS;
 433     if (def_dlg_h > LINES - 2)
 434         def_dlg_h = LINES - 2;
 435 
 436     offset = start_x + def_dlg_w - COLS;
 437     if (offset > 0)
 438         start_x -= offset;
 439     offset = start_y + def_dlg_h - LINES;
 440     if (offset > 0)
 441         start_y -= (offset + 1);
 442 
 443     def_dlg = dlg_create (TRUE, start_y, start_x, def_dlg_h, def_dlg_w, WPOS_KEEP_DEFAULT, TRUE,
 444                           dialog_colors, NULL, NULL, "[Definitions]", match_expr);
 445     def_list = listbox_new (1, 1, def_dlg_h - 2, def_dlg_w - 2, FALSE, NULL);
 446     add_widget (def_dlg, def_list);
 447 
 448     /* fill the listbox with the completions */
 449     for (i = 0; i < num_lines; i++)
 450     {
 451         char *label_def;
 452 
 453         label_def =
 454             g_strdup_printf ("%s -> %s:%ld", def_hash[i].short_define, def_hash[i].filename,
 455                              def_hash[i].line);
 456         listbox_add_item (def_list, LISTBOX_APPEND_AT_END, 0, label_def, &def_hash[i], FALSE);
 457         g_free (label_def);
 458     }
 459 
 460     /* pop up the dialog and apply the chosen completion */
 461     if (dlg_run (def_dlg) == B_ENTER)
 462     {
 463         etags_hash_t *curr_def = NULL;
 464         gboolean do_moveto = FALSE;
 465 
 466         listbox_get_current (def_list, &curr, (void **) &curr_def);
 467 
 468         if (!edit->modified)
 469             do_moveto = TRUE;
 470         else if (!edit_query_dialog2
 471                  (_("Warning"),
 472                   _("Current text was modified without a file save.\n"
 473                     "Continue discards these changes."), _("C&ontinue"), _("&Cancel")))
 474         {
 475             edit->force |= REDRAW_COMPLETELY;
 476             do_moveto = TRUE;
 477         }
 478 
 479         if (curr != NULL && do_moveto && edit_stack_iterator + 1 < MAX_HISTORY_MOVETO)
 480         {
 481             vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath);
 482 
 483             if (edit->dir_vpath != NULL)
 484                 edit_history_moveto[edit_stack_iterator].filename_vpath =
 485                     vfs_path_append_vpath_new (edit->dir_vpath, edit->filename_vpath, NULL);
 486             else
 487                 edit_history_moveto[edit_stack_iterator].filename_vpath =
 488                     vfs_path_clone (edit->filename_vpath);
 489 
 490             edit_history_moveto[edit_stack_iterator].line = edit->start_line + edit->curs_row + 1;
 491             edit_stack_iterator++;
 492             vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath);
 493             edit_history_moveto[edit_stack_iterator].filename_vpath =
 494                 vfs_path_from_str ((char *) curr_def->fullpath);
 495             edit_history_moveto[edit_stack_iterator].line = curr_def->line;
 496             edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath,
 497                               edit_history_moveto[edit_stack_iterator].line);
 498         }
 499     }
 500 
 501     /* clear definition hash */
 502     for (i = 0; i < MAX_DEFINITIONS; i++)
 503         g_free (def_hash[i].filename);
 504 
 505     /* destroy dialog before return */
 506     dlg_destroy (def_dlg);
 507 }
 508 
 509 /* --------------------------------------------------------------------------------------------- */

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