1 /*
2 Editor high level editing commands
3
4 Copyright (C) 1996-2021
5 Free Software Foundation, Inc.
6
7 Written by:
8 Paul Sheer, 1996, 1997
9 Andrew Borodin <aborodin@vmail.ru>, 2012-2021
10 Ilia Maslakov <il.smind@gmail.com>, 2012
11
12 This file is part of the Midnight Commander.
13
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
18
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28 /** \file
29 * \brief Source: editor high level editing commands
30 * \author Paul Sheer
31 * \date 1996, 1997
32 */
33
34 /* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
35
36 #include <config.h>
37
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <stdarg.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <errno.h>
45 #include <sys/stat.h>
46 #include <stdlib.h>
47
48 #include "lib/global.h"
49 #include "lib/tty/tty.h"
50 #include "lib/tty/key.h" /* XCTRL */
51 #include "lib/strutil.h" /* utf string functions */
52 #include "lib/fileloc.h"
53 #include "lib/lock.h"
54 #include "lib/util.h" /* tilde_expand() */
55 #include "lib/vfs/vfs.h"
56 #include "lib/widget.h"
57 #include "lib/event.h" /* mc_event_raise() */
58 #ifdef HAVE_CHARSET
59 #include "lib/charsets.h"
60 #endif
61
62 #include "src/history.h"
63 #include "src/file_history.h" /* show_file_history() */
64 #include "src/setup.h" /* option_tab_spacing */
65 #ifdef HAVE_CHARSET
66 #include "src/selcodepage.h"
67 #endif
68 #include "src/util.h" /* check_for_default() */
69
70 #include "edit-impl.h"
71 #include "editwidget.h"
72 #include "editsearch.h"
73 #include "etags.h"
74
75 /*** global variables ****************************************************************************/
76
77 /* search and replace: */
78 int search_create_bookmark = FALSE;
79
80 /* queries on a save */
81 gboolean edit_confirm_save = TRUE;
82
83 /* whether we need to drop selection on copy to buffer */
84 gboolean option_drop_selection_on_copy = TRUE;
85
86 /*** file scope macro definitions ****************************************************************/
87
88 #define space_width 1
89
90 #define TEMP_BUF_LEN 1024
91
92 /*** file scope type declarations ****************************************************************/
93
94 /*** file scope variables ************************************************************************/
95
96 static unsigned long edit_save_mode_radio_id, edit_save_mode_input_id;
97
98 /* --------------------------------------------------------------------------------------------- */
99 /*** file scope functions ************************************************************************/
100 /* --------------------------------------------------------------------------------------------- */
101
102 static cb_ret_t
edit_save_mode_callback(Widget * w,Widget * sender,widget_msg_t msg,int parm,void * data)103 edit_save_mode_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
104 {
105 switch (msg)
106 {
107 case MSG_CHANGED_FOCUS:
108 if (sender != NULL && sender->id == edit_save_mode_radio_id)
109 {
110 Widget *ww;
111
112 ww = widget_find_by_id (w, edit_save_mode_input_id);
113 widget_disable (ww, RADIO (sender)->sel != 2);
114 return MSG_HANDLED;
115 }
116 return MSG_NOT_HANDLED;
117
118 default:
119 return dlg_default_callback (w, sender, msg, parm, data);
120 }
121 }
122
123 /* --------------------------------------------------------------------------------------------- */
124
125 /* If 0 (quick save) then a) create/truncate <filename> file,
126 b) save to <filename>;
127 if 1 (safe save) then a) save to <tempnam>,
128 b) rename <tempnam> to <filename>;
129 if 2 (do backups) then a) save to <tempnam>,
130 b) rename <filename> to <filename.backup_ext>,
131 c) rename <tempnam> to <filename>. */
132
133 /* returns 0 on error, -1 on abort */
134
135 static int
edit_save_file(WEdit * edit,const vfs_path_t * filename_vpath)136 edit_save_file (WEdit * edit, const vfs_path_t * filename_vpath)
137 {
138 char *p;
139 gchar *tmp;
140 off_t filelen = 0;
141 int this_save_mode, rv, fd = -1;
142 vfs_path_t *real_filename_vpath;
143 vfs_path_t *savename_vpath = NULL;
144 const char *start_filename;
145 const vfs_path_element_t *vpath_element;
146 struct stat sb;
147
148 vpath_element = vfs_path_get_by_index (filename_vpath, 0);
149 if (vpath_element == NULL)
150 return 0;
151
152 start_filename = vpath_element->path;
153 if (*start_filename == '\0')
154 return 0;
155
156 if (!IS_PATH_SEP (*start_filename) && edit->dir_vpath != NULL)
157 real_filename_vpath = vfs_path_append_vpath_new (edit->dir_vpath, filename_vpath, NULL);
158 else
159 real_filename_vpath = vfs_path_clone (filename_vpath);
160
161 this_save_mode = option_save_mode;
162 if (this_save_mode != EDIT_QUICK_SAVE)
163 {
164 if (!vfs_file_is_local (real_filename_vpath))
165 /* The file does not exists yet, so no safe save or backup are necessary. */
166 this_save_mode = EDIT_QUICK_SAVE;
167 else
168 {
169 fd = mc_open (real_filename_vpath, O_RDONLY | O_BINARY);
170 if (fd == -1)
171 /* The file does not exists yet, so no safe save or backup are necessary. */
172 this_save_mode = EDIT_QUICK_SAVE;
173 }
174
175 if (fd != -1)
176 mc_close (fd);
177 }
178
179 rv = mc_stat (real_filename_vpath, &sb);
180 if (rv == 0)
181 {
182 if (this_save_mode == EDIT_QUICK_SAVE && !edit->skip_detach_prompt && sb.st_nlink > 1)
183 {
184 rv = edit_query_dialog3 (_("Warning"),
185 _("File has hard-links. Detach before saving?"),
186 _("&Yes"), _("&No"), _("&Cancel"));
187 switch (rv)
188 {
189 case 0:
190 this_save_mode = EDIT_SAFE_SAVE;
191 MC_FALLTHROUGH;
192 case 1:
193 edit->skip_detach_prompt = 1;
194 break;
195 default:
196 vfs_path_free (real_filename_vpath, TRUE);
197 return -1;
198 }
199 }
200
201 /* Prevent overwriting changes from other editor sessions. */
202 if (edit->stat1.st_mtime != 0 && edit->stat1.st_mtime != sb.st_mtime)
203 {
204 /* The default action is "Cancel". */
205 query_set_sel (1);
206
207 rv = edit_query_dialog2 (_("Warning"),
208 _("The file has been modified in the meantime. Save anyway?"),
209 _("&Yes"), _("&Cancel"));
210 if (rv != 0)
211 {
212 vfs_path_free (real_filename_vpath, TRUE);
213 return -1;
214 }
215 }
216 }
217
218 if (this_save_mode == EDIT_QUICK_SAVE)
219 savename_vpath = vfs_path_clone (real_filename_vpath);
220 else
221 {
222 char *savedir, *saveprefix;
223
224 savedir = vfs_path_tokens_get (real_filename_vpath, 0, -1);
225 if (savedir == NULL)
226 savedir = g_strdup (".");
227
228 /* Token-related function never return leading slash, so we need add it manually */
229 saveprefix = mc_build_filename (PATH_SEP_STR, savedir, "cooledit", (char *) NULL);
230 g_free (savedir);
231 fd = mc_mkstemps (&savename_vpath, saveprefix, NULL);
232 g_free (saveprefix);
233 if (savename_vpath == NULL)
234 {
235 vfs_path_free (real_filename_vpath, TRUE);
236 return 0;
237 }
238 /* FIXME:
239 * Close for now because mc_mkstemps use pure open system call
240 * to create temporary file and it needs to be reopened by
241 * VFS-aware mc_open().
242 */
243 close (fd);
244 }
245
246 (void) mc_chown (savename_vpath, edit->stat1.st_uid, edit->stat1.st_gid);
247 (void) mc_chmod (savename_vpath, edit->stat1.st_mode);
248
249 fd = mc_open (savename_vpath, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, edit->stat1.st_mode);
250 if (fd == -1)
251 goto error_save;
252
253 /* pipe save */
254 p = edit_get_write_filter (savename_vpath, real_filename_vpath);
255 if (p != NULL)
256 {
257 FILE *file;
258
259 mc_close (fd);
260 file = (FILE *) popen (p, "w");
261
262 if (file != NULL)
263 {
264 filelen = edit_write_stream (edit, file);
265 #if 1
266 pclose (file);
267 #else
268 if (pclose (file) != 0)
269 {
270 tmp = g_strdup_printf (_("Error writing to pipe: %s"), p);
271 edit_error_dialog (_("Error"), tmp);
272 g_free (tmp);
273 g_free (p);
274 goto error_save;
275 }
276 #endif
277 }
278 else
279 {
280 tmp = g_strdup_printf (_("Cannot open pipe for writing: %s"), p);
281 edit_error_dialog (_("Error"), get_sys_error (tmp));
282 g_free (p);
283 g_free (tmp);
284 goto error_save;
285 }
286 g_free (p);
287 }
288 else if (edit->lb == LB_ASIS)
289 { /* do not change line breaks */
290 filelen = edit_buffer_write_file (&edit->buffer, fd);
291
292 if (filelen != edit->buffer.size)
293 {
294 mc_close (fd);
295 goto error_save;
296 }
297
298 if (mc_close (fd) != 0)
299 goto error_save;
300
301 /* Update the file information, especially the mtime. */
302 if (mc_stat (savename_vpath, &edit->stat1) == -1)
303 goto error_save;
304 }
305 else
306 { /* change line breaks */
307 FILE *file;
308 const vfs_path_element_t *path_element;
309
310 mc_close (fd);
311
312 path_element = vfs_path_get_by_index (savename_vpath, -1);
313 file = (FILE *) fopen (path_element->path, "w");
314 if (file != NULL)
315 {
316 filelen = edit_write_stream (edit, file);
317 fclose (file);
318 }
319 else
320 {
321 char *msg;
322
323 msg = g_strdup_printf (_("Cannot open file for writing: %s"), path_element->path);
324 edit_error_dialog (_("Error"), msg);
325 g_free (msg);
326 goto error_save;
327 }
328 }
329
330 if (filelen != edit->buffer.size)
331 goto error_save;
332
333 if (this_save_mode == EDIT_DO_BACKUP)
334 {
335 char *tmp_store_filename;
336 vfs_path_element_t *last_vpath_element;
337 vfs_path_t *tmp_vpath;
338 gboolean ok;
339
340 g_assert (option_backup_ext != NULL);
341
342 /* add backup extension to the path */
343 tmp_vpath = vfs_path_clone (real_filename_vpath);
344 last_vpath_element = (vfs_path_element_t *) vfs_path_get_by_index (tmp_vpath, -1);
345 tmp_store_filename = last_vpath_element->path;
346 last_vpath_element->path = g_strdup_printf ("%s%s", tmp_store_filename, option_backup_ext);
347 g_free (tmp_store_filename);
348
349 ok = (mc_rename (real_filename_vpath, tmp_vpath) != -1);
350 vfs_path_free (tmp_vpath, TRUE);
351 if (!ok)
352 goto error_save;
353 }
354
355 if (this_save_mode != EDIT_QUICK_SAVE && mc_rename (savename_vpath, real_filename_vpath) == -1)
356 goto error_save;
357
358 vfs_path_free (real_filename_vpath, TRUE);
359 vfs_path_free (savename_vpath, TRUE);
360 return 1;
361 error_save:
362 /* FIXME: Is this safe ?
363 * if (this_save_mode != EDIT_QUICK_SAVE)
364 * mc_unlink (savename);
365 */
366 vfs_path_free (real_filename_vpath, TRUE);
367 vfs_path_free (savename_vpath, TRUE);
368 return 0;
369 }
370
371 /* --------------------------------------------------------------------------------------------- */
372
373 static gboolean
edit_check_newline(const edit_buffer_t * buf)374 edit_check_newline (const edit_buffer_t * buf)
375 {
376 return !(option_check_nl_at_eof && buf->size > 0
377 && edit_buffer_get_byte (buf, buf->size - 1) != '\n'
378 && edit_query_dialog2 (_("Warning"),
379 _("The file you are saving does not end with a newline."),
380 _("C&ontinue"), _("&Cancel")) != 0);
381 }
382
383 /* --------------------------------------------------------------------------------------------- */
384
385 static vfs_path_t *
edit_get_save_file_as(WEdit * edit)386 edit_get_save_file_as (WEdit * edit)
387 {
388 static LineBreaks cur_lb = LB_ASIS;
389 char *filename_res;
390 vfs_path_t *ret_vpath = NULL;
391
392 const char *lb_names[LB_NAMES] = {
393 N_("&Do not change"),
394 N_("&Unix format (LF)"),
395 N_("&Windows/DOS format (CR LF)"),
396 N_("&Macintosh format (CR)")
397 };
398
399 quick_widget_t quick_widgets[] = {
400 /* *INDENT-OFF* */
401 QUICK_LABELED_INPUT (N_("Enter file name:"), input_label_above,
402 vfs_path_as_str (edit->filename_vpath), "save-as",
403 &filename_res, NULL, FALSE, FALSE, INPUT_COMPLETE_FILENAMES),
404 QUICK_SEPARATOR (TRUE),
405 QUICK_LABEL (N_("Change line breaks to:"), NULL),
406 QUICK_RADIO (LB_NAMES, lb_names, (int *) &cur_lb, NULL),
407 QUICK_BUTTONS_OK_CANCEL,
408 QUICK_END
409 /* *INDENT-ON* */
410 };
411
412 quick_dialog_t qdlg = {
413 -1, -1, 64,
414 N_("Save As"), "[Save File As]",
415 quick_widgets, NULL, NULL
416 };
417
418 if (quick_dialog (&qdlg) != B_CANCEL)
419 {
420 char *fname;
421
422 edit->lb = cur_lb;
423 fname = tilde_expand (filename_res);
424 g_free (filename_res);
425 ret_vpath = vfs_path_from_str (fname);
426 g_free (fname);
427 }
428
429 return ret_vpath;
430 }
431
432 /* --------------------------------------------------------------------------------------------- */
433
434 /** returns TRUE on success */
435
436 static gboolean
edit_save_cmd(WEdit * edit)437 edit_save_cmd (WEdit * edit)
438 {
439 int res, save_lock = 0;
440
441 if (!edit->locked && !edit->delete_file)
442 save_lock = lock_file (edit->filename_vpath);
443 res = edit_save_file (edit, edit->filename_vpath);
444
445 /* Maintain modify (not save) lock on failure */
446 if ((res > 0 && edit->locked) || save_lock)
447 edit->locked = unlock_file (edit->filename_vpath);
448
449 /* On failure try 'save as', it does locking on its own */
450 if (res == 0)
451 return edit_save_as_cmd (edit);
452
453 if (res > 0)
454 {
455 edit->delete_file = 0;
456 edit->modified = 0;
457 }
458
459 edit->force |= REDRAW_COMPLETELY;
460
461 return TRUE;
462 }
463
464 /* --------------------------------------------------------------------------------------------- */
465 /**
466 * Load file content
467 *
468 * @param h screen the owner of editor window
469 * @param vpath vfs file path
470 * @return TRUE if file content was successfully loaded, FALSE otherwise
471 */
472
473 static inline gboolean
edit_load_file_from_filename(WDialog * h,const vfs_path_t * vpath)474 edit_load_file_from_filename (WDialog * h, const vfs_path_t * vpath)
475 {
476 Widget *w = WIDGET (h);
477
478 return edit_add_window (h, w->y + 1, w->x, w->lines - 2, w->cols, vpath, 0);
479 }
480
481 /* --------------------------------------------------------------------------------------------- */
482
483 static void
edit_delete_column_of_text(WEdit * edit)484 edit_delete_column_of_text (WEdit * edit)
485 {
486 off_t m1, m2;
487 off_t n;
488 long b, c, d;
489
490 eval_marks (edit, &m1, &m2);
491 n = edit_buffer_get_forward_offset (&edit->buffer, m1, 0, m2) + 1;
492 c = (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, m1), 0, m1);
493 d = (long) edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, m2), 0, m2);
494 b = MAX (MIN (c, d), MIN (edit->column1, edit->column2));
495 c = MAX (c, MAX (edit->column1, edit->column2));
496
497 while (n-- != 0)
498 {
499 off_t r, p, q;
500
501 r = edit_buffer_get_current_bol (&edit->buffer);
502 p = edit_move_forward3 (edit, r, b, 0);
503 q = edit_move_forward3 (edit, r, c, 0);
504 p = MAX (p, m1);
505 q = MIN (q, m2);
506 edit_cursor_move (edit, p - edit->buffer.curs1);
507 /* delete line between margins */
508 for (; q > p; q--)
509 if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
510 edit_delete (edit, TRUE);
511
512 /* move to next line except on the last delete */
513 if (n != 0)
514 edit_cursor_move (edit,
515 edit_buffer_get_forward_offset (&edit->buffer, edit->buffer.curs1, 1,
516 0) - edit->buffer.curs1);
517 }
518 }
519
520 /* --------------------------------------------------------------------------------------------- */
521 /** if success return 0 */
522
523 static int
edit_block_delete(WEdit * edit)524 edit_block_delete (WEdit * edit)
525 {
526 off_t start_mark, end_mark;
527 off_t curs_pos;
528 long curs_line, c1, c2;
529
530 if (!eval_marks (edit, &start_mark, &end_mark))
531 return 0;
532
533 if (edit->column_highlight && edit->mark2 < 0)
534 edit_mark_cmd (edit, FALSE);
535
536 /* Warning message with a query to continue or cancel the operation */
537 if ((end_mark - start_mark) > option_max_undo / 2 &&
538 edit_query_dialog2 (_("Warning"),
539 ("Block is large, you may not be able to undo this action"),
540 _("C&ontinue"), _("&Cancel")) != 0)
541 return 1;
542
543 c1 = MIN (edit->column1, edit->column2);
544 c2 = MAX (edit->column1, edit->column2);
545 edit->column1 = c1;
546 edit->column2 = c2;
547
548 edit_push_markers (edit);
549
550 curs_line = edit->buffer.curs_line;
551
552 curs_pos = edit->curs_col + edit->over_col;
553
554 /* move cursor to start of selection */
555 edit_cursor_move (edit, start_mark - edit->buffer.curs1);
556 edit_scroll_screen_over_cursor (edit);
557
558 if (start_mark < end_mark)
559 {
560 if (edit->column_highlight)
561 {
562 off_t line_width;
563
564 if (edit->mark2 < 0)
565 edit_mark_cmd (edit, FALSE);
566 edit_delete_column_of_text (edit);
567 /* move cursor to the saved position */
568 edit_move_to_line (edit, curs_line);
569 /* calculate line width and cursor position before cut */
570 line_width = edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer), 0,
571 edit_buffer_get_current_eol (&edit->buffer));
572 if (option_cursor_beyond_eol && curs_pos > line_width)
573 edit->over_col = curs_pos - line_width;
574 }
575 else
576 {
577 off_t count;
578
579 for (count = start_mark; count < end_mark; count++)
580 edit_delete (edit, TRUE);
581 }
582 }
583
584 edit_set_markers (edit, 0, 0, 0, 0);
585 edit->force |= REDRAW_PAGE;
586
587 return 0;
588 }
589
590 /* --------------------------------------------------------------------------------------------- */
591 /** Return a null terminated length of text. Result must be g_free'd */
592
593 static unsigned char *
edit_get_block(WEdit * edit,off_t start,off_t finish,off_t * l)594 edit_get_block (WEdit * edit, off_t start, off_t finish, off_t * l)
595 {
596 unsigned char *s, *r;
597
598 r = s = g_malloc0 (finish - start + 1);
599
600 if (edit->column_highlight)
601 {
602 *l = 0;
603
604 /* copy from buffer, excluding chars that are out of the column 'margins' */
605 for (; start < finish; start++)
606 {
607 int c;
608 off_t x;
609
610 x = edit_move_forward3 (edit, edit_buffer_get_bol (&edit->buffer, start), 0, start);
611 c = edit_buffer_get_byte (&edit->buffer, start);
612 if ((x >= edit->column1 && x < edit->column2)
613 || (x >= edit->column2 && x < edit->column1) || c == '\n')
614 {
615 *s++ = c;
616 (*l)++;
617 }
618 }
619 }
620 else
621 {
622 *l = finish - start;
623
624 for (; start < finish; start++)
625 *s++ = edit_buffer_get_byte (&edit->buffer, start);
626 }
627
628 *s = '\0';
629
630 return r;
631 }
632
633 /* --------------------------------------------------------------------------------------------- */
634 /** copies a block to clipboard file */
635
636 static gboolean
edit_save_block_to_clip_file(WEdit * edit,off_t start,off_t finish)637 edit_save_block_to_clip_file (WEdit * edit, off_t start, off_t finish)
638 {
639 gboolean ret;
640 gchar *tmp;
641
642 tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
643 ret = edit_save_block (edit, tmp, start, finish);
644 g_free (tmp);
645
646 return ret;
647 }
648
649 /* --------------------------------------------------------------------------------------------- */
650
651 static void
pipe_mail(const edit_buffer_t * buf,char * to,char * subject,char * cc)652 pipe_mail (const edit_buffer_t * buf, char *to, char *subject, char *cc)
653 {
654 FILE *p = 0;
655 char *s;
656
657 to = name_quote (to, FALSE);
658 subject = name_quote (subject, FALSE);
659 cc = name_quote (cc, FALSE);
660 s = g_strconcat ("mail -s ", subject, *cc ? " -c " : "", cc, " ", to, (char *) NULL);
661 g_free (to);
662 g_free (subject);
663 g_free (cc);
664
665 if (s != NULL)
666 {
667 p = popen (s, "w");
668 g_free (s);
669 }
670
671 if (p != NULL)
672 {
673 off_t i;
674
675 for (i = 0; i < buf->size; i++)
676 if (fputc (edit_buffer_get_byte (buf, i), p) < 0)
677 break;
678 pclose (p);
679 }
680 }
681
682 /* --------------------------------------------------------------------------------------------- */
683
684 static void
edit_insert_column_of_text(WEdit * edit,unsigned char * data,off_t size,long width,off_t * start_pos,off_t * end_pos,long * col1,long * col2)685 edit_insert_column_of_text (WEdit * edit, unsigned char *data, off_t size, long width,
686 off_t * start_pos, off_t * end_pos, long *col1, long *col2)
687 {
688 off_t i, cursor;
689 long col;
690
691 cursor = edit->buffer.curs1;
692 col = edit_get_col (edit);
693
694 for (i = 0; i < size; i++)
695 {
696 if (data[i] != '\n')
697 edit_insert (edit, data[i]);
698 else
699 { /* fill in and move to next line */
700 long l;
701 off_t p;
702
703 if (edit_buffer_get_current_byte (&edit->buffer) != '\n')
704 {
705 for (l = width - (edit_get_col (edit) - col); l > 0; l -= space_width)
706 edit_insert (edit, ' ');
707 }
708 for (p = edit->buffer.curs1;; p++)
709 {
710 if (p == edit->buffer.size)
711 {
712 edit_cursor_move (edit, edit->buffer.size - edit->buffer.curs1);
713 edit_insert_ahead (edit, '\n');
714 p++;
715 break;
716 }
717 if (edit_buffer_get_byte (&edit->buffer, p) == '\n')
718 {
719 p++;
720 break;
721 }
722 }
723 edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->buffer.curs1);
724
725 for (l = col - edit_get_col (edit); l >= space_width; l -= space_width)
726 edit_insert (edit, ' ');
727 }
728 }
729
730 *col1 = col;
731 *col2 = col + width;
732 *start_pos = cursor;
733 *end_pos = edit->buffer.curs1;
734 edit_cursor_move (edit, cursor - edit->buffer.curs1);
735 }
736
737 /* --------------------------------------------------------------------------------------------- */
738 /**
739 * Callback for the iteration of objects in the 'editors' array.
740 * Toggle syntax highlighting in editor object.
741 *
742 * @param data probably WEdit object
743 * @param user_data unused
744 */
745
746 static void
edit_syntax_onoff_cb(void * data,void * user_data)747 edit_syntax_onoff_cb (void *data, void *user_data)
748 {
749 (void) user_data;
750
751 if (edit_widget_is_editor (CONST_WIDGET (data)))
752 {
753 WEdit *edit = (WEdit *) data;
754
755 if (option_syntax_highlighting)
756 edit_load_syntax (edit, NULL, edit->syntax_type);
757 edit->force |= REDRAW_PAGE;
758 }
759 }
760
761 /* --------------------------------------------------------------------------------------------- */
762
763 static cb_ret_t
editcmd_dialog_raw_key_query_cb(Widget * w,Widget * sender,widget_msg_t msg,int parm,void * data)764 editcmd_dialog_raw_key_query_cb (Widget * w, Widget * sender, widget_msg_t msg, int parm,
765 void *data)
766 {
767 WDialog *h = DIALOG (w);
768
769 switch (msg)
770 {
771 case MSG_KEY:
772 h->ret_value = parm;
773 dlg_stop (h);
774 return MSG_HANDLED;
775 default:
776 return dlg_default_callback (w, sender, msg, parm, data);
777 }
778 }
779
780 /* --------------------------------------------------------------------------------------------- */
781 /*** public functions ****************************************************************************/
782 /* --------------------------------------------------------------------------------------------- */
783
784 void
edit_refresh_cmd(void)785 edit_refresh_cmd (void)
786 {
787 tty_clear_screen ();
788 repaint_screen ();
789 tty_keypad (TRUE);
790 }
791
792 /* --------------------------------------------------------------------------------------------- */
793 /**
794 * Toggle syntax highlighting in all editor windows.
795 *
796 * @param h root widget for all windows
797 */
798
799 void
edit_syntax_onoff_cmd(WDialog * h)800 edit_syntax_onoff_cmd (WDialog * h)
801 {
802 option_syntax_highlighting = !option_syntax_highlighting;
803 g_list_foreach (GROUP (h)->widgets, edit_syntax_onoff_cb, NULL);
804 widget_draw (WIDGET (h));
805 }
806
807 /* --------------------------------------------------------------------------------------------- */
808 /**
809 * Toggle tabs showing in all editor windows.
810 *
811 * @param h root widget for all windows
812 */
813
814 void
edit_show_tabs_tws_cmd(WDialog * h)815 edit_show_tabs_tws_cmd (WDialog * h)
816 {
817 enable_show_tabs_tws = !enable_show_tabs_tws;
818 widget_draw (WIDGET (h));
819 }
820
821 /* --------------------------------------------------------------------------------------------- */
822 /**
823 * Toggle right margin showing in all editor windows.
824 *
825 * @param h root widget for all windows
826 */
827
828 void
edit_show_margin_cmd(WDialog * h)829 edit_show_margin_cmd (WDialog * h)
830 {
831 show_right_margin = !show_right_margin;
832 widget_draw (WIDGET (h));
833 }
834
835 /* --------------------------------------------------------------------------------------------- */
836 /**
837 * Toggle line numbers showing in all editor windows.
838 *
839 * @param h root widget for all windows
840 */
841
842 void
edit_show_numbers_cmd(WDialog * h)843 edit_show_numbers_cmd (WDialog * h)
844 {
845 option_line_state = !option_line_state;
846 option_line_state_width = option_line_state ? LINE_STATE_WIDTH : 0;
847 widget_draw (WIDGET (h));
848 }
849
850 /* --------------------------------------------------------------------------------------------- */
851
852 void
edit_save_mode_cmd(void)853 edit_save_mode_cmd (void)
854 {
855 char *str_result = NULL;
856
857 const char *str[] = {
858 N_("&Quick save"),
859 N_("&Safe save"),
860 N_("&Do backups with following extension:")
861 };
862
863 #ifdef ENABLE_NLS
864 size_t i;
865
866 for (i = 0; i < 3; i++)
867 str[i] = _(str[i]);
868 #endif
869
870 g_assert (option_backup_ext != NULL);
871
872 {
873 quick_widget_t quick_widgets[] = {
874 /* *INDENT-OFF* */
875 QUICK_RADIO (3, str, &option_save_mode, &edit_save_mode_radio_id),
876 QUICK_INPUT (option_backup_ext, "edit-backup-ext", &str_result,
877 &edit_save_mode_input_id, FALSE, FALSE, INPUT_COMPLETE_NONE),
878 QUICK_SEPARATOR (TRUE),
879 QUICK_CHECKBOX (N_("Check &POSIX new line"), &option_check_nl_at_eof, NULL),
880 QUICK_BUTTONS_OK_CANCEL,
881 QUICK_END
882 /* *INDENT-ON* */
883 };
884
885 quick_dialog_t qdlg = {
886 -1, -1, 38,
887 N_("Edit Save Mode"), "[Edit Save Mode]",
888 quick_widgets, edit_save_mode_callback, NULL
889 };
890
891 if (quick_dialog (&qdlg) != B_CANCEL)
892 {
893 g_free (option_backup_ext);
894 option_backup_ext = str_result;
895 }
896 }
897 }
898
899 /* --------------------------------------------------------------------------------------------- */
900
901 void
edit_set_filename(WEdit * edit,const vfs_path_t * name_vpath)902 edit_set_filename (WEdit * edit, const vfs_path_t * name_vpath)
903 {
904 vfs_path_free (edit->filename_vpath, TRUE);
905 edit->filename_vpath = vfs_path_clone (name_vpath);
906
907 if (edit->dir_vpath == NULL)
908 edit->dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
909 }
910
911 /* --------------------------------------------------------------------------------------------- */
912 /* Here we want to warn the users of overwriting an existing file,
913 but only if they have made a change to the filename */
914 /* returns TRUE on success */
915 gboolean
edit_save_as_cmd(WEdit * edit)916 edit_save_as_cmd (WEdit * edit)
917 {
918 /* This heads the 'Save As' dialog box */
919 vfs_path_t *exp_vpath;
920 int save_lock = 0;
921 gboolean different_filename = FALSE;
922 gboolean ret = FALSE;
923
924 if (!edit_check_newline (&edit->buffer))
925 return FALSE;
926
927 exp_vpath = edit_get_save_file_as (edit);
928 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
929
930 if (exp_vpath != NULL && vfs_path_len (exp_vpath) != 0)
931 {
932 int rv;
933
934 if (!vfs_path_equal (edit->filename_vpath, exp_vpath))
935 {
936 int file;
937 struct stat sb;
938
939 if (mc_stat (exp_vpath, &sb) == 0 && !S_ISREG (sb.st_mode))
940 {
941 edit_error_dialog (_("Save as"),
942 get_sys_error (_
943 ("Cannot save: destination is not a regular file")));
944 goto ret;
945 }
946
947 different_filename = TRUE;
948 file = mc_open (exp_vpath, O_RDONLY | O_BINARY);
949
950 if (file == -1)
951 edit->stat1.st_mode |= S_IWUSR;
952 else
953 {
954 /* the file exists */
955 mc_close (file);
956 /* Overwrite the current file or cancel the operation */
957 if (edit_query_dialog2
958 (_("Warning"),
959 _("A file already exists with this name"), _("&Overwrite"), _("&Cancel")))
960 goto ret;
961 }
962
963 save_lock = lock_file (exp_vpath);
964 }
965 else if (!edit->locked && !edit->delete_file)
966 /* filenames equal, check if already locked */
967 save_lock = lock_file (exp_vpath);
968
969 if (different_filename)
970 /* Allow user to write into saved (under another name) file
971 * even if original file had r/o user permissions. */
972 edit->stat1.st_mode |= S_IWUSR;
973
974 rv = edit_save_file (edit, exp_vpath);
975 switch (rv)
976 {
977 case 1:
978 /* Successful, so unlock both files */
979 if (different_filename)
980 {
981 if (save_lock)
982 unlock_file (exp_vpath);
983 if (edit->locked)
984 edit->locked = unlock_file (edit->filename_vpath);
985 }
986 else if (edit->locked || save_lock)
987 edit->locked = unlock_file (edit->filename_vpath);
988
989 edit_set_filename (edit, exp_vpath);
990 if (edit->lb != LB_ASIS)
991 edit_reload (edit, exp_vpath);
992 edit->modified = 0;
993 edit->delete_file = 0;
994 if (different_filename)
995 edit_load_syntax (edit, NULL, edit->syntax_type);
996 ret = TRUE;
997 break;
998
999 default:
1000 edit_error_dialog (_("Save as"), get_sys_error (_("Cannot save file")));
1001 MC_FALLTHROUGH;
1002
1003 case -1:
1004 /* Failed, so maintain modify (not save) lock */
1005 if (save_lock)
1006 unlock_file (exp_vpath);
1007 break;
1008 }
1009 }
1010
1011 ret:
1012 vfs_path_free (exp_vpath, TRUE);
1013 edit->force |= REDRAW_COMPLETELY;
1014 return ret;
1015 }
1016
1017 /* --------------------------------------------------------------------------------------------- */
1018 /** returns TRUE on success */
1019
1020 gboolean
edit_save_confirm_cmd(WEdit * edit)1021 edit_save_confirm_cmd (WEdit * edit)
1022 {
1023 if (edit->filename_vpath == NULL)
1024 return edit_save_as_cmd (edit);
1025
1026 if (!edit_check_newline (&edit->buffer))
1027 return FALSE;
1028
1029 if (edit_confirm_save)
1030 {
1031 char *f;
1032 gboolean ok;
1033
1034 f = g_strdup_printf (_("Confirm save file: \"%s\""),
1035 vfs_path_as_str (edit->filename_vpath));
1036 ok = (edit_query_dialog2 (_("Save file"), f, _("&Save"), _("&Cancel")) == 0);
1037 g_free (f);
1038 if (!ok)
1039 return FALSE;
1040 }
1041
1042 return edit_save_cmd (edit);
1043 }
1044
1045 /* --------------------------------------------------------------------------------------------- */
1046 /**
1047 * Ask file to edit and load it.
1048 *
1049 * @return TRUE on success or cancel of ask.
1050 */
1051
1052 gboolean
edit_load_cmd(WDialog * h)1053 edit_load_cmd (WDialog * h)
1054 {
1055 char *exp;
1056 gboolean ret = TRUE; /* possible cancel */
1057
1058 exp = input_expand_dialog (_("Load"), _("Enter file name:"),
1059 MC_HISTORY_EDIT_LOAD, INPUT_LAST_TEXT,
1060 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD);
1061
1062 if (exp != NULL && *exp != '\0')
1063 {
1064 vfs_path_t *exp_vpath;
1065
1066 exp_vpath = vfs_path_from_str (exp);
1067 ret = edit_load_file_from_filename (h, exp_vpath);
1068 vfs_path_free (exp_vpath, TRUE);
1069 }
1070
1071 g_free (exp);
1072
1073 return ret;
1074 }
1075
1076 /* --------------------------------------------------------------------------------------------- */
1077 /**
1078 * Show history od edited or viewed files and open selected file.
1079 *
1080 * @return TRUE on success, FALSE otherwise.
1081 */
1082
1083 gboolean
edit_load_file_from_history(WDialog * h)1084 edit_load_file_from_history (WDialog * h)
1085 {
1086 char *exp;
1087 int action;
1088 gboolean ret = TRUE; /* possible cancel */
1089
1090 exp = show_file_history (CONST_WIDGET (h), &action);
1091 if (exp != NULL && (action == CK_Edit || action == CK_Enter))
1092 {
1093 vfs_path_t *exp_vpath;
1094
1095 exp_vpath = vfs_path_from_str (exp);
1096 ret = edit_load_file_from_filename (h, exp_vpath);
1097 vfs_path_free (exp_vpath, TRUE);
1098 }
1099
1100 g_free (exp);
1101
1102 return ret;
1103 }
1104
1105 /* --------------------------------------------------------------------------------------------- */
1106 /**
1107 * Load syntax file to edit.
1108 *
1109 * @return TRUE on success
1110 */
1111
1112 gboolean
edit_load_syntax_file(WDialog * h)1113 edit_load_syntax_file (WDialog * h)
1114 {
1115 vfs_path_t *extdir_vpath;
1116 int dir = 0;
1117 gboolean ret = FALSE;
1118
1119 if (geteuid () == 0)
1120 dir = query_dialog (_("Syntax file edit"),
1121 _("Which syntax file you want to edit?"), D_NORMAL, 2,
1122 _("&User"), _("&System wide"));
1123
1124 extdir_vpath =
1125 vfs_path_build_filename (mc_global.sysconfig_dir, "syntax", "Syntax", (char *) NULL);
1126 if (!exist_file (vfs_path_get_last_path_str (extdir_vpath)))
1127 {
1128 vfs_path_free (extdir_vpath, TRUE);
1129 extdir_vpath =
1130 vfs_path_build_filename (mc_global.share_data_dir, "syntax", "Syntax", (char *) NULL);
1131 }
1132
1133 if (dir == 0)
1134 {
1135 vfs_path_t *user_syntax_file_vpath;
1136
1137 user_syntax_file_vpath = mc_config_get_full_vpath (EDIT_HOME_SYNTAX_FILE);
1138 check_for_default (extdir_vpath, user_syntax_file_vpath);
1139 ret = edit_load_file_from_filename (h, user_syntax_file_vpath);
1140 vfs_path_free (user_syntax_file_vpath, TRUE);
1141 }
1142 else if (dir == 1)
1143 ret = edit_load_file_from_filename (h, extdir_vpath);
1144
1145 vfs_path_free (extdir_vpath, TRUE);
1146
1147 return ret;
1148 }
1149
1150 /* --------------------------------------------------------------------------------------------- */
1151 /**
1152 * Load menu file to edit.
1153 *
1154 * @return TRUE on success
1155 */
1156
1157 gboolean
edit_load_menu_file(WDialog * h)1158 edit_load_menu_file (WDialog * h)
1159 {
1160 vfs_path_t *buffer_vpath;
1161 vfs_path_t *menufile_vpath;
1162 int dir;
1163 gboolean ret;
1164
1165 query_set_sel (1);
1166 dir = query_dialog (_("Menu edit"),
1167 _("Which menu file do you want to edit?"), D_NORMAL,
1168 geteuid () != 0 ? 2 : 3, _("&Local"), _("&User"), _("&System wide"));
1169
1170 menufile_vpath =
1171 vfs_path_build_filename (mc_global.sysconfig_dir, EDIT_GLOBAL_MENU, (char *) NULL);
1172 if (!exist_file (vfs_path_get_last_path_str (menufile_vpath)))
1173 {
1174 vfs_path_free (menufile_vpath, TRUE);
1175 menufile_vpath =
1176 vfs_path_build_filename (mc_global.share_data_dir, EDIT_GLOBAL_MENU, (char *) NULL);
1177 }
1178
1179 switch (dir)
1180 {
1181 case 0:
1182 buffer_vpath = vfs_path_from_str (EDIT_LOCAL_MENU);
1183 check_for_default (menufile_vpath, buffer_vpath);
1184 chmod (vfs_path_get_last_path_str (buffer_vpath), 0600);
1185 break;
1186
1187 case 1:
1188 buffer_vpath = mc_config_get_full_vpath (EDIT_HOME_MENU);
1189 check_for_default (menufile_vpath, buffer_vpath);
1190 break;
1191
1192 case 2:
1193 buffer_vpath =
1194 vfs_path_build_filename (mc_global.sysconfig_dir, EDIT_GLOBAL_MENU, (char *) NULL);
1195 if (!exist_file (vfs_path_get_last_path_str (buffer_vpath)))
1196 {
1197 vfs_path_free (buffer_vpath, TRUE);
1198 buffer_vpath =
1199 vfs_path_build_filename (mc_global.share_data_dir, EDIT_GLOBAL_MENU, (char *) NULL);
1200 }
1201 break;
1202
1203 default:
1204 vfs_path_free (menufile_vpath, TRUE);
1205 return FALSE;
1206 }
1207
1208 ret = edit_load_file_from_filename (h, buffer_vpath);
1209
1210 vfs_path_free (buffer_vpath, TRUE);
1211 vfs_path_free (menufile_vpath, TRUE);
1212
1213 return ret;
1214 }
1215
1216 /* --------------------------------------------------------------------------------------------- */
1217 /**
1218 * Close window with opened file.
1219 *
1220 * @return TRUE if file was closed.
1221 */
1222
1223 gboolean
edit_close_cmd(WEdit * edit)1224 edit_close_cmd (WEdit * edit)
1225 {
1226 gboolean ret;
1227
1228 ret = (edit != NULL) && edit_ok_to_exit (edit);
1229
1230 if (ret)
1231 {
1232 Widget *w = WIDGET (edit);
1233 WGroup *g = w->owner;
1234
1235 if (edit->locked != 0)
1236 unlock_file (edit->filename_vpath);
1237
1238 group_remove_widget (w);
1239 widget_destroy (w);
1240
1241 if (edit_widget_is_editor (CONST_WIDGET (g->current->data)))
1242 edit = (WEdit *) (g->current->data);
1243 else
1244 {
1245 edit = find_editor (DIALOG (g));
1246 if (edit != NULL)
1247 widget_select (WIDGET (edit));
1248 }
1249 }
1250
1251 if (edit != NULL)
1252 edit->force |= REDRAW_COMPLETELY;
1253
1254 return ret;
1255 }
1256
1257 /* --------------------------------------------------------------------------------------------- */
1258 /**
1259 if mark2 is -1 then marking is from mark1 to the cursor.
1260 Otherwise its between the markers. This handles this.
1261 Returns FALSE if no text is marked.
1262 */
1263
1264 gboolean
eval_marks(WEdit * edit,off_t * start_mark,off_t * end_mark)1265 eval_marks (WEdit * edit, off_t * start_mark, off_t * end_mark)
1266 {
1267 long end_mark_curs;
1268
1269 if (edit->mark1 == edit->mark2)
1270 {
1271 *start_mark = *end_mark = 0;
1272 edit->column2 = edit->column1 = 0;
1273 return FALSE;
1274 }
1275
1276 if (edit->end_mark_curs < 0)
1277 end_mark_curs = edit->buffer.curs1;
1278 else
1279 end_mark_curs = edit->end_mark_curs;
1280
1281 if (edit->mark2 >= 0)
1282 {
1283 *start_mark = MIN (edit->mark1, edit->mark2);
1284 *end_mark = MAX (edit->mark1, edit->mark2);
1285 }
1286 else
1287 {
1288 *start_mark = MIN (edit->mark1, end_mark_curs);
1289 *end_mark = MAX (edit->mark1, end_mark_curs);
1290 edit->column2 = edit->curs_col + edit->over_col;
1291 }
1292
1293 if (edit->column_highlight
1294 && ((edit->mark1 > end_mark_curs && edit->column1 < edit->column2)
1295 || (edit->mark1 < end_mark_curs && edit->column1 > edit->column2)))
1296 {
1297 off_t start_bol, start_eol;
1298 off_t end_bol, end_eol;
1299 long col1, col2;
1300 off_t diff1, diff2;
1301
1302 start_bol = edit_buffer_get_bol (&edit->buffer, *start_mark);
1303 start_eol = edit_buffer_get_eol (&edit->buffer, start_bol - 1) + 1;
1304 end_bol = edit_buffer_get_bol (&edit->buffer, *end_mark);
1305 end_eol = edit_buffer_get_eol (&edit->buffer, *end_mark);
1306 col1 = MIN (edit->column1, edit->column2);
1307 col2 = MAX (edit->column1, edit->column2);
1308
1309 diff1 = edit_move_forward3 (edit, start_bol, col2, 0) -
1310 edit_move_forward3 (edit, start_bol, col1, 0);
1311 diff2 = edit_move_forward3 (edit, end_bol, col2, 0) -
1312 edit_move_forward3 (edit, end_bol, col1, 0);
1313
1314 *start_mark -= diff1;
1315 *end_mark += diff2;
1316 *start_mark = MAX (*start_mark, start_eol);
1317 *end_mark = MIN (*end_mark, end_eol);
1318 }
1319
1320 return TRUE;
1321 }
1322
1323 /* --------------------------------------------------------------------------------------------- */
1324
1325 void
edit_block_copy_cmd(WEdit * edit)1326 edit_block_copy_cmd (WEdit * edit)
1327 {
1328 off_t start_mark, end_mark, current = edit->buffer.curs1;
1329 off_t mark1 = 0, mark2 = 0;
1330 long c1 = 0, c2 = 0;
1331 off_t size;
1332 unsigned char *copy_buf;
1333
1334 edit_update_curs_col (edit);
1335 if (!eval_marks (edit, &start_mark, &end_mark))
1336 return;
1337
1338 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1339
1340 /* all that gets pushed are deletes hence little space is used on the stack */
1341
1342 edit_push_markers (edit);
1343
1344 if (edit->column_highlight)
1345 {
1346 long col_delta;
1347
1348 col_delta = labs (edit->column2 - edit->column1);
1349 edit_insert_column_of_text (edit, copy_buf, size, col_delta, &mark1, &mark2, &c1, &c2);
1350 }
1351 else
1352 {
1353 int size_orig = size;
1354
1355 while (size-- != 0)
1356 edit_insert_ahead (edit, copy_buf[size]);
1357
1358 /* Place cursor at the end of text selection */
1359 if (option_cursor_after_inserted_block)
1360 edit_cursor_move (edit, size_orig);
1361 }
1362
1363 g_free (copy_buf);
1364 edit_scroll_screen_over_cursor (edit);
1365
1366 if (edit->column_highlight)
1367 edit_set_markers (edit, edit->buffer.curs1, mark2, c1, c2);
1368 else if (start_mark < current && end_mark > current)
1369 edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
1370
1371 edit->force |= REDRAW_PAGE;
1372 }
1373
1374
1375 /* --------------------------------------------------------------------------------------------- */
1376
1377 void
edit_block_move_cmd(WEdit * edit)1378 edit_block_move_cmd (WEdit * edit)
1379 {
1380 off_t current;
1381 unsigned char *copy_buf = NULL;
1382 off_t start_mark, end_mark;
1383
1384 if (!eval_marks (edit, &start_mark, &end_mark))
1385 return;
1386
1387 if (!edit->column_highlight && edit->buffer.curs1 > start_mark && edit->buffer.curs1 < end_mark)
1388 return;
1389
1390 if (edit->mark2 < 0)
1391 edit_mark_cmd (edit, FALSE);
1392 edit_push_markers (edit);
1393
1394 if (edit->column_highlight)
1395 {
1396 off_t mark1, mark2;
1397 off_t size;
1398 long c1, c2, b_width;
1399 long x, x2;
1400
1401 c1 = MIN (edit->column1, edit->column2);
1402 c2 = MAX (edit->column1, edit->column2);
1403 b_width = c2 - c1;
1404
1405 edit_update_curs_col (edit);
1406
1407 x = edit->curs_col;
1408 x2 = x + edit->over_col;
1409
1410 /* do nothing when cursor inside first line of selected area */
1411 if ((edit_buffer_get_eol (&edit->buffer, edit->buffer.curs1) ==
1412 edit_buffer_get_eol (&edit->buffer, start_mark)) && x2 > c1 && x2 <= c2)
1413 return;
1414
1415 if (edit->buffer.curs1 > start_mark
1416 && edit->buffer.curs1 < edit_buffer_get_eol (&edit->buffer, end_mark))
1417 {
1418 if (x > c2)
1419 x -= b_width;
1420 else if (x > c1 && x <= c2)
1421 x = c1;
1422 }
1423 /* save current selection into buffer */
1424 copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
1425
1426 /* remove current selection */
1427 edit_block_delete_cmd (edit);
1428
1429 edit->over_col = MAX (0, edit->over_col - b_width);
1430 /* calculate the cursor pos after delete block */
1431 current = edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer), x, 0);
1432 edit_cursor_move (edit, current - edit->buffer.curs1);
1433 edit_scroll_screen_over_cursor (edit);
1434
1435 /* add TWS if need before block insertion */
1436 if (option_cursor_beyond_eol && edit->over_col > 0)
1437 edit_insert_over (edit);
1438
1439 edit_insert_column_of_text (edit, copy_buf, size, b_width, &mark1, &mark2, &c1, &c2);
1440 edit_set_markers (edit, mark1, mark2, c1, c2);
1441 }
1442 else
1443 {
1444 off_t count, count_orig;
1445
1446 current = edit->buffer.curs1;
1447 copy_buf = g_malloc0 (end_mark - start_mark);
1448 edit_cursor_move (edit, start_mark - edit->buffer.curs1);
1449 edit_scroll_screen_over_cursor (edit);
1450
1451 for (count = start_mark; count < end_mark; count++)
1452 copy_buf[end_mark - count - 1] = edit_delete (edit, TRUE);
1453
1454 edit_scroll_screen_over_cursor (edit);
1455 edit_cursor_move (edit,
1456 current - edit->buffer.curs1 -
1457 (((current - edit->buffer.curs1) > 0) ? end_mark - start_mark : 0));
1458 edit_scroll_screen_over_cursor (edit);
1459 count_orig = count;
1460 while (count-- > start_mark)
1461 edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
1462
1463 edit_set_markers (edit, edit->buffer.curs1, edit->buffer.curs1 + end_mark - start_mark, 0,
1464 0);
1465
1466 /* Place cursor at the end of text selection */
1467 if (option_cursor_after_inserted_block)
1468 edit_cursor_move (edit, count_orig - start_mark);
1469 }
1470
1471 edit_scroll_screen_over_cursor (edit);
1472 g_free (copy_buf);
1473 edit->force |= REDRAW_PAGE;
1474 }
1475
1476 /* --------------------------------------------------------------------------------------------- */
1477 /** returns 1 if canceelled by user */
1478
1479 int
edit_block_delete_cmd(WEdit * edit)1480 edit_block_delete_cmd (WEdit * edit)
1481 {
1482 off_t start_mark, end_mark;
1483
1484 if (eval_marks (edit, &start_mark, &end_mark))
1485 return edit_block_delete (edit);
1486
1487 edit_delete_line (edit);
1488
1489 return 0;
1490 }
1491
1492 /* --------------------------------------------------------------------------------------------- */
1493 /**
1494 * Check if it's OK to close the file. If there are unsaved changes, ask user.
1495 *
1496 * @return TRUE if it's OK to exit, FALSE to continue editing.
1497 */
1498
1499 gboolean
edit_ok_to_exit(WEdit * edit)1500 edit_ok_to_exit (WEdit * edit)
1501 {
1502 const char *fname = N_("[NoName]");
1503 char *msg;
1504 int act;
1505
1506 if (!edit->modified)
1507 return TRUE;
1508
1509 if (edit->filename_vpath != NULL)
1510 fname = vfs_path_as_str (edit->filename_vpath);
1511 #ifdef ENABLE_NLS
1512 else
1513 fname = _(fname);
1514 #endif
1515
1516 if (!mc_global.midnight_shutdown)
1517 {
1518 query_set_sel (2);
1519
1520 msg = g_strdup_printf (_("File %s was modified.\nSave before close?"), fname);
1521 act = edit_query_dialog3 (_("Close file"), msg, _("&Yes"), _("&No"), _("&Cancel"));
1522 }
1523 else
1524 {
1525 msg = g_strdup_printf (_("Midnight Commander is being shut down.\nSave modified file %s?"),
1526 fname);
1527 act = edit_query_dialog2 (_("Quit"), msg, _("&Yes"), _("&No"));
1528
1529 /* Esc is No */
1530 if (act == -1)
1531 act = 1;
1532 }
1533
1534 g_free (msg);
1535
1536 switch (act)
1537 {
1538 case 0: /* Yes */
1539 if (!mc_global.midnight_shutdown && !edit_check_newline (&edit->buffer))
1540 return FALSE;
1541 edit_push_markers (edit);
1542 edit_set_markers (edit, 0, 0, 0, 0);
1543 if (!edit_save_cmd (edit) || mc_global.midnight_shutdown)
1544 return mc_global.midnight_shutdown;
1545 break;
1546 case 1: /* No */
1547 default:
1548 break;
1549 case 2: /* Cancel quit */
1550 case -1: /* Esc */
1551 return FALSE;
1552 }
1553
1554 return TRUE;
1555 }
1556
1557 /* --------------------------------------------------------------------------------------------- */
1558 /** save block, returns TRUE on success */
1559
1560 gboolean
edit_save_block(WEdit * edit,const char * filename,off_t start,off_t finish)1561 edit_save_block (WEdit * edit, const char *filename, off_t start, off_t finish)
1562 {
1563 int file;
1564 off_t len = 1;
1565 vfs_path_t *vpath;
1566
1567 vpath = vfs_path_from_str (filename);
1568 file = mc_open (vpath, O_CREAT | O_WRONLY | O_TRUNC,
1569 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_BINARY);
1570 vfs_path_free (vpath, TRUE);
1571 if (file == -1)
1572 return FALSE;
1573
1574 if (edit->column_highlight)
1575 {
1576 int r;
1577
1578 r = mc_write (file, VERTICAL_MAGIC, sizeof (VERTICAL_MAGIC));
1579 if (r > 0)
1580 {
1581 unsigned char *block, *p;
1582
1583 p = block = edit_get_block (edit, start, finish, &len);
1584 while (len != 0)
1585 {
1586 r = mc_write (file, p, len);
1587 if (r < 0)
1588 break;
1589 p += r;
1590 len -= r;
1591 }
1592 g_free (block);
1593 }
1594 }
1595 else
1596 {
1597 unsigned char *buf;
1598 off_t i = start;
1599
1600 len = finish - start;
1601 buf = g_malloc0 (TEMP_BUF_LEN);
1602 while (start != finish)
1603 {
1604 off_t end;
1605
1606 end = MIN (finish, start + TEMP_BUF_LEN);
1607 for (; i < end; i++)
1608 buf[i - start] = edit_buffer_get_byte (&edit->buffer, i);
1609 len -= mc_write (file, (char *) buf, end - start);
1610 start = end;
1611 }
1612 g_free (buf);
1613 }
1614 mc_close (file);
1615
1616 return (len == 0);
1617 }
1618
1619 /* --------------------------------------------------------------------------------------------- */
1620
1621 void
edit_paste_from_history(WEdit * edit)1622 edit_paste_from_history (WEdit * edit)
1623 {
1624 (void) edit;
1625 edit_error_dialog (_("Error"), _("This function is not implemented"));
1626 }
1627
1628 /* --------------------------------------------------------------------------------------------- */
1629
1630 gboolean
edit_copy_to_X_buf_cmd(WEdit * edit)1631 edit_copy_to_X_buf_cmd (WEdit * edit)
1632 {
1633 off_t start_mark, end_mark;
1634
1635 if (!eval_marks (edit, &start_mark, &end_mark))
1636 return TRUE;
1637
1638 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
1639 {
1640 edit_error_dialog (_("Copy to clipboard"), get_sys_error (_("Unable to save to file")));
1641 return FALSE;
1642 }
1643 /* try use external clipboard utility */
1644 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
1645
1646 if (option_drop_selection_on_copy)
1647 edit_mark_cmd (edit, TRUE);
1648
1649 return TRUE;
1650 }
1651
1652 /* --------------------------------------------------------------------------------------------- */
1653
1654 gboolean
edit_cut_to_X_buf_cmd(WEdit * edit)1655 edit_cut_to_X_buf_cmd (WEdit * edit)
1656 {
1657 off_t start_mark, end_mark;
1658
1659 if (!eval_marks (edit, &start_mark, &end_mark))
1660 return TRUE;
1661
1662 if (!edit_save_block_to_clip_file (edit, start_mark, end_mark))
1663 {
1664 edit_error_dialog (_("Cut to clipboard"), _("Unable to save to file"));
1665 return FALSE;
1666 }
1667 /* try use external clipboard utility */
1668 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
1669
1670 edit_block_delete_cmd (edit);
1671 edit_mark_cmd (edit, TRUE);
1672
1673 return TRUE;
1674 }
1675
1676 /* --------------------------------------------------------------------------------------------- */
1677
1678 gboolean
edit_paste_from_X_buf_cmd(WEdit * edit)1679 edit_paste_from_X_buf_cmd (WEdit * edit)
1680 {
1681 vfs_path_t *tmp;
1682 gboolean ret;
1683
1684 /* try use external clipboard utility */
1685 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_from_ext_clip", NULL);
1686 tmp = mc_config_get_full_vpath (EDIT_HOME_CLIP_FILE);
1687 ret = (edit_insert_file (edit, tmp) >= 0);
1688 vfs_path_free (tmp, TRUE);
1689
1690 return ret;
1691 }
1692
1693 /* --------------------------------------------------------------------------------------------- */
1694 /**
1695 * Ask user for the line and go to that line.
1696 * Negative numbers mean line from the end (i.e. -1 is the last line).
1697 */
1698
1699 void
edit_goto_cmd(WEdit * edit)1700 edit_goto_cmd (WEdit * edit)
1701 {
1702 static gboolean first_run = TRUE;
1703
1704 char *f;
1705 long l;
1706 char *error;
1707
1708 f = input_dialog (_("Goto line"), _("Enter line:"), MC_HISTORY_EDIT_GOTO_LINE,
1709 first_run ? NULL : INPUT_LAST_TEXT, INPUT_COMPLETE_NONE);
1710 if (f == NULL || *f == '\0')
1711 {
1712 g_free (f);
1713 return;
1714 }
1715
1716 l = strtol (f, &error, 0);
1717 if (*error != '\0')
1718 {
1719 g_free (f);
1720 return;
1721 }
1722
1723 if (l < 0)
1724 l = edit->buffer.lines + l + 2;
1725
1726 edit_move_display (edit, l - WIDGET (edit)->lines / 2 - 1);
1727 edit_move_to_line (edit, l - 1);
1728 edit->force |= REDRAW_COMPLETELY;
1729
1730 g_free (f);
1731 first_run = FALSE;
1732 }
1733
1734 /* --------------------------------------------------------------------------------------------- */
1735 /** Return TRUE on success */
1736
1737 gboolean
edit_save_block_cmd(WEdit * edit)1738 edit_save_block_cmd (WEdit * edit)
1739 {
1740 off_t start_mark, end_mark;
1741 char *exp, *tmp;
1742 gboolean ret = FALSE;
1743
1744 if (!eval_marks (edit, &start_mark, &end_mark))
1745 return TRUE;
1746
1747 tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
1748 exp =
1749 input_expand_dialog (_("Save block"), _("Enter file name:"),
1750 MC_HISTORY_EDIT_SAVE_BLOCK, tmp, INPUT_COMPLETE_FILENAMES);
1751 g_free (tmp);
1752 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
1753
1754 if (exp != NULL && *exp != '\0')
1755 {
1756 if (edit_save_block (edit, exp, start_mark, end_mark))
1757 ret = TRUE;
1758 else
1759 edit_error_dialog (_("Save block"), get_sys_error (_("Cannot save file")));
1760
1761 edit->force |= REDRAW_COMPLETELY;
1762 }
1763
1764 g_free (exp);
1765
1766 return ret;
1767 }
1768
1769 /* --------------------------------------------------------------------------------------------- */
1770
1771 /** returns TRUE on success */
1772 gboolean
edit_insert_file_cmd(WEdit * edit)1773 edit_insert_file_cmd (WEdit * edit)
1774 {
1775 char *tmp;
1776 char *exp;
1777 gboolean ret = FALSE;
1778
1779 tmp = mc_config_get_full_path (EDIT_HOME_CLIP_FILE);
1780 exp = input_expand_dialog (_("Insert file"), _("Enter file name:"),
1781 MC_HISTORY_EDIT_INSERT_FILE, tmp, INPUT_COMPLETE_FILENAMES);
1782 g_free (tmp);
1783
1784 edit_push_undo_action (edit, KEY_PRESS + edit->start_display);
1785
1786 if (exp != NULL && *exp != '\0')
1787 {
1788 vfs_path_t *exp_vpath;
1789
1790 exp_vpath = vfs_path_from_str (exp);
1791 ret = (edit_insert_file (edit, exp_vpath) >= 0);
1792 vfs_path_free (exp_vpath, TRUE);
1793
1794 if (!ret)
1795 edit_error_dialog (_("Insert file"), get_sys_error (_("Cannot insert file")));
1796 }
1797
1798 g_free (exp);
1799
1800 edit->force |= REDRAW_COMPLETELY;
1801 return ret;
1802 }
1803
1804 /* --------------------------------------------------------------------------------------------- */
1805 /** sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
1806
1807 int
edit_sort_cmd(WEdit * edit)1808 edit_sort_cmd (WEdit * edit)
1809 {
1810 char *exp, *tmp, *tmp_edit_block_name, *tmp_edit_temp_name;
1811 off_t start_mark, end_mark;
1812 int e;
1813
1814 if (!eval_marks (edit, &start_mark, &end_mark))
1815 {
1816 edit_error_dialog (_("Sort block"), _("You must first highlight a block of text"));
1817 return 0;
1818 }
1819
1820 tmp = mc_config_get_full_path (EDIT_HOME_BLOCK_FILE);
1821 edit_save_block (edit, tmp, start_mark, end_mark);
1822 g_free (tmp);
1823
1824 exp = input_dialog (_("Run sort"),
1825 _("Enter sort options (see manpage) separated by whitespace:"),
1826 MC_HISTORY_EDIT_SORT, INPUT_LAST_TEXT, INPUT_COMPLETE_NONE);
1827
1828 if (exp == NULL)
1829 return 1;
1830
1831 tmp_edit_block_name = mc_config_get_full_path (EDIT_HOME_BLOCK_FILE);
1832 tmp_edit_temp_name = mc_config_get_full_path (EDIT_HOME_TEMP_FILE);
1833 tmp =
1834 g_strconcat (" sort ", exp, " ", tmp_edit_block_name,
1835 " > ", tmp_edit_temp_name, (char *) NULL);
1836 g_free (tmp_edit_temp_name);
1837 g_free (tmp_edit_block_name);
1838 g_free (exp);
1839
1840 e = system (tmp);
1841 g_free (tmp);
1842 if (e != 0)
1843 {
1844 if (e == -1 || e == 127)
1845 edit_error_dialog (_("Sort"), get_sys_error (_("Cannot execute sort command")));
1846 else
1847 {
1848 char q[8];
1849
1850 sprintf (q, "%d ", e);
1851 tmp = g_strdup_printf (_("Sort returned non-zero: %s"), q);
1852 edit_error_dialog (_("Sort"), tmp);
1853 g_free (tmp);
1854 }
1855
1856 return -1;
1857 }
1858
1859 edit->force |= REDRAW_COMPLETELY;
1860
1861 if (edit_block_delete_cmd (edit))
1862 return 1;
1863
1864 {
1865 vfs_path_t *tmp_vpath;
1866
1867 tmp_vpath = mc_config_get_full_vpath (EDIT_HOME_TEMP_FILE);
1868 edit_insert_file (edit, tmp_vpath);
1869 vfs_path_free (tmp_vpath, TRUE);
1870 }
1871
1872 return 0;
1873 }
1874
1875 /* --------------------------------------------------------------------------------------------- */
1876 /**
1877 * Ask user for a command, execute it and paste its output back to the
1878 * editor.
1879 */
1880
1881 int
edit_ext_cmd(WEdit * edit)1882 edit_ext_cmd (WEdit * edit)
1883 {
1884 char *exp, *tmp, *tmp_edit_temp_file;
1885 int e;
1886
1887 exp =
1888 input_dialog (_("Paste output of external command"),
1889 _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, INPUT_LAST_TEXT,
1890 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES
1891 | INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_CD | INPUT_COMPLETE_COMMANDS |
1892 INPUT_COMPLETE_SHELL_ESC);
1893
1894 if (!exp)
1895 return 1;
1896
1897 tmp_edit_temp_file = mc_config_get_full_path (EDIT_HOME_TEMP_FILE);
1898 tmp = g_strconcat (exp, " > ", tmp_edit_temp_file, (char *) NULL);
1899 g_free (tmp_edit_temp_file);
1900 e = system (tmp);
1901 g_free (tmp);
1902 g_free (exp);
1903
1904 if (e != 0)
1905 {
1906 edit_error_dialog (_("External command"), get_sys_error (_("Cannot execute command")));
1907 return -1;
1908 }
1909
1910 edit->force |= REDRAW_COMPLETELY;
1911
1912 {
1913 vfs_path_t *tmp_vpath;
1914
1915 tmp_vpath = mc_config_get_full_vpath (EDIT_HOME_TEMP_FILE);
1916 edit_insert_file (edit, tmp_vpath);
1917 vfs_path_free (tmp_vpath, TRUE);
1918 }
1919
1920 return 0;
1921 }
1922
1923 /* --------------------------------------------------------------------------------------------- */
1924 /** if block is 1, a block must be highlighted and the shell command
1925 processes it. If block is 0 the shell command is a straight system
1926 command, that just produces some output which is to be inserted */
1927
1928 void
edit_block_process_cmd(WEdit * edit,int macro_number)1929 edit_block_process_cmd (WEdit * edit, int macro_number)
1930 {
1931 char *fname;
1932 char *macros_fname = NULL;
1933
1934 fname = g_strdup_printf ("%s.%i.sh", EDIT_HOME_MACRO_FILE, macro_number);
1935 macros_fname = g_build_filename (mc_config_get_data_path (), fname, (char *) NULL);
1936 user_menu (edit, macros_fname, 0);
1937 g_free (fname);
1938 g_free (macros_fname);
1939 edit->force |= REDRAW_COMPLETELY;
1940 }
1941
1942 /* --------------------------------------------------------------------------------------------- */
1943
1944 void
edit_mail_dialog(WEdit * edit)1945 edit_mail_dialog (WEdit * edit)
1946 {
1947 char *mail_to, *mail_subject, *mail_cc;
1948
1949 quick_widget_t quick_widgets[] = {
1950 /* *INDENT-OFF* */
1951 QUICK_LABEL (N_("mail -s <subject> -c <cc> <to>"), NULL),
1952 QUICK_LABELED_INPUT (N_("To"), input_label_above,
1953 INPUT_LAST_TEXT, "mail-dlg-input-3",
1954 &mail_to, NULL, FALSE, FALSE, INPUT_COMPLETE_USERNAMES),
1955 QUICK_LABELED_INPUT (N_("Subject"), input_label_above,
1956 INPUT_LAST_TEXT, "mail-dlg-input-2",
1957 &mail_subject, NULL, FALSE, FALSE, INPUT_COMPLETE_NONE),
1958 QUICK_LABELED_INPUT (N_("Copies to"), input_label_above,
1959 INPUT_LAST_TEXT, "mail-dlg-input",
1960 &mail_cc, NULL, FALSE, FALSE, INPUT_COMPLETE_USERNAMES),
1961 QUICK_BUTTONS_OK_CANCEL,
1962 QUICK_END
1963 /* *INDENT-ON* */
1964 };
1965
1966 quick_dialog_t qdlg = {
1967 -1, -1, 50,
1968 N_("Mail"), "[Input Line Keys]",
1969 quick_widgets, NULL, NULL
1970 };
1971
1972 if (quick_dialog (&qdlg) != B_CANCEL)
1973 {
1974 pipe_mail (&edit->buffer, mail_to, mail_subject, mail_cc);
1975 g_free (mail_to);
1976 g_free (mail_subject);
1977 g_free (mail_cc);
1978 }
1979 }
1980
1981 /* --------------------------------------------------------------------------------------------- */
1982
1983 #ifdef HAVE_CHARSET
1984 void
edit_select_codepage_cmd(WEdit * edit)1985 edit_select_codepage_cmd (WEdit * edit)
1986 {
1987 if (do_select_codepage ())
1988 edit_set_codeset (edit);
1989
1990 edit->force = REDRAW_PAGE;
1991 widget_draw (WIDGET (edit));
1992 }
1993 #endif
1994
1995 /* --------------------------------------------------------------------------------------------- */
1996
1997 void
edit_insert_literal_cmd(WEdit * edit)1998 edit_insert_literal_cmd (WEdit * edit)
1999 {
2000 int char_for_insertion;
2001
2002 char_for_insertion = editcmd_dialog_raw_key_query (_("Insert literal"),
2003 _("Press any key:"), FALSE);
2004 edit_execute_key_command (edit, -1, ascii_alpha_to_cntrl (char_for_insertion));
2005 }
2006
2007 /* --------------------------------------------------------------------------------------------- */
2008
2009 gboolean
edit_load_forward_cmd(WEdit * edit)2010 edit_load_forward_cmd (WEdit * edit)
2011 {
2012 if (edit->modified
2013 && edit_query_dialog2 (_("Warning"),
2014 _("Current text was modified without a file save.\n"
2015 "Continue discards these changes."), _("C&ontinue"),
2016 _("&Cancel")) == 1)
2017 {
2018 edit->force |= REDRAW_COMPLETELY;
2019 return TRUE;
2020 }
2021
2022 if (edit_stack_iterator + 1 >= MAX_HISTORY_MOVETO)
2023 return FALSE;
2024
2025 if (edit_history_moveto[edit_stack_iterator + 1].line < 1)
2026 return FALSE;
2027
2028 edit_stack_iterator++;
2029 if (edit_history_moveto[edit_stack_iterator].filename_vpath != NULL)
2030 return edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath,
2031 edit_history_moveto[edit_stack_iterator].line);
2032
2033 return FALSE;
2034 }
2035
2036 /* --------------------------------------------------------------------------------------------- */
2037
2038 gboolean
edit_load_back_cmd(WEdit * edit)2039 edit_load_back_cmd (WEdit * edit)
2040 {
2041 if (edit->modified
2042 && edit_query_dialog2 (_("Warning"),
2043 _("Current text was modified without a file save.\n"
2044 "Continue discards these changes."), _("C&ontinue"),
2045 _("&Cancel")) == 1)
2046 {
2047 edit->force |= REDRAW_COMPLETELY;
2048 return TRUE;
2049 }
2050
2051 /* we are in the bottom of the stack, NO WAY! */
2052 if (edit_stack_iterator == 0)
2053 return FALSE;
2054
2055 edit_stack_iterator--;
2056 if (edit_history_moveto[edit_stack_iterator].filename_vpath != NULL)
2057 return edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath,
2058 edit_history_moveto[edit_stack_iterator].line);
2059
2060 return FALSE;
2061 }
2062
2063 /* --------------------------------------------------------------------------------------------- */
2064
2065 /* gets a raw key from the keyboard. Passing cancel = 1 draws
2066 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
2067 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
2068 and Esc are cannot returned */
2069
2070 int
editcmd_dialog_raw_key_query(const char * heading,const char * query,gboolean cancel)2071 editcmd_dialog_raw_key_query (const char *heading, const char *query, gboolean cancel)
2072 {
2073 int w, wq;
2074 int y = 2;
2075 WDialog *raw_dlg;
2076 WGroup *g;
2077
2078 w = str_term_width1 (heading) + 6;
2079 wq = str_term_width1 (query);
2080 w = MAX (w, wq + 3 * 2 + 1 + 2);
2081
2082 raw_dlg =
2083 dlg_create (TRUE, 0, 0, cancel ? 7 : 5, w, WPOS_CENTER | WPOS_TRYUP, FALSE, dialog_colors,
2084 editcmd_dialog_raw_key_query_cb, NULL, NULL, heading);
2085 g = GROUP (raw_dlg);
2086 widget_want_tab (WIDGET (raw_dlg), TRUE);
2087
2088 group_add_widget (g, label_new (y, 3, query));
2089 group_add_widget (g,
2090 input_new (y++, 3 + wq + 1, input_colors, w - (6 + wq + 1), "", 0,
2091 INPUT_COMPLETE_NONE));
2092 if (cancel)
2093 {
2094 group_add_widget (g, hline_new (y++, -1, -1));
2095 /* Button w/o hotkey to allow use any key as raw or macro one */
2096 group_add_widget_autopos (g, button_new (y, 1, B_CANCEL, NORMAL_BUTTON, _("Cancel"), NULL),
2097 WPOS_KEEP_TOP | WPOS_CENTER_HORZ, NULL);
2098 }
2099
2100 w = dlg_run (raw_dlg);
2101 widget_destroy (WIDGET (raw_dlg));
2102
2103 return (cancel && (w == ESC_CHAR || w == B_CANCEL)) ? 0 : w;
2104 }
2105
2106 /* --------------------------------------------------------------------------------------------- */
2107